### Implement UPnP Device Server in C++ Source: https://context7.com/kleymenus/libupnpp/llms.txt This C++ code demonstrates how to implement a UPnP device server using the libupnpp library. It includes setting up device and service descriptions, registering actions, and handling events. The code initializes the UPnP library, creates a device with a virtual file system for descriptions, adds a custom service, and starts the event loop. ```cpp #include "libupnpp/device/device.hxx" #include "libupnpp/upnpplib.hxx" #include "libupnpp/soaphelp.hxx" #include #include // Service implementation class MyService : public UPnPProvider::UpnpService { public: MyService(UPnPProvider::UpnpDevice* dev) : UpnpService("urn:schemas-upnp-org:service:MyService:1", "urn:upnp-org:serviceId:MyService", dev), m_value(0) { // Register action handlers dev->addActionMapping(this, "SetValue", [this](const UPnPP::SoapIncoming& in, UPnPP::SoapOutgoing& out) { return this->setValueAction(in, out); }); dev->addActionMapping(this, "GetValue", [this](const UPnPP::SoapIncoming& in, UPnPP::SoapOutgoing& out) { return this->getValueAction(in, out); }); } // Provide event data when state changes bool getEventData(bool all, std::vector& names, std::vector& values) override { if (all || m_valueChanged) { names.push_back("Value"); values.push_back(std::to_string(m_value)); m_valueChanged = false; return true; } return false; } private: int setValueAction(const UPnPP::SoapIncoming& in, UPnPP::SoapOutgoing& out) { int newValue; if (!in.get("NewValue", &newValue)) { return UPNP_E_INVALID_PARAM; } m_value = newValue; m_valueChanged = true; return UPNP_E_SUCCESS; } int getValueAction(const UPnPP::SoapIncoming& in, UPnPP::SoapOutgoing& out) { out.addarg("CurrentValue", std::to_string(m_value)); return UPNP_E_SUCCESS; } int m_value; bool m_valueChanged = false; }; int main() { // Initialize library std::string hwaddr; UPnPP::LibUPnP* lib = UPnPP::LibUPnP::getLibUPnP(true, &hwaddr); if (!lib || !lib->ok()) return 1; std::string uuid = UPnPP::LibUPnP::makeDevUUID("MyDevice", hwaddr); // Device description XML std::string description = R"( 10 urn:schemas-upnp-org:device:Basic:1 My UPnP Device Example Demo Device )" + uuid + R"( urn:schemas-upnp-org:service:MyService:1 urn:upnp-org:serviceId:MyService /myservice/scpd.xml /myservice/control /myservice/event )"; // Service description XML std::string scpd = R"( 10 SetValue NewValue in Value GetValue CurrentValue out Value Value i4 )"; // Setup virtual directory with description files std::unordered_map files; files["/description.xml"] = UPnPProvider::VDirContent(description, "text/xml"); files["/myservice/scpd.xml"] = UPnPProvider::VDirContent(scpd, "text/xml"); // Create device UPnPProvider::UpnpDevice device(uuid, files); if (!device.ok()) { std::cerr << "Failed to create device" << std::endl; return 1; } // Create and add service MyService service(&device); device.addService(&service, "urn:upnp-org:serviceId:MyService"); std::cout << "Device started. Press Ctrl+C to exit." << std::endl; // Run event loop (blocks until shouldExit() is called) device.eventloop(); return 0; } ``` -------------------------------- ### Control OpenHome Volume with C++ Source: https://context7.com/kleymenus/libupnpp/llms.txt Illustrates the use of the OHVolume service client for managing audio volume on OpenHome devices. It covers getting and setting volume levels, querying volume limits, and controlling mute functionality. This requires the libupnpp library and an OpenHome-compatible renderer. ```cpp #include "libupnpp/control/ohvolume.hxx" #include "libupnpp/control/mediarenderer.hxx" #include int main() { std::vector renderers; UPnPClient::MediaRenderer::getDeviceDescs(renderers); if (renderers.empty()) return 1; UPnPClient::MediaRenderer renderer(renderers[0]); UPnPClient::OHVLH ohvol = renderer.ohvl(); if (!ohvol) { std::cerr << "OpenHome Volume not available" << std::endl; return 1; } // Get current volume int vol; ohvol->volume(&vol); std::cout << "Current volume: " << vol << std::endl; // Set volume ohvol->setVolume(40); // Get volume limit (max allowed volume) int limit; ohvol->volumeLimit(&limit); std::cout << "Volume limit: " << limit << std::endl; // Mute control bool muted; ohvol->mute(&muted); std::cout << "Muted: " << (muted ? "yes" : "no") << std::endl; ohvol->setMute(true); // Mute ohvol->setMute(false); // Unmute return 0; } ``` -------------------------------- ### Perform XML Utility Operations Source: https://context7.com/kleymenus/libupnpp/llms.txt Provides examples of using SoapHelp utilities for XML character quoting, unquoting, and data type conversion to strings. ```cpp void xmlUtilities() { std::string text = "Tom & Jerry "; std::string quoted = UPnPP::SoapHelp::xmlQuote(text); std::string original = UPnPP::SoapHelp::xmlUnquote(quoted); std::string intStr = UPnPP::SoapHelp::i2s(42); std::string boolStr = UPnPP::SoapHelp::val2s(true); } ``` -------------------------------- ### Browse UPnP Media Servers with C++ ContentDirectory Client Source: https://context7.com/kleymenus/libupnpp/llms.txt This C++ code snippet demonstrates how to use the libupnpp ContentDirectory client to discover media servers, read directory contents, list containers and items, retrieve item properties like artist and album, get resource information, perform searches, and fetch metadata. It includes error handling and server type detection. ```cpp #include "libupnpp/control/cdirectory.hxx" #include "libupnpp/control/cdircontent.hxx" #include #include int main() { // Get all content directory services (media servers) std::vector servers; UPnPClient::ContentDirectory::getServices(servers); std::cout << "Found " << servers.size() << " media servers" << std::endl; // Find server by name UPnPClient::CDSH server; if (!UPnPClient::ContentDirectory::getServerByName("My Media Server", server)) { std::cerr << "Server not found" << std::endl; return 1; } // Detect server type for compatibility adjustments UPnPClient::ContentDirectory::ServiceKind kind = server->getKind(); switch (kind) { case UPnPClient::ContentDirectory::CDSKIND_MINIDLNA: std::cout << "MiniDLNA server detected" << std::endl; break; case UPnPClient::ContentDirectory::CDSKIND_MEDIATOMB: std::cout << "MediaTomb server detected" << std::endl; break; default: break; } // Read root directory ("0" is always the root) UPnPClient::UPnPDirContent rootContent; int ret = server->readDir("0", rootContent); if (ret != UPNP_E_SUCCESS) { std::cerr << "Failed to read root directory" << std::endl; return 1; } // List containers (folders) std::cout << "Containers:" << std::endl; for (const auto& container : rootContent.m_containers) { std::cout << " [" << container.m_id << "] " << container.m_title << std::endl; } // List items (tracks) std::cout << "Items:" << std::endl; for (const auto& item : rootContent.m_items) { std::cout << " [" << item.m_id << "] " << item.m_title << std::endl; // Get item properties std::string artist, album; item.getprop("upnp:artist", artist); item.getprop("upnp:album", album); std::cout << " Artist: " << artist << ", Album: " << album << std::endl; // Get resource (stream) information if (!item.m_resources.empty()) { std::cout << " URI: " << item.m_resources[0].m_uri << std::endl; std::string bitrate; item.getrprop(0, "bitrate", bitrate); std::cout << " Bitrate: " << bitrate << std::endl; } // Get duration int duration = item.getDurationSeconds(); std::cout << " Duration: " << duration << " seconds" << std::endl; } // Read a subdirectory with pagination UPnPClient::UPnPDirContent musicContent; int didread, total; ret = server->readDirSlice("1", 0, 50, musicContent, &didread, &total); std::cout << "Read " << didread << " of " << total << " items" << std::endl; // Get search capabilities std::set searchCaps; server->getSearchCapabilities(searchCaps); if (searchCaps.count("*") || searchCaps.count("dc:title")) { // Search for items containing "Beatles" UPnPClient::UPnPDirContent searchResults; ret = server->search("0", "dc:title contains \"Beatles\"", searchResults); std::cout << "Found " << searchResults.m_items.size() << " items" << std::endl; } // Get metadata for specific object UPnPClient::UPnPDirContent metadata; server->getMetadata("123", metadata); if (!metadata.m_items.empty()) { std::cout << "Item title: " << metadata.m_items[0].m_title << std::endl; } return 0; } ``` -------------------------------- ### Build SOAP Action Requests and Responses with SoapOutgoing Source: https://context7.com/kleymenus/libupnpp/llms.txt Demonstrates how to construct SOAP action requests using addarg or chaining operators, and how to build response messages with output arguments. ```cpp #include "libupnpp/soaphelp.hxx" void buildActionRequest() { UPnPP::SoapOutgoing request("urn:schemas-upnp-org:service:AVTransport:1", "Play"); request.addarg("InstanceID", "0"); request.addarg("Speed", "1"); UPnPP::SoapOutgoing request2("urn:schemas-upnp-org:service:RenderingControl:1", "SetVolume"); request2("InstanceID", "0")("Channel", "Master")("DesiredVolume", "50"); IXML_Document* doc = request.buildSoapBody(false); } ``` -------------------------------- ### Initialize and Use libupnpp Logger in C++ Source: https://context7.com/kleymenus/libupnpp/llms.txt Demonstrates how to initialize the Logger singleton, set the log level, and use logging macros for diagnostic output in C++. The logger supports various levels from fatal errors to verbose debug messages and automatically includes file and line information. ```cpp #include "libupnpp/log.hxx" #include int main() { // Initialize logger with file output // Empty string ("" means output to stderr) UPnPP::Logger* log = UPnPP::Logger::getTheLog("/tmp/myapp.log"); // Set log level log->setLogLevel(UPnPP::Logger::LLDEB); // Enable debug output // Available levels: // LLNON - No logging // LLFAT - Fatal errors only // LLERR - Errors // LLINF - Info messages // LLDEB - Debug messages // LLDEB1 - Verbose debug // Use logging macros (includes file:line automatically) LOGFAT("Fatal error: system crash" << std::endl); LOGERR("Error: connection failed" << std::endl); LOGINF("Info: connected to device" << std::endl); LOGDEB("Debug: processing request id=" << 42 << std::endl); LOGDEB1("Verbose: packet data=" << "..." << std::endl); // Direct stream access log->getstream() << "Direct output to log" << std::endl; // Check current log level int level = log->getloglevel(); if (level >= UPnPP::Logger::LLDEB) { // Perform expensive debug operations } return 0; } ``` -------------------------------- ### Discover and Browse Media Servers using C++ Source: https://context7.com/kleymenus/libupnpp/llms.txt This snippet demonstrates how to discover UPnP media servers on the network, filter them by name, and interact with the ContentDirectory service to list media folders. It requires the libupnpp library and handles device descriptions and service handles. ```cpp #include "libupnpp/control/mediaserver.hxx" #include "libupnpp/control/cdirectory.hxx" #include #include int main() { std::vector servers; if (!UPnPClient::MediaServer::getDeviceDescs(servers)) { std::cerr << "Failed to discover media servers" << std::endl; return 1; } std::cout << "Found " << servers.size() << " media servers:" << std::endl; for (const auto& srv : servers) { std::cout << " " << srv.friendlyName << " (" << srv.modelName << ")" << std::endl; } std::vector namedServers; UPnPClient::MediaServer::getDeviceDescs(namedServers, "My NAS"); if (!namedServers.empty()) { UPnPClient::MediaServer server(namedServers[0]); UPnPClient::CDSH cds = server.cds(); if (cds) { UPnPClient::UPnPDirContent content; cds->readDir("0", content); for (const auto& container : content.m_containers) { std::cout << "Folder: " << container.m_title << std::endl; } } } if (UPnPClient::MediaServer::isMSDevice("urn:schemas-upnp-org:device:MediaServer:1")) { std::cout << "This is a media server device type" << std::endl; } return 0; } ``` -------------------------------- ### Initialize LibUPnP Singleton Source: https://context7.com/kleymenus/libupnpp/llms.txt This snippet demonstrates how to initialize the LibUPnP singleton, configure network interfaces, set logging, and generate a unique device UUID. It is the mandatory first step before utilizing any other library functionality. ```cpp #include "libupnpp/upnpplib.hxx" #include int main() { std::string hwaddr; UPnPP::LibUPnP* lib = UPnPP::LibUPnP::getLibUPnP( false, &hwaddr, "eth0", "", 0 ); if (!lib || !lib->ok()) { std::cerr << "Failed to initialize libupnp: " << UPnPP::LibUPnP::errAsString("init", lib->getInitError()) << std::endl; return 1; } lib->setLogFileName("/tmp/upnp.log", UPnPP::LibUPnP::LogLevelDebug); lib->setMaxContentLength(4 * 1024 * 1024); std::string uuid = UPnPP::LibUPnP::makeDevUUID("MyMediaRenderer", hwaddr); std::cout << "Device UUID: " << uuid << std::endl; return 0; } ``` -------------------------------- ### Control OpenHome Playlist with C++ Source: https://context7.com/kleymenus/libupnpp/llms.txt Demonstrates how to use the OHPlaylist service client to manage playlists on OpenHome renderers. It covers track insertion, deletion, navigation, playback control, and querying playlist status. Requires libupnpp library and an OpenHome-compatible renderer. ```cpp #include "libupnpp/control/ohplaylist.hxx" #include "libupnpp/control/mediarenderer.hxx" #include #include int main() { std::vector renderers; UPnPClient::MediaRenderer::getDeviceDescs(renderers); if (renderers.empty()) return 1; UPnPClient::MediaRenderer renderer(renderers[0]); if (!renderer.hasOpenHome()) { std::cerr << "Renderer does not support OpenHome" << std::endl; return 1; } UPnPClient::OHPLH ohpl = renderer.ohpl(); if (!ohpl) return 1; // Clear existing playlist ohpl->deleteAll(); // Get maximum tracks supported int maxTracks; ohpl->tracksMax(&maxTracks); std::cout << "Max playlist tracks: " << maxTracks << std::endl; // Insert tracks (afterid=0 means insert at beginning) int newId; std::string uri = "http://192.168.1.100/music/song1.flac"; std::string didl = "Song 1"; ohpl->insert(0, uri, didl, &newId); std::cout << "Inserted track with id: " << newId << std::endl; // Insert another track after the first ohpl->insert(newId, "http://192.168.1.100/music/song2.flac", "", &newId); // Get track list std::vector ids; int token; ohpl->idArray(&ids, &token); std::cout << "Playlist contains " << ids.size() << " tracks" << std::endl; // Read track information std::vector tracks; ohpl->readList(ids, &tracks); for (const auto& track : tracks) { std::cout << "Track " << track.id << ": " << track.dirent.m_title << std::endl; } // Read single track std::string trackUri; UPnPClient::UPnPDirObject trackMeta; ohpl->read(ids[0], &trackUri, &trackMeta); // Playback control ohpl->play(); ohpl->pause(); ohpl->stop(); // Navigation ohpl->next(); ohpl->previous(); // Seek within track (seconds) ohpl->seekSecondAbsolute(90); // Seek to 1:30 ohpl->seekSecondRelative(-10); // Go back 10 seconds // Jump to specific track ohpl->seekId(newId); // By track ID ohpl->seekIndex(0); // By playlist index // Set shuffle and repeat ohpl->setShuffle(true); ohpl->setRepeat(true); bool shuffleOn, repeatOn; ohpl->shuffle(&shuffleOn); ohpl->repeat(&repeatOn); // Get current track ID int currentId; ohpl->id(¤tId); // Get transport state UPnPClient::OHPlaylist::TPState state; ohpl->transportState(&state); if (state == UPnPClient::OHPlaylist::TPS_Playing) { std::cout << "Currently playing" << std::endl; } // Delete specific track ohpl->deleteId(ids[0]); // Check if playlist changed (for cache invalidation) bool changed; ohpl->idArrayChanged(token, &changed); if (changed) { std::cout << "Playlist was modified" << std::endl; } // Get supported protocols std::string protocols; ohpl->protocolInfo(&protocols); std::cout << "Supported formats: " << protocols << std::endl; return 0; } ``` -------------------------------- ### Process Incoming SOAP Actions with SoapIncoming Source: https://context7.com/kleymenus/libupnpp/llms.txt Shows how to extract parameters from incoming SOAP requests and handle action logic using the SoapIncoming class. ```cpp int processSetVolumeAction(const UPnPP::SoapIncoming& in, UPnPP::SoapOutgoing& out) { int instanceId, volume; std::string channel; if (!in.get("InstanceID", &instanceId) || !in.get("Channel", &channel) || !in.get("DesiredVolume", &volume)) { return UPNP_E_INVALID_PARAM; } return UPNP_E_SUCCESS; } ``` -------------------------------- ### MediaServer Discovery and Browsing Source: https://context7.com/kleymenus/libupnpp/llms.txt This section covers how to discover available media servers on the network and browse their content directories using the libupnpp library. ```APIDOC ## GET /libupnpp/MediaServer/Discovery ### Description Discovers UPnP media server devices available on the local network. It can return all available devices or filter by a specific friendly name. ### Method GET ### Endpoint UPnPClient::MediaServer::getDeviceDescs(std::vector& servers, const std::string& name = "") ### Parameters #### Path Parameters - **servers** (std::vector) - Required - Output vector to store discovered device descriptors. - **name** (std::string) - Optional - Filter discovery by a specific friendly name. ### Response #### Success Response (bool) - **Returns** (bool) - True if discovery was successful, false otherwise. --- ## GET /libupnpp/MediaServer/ContentDirectory ### Description Accesses the ContentDirectory service of a discovered media server to browse its media library. ### Method GET ### Endpoint UPnPClient::CDSH cds = server.cds(); cds->readDir(const std::string& objectId, UPnPClient::UPnPDirContent& content); ### Parameters #### Path Parameters - **objectId** (std::string) - Required - The ID of the container to browse (e.g., "0" for root). - **content** (UPnPClient::UPnPDirContent) - Required - Output object to store the directory listing. ### Response #### Success Response (void) - **content** (UPnPClient::UPnPDirContent) - Populated object containing containers and items found in the directory. ``` -------------------------------- ### LibUPnP Initialization Source: https://context7.com/kleymenus/libupnpp/llms.txt Initializes the libupnp stack and configures core settings such as logging, network interfaces, and UUID generation. ```APIDOC ## LibUPnP Initialization ### Description Initializes the underlying libupnp library instance. This singleton must be called before any other UPnP operations to manage the stack lifecycle and network configuration. ### Method Static Factory Method ### Endpoint UPnPP::LibUPnP::getLibUPnP ### Parameters #### Arguments - **serveronly** (bool) - Required - If true, initializes only as a server; if false, enables client functionality. - **hwaddr** (std::string*) - Optional - Pointer to store the detected hardware address. - **iface** (std::string) - Optional - The network interface name (e.g., "eth0"). - **ip** (std::string) - Optional - Specific IP address to bind. - **port** (int) - Optional - Port number (0 for default). ### Request Example UPnPP::LibUPnP::getLibUPnP(false, &hwaddr, "eth0", "", 0); ### Response #### Success Response (Pointer) - **LibUPnP*** - A pointer to the initialized singleton instance. #### Error Handling - Returns nullptr or a LibUPnP instance where ok() returns false if initialization fails. Use errAsString() to retrieve error details. ``` -------------------------------- ### Control Media Playback with AVTransport Source: https://context7.com/kleymenus/libupnpp/llms.txt Demonstrates how to initialize an AVTransport service to control media playback. It covers setting URIs, playback state management (play/pause/stop), seeking, and retrieving transport information. ```cpp #include "libupnpp/control/avtransport.hxx" #include "libupnpp/control/mediarenderer.hxx" #include int main() { std::vector renderers; UPnPClient::MediaRenderer::getDeviceDescs(renderers); if (renderers.empty()) return 1; UPnPClient::MediaRenderer renderer(renderers[0]); UPnPClient::AVTH avt = renderer.avt(); if (!avt) { std::cerr << "AVTransport service not available" << std::endl; return 1; } std::string uri = "http://192.168.1.100:8080/music/track.mp3"; std::string metadata = "" "My Song"; int ret = avt->setAVTransportURI(uri, metadata); if (ret != 0) { std::cerr << "Failed to set URI: " << ret << std::endl; } avt->play(1); avt->pause(); avt->stop(); avt->seek(UPnPClient::AVTransport::SEEK_ABS_TIME, 120); UPnPClient::AVTransport::TransportInfo tinfo; avt->getTransportInfo(tinfo); return 0; } ``` -------------------------------- ### Manage Volume and Mute with RenderingControl Source: https://context7.com/kleymenus/libupnpp/llms.txt Shows how to use the RenderingControl service to adjust volume levels and mute states on a media renderer. Volume values are normalized to a 0-100 scale. ```cpp #include "libupnpp/control/renderingcontrol.hxx" #include "libupnpp/control/mediarenderer.hxx" #include int main() { std::vector renderers; UPnPClient::MediaRenderer::getDeviceDescs(renderers); if (renderers.empty()) return 1; UPnPClient::MediaRenderer renderer(renderers[0]); UPnPClient::RDCH rdc = renderer.rdc(); if (!rdc) { std::cerr << "RenderingControl service not available" << std::endl; return 1; } int volume = rdc->getVolume("Master"); std::cout << "Current volume: " << volume << "%" << std::endl; rdc->setVolume(50, "Master"); bool muted = rdc->getMute("Master"); rdc->setMute(!muted, "Master"); return 0; } ``` -------------------------------- ### UPnPDeviceDirectory: Discover and Manage UPnP Devices Source: https://context7.com/kleymenus/libupnpp/llms.txt Manages UPnP device discovery on the local network. It maintains a directory of active devices, handles SSDP messages, and provides methods to traverse or find devices by name or UUID. Discovery runs asynchronously with configurable search windows. Includes callbacks for real-time discovery events. ```cpp #include "libupnpp/control/discovery.hxx" #include "libupnpp/control/description.hxx" #include // Callback function called for each discovered device/service pair bool deviceVisitor(const UPnPClient::UPnPDeviceDesc& device, const UPnPClient::UPnPServiceDesc& service) { std::cout << "Found device: " << device.friendlyName << std::endl; std::cout << " Type: " << device.deviceType << std::endl; std::cout << " UDN: " << device.UDN << std::endl; std::cout << " Manufacturer: " << device.manufacturer << std::endl; std::cout << " Service: " << service.serviceType << std::endl; std::cout << " Control URL: " << service.controlURL << std::endl; return true; // Continue traversal } int main() { // Get the discovery directory (starts discovery if first call) // search_window: seconds to wait for device responses UPnPClient::UPnPDeviceDirectory* dir = UPnPClient::UPnPDeviceDirectory::getTheDir(5); if (!dir->ok()) { std::cerr << "Discovery failed: " << dir->getReason() << std::endl; return 1; } // Wait for initial discovery to complete then traverse all devices std::cout << "Waiting " << dir->getRemainingDelay() << " seconds for discovery..." << std::endl; dir->traverse(deviceVisitor); // Find a specific device by friendly name UPnPClient::UPnPDeviceDesc device; if (dir->getDevByFName("Living Room Speaker", device)) { std::cout << "Found device by name: " << device.dump() << std::endl; } // Find device by UDN (unique device name) if (dir->getDevByUDN("uuid:4d696e69-444c-164e-9d41-001e8c123456", device)) { std::cout << "Found device by UDN" << std::endl; } // Register callback for real-time device discovery events unsigned int callbackId = UPnPClient::UPnPDeviceDirectory::addCallback( [](const UPnPClient::UPnPDeviceDesc& dev, const UPnPClient::UPnPServiceDesc&){ std::cout << "New device appeared: " << dev.friendlyName << std::endl; return true; } ); // Later, remove the callback UPnPClient::UPnPDeviceDirectory::delCallback(callbackId); // Cleanup before exit UPnPClient::UPnPDeviceDirectory::terminate(); return 0; } ``` -------------------------------- ### OHPlaylist - OpenHome Playlist Control API Source: https://context7.com/kleymenus/libupnpp/llms.txt Client for controlling playlist functionality on OpenHome-compatible renderers, offering advanced playback and playlist management. ```APIDOC ## OHPlaylist - OpenHome Playlist Control ### Description The `OHPlaylist` service client controls playlist functionality on OpenHome-compatible renderers. It provides comprehensive playlist management including track insertion, deletion, and navigation. This service offers more advanced playback control than standard UPnP AVTransport. ### Methods - **deleteAll()**: Clears the entire playlist. - **tracksMax(int* maxTracks)**: Retrieves the maximum number of tracks the playlist can hold. - **insert(int afterId, string uri, string didl, int* newId)**: Inserts a new track into the playlist. `afterId=0` inserts at the beginning. - **idArray(vector* ids, int* token)**: Retrieves an array of track IDs and a token for change detection. - **readList(vector ids, vector* tracks)**: Reads detailed information for a list of tracks. - **read(int id, string* trackUri, UPnPDirObject* trackMeta)**: Reads the URI and metadata for a specific track. - **play()**: Starts playback. - **pause()**: Pauses playback. - **stop()**: Stops playback. - **next()**: Skips to the next track. - **previous()**: Skips to the previous track. - **seekSecondAbsolute(int seconds)**: Seeks to a specific second within the current track. - **seekSecondRelative(int seconds)**: Seeks forward or backward by a specified number of seconds. - **seekId(int id)**: Jumps to a specific track by its ID. - **seekIndex(int index)**: Jumps to a specific track by its playlist index. - **setShuffle(bool shuffleOn)**: Enables or disables shuffle mode. - **shuffle(bool* shuffleOn)**: Retrieves the current shuffle mode status. - **setRepeat(bool repeatOn)**: Enables or disables repeat mode. - **repeat(bool* repeatOn)**: Retrieves the current repeat mode status. - **id(int* currentId)**: Retrieves the ID of the currently playing track. - **transportState(TPState* state)**: Retrieves the current transport state (e.g., Playing, Paused, Stopped). - **deleteId(int id)**: Deletes a specific track from the playlist by its ID. - **idArrayChanged(int token, bool* changed)**: Checks if the playlist has been modified since the last token. - **protocolInfo(string* protocols)**: Retrieves information about supported media formats. ### Example Usage (C++) ```cpp #include "libupnpp/control/ohplaylist.hxx" #include "libupnpp/control/mediarenderer.hxx" #include #include int main() { std::vector renderers; UPnPClient::MediaRenderer::getDeviceDescs(renderers); if (renderers.empty()) return 1; UPnPClient::MediaRenderer renderer(renderers[0]); if (!renderer.hasOpenHome()) { std::cerr << "Renderer does not support OpenHome" << std::endl; return 1; } UPnPClient::OHPLH ohpl = renderer.ohpl(); if (!ohpl) return 1; // Clear existing playlist ohpl->deleteAll(); // Get maximum tracks supported int maxTracks; ohpl->tracksMax(&maxTracks); std::cout << "Max playlist tracks: " << maxTracks << std::endl; // Insert tracks (afterid=0 means insert at beginning) int newId; std::string uri = "http://192.168.1.100/music/song1.flac"; std::string didl = "Song 1"; ohpl->insert(0, uri, didl, &newId); std::cout << "Inserted track with id: " << newId << std::endl; // Insert another track after the first ohpl->insert(newId, "http://192.168.1.100/music/song2.flac", "", &newId); // Get track list std::vector ids; int token; ohpl->idArray(&ids, &token); std::cout << "Playlist contains " << ids.size() << " tracks" << std::endl; // Read track information std::vector tracks; ohpl->readList(ids, &tracks); for (const auto& track : tracks) { std::cout << "Track " << track.id << ": " << track.dirent.m_title << std::endl; } // Read single track std::string trackUri; UPnPClient::UPnPDirObject trackMeta; ohpl->read(ids[0], &trackUri, &trackMeta); // Playback control ohpl->play(); ohpl->pause(); ohpl->stop(); // Navigation ohpl->next(); ohpl->previous(); // Seek within track (seconds) ohpl->seekSecondAbsolute(90); // Seek to 1:30 ohpl->seekSecondRelative(-10); // Go back 10 seconds // Jump to specific track ohpl->seekId(newId); // By track ID ohpl->seekIndex(0); // By playlist index // Set shuffle and repeat ohpl->setShuffle(true); ohpl->setRepeat(true); bool shuffleOn, repeatOn; ohpl->shuffle(&shuffleOn); ohpl->repeat(&repeatOn); // Get current track ID int currentId; ohpl->id(¤tId); // Get transport state UPnPClient::OHPlaylist::TPState state; ohpl->transportState(&state); if (state == UPnPClient::OHPlaylist::TPS_Playing) { std::cout << "Currently playing" << std::endl; } // Delete specific track ohpl->deleteId(ids[0]); // Check if playlist changed (for cache invalidation) bool changed; ohpl->idArrayChanged(token, &changed); if (changed) { std::cout << "Playlist was modified" << std::endl; } // Get supported protocols std::string protocols; ohpl->protocolInfo(&protocols); std::cout << "Supported formats: " << protocols << std::endl; return 0; } ``` -------------------------------- ### MediaRenderer: Control UPnP Media Renderers Source: https://context7.com/kleymenus/libupnpp/llms.txt Provides a high-level interface to control UPnP media renderer devices, aggregating access to AVTransport, RenderingControl, and OpenHome services. Use this class to discover and control playback devices on your network. It allows finding renderers by name and accessing their specific UPnP services. ```cpp #include "libupnpp/control/mediarenderer.hxx" #include "libupnpp/control/discovery.hxx" #include #include int main() { // Discover all media renderers on the network std::vector renderers; if (!UPnPClient::MediaRenderer::getDeviceDescs(renderers)) { std::cerr << "Failed to get media renderers" << std::endl; return 1; } std::cout << "Found " << renderers.size() << " renderers" << std::endl; // Find a specific renderer by friendly name std::vector namedRenderers; UPnPClient::MediaRenderer::getDeviceDescs(namedRenderers, "Living Room"); if (namedRenderers.empty()) { std::cerr << "Renderer not found" << std::endl; return 1; } // Create renderer control object UPnPClient::MediaRenderer renderer(namedRenderers[0]); // Check for OpenHome support if (renderer.hasOpenHome()) { std::cout << "Renderer supports OpenHome protocol" << std::endl; // Get OpenHome services UPnPClient::OHPLH ohPlaylist = renderer.ohpl(); // OpenHome Playlist UPnPClient::OHPRH ohProduct = renderer.ohpr(); // OpenHome Product UPnPClient::OHVLH ohVolume = renderer.ohvl(); // OpenHome Volume } // Get standard UPnP AV services UPnPClient::AVTH avTransport = renderer.avt(); // AVTransport UPnPClient::RDCH renderingControl = renderer.rdc(); // RenderingControl std::cout << "Connected to: " << renderer.desc()->friendlyName << std::endl; return 0; } ``` -------------------------------- ### Implement VarEventReporter for UPnP Service Notifications Source: https://context7.com/kleymenus/libupnpp/llms.txt This snippet demonstrates how to subclass VarEventReporter to handle various data types including integers, strings, metadata objects, and playlist IDs. It also shows how to register the reporter with an AVTransport service instance to begin receiving event callbacks. ```cpp #include "libupnpp/control/service.hxx" #include "libupnpp/control/avtransport.hxx" #include "libupnpp/control/mediarenderer.hxx" #include class MyEventReporter : public UPnPClient::VarEventReporter { public: void changed(const char* name, int value) override { std::cout << "Event: " << name << " = " << value << std::endl; if (std::string(name) == "Volume") onVolumeChanged(value); } void changed(const char* name, const char* value) override { std::cout << "Event: " << name << " = " << value << std::endl; if (std::string(name) == "TransportState") onTransportStateChanged(value); } void changed(const char* name, UPnPClient::UPnPDirObject meta) override { std::cout << "Metadata changed: " << name << std::endl; onTrackChanged(meta); } void changed(const char* name, std::vector ids) override { std::cout << "Playlist changed: " << ids.size() << " tracks" << std::endl; onPlaylistChanged(ids); } private: void onVolumeChanged(int volume) {} void onTransportStateChanged(const std::string& state) {} void onTrackChanged(const UPnPClient::UPnPDirObject& meta) {} void onPlaylistChanged(const std::vector& ids) {} }; int main() { std::vector renderers; UPnPClient::MediaRenderer::getDeviceDescs(renderers); if (renderers.empty()) return 1; UPnPClient::MediaRenderer renderer(renderers[0]); UPnPClient::AVTH avt = renderer.avt(); if (!avt) return 1; MyEventReporter reporter; avt->installReporter(&reporter); std::cin.get(); avt->installReporter(nullptr); return 0; } ``` -------------------------------- ### OHVolume - OpenHome Volume Control API Source: https://context7.com/kleymenus/libupnpp/llms.txt Client for controlling volume on OpenHome-compatible devices, including mute and volume limits. ```APIDOC ## OHVolume - OpenHome Volume Control ### Description The `OHVolume` service client provides volume control for OpenHome-compatible devices. It offers similar functionality to RenderingControl but follows the OpenHome specification with volume normalization and limit queries. ### Methods - **volume(int* vol)**: Retrieves the current volume level. - **setVolume(int vol)**: Sets the volume to a specified level. - **volumeLimit(int* limit)**: Retrieves the maximum allowed volume level. - **mute(bool* muted)**: Retrieves the current mute status. - **setMute(bool muted)**: Sets the mute status (true to mute, false to unmute). ### Example Usage (C++) ```cpp #include "libupnpp/control/ohvolume.hxx" #include "libupnpp/control/mediarenderer.hxx" #include int main() { std::vector renderers; UPnPClient::MediaRenderer::getDeviceDescs(renderers); if (renderers.empty()) return 1; UPnPClient::MediaRenderer renderer(renderers[0]); UPnPClient::OHVLH ohvol = renderer.ohvl(); if (!ohvol) { std::cerr << "OpenHome Volume not available" << std::endl; return 1; } // Get current volume int vol; ohvol->volume(&vol); std::cout << "Current volume: " << vol << std::endl; // Set volume ohvol->setVolume(40); // Get volume limit (max allowed volume) int limit; ohvol->volumeLimit(&limit); std::cout << "Volume limit: " << limit << std::endl; // Mute control bool muted; ohvol->mute(&muted); std::cout << "Muted: " << (muted ? "yes" : "no") << std::endl; ohvol->setMute(true); // Mute ohvol->setMute(false); // Unmute return 0; } ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.