diff options
author | Joakim Plate <elupus@ecce.se> | 2012-10-28 20:12:26 +0100 |
---|---|---|
committer | Joakim Plate <elupus@ecce.se> | 2013-01-20 18:31:21 +0100 |
commit | 859ab5f54f19814ae178a2f7b6e7718669229873 (patch) | |
tree | 6df35d5a5f5eebaa1763cffd30844f72959c2d30 | |
parent | 8d361fd161c11014dd3f459a922a77ddffc8053d (diff) |
upnp: add support for controlling external player
-rw-r--r-- | XBMC-ATV2.xcodeproj/project.pbxproj | 6 | ||||
-rw-r--r-- | XBMC-IOS.xcodeproj/project.pbxproj | 6 | ||||
-rw-r--r-- | XBMC.xcodeproj/project.pbxproj | 6 | ||||
-rw-r--r-- | language/English/strings.po | 6 | ||||
-rw-r--r-- | project/VS2010Express/XBMC.vcxproj | 2 | ||||
-rw-r--r-- | project/VS2010Express/XBMC.vcxproj.filters | 6 | ||||
-rw-r--r-- | xbmc/Application.cpp | 23 | ||||
-rw-r--r-- | xbmc/Application.h | 2 | ||||
-rw-r--r-- | xbmc/cores/playercorefactory/PlayerCoreConfig.h | 6 | ||||
-rw-r--r-- | xbmc/cores/playercorefactory/PlayerCoreFactory.h | 3 | ||||
-rw-r--r-- | xbmc/network/upnp/Makefile.in | 1 | ||||
-rw-r--r-- | xbmc/network/upnp/UPnP.cpp | 84 | ||||
-rw-r--r-- | xbmc/network/upnp/UPnP.h | 3 | ||||
-rw-r--r-- | xbmc/network/upnp/UPnPInternal.cpp | 4 | ||||
-rw-r--r-- | xbmc/network/upnp/UPnPPlayer.cpp | 503 | ||||
-rw-r--r-- | xbmc/network/upnp/UPnPPlayer.h | 81 | ||||
-rw-r--r-- | xbmc/settings/GUISettings.cpp | 1 | ||||
-rw-r--r-- | xbmc/settings/GUIWindowSettingsCategory.cpp | 8 |
18 files changed, 748 insertions, 3 deletions
diff --git a/XBMC-ATV2.xcodeproj/project.pbxproj b/XBMC-ATV2.xcodeproj/project.pbxproj index 426c628b84..b9e7caa400 100644 --- a/XBMC-ATV2.xcodeproj/project.pbxproj +++ b/XBMC-ATV2.xcodeproj/project.pbxproj @@ -28,6 +28,7 @@ 36A9468E15CF217400727135 /* MusicDbUrl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9468C15CF217400727135 /* MusicDbUrl.cpp */; }; 36A95DB41624898700727135 /* GUIDialogMediaFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A95DB21624898700727135 /* GUIDialogMediaFilter.cpp */; }; 4D5D2E131301753F006ABC13 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D5D2E121301753F006ABC13 /* CFNetwork.framework */; }; + 5500731516A75A2700097786 /* UPnPPlayer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5500731316A75A2700097786 /* UPnPPlayer.cpp */; }; 7C0A7ECD13A5DBF900AFC2BD /* AppParamParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C0A7ECB13A5DBF900AFC2BD /* AppParamParser.cpp */; }; 7C0A7FC813A9E75400AFC2BD /* DirtyRegionSolvers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C0A7FC413A9E75400AFC2BD /* DirtyRegionSolvers.cpp */; }; 7C0A7FC913A9E75400AFC2BD /* DirtyRegionTracker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C0A7FC613A9E75400AFC2BD /* DirtyRegionTracker.cpp */; }; @@ -1078,6 +1079,8 @@ 36A95DB21624898700727135 /* GUIDialogMediaFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogMediaFilter.cpp; sourceTree = "<group>"; }; 36A95DB31624898700727135 /* GUIDialogMediaFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogMediaFilter.h; sourceTree = "<group>"; }; 4D5D2E121301753F006ABC13 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; + 5500731316A75A2700097786 /* UPnPPlayer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UPnPPlayer.cpp; sourceTree = "<group>"; }; + 5500731416A75A2700097786 /* UPnPPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UPnPPlayer.h; sourceTree = "<group>"; }; 7C0A7ECB13A5DBF900AFC2BD /* AppParamParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppParamParser.cpp; sourceTree = "<group>"; }; 7C0A7ECC13A5DBF900AFC2BD /* AppParamParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppParamParser.h; sourceTree = "<group>"; }; 7C0A7FC313A9E75400AFC2BD /* DirtyRegion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DirtyRegion.h; sourceTree = "<group>"; }; @@ -3556,6 +3559,8 @@ DF23460815FA671900A934F6 /* UPnP.h */, DF23460915FA671900A934F6 /* UPnPInternal.cpp */, DF23460A15FA671900A934F6 /* UPnPInternal.h */, + 5500731316A75A2700097786 /* UPnPPlayer.cpp */, + 5500731416A75A2700097786 /* UPnPPlayer.h */, DF23460B15FA671900A934F6 /* UPnPRenderer.cpp */, DF23460C15FA671900A934F6 /* UPnPRenderer.h */, DF23460D15FA671900A934F6 /* UPnPServer.cpp */, @@ -7667,6 +7672,7 @@ DFB02E0816629E1900F37752 /* PyContext.cpp in Sources */, DF07255216873553008DCAAD /* karaokevideobackground.cpp in Sources */, DF07255516873565008DCAAD /* FFmpegVideoDecoder.cpp in Sources */, + 5500731516A75A2700097786 /* UPnPPlayer.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/XBMC-IOS.xcodeproj/project.pbxproj b/XBMC-IOS.xcodeproj/project.pbxproj index 8422f21fd4..e571209529 100644 --- a/XBMC-IOS.xcodeproj/project.pbxproj +++ b/XBMC-IOS.xcodeproj/project.pbxproj @@ -29,6 +29,7 @@ 36A9467E15CF20E100727135 /* DbUrl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9467C15CF20E100727135 /* DbUrl.cpp */; }; 36A95DAD1624896C00727135 /* GUIDialogMediaFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A95DAB1624896C00727135 /* GUIDialogMediaFilter.cpp */; }; 4D5D2E1E1301758F006ABC13 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D5D2E1D1301758F006ABC13 /* CFNetwork.framework */; }; + 5500730E16A759D800097786 /* UPnPPlayer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5500730C16A759D800097786 /* UPnPPlayer.cpp */; }; 7C0A7EDE13A5DC2800AFC2BD /* AppParamParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C0A7EDC13A5DC2800AFC2BD /* AppParamParser.cpp */; }; 7C0A7F9D13A9E70800AFC2BD /* GUIWindowDebugInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C0A7F9B13A9E70800AFC2BD /* GUIWindowDebugInfo.cpp */; }; 7C0A7FB213A9E72E00AFC2BD /* DirtyRegionSolvers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C0A7FAE13A9E72E00AFC2BD /* DirtyRegionSolvers.cpp */; }; @@ -1080,6 +1081,8 @@ 36A95DAB1624896C00727135 /* GUIDialogMediaFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDialogMediaFilter.cpp; sourceTree = "<group>"; }; 36A95DAC1624896C00727135 /* GUIDialogMediaFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDialogMediaFilter.h; sourceTree = "<group>"; }; 4D5D2E1D1301758F006ABC13 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; }; + 5500730C16A759D800097786 /* UPnPPlayer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UPnPPlayer.cpp; sourceTree = "<group>"; }; + 5500730D16A759D800097786 /* UPnPPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UPnPPlayer.h; sourceTree = "<group>"; }; 7C0A7EDC13A5DC2800AFC2BD /* AppParamParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppParamParser.cpp; sourceTree = "<group>"; }; 7C0A7EDD13A5DC2800AFC2BD /* AppParamParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppParamParser.h; sourceTree = "<group>"; }; 7C0A7F9B13A9E70800AFC2BD /* GUIWindowDebugInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIWindowDebugInfo.cpp; sourceTree = "<group>"; }; @@ -3560,6 +3563,8 @@ DF23461A15FA675200A934F6 /* UPnP.h */, DF23461B15FA675200A934F6 /* UPnPInternal.cpp */, DF23461C15FA675200A934F6 /* UPnPInternal.h */, + 5500730C16A759D800097786 /* UPnPPlayer.cpp */, + 5500730D16A759D800097786 /* UPnPPlayer.h */, DF23461D15FA675200A934F6 /* UPnPRenderer.cpp */, DF23461E15FA675200A934F6 /* UPnPRenderer.h */, DF23461F15FA675200A934F6 /* UPnPServer.cpp */, @@ -7692,6 +7697,7 @@ DFB02DFB16629DF200F37752 /* PyContext.cpp in Sources */, DF07254116873517008DCAAD /* karaokevideobackground.cpp in Sources */, DF0725441687352C008DCAAD /* FFmpegVideoDecoder.cpp in Sources */, + 5500730E16A759D800097786 /* UPnPPlayer.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/XBMC.xcodeproj/project.pbxproj b/XBMC.xcodeproj/project.pbxproj index bf4a009b7a..0fced6e8b1 100644 --- a/XBMC.xcodeproj/project.pbxproj +++ b/XBMC.xcodeproj/project.pbxproj @@ -241,6 +241,7 @@ 43BF09A21080D1E900E25290 /* AVTransportSCPD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 43BF099E1080D1E900E25290 /* AVTransportSCPD.cpp */; settings = {COMPILER_FLAGS = "-I$SRCROOT/lib/libUPnP/Platinum/Source/Core -I$SRCROOT/lib/libUPnP/Platinum/Source/Platinum -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaConnect -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaRenderer -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaServer -I$SRCROOT/lib/libUPnP/Platinum/Source/Extras -I$SRCROOT/lib/libUPnP/Neptune/Source/System/Posix -I$SRCROOT/lib/libUPnP/Neptune/Source/Core"; }; }; 43BF09A31080D1E900E25290 /* RenderingControlSCPD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 43BF099F1080D1E900E25290 /* RenderingControlSCPD.cpp */; settings = {COMPILER_FLAGS = "-I$SRCROOT/lib/libUPnP/Platinum/Source/Core -I$SRCROOT/lib/libUPnP/Platinum/Source/Platinum -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaConnect -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaRenderer -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaServer -I$SRCROOT/lib/libUPnP/Platinum/Source/Extras -I$SRCROOT/lib/libUPnP/Neptune/Source/System/Posix -I$SRCROOT/lib/libUPnP/Neptune/Source/Core"; }; }; 43BF09AB1080D2ED00E25290 /* RdrConnectionManagerSCPD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 43BF09A81080D2ED00E25290 /* RdrConnectionManagerSCPD.cpp */; settings = {COMPILER_FLAGS = "-I$SRCROOT/lib/libUPnP/Platinum/Source/Core -I$SRCROOT/lib/libUPnP/Platinum/Source/Platinum -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaConnect -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaRenderer -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaServer -I$SRCROOT/lib/libUPnP/Platinum/Source/Extras -I$SRCROOT/lib/libUPnP/Neptune/Source/System/Posix -I$SRCROOT/lib/libUPnP/Neptune/Source/Core"; }; }; + 552840CC1626163B00ED1333 /* UPnPPlayer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 552840CA1626163B00ED1333 /* UPnPPlayer.cpp */; settings = {COMPILER_FLAGS = "-I$SRCROOT/lib/libUPnP/Platinum/Source/Core -I$SRCROOT/lib/libUPnP/Platinum/Source/Platinum -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaConnect -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaRenderer -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaServer -I$SRCROOT/lib/libUPnP/Platinum/Source/Extras -I$SRCROOT/lib/libUPnP/Neptune/Source/System/Posix -I$SRCROOT/lib/libUPnP/Neptune/Source/Core"; }; }; 552A226915F7E14B0015C0D0 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 552A226815F7E14B0015C0D0 /* main.cpp */; }; 553840F215F360B400CE061B /* PltMimeType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 553840ED15F360B400CE061B /* PltMimeType.cpp */; settings = {COMPILER_FLAGS = "-I$SRCROOT/lib/libUPnP/Platinum/Source/Core -I$SRCROOT/lib/libUPnP/Platinum/Source/Platinum -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaConnect -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaRenderer -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaServer -I$SRCROOT/lib/libUPnP/Platinum/Source/Extras -I$SRCROOT/lib/libUPnP/Neptune/Source/System/Posix -I$SRCROOT/lib/libUPnP/Neptune/Source/Core"; }; }; 553840F315F360B400CE061B /* PltProtocolInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 553840EF15F360B400CE061B /* PltProtocolInfo.cpp */; settings = {COMPILER_FLAGS = "-I$SRCROOT/lib/libUPnP/Platinum/Source/Core -I$SRCROOT/lib/libUPnP/Platinum/Source/Platinum -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaConnect -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaRenderer -I$SRCROOT/lib/libUPnP/Platinum/Source/Devices/MediaServer -I$SRCROOT/lib/libUPnP/Platinum/Source/Extras -I$SRCROOT/lib/libUPnP/Neptune/Source/System/Posix -I$SRCROOT/lib/libUPnP/Neptune/Source/Core"; }; }; @@ -1539,6 +1540,8 @@ 43BF09A91080D2ED00E25290 /* RenderingControlSCPD_Full.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = RenderingControlSCPD_Full.xml; sourceTree = "<group>"; }; 43BF09DD1080D39300E25290 /* fastmemcpy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = fastmemcpy.h; sourceTree = "<group>"; }; 43FAC87112D6349400F67914 /* IStorageProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IStorageProvider.h; sourceTree = "<group>"; }; + 552840CA1626163B00ED1333 /* UPnPPlayer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UPnPPlayer.cpp; sourceTree = "<group>"; }; + 552840CB1626163B00ED1333 /* UPnPPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UPnPPlayer.h; sourceTree = "<group>"; }; 552A226815F7E14B0015C0D0 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = main/main.cpp; sourceTree = "<group>"; }; 553840ED15F360B400CE061B /* PltMimeType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PltMimeType.cpp; sourceTree = "<group>"; }; 553840EE15F360B400CE061B /* PltMimeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PltMimeType.h; sourceTree = "<group>"; }; @@ -4566,6 +4569,8 @@ DF2345D715FA639500A934F6 /* upnp */ = { isa = PBXGroup; children = ( + 552840CA1626163B00ED1333 /* UPnPPlayer.cpp */, + 552840CB1626163B00ED1333 /* UPnPPlayer.h */, DF2345D915FA639500A934F6 /* UPnP.cpp */, DF2345DA15FA639500A934F6 /* UPnP.h */, DF2345DB15FA639500A934F6 /* UPnPInternal.cpp */, @@ -7665,6 +7670,7 @@ DFB15B2215F8FB8100CDF0DE /* SDLMain.mm in Sources */, DF2345E115FA639500A934F6 /* UPnP.cpp in Sources */, DF2345E215FA639500A934F6 /* UPnPInternal.cpp in Sources */, + 552840CC1626163B00ED1333 /* UPnPPlayer.cpp in Sources */, DF2345E315FA639500A934F6 /* UPnPRenderer.cpp in Sources */, DF2345E415FA639500A934F6 /* UPnPServer.cpp in Sources */, AE84CB5A15A5B8A600A3810E /* TagLibVFSStream.cpp in Sources */, diff --git a/language/English/strings.po b/language/English/strings.po index dff2978eed..ddbc987fe3 100644 --- a/language/English/strings.po +++ b/language/English/strings.po @@ -9350,7 +9350,11 @@ msgctxt "#21360" msgid "Share video and music libraries through UPnP" msgstr "" -#empty strings from id 21361 to 21363 +msgctxt "#21361" +msgid "Look for remote UPnP players" +msgstr "" + +#empty strings from id 21362 to 21363 msgctxt "#21364" msgid "Edit media share" diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj index fb0947e22f..48ef1202cc 100644 --- a/project/VS2010Express/XBMC.vcxproj +++ b/project/VS2010Express/XBMC.vcxproj @@ -841,6 +841,7 @@ <ClCompile Include="..\..\xbmc\network\UdpClient.cpp" /> <ClCompile Include="..\..\xbmc\network\upnp\UPnP.cpp" /> <ClCompile Include="..\..\xbmc\network\upnp\UPnPInternal.cpp" /> + <ClCompile Include="..\..\xbmc\network\upnp\UPnPPlayer.cpp" /> <ClCompile Include="..\..\xbmc\network\upnp\UPnPRenderer.cpp" /> <ClCompile Include="..\..\xbmc\network\upnp\UPnPServer.cpp" /> <ClCompile Include="..\..\xbmc\network\WebServer.cpp" /> @@ -1095,6 +1096,7 @@ <ClInclude Include="..\..\xbmc\network\DllLibShairplay.h" /> <ClInclude Include="..\..\xbmc\network\upnp\UPnP.h" /> <ClInclude Include="..\..\xbmc\network\upnp\UPnPInternal.h" /> + <ClInclude Include="..\..\xbmc\network\upnp\UPnPPlayer.h" /> <ClInclude Include="..\..\xbmc\network\upnp\UPnPRenderer.h" /> <ClInclude Include="..\..\xbmc\network\upnp\UPnPServer.h" /> <ClInclude Include="..\..\xbmc\network\websocket\WebSocket.h" /> diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters index 53a6c9754f..e214bdca91 100644 --- a/project/VS2010Express/XBMC.vcxproj.filters +++ b/project/VS2010Express/XBMC.vcxproj.filters @@ -2798,6 +2798,9 @@ <ClCompile Include="..\..\xbmc\network\upnp\UPnPInternal.cpp"> <Filter>network\upnp</Filter> </ClCompile> + <ClCompile Include="..\..\xbmc\network\upnp\UPnPPlayer.cpp"> + <Filter>network\upnp</Filter> + </ClCompile> <ClCompile Include="..\..\xbmc\network\upnp\UPnPRenderer.cpp"> <Filter>network\upnp</Filter> </ClCompile> @@ -5602,6 +5605,9 @@ <ClInclude Include="..\..\xbmc\network\upnp\UPnPInternal.h"> <Filter>network\upnp</Filter> </ClInclude> + <ClInclude Include="..\..\xbmc\network\upnp\UPnPPlayer.h"> + <Filter>network\upnp</Filter> + </ClInclude> <ClInclude Include="..\..\xbmc\network\upnp\UPnPRenderer.h"> <Filter>network\upnp</Filter> </ClInclude> diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp index 665434a658..0a8a6df8ec 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp @@ -1661,6 +1661,7 @@ void CApplication::StopJSONRPCServer(bool bWait) void CApplication::StartUPnP() { #ifdef HAS_UPNP + StartUPnPClient(); StartUPnPServer(); StartUPnPRenderer(); #endif @@ -1744,6 +1745,28 @@ void CApplication::RefreshEventServer() #endif } +void CApplication::StartUPnPClient() +{ +#ifdef HAS_UPNP + if (g_guiSettings.GetBool("services.upnpcontroller")) + { + CLog::Log(LOGNOTICE, "starting upnp client"); + UPNP::CUPnP::GetInstance()->StartClient(); + } +#endif +} + +void CApplication::StopUPnPClient() +{ +#ifdef HAS_UPNP + if (UPNP::CUPnP::IsInstantiated()) + { + CLog::Log(LOGNOTICE, "stopping upnp client"); + UPNP::CUPnP::GetInstance()->StopClient(); + } +#endif +} + void CApplication::StartUPnPRenderer() { #ifdef HAS_UPNP diff --git a/xbmc/Application.h b/xbmc/Application.h index 69609fae74..bb0c0c7c9d 100644 --- a/xbmc/Application.h +++ b/xbmc/Application.h @@ -145,6 +145,8 @@ public: void StopJSONRPCServer(bool bWait); void StartUPnP(); void StopUPnP(bool bWait); + void StartUPnPClient(); + void StopUPnPClient(); void StartUPnPRenderer(); void StopUPnPRenderer(); void StartUPnPServer(); diff --git a/xbmc/cores/playercorefactory/PlayerCoreConfig.h b/xbmc/cores/playercorefactory/PlayerCoreConfig.h index 3a50b6909c..da8e4f911e 100644 --- a/xbmc/cores/playercorefactory/PlayerCoreConfig.h +++ b/xbmc/cores/playercorefactory/PlayerCoreConfig.h @@ -31,6 +31,9 @@ #include "cores/omxplayer/OMXPlayer.h" #endif #include "cores/ExternalPlayer/ExternalPlayer.h" +#ifdef HAS_UPNP +#include "network/upnp/UPnPPlayer.h" +#endif #include "utils/log.h" class CPlayerCoreConfig @@ -108,6 +111,9 @@ public: #if defined(HAS_OMXPLAYER) case EPC_OMXPLAYER: pPlayer = new COMXPlayer(callback); break; #endif +#if defined(HAS_UPNP) + case EPC_UPNPPLAYER: pPlayer = new UPNP::CUPnPPlayer(callback, m_id.c_str()); break; +#endif default: return NULL; } diff --git a/xbmc/cores/playercorefactory/PlayerCoreFactory.h b/xbmc/cores/playercorefactory/PlayerCoreFactory.h index 82eea4a56f..fa7064bd33 100644 --- a/xbmc/cores/playercorefactory/PlayerCoreFactory.h +++ b/xbmc/cores/playercorefactory/PlayerCoreFactory.h @@ -42,7 +42,8 @@ enum EPLAYERCORES #if defined(HAS_OMXPLAYER) EPC_OMXPLAYER, #endif - EPC_EXTPLAYER + EPC_EXTPLAYER, + EPC_UPNPPLAYER, }; typedef unsigned int PLAYERCOREID; diff --git a/xbmc/network/upnp/Makefile.in b/xbmc/network/upnp/Makefile.in index 313f81b65d..ac3ef30e0f 100644 --- a/xbmc/network/upnp/Makefile.in +++ b/xbmc/network/upnp/Makefile.in @@ -9,6 +9,7 @@ INCLUDES+=-I@abs_top_srcdir@/lib/libUPnP/Platinum/Source/Core \ -I@abs_top_srcdir@/lib/libUPnP/Neptune/Source/Core SRCS= UPnP.cpp \ + UPnPPlayer.cpp \ UPnPRenderer.cpp \ UPnPServer.cpp \ UPnPInternal.cpp diff --git a/xbmc/network/upnp/UPnP.cpp b/xbmc/network/upnp/UPnP.cpp index 03fb92d322..591590c5e0 100644 --- a/xbmc/network/upnp/UPnP.cpp +++ b/xbmc/network/upnp/UPnP.cpp @@ -192,10 +192,77 @@ public: /*---------------------------------------------------------------------- +| CMediaController class ++---------------------------------------------------------------------*/ +class CMediaController + : public PLT_MediaControllerDelegate + , public PLT_MediaController +{ +public: + CMediaController(PLT_CtrlPointReference& ctrl_point) + : PLT_MediaController(ctrl_point) + { + PLT_MediaController::SetDelegate(this); + } + + ~CMediaController() + { + } + + virtual void OnStopResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata) + { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnStopResult(res, device, userdata); } + + virtual void OnSetPlayModeResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata) + { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnSetPlayModeResult(res, device, userdata); } + + virtual void OnSetAVTransportURIResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata) + { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnSetAVTransportURIResult(res, device, userdata); } + + virtual void OnSeekResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata) + { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnSeekResult(res, device, userdata); } + + virtual void OnPreviousResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata) + { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnPreviousResult(res, device, userdata); } + + virtual void OnPlayResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata) + { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnPlayResult(res, device, userdata); } + + virtual void OnPauseResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata) + { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnPauseResult(res, device, userdata); } + + virtual void OnNextResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata) + { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnNextResult(res, device, userdata); } + + virtual void OnGetMediaInfoResult(NPT_Result res, PLT_DeviceDataReference& device, PLT_MediaInfo* info, void* userdata) + { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnGetMediaInfoResult(res, device, info, userdata); } + + virtual void OnGetPositionInfoResult(NPT_Result res, PLT_DeviceDataReference& device, PLT_PositionInfo* info, void* userdata) + { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnGetPositionInfoResult(res, device, info, userdata); } + + virtual void OnGetTransportInfoResult(NPT_Result res, PLT_DeviceDataReference& device, PLT_TransportInfo* info, void* userdata) + { static_cast<PLT_MediaControllerDelegate*>(userdata)->OnGetTransportInfoResult(res, device, info, userdata); } + + + virtual bool OnMRAdded(PLT_DeviceDataReference& device ) + { + CPlayerCoreFactory::OnPlayerDiscovered((const char*)device->GetUUID() + ,(const char*)device->GetFriendlyName() + , EPC_UPNPPLAYER); + return true; + } + + virtual void OnMRRemoved(PLT_DeviceDataReference& device ) + { + CPlayerCoreFactory::OnPlayerRemoved((const char*)device->GetUUID()); + } +}; + +/*---------------------------------------------------------------------- | CUPnP::CUPnP +---------------------------------------------------------------------*/ CUPnP::CUPnP() : m_MediaBrowser(NULL), + m_MediaController(NULL), m_ServerHolder(new CDeviceHostReferenceHolder()), m_RendererHolder(new CRendererReferenceHolder()), m_CtrlPointHolder(new CCtrlPointReferenceHolder()) @@ -268,6 +335,16 @@ CUPnP::ReleaseInstance(bool bWait) } /*---------------------------------------------------------------------- +| CUPnP::StartServer ++---------------------------------------------------------------------*/ +CUPnPServer* CUPnP::GetServer() +{ + if(upnp) + return (CUPnPServer*)upnp->m_ServerHolder->m_Device.AsPointer(); + return NULL; +} + +/*---------------------------------------------------------------------- | CUPnP::StartClient +---------------------------------------------------------------------*/ void @@ -283,6 +360,11 @@ CUPnP::StartClient() // start browser m_MediaBrowser = new CMediaBrowser(m_CtrlPointHolder->m_CtrlPoint); + + // start controller + if (g_guiSettings.GetBool("services.upnpcontroller")) { + m_MediaController = new CMediaController(m_CtrlPointHolder->m_CtrlPoint); + } } /*---------------------------------------------------------------------- @@ -298,6 +380,8 @@ CUPnP::StopClient() delete m_MediaBrowser; m_MediaBrowser = NULL; + delete m_MediaController; + m_MediaController = NULL; } /*---------------------------------------------------------------------- diff --git a/xbmc/network/upnp/UPnP.h b/xbmc/network/upnp/UPnP.h index f253378355..ce39d79fb3 100644 --- a/xbmc/network/upnp/UPnP.h +++ b/xbmc/network/upnp/UPnP.h @@ -27,6 +27,7 @@ class PLT_UPnP; class PLT_SyncMediaBrowser; +class PLT_MediaController; class PLT_MediaObject; class PLT_MediaItemResource; @@ -61,6 +62,7 @@ public: // class methods static CUPnP* GetInstance(); + static CUPnPServer* GetServer(); static void ReleaseInstance(bool bWait); static bool IsInstantiated() { return upnp != NULL; } @@ -71,6 +73,7 @@ private: public: PLT_SyncMediaBrowser* m_MediaBrowser; + PLT_MediaController* m_MediaController; private: CStdString m_IP; diff --git a/xbmc/network/upnp/UPnPInternal.cpp b/xbmc/network/upnp/UPnPInternal.cpp index b8bf9acb05..77a0a3d770 100644 --- a/xbmc/network/upnp/UPnPInternal.cpp +++ b/xbmc/network/upnp/UPnPInternal.cpp @@ -311,7 +311,7 @@ BuildObject(CFileItem& item, PLT_MediaObject* object = NULL; std::string thumb, fanart; - CLog::Log(LOGDEBUG, "Building didl for object '%s'", (const char*)item.GetPath()); + CLog::Log(LOGDEBUG, "UPnP: Building didl for object '%s'", (const char*)item.GetPath()); EClientQuirks quirks = GetClientQuirks(context); @@ -326,6 +326,8 @@ BuildObject(CFileItem& item, rooturi = NPT_HttpUrl(context->GetLocalAddress().GetIpAddress().ToString(), context->GetLocalAddress().GetPort(), "/"); ips.Remove(context->GetLocalAddress().GetIpAddress()); ips.Insert(ips.GetFirstItem(), context->GetLocalAddress().GetIpAddress()); + } else if(upnp_server) { + rooturi = NPT_HttpUrl("localhost", upnp_server->GetPort(), "/"); } if (!item.m_bIsFolder) { diff --git a/xbmc/network/upnp/UPnPPlayer.cpp b/xbmc/network/upnp/UPnPPlayer.cpp new file mode 100644 index 0000000000..5695e44686 --- /dev/null +++ b/xbmc/network/upnp/UPnPPlayer.cpp @@ -0,0 +1,503 @@ +/* +* Copyright (c) 2006 elupus (Joakim Plate) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "UPnPPlayer.h" +#include "UPnP.h" +#include "UPnPInternal.h" +#include "Platinum.h" +#include "PltMediaController.h" +#include "PltDidl.h" +#include "FileItem.h" +#include "threads/Event.h" +#include "utils/log.h" +#include "utils/TimeUtils.h" +#include "GUIInfoManager.h" +#include "ThumbLoader.h" +#include "video/VideoThumbLoader.h" +#include "music/MusicThumbLoader.h" +#include "ApplicationMessenger.h" +#include "Application.h" +#include "dialogs/GUIDialogBusy.h" +#include "guilib/GUIWindowManager.h" + + +NPT_SET_LOCAL_LOGGER("xbmc.upnp.player") + +namespace UPNP +{ + +class CUPnPPlayerController + : public PLT_MediaControllerDelegate +{ +public: + CUPnPPlayerController(PLT_MediaController* control, PLT_DeviceDataReference& device, IPlayerCallback& callback) + : m_control(control) + , m_transport(NULL) + , m_device(device) + , m_instance(0) + , m_callback(callback) + , m_postime(0) + { + memset(&m_posinfo, 0, sizeof(m_posinfo)); + m_device->FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", m_transport); + } + + virtual void OnSetAVTransportURIResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata) + { + if(NPT_FAILED(res)) + CLog::Log(LOGERROR, "UPNP: CUPnPPlayer : OnSetAVTransportURIResult failed"); + m_resstatus = res; + m_resevent.Set(); + } + + virtual void OnPlayResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata) + { + if(NPT_FAILED(res)) + CLog::Log(LOGERROR, "UPNP: CUPnPPlayer : OnPlayResult failed"); + m_resstatus = res; + m_resevent.Set(); + } + + virtual void OnStopResult(NPT_Result res, PLT_DeviceDataReference& device, void* userdata) + { + if(NPT_FAILED(res)) + CLog::Log(LOGERROR, "UPNP: CUPnPPlayer : OnStopResult failed"); + m_resstatus = res; + m_resevent.Set(); + } + + virtual void OnGetMediaInfoResult(NPT_Result res, PLT_DeviceDataReference& device, PLT_MediaInfo* info, void* userdata) + { + if(NPT_FAILED(res) || info == NULL) + CLog::Log(LOGERROR, "UPNP: CUPnPPlayer : OnGetMediaInfoResult failed"); + } + + virtual void OnGetTransportInfoResult(NPT_Result res, PLT_DeviceDataReference& device, PLT_TransportInfo* info, void* userdata) + { + CSingleLock lock(m_section); + + if(NPT_FAILED(res)) + { + CLog::Log(LOGERROR, "UPNP: CUPnPPlayer : OnGetTransportInfoResult failed"); + m_trainfo.cur_speed = "0"; + m_trainfo.cur_transport_state = "STOPPED"; + m_trainfo.cur_transport_status = "ERROR_OCCURED"; + } + else + m_trainfo = *info; + m_traevnt.Set(); + } + + void UpdatePositionInfo() + { + if(m_postime == 0 + || m_postime > CTimeUtils::GetFrameTime()) + return; + + m_control->GetTransportInfo(m_device, m_instance, this); + m_control->GetPositionInfo(m_device, m_instance, this); + m_postime = 0; + } + + virtual void OnGetPositionInfoResult(NPT_Result res, PLT_DeviceDataReference& device, PLT_PositionInfo* info, void* userdata) + { + CSingleLock lock(m_section); + + if(NPT_FAILED(res) || info == NULL) + { + CLog::Log(LOGERROR, "UPNP: CUPnPPlayer : OnGetMediaInfoResult failed"); + m_posinfo = PLT_PositionInfo(); + } + else + m_posinfo = *info; + m_postime = CTimeUtils::GetFrameTime() + 500; + m_posevnt.Set(); + } + + + ~CUPnPPlayerController() + { + } + + PLT_MediaController* m_control; + PLT_Service * m_transport; + PLT_DeviceDataReference m_device; + NPT_UInt32 m_instance; + IPlayerCallback& m_callback; + + NPT_Result m_resstatus; + CEvent m_resevent; + + CCriticalSection m_section; + unsigned int m_postime; + + CEvent m_posevnt; + PLT_PositionInfo m_posinfo; + + CEvent m_traevnt; + PLT_TransportInfo m_trainfo; +}; + +CUPnPPlayer::CUPnPPlayer(IPlayerCallback& callback, const char* uuid) +: IPlayer(callback) +, m_control(NULL) +, m_delegate(NULL) +, m_started(false) +{ + m_control = CUPnP::GetInstance()->m_MediaController; + + PLT_DeviceDataReference device; + if(NPT_SUCCEEDED(m_control->FindRenderer(uuid, device))) + m_delegate = new CUPnPPlayerController(m_control, device, callback); + else + CLog::Log(LOGERROR, "UPNP: CUPnPPlayer couldn't find device as %s", uuid); +} + +CUPnPPlayer::~CUPnPPlayer() +{ + CloseFile(); +} + +static NPT_Result WaitOnEvent(CEvent& event, XbmcThreads::EndTime& timeout, CGUIDialogBusy*& dialog) +{ + if(event.WaitMSec(0)) + return NPT_SUCCESS; + + if(dialog == NULL) { + dialog = (CGUIDialogBusy*)g_windowManager.GetWindow(WINDOW_DIALOG_BUSY); + dialog->Show(); + } + + g_windowManager.ProcessRenderLoop(false); + + do { + if(event.WaitMSec(100)) + return NPT_SUCCESS; + + g_windowManager.ProcessRenderLoop(false); + + if(dialog->IsCanceled()) + return NPT_FAILURE; + + } while(!timeout.IsTimePast()); + + return NPT_FAILURE; +} + +bool CUPnPPlayer::OpenFile(const CFileItem& file, const CPlayerOptions& options) +{ + CFileItem item(file); + NPT_Reference<CThumbLoader> thumb_loader; + NPT_Reference<PLT_MediaObject> obj; + NPT_String path(file.GetPath().c_str()); + NPT_String tmp, resource; + XbmcThreads::EndTime timeout; + CGUIDialogBusy* dialog = NULL; + + NPT_CHECK_POINTER_LABEL_SEVERE(m_delegate, failed); + + /* if no path we want to attach to a already playing player */ + if(path != "") { + if (file.IsVideoDb()) + thumb_loader = NPT_Reference<CThumbLoader>(new CVideoThumbLoader()); + else if (item.IsMusicDb()) + thumb_loader = NPT_Reference<CThumbLoader>(new CMusicThumbLoader()); + + obj = BuildObject(item, path, false, thumb_loader, NULL, CUPnP::GetServer()); + if(obj.IsNull()) goto failed; + + NPT_CHECK_LABEL_SEVERE(PLT_Didl::ToDidl(*obj, "", tmp), failed); + tmp.Insert(didl_header, 0); + tmp.Append(didl_footer); + + /* The resource uri's are stored in the Didl. We must choose the best resource + * for the playback device */ + NPT_Cardinal res_index; + NPT_CHECK_LABEL_SEVERE(m_control->FindBestResource(m_delegate->m_device, *obj, res_index), failed); + + + /* dlna specifies that a return code of 705 should be returned + * if TRANSPORT_STATE is not STOPPED or NO_MEDIA_PRESENT */ + NPT_CHECK_LABEL_SEVERE(m_control->Stop(m_delegate->m_device + , m_delegate->m_instance + , m_delegate), failed); + NPT_CHECK_LABEL_SEVERE(WaitOnEvent(m_delegate->m_resevent, timeout, dialog), failed); + NPT_CHECK_LABEL_SEVERE(m_delegate->m_resstatus, failed); + + + NPT_CHECK_LABEL_SEVERE(m_control->SetAVTransportURI(m_delegate->m_device + , m_delegate->m_instance + , obj->m_Resources[res_index].m_Uri + , (const char*)tmp + , m_delegate), failed); + NPT_CHECK_LABEL_SEVERE(WaitOnEvent(m_delegate->m_resevent, timeout, dialog), failed); + NPT_CHECK_LABEL_SEVERE(m_delegate->m_resstatus, failed); + + NPT_CHECK_LABEL_SEVERE(m_control->Play(m_delegate->m_device + , m_delegate->m_instance + , "1" + , m_delegate), failed); + NPT_CHECK_LABEL_SEVERE(WaitOnEvent(m_delegate->m_resevent, timeout, dialog), failed); + NPT_CHECK_LABEL_SEVERE(m_delegate->m_resstatus, failed); + } + + + /* wait for PLAYING state */ + timeout.Set(10000); + do { + NPT_CHECK_LABEL_SEVERE(m_control->GetTransportInfo(m_delegate->m_device + , m_delegate->m_instance + , m_delegate), failed); + + + { CSingleLock lock(m_delegate->m_section); + if(m_delegate->m_trainfo.cur_transport_state == "PLAYING" + || m_delegate->m_trainfo.cur_transport_state == "PAUSED_PLAYBACK") + break; + + if(m_delegate->m_trainfo.cur_transport_state == "STOPPED" + && m_delegate->m_trainfo.cur_transport_status != "OK") + { + CLog::Log(LOGERROR, "UPNP: CUPnPPlayer::OpenFile - remote player signalled error %s", file.GetPath().c_str()); + goto failed; + } + } + + NPT_CHECK_LABEL_SEVERE(WaitOnEvent(m_delegate->m_traevnt, timeout, dialog), failed); + + } while(!timeout.IsTimePast()); + + if(options.starttime > 0) + { + /* many upnp units won't load file properly until after play (including xbmc) */ + NPT_CHECK_LABEL(m_control->Seek(m_delegate->m_device + , m_delegate->m_instance + , "REL_TIME" + , PLT_Didl::FormatTimeStamp((NPT_UInt32)options.starttime) + , m_delegate), failed); + } + + m_started = true; + m_callback.OnPlayBackStarted(); + NPT_CHECK_LABEL_SEVERE(m_control->GetPositionInfo(m_delegate->m_device + , m_delegate->m_instance + , m_delegate), failed); + NPT_CHECK_LABEL_SEVERE(m_control->GetMediaInfo(m_delegate->m_device + , m_delegate->m_instance + , m_delegate), failed); + + if(dialog) + dialog->Close(); + + return true; +failed: + CLog::Log(LOGERROR, "UPNP: CUPnPPlayer::OpenFile - unable to open file %s", file.GetPath().c_str()); + if(dialog) + dialog->Close(); + return false; +} + +bool CUPnPPlayer::QueueNextFile(const CFileItem& file) +{ + CFileItem item(file); + NPT_Reference<CThumbLoader> thumb_loader; + NPT_Reference<PLT_MediaObject> obj; + NPT_String path(file.GetPath().c_str()); + NPT_String tmp; + + if (file.IsVideoDb()) + thumb_loader = NPT_Reference<CThumbLoader>(new CVideoThumbLoader()); + else if (item.IsMusicDb()) + thumb_loader = NPT_Reference<CThumbLoader>(new CMusicThumbLoader()); + + + obj = BuildObject(item, path, 0, thumb_loader, NULL, CUPnP::GetServer()); + if(!obj.IsNull()) + { + NPT_CHECK_LABEL_SEVERE(PLT_Didl::ToDidl(*obj, "", tmp), failed); + tmp.Insert(didl_header, 0); + tmp.Append(didl_footer); + } + + NPT_CHECK_LABEL_WARNING(m_control->SetNextAVTransportURI(m_delegate->m_device + , m_delegate->m_instance + , file.GetPath().c_str() + , (const char*)tmp + , m_delegate), failed); + if(!m_delegate->m_resevent.WaitMSec(10000)) goto failed; + NPT_CHECK_LABEL_WARNING(m_delegate->m_resstatus, failed); + return true; + +failed: + CLog::Log(LOGERROR, "UPNP: CUPnPPlayer::QueueNextFile - unable to queue file %s", file.GetPath().c_str()); + return false; +} + +bool CUPnPPlayer::CloseFile() +{ + NPT_CHECK_POINTER_LABEL_SEVERE(m_delegate, failed); + NPT_CHECK_LABEL(m_control->Stop(m_delegate->m_device + , m_delegate->m_instance + , m_delegate), failed); + if(!m_delegate->m_resevent.WaitMSec(10000)) goto failed; + NPT_CHECK_LABEL(m_delegate->m_resstatus, failed); + m_callback.OnPlayBackStopped(); + return true; +failed: + CLog::Log(LOGERROR, "UPNP: CUPnPPlayer::CloseFile - unable to stop playback"); + return false; +} + +void CUPnPPlayer::Pause() +{ + if(IsPaused()) + NPT_CHECK_LABEL(m_control->Play(m_delegate->m_device + , m_delegate->m_instance + , "1" + , m_delegate), failed); + else + NPT_CHECK_LABEL(m_control->Pause(m_delegate->m_device + , m_delegate->m_instance + , m_delegate), failed); + + return; +failed: + CLog::Log(LOGERROR, "UPNP: CUPnPPlayer::CloseFile - unable to pause/unpause playback"); + return; +} + +void CUPnPPlayer::SeekTime(__int64 ms) +{ + NPT_CHECK_LABEL(m_control->Seek(m_delegate->m_device + , m_delegate->m_instance + , "REL_TIME", PLT_Didl::FormatTimeStamp(ms / 1000) + , m_delegate), failed); + + g_infoManager.SetDisplayAfterSeek(); + return; +failed: + CLog::Log(LOGERROR, "UPNP: CUPnPPlayer::SeekTime - unable to seek playback"); +} + +float CUPnPPlayer::GetPercentage() +{ + int64_t tot = GetTotalTime(); + if(tot) + return 100.0f * GetTime() / tot; + else + return 0.0f; +} + +void CUPnPPlayer::SeekPercentage(float percent) +{ + int64_t tot = GetTotalTime(); + if (tot) + SeekTime((int64_t)(tot * percent / 100)); +} + +void CUPnPPlayer::Seek(bool bPlus, bool bLargeStep) +{ +} + +void CUPnPPlayer::DoAudioWork() +{ + NPT_String data; + NPT_CHECK_POINTER_LABEL_SEVERE(m_delegate, failed); + m_delegate->UpdatePositionInfo(); + + if(m_started) { + NPT_String uri, meta; + NPT_CHECK_LABEL(m_delegate->m_transport->GetStateVariableValue("CurrentTrackURI", uri), failed); + NPT_CHECK_LABEL(m_delegate->m_transport->GetStateVariableValue("CurrentTrackMetadata", meta), failed); + + if(m_current_uri != (const char*)uri + || m_current_meta != (const char*)meta) { + m_current_uri = (const char*)uri; + m_current_meta = (const char*)meta; + CFileItemPtr item = GetFileItem(uri, meta); + g_application.CurrentFileItem() = *item; + CApplicationMessenger::Get().SetCurrentItem(*item.get()); + } + + NPT_CHECK_LABEL(m_delegate->m_transport->GetStateVariableValue("TransportState", data), failed); + if(data == "STOPPED") + { + m_started = false; + m_callback.OnPlayBackEnded(); + } + } + return; +failed: + return; +} + +bool CUPnPPlayer::IsPlaying() const +{ + NPT_String data; + NPT_CHECK_POINTER_LABEL_SEVERE(m_delegate, failed); + NPT_CHECK_LABEL(m_delegate->m_transport->GetStateVariableValue("TransportState", data), failed); + return data != "STOPPED"; +failed: + return false; +} + +bool CUPnPPlayer::IsPaused() const +{ + NPT_String data; + NPT_CHECK_POINTER_LABEL_SEVERE(m_delegate, failed); + NPT_CHECK_LABEL(m_delegate->m_transport->GetStateVariableValue("TransportState", data), failed); + return data == "PAUSED_PLAYBACK"; +failed: + return false; +} + +void CUPnPPlayer::SetVolume(float volume) +{ + NPT_CHECK_POINTER_LABEL_SEVERE(m_delegate, failed); + NPT_CHECK_LABEL(m_control->SetVolume(m_delegate->m_device + , m_delegate->m_instance + , "Master", (int)(volume * 100) + , m_delegate), failed); + return; +failed: + CLog::Log(LOGERROR, "UPNP: CUPnPPlayer - unable to set volume"); + return; +} + +int64_t CUPnPPlayer::GetTime() +{ + NPT_CHECK_POINTER_LABEL_SEVERE(m_delegate, failed); + return m_delegate->m_posinfo.rel_time.ToMillis(); +failed: + return 0; +} + +int64_t CUPnPPlayer::GetTotalTime() +{ + NPT_CHECK_POINTER_LABEL_SEVERE(m_delegate, failed); + return m_delegate->m_posinfo.track_duration.ToMillis(); +failed: + return 0; +}; + +CStdString CUPnPPlayer::GetPlayingTitle() +{ + return ""; +}; + +} /* namespace UPNP */ diff --git a/xbmc/network/upnp/UPnPPlayer.h b/xbmc/network/upnp/UPnPPlayer.h new file mode 100644 index 0000000000..636e72bc3b --- /dev/null +++ b/xbmc/network/upnp/UPnPPlayer.h @@ -0,0 +1,81 @@ +/* +* Copyright (c) 2006 elupus (Joakim Plate) +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "cores/IPlayer.h" + +class PLT_MediaController; + +namespace UPNP +{ + +class CUPnPPlayerController; + +class CUPnPPlayer + : public IPlayer +{ +public: + CUPnPPlayer(IPlayerCallback& callback, const char* uuid); + virtual ~CUPnPPlayer(); + + virtual bool OpenFile(const CFileItem& file, const CPlayerOptions& options); + virtual bool QueueNextFile(const CFileItem &file); + virtual bool CloseFile(); + virtual bool IsPlaying() const; + virtual void Pause(); + virtual bool IsPaused() const; + virtual bool HasVideo() const { return false; } + virtual bool HasAudio() const { return false; } + virtual void Seek(bool bPlus, bool bLargeStep); + virtual void SeekPercentage(float fPercent = 0); + virtual float GetPercentage(); + virtual void SetVolume(float volume); + virtual void GetAudioInfo( CStdString& strAudioInfo) {}; + virtual void GetVideoInfo( CStdString& strVideoInfo) {}; + virtual void GetGeneralInfo( CStdString& strVideoInfo) {}; + virtual void Update(bool bPauseDrawing = false) {}; + virtual bool CanRecord() { return false;}; + virtual bool IsRecording() { return false;}; + virtual bool Record(bool bOnOff) { return false;}; + + virtual int GetChapterCount() { return 0; } + virtual int GetChapter() { return -1; } + virtual void GetChapterName(CStdString& strChapterName) { return; } + virtual int SeekChapter(int iChapter) { return -1; } + + virtual void SeekTime(__int64 iTime = 0); + virtual int64_t GetTime(); + virtual int64_t GetTotalTime(); + virtual void ToFFRW(int iSpeed = 0){}; + + virtual bool SkipNext(){return false;} + virtual bool IsCaching() const {return false;}; + virtual int GetCacheLevel() const {return -1;}; + virtual void DoAudioWork(); + + + virtual CStdString GetPlayingTitle(); + +private: + PLT_MediaController* m_control; + CUPnPPlayerController* m_delegate; + CStdString m_current_uri; + CStdString m_current_meta; + bool m_started; +}; + +} /* namespace UPNP */ diff --git a/xbmc/settings/GUISettings.cpp b/xbmc/settings/GUISettings.cpp index 23fdee7b4b..92dcb63ae0 100644 --- a/xbmc/settings/GUISettings.cpp +++ b/xbmc/settings/GUISettings.cpp @@ -827,6 +827,7 @@ void CGUISettings::Initialize() AddBool(srvUpnp, "services.upnpserver", 21360, false); AddBool(srvUpnp, "services.upnpannounce", 20188, true); AddBool(srvUpnp, "services.upnprenderer", 21881, false); + AddBool(srvUpnp, "services.upnpcontroller", 21361, false); #ifdef HAS_WEB_SERVER CSettingsCategory* srvWeb = AddCategory(SETTINGS_SERVICE, "webserver", 33101); diff --git a/xbmc/settings/GUIWindowSettingsCategory.cpp b/xbmc/settings/GUIWindowSettingsCategory.cpp index 4ac2663048..d0c0cf03c2 100644 --- a/xbmc/settings/GUIWindowSettingsCategory.cpp +++ b/xbmc/settings/GUIWindowSettingsCategory.cpp @@ -1697,6 +1697,14 @@ void CGUIWindowSettingsCategory::OnSettingChanged(BaseSettingControlPtr pSetting g_application.StopUPnPRenderer(); #endif } + else if (strSetting.Equals("services.upnpcontroller")) + { +#ifdef HAS_UPNP + g_application.StopUPnPClient(); /* always stop and restart */ + if (g_guiSettings.GetBool("services.upnpcontroller")) + g_application.StartUPnPClient(); +#endif + } else if (strSetting.Equals("services.esenabled")) { #ifdef HAS_EVENT_SERVER |