aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoakim Plate <elupus@ecce.se>2012-10-28 20:12:26 +0100
committerJoakim Plate <elupus@ecce.se>2013-01-20 18:31:21 +0100
commit859ab5f54f19814ae178a2f7b6e7718669229873 (patch)
tree6df35d5a5f5eebaa1763cffd30844f72959c2d30
parent8d361fd161c11014dd3f459a922a77ddffc8053d (diff)
upnp: add support for controlling external player
-rw-r--r--XBMC-ATV2.xcodeproj/project.pbxproj6
-rw-r--r--XBMC-IOS.xcodeproj/project.pbxproj6
-rw-r--r--XBMC.xcodeproj/project.pbxproj6
-rw-r--r--language/English/strings.po6
-rw-r--r--project/VS2010Express/XBMC.vcxproj2
-rw-r--r--project/VS2010Express/XBMC.vcxproj.filters6
-rw-r--r--xbmc/Application.cpp23
-rw-r--r--xbmc/Application.h2
-rw-r--r--xbmc/cores/playercorefactory/PlayerCoreConfig.h6
-rw-r--r--xbmc/cores/playercorefactory/PlayerCoreFactory.h3
-rw-r--r--xbmc/network/upnp/Makefile.in1
-rw-r--r--xbmc/network/upnp/UPnP.cpp84
-rw-r--r--xbmc/network/upnp/UPnP.h3
-rw-r--r--xbmc/network/upnp/UPnPInternal.cpp4
-rw-r--r--xbmc/network/upnp/UPnPPlayer.cpp503
-rw-r--r--xbmc/network/upnp/UPnPPlayer.h81
-rw-r--r--xbmc/settings/GUISettings.cpp1
-rw-r--r--xbmc/settings/GUIWindowSettingsCategory.cpp8
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