/*---------------------------------------------------------------------- | PLT_LightSampleDevice::OnAction +---------------------------------------------------------------------*/ NPT_Result PLT_LightSampleDevice::OnAction(PLT_ActionReference& action, NPT_SocketInfo* /* info */) { /* parse the action name */ NPT_String name = action->GetActionDesc()->GetName(); if (name.Compare("SetTarget") == 0) { NPT_String value; action->GetArgumentValue("newTargetValue", value); PLT_StateVariable* variable = action->GetActionDesc()->GetService()->FindStateVariable("Status"); if (NPT_FAILED(variable->SetValue(value))) { action->SetError(402, "Invalid Args"); return NPT_FAILURE; } return NPT_SUCCESS; } else if (name.Compare("GetStatus") == 0) { PLT_StateVariable* variable = action->GetActionDesc()->GetService()->FindStateVariable("Status"); if (variable) { action->SetArgumentValue("ResultStatus", variable->GetValue()); return NPT_SUCCESS; } } action->SetError(501, "Action Failed"); return NPT_FAILURE; }
/*---------------------------------------------------------------------- | PLT_FileMediaServer::ServeFile +---------------------------------------------------------------------*/ NPT_Result PLT_FileMediaServer::ServeFile(NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response, const NPT_String& uri_path, const NPT_String& file_path) { NPT_COMPILER_UNUSED(context); // prevent hackers from accessing files outside of our root if ((file_path.Find("/..") >= 0) || (file_path.Find("\\..") >= 0)) { return NPT_FAILURE; } // File requested NPT_String path = m_FileBaseUri.GetPath(); if (path.Compare(uri_path.Left(path.GetLength()), true) == 0) { NPT_Position start, end; PLT_HttpHelper::GetRange(request, start, end); return PLT_FileServer::ServeFile(response, NPT_FilePath::Create(m_Path, file_path), start, end, !request.GetMethod().Compare("HEAD")); } // Album Art requested path = m_AlbumArtBaseUri.GetPath(); if (path.Compare(uri_path.Left(path.GetLength()), true) == 0) { return OnAlbumArtRequest(response, m_Path + file_path); } return NPT_FAILURE; }
/*---------------------------------------------------------------------- | NPT_LogManager::ConfigValueIsBooleanFalse +---------------------------------------------------------------------*/ bool NPT_LogManager::ConfigValueIsBooleanFalse(NPT_String& value) { return value.Compare("false", true) == 0 || value.Compare("no", true) == 0 || value.Compare("off", true) == 0 || value.Compare("0", true) == 0; }
/*---------------------------------------------------------------------- | NPT_LogManager::ConfigValueIsBooleanTrue +---------------------------------------------------------------------*/ bool NPT_LogManager::ConfigValueIsBooleanTrue(NPT_String& value) { return value.Compare("true", true) == 0 || value.Compare("yes", true) == 0 || value.Compare("on", true) == 0 || value.Compare("1", true) == 0; }
/*---------------------------------------------------------------------- | PLT_FileMediaServer::ProcessFileRequest +---------------------------------------------------------------------*/ NPT_Result PLT_FileMediaServer::ProcessFileRequest(NPT_HttpRequest& request, NPT_HttpResponse& response, NPT_SocketInfo& client_info) { NPT_COMPILER_UNUSED(client_info); NPT_LOG_FINE("PLT_FileMediaServer::ProcessFileRequest Received Request:"); PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, &request); response.GetHeaders().SetHeader("Accept-Ranges", "bytes"); if (request.GetMethod().Compare("GET") && request.GetMethod().Compare("HEAD")) { response.SetStatus(500, "Internal Server Error"); return NPT_SUCCESS; } // File requested NPT_String path = m_FileBaseUri.GetPath(); NPT_String strUri = NPT_Uri::PercentDecode(request.GetUrl().GetPath()); NPT_HttpUrlQuery query(request.GetUrl().GetQuery()); NPT_String file_path = query.GetField("path"); // hack for XBMC support for 360, we urlencoded the ? to that the 360 doesn't strip out the query // but then the query ends being parsed as part of the path int index = strUri.Find("path="); if (index>0) file_path = strUri.Right(strUri.GetLength()-index-5); if (file_path.GetLength() == 0) goto failure; // HACK for wmp: somehow they inverse our slashes ! // do it only if we're on windows if (m_DirDelimiter == "\\") { file_path.Replace('/', '\\'); } if (path.Compare(strUri.Left(path.GetLength()), true) == 0) { NPT_Integer start, end; PLT_HttpHelper::GetRange(&request, start, end); return PLT_FileServer::ServeFile(m_Path + file_path, &response, start, end, !request.GetMethod().Compare("HEAD")); } // Album Art requested path = m_AlbumArtBaseUri.GetPath(); if (path.Compare(strUri.Left(path.GetLength()), true) == 0) { return OnAlbumArtRequest(m_Path + file_path, response); } failure: response.SetStatus(404, "File Not Found"); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | CUPnPDirectory::GetFriendlyName +---------------------------------------------------------------------*/ const char* CUPnPDirectory::GetFriendlyName(const char* url) { NPT_String path = url; if (!path.EndsWith("/")) path += "/"; if (path.Left(7).Compare("upnp://", true) != 0) { return NULL; } else if (path.Compare("upnp://", true) == 0) { return "UPnP Media Servers (Auto-Discover)"; } // look for nextslash int next_slash = path.Find('/', 7); if (next_slash == -1) return NULL; NPT_String uuid = path.SubString(7, next_slash-7); NPT_String object_id = path.SubString(next_slash+1, path.GetLength()-next_slash-2); // look for device PLT_DeviceDataReference* device; const NPT_Lock<PLT_DeviceMap>& devices = CUPnP::GetInstance()->m_MediaBrowser->GetMediaServers(); if (NPT_FAILED(devices.Get(uuid, device)) || device == NULL) return NULL; return (const char*)(*device)->GetFriendlyName(); }
/*---------------------------------------------------------------------- | CUPnPDirectory::GetFriendlyName +---------------------------------------------------------------------*/ const char* CUPnPDirectory::GetFriendlyName(const char* url) { NPT_String path = url; if (!path.EndsWith("/")) path += "/"; if (path.Left(7).Compare("upnp://", true) != 0) { return NULL; } else if (path.Compare("upnp://", true) == 0) { return "UPnP Media Servers (Auto-Discover)"; } // look for nextslash int next_slash = path.Find('/', 7); if (next_slash == -1) return NULL; NPT_String uuid = path.SubString(7, next_slash-7); NPT_String object_id = path.SubString(next_slash+1, path.GetLength()-next_slash-2); // look for device PLT_DeviceDataReference device; if(!FindDeviceWait(CUPnP::GetInstance(), uuid, device)) return NULL; return (const char*)device->GetFriendlyName(); }
/*---------------------------------------------------------------------- | PLT_MicroMediaController::PopDirectoryStackToRoot +---------------------------------------------------------------------*/ void PLT_MicroMediaController::PopDirectoryStackToRoot(void) { NPT_String val; while (NPT_SUCCEEDED(m_CurBrowseDirectoryStack.Peek(val)) && val.Compare("0")) { m_CurBrowseDirectoryStack.Pop(val); } }
/*---------------------------------------------------------------------- | PLT_HttpHelper::IsConnectionKeepAlive +---------------------------------------------------------------------*/ bool PLT_HttpHelper::IsConnectionKeepAlive(NPT_HttpMessage* message) { NPT_String connection; message->GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_CONNECTION, connection); // if we have the keep-alive header then no matter what protocol version we want keep-alive // if we are in HTTP 1.1 and we don't have the keep-alive header, make sure we also don't have the Connection: close header. NPT_String protocol = message->GetProtocol(); if ((!protocol.Compare(NPT_HTTP_PROTOCOL_1_1, true) && connection.Compare("Close", true)) || !connection.Compare("keep-alive", true)) { return true; } return false; }
/*---------------------------------------------------------------------- | PLT_MediaConnect::OnAction +---------------------------------------------------------------------*/ NPT_Result PLT_MediaConnect::OnAction(PLT_ActionReference& action, const NPT_HttpRequestContext& context) { PLT_MediaConnectInfo* mc_info = NULL; // /* get MAC address from IP */ // if (info != NULL) { // NPT_String ip = info->remote_address.GetIpAddress().ToString(); // NPT_String MAC; // GetMACFromIP(ip, MAC); // // if (MAC.GetLength()) { // NPT_Result res = m_MediaConnectDeviceInfoMap.Get(MAC, mc_info); // if (NPT_FAILED(res)) { // m_MediaConnectDeviceInfoMap.Put(MAC, PLT_MediaConnectInfo()); // m_MediaConnectDeviceInfoMap.Get(MAC, mc_info); // // // automatically validate for now // Authorize(mc_info, true); // } // } // } // // /* verify device is allowed first */ // if (mc_info == NULL || !mc_info->m_Authorized) { // action->SetError(801, "Access Denied"); // return NPT_SUCCESS; // } /* parse the action name */ NPT_String name = action->GetActionDesc()->GetName(); /* handle X_MS_MediaReceiverRegistrar actions here */ if (name.Compare("IsAuthorized") == 0) { return OnIsAuthorized(action, mc_info); } if (name.Compare("RegisterDevice") == 0) { return OnRegisterDevice(action, mc_info); } if (name.Compare("IsValidated") == 0) { return OnIsValidated(action, mc_info); } return PLT_FileMediaServer::OnAction(action, context); }
/*---------------------------------------------------------------------- | PLT_MediaConnect::OnAction +---------------------------------------------------------------------*/ NPT_Result PLT_MediaConnect::OnAction(PLT_ActionReference& action, const PLT_HttpRequestContext& context) { /* parse the action name */ NPT_String name = action->GetActionDesc().GetName(); /* handle X_MS_MediaReceiverRegistrar actions here */ if (name.Compare("IsAuthorized") == 0) { return OnIsAuthorized(action); } if (name.Compare("RegisterDevice") == 0) { return OnRegisterDevice(action); } if (name.Compare("IsValidated") == 0) { return OnIsValidated(action); } return PLT_MediaServer::OnAction(action, context); }
/*---------------------------------------------------------------------- | PLT_MediaBrowser::OnActionResponse +---------------------------------------------------------------------*/ NPT_Result PLT_MediaBrowser::OnActionResponse(NPT_Result res, PLT_ActionReference& action, void* userdata) { NPT_String actionName = action->GetActionDesc().GetName(); // look for device in our list first PLT_DeviceDataReference device; NPT_String uuid = action->GetActionDesc().GetService()->GetDevice()->GetUUID(); if (NPT_FAILED(FindServer(uuid, device))) res = NPT_FAILURE; // Browse action response if (actionName.Compare("Browse", true) == 0) { return OnBrowseResponse(res, device, action, userdata); } else if (actionName.Compare("Search", true) == 0) { return OnSearchResponse(res, device, action, userdata); } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_cdup +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_cdup() { // we don't want to pop the root off now.... NPT_String val; m_CurBrowseDirectoryStack.Peek(val); if (val.Compare("0")) { m_CurBrowseDirectoryStack.Pop(val); } else { printf("Already at root\n"); } }
////////////////////////////////////////////////////////////////////////// // CHttpHelper bool CHttpHelper::IsConnectionKeepAlive(NPT_HttpMessage& message) { const NPT_String* connection = message.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_CONNECTION); // the DLNA says that all HTTP 1.0 requests should be closed immediately by the server NPT_String protocol = message.GetProtocol(); if (protocol.Compare(NPT_HTTP_PROTOCOL_1_0, true) == 0) return false; // all HTTP 1.1 requests without a Connection header // or with a keep-alive Connection header should be kept alive if possible return (!connection || connection->Compare("keep-alive", true) == 0); }
/*---------------------------------------------------------------------- | PLT_MediaServer::OnAction +---------------------------------------------------------------------*/ NPT_Result PLT_MediaServer::OnAction(PLT_ActionReference& action, const PLT_HttpRequestContext& context) { /* parse the action name */ NPT_String name = action->GetActionDesc().GetName(); // ContentDirectory if (name.Compare("Browse", true) == 0) { return OnBrowse(action, context); } if (name.Compare("Search", true) == 0) { return OnSearch(action, context); } if (name.Compare("UpdateObject", true) == 0) { return OnUpdate(action, context); } if (name.Compare("GetSystemUpdateID", true) == 0) { return OnGetSystemUpdateID(action, context); } if (name.Compare("GetSortCapabilities", true) == 0) { return OnGetSortCapabilities(action, context); } if (name.Compare("GetSearchCapabilities", true) == 0) { return OnGetSearchCapabilities(action, context); } // ConnectionMananger if (name.Compare("GetCurrentConnectionIDs", true) == 0) { return OnGetCurrentConnectionIDs(action, context); } if (name.Compare("GetProtocolInfo", true) == 0) { return OnGetProtocolInfo(action, context); } if (name.Compare("GetCurrentConnectionInfo", true) == 0) { return OnGetCurrentConnectionInfo(action, context); } action->SetError(401,"No Such Action."); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_HttpHelper::IsConnectionKeepAlive +---------------------------------------------------------------------*/ bool PLT_HttpHelper::IsConnectionKeepAlive(NPT_HttpMessage& message) { const NPT_String* connection = message.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_CONNECTION); // the DLNA says that all HTTP 1.0 requests should be closed immediately by the server // all HTTP 1.1 requests without a Connection header or with a Connection header // NOT saying "Close" should be kept alive NPT_String protocol = message.GetProtocol(); if (!protocol.Compare(NPT_HTTP_PROTOCOL_1_1, true) && (!connection || connection->Compare("close", true))) { return true; } return false; }
/*---------------------------------------------------------------------- | 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; }
NPT_Result GPAC_MediaRenderer::OnAction(PLT_ActionReference& action, const PLT_HttpRequestContext& context) { NPT_COMPILER_UNUSED(context); /* parse the action name */ NPT_String name = action->GetActionDesc().GetName(); m_ip_src = context.GetRemoteAddress().GetIpAddress().ToString(); /* Is it a ConnectionManager Service Action ? */ if (name.Compare("GetCurrentConnectionIDs", true) == 0) { if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } return NPT_SUCCESS; } if (name.Compare("GetProtocolInfo", true) == 0) { if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } return NPT_SUCCESS; } if (name.Compare("GetCurrentConnectionInfo", true) == 0) { return OnGetCurrentConnectionInfo(action); } if (name.Compare("StopForMigration", true) == 0) { NPT_String res = m_pUPnP->OnMigrate(); m_pMigrationService->SetStateVariable("MigrationStatus", "OK"); m_pMigrationService->SetStateVariable("MigrationMetaData", res); if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } return NPT_SUCCESS; } /* Is it a AVTransport Service Action ? */ // since all actions take an instance ID and we only support 1 instance // verify that the Instance ID is 0 and return an error here now if not NPT_String serviceType = action->GetActionDesc().GetService()->GetServiceType(); if (serviceType.Compare("urn:schemas-upnp-org:service:AVTransport:1", true) == 0) { if (NPT_FAILED(action->VerifyArgumentValue("InstanceID", "0"))) { action->SetError(802,"Not valid InstanceID."); return NPT_FAILURE; } } if (name.Compare("GetCurrentTransportActions", true) == 0) { if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } return NPT_SUCCESS; } if (name.Compare("GetDeviceCapabilities", true) == 0) { if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } return NPT_SUCCESS; } if (name.Compare("GetMediaInfo", true) == 0) { if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } return NPT_SUCCESS; } if (name.Compare("GetPositionInfo", true) == 0) { if (m_pUPnP->m_pTerm->root_scene) { char szVal[100]; m_pAVService->SetStateVariable("CurrentTrack", "0"); format_time_string(szVal, m_Duration); m_pAVService->SetStateVariable("CurrentTrackDuration", szVal); m_pAVService->SetStateVariable("CurrentTrackMetadata", ""); m_pAVService->SetStateVariable("CurrentTrackURI", ""); format_time_string(szVal, m_Time); m_pAVService->SetStateVariable("RelativeTimePosition", szVal); m_pAVService->SetStateVariable("AbsoluteTimePosition", szVal); m_pAVService->SetStateVariable("RelativeCounterPosition", "2147483647"); // means NOT_IMPLEMENTED m_pAVService->SetStateVariable("AbsoluteCounterPosition", "2147483647"); // means NOT_IMPLEMENTED } else { if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } } return NPT_SUCCESS; } if (name.Compare("GetTransportInfo", true) == 0) { if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } return NPT_SUCCESS; } if (name.Compare("GetTransportSettings", true) == 0) { if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } return NPT_SUCCESS; } if (name.Compare("Next", true) == 0) { return OnNext(action); } if (name.Compare("Pause", true) == 0) { return OnPause(action); } if (name.Compare("Play", true) == 0) { return OnPlay(action); } if (name.Compare("Previous", true) == 0) { return OnPrevious(action); } if (name.Compare("Seek", true) == 0) { return OnSeek(action); } if (name.Compare("Stop", true) == 0) { return OnStop(action); } if (name.Compare("SetAVTransportURI", true) == 0) { return OnSetAVTransportURI(action); } if (name.Compare("SetPlayMode", true) == 0) { return OnSetPlayMode(action); } /* Is it a RendererControl Service Action ? */ if (serviceType.Compare("urn:schemas-upnp-org:service:RenderingControl:1", true) == 0) { /* we only support master channel */ if (NPT_FAILED(action->VerifyArgumentValue("Channel", "Master"))) { action->SetError(402,"Invalid Args."); return NPT_FAILURE; } } if (name.Compare("GetVolume", true) == 0) { NPT_CHECK_SEVERE(action->SetArgumentsOutFromStateVariable()); return NPT_SUCCESS; } if (name.Compare("GetMute", true) == 0) { NPT_CHECK_SEVERE(action->SetArgumentsOutFromStateVariable()); return NPT_SUCCESS; } if (name.Compare("SetVolume", true) == 0) { return OnSetVolume(action); } if (name.Compare("SetMute", true) == 0) { return OnSetMute(action); } action->SetError(401,"No Such Action."); return NPT_FAILURE; }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | PLT_HttpServerSocketTask::SendResponseHeaders +---------------------------------------------------------------------*/ NPT_Result PLT_HttpServerSocketTask::SendResponseHeaders(NPT_HttpResponse* response, NPT_OutputStream& output_stream, bool& keep_alive) { // add any headers that may be missing NPT_HttpHeaders& headers = response->GetHeaders(); // get the request entity to set additional headers NPT_InputStreamReference body_stream; NPT_HttpEntity* entity = response->GetEntity(); if (entity && NPT_SUCCEEDED(entity->GetInputStream(body_stream))) { // set the content length if known if (entity->ContentLengthIsKnown()) { headers.SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, NPT_String::FromIntegerU(entity->GetContentLength())); } // content type NPT_String content_type = entity->GetContentType(); if (!content_type.IsEmpty()) { headers.SetHeader(NPT_HTTP_HEADER_CONTENT_TYPE, content_type); } // content encoding NPT_String content_encoding = entity->GetContentEncoding(); if (!content_encoding.IsEmpty()) { headers.SetHeader(NPT_HTTP_HEADER_CONTENT_ENCODING, content_encoding); } // transfer encoding const NPT_String& transfer_encoding = entity->GetTransferEncoding(); if (!transfer_encoding.IsEmpty()) { headers.SetHeader(NPT_HTTP_HEADER_TRANSFER_ENCODING, transfer_encoding); } } else if (!headers.GetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH)) { // force content length to 0 if there is no message body // (necessary for 1.1 or 1.0 with keep-alive connections) headers.SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, "0"); } const NPT_String* content_length = headers.GetHeaderValue(NPT_HTTP_HEADER_CONTENT_LENGTH); const NPT_String* transfer_encoding = headers.GetHeaderValue(NPT_HTTP_HEADER_TRANSFER_ENCODING); const NPT_String* connection_header = headers.GetHeaderValue(NPT_HTTP_HEADER_CONNECTION); if (keep_alive) { if (connection_header && connection_header->Compare("close") == 0) { keep_alive = false; } else { // the request says client supports keep-alive // but override if response has content-length header or // transfer chunked encoding keep_alive = content_length || (transfer_encoding && transfer_encoding->Compare(NPT_HTTP_TRANSFER_ENCODING_CHUNKED) == 0); } } // only write keep-alive header for 1.1 if it's close NPT_String protocol = response->GetProtocol(); if (protocol.Compare(NPT_HTTP_PROTOCOL_1_0, true) == 0 || !keep_alive) { headers.SetHeader(NPT_HTTP_HEADER_CONNECTION, keep_alive?"keep-alive":"close", true); } headers.SetHeader(NPT_HTTP_HEADER_SERVER, PLT_HTTP_DEFAULT_SERVER, false); // set but don't replace PLT_LOG_HTTP_RESPONSE(NPT_LOG_LEVEL_FINE, "PLT_HttpServerSocketTask::Write", response); // create a memory stream to buffer the headers NPT_MemoryStream header_stream; response->Emit(header_stream); // send the headers NPT_CHECK_WARNING(output_stream.WriteFully(header_stream.GetData(), header_stream.GetDataSize())); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | CUPnPDirectory::GetDirectory +---------------------------------------------------------------------*/ bool CUPnPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items) { CUPnP* upnp = CUPnP::GetInstance(); /* upnp should never be cached, it has internal cache */ items.SetCacheToDisc(CFileItemList::CACHE_NEVER); // 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) { upnp->StartClient(); // root -> get list of devices const NPT_Lock<PLT_DeviceDataReferenceList>& devices = upnp->m_MediaBrowser->GetMediaServers(); NPT_List<PLT_DeviceDataReference>::Iterator device = devices.GetFirstItem(); while (device) { NPT_String name = (*device)->GetFriendlyName(); NPT_String uuid = (*device)->GetUUID(); CFileItemPtr pItem(new CFileItem((const char*)name)); pItem->SetPath(CStdString((const char*) "upnp://" + uuid + "/")); pItem->m_bIsFolder = true; pItem->SetThumbnailImage((const char*)(*device)->GetIconUrl("image/jpeg")); items.Add(pItem); ++device; } } 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; CURL::Decode(tmp); object_id = tmp; } // try to find the device with wait on startup PLT_DeviceDataReference device; if (!FindDeviceWait(upnp, uuid, device)) goto failure; // issue a browse request with object_id // if object_id is empty use "0" for root object_id = object_id.IsEmpty()?"0":object_id; // remember a count of object classes std::map<NPT_String, int> classes; // 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 // 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->BrowseSync(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; } } NPT_String ObjectClass = (*entry)->m_ObjectClass.type.ToLowercase(); // keep count of classes classes[(*entry)->m_ObjectClass.type]++; CFileItemPtr pItem(new CFileItem((const char*)(*entry)->m_Title)); pItem->SetLabelPreformated(true); pItem->m_strTitle = (const char*)(*entry)->m_Title; pItem->m_bIsFolder = (*entry)->IsContainer(); CStdString id = (char*) (*entry)->m_ObjectID; CURL::Encode(id); pItem->SetPath(CStdString((const char*) "upnp://" + uuid + "/" + id.c_str())); // if it's a container, format a string as upnp://uuid/object_id if (pItem->m_bIsFolder) { pItem->SetPath(pItem->GetPath() + "/"); // look for metadata if( ObjectClass.StartsWith("object.container.album.videoalbum") ) { pItem->SetLabelPreformated(false); CUPnP::PopulateTagFromObject(*pItem->GetVideoInfoTag(), *(*entry), NULL); } else if( ObjectClass.StartsWith("object.container.album.photoalbum")) { //CPictureInfoTag* tag = pItem->GetPictureInfoTag(); } else if( ObjectClass.StartsWith("object.container.album") ) { pItem->SetLabelPreformated(false); CUPnP::PopulateTagFromObject(*pItem->GetMusicInfoTag(), *(*entry), NULL); } } else { // set a general content type if (ObjectClass.StartsWith("object.item.videoitem")) pItem->SetMimeType("video/octet-stream"); else if(ObjectClass.StartsWith("object.item.audioitem")) pItem->SetMimeType("audio/octet-stream"); else if(ObjectClass.StartsWith("object.item.imageitem")) pItem->SetMimeType("image/octet-stream"); if ((*entry)->m_Resources.GetItemCount()) { PLT_MediaItemResource& resource = (*entry)->m_Resources[0]; // set metadata if (resource.m_Size != (NPT_LargeSize)-1) { pItem->m_dwSize = resource.m_Size; } // look for metadata if( ObjectClass.StartsWith("object.item.videoitem") ) { pItem->SetLabelPreformated(false); CUPnP::PopulateTagFromObject(*pItem->GetVideoInfoTag(), *(*entry), &resource); } else if( ObjectClass.StartsWith("object.item.audioitem") ) { pItem->SetLabelPreformated(false); CUPnP::PopulateTagFromObject(*pItem->GetMusicInfoTag(), *(*entry), &resource); } else if( ObjectClass.StartsWith("object.item.imageitem") ) { //CPictureInfoTag* tag = pItem->GetPictureInfoTag(); } } } // 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; } // 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); PLT_ProtocolInfo fanart_mask("xbmc.org", "*", "fanart", "*"); for(unsigned i = 0; i < (*entry)->m_Resources.GetItemCount(); ++i) { PLT_MediaItemResource& res = (*entry)->m_Resources[i]; if(res.m_ProtocolInfo.Match(fanart_mask)) { pItem->SetProperty("fanart_image", (const char*)res.m_Uri); break; } } items.Add(pItem); ++entry; } NPT_String max_string = ""; int max_count = 0; for(std::map<NPT_String, int>::iterator it = classes.begin(); it != classes.end(); it++) { if(it->second > max_count) { max_string = it->first; max_count = it->second; } } items.SetContent(GetContentMapping(max_string)); } cleanup: return true; failure: return false; }
/*---------------------------------------------------------------------- | CUPnPDirectory::GetDirectory +---------------------------------------------------------------------*/ bool CUPnPDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items) { CUPnP* upnp = CUPnP::GetInstance(); /* upnp should never be cached, it has internal cache */ items.SetCacheToDisc(CFileItemList::CACHE_NEVER); // 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) { upnp->StartClient(); // root -> get list of devices const NPT_Lock<PLT_DeviceDataReferenceList>& devices = upnp->m_MediaBrowser->GetMediaServers(); NPT_List<PLT_DeviceDataReference>::Iterator device = devices.GetFirstItem(); while (device) { NPT_String name = (*device)->GetFriendlyName(); NPT_String uuid = (*device)->GetUUID(); CFileItemPtr pItem(new CFileItem((const char*)name)); pItem->SetPath(CStdString((const char*) "upnp://" + uuid + "/")); pItem->m_bIsFolder = true; pItem->SetArt("thumb", (const char*)(*device)->GetIconUrl("image/png")); items.Add(pItem); ++device; } } 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; CURL::Decode(tmp); object_id = tmp; } // try to find the device with wait on startup PLT_DeviceDataReference device; if (!FindDeviceWait(upnp, uuid, device)) goto failure; // issue a browse request with object_id // if object_id is empty use "0" for root object_id = object_id.IsEmpty()?"0":object_id; // remember a count of object classes std::map<NPT_String, int> classes; // 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 // 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->BrowseSync(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; } } // keep count of classes classes[(*entry)->m_ObjectClass.type]++; CFileItemPtr pItem = BuildObject(*entry); if(!pItem) { ++entry; continue; } CStdString id = (char*) (*entry)->m_ObjectID; CURL::Encode(id); URIUtils::AddSlashAtEnd(id); pItem->SetPath(CStdString((const char*) "upnp://" + uuid + "/" + id.c_str())); items.Add(pItem); ++entry; } NPT_String max_string = ""; int max_count = 0; for(std::map<NPT_String, int>::iterator it = classes.begin(); it != classes.end(); it++) { if(it->second > max_count) { max_string = it->first; max_count = it->second; } } std::string content = GetContentMapping(max_string); items.SetContent(content); if (content == "unknown") { items.AddSortMethod(SORT_METHOD_UNSORTED, 571, LABEL_MASKS("%L", "%I", "%L", "")); items.AddSortMethod(SORT_METHOD_LABEL_IGNORE_FOLDERS, 551, LABEL_MASKS("%L", "%I", "%L", "")); items.AddSortMethod(SORT_METHOD_SIZE, 553, LABEL_MASKS("%L", "%I", "%L", "%I")); items.AddSortMethod(SORT_METHOD_DATE, 552, LABEL_MASKS("%L", "%J", "%L", "%J")); } } cleanup: return true; failure: return false; }
/*---------------------------------------------------------------------- | PLT_MediaRenderer::OnAction +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::OnAction(PLT_ActionReference& action, const PLT_HttpRequestContext& context) { NPT_COMPILER_UNUSED(context); /* parse the action name */ NPT_String name = action->GetActionDesc().GetName(); // since all actions take an instance ID and we only support 1 instance // verify that the Instance ID is 0 and return an error here now if not NPT_String serviceType = action->GetActionDesc().GetService()->GetServiceType(); if (serviceType.Compare("urn:schemas-upnp-org:service:AVTransport:1", true) == 0) { if (NPT_FAILED(action->VerifyArgumentValue("InstanceID", "0"))) { action->SetError(718, "Not valid InstanceID"); return NPT_FAILURE; } } serviceType = action->GetActionDesc().GetService()->GetServiceType(); if (serviceType.Compare("urn:schemas-upnp-org:service:RenderingControl:1", true) == 0) { if (NPT_FAILED(action->VerifyArgumentValue("InstanceID", "0"))) { action->SetError(702, "Not valid InstanceID"); return NPT_FAILURE; } } /* Is it a ConnectionManager Service Action ? */ if (name.Compare("GetCurrentConnectionInfo", true) == 0) { return OnGetCurrentConnectionInfo(action); } /* Is it a AVTransport Service Action ? */ if (name.Compare("Next", true) == 0) { return OnNext(action); } if (name.Compare("Pause", true) == 0) { return OnPause(action); } if (name.Compare("Play", true) == 0) { return OnPlay(action); } if (name.Compare("Previous", true) == 0) { return OnPrevious(action); } if (name.Compare("Seek", true) == 0) { return OnSeek(action); } if (name.Compare("Stop", true) == 0) { return OnStop(action); } if (name.Compare("SetAVTransportURI", true) == 0) { return OnSetAVTransportURI(action); } if (name.Compare("SetNextAVTransportURI", true) == 0) { return OnSetNextAVTransportURI(action); } if (name.Compare("SetPlayMode", true) == 0) { return OnSetPlayMode(action); } /* Is it a RendererControl Service Action ? */ if (name.Compare("SetVolume", true) == 0) { return OnSetVolume(action); } if (name.Compare("SetVolumeDB", true) == 0) { return OnSetVolumeDB(action); } if (name.Compare("GetVolumeDBRange", true) == 0) { return OnGetVolumeDBRange(action); } if (name.Compare("SetMute", true) == 0) { return OnSetMute(action); } // other actions rely on state variables NPT_CHECK_LABEL_WARNING(action->SetArgumentsOutFromStateVariable(), failure); return NPT_SUCCESS; failure: action->SetError(401,"No Such Action."); return NPT_FAILURE; }
/*---------------------------------------------------------------------- | PLT_MediaController::OnActionResponse +---------------------------------------------------------------------*/ NPT_Result PLT_MediaController::OnActionResponse(NPT_Result res, PLT_ActionReference& action, void* userdata) { if (m_Delegate == NULL) return NPT_SUCCESS; PLT_DeviceDataReference device; NPT_String uuid = action->GetActionDesc().GetService()->GetDevice()->GetUUID(); /* extract action name */ NPT_String actionName = action->GetActionDesc().GetName(); /* AVTransport response ? */ if (actionName.Compare("GetCurrentTransportActions", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; return OnGetCurrentTransportActionsResponse(res, device, action, userdata); } else if (actionName.Compare("GetDeviceCapabilities", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; return OnGetDeviceCapabilitiesResponse(res, device, action, userdata); } else if (actionName.Compare("GetMediaInfo", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; return OnGetMediaInfoResponse(res, device, action, userdata); } else if (actionName.Compare("GetPositionInfo", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; return OnGetPositionInfoResponse(res, device, action, userdata); } else if (actionName.Compare("GetTransportInfo", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; return OnGetTransportInfoResponse(res, device, action, userdata); } else if (actionName.Compare("GetTransportSettings", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; return OnGetTransportSettingsResponse(res, device, action, userdata); } else if (actionName.Compare("Next", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; m_Delegate->OnNextResult(res, device, userdata); } else if (actionName.Compare("Pause", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; m_Delegate->OnPauseResult(res, device, userdata); } else if (actionName.Compare("Play", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; m_Delegate->OnPlayResult(res, device, userdata); } else if (actionName.Compare("Previous", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; m_Delegate->OnPreviousResult(res, device, userdata); } else if (actionName.Compare("Seek", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; m_Delegate->OnSeekResult(res, device, userdata); } else if (actionName.Compare("SetAVTransportURI", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; m_Delegate->OnSetAVTransportURIResult(res, device, userdata); } else if (actionName.Compare("SetPlayMode", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; m_Delegate->OnSetPlayModeResult(res, device, userdata); } else if (actionName.Compare("Stop", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; m_Delegate->OnStopResult(res, device, userdata); } else if (actionName.Compare("GetCurrentConnectionIDs", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; return OnGetCurrentConnectionIDsResponse(res, device, action, userdata); } else if (actionName.Compare("GetCurrentConnectionInfo", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; return OnGetCurrentConnectionInfoResponse(res, device, action, userdata); } else if (actionName.Compare("GetProtocolInfo", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; return OnGetProtocolInfoResponse(res, device, action, userdata); } else if (actionName.Compare("SetMute", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; m_Delegate->OnSetMuteResult(res, device, userdata); } else if (actionName.Compare("GetMute", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; return OnGetMuteResponse(res, device, action, userdata); } else if (actionName.Compare("SetVolume", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; m_Delegate->OnSetVolumeResult(res, device, userdata); } else if (actionName.Compare("GetVolume", true) == 0) { if (NPT_FAILED(FindRenderer(uuid, device))) res = NPT_FAILURE; return OnGetVolumeResponse(res, device, action, userdata); } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_MediaRenderer::OnAction +---------------------------------------------------------------------*/ NPT_Result PLT_MediaRenderer::OnAction(PLT_ActionReference& action, NPT_SocketInfo* info /* = NULL */) { NPT_COMPILER_UNUSED(info); /* parse the action name */ NPT_String name = action->GetActionDesc()->GetName(); /* Is it a ConnectionManager Service Action ? */ if (name.Compare("GetCurrentConnectionIDs", true) == 0) { if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } return NPT_SUCCESS; } if (name.Compare("GetProtocolInfo", true) == 0) { if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } return NPT_SUCCESS; } if (name.Compare("GetCurrentConnectionInfo", true) == 0) { return OnGetCurrentConnectionInfo(action); } /* Is it a AVTransport Service Action ? */ // since all actions take an instance ID and we only support 1 instance // verify that the Instance ID is 0 and return an error here now if not NPT_String serviceType = action->GetActionDesc()->GetService()->GetServiceType(); if (serviceType.Compare("urn:schemas-upnp-org:service:AVTransport:1", true) == 0) { if (NPT_FAILED(action->VerifyArgumentValue("InstanceID", "0"))) { action->SetError(802,"Not valid InstanceID."); return NPT_FAILURE; } } if (name.Compare("GetCurrentTransportActions", true) == 0) { if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } return NPT_SUCCESS; } if (name.Compare("GetDeviceCapabilities", true) == 0) { if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } return NPT_SUCCESS; } if (name.Compare("GetMediaInfo", true) == 0) { if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } return NPT_SUCCESS; } if (name.Compare("GetPositionInfo", true) == 0) { if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } return NPT_SUCCESS; } if (name.Compare("GetTransportInfo", true) == 0) { if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } return NPT_SUCCESS; } if (name.Compare("GetTransportSettings", true) == 0) { if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) { return NPT_FAILURE; } return NPT_SUCCESS; } if (name.Compare("Next", true) == 0) { return OnNext(action); } if (name.Compare("Pause", true) == 0) { return OnPause(action); } if (name.Compare("Play", true) == 0) { return OnPlay(action); } if (name.Compare("Previous", true) == 0) { return OnPrevious(action); } if (name.Compare("Seek", true) == 0) { return OnSeek(action); } if (name.Compare("Stop", true) == 0) { return OnStop(action); } if (name.Compare("SetAVTransportURI", true) == 0) { return OnSetAVTransportURI(action); } if (name.Compare("SetPlayMode", true) == 0) { return OnSetPlayMode(action); } action->SetError(401,"No Such Action."); return NPT_FAILURE; }
/*---------------------------------------------------------------------- | 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; }