/*---------------------------------------------------------------------- | PLT_StateVariable::Find +---------------------------------------------------------------------*/ PLT_StateVariable* PLT_StateVariable::Find(NPT_List<PLT_StateVariable*>& vars, const char* name) { PLT_StateVariable* stateVariable = NULL; NPT_ContainerFind(vars, PLT_StateVariableNameFinder(name), stateVariable); return stateVariable; }
/*---------------------------------------------------------------------- | PLT_MediaBrowser::OnDeviceRemoved +---------------------------------------------------------------------*/ NPT_Result PLT_MediaBrowser::OnDeviceRemoved(PLT_DeviceDataReference& device) { PLT_DeviceDataReference data; { NPT_AutoLock lock(m_MediaServers); // only release if we have kept it around NPT_String uuid = device->GetUUID(); // is it a new device? if (NPT_FAILED(NPT_ContainerFind(m_MediaServers, PLT_DeviceDataFinder(uuid), data))) { NPT_LOG_WARNING_1("Device (%s) not found in our list!", (const char*)uuid); return NPT_FAILURE; } NPT_LOG_FINE("Device Removed:"); device->ToLog(NPT_LOG_LEVEL_FINE); m_MediaServers.Remove(device); } if (m_Listener) { m_Listener->OnMSAddedRemoved(device, 0); } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_MediaBrowser::OnDeviceRemoved +---------------------------------------------------------------------*/ NPT_Result PLT_MediaBrowser::OnDeviceRemoved(PLT_DeviceDataReference& device) { if (!device->GetType().StartsWith("urn:schemas-upnp-org:device:MediaServer")) return NPT_FAILURE; { NPT_AutoLock lock(m_MediaServers); // only release if we have kept it around PLT_DeviceDataReference data; NPT_String uuid = device->GetUUID(); // Have we seen that device? if (NPT_FAILED(NPT_ContainerFind(m_MediaServers, PLT_DeviceDataFinder(uuid), data))) { NPT_LOG_WARNING_1("Device (%s) not found in our list!", (const char*)uuid); return NPT_FAILURE; } NPT_LOG_FINE_1("Device Removed: %s", (const char*)*device); m_MediaServers.Remove(device); } if (m_Delegate) { m_Delegate->OnMSRemoved(device); } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_DeviceData::FindServiceByType +---------------------------------------------------------------------*/ NPT_Result PLT_DeviceData::FindServiceByType(const char* type, PLT_Service*& service) { return NPT_ContainerFind(m_Services, PLT_ServiceTypeFinder(type), service); }
/*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_info +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_info() { NPT_String object_id; PLT_StringMap tracks; PLT_DeviceDataReference device; // issue a browse DoBrowse(); if (!m_MostRecentBrowseResults.IsNull()) { // create a map item id -> item title NPT_List<PLT_MediaObject*>::Iterator item = m_MostRecentBrowseResults->GetFirstItem(); while (item) { if (!(*item)->IsContainer()) { tracks.Put((*item)->m_ObjectID, (*item)->m_Title); } ++item; } // let the user choose which one object_id = ChooseIDFromTable(tracks); if (object_id.GetLength()) { // issue a browse with metadata DoBrowse(object_id, true); // look back for the PLT_MediaItem in the results PLT_MediaObject* track = NULL; if (!m_MostRecentBrowseResults.IsNull() && NPT_SUCCEEDED(NPT_ContainerFind(*m_MostRecentBrowseResults, PLT_MediaItemIDFinder(object_id), track))) { // display info printf("Title: %s \n", track->m_Title.GetChars()); printf("OjbectID: %s\n", track->m_ObjectID.GetChars()); printf("Class: %s\n", track->m_ObjectClass.type.GetChars()); printf("Creator: %s\n", track->m_Creator.GetChars()); printf("Date: %s\n", track->m_Date.GetChars()); for (NPT_List<PLT_AlbumArtInfo>::Iterator iter = track->m_ExtraInfo.album_arts.GetFirstItem(); iter; iter++) { printf("Art Uri: %s\n", (*iter).uri.GetChars()); printf("Art Uri DLNA Profile: %s\n", (*iter).dlna_profile.GetChars()); } for (NPT_Cardinal i=0;i<track->m_Resources.GetItemCount(); i++) { printf("\tResource[%d].uri: %s\n", i, track->m_Resources[i].m_Uri.GetChars()); printf("\tResource[%d].profile: %s\n", i, track->m_Resources[i].m_ProtocolInfo.ToString().GetChars()); printf("\tResource[%d].duration: %d\n", i, track->m_Resources[i].m_Duration); printf("\tResource[%d].size: %d\n", i, (int)track->m_Resources[i].m_Size); printf("\n"); } printf("Didl: %s\n", (const char*)track->m_Didl); } else { printf("Couldn't find the track\n"); } } m_MostRecentBrowseResults = NULL; } }
/*---------------------------------------------------------------------- | PLT_DeviceData::FindServiceById +---------------------------------------------------------------------*/ NPT_Result PLT_DeviceData::FindServiceById(const char* id, PLT_Service*& service) { return NPT_ContainerFind(m_Services, PLT_ServiceIDFinder(id), service); }
/*---------------------------------------------------------------------- | CMediaCrawler::ProcessFileRequest +---------------------------------------------------------------------*/ NPT_Result CMediaCrawler::ProcessFileRequest(NPT_HttpRequest& request, NPT_HttpResponse& response, NPT_SocketInfo& info) { NPT_COMPILER_UNUSED(info); NPT_LOG_FINE("CMediaCrawler::ProcessFileRequest Received Request:"); PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, &request); if (request.GetMethod().Compare("GET") && request.GetMethod().Compare("HEAD")) { response.SetStatus(500, "Internal Server Error"); return NPT_SUCCESS; } // add the user agent header, some stupid media servers like YME needs it if (!request.GetHeaders().GetHeader(NPT_HTTP_HEADER_USER_AGENT)) { request.GetHeaders().SetHeader(NPT_HTTP_HEADER_USER_AGENT, "Platinum/" PLT_PLATINUM_VERSION_STRING); } // File requested NPT_HttpResponse* out_response = NULL; NPT_HttpUrlQuery query(request.GetUrl().GetQuery()); const char* url = query.GetField("url"); if (url) { // look for handler CStreamHandler* handler = NULL; NPT_ContainerFind(m_StreamHandlers, CStreamHandlerFinder(NULL, url), handler); if (handler && NPT_SUCCEEDED(handler->ProcessFileRequest(request, out_response)) && out_response) { // copy response code and reason response.SetStatus(out_response->GetStatusCode(), out_response->GetReasonPhrase()); // copy headers NPT_List<NPT_HttpHeader*>::Iterator headers = out_response->GetHeaders().GetHeaders().GetFirstItem(); while (headers) { response.GetHeaders().SetHeader((*headers)->GetName(), (*headers)->GetValue()); ++headers; } response.SetEntity(new NPT_HttpEntity(response.GetHeaders())); // update inputstream NPT_HttpEntity* out_entity; if ((out_entity = out_response->GetEntity()) != NULL) { NPT_InputStreamReference inputstream; out_entity->GetInputStream(inputstream); if (!inputstream.IsNull()) { // set the stream but do not update the content length response.GetEntity()->SetInputStream(inputstream, false); } } delete out_response; return NPT_SUCCESS; } } response.SetStatus(404, "File Not Found"); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_DeviceData::FindEmbeddedDeviceByType +---------------------------------------------------------------------*/ NPT_Result PLT_DeviceData::FindEmbeddedDeviceByType(const char* type, PLT_DeviceDataReference& device) { return NPT_ContainerFind(m_EmbeddedDevices, PLT_DeviceDataFinderByType(type), device); }
/*---------------------------------------------------------------------- | PLT_EventSubscriber::FindCallbackURL +---------------------------------------------------------------------*/ NPT_Result PLT_EventSubscriber::FindCallbackURL(const char* callback_url) { NPT_String res; return NPT_ContainerFind(m_CallbackURLs, NPT_StringFinder(callback_url), res); }
/*---------------------------------------------------------------------- | PLT_MediaBrowser::OnDeviceAdded +---------------------------------------------------------------------*/ NPT_Result PLT_MediaBrowser::OnDeviceAdded(PLT_DeviceDataReference& device) { // verify the device implements the function we need PLT_Service* serviceCDS; PLT_Service* serviceCMR; NPT_String type; if (!device->GetType().StartsWith("urn:schemas-upnp-org:device:MediaServer")) return NPT_FAILURE; type = "urn:schemas-upnp-org:service:ContentDirectory:*"; if (NPT_FAILED(device->FindServiceByType(type, serviceCDS))) { NPT_LOG_WARNING_2("Service %s not found in device \"%s\"", type.GetChars(), device->GetFriendlyName().GetChars()); return NPT_FAILURE; } else { // in case it's a newer upnp implementation, force to 1 serviceCDS->ForceVersion(1); } type = "urn:schemas-upnp-org:service:ConnectionManager:*"; if (NPT_FAILED(device->FindServiceByType(type, serviceCMR))) { NPT_LOG_WARNING_2("Service %s not found in device \"%s\"", type.GetChars(), device->GetFriendlyName().GetChars()); return NPT_FAILURE; } else { // in case it's a newer upnp implementation, force to 1 serviceCMR->ForceVersion(1); } { NPT_AutoLock lock(m_MediaServers); PLT_DeviceDataReference data; NPT_String uuid = device->GetUUID(); // is it a new device? if (NPT_SUCCEEDED(NPT_ContainerFind(m_MediaServers, PLT_DeviceDataFinder(uuid), data))) { NPT_LOG_WARNING_1("Device (%s) is already in our list!", (const char*)uuid); return NPT_FAILURE; } NPT_LOG_FINE_1("Device Found: %s", (const char*)*device); m_MediaServers.Add(device); } if (m_Delegate && m_Delegate->OnMSAdded(device)) { m_CtrlPoint->Subscribe(serviceCDS); m_CtrlPoint->Subscribe(serviceCMR); } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_DeviceData::FindServiceByName +---------------------------------------------------------------------*/ NPT_Result PLT_DeviceData::FindServiceByName(const char* name, PLT_Service*& service) { // do not try to find it within embedded devices, since different // embedded devices could have an identical service return NPT_ContainerFind(m_Services, PLT_ServiceNameFinder(name), service); }
/*---------------------------------------------------------------------- | PLT_DeviceData::FindServiceByEventSubURI +---------------------------------------------------------------------*/ NPT_Result PLT_DeviceData::FindServiceByEventSubURI(const char* uri, PLT_Service*& service) { if (NPT_SUCCEEDED(NPT_ContainerFind(m_Services, PLT_ServiceEventSubURLFinder(uri), service))) { return NPT_SUCCESS; } for (int i=0; i < (int)m_EmbeddedDevices.GetItemCount(); i++) { if (NPT_SUCCEEDED(NPT_ContainerFind(m_EmbeddedDevices[i]->m_Services, PLT_ServiceEventSubURLFinder(uri), service))) return NPT_SUCCESS; } return NPT_FAILURE; }
/*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_open +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_open() { NPT_String object_id; PLT_StringMap tracks; PLT_DeviceDataReference device; GetCurMediaRenderer(device); if (!device.IsNull()) { // get the protocol info to try to see in advance if a track would play on the device // issue a browse DoBrowse(); if (!m_MostRecentBrowseResults.IsNull()) { // create a map item id -> item title NPT_List<PLT_MediaObject*>::Iterator item = m_MostRecentBrowseResults->GetFirstItem(); while (item) { if (!(*item)->IsContainer()) { tracks.Put((*item)->m_ObjectID, (*item)->m_Title); } ++item; } // let the user choose which one object_id = ChooseIDFromTable(tracks); if (object_id.GetLength()) { // look back for the PLT_MediaItem in the results PLT_MediaObject* track = NULL; if (NPT_SUCCEEDED(NPT_ContainerFind(*m_MostRecentBrowseResults, PLT_MediaItemIDFinder(object_id), track))) { if (track->m_Resources.GetItemCount() > 0) { // look for best resource to use by matching each resource to a sink advertised by renderer NPT_Cardinal resource_index = 0; if (NPT_FAILED(FindBestResource(device, *track, resource_index))) { printf("No matching resource\n"); return; } // invoke the setUri printf("Issuing SetAVTransportURI with url=%s & didl=%s", (const char*)track->m_Resources[resource_index].m_Uri, (const char*)track->m_Didl); SetAVTransportURI(device, 0, track->m_Resources[resource_index].m_Uri, track->m_Didl, NULL); } else { printf("Couldn't find the proper resource\n"); } } else { printf("Couldn't find the track\n"); } } m_MostRecentBrowseResults = NULL; } } }
/*---------------------------------------------------------------------- | PLT_MediaBrowser::FindServer +---------------------------------------------------------------------*/ NPT_Result PLT_MediaBrowser::FindServer(const char* uuid, PLT_DeviceDataReference& device) { NPT_AutoLock lock(m_MediaServers); if (NPT_FAILED(NPT_ContainerFind(m_MediaServers, PLT_DeviceDataFinder(uuid), device))) { NPT_LOG_FINE_1("Device (%s) not found in our list of servers", (const char*)uuid); return NPT_FAILURE; } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_FileMediaServer::OnAlbumArtRequest +---------------------------------------------------------------------*/ NPT_Result PLT_FileMediaServer::OnAlbumArtRequest(NPT_HttpResponse& response, NPT_String file_path) { NPT_LargeSize total_len; NPT_File file(file_path); NPT_InputStreamReference stream; // prevent hackers from accessing files outside of our root if ((file_path.Find("/..") >= 0) || (file_path.Find("\\..") >= 0)) { return NPT_FAILURE; } if (NPT_FAILED(file.Open(NPT_FILE_OPEN_MODE_READ)) || NPT_FAILED(file.GetInputStream(stream)) || NPT_FAILED(stream->GetSize(total_len)) || (total_len == 0)) { goto filenotfound; } else { NPT_String extension = NPT_FilePath::FileExtension(file_path); if (extension.GetLength() == 0) { goto filenotfound; } PLT_MetadataHandler* metadataHandler = NULL; char* caData; int caDataLen; NPT_Result ret = NPT_ContainerFind(m_MetadataHandlers, PLT_MetadataHandlerFinder(extension), metadataHandler); if (NPT_FAILED(ret) || metadataHandler == NULL) { goto filenotfound; } // load the metadatahandler and read the cover art if (NPT_FAILED(metadataHandler->Load(*stream)) || NPT_FAILED(metadataHandler->GetCoverArtData(caData, caDataLen))) { goto filenotfound; } PLT_HttpHelper::SetContentType(response, "application/octet-stream"); PLT_HttpHelper::SetBody(response, caData, caDataLen); delete caData; return NPT_SUCCESS; } filenotfound: response.SetStatus(404, "File Not Found"); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_MediaBrowser::OnDeviceAdded +---------------------------------------------------------------------*/ NPT_Result PLT_MediaBrowser::OnDeviceAdded(PLT_DeviceDataReference& device) { // verify the device implements the function we need PLT_Service* serviceCDS; PLT_Service* serviceCMR; NPT_String type; type = "urn:schemas-upnp-org:service:ContentDirectory:1"; if (NPT_FAILED(device->FindServiceByType(type, serviceCDS))) { NPT_LOG_WARNING_1("Service %s not found", (const char*)type); return NPT_FAILURE; } type = "urn:schemas-upnp-org:service:ConnectionManager:1"; if (NPT_FAILED(device->FindServiceByType(type, serviceCMR))) { NPT_LOG_WARNING_1("Service %s not found", (const char*)type); return NPT_FAILURE; } { NPT_AutoLock lock(m_MediaServers); PLT_DeviceDataReference data; NPT_String uuid = device->GetUUID(); // is it a new device? if (NPT_SUCCEEDED(NPT_ContainerFind(m_MediaServers, PLT_DeviceDataFinder(uuid), data))) { NPT_LOG_WARNING_1("Device (%s) is already in our list!", (const char*)uuid); return NPT_FAILURE; } NPT_LOG_FINE("Device Found:"); device->ToLog(NPT_LOG_LEVEL_FINE); m_MediaServers.Add(device); } if (m_Listener) { m_Listener->OnMSAddedRemoved(device, 1); } m_CtrlPoint->Subscribe(serviceCDS); m_CtrlPoint->Subscribe(serviceCMR); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_DeviceData::FindEmbeddedDeviceByType +---------------------------------------------------------------------*/ NPT_Result PLT_DeviceData::FindEmbeddedDeviceByType(const char* type, PLT_DeviceDataReference& device) { NPT_Result res = NPT_ContainerFind(m_EmbeddedDevices, PLT_DeviceDataFinderByType(type), device); if (NPT_SUCCEEDED(res)) return res; for (int i=0; i<(int)m_EmbeddedDevices.GetItemCount(); i++) { res = m_EmbeddedDevices[i]->FindEmbeddedDeviceByType( type, device); if (NPT_SUCCEEDED(res)) return res; } return NPT_FAILURE; }
/*---------------------------------------------------------------------- | PLT_MediaBrowser::OnEventNotify +---------------------------------------------------------------------*/ NPT_Result PLT_MediaBrowser::OnEventNotify(PLT_Service* service, NPT_List<PLT_StateVariable*>* vars) { PLT_DeviceDataReference data; { NPT_AutoLock lock(m_MediaServers); NPT_String uuid = service->GetDevice()->GetUUID(); if (NPT_FAILED(NPT_ContainerFind(m_MediaServers, PLT_DeviceDataFinder(uuid), data))) { NPT_LOG_WARNING_1("Device (%s) not found in our list!", (const char*)uuid); return NPT_FAILURE; } } if (m_Listener) m_Listener->OnMSStateVariablesChanged(service, vars); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_MediaController::OnDeviceAdded +---------------------------------------------------------------------*/ NPT_Result PLT_MediaController::OnDeviceAdded(PLT_DeviceDataReference& device) { PLT_DeviceDataReference data; NPT_String uuid = device->GetUUID(); // is it a new device? if (NPT_SUCCEEDED(NPT_ContainerFind(m_MediaRenderers, PLT_DeviceDataFinder(uuid), data))) { NPT_LOG_FINE_1("Device (%s) is already in our list!", (const char*)uuid); return NPT_FAILURE; } NPT_LOG_FINE("Device Found:"); device->ToLog(NPT_LOG_LEVEL_FINE); // verify the device implements the function we need PLT_Service* serviceAVT; PLT_Service* serviceCMR; NPT_String type; type = "urn:schemas-upnp-org:service:AVTransport:1"; if (NPT_FAILED(device->FindServiceByType(type, serviceAVT))) { NPT_LOG_FINE_1("Service %s not found", (const char*)type); return NPT_FAILURE; } type = "urn:schemas-upnp-org:service:ConnectionManager:1"; if (NPT_FAILED(device->FindServiceByType(type, serviceCMR))) { NPT_LOG_FINE_1("Service %s not found", (const char*)type); return NPT_FAILURE; } m_MediaRenderers.Add(device); if (m_Listener) { m_Listener->OnMRAddedRemoved(device, 1); } // subscribe to AVT eventing m_CtrlPoint->Subscribe(serviceAVT); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_DeviceData::FindServiceByEventSubURL +---------------------------------------------------------------------*/ NPT_Result PLT_DeviceData::FindServiceByEventSubURL(const char* url, PLT_Service*& service, bool recursive /* = false */) { NPT_Result res = NPT_ContainerFind(m_Services, PLT_ServiceEventSubURLFinder(url), service); if (NPT_SUCCEEDED(res)) return res; if (recursive) { for (int i=0; i<(int)m_EmbeddedDevices.GetItemCount(); i++) { res = m_EmbeddedDevices[i]->FindServiceByEventSubURL( url, service, recursive); if (NPT_SUCCEEDED(res)) return res; } } return NPT_FAILURE; }
/*---------------------------------------------------------------------- | PLT_MediaBrowser::OnActionResponse +---------------------------------------------------------------------*/ NPT_Result PLT_MediaBrowser::OnActionResponse(NPT_Result res, PLT_ActionReference& action, void* userdata) { PLT_DeviceDataReference device; { NPT_AutoLock lock(m_MediaServers); NPT_String uuid = action->GetActionDesc()->GetService()->GetDevice()->GetUUID(); if (NPT_FAILED(NPT_ContainerFind(m_MediaServers, PLT_DeviceDataFinder(uuid), device))) { NPT_LOG_WARNING_1("Device (%s) not found in our list of servers", (const char*)uuid); return NPT_FAILURE; } } NPT_String actionName = action->GetActionDesc()->GetName(); // Browse action response if (actionName.Compare("Browse", true) == 0) { return OnBrowseResponse(res, device, action, userdata); } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_FileMediaServer::OnAlbumArtRequest +---------------------------------------------------------------------*/ NPT_Result PLT_FileMediaServer::OnAlbumArtRequest(NPT_String filepath, NPT_HttpResponse& response) { NPT_Size total_len; NPT_File file(filepath); NPT_InputStreamReference stream; if (NPT_FAILED(file.Open(NPT_FILE_OPEN_MODE_READ)) || NPT_FAILED(file.GetInputStream(stream)) || NPT_FAILED(stream->GetSize(total_len)) || (total_len == 0)) { goto filenotfound; } else { const char* extension = PLT_MediaItem::GetExtFromFilePath(filepath, m_DirDelimiter); if (extension == NULL) { goto filenotfound; } PLT_MetadataHandler* metadataHandler = NULL; char* caData; int caDataLen; NPT_Result ret = NPT_ContainerFind(m_MetadataHandlers, PLT_MetadataHandlerFinder(extension), metadataHandler); if (NPT_FAILED(ret) || metadataHandler == NULL) { goto filenotfound; } // load the metadatahandler and read the cover art if (NPT_FAILED(metadataHandler->Load(*stream)) || NPT_FAILED(metadataHandler->GetCoverArtData(caData, caDataLen))) { goto filenotfound; } PLT_HttpHelper::SetContentType(&response, "application/octet-stream"); PLT_HttpHelper::SetBody(&response, caData, caDataLen); delete caData; return NPT_SUCCESS; } filenotfound: response.SetStatus(404, "File Not Found"); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | CMediaCrawler::OnBrowseDevice +---------------------------------------------------------------------*/ NPT_Result CMediaCrawler::OnBrowseDevice(PLT_ActionReference& action, const char* server_uuid, const char* server_object_id, NPT_SocketInfo* info /* = NULL */) { NPT_Result res; PLT_DeviceDataReference device; { // look for device first const NPT_Lock<PLT_DeviceDataReferenceList>& devices = GetMediaServers(); //NPT_AutoLock lock(devices); if (NPT_FAILED(NPT_ContainerFind(devices, PLT_DeviceDataFinder(server_uuid), device))) { /* error */ NPT_LOG_WARNING("CMediaCrawler::OnBrowseDevice - device not found."); action->SetError(701, "No Such Object."); return NPT_FAILURE; } } // look for args and convert them NPT_String browseFlagValue; NPT_String startingInd; NPT_String reqCount; NPT_String filter; NPT_String sort; NPT_CHECK_SEVERE(action->GetArgumentValue("BrowseFlag", browseFlagValue)); NPT_CHECK_SEVERE(action->GetArgumentValue("StartingIndex", startingInd)); NPT_CHECK_SEVERE(action->GetArgumentValue("RequestedCount", reqCount)); NPT_CHECK_SEVERE(action->GetArgumentValue("Filter", filter)); NPT_CHECK_SEVERE(action->GetArgumentValue("SortCriteria", sort)); unsigned long start_index, req_count; if (NPT_FAILED(startingInd.ToInteger(start_index)) || NPT_FAILED(reqCount.ToInteger(req_count))) { return NPT_FAILURE; } // create a container for our result // this will be filled in by OnBrowseResponse CMediaCrawlerBrowseInfoReference browse_info(new CMediaCrawlerBrowseInfo()); browse_info->shared_var.SetValue(0); // send off the browse packet. Note that this will // not block. The shared variable is used to block // until the response has been received. res = Browse(device, server_object_id, start_index, req_count, (browseFlagValue == "BrowseMetadata")?1:0, filter, sort, new CMediaCrawlerBrowseInfoReference(browse_info)); NPT_CHECK_SEVERE(res); // wait 30 secs for response res = browse_info->shared_var.WaitUntilEquals(1, 30000); NPT_CHECK_SEVERE(res); // did the browse fail? if (NPT_FAILED(browse_info->res)) { action->SetError(browse_info->code, ""); return NPT_FAILURE; } action->SetArgumentValue("Result", UpdateDidl(server_uuid, browse_info->didl, info)); action->SetArgumentValue("NumberReturned", browse_info->nr); action->SetArgumentValue("TotalMatches", browse_info->tm); action->SetArgumentValue("UpdateId", browse_info->uid); action->SetArgumentValue("ObjectID", FormatObjectId(server_uuid, browse_info->object_id)); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_MediaController::OnDeviceAdded +---------------------------------------------------------------------*/ NPT_Result PLT_MediaController::OnDeviceAdded(PLT_DeviceDataReference& device) { // verify the device implements the function we need PLT_Service* serviceAVT = NULL; PLT_Service* serviceCMR; PLT_Service* serviceRC; NPT_String type; if (!device->GetType().StartsWith("urn:schemas-upnp-org:device:MediaRenderer")) return NPT_FAILURE; // optional service type = "urn:schemas-upnp-org:service:AVTransport:*"; if (NPT_SUCCEEDED(device->FindServiceByType(type, serviceAVT))) { // in case it's a newer upnp implementation, force to 1 NPT_LOG_FINE_1("Service %s found", (const char*)type); serviceAVT->ForceVersion(1); } // required services type = "urn:schemas-upnp-org:service:ConnectionManager:*"; if (NPT_FAILED(device->FindServiceByType(type, serviceCMR))) { NPT_LOG_FINE_1("Service %s not found", (const char*)type); return NPT_FAILURE; } else { // in case it's a newer upnp implementation, force to 1 serviceCMR->ForceVersion(1); } type = "urn:schemas-upnp-org:service:RenderingControl:*"; if (NPT_FAILED(device->FindServiceByType(type, serviceRC))) { NPT_LOG_FINE_1("Service %s not found", (const char*)type); return NPT_FAILURE; } else { // in case it's a newer upnp implementation, force to 1 serviceRC->ForceVersion(1); } { NPT_AutoLock lock(m_MediaRenderers); PLT_DeviceDataReference data; NPT_String uuid = device->GetUUID(); // is it a new device? if (NPT_SUCCEEDED(NPT_ContainerFind(m_MediaRenderers, PLT_DeviceDataFinder(uuid), data))) { NPT_LOG_WARNING_1("Device (%s) is already in our list!", (const char*)uuid); return NPT_FAILURE; } NPT_LOG_FINE_1("Device Found: %s", (const char*)*device); m_MediaRenderers.Add(device); } if (m_Delegate && m_Delegate->OnMRAdded(device)) { // subscribe to services eventing only if delegate wants it if (serviceAVT) m_CtrlPoint->Subscribe(serviceAVT); // subscribe to required services m_CtrlPoint->Subscribe(serviceCMR); m_CtrlPoint->Subscribe(serviceRC); } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_MediaController::OnEventNotify +---------------------------------------------------------------------*/ NPT_Result PLT_MediaController::OnEventNotify(PLT_Service* service, NPT_List<PLT_StateVariable*>* vars) { if (m_Listener) { // parse LastChange var into smaller vars PLT_StateVariable* lastChangeVar = NULL; if (NPT_SUCCEEDED(NPT_ContainerFind(*vars, PLT_ListStateVariableNameFinder("LastChange"), lastChangeVar))) { vars->Remove(lastChangeVar); PLT_Service* var_service = lastChangeVar->GetService(); NPT_String text = lastChangeVar->GetValue(); NPT_XmlNode* xml = NULL; NPT_XmlParser parser; if (NPT_FAILED(parser.Parse(text, xml)) || !xml || !xml->AsElementNode()) { delete xml; return NPT_FAILURE; } NPT_XmlElementNode* node = xml->AsElementNode(); if (!node->GetTag().Compare("Event", true)) { // look for the instance with attribute id = 0 NPT_XmlElementNode* instance = NULL; for (NPT_Cardinal i=0; i<node->GetChildren().GetItemCount(); i++) { NPT_XmlElementNode* child; if (NPT_FAILED(PLT_XmlHelper::GetChild(node, child, i))) continue; if (!child->GetTag().Compare("InstanceID", true)) { // extract the "val" attribute value NPT_String value; if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(child, "val", value)) && !value.Compare("0")) { instance = child; break; } } } // did we find an instance with id = 0 ? if (instance != NULL) { // all the children of the Instance node are state variables for (NPT_Cardinal j=0; j<instance->GetChildren().GetItemCount(); j++) { NPT_XmlElementNode* var_node; if (NPT_FAILED(PLT_XmlHelper::GetChild(instance, var_node, j))) continue; // look for the state variable in this service const NPT_String* value = var_node->GetAttribute("val"); PLT_StateVariable* var = var_service->FindStateVariable(var_node->GetTag()); if (value != NULL && var != NULL) { // get the value and set the state variable // if it succeeded, add it to the list of vars we'll event if (NPT_SUCCEEDED(var->SetValue(*value, false))) { vars->Add(var); NPT_LOG_FINE_2("PLT_MediaController received var change for (%s): %s", (const char*)var->GetName(), (const char*)var->GetValue()); } } } } } delete xml; } if (vars->GetItemCount()) { m_Listener->OnMRStateVariablesChanged(service, vars); } } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | CUPnPDirectory::GetDirectory +---------------------------------------------------------------------*/ bool CUPnPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items) { CGUIDialogProgress* dlgProgress = NULL; CUPnP* upnp = CUPnP::GetInstance(); /* upnp should never be cached, it has internal cache */ items.SetCacheToDisc(CFileItemList::CACHE_NEVER); // start client if it hasn't been done yet bool client_started = upnp->IsClientStarted(); upnp->StartClient(); // We accept upnp://devuuid/[item_id/] NPT_String path = strPath.c_str(); if (!path.StartsWith("upnp://", true)) { return false; } if (path.Compare("upnp://", true) == 0) { // root -> get list of devices const NPT_Lock<PLT_DeviceMap>& devices = upnp->m_MediaBrowser->GetMediaServers(); const NPT_List<PLT_DeviceMapEntry*>& entries = devices.GetEntries(); NPT_List<PLT_DeviceMapEntry*>::Iterator entry = entries.GetFirstItem(); while (entry) { PLT_DeviceDataReference device = (*entry)->GetValue(); NPT_String name = device->GetFriendlyName(); NPT_String uuid = (*entry)->GetKey(); CFileItemPtr pItem(new CFileItem((const char*)name)); pItem->m_strPath = (const char*) "upnp://" + uuid + "/"; pItem->m_bIsFolder = true; pItem->SetThumbnailImage((const char*)device->GetIconUrl("image/jpeg")); items.Add(pItem); ++entry; } } else { if (!path.EndsWith("/")) path += "/"; // look for nextslash int next_slash = path.Find('/', 7); NPT_String uuid = (next_slash==-1)?path.SubString(7):path.SubString(7, next_slash-7); NPT_String object_id = (next_slash==-1)?"":path.SubString(next_slash+1); object_id.TrimRight("/"); if (object_id.GetLength()) { CStdString tmp = (char*) object_id; CUtil::UrlDecode(tmp); object_id = tmp; } // look for device in our list // (and wait for it to respond for 5 secs if we're just starting upnp client) NPT_TimeStamp watchdog; NPT_System::GetCurrentTimeStamp(watchdog); watchdog += 5.f; PLT_DeviceDataReference* device; for (;;) { const NPT_Lock<PLT_DeviceMap>& devices = upnp->m_MediaBrowser->GetMediaServers(); if (NPT_SUCCEEDED(devices.Get(uuid, device)) && device) break; // fail right away if device not found and upnp client was already running if (client_started) goto failure; // otherwise check if we've waited long enough without success NPT_TimeStamp now; NPT_System::GetCurrentTimeStamp(now); if (now > watchdog) goto failure; // sleep a bit and try again NPT_System::Sleep(NPT_TimeInterval(1, 0)); } // issue a browse request with object_id // if object_id is empty use "0" for root object_id = object_id.IsEmpty()?"0":object_id; // just a guess as to what types of files we want bool video = true; bool audio = true; bool image = true; m_strFileMask.TrimLeft("/"); if (!m_strFileMask.IsEmpty()) { video = m_strFileMask.Find(".wmv") >= 0; audio = m_strFileMask.Find(".wma") >= 0; image = m_strFileMask.Find(".jpg") >= 0; } // special case for Windows Media Connect and WMP11 when looking for root // We can target which root subfolder we want based on directory mask if (object_id == "0" && (((*device)->GetFriendlyName().Find("Windows Media Connect", 0, true) >= 0) || ((*device)->m_ModelName == "Windows Media Player Sharing"))) { // look for a specific type to differentiate which folder we want if (audio && !video && !image) { // music object_id = "1"; } else if (!audio && video && !image) { // video object_id = "2"; } else if (!audio && !video && image) { // pictures object_id = "3"; } } #ifdef DISABLE_SPECIALCASE // same thing but special case for XBMC if (object_id == "0" && (((*device)->m_ModelName.Find("XBMC", 0, true) >= 0) || ((*device)->m_ModelName.Find("Xbox Media Center", 0, true) >= 0))) { // look for a specific type to differentiate which folder we want if (audio && !video && !image) { // music object_id = "virtualpath://upnpmusic"; } else if (!audio && video && !image) { // video object_id = "virtualpath://upnpvideo"; } else if (!audio && !video && image) { // pictures object_id = "virtualpath://upnppictures"; } } #endif // bring up dialog if object is not cached if (!upnp->m_MediaBrowser->IsCached(uuid, object_id)) { dlgProgress = (CGUIDialogProgress*)m_gWindowManager.GetWindow(WINDOW_DIALOG_PROGRESS); if (dlgProgress) { dlgProgress->ShowProgressBar(false); dlgProgress->SetCanCancel(false); dlgProgress->SetHeading(20334); dlgProgress->SetLine(0, 194); dlgProgress->SetLine(1, ""); dlgProgress->SetLine(2, ""); dlgProgress->StartModal(); } } // if error, return now, the device could have gone away // this will make us go back to the sources list PLT_MediaObjectListReference list; NPT_Result res = upnp->m_MediaBrowser->Browse(*device, object_id, list); if (NPT_FAILED(res)) goto failure; // empty list is ok if (list.IsNull()) goto cleanup; PLT_MediaObjectList::Iterator entry = list->GetFirstItem(); while (entry) { // disregard items with wrong class/type if( (!video && (*entry)->m_ObjectClass.type.CompareN("object.item.videoitem", 21,true) == 0) || (!audio && (*entry)->m_ObjectClass.type.CompareN("object.item.audioitem", 21,true) == 0) || (!image && (*entry)->m_ObjectClass.type.CompareN("object.item.imageitem", 21,true) == 0) ) { ++entry; continue; } // never show empty containers in media views if((*entry)->IsContainer()) { if( (audio || video || image) && ((PLT_MediaContainer*)(*entry))->m_ChildrenCount == 0) { ++entry; continue; } } CFileItemPtr pItem(new CFileItem((const char*)(*entry)->m_Title)); pItem->SetLabelPreformated(true); pItem->m_bIsFolder = (*entry)->IsContainer(); // if it's a container, format a string as upnp://uuid/object_id if (pItem->m_bIsFolder) { CStdString id = (char*) (*entry)->m_ObjectID; CUtil::URLEncode(id); pItem->m_strPath = (const char*) "upnp://" + uuid + "/" + id.c_str() + "/"; } else { if ((*entry)->m_Resources.GetItemCount()) { PLT_MediaItemResource& resource = (*entry)->m_Resources[0]; // look for a resource with "xbmc-get" protocol // if we can't find one, keep the first resource NPT_ContainerFind((*entry)->m_Resources, CProtocolFinder("xbmc-get"), resource); CLog::Log(LOGDEBUG, "CUPnPDirectory::GetDirectory - resource protocol info '%s'", (const char*)(resource.m_ProtocolInfo)); // if it's an item, path is the first url to the item // we hope the server made the first one reachable for us // (it could be a format we dont know how to play however) pItem->m_strPath = (const char*) resource.m_Uri; // set metadata if (resource.m_Size > 0) { pItem->m_dwSize = resource.m_Size; } // set a general content type CStdString type = (const char*)(*entry)->m_ObjectClass.type.Left(21); if (type.Equals("object.item.videoitem")) pItem->SetContentType("video/octet-stream"); else if(type.Equals("object.item.audioitem")) pItem->SetContentType("audio/octet-stream"); else if(type.Equals("object.item.imageitem")) pItem->SetContentType("image/octet-stream"); // look for content type in protocol info if (resource.m_ProtocolInfo.GetLength()) { char proto[1024]; char dummy1[1024]; char ct[1204]; char dummy2[1024]; int fields = sscanf(resource.m_ProtocolInfo, "%[^:]:%[^:]:%[^:]:%[^:]", proto, dummy1, ct, dummy2); if (fields == 4) { if (strcmp(ct, "application/octet-stream") != 0) { pItem->SetContentType(ct); } } else { CLog::Log(LOGERROR, "CUPnPDirectory::GetDirectory - invalid protocol info '%s'", (const char*)(resource.m_ProtocolInfo)); } } // look for date? if((*entry)->m_Description.date.GetLength()) { SYSTEMTIME time = {}; sscanf((*entry)->m_Description.date, "%hu-%hu-%huT%hu:%hu:%hu", &time.wYear, &time.wMonth, &time.wDay, &time.wHour, &time.wMinute, &time.wSecond); pItem->m_dateTime = time; } // look for metadata if( (*entry)->m_ObjectClass.type.CompareN("object.item.videoitem", 21,true) == 0 ) { pItem->SetLabelPreformated(false); CUPnP::PopulateTagFromObject(*pItem->GetVideoInfoTag(), *(*entry), &resource); } else if( (*entry)->m_ObjectClass.type.CompareN("object.item.audioitem", 21,true) == 0 ) { pItem->SetLabelPreformated(false); CUPnP::PopulateTagFromObject(*pItem->GetMusicInfoTag(), *(*entry), &resource); } else if( (*entry)->m_ObjectClass.type.CompareN("object.item.imageitem", 21,true) == 0 ) { //CPictureInfoTag* tag = pItem->GetPictureInfoTag(); } } } // if there is a thumbnail available set it here if((*entry)->m_ExtraInfo.album_art_uri.GetLength()) pItem->SetThumbnailImage((const char*) (*entry)->m_ExtraInfo.album_art_uri); else if((*entry)->m_Description.icon_uri.GetLength()) pItem->SetThumbnailImage((const char*) (*entry)->m_Description.icon_uri); items.Add(pItem); ++entry; } } cleanup: if (dlgProgress) dlgProgress->Close(); return true; failure: if (dlgProgress) dlgProgress->Close(); return false; }
/*---------------------------------------------------------------------- | PLT_MediaController::OnActionResponse +---------------------------------------------------------------------*/ NPT_Result PLT_MediaController::OnActionResponse(NPT_Result res, PLT_ActionReference& action, void* userdata) { if (m_Listener == NULL) { return NPT_SUCCESS; } /* make sure device is a renderer we've previously found */ PLT_DeviceDataReference device; NPT_String uuid = action->GetActionDesc()->GetService()->GetDevice()->GetUUID(); if (NPT_FAILED(NPT_ContainerFind(m_MediaRenderers, PLT_DeviceDataFinder(uuid), device))) { NPT_LOG_FINE_1("Device (%s) not found in our list of renderers", (const char*)uuid); res = NPT_FAILURE; } /* extract action name */ NPT_String actionName = action->GetActionDesc()->GetName(); /* AVTransport response ? */ if (actionName.Compare("GetCurrentTransportActions", true) == 0) { return OnGetCurrentTransportActionsResponse(res, device, action, userdata); } else if (actionName.Compare("GetDeviceCapabilities", true) == 0) { return OnGetDeviceCapabilitiesResponse(res, device, action, userdata); } else if (actionName.Compare("GetMediaInfo", true) == 0) { return OnGetMediaInfoResponse(res, device, action, userdata); } else if (actionName.Compare("GetPositionInfo", true) == 0) { return OnGetPositionInfoResponse(res, device, action, userdata); } else if (actionName.Compare("GetTransportInfo", true) == 0) { return OnGetTransportInfoResponse(res, device, action, userdata); } else if (actionName.Compare("GetTransportSettings", true) == 0) { return OnGetTransportSettingsResponse(res, device, action, userdata); } else if (actionName.Compare("Next", true) == 0) { m_Listener->OnNextResult(res, device, userdata); } else if (actionName.Compare("Pause", true) == 0) { m_Listener->OnPauseResult(res, device, userdata); } else if (actionName.Compare("Play", true) == 0) { m_Listener->OnPlayResult(res, device, userdata); } else if (actionName.Compare("Previous", true) == 0) { m_Listener->OnPreviousResult(res, device, userdata); } else if (actionName.Compare("Seek", true) == 0) { m_Listener->OnSeekResult(res, device, userdata); } else if (actionName.Compare("SetAVTransportURI", true) == 0) { m_Listener->OnSetAVTransportURIResult(res, device, userdata); } else if (actionName.Compare("SetPlayMode", true) == 0) { m_Listener->OnSetPlayModeResult(res, device, userdata); } else if (actionName.Compare("Stop", true) == 0) { m_Listener->OnStopResult(res, device, userdata); } else if (actionName.Compare("GetCurrentConnectionIDs", true) == 0) { return OnGetCurrentConnectionIDsResponse(res, device, action, userdata); } else if (actionName.Compare("GetCurrentConnectionInfo", true) == 0) { return OnGetCurrentConnectionInfoResponse(res, device, action, userdata); } else if (actionName.Compare("GetProtocolInfo", true) == 0) { return OnGetProtocolInfoResponse(res, device, action, userdata); } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | CUPnPDirectory::GetDirectory +---------------------------------------------------------------------*/ bool CUPnPDirectory::GetResource(const CURL& path, CFileItem &item) { if(path.GetProtocol() != "upnp") return false; CUPnP* upnp = CUPnP::GetInstance(); if(!upnp) return false; CStdString uuid = path.GetHostName(); CStdString object = path.GetFileName(); object.TrimRight("/"); CURL::Decode(object); PLT_DeviceDataReference device; if(!FindDeviceWait(upnp, uuid.c_str(), device)) return false; PLT_MediaObjectListReference list; if (NPT_FAILED(upnp->m_MediaBrowser->BrowseSync(device, object.c_str(), list, true))) return false; PLT_MediaObjectList::Iterator entry = list->GetFirstItem(); if (entry == 0) return false; PLT_MediaItemResource resource; // look for a resource with "xbmc-get" protocol // if we can't find one, keep the first resource if(NPT_FAILED(NPT_ContainerFind((*entry)->m_Resources, CProtocolFinder("xbmc-get"), resource))) { if((*entry)->m_Resources.GetItemCount()) resource = (*entry)->m_Resources[0]; else return false; } // store original path so we remember it item.SetProperty("original_listitem_url", item.GetPath()); item.SetProperty("original_listitem_mime", item.GetMimeType(false)); // if it's an item, path is the first url to the item // we hope the server made the first one reachable for us // (it could be a format we dont know how to play however) item.SetPath((const char*) resource.m_Uri); // look for content type in protocol info if (resource.m_ProtocolInfo.IsValid()) { CLog::Log(LOGDEBUG, "CUPnPDirectory::GetResource - resource protocol info '%s'", (const char*)(resource.m_ProtocolInfo.ToString())); if (resource.m_ProtocolInfo.GetContentType().Compare("application/octet-stream") != 0) { item.SetMimeType((const char*)resource.m_ProtocolInfo.GetContentType()); } } else { CLog::Log(LOGERROR, "CUPnPDirectory::GetResource - invalid protocol info '%s'", (const char*)(resource.m_ProtocolInfo.ToString())); } // look for subtitles unsigned subs = 0; for(unsigned r = 0; r < (*entry)->m_Resources.GetItemCount(); r++) { PLT_MediaItemResource& res = (*entry)->m_Resources[r]; PLT_ProtocolInfo& info = res.m_ProtocolInfo; static const char* allowed[] = { "text/srt" , "text/ssa" , "text/sub" , "text/idx" }; for(unsigned type = 0; type < sizeof(allowed)/sizeof(allowed[0]); type++) { if(info.Match(PLT_ProtocolInfo("*", "*", allowed[type], "*"))) { CStdString prop; prop.Format("upnp:subtitle:%d", ++subs); item.SetProperty(prop, (const char*)res.m_Uri); break; } } } return true; }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | CMediaCrawler::UpdateDidl +---------------------------------------------------------------------*/ NPT_String CMediaCrawler::UpdateDidl(const char* server_uuid, const NPT_String& didl, NPT_SocketInfo* info) { NPT_String new_didl; NPT_String str; NPT_XmlNode* node = NULL; NPT_XmlWriter writer; NPT_OutputStreamReference stream(new NPT_StringOutputStream(&new_didl)); NPT_LOG_FINE("Parsing Didl..."); NPT_XmlElementNode* tree = NULL; NPT_XmlParser parser; if (NPT_FAILED(parser.Parse(didl, node)) || !node || !node->AsElementNode()) { goto cleanup; } tree = node->AsElementNode(); NPT_LOG_FINE("Processing Didl xml..."); if (tree->GetTag().Compare("DIDL-Lite", true)) { goto cleanup; } // iterate through children NPT_Result res; for (NPT_List<NPT_XmlNode*>::Iterator children = tree->GetChildren().GetFirstItem(); children; children++) { NPT_XmlElementNode* child = (*children)->AsElementNode(); if (!child) continue; // object id remapping NPT_XmlAttribute* attribute_id; res = PLT_XmlHelper::GetAttribute(child, "id", attribute_id); if (NPT_SUCCEEDED(res) && attribute_id) { attribute_id->SetValue(FormatObjectId(server_uuid, attribute_id->GetValue())); } // parent ID remapping NPT_XmlAttribute* attribute_parent_id; res = PLT_XmlHelper::GetAttribute(child, "parentID", attribute_parent_id); if (NPT_SUCCEEDED(res)) { attribute_parent_id->SetValue(attribute_parent_id->GetValue().Compare("-1")?FormatObjectId(server_uuid, attribute_parent_id->GetValue()):"0"); } // resources remapping NPT_Array<NPT_XmlElementNode*> res; PLT_XmlHelper::GetChildren(child, res, "res"); if (res.GetItemCount() > 0) { for (unsigned int i=0; i<res.GetItemCount(); i++) { NPT_XmlElementNode* resource = res[i]; NPT_XmlAttribute* attribute_prot; const NPT_String* url; if (NPT_SUCCEEDED(PLT_XmlHelper::GetAttribute(resource, "protocolInfo", attribute_prot)) && (url = resource->GetText())) { // special case for Windows Media Connect // When a browse is done on the same machine, WMC uses localhost // instead of the IP for all resources urls which means we cannot advertise that // since it would be useless for a remote device // so we try to replace it with the right IP address by looking at which interface we received the // initial browse request on to make sure the remote device will be able to access the modified resource // urls (in case the local PC has more than 1 NICs) // replace the url NPT_List<NPT_XmlNode*>& children = resource->GetChildren(); NPT_HttpUrl http_url(NPT_Uri::PercentDecode(*url)); if ((http_url.GetHost() == "localhost" || http_url.GetHost() == "127.0.0.1") && info) { if (info->local_address.GetIpAddress().AsLong()) { http_url.SetHost(info->local_address.GetIpAddress().ToString()); // replace text children.Apply(NPT_ObjectDeleter<NPT_XmlNode>()); children.Clear(); resource->AddText(http_url.ToString()); url = resource->GetText(); } } CStreamHandler* handler = NULL; NPT_Result res = NPT_ContainerFind(m_StreamHandlers, CStreamHandlerFinder(attribute_prot->GetValue(), *url), handler); if (NPT_SUCCEEDED(res)) { handler->ModifyResource(resource); } } } } } // serialize modified node into new didl writer.Serialize(*node, *stream); delete node; return new_didl; cleanup: delete node; return didl; }