/* * Presents a list to the user, allows the user to choose one item. * * Parameters: * PLT_StringMap: A map that contains the set of items from * which the user should choose. The key should be a unique ID, * and the value should be a string describing the item. * returns a NPT_String with the unique ID. */ const char* PLT_MicroMediaController::ChooseIDFromTable(PLT_StringMap& table) { printf("Select one of the following:\n"); NPT_List<PLT_StringMapEntry*> entries = table.GetEntries(); if (entries.GetItemCount() == 0) { printf("None available\n"); } else { // display the list of entries NPT_List<PLT_StringMapEntry*>::Iterator entry = entries.GetFirstItem(); int count = 0; while (entry) { printf("%d)\t%s (%s)\n", ++count, (const char*)(*entry)->GetValue(), (const char*)(*entry)->GetKey()); ++entry; } int index, watchdog = 3; char buffer[1024]; // wait for input /*while (watchdog > 0) { fgets(buffer, 1024, stdin); strchomp(buffer); if (1 != sscanf(buffer, "%d", &index)) { printf("Please enter a number\n"); } else if (index < 0 || index > count) { printf("Please choose one of the above, or 0 for none\n"); watchdog--; index = 0; } else { watchdog = 0; } }*/ index = 1; // find the entry back if (index != 0) { entry = entries.GetFirstItem(); while (entry && --index) { ++entry; } if (entry) { return (*entry)->GetKey(); } } } return NULL; }
/*---------------------------------------------------------------------- | NPT_PosixQueue::Peek +---------------------------------------------------------------------*/ NPT_Result NPT_PosixQueue::Peek(NPT_QueueItem*& item, NPT_Timeout timeout) { struct timespec timed; if (timeout != NPT_TIMEOUT_INFINITE) { NPT_CHECK(GetTimeOut(timeout, timed)); } // lock the mutex that protects the list if (pthread_mutex_lock(&m_Mutex)) { return NPT_FAILURE; } NPT_Result result = NPT_SUCCESS; NPT_List<NPT_QueueItem*>::Iterator head = m_Items.GetFirstItem(); if (timeout) { while (!head) { // no item in the list, wait for one ++m_PoppersWaitingCount; if (timeout == NPT_TIMEOUT_INFINITE) { pthread_cond_wait(&m_CanPopCondition, &m_Mutex); --m_PoppersWaitingCount; } else { int wait_res = pthread_cond_timedwait(&m_CanPopCondition, &m_Mutex, &timed); --m_PoppersWaitingCount; if (wait_res == ETIMEDOUT) { result = NPT_ERROR_TIMEOUT; break; } } if (m_Aborting) { result = NPT_ERROR_INTERRUPTED; break; } head = m_Items.GetFirstItem(); } } else { if (!head) result = NPT_ERROR_LIST_EMPTY; } item = head?*head:NULL; // unlock the mutex pthread_mutex_unlock(&m_Mutex); return result; }
/*---------------------------------------------------------------------- | PLT_StateVariable::ValidateValue +---------------------------------------------------------------------*/ NPT_Result PLT_StateVariable::ValidateValue(const char* value) { if (m_DataType.Compare("string", true) == 0) { // if we have a value allowed restriction, make sure the value is in our list if (m_AllowedValues.GetItemCount()) { // look for a comma separated list NPT_String _value = value; NPT_List<NPT_String> values = _value.Split(","); NPT_List<NPT_String>::Iterator val = values.GetFirstItem(); while (val) { val->Trim(" "); if (!m_AllowedValues.Find(NPT_StringFinder(*val))) { #if defined(NPT_CONFIG_ENABLE_LOGGING) NPT_LOG_WARNING_2("Invalid value of %s for state variable %s", (const char*)*val, (const char*)m_Name); for (unsigned long i=0; i < m_AllowedValues.GetItemCount(); i++) { NPT_String *val2 = *m_AllowedValues.GetItem(i); NPT_LOG_WARNING_1("Allowed: %s", (const char*)*val2); } #endif return NPT_ERROR_INVALID_PARAMETERS; } ++val; } } } // TODO: there are more to it than allowed values, we need to test for range, etc.. return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | NPT_File::RemoveDir +---------------------------------------------------------------------*/ NPT_Result NPT_File::RemoveDir(const char* path, bool force_if_not_empty) { NPT_String root_path = path; // normalize path separators root_path.Replace((NPT_FilePath::Separator[0] == '/')?'\\':'/', NPT_FilePath::Separator); // remove superfluous delimiters at the end root_path.TrimRight(NPT_FilePath::Separator); // remove all entries in the directory if required if (force_if_not_empty) { // enumerate all entries NPT_File dir(root_path); NPT_List<NPT_String> entries; NPT_CHECK_WARNING(dir.ListDir(entries)); for (NPT_List<NPT_String>::Iterator it = entries.GetFirstItem(); it; ++it) { NPT_File::Remove(NPT_FilePath::Create(root_path, *it), true); } } // remove the (now empty) directory return NPT_File::RemoveDir(root_path); }
/*---------------------------------------------------------------------- | PLT_MediaServer::ParseSort +---------------------------------------------------------------------*/ NPT_Result PLT_MediaServer::ParseSort(const NPT_String& sort, NPT_List<NPT_String>& list) { // reset output params first list.Clear(); // easy out if (sort.GetLength() == 0 || sort == "*") return NPT_SUCCESS; list = sort.Split(","); // verify each property has a namespace NPT_List<NPT_String>::Iterator property = list.GetFirstItem(); while (property) { NPT_List<NPT_String> parsed_property = (*property).Split(":"); if (parsed_property.GetItemCount() != 2) parsed_property = (*property).Split("@"); if (parsed_property.GetItemCount() != 2 || (!(*property).StartsWith("-") && !(*property).StartsWith("+"))) { NPT_LOG_WARNING_1("Invalid SortCriteria property %s", (*property).GetChars()); return NPT_FAILURE; } property++; } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | CUPnP::CUPnP +---------------------------------------------------------------------*/ CUPnP::CUPnP() : m_MediaBrowser(NULL), m_MediaController(NULL), m_LogHandler(NULL), m_ServerHolder(new CDeviceHostReferenceHolder()), m_RendererHolder(new CRendererReferenceHolder()), m_CtrlPointHolder(new CCtrlPointReferenceHolder()) { NPT_LogManager::GetDefault().Configure("plist:.level=FINE;.handlers=CustomHandler;"); NPT_LogHandler::Create("xbmc", "CustomHandler", m_LogHandler); m_LogHandler->SetCustomHandlerFunction(&UPnPLogger); // initialize upnp context m_UPnP = new PLT_UPnP(); // keep main IP around if (g_application.getNetwork().GetFirstConnectedInterface()) { m_IP = g_application.getNetwork().GetFirstConnectedInterface()->GetCurrentIPAddress().c_str(); } NPT_List<NPT_IpAddress> list; if (NPT_SUCCEEDED(PLT_UPnPMessageHelper::GetIPAddresses(list)) && list.GetItemCount()) { m_IP = (*(list.GetFirstItem())).ToString(); } else if(m_IP.empty()) m_IP = "localhost"; // start upnp monitoring m_UPnP->Start(); }
/*---------------------------------------------------------------------- | NPT_Win32Queue::Peek +---------------------------------------------------------------------*/ NPT_Result NPT_Win32Queue::Peek(NPT_QueueItem*& item, NPT_Timeout timeout) { // default value item = NULL; // lock the mutex that protects the list NPT_CHECK(m_Mutex.Lock()); NPT_Result result = NPT_SUCCESS; NPT_List<NPT_QueueItem*>::Iterator head = m_Items.GetFirstItem(); if (timeout) { while (!head) { // no item in the list, wait for one // reset the condition to indicate that the queue is empty m_CanPopCondition->Reset(); // unlock the mutex so that another thread can push m_Mutex.Unlock(); // wait for the condition to signal that we can pop NPT_Result result = m_CanPopCondition->Wait(timeout); if (NPT_FAILED(result)) return result; // relock the mutex so that we can check the list again NPT_CHECK(m_Mutex.Lock()); // try again head = m_Items.GetFirstItem(); } } else { if (!head) result = NPT_ERROR_LIST_EMPTY; } if (head) item = *head; // unlock the mutex m_Mutex.Unlock(); return result; }
/*---------------------------------------------------------------------- | NPT_String::Join +---------------------------------------------------------------------*/ NPT_String NPT_String::Join(NPT_List<NPT_String>& args, const char* separator) { NPT_String output; NPT_List<NPT_String>::Iterator arg = args.GetFirstItem(); while (arg) { output += *arg; if (++arg) output += separator; } return output; }
/*---------------------------------------------------------------------- | PLT_MediaController::FindMatchingProtocolInfo +---------------------------------------------------------------------*/ NPT_Result PLT_MediaController::FindMatchingProtocolInfo(NPT_List<NPT_String>& sinks, const char* protocol_info) { PLT_ProtocolInfo protocol(protocol_info); for (NPT_List<NPT_String>::Iterator iter = sinks.GetFirstItem(); iter; iter++) { PLT_ProtocolInfo sink(*iter); if (sink.Match(protocol)) return NPT_SUCCESS; } return NPT_ERROR_NO_SUCH_ITEM; }
/*---------------------------------------------------------------------- | PLT_MediaServer::ParseTagList +---------------------------------------------------------------------*/ NPT_Result PLT_MediaServer::ParseTagList(const NPT_String& updates, NPT_Map<NPT_String,NPT_String>& tags) { // reset output params first tags.Clear(); NPT_List<NPT_String> split = updates.Split(","); NPT_XmlNode* node = NULL; NPT_XmlElementNode* didl_partial = NULL; NPT_XmlParser parser; // as these are single name value pairs, separated by commas we wrap in a tag // to create a valid tree NPT_String xml("<TagValueList>"); for (NPT_List<NPT_String>::Iterator entry = split.GetFirstItem(); entry; entry++) { NPT_String& element = (*entry); if (element.IsEmpty()) xml.Append("<empty>empty</empty>"); else xml.Append(element); } xml.Append("</TagValueList>"); NPT_LOG_FINE("Parsing TagList..."); NPT_CHECK_LABEL_SEVERE(parser.Parse(xml, node), cleanup); if (!node || !node->AsElementNode()) { NPT_LOG_SEVERE("Invalid node type"); goto cleanup; } didl_partial = node->AsElementNode(); if (didl_partial->GetTag().Compare("TagValueList", true)) { NPT_LOG_SEVERE("Invalid node tag"); goto cleanup; } for (NPT_List<NPT_XmlNode*>::Iterator children = didl_partial->GetChildren().GetFirstItem(); children; children++) { NPT_XmlElementNode* child = (*children)->AsElementNode(); if (!child) continue; tags[child->GetTag()] = *child->GetText(); } return NPT_SUCCESS; cleanup: if (node) delete node; return NPT_FAILURE; }
/*---------------------------------------------------------------------- | PLT_FileMediaServer::SetupDevice +---------------------------------------------------------------------*/ NPT_Result PLT_FileMediaServer::SetupDevice() { // FIXME: hack for now: find the first valid non local ip address // to use in item resources. TODO: we should advertise all ips as // multiple resources instead. NPT_List<NPT_String> ips; PLT_UPnPMessageHelper::GetIPAddresses(ips); if (ips.GetItemCount() == 0) return NPT_ERROR_INTERNAL; // set the base paths for content and album arts m_FileBaseUri = NPT_HttpUrl(*ips.GetFirstItem(), GetPort(), "/content"); m_AlbumArtBaseUri = NPT_HttpUrl(*ips.GetFirstItem(), GetPort(), "/albumart"); return PLT_MediaServer::SetupDevice(); }
/*---------------------------------------------------------------------- | main +---------------------------------------------------------------------*/ int main(int /* argc */, char** argv) { /* parse command line */ ParseCommandLine(argv+1); PLT_UPnP upnp(1900, !Options.broadcast); PLT_DeviceHostReference device( new PLT_FileMediaServer( Options.path, Options.friendly_name?Options.friendly_name:"Platinum UPnP Media Server", false, "SAMEDEVICEGUID", (NPT_UInt16)Options.port) ); NPT_List<NPT_String> list; NPT_CHECK_SEVERE(PLT_UPnPMessageHelper::GetIPAddresses(list)); NPT_String ip = *(list.GetFirstItem()); //device->m_PresentationURL = NPT_HttpUrl(ip, 80, "/").ToString(); device->m_ModelDescription = "Platinum File Media Server"; device->m_ModelURL = "http://www.plutinosoft.com/"; device->m_ModelNumber = "1.0"; device->m_ModelName = "Platinum File Media Server"; device->m_Manufacturer = "Plutinosoft"; device->m_ManufacturerURL = "http://www.plutinosoft.com/"; if (Options.broadcast) device->SetBroadcast(true); upnp.AddDevice(device); NPT_String uuid = device->GetUUID(); NPT_CHECK_SEVERE(upnp.Start()); NPT_LOG_INFO("Press 'q' to quit."); char buf[256]; while (gets(buf)) { if (*buf == 'q') break; } upnp.Stop(); return 0; }
/*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_seek +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_seek(const char* command) { PLT_DeviceDataReference device; GetCurMediaRenderer(device); if (!device.IsNull()) { // remove first part of command ("seek") NPT_String target = command; NPT_List<NPT_String> args = target.Split(" "); if (args.GetItemCount() < 2) return; args.Erase(args.GetFirstItem()); target = NPT_String::Join(args, " "); Seek(device, 0, (target.Find(":")!=-1)?"REL_TIME":"X_DLNA_REL_BYTE", target, NULL); } }
/*---------------------------------------------------------------------- | CUPnP::CUPnP +---------------------------------------------------------------------*/ CUPnP::CUPnP() : m_MediaBrowser(NULL), m_ServerHolder(new CDeviceHostReferenceHolder()), m_RendererHolder(new CRendererReferenceHolder()), m_CtrlPointHolder(new CCtrlPointReferenceHolder()) { // initialize upnp context m_UPnP = new PLT_UPnP(); // keep main IP around m_IP = g_application.getNetworkManager().GetDefaultConnectionAddress().c_str(); NPT_List<NPT_IpAddress> list; if (NPT_SUCCEEDED(PLT_UPnPMessageHelper::GetIPAddresses(list)) && list.GetItemCount()) { m_IP = (*(list.GetFirstItem())).ToString(); } else if(m_IP.IsEmpty()) m_IP = "localhost"; // start upnp monitoring m_UPnP->Start(); }
/*---------------------------------------------------------------------- | PLT_FileMediaServer::Start +---------------------------------------------------------------------*/ NPT_Result PLT_FileMediaServer::Start(PLT_SsdpListenTask* task) { // start our file server m_FileServer = new PLT_HttpServer(m_FileServerPort); NPT_CHECK_SEVERE(m_FileServer->Start()); m_FileServer->AddRequestHandler(m_FileServerHandler, "/", true); // FIXME: hack for now: find the first valid non local ip address // to use in item resources. TODO: we should advertise all ips as // multiple resources instead. NPT_List<NPT_String> ips; PLT_UPnPMessageHelper::GetIPAddresses(ips); if (ips.GetItemCount() == 0) return NPT_ERROR_INTERNAL; // set the base paths for content and album arts m_FileBaseUri = NPT_HttpUrl(*ips.GetFirstItem(), m_FileServer->GetPort(), "/content"); m_AlbumArtBaseUri = NPT_HttpUrl(*ips.GetFirstItem(), m_FileServer->GetPort(), "/albumart"); return PLT_MediaServer::Start(task); }
NPT_Result CHttpServer::SetupResponse(NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response) { NPT_String prefix = NPT_String::Format("PLT_HttpServer::SetupResponse %s request from %s for \"%s\"", (const char*) request.GetMethod(), (const char*) context.GetRemoteAddress().ToString(), (const char*) request.GetUrl().ToString()); NPT_List<NPT_HttpRequestHandler*> handlers = FindRequestHandlers(request); if (handlers.GetItemCount() == 0) return NPT_ERROR_NO_SUCH_ITEM; // ask the handler to setup the response NPT_Result result = (*handlers.GetFirstItem())->SetupResponse(request, context, response); // DLNA compliance UPNPMessageHelper::SetDate(response); if (request.GetHeaders().GetHeader("Accept-Language")) { response.GetHeaders().SetHeader("Content-Language", "en"); } return result; }
/*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_cd +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_cd(const char* command) { NPT_String newobject_id; PLT_StringMap containers; // if command has parameter, push it to stack and return NPT_String id = command; NPT_List<NPT_String> args = id.Split(" "); if (args.GetItemCount() >= 2) { args.Erase(args.GetFirstItem()); id = NPT_String::Join(args, " "); m_CurBrowseDirectoryStack.Push(id); return; } // list current directory to let user choose DoBrowse(); if (!m_MostRecentBrowseResults.IsNull()) { NPT_List<PLT_MediaObject*>::Iterator item = m_MostRecentBrowseResults->GetFirstItem(); while (item) { if ((*item)->IsContainer()) { containers.Put((*item)->m_ObjectID, (*item)->m_Title); } ++item; } newobject_id = ChooseIDFromTable(containers); if (newobject_id.GetLength()) { m_CurBrowseDirectoryStack.Push(newobject_id); } m_MostRecentBrowseResults = NULL; } }
/*---------------------------------------------------------------------- | PLT_FileMediaServer::BuildFromFilePath +---------------------------------------------------------------------*/ PLT_MediaObject* PLT_FileMediaServer::BuildFromFilePath(const NPT_String& filepath, bool with_count /* = true */, NPT_SocketInfo* info /* = NULL */, bool keep_extension_in_title /* = false */) { NPT_String delimiter = m_DirDelimiter; NPT_String root = m_Path; PLT_MediaItemResource resource; PLT_MediaObject* object = NULL; int dir_delim_index; /* make sure this is a valid entry */ /* and retrieve the entry type (directory or file) */ NPT_DirectoryEntryInfo entry_info; if (!ProceedWithEntry(filepath, entry_info)) goto failure; /* find the last directory delimiter */ dir_delim_index = filepath.ReverseFind(delimiter); if (dir_delim_index < 0) goto failure; if (entry_info.type == NPT_FILE_TYPE) { object = new PLT_MediaItem(); /* we need a valid extension to retrieve the mimetype for the protocol info */ int ext_index = filepath.ReverseFind('.'); if (ext_index <= 0 || ext_index < dir_delim_index) { ext_index = filepath.GetLength(); } /* Set the title using the filename for now */ object->m_Title = filepath.SubString(dir_delim_index+1, keep_extension_in_title?filepath.GetLength():ext_index - dir_delim_index -1); if (object->m_Title.GetLength() == 0) goto failure; /* Set the protocol Info from the extension */ const char* ext = ((const char*)filepath) + ext_index; resource.m_ProtocolInfo = PLT_MediaItem::GetProtInfoFromExt(ext); if (resource.m_ProtocolInfo.GetLength() == 0) goto failure; /* Set the resource file size */ resource.m_Size = entry_info.size; /* format the resource URI */ NPT_String url = filepath.SubString(root.GetLength()); // get list of ip addresses NPT_List<NPT_String> ips; NPT_CHECK_LABEL_SEVERE(PLT_UPnPMessageHelper::GetIPAddresses(ips), failure); // if we're passed an interface where we received the request from // move the ip to the top if (info && info->local_address.GetIpAddress().ToString() != "0.0.0.0") { ips.Remove(info->local_address.GetIpAddress().ToString()); ips.Insert(ips.GetFirstItem(), info->local_address.GetIpAddress().ToString()); } // iterate through list and build list of resources NPT_List<NPT_String>::Iterator ip = ips.GetFirstItem(); while (ip) { NPT_HttpUrl uri = m_FileBaseUri; NPT_HttpUrlQuery query; query.AddField("path", url); uri.SetHost(*ip); uri.SetQuery(query.ToString()); //uri.SetPath(uri.GetPath() + url); /* prepend the base URI and url encode it */ //resource.m_Uri = NPT_Uri::Encode(uri.ToString(), NPT_Uri::UnsafeCharsToEncode); resource.m_Uri = uri.ToString(); /* Look to see if a metadatahandler exists for this extension */ PLT_MetadataHandler* handler = NULL; NPT_Result res = NPT_ContainerFind(m_MetadataHandlers, PLT_MetadataHandlerFinder(ext), handler); if (NPT_SUCCEEDED(res) && handler) { /* if it failed loading data, reset the metadatahandler so we don't use it */ if (NPT_SUCCEEDED(handler->LoadFile(filepath))) { /* replace the title with the one from the Metadata */ NPT_String newTitle; if (handler->GetTitle(newTitle) != NULL) { object->m_Title = newTitle; } /* assign description */ handler->GetDescription(object->m_Description.long_description); /* assign album art uri if we haven't yet */ /* prepend the album art base URI and url encode it */ if (object->m_ExtraInfo.album_art_uri.GetLength() == 0) { NPT_HttpUrl uri = m_AlbumArtBaseUri; NPT_HttpUrlQuery query; query.AddField("path", url); uri.SetHost(*ip); uri.SetQuery(query.ToString()); //uri.SetPath(uri.GetPath() + url); object->m_ExtraInfo.album_art_uri = NPT_Uri::PercentEncode(uri.ToString(), NPT_Uri::UnsafeCharsToEncode); } /* duration */ handler->GetDuration((NPT_UInt32&)resource.m_Duration); /* protection */ handler->GetProtection(resource.m_Protection); } } object->m_ObjectClass.type = PLT_MediaItem::GetUPnPClassFromExt(ext); object->m_Resources.Add(resource); ++ip; } } else { object = new PLT_MediaContainer; /* Assign a title for this container */ if (filepath.Compare(root, true) == 0) { object->m_Title = "Root"; } else { object->m_Title = filepath.SubString(dir_delim_index+1, filepath.GetLength() - dir_delim_index -1); if (object->m_Title.GetLength() == 0) goto failure; } /* Get the number of children for this container */ if (with_count) { NPT_Cardinal count = 0; NPT_CHECK_LABEL_SEVERE(GetEntryCount(filepath, count), failure); ((PLT_MediaContainer*)object)->m_ChildrenCount = count; } object->m_ObjectClass.type = "object.container"; } /* is it the root? */ if (filepath.Compare(root, true) == 0) { object->m_ParentID = "-1"; object->m_ObjectID = "0"; } else { /* is the parent path the root? */ if (dir_delim_index == (int)root.GetLength() - 1) { object->m_ParentID = "0"; } else { object->m_ParentID = "0" + delimiter + filepath.SubString(root.GetLength(), dir_delim_index - root.GetLength()); } object->m_ObjectID = "0" + delimiter + filepath.SubString(root.GetLength()); } return object; failure: delete object; return NULL; }
/*---------------------------------------------------------------------- | main +---------------------------------------------------------------------*/ int main(void) { // Create upnp engine PLT_UPnP upnp(1900, true); // Create control point PLT_CtrlPointReference ctrlPoint(new PLT_CtrlPoint()); // Create controller PLT_MicroMediaController controller(ctrlPoint); #ifdef HAS_SERVER // create device PLT_DeviceHostReference server( new PLT_FileMediaServer( "C:\\Music", "Platinum UPnP Media Server")); NPT_String ip; NPT_List<NPT_String> list; if (NPT_SUCCEEDED(PLT_UPnPMessageHelper::GetIPAddresses(list))) { ip = *(list.GetFirstItem()); } server->m_PresentationURL = NPT_HttpUrl(ip, 80, "/").ToString(); server->m_ModelDescription = "Platinum File Media Server"; server->m_ModelURL = "http://www.plutinosoft.com/"; server->m_ModelNumber = "1.0"; server->m_ModelName = "Platinum File Media Server"; server->m_Manufacturer = "Plutinosoft"; server->m_ManufacturerURL = "http://www.plutinosoft.com/"; // add device upnp.AddDevice(server); // remove device uuid from ctrlpoint ctrlPoint->IgnoreUUID(server->GetUUID()); #endif #ifdef HAS_RENDERER // create device PLT_DeviceHostReference renderer( new PLT_MediaRenderer(NULL, "Platinum Media Renderer")); renderer->m_SerialNumber = "308485761705"; renderer->m_ModelDescription = "Platinum Renderer"; renderer->m_ModelName = "Platinum"; renderer->m_Manufacturer = "Plutinosoft"; // add device upnp.AddDevice(renderer); ctrlPoint->IgnoreUUID(renderer->GetUUID()); #endif // add control point to upnp engine and start it upnp.AddCtrlPoint(ctrlPoint); upnp.Start(); #ifdef BROADCAST_EXTRA // tell control point to perform extra broadcast discover every secs // in case our device doesn't support multicast ctrlPoint->Discover(NPT_HttpUrl("255.255.255.255", 1900, "*"), "upnp:rootdevice", 1, 6000); ctrlPoint->Discover(NPT_HttpUrl("239.255.255.250", 1900, "*"), "upnp:rootdevice", 1, 6000); #endif // start to process commands controller.ProcessCommandLoop(); upnp.Stop(); return 0; }
/*---------------------------------------------------------------------- | NPT_NetworkInterface::GetNetworkInterfaces +---------------------------------------------------------------------*/ NPT_Result NPT_NetworkInterface::GetNetworkInterfaces(NPT_List<NPT_NetworkInterface*>& interfaces) { int result = 0; struct ifaddrs * ifaddrsList = NULL; struct ifaddrs * ifaddr = NULL; NPT_Flags flags = 0; result = getifaddrs(&ifaddrsList); if( result != 0 || ifaddrsList == NULL) return NPT_FAILURE; for(ifaddr = ifaddrsList; NULL!= ifaddr; ifaddr = ifaddr->ifa_next) { if(ifaddr->ifa_addr == NULL /*|| ifaddr->ifa_addr->sa_family == AF_INET6*/) continue; // process the flags if ((ifaddr->ifa_flags & IFF_UP) == 0) { // the interface is not up, ignore it continue; } if (ifaddr->ifa_flags & IFF_BROADCAST) { flags |= NPT_NETWORK_INTERFACE_FLAG_BROADCAST; } if (ifaddr->ifa_flags & IFF_LOOPBACK) { flags |= NPT_NETWORK_INTERFACE_FLAG_LOOPBACK; } #if defined(IFF_POINTOPOINT) if (ifaddr->ifa_flags & IFF_POINTOPOINT) { flags |= NPT_NETWORK_INTERFACE_FLAG_POINT_TO_POINT; } #endif // defined(IFF_POINTOPOINT) if (ifaddr->ifa_flags & IFF_PROMISC) { flags |= NPT_NETWORK_INTERFACE_FLAG_PROMISCUOUS; } if (ifaddr->ifa_flags & IFF_MULTICAST) { flags |= NPT_NETWORK_INTERFACE_FLAG_MULTICAST; } NPT_NetworkInterface* interface = NULL; for (NPT_List<NPT_NetworkInterface*>::Iterator iface_iter = interfaces.GetFirstItem(); iface_iter; ++iface_iter) { if ((*iface_iter)->GetName() == (const char*)ifaddr->ifa_name) { interface = *iface_iter; break; } } // create a new interface object if(interface == NULL) interface = new NPT_NetworkInterface(ifaddr->ifa_name, flags); if (interface == NULL) continue; // get the mac address NPT_MacAddress::Type mac_addr_type; unsigned int mac_addr_length = IFHWADDRLEN; switch (ifaddr->ifa_addr->sa_family) { case AF_LOCAL: case AF_INET: #if defined(AF_LINK) case AF_LINK: #endif mac_addr_type = NPT_MacAddress::TYPE_ETHERNET; #if defined(ARPHRD_LOOPBACK) mac_addr_type = NPT_MacAddress::TYPE_LOOPBACK; length = 0; #endif break; #if defined(AF_PPP) case AF_PPP: mac_addr_type = NPT_MacAddress::TYPE_PPP; mac_addr_length = 0; break; #endif #if defined(AF_IEEE80211) case AF_IEEE80211: mac_addr_type = NPT_MacAddress::TYPE_IEEE_802_11; break; #endif default: mac_addr_type = NPT_MacAddress::TYPE_UNKNOWN; mac_addr_length = sizeof(ifaddr->ifa_addr->sa_data); break; } if(interface->GetMacAddress().GetLength() == 0) interface->SetMacAddress(mac_addr_type, (const unsigned char*)ifaddr->ifa_addr->sa_data, mac_addr_length); #if defined(NPT_CONFIG_HAVE_NET_IF_DL_H) if (ifaddr->ifa_addr->sa_family == AF_LINK) { //Refer to LLADDR struct sockaddr_dl * socket_dl = (struct sockaddr_dl *)ifaddr->ifa_addr; interface->SetMacAddress(mac_addr_type, (const unsigned char*)socket_dl->sdl_data+socket_dl->sdl_nlen, socket_dl->sdl_alen); } #endif switch (ifaddr->ifa_addr->sa_family) { case AF_INET: { // primary address NPT_IpAddress primary_address( ntohl(((struct sockaddr_in *)ifaddr->ifa_addr)->sin_addr.s_addr)); // broadcast address NPT_IpAddress broadcast_address; if ((flags & NPT_NETWORK_INTERFACE_FLAG_BROADCAST) && ifaddr->ifa_dstaddr) { broadcast_address.Set(ntohl(((struct sockaddr_in*)ifaddr->ifa_dstaddr)->sin_addr.s_addr)); } // point to point address NPT_IpAddress destination_address; if ((flags & NPT_NETWORK_INTERFACE_FLAG_POINT_TO_POINT) && ifaddr->ifa_dstaddr) { destination_address.Set(ntohl(((struct sockaddr_in*)ifaddr->ifa_dstaddr)->sin_addr.s_addr)); } // netmask NPT_IpAddress netmask(0xFFFFFFFF); if(ifaddr->ifa_netmask) netmask.Set(ntohl(((struct sockaddr_in*)ifaddr->ifa_netmask)->sin_addr.s_addr)); // add the address to the interface NPT_NetworkInterfaceAddress iface_address(primary_address, broadcast_address, destination_address, netmask); interface->AddAddress(iface_address); break; } } // add the interface to the list interfaces.Add(interface); } freeifaddrs(ifaddrsList); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | NPT_NetworkInterface::GetNetworkInterfaces +---------------------------------------------------------------------*/ NPT_Result NPT_NetworkInterface::GetNetworkInterfaces(NPT_List<NPT_NetworkInterface*>& interfaces) { int net = socket(AF_INET, SOCK_DGRAM, 0); // Try to get the config until we have enough memory for it // According to "Unix Network Programming", some implementations // do not return an error when the supplied buffer is too small // so we need to try, increasing the buffer size every time, // until we get the same size twice. We cannot assume success when // the returned size is smaller than the supplied buffer, because // some implementations can return less that the buffer size if // another structure does not fit. unsigned int buffer_size = 4096; // initial guess unsigned int last_size = 0; struct ifconf config; unsigned char* buffer; for (; buffer_size < 65536;) { buffer = new unsigned char[buffer_size]; config.ifc_len = buffer_size; config.ifc_buf = (char*)buffer; if (ioctl(net, SIOCGIFCONF, &config) < 0) { if (errno != EINVAL || last_size != 0) { return NPT_ERROR_BASE_UNIX-errno; } } else { if ((unsigned int)config.ifc_len == last_size) { // same size, we can use the buffer break; } // different size, we need to reallocate last_size = config.ifc_len; } // supply 4096 more bytes more next time around buffer_size += 4096; delete[] buffer; } // iterate over all objects unsigned char *entries; for (entries = buffer; entries < buffer+config.ifc_len;) { struct ifreq* entry = (struct ifreq*)entries; // get the size of the addresses unsigned int address_length; #if defined(NPT_CONFIG_HAVE_SOCKADDR_SA_LEN) address_length = sizeof(struct sockaddr) > entry->ifr_addr.sa_len ? sizeof(sockaddr) : entry->ifr_addr.sa_len; #else switch (entry->ifr_addr.sa_family) { #if defined(AF_INET6) case AF_INET6: address_length = sizeof(struct sockaddr_in6); break; #endif // defined(AF_INET6) default: address_length = sizeof(struct sockaddr); break; } #endif // point to the next entry entries += address_length + sizeof(entry->ifr_name); // ignore anything except AF_INET and AF_LINK addresses if (entry->ifr_addr.sa_family != AF_INET #if defined(AF_LINK) && entry->ifr_addr.sa_family != AF_LINK #endif ) { continue; } // get detailed info about the interface NPT_Flags flags = 0; #if defined(SIOCGIFFLAGS) struct ifreq query = *entry; if (ioctl(net, SIOCGIFFLAGS, &query) < 0) continue; // process the flags if ((query.ifr_flags & IFF_UP) == 0) { // the interface is not up, ignore it continue; } if (query.ifr_flags & IFF_BROADCAST) { flags |= NPT_NETWORK_INTERFACE_FLAG_BROADCAST; } if (query.ifr_flags & IFF_LOOPBACK) { flags |= NPT_NETWORK_INTERFACE_FLAG_LOOPBACK; } #if defined(IFF_POINTOPOINT) if (query.ifr_flags & IFF_POINTOPOINT) { flags |= NPT_NETWORK_INTERFACE_FLAG_POINT_TO_POINT; } #endif // defined(IFF_POINTOPOINT) if (query.ifr_flags & IFF_PROMISC) { flags |= NPT_NETWORK_INTERFACE_FLAG_PROMISCUOUS; } if (query.ifr_flags & IFF_MULTICAST) { flags |= NPT_NETWORK_INTERFACE_FLAG_MULTICAST; } #endif // defined(SIOCGIFFLAGS) // get a pointer to an interface we've looped over before // or create a new one NPT_NetworkInterface* interface = NULL; for (NPT_List<NPT_NetworkInterface*>::Iterator iface_iter = interfaces.GetFirstItem(); iface_iter; ++iface_iter) { if ((*iface_iter)->GetName() == (const char*)entry->ifr_name) { interface = *iface_iter; break; } } if (interface == NULL) { // create a new interface object interface = new NPT_NetworkInterface(entry->ifr_name, flags); // add the interface to the list interfaces.Add(interface); // get the mac address #if defined(SIOCGIFHWADDR) if (ioctl(net, SIOCGIFHWADDR, &query) == 0) { NPT_MacAddress::Type mac_addr_type; unsigned int mac_addr_length = IFHWADDRLEN; switch (query.ifr_addr.sa_family) { #if defined(ARPHRD_ETHER) case ARPHRD_ETHER: mac_addr_type = NPT_MacAddress::TYPE_ETHERNET; break; #endif #if defined(ARPHRD_LOOPBACK) case ARPHRD_LOOPBACK: mac_addr_type = NPT_MacAddress::TYPE_LOOPBACK; length = 0; break; #endif #if defined(ARPHRD_PPP) case ARPHRD_PPP: mac_addr_type = NPT_MacAddress::TYPE_PPP; mac_addr_length = 0; break; #endif #if defined(ARPHRD_IEEE80211) case ARPHRD_IEEE80211: mac_addr_type = NPT_MacAddress::TYPE_IEEE_802_11; break; #endif default: mac_addr_type = NPT_MacAddress::TYPE_UNKNOWN; mac_addr_length = sizeof(query.ifr_addr.sa_data); break; } interface->SetMacAddress(mac_addr_type, (const unsigned char*)query.ifr_addr.sa_data, mac_addr_length); } #endif } switch (entry->ifr_addr.sa_family) { case AF_INET: { // primary address NPT_IpAddress primary_address(ntohl(((struct sockaddr_in*)&entry->ifr_addr)->sin_addr.s_addr)); // broadcast address NPT_IpAddress broadcast_address; #if defined(SIOCGIFBRDADDR) if (flags & NPT_NETWORK_INTERFACE_FLAG_BROADCAST) { if (ioctl(net, SIOCGIFBRDADDR, &query) == 0) { broadcast_address.Set(ntohl(((struct sockaddr_in*)&query.ifr_addr)->sin_addr.s_addr)); } } #endif // point to point address NPT_IpAddress destination_address; #if defined(SIOCGIFDSTADDR) if (flags & NPT_NETWORK_INTERFACE_FLAG_POINT_TO_POINT) { if (ioctl(net, SIOCGIFDSTADDR, &query) == 0) { destination_address.Set(ntohl(((struct sockaddr_in*)&query.ifr_addr)->sin_addr.s_addr)); } } #endif // netmask NPT_IpAddress netmask(0xFFFFFFFF); #if defined(SIOCGIFNETMASK) if (ioctl(net, SIOCGIFNETMASK, &query) == 0) { netmask.Set(ntohl(((struct sockaddr_in*)&query.ifr_addr)->sin_addr.s_addr)); } #endif // add the address to the interface NPT_NetworkInterfaceAddress iface_address( primary_address, broadcast_address, destination_address, netmask); interface->AddAddress(iface_address); break; } #if defined(AF_LINK) && defined(NPT_CONFIG_HAVE_SOCKADDR_DL) case AF_LINK: { struct sockaddr_dl* mac_addr = (struct sockaddr_dl*)&entry->ifr_addr; NPT_MacAddress::Type mac_addr_type = NPT_MacAddress::TYPE_UNKNOWN; switch (mac_addr->sdl_type) { #if defined(IFT_LOOP) case IFT_LOOP: mac_addr_type = NPT_MacAddress::TYPE_LOOPBACK; break; #endif #if defined(IFT_ETHER) case IFT_ETHER: mac_addr_type = NPT_MacAddress::TYPE_ETHERNET; break; #endif #if defined(IFT_PPP) case IFT_PPP: mac_addr_type = NPT_MacAddress::TYPE_PPP; break; #endif } interface->SetMacAddress(mac_addr_type, (const unsigned char*)(&mac_addr->sdl_data[mac_addr->sdl_nlen]), mac_addr->sdl_alen); break; } #endif } } // free resources delete[] buffer; close(net); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_FileMediaServer::BuildFromFilePath +---------------------------------------------------------------------*/ PLT_MediaObject* PLT_FileMediaServer::BuildFromFilePath(const NPT_String& filepath, bool with_count /* = true */, const NPT_SocketAddress* req_local_address /* = NULL */, bool keep_extension_in_title /* = false */) { NPT_String root = m_Path; PLT_MediaItemResource resource; PLT_MediaObject* object = NULL; /* retrieve the entry type (directory or file) */ NPT_FileInfo info; NPT_CHECK_LABEL_FATAL(NPT_File::GetInfo(filepath, &info), failure); if (info.m_Type == NPT_FileInfo::FILE_TYPE_REGULAR) { object = new PLT_MediaItem(); /* Set the title using the filename for now */ object->m_Title = NPT_FilePath::BaseName(filepath, keep_extension_in_title); if (object->m_Title.GetLength() == 0) goto failure; /* Set the protocol Info from the extension */ resource.m_ProtocolInfo = PLT_MediaItem::GetProtInfoFromExt(NPT_FilePath::FileExtension(filepath)); if (resource.m_ProtocolInfo.GetLength() == 0) goto failure; /* Set the resource file size */ resource.m_Size = info.m_Size; /* format the resource URI */ NPT_String url = filepath.SubString(root.GetLength()+1); // get list of ip addresses NPT_List<NPT_String> ips; NPT_CHECK_LABEL_SEVERE(PLT_UPnPMessageHelper::GetIPAddresses(ips), failure); // if we're passed an interface where we received the request from // move the ip to the top if (req_local_address && req_local_address->GetIpAddress().ToString() != "0.0.0.0") { ips.Remove(req_local_address->GetIpAddress().ToString()); ips.Insert(ips.GetFirstItem(), req_local_address->GetIpAddress().ToString()); } // iterate through list and build list of resources NPT_List<NPT_String>::Iterator ip = ips.GetFirstItem(); while (ip) { /* prepend the base URI and url encode it */ //resource.m_Uri = NPT_Uri::Encode(uri.ToString(), NPT_Uri::UnsafeCharsToEncode); resource.m_Uri = BuildResourceUri(m_FileBaseUri, *ip, url); /* Look to see if a metadatahandler exists for this extension */ PLT_MetadataHandler* handler = NULL; NPT_Result res = NPT_ContainerFind( m_MetadataHandlers, PLT_MetadataHandlerFinder(NPT_FilePath::FileExtension(filepath)), handler); if (NPT_SUCCEEDED(res) && handler) { /* if it failed loading data, reset the metadatahandler so we don't use it */ if (NPT_SUCCEEDED(handler->LoadFile(filepath))) { /* replace the title with the one from the Metadata */ NPT_String newTitle; if (handler->GetTitle(newTitle) != NULL) { object->m_Title = newTitle; } /* assign description */ handler->GetDescription(object->m_Description.long_description); /* assign album art uri if we haven't yet */ /* prepend the album art base URI and url encode it */ if (object->m_ExtraInfo.album_art_uri.GetLength() == 0) { object->m_ExtraInfo.album_art_uri = NPT_Uri::PercentEncode(BuildResourceUri(m_AlbumArtBaseUri, *ip, url), NPT_Uri::UnsafeCharsToEncode); } /* duration */ handler->GetDuration(resource.m_Duration); /* protection */ handler->GetProtection(resource.m_Protection); } } object->m_ObjectClass.type = PLT_MediaItem::GetUPnPClassFromExt(NPT_FilePath::FileExtension(filepath)); object->m_Resources.Add(resource); ++ip; } } else { object = new PLT_MediaContainer; /* Assign a title for this container */ if (filepath.Compare(root, true) == 0) { object->m_Title = "Root"; } else { object->m_Title = NPT_FilePath::BaseName(filepath, keep_extension_in_title); if (object->m_Title.GetLength() == 0) goto failure; } /* Get the number of children for this container */ NPT_Cardinal count = 0; if (with_count && NPT_SUCCEEDED(NPT_File::GetCount(filepath, count))) { ((PLT_MediaContainer*)object)->m_ChildrenCount = count; } object->m_ObjectClass.type = "object.container"; } /* is it the root? */ if (filepath.Compare(root, true) == 0) { object->m_ParentID = "-1"; object->m_ObjectID = "0"; } else { NPT_String directory = NPT_FilePath::DirectoryName(filepath); /* is the parent path the root? */ if (directory.GetLength() == root.GetLength()) { object->m_ParentID = "0"; } else { object->m_ParentID = "0" + filepath.SubString(root.GetLength(), directory.GetLength() - root.GetLength()); } object->m_ObjectID = "0" + filepath.SubString(root.GetLength()); } return object; failure: delete object; return NULL; }
/*---------------------------------------------------------------------- | PLT_EventSubscriber::Notify +---------------------------------------------------------------------*/ NPT_Result PLT_EventSubscriber::Notify(NPT_List<PLT_StateVariable*>& vars) { // verify we have eventable variables bool foundVars = false; NPT_XmlElementNode* propertyset = new NPT_XmlElementNode("e", "propertyset"); NPT_CHECK_SEVERE(propertyset->SetNamespaceUri( "e", "urn:schemas-upnp-org:event-1-0")); NPT_List<PLT_StateVariable*>::Iterator var = vars.GetFirstItem(); while (var) { if ((*var)->IsSendingEvents()) { NPT_XmlElementNode* property = new NPT_XmlElementNode("e", "property"); propertyset->AddChild(property); PLT_XmlHelper::AddChildText(property, (*var)->GetName(), (*var)->GetValue()); foundVars = true; } ++var; } // no eventable state variables found! if (foundVars == false) { delete propertyset; return NPT_FAILURE; } // format the body with the xml NPT_String xml; if (NPT_FAILED(PLT_XmlHelper::Serialize(*propertyset, xml))) { delete propertyset; NPT_CHECK_FATAL(NPT_FAILURE); } delete propertyset; // parse the callback url NPT_HttpUrl url(m_CallbackURLs[0]); if (!url.IsValid()) { NPT_CHECK_FATAL(NPT_FAILURE); } // format request NPT_HttpRequest* request = new NPT_HttpRequest(url, "NOTIFY", NPT_HTTP_PROTOCOL_1_1); NPT_HttpEntity* entity; PLT_HttpHelper::SetBody(*request, xml, &entity); // add the extra headers entity->SetContentType("text/xml; charset=\"utf-8\""); PLT_UPnPMessageHelper::SetNT(*request, "upnp:event"); PLT_UPnPMessageHelper::SetNTS(*request, "upnp:propchange"); PLT_UPnPMessageHelper::SetSID(*request, m_SID); PLT_UPnPMessageHelper::SetSeq(*request, m_EventKey); // wrap around sequence to 1 if (++m_EventKey == 0) m_EventKey = 1; // start the task now if not started already if (!m_SubscriberTask) { // TODO: the subscriber task should inform subscriber if // a notification failed to be received so it can be removed // from the list of subscribers inside the device host m_SubscriberTask = new PLT_HttpClientSocketTask(request, true); // short connection time out in case subscriber is not alive NPT_HttpClient::Config config; config.m_ConnectionTimeout = 2000; m_SubscriberTask->SetHttpClientConfig(config); // add initial delay to make sure ctrlpoint receives response to subscription // before our first NOTIFY. Also make sure task is not auto-destroy // since we want to destroy it manually when the subscriber goes away. NPT_TimeInterval delay(0.05f); NPT_CHECK_FATAL(m_TaskManager->StartTask(m_SubscriberTask, NULL /*&delay*/, false)); } else { m_SubscriberTask->AddRequest(request); } return NPT_SUCCESS; }
int SimpleDMR::onAction(const ServiceDecl *serviceDecl, const ActionDecl *actionDecl, AbortableTask *task, const FrontEnd::InterfaceContext *ifctx, const FrontEnd::RequestContext& reqCtx, const NPT_HttpRequest *req, const NPT_List<NPT_String>& inputArgNames, const NPT_List<NPT_String>& inputArgValues, NPT_List<NPT_String>& outputArgValues) { WriteLocker locker(m_stateLock); if (NPT_String::Compare(serviceDecl->serviceId, "urn:upnp-org:serviceId:AVTransport") == 0) { if (NPT_String::Compare(actionDecl->name, "SetAVTransportURI") == 0) { if (inputArgValues.GetItemCount() != 3) { // Invalid Args return 402; } if (inputArgValues.GetFirstItem()->Compare("0") != 0) { // Invalid InstanceID return 718; } NPT_HttpClient httpClient; NPT_HttpRequest req(*inputArgValues.GetItem(1), NPT_HTTP_METHOD_GET, NPT_HTTP_PROTOCOL_1_1); Helper::setupHttpRequest(req); NPT_HttpResponse *resp; NPT_Result nr; HttpClientAbortCallback abortCallback(&httpClient); if (task->registerAbortCallback(&abortCallback)) { nr = httpClient.SendRequest(req, resp); task->unregisterAbortCallback(&abortCallback); } else { return 715; } if (NPT_FAILED(nr)) { return 716; } PtrHolder<NPT_HttpResponse> resp1(resp); if (resp->GetStatusCode() != 200) { return 716; } NPT_HttpHeader *hdrContentType = resp->GetHeaders().GetHeader(NPT_HTTP_HEADER_CONTENT_TYPE); if (!hdrContentType) { return 714; } setVar(DMRVAR_AVTransportURI, *inputArgValues.GetItem(1)); setVar(DMRVAR_AVTransportURIMetaData, *inputArgValues.GetItem(2)); setVar(DMRVAR_CurrentTrackMetaData, *inputArgValues.GetItem(2)); m_callback->doDmrOpen(this, *inputArgValues.GetItem(1), hdrContentType->GetValue(), *inputArgValues.GetItem(2)); return 0; } if (NPT_String::Compare(actionDecl->name, "GetMediaInfo") == 0) { if (inputArgValues.GetItemCount() != 1) { // Invalid Args return 402; } if (inputArgValues.GetFirstItem()->Compare("0") != 0) { // Invalid InstanceID return 718; } *outputArgValues.GetItem(0) = m_avtVars[DMRVAR_NumberOfTracks - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(1) = m_avtVars[DMRVAR_CurrentMediaDuration - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(2) = m_avtVars[DMRVAR_AVTransportURI - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(3) = m_avtVars[DMRVAR_AVTransportURIMetaData - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(4) = m_avtVars[DMRVAR_NextAVTransportURI - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(5) = m_avtVars[DMRVAR_NextAVTransportURIMetaData - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(6) = m_avtVars[DMRVAR_PlaybackStorageMedium - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(7) = m_avtVars[DMRVAR_RecordStorageMedium - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(8) = m_avtVars[DMRVAR_RecordMediumWriteStatus - DMRVAR_BaseIndexAVT]; return 0; } if (NPT_String::Compare(actionDecl->name, "GetTransportInfo") == 0) { if (inputArgValues.GetItemCount() != 1) { // Invalid Args return 402; } if (inputArgValues.GetFirstItem()->Compare("0") != 0) { // Invalid InstanceID return 718; } *outputArgValues.GetItem(0) = m_avtVars[DMRVAR_TransportState - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(1) = m_avtVars[DMRVAR_TransportStatus - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(2) = m_avtVars[DMRVAR_TransportPlaySpeed - DMRVAR_BaseIndexAVT]; return 0; } if (NPT_String::Compare(actionDecl->name, "GetPositionInfo") == 0) { if (inputArgValues.GetItemCount() != 1) { // Invalid Args return 402; } if (inputArgValues.GetFirstItem()->Compare("0") != 0) { // Invalid InstanceID return 718; } *outputArgValues.GetItem(0) = m_avtVars[DMRVAR_CurrentTrack - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(1) = m_avtVars[DMRVAR_CurrentTrackDuration - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(2) = m_avtVars[DMRVAR_CurrentTrackMetaData - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(3) = m_avtVars[DMRVAR_CurrentTrackURI - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(4) = m_avtVars[DMRVAR_RelativeTimePosition - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(5) = m_avtVars[DMRVAR_AbsoluteTimePosition - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(6) = m_avtVars[DMRVAR_RelativeCounterPosition - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(7) = m_avtVars[DMRVAR_AbsoluteCounterPosition - DMRVAR_BaseIndexAVT]; return 0; } if (NPT_String::Compare(actionDecl->name, "GetDeviceCapabilities") == 0) { if (inputArgValues.GetItemCount() != 1) { // Invalid Args return 402; } if (inputArgValues.GetFirstItem()->Compare("0") != 0) { // Invalid InstanceID return 718; } *outputArgValues.GetItem(0) = m_avtVars[DMRVAR_PossiblePlaybackStorageMedia - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(1) = m_avtVars[DMRVAR_PossibleRecordStorageMedia - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(2) = m_avtVars[DMRVAR_PossibleRecordQualityModes - DMRVAR_BaseIndexAVT]; return 0; } if (NPT_String::Compare(actionDecl->name, "GetTransportSettings") == 0) { if (inputArgValues.GetItemCount() != 1) { // Invalid Args return 402; } if (inputArgValues.GetFirstItem()->Compare("0") != 0) { // Invalid InstanceID return 718; } *outputArgValues.GetItem(0) = m_avtVars[DMRVAR_CurrentPlayMode - DMRVAR_BaseIndexAVT]; *outputArgValues.GetItem(1) = m_avtVars[DMRVAR_CurrentRecordQualityMode - DMRVAR_BaseIndexAVT]; return 0; } if (NPT_String::Compare(actionDecl->name, "Stop") == 0) { m_callback->doDmrStop(this); return 0; } if (NPT_String::Compare(actionDecl->name, "Play") == 0) { m_callback->doDmrPlay(this); return 0; } if (NPT_String::Compare(actionDecl->name, "Pause") == 0) { m_callback->doDmrPause(this); return 0; } if (NPT_String::Compare(actionDecl->name, "Seek") == 0) { if (inputArgValues.GetItemCount() != 3) { // Invalid Args return 402; } if (inputArgValues.GetFirstItem()->Compare("0") != 0) { // Invalid InstanceID return 718; } const NPT_String& seekMode = *inputArgValues.GetItem(1); const NPT_String& seekTarget = *inputArgValues.GetItem(2); if (seekMode.Compare("TRACK_NR") == 0) { // TODO: } else if (seekMode.Compare("REL_TIME") == 0) { NPT_UInt64 pos; if (NPT_FAILED(Helper::parseTrackDurationString(seekTarget, pos))) { // Illegal seek target return 711; } m_callback->doDmrSeekTo(this, pos); } else { // Seek mode not supported return 710; } return 0; } if (NPT_String::Compare(actionDecl->name, "Next") == 0) { return 0; } if (NPT_String::Compare(actionDecl->name, "Previous") == 0) { return 0; } return 602; } if (NPT_String::Compare(serviceDecl->serviceId, "urn:upnp-org:serviceId:RenderingControl") == 0) { if (NPT_String::Compare(actionDecl->name, "ListPresets") == 0) { if (inputArgValues.GetItemCount() != 1) { // Invalid Args return 402; } if (inputArgValues.GetFirstItem()->Compare("0") != 0) { // Invalid InstanceID return 702; } *outputArgValues.GetItem(0) = m_rcsVars[DMRVAR_PresetNameList - DMRVAR_BaseIndexRCS]; return 0; } if (NPT_String::Compare(actionDecl->name, "SelectPreset") == 0) { return 0; } if (NPT_String::Compare(actionDecl->name, "GetMute") == 0) { if (inputArgValues.GetItemCount() != 2) { // Invalid Args return 402; } if (inputArgValues.GetFirstItem()->Compare("0") != 0) { // Invalid InstanceID return 702; } *outputArgValues.GetItem(0) = m_rcsVars[DMRVAR_Mute - DMRVAR_BaseIndexRCS]; return 0; } if (NPT_String::Compare(actionDecl->name, "SetMute") == 0) { if (inputArgValues.GetItemCount() != 3) { // Invalid Args return 402; } if (inputArgValues.GetFirstItem()->Compare("0") != 0) { // Invalid InstanceID return 702; } const NPT_String& desiredMute = *inputArgValues.GetItem(2); m_callback->doDmrSetMute(this, desiredMute.Compare("true", true) == 0 || desiredMute.Compare("1") == 0); return 0; } if (NPT_String::Compare(actionDecl->name, "GetVolume") == 0) { if (inputArgValues.GetItemCount() != 2) { // Invalid Args return 402; } if (inputArgValues.GetFirstItem()->Compare("0") != 0) { // Invalid InstanceID return 702; } *outputArgValues.GetItem(0) = m_rcsVars[DMRVAR_Volume - DMRVAR_BaseIndexRCS]; return 0; } if (NPT_String::Compare(actionDecl->name, "SetVolume") == 0) { if (inputArgValues.GetItemCount() != 3) { // Invalid Args return 402; } if (inputArgValues.GetFirstItem()->Compare("0") != 0) { // Invalid InstanceID return 702; } const NPT_String& desiredVolume = *inputArgValues.GetItem(2); int volume; if (NPT_FAILED(NPT_ParseInteger(desiredVolume, volume))) { // Invalid Args return 402; } m_callback->doDmrSetVolume(this, volume); return 0; } return 602; } if (NPT_String::Compare(serviceDecl->serviceId, "urn:upnp-org:serviceId:ConnectionManager") == 0) { if (NPT_String::Compare(actionDecl->name, "GetProtocolInfo") == 0) { NPT_String v; if (getStateValue(serviceDecl->serviceId, "SourceProtocolInfo", v)) { *outputArgValues.GetItem(0) = v; } if (getStateValue(serviceDecl->serviceId, "SinkProtocolInfo", v)) { *outputArgValues.GetItem(1) = v; } return 0; } if (NPT_String::Compare(actionDecl->name, "GetCurrentConnectionIDs") == 0) { NPT_String v; if (getStateValue(serviceDecl->serviceId, "SourceProtocolInfo", v)) { *outputArgValues.GetItem(0) = v; } return 0; } if (NPT_String::Compare(actionDecl->name, "GetCurrentConnectionInfo") == 0) { *outputArgValues.GetItem(0) = "0"; *outputArgValues.GetItem(1) = "0"; *outputArgValues.GetItem(2) = ""; *outputArgValues.GetItem(3) = ""; *outputArgValues.GetItem(4) = "-1"; *outputArgValues.GetItem(5) = "Input"; // or "Output"? WTF! *outputArgValues.GetItem(6) = "OK"; return 0; } return 602; } return 501; }
/*---------------------------------------------------------------------- | PLT_FileMediaServer::OnBrowseDirectChildren +---------------------------------------------------------------------*/ NPT_Result PLT_FileMediaServer::OnBrowseDirectChildren(PLT_ActionReference& action, const char* object_id, const NPT_HttpRequestContext& context) { /* locate the file from the object ID */ NPT_String dir; if (NPT_FAILED(GetFilePath(object_id, dir))) { /* error */ NPT_LOG_WARNING("PLT_FileMediaServer::OnBrowse - ObjectID not found."); action->SetError(701, "No Such Object."); return NPT_FAILURE; } /* retrieve the item type */ NPT_FileInfo info; NPT_Result res = NPT_File::GetInfo(dir, &info); if (NPT_FAILED(res)) { /* Object does not exist */ NPT_LOG_WARNING_1("PLT_FileMediaServer::OnBrowse - BROWSEDIRECTCHILDREN failed for item %s", dir.GetChars()); action->SetError(800, "Can't retrieve info " + dir); return NPT_FAILURE; } if (info.m_Type != NPT_FileInfo::FILE_TYPE_DIRECTORY) { /* error */ NPT_LOG_WARNING("PLT_FileMediaServer::OnBrowse - BROWSEDIRECTCHILDREN not allowed on an item."); action->SetError(710, "item is not a container."); return NPT_FAILURE; } NPT_String filter; NPT_String startingInd; NPT_String reqCount; NPT_CHECK_SEVERE(action->GetArgumentValue("Filter", filter)); NPT_CHECK_SEVERE(action->GetArgumentValue("StartingIndex", startingInd)); NPT_CHECK_SEVERE(action->GetArgumentValue("RequestedCount", reqCount)); NPT_UInt32 start_index, req_count; if (NPT_FAILED(startingInd.ToInteger(start_index)) || NPT_FAILED(reqCount.ToInteger(req_count))) { action->SetError(412, "Precondition failed"); return NPT_FAILURE; } NPT_List<NPT_String> entries; res = NPT_File::ListDirectory(dir, entries, 0, 0); if (NPT_FAILED(res)) { NPT_LOG_WARNING_1("PLT_FileMediaServer::OnBrowseDirectChildren - failed to open dir %s", (const char*) dir); return res; } unsigned long cur_index = 0; unsigned long num_returned = 0; unsigned long total_matches = 0; NPT_String didl = didl_header; PLT_MediaObjectReference item; for (NPT_List<NPT_String>::Iterator it = entries.GetFirstItem(); it; ++it) { NPT_String& filename = *it; item = BuildFromFilePath( NPT_FilePath::Create(dir, filename), true, &context.GetLocalAddress()); if (!item.IsNull()) { if ((cur_index >= start_index) && ((num_returned < req_count) || (req_count == 0))) { NPT_String tmp; NPT_CHECK_SEVERE(PLT_Didl::ToDidl(*item.AsPointer(), filter, tmp)); didl += tmp; num_returned++; } cur_index++; total_matches++; } }; didl += didl_footer; NPT_CHECK_SEVERE(action->SetArgumentValue("Result", didl)); NPT_CHECK_SEVERE(action->SetArgumentValue("NumberReturned", NPT_String::FromInteger(num_returned))); NPT_CHECK_SEVERE(action->SetArgumentValue("TotalMatches", NPT_String::FromInteger(total_matches))); // 0 means we don't know how many we have but most browsers don't like that!! NPT_CHECK_SEVERE(action->SetArgumentValue("UpdateId", "1")); return NPT_SUCCESS; }