aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2014-05-20 20:56:24 -0400
committerLuke Pulverenti <luke.pulverenti@gmail.com>2014-05-20 20:56:24 -0400
commit1774e5b1ac9f809fd97c1d95666fc563afa87914 (patch)
treef0c2c3f84de84def4f9e80d1f187069e4763f496
parentad3c30c14535780fcbd11b049603991e8d3cfe9e (diff)
added upnp ConnectionManager.cs
-rw-r--r--MediaBrowser.Api/Dlna/DlnaServerService.cs48
-rw-r--r--MediaBrowser.Controller/Dlna/IConnectionManager.cs7
-rw-r--r--MediaBrowser.Controller/Dlna/IContentDirectory.cs18
-rw-r--r--MediaBrowser.Controller/Dlna/IUpnpService.cs21
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj2
-rw-r--r--MediaBrowser.Dlna/ConnectionManager/ConnectionManager.cs34
-rw-r--r--MediaBrowser.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs106
-rw-r--r--MediaBrowser.Dlna/ConnectionManager/ControlHandler.cs30
-rw-r--r--MediaBrowser.Dlna/ConnectionManager/ServiceActionListBuilder.cs205
-rw-r--r--MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs (renamed from MediaBrowser.Dlna/Server/ContentDirectory.cs)11
-rw-r--r--MediaBrowser.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs (renamed from MediaBrowser.Dlna/Server/ContentDirectoryXmlBuilder.cs)98
-rw-r--r--MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs (renamed from MediaBrowser.Dlna/Server/ControlHandler.cs)156
-rw-r--r--MediaBrowser.Dlna/ContentDirectory/ServiceActionListBuilder.cs (renamed from MediaBrowser.Dlna/Server/ServiceActionListBuilder.cs)2
-rw-r--r--MediaBrowser.Dlna/Didl/DidlBuilder.cs11
-rw-r--r--MediaBrowser.Dlna/MediaBrowser.Dlna.csproj16
-rw-r--r--MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs9
-rw-r--r--MediaBrowser.Dlna/Service/BaseControlHandler.cs112
-rw-r--r--MediaBrowser.Dlna/Service/ControlErrorHandler.cs41
-rw-r--r--MediaBrowser.Dlna/Service/ServiceXmlBuilder.cs90
-rw-r--r--MediaBrowser.Server.Implementations/Channels/ChannelManager.cs2
-rw-r--r--MediaBrowser.Server.Implementations/Session/HttpSessionController.cs32
-rw-r--r--MediaBrowser.Server.Implementations/WebSocket/AlchemyServer.cs4
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs5
23 files changed, 779 insertions, 281 deletions
diff --git a/MediaBrowser.Api/Dlna/DlnaServerService.cs b/MediaBrowser.Api/Dlna/DlnaServerService.cs
index 05d41c18b..8e4e559df 100644
--- a/MediaBrowser.Api/Dlna/DlnaServerService.cs
+++ b/MediaBrowser.Api/Dlna/DlnaServerService.cs
@@ -25,8 +25,23 @@ namespace MediaBrowser.Api.Dlna
{
}
+ [Route("/Dlna/connectionmanager/connectionmanager.xml", "GET", Summary = "Gets dlna connection manager xml")]
+ [Route("/Dlna/connectionmanager/connectionmanager", "GET", Summary = "Gets dlna connection manager xml")]
+ public class GetConnnectionManager
+ {
+ }
+
[Route("/Dlna/contentdirectory/{UuId}/control", "POST", Summary = "Processes a control request")]
- public class ProcessControlRequest : IRequiresRequestStream
+ public class ProcessContentDirectoryControlRequest : IRequiresRequestStream
+ {
+ [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string UuId { get; set; }
+
+ public Stream RequestStream { get; set; }
+ }
+
+ [Route("/Dlna/connectionmanager/{UuId}/control", "POST", Summary = "Processes a control request")]
+ public class ProcessConnectionManagerControlRequest : IRequiresRequestStream
{
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
public string UuId { get; set; }
@@ -35,6 +50,7 @@ namespace MediaBrowser.Api.Dlna
}
[Route("/Dlna/contentdirectory/{UuId}/events", Summary = "Processes an event subscription request")]
+ [Route("/Dlna/connectionmanager/{UuId}/events", Summary = "Processes an event subscription request")]
public class ProcessEventRequest
{
[ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")]
@@ -53,12 +69,14 @@ namespace MediaBrowser.Api.Dlna
private readonly IDlnaManager _dlnaManager;
private readonly IContentDirectory _contentDirectory;
private readonly IEventManager _eventManager;
+ private readonly IConnectionManager _connectionManager;
- public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IEventManager eventManager)
+ public DlnaServerService(IDlnaManager dlnaManager, IContentDirectory contentDirectory, IEventManager eventManager, IConnectionManager connectionManager)
{
_dlnaManager = dlnaManager;
_contentDirectory = contentDirectory;
_eventManager = eventManager;
+ _connectionManager = connectionManager;
}
public object Get(GetDescriptionXml request)
@@ -70,26 +88,40 @@ namespace MediaBrowser.Api.Dlna
public object Get(GetContentDirectory request)
{
- var xml = _contentDirectory.GetContentDirectoryXml(GetRequestHeaders());
+ var xml = _contentDirectory.GetServiceXml(GetRequestHeaders());
return ResultFactory.GetResult(xml, "text/xml");
}
- public object Post(ProcessControlRequest request)
+ public object Get(GetConnnectionManager request)
+ {
+ var xml = _connectionManager.GetServiceXml(GetRequestHeaders());
+
+ return ResultFactory.GetResult(xml, "text/xml");
+ }
+
+ public object Post(ProcessContentDirectoryControlRequest request)
+ {
+ var response = PostAsync(request.RequestStream, _contentDirectory).Result;
+
+ return ResultFactory.GetResult(response.Xml, "text/xml");
+ }
+
+ public object Post(ProcessConnectionManagerControlRequest request)
{
- var response = PostAsync(request).Result;
+ var response = PostAsync(request.RequestStream, _connectionManager).Result;
return ResultFactory.GetResult(response.Xml, "text/xml");
}
- private async Task<ControlResponse> PostAsync(ProcessControlRequest request)
+ private async Task<ControlResponse> PostAsync(Stream requestStream, IUpnpService service)
{
var pathInfo = PathInfo.Parse(Request.PathInfo);
var id = pathInfo.GetArgumentValue<string>(2);
- using (var reader = new StreamReader(request.RequestStream))
+ using (var reader = new StreamReader(requestStream))
{
- return _contentDirectory.ProcessControlRequest(new ControlRequest
+ return service.ProcessControlRequest(new ControlRequest
{
Headers = GetRequestHeaders(),
InputXml = await reader.ReadToEndAsync().ConfigureAwait(false),
diff --git a/MediaBrowser.Controller/Dlna/IConnectionManager.cs b/MediaBrowser.Controller/Dlna/IConnectionManager.cs
new file mode 100644
index 000000000..942e523e8
--- /dev/null
+++ b/MediaBrowser.Controller/Dlna/IConnectionManager.cs
@@ -0,0 +1,7 @@
+
+namespace MediaBrowser.Controller.Dlna
+{
+ public interface IConnectionManager : IUpnpService
+ {
+ }
+}
diff --git a/MediaBrowser.Controller/Dlna/IContentDirectory.cs b/MediaBrowser.Controller/Dlna/IContentDirectory.cs
index e48d498df..00c236813 100644
--- a/MediaBrowser.Controller/Dlna/IContentDirectory.cs
+++ b/MediaBrowser.Controller/Dlna/IContentDirectory.cs
@@ -1,21 +1,7 @@
-using System.Collections.Generic;
-
+
namespace MediaBrowser.Controller.Dlna
{
- public interface IContentDirectory
+ public interface IContentDirectory : IUpnpService
{
- /// <summary>
- /// Gets the content directory XML.
- /// </summary>
- /// <param name="headers">The headers.</param>
- /// <returns>System.String.</returns>
- string GetContentDirectoryXml(IDictionary<string, string> headers);
-
- /// <summary>
- /// Processes the control request.
- /// </summary>
- /// <param name="request">The request.</param>
- /// <returns>ControlResponse.</returns>
- ControlResponse ProcessControlRequest(ControlRequest request);
}
}
diff --git a/MediaBrowser.Controller/Dlna/IUpnpService.cs b/MediaBrowser.Controller/Dlna/IUpnpService.cs
new file mode 100644
index 000000000..3511740ad
--- /dev/null
+++ b/MediaBrowser.Controller/Dlna/IUpnpService.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Dlna
+{
+ public interface IUpnpService
+ {
+ /// <summary>
+ /// Gets the content directory XML.
+ /// </summary>
+ /// <param name="headers">The headers.</param>
+ /// <returns>System.String.</returns>
+ string GetServiceXml(IDictionary<string, string> headers);
+
+ /// <summary>
+ /// Processes the control request.
+ /// </summary>
+ /// <param name="request">The request.</param>
+ /// <returns>ControlResponse.</returns>
+ ControlResponse ProcessControlRequest(ControlRequest request);
+ }
+}
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index bab550e45..fa7842a68 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -92,9 +92,11 @@
<Compile Include="Dlna\ControlResponse.cs" />
<Compile Include="Dlna\DlnaIconResponse.cs" />
<Compile Include="Dlna\EventSubscriptionResponse.cs" />
+ <Compile Include="Dlna\IConnectionManager.cs" />
<Compile Include="Dlna\IContentDirectory.cs" />
<Compile Include="Dlna\IDlnaManager.cs" />
<Compile Include="Dlna\IEventManager.cs" />
+ <Compile Include="Dlna\IUpnpService.cs" />
<Compile Include="Drawing\IImageProcessor.cs" />
<Compile Include="Drawing\ImageFormat.cs" />
<Compile Include="Drawing\ImageProcessingOptions.cs" />
diff --git a/MediaBrowser.Dlna/ConnectionManager/ConnectionManager.cs b/MediaBrowser.Dlna/ConnectionManager/ConnectionManager.cs
new file mode 100644
index 000000000..3270fca72
--- /dev/null
+++ b/MediaBrowser.Dlna/ConnectionManager/ConnectionManager.cs
@@ -0,0 +1,34 @@
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
+using MediaBrowser.Model.Logging;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Dlna.ConnectionManager
+{
+ public class ConnectionManager : IConnectionManager
+ {
+ private readonly IDlnaManager _dlna;
+ private readonly ILogger _logger;
+ private readonly IServerConfigurationManager _config;
+
+ public ConnectionManager(IDlnaManager dlna, ILogManager logManager, IServerConfigurationManager config)
+ {
+ _dlna = dlna;
+ _config = config;
+ _logger = logManager.GetLogger("UpnpConnectionManager");
+ }
+
+ public string GetServiceXml(IDictionary<string, string> headers)
+ {
+ return new ConnectionManagerXmlBuilder().GetXml();
+ }
+
+ public ControlResponse ProcessControlRequest(ControlRequest request)
+ {
+ var profile = _dlna.GetProfile(request.Headers) ??
+ _dlna.GetDefaultProfile();
+
+ return new ControlHandler(_logger, profile, _config).ProcessControlRequest(request);
+ }
+ }
+}
diff --git a/MediaBrowser.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs b/MediaBrowser.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs
new file mode 100644
index 000000000..4efa11159
--- /dev/null
+++ b/MediaBrowser.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs
@@ -0,0 +1,106 @@
+using MediaBrowser.Dlna.Common;
+using MediaBrowser.Dlna.Service;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Dlna.ConnectionManager
+{
+ public class ConnectionManagerXmlBuilder
+ {
+ public string GetXml()
+ {
+ return new ServiceXmlBuilder().GetXml(new ServiceActionListBuilder().GetActions(), GetStateVariables());
+ }
+
+ private IEnumerable<StateVariable> GetStateVariables()
+ {
+ var list = new List<StateVariable>();
+
+ list.Add(new StateVariable
+ {
+ Name = "SourceProtocolInfo",
+ DataType = "string",
+ SendsEvents = true
+ });
+
+ list.Add(new StateVariable
+ {
+ Name = "SinkProtocolInfo",
+ DataType = "string",
+ SendsEvents = true
+ });
+
+ list.Add(new StateVariable
+ {
+ Name = "CurrentConnectionIDs",
+ DataType = "string",
+ SendsEvents = true
+ });
+
+ list.Add(new StateVariable
+ {
+ Name = "A_ARG_TYPE_ConnectionStatus",
+ DataType = "string",
+ SendsEvents = false,
+
+ AllowedValues = new List<string>
+ {
+ "OK",
+ "ContentFormatMismatch",
+ "InsufficientBandwidth",
+ "UnreliableChannel",
+ "Unknown"
+ }
+ });
+
+ list.Add(new StateVariable
+ {
+ Name = "A_ARG_TYPE_ConnectionManager",
+ DataType = "string",
+ SendsEvents = false
+ });
+
+ list.Add(new StateVariable
+ {
+ Name = "A_ARG_TYPE_Direction",
+ DataType = "string",
+ SendsEvents = false,
+
+ AllowedValues = new List<string>
+ {
+ "Output",
+ "Input"
+ }
+ });
+
+ list.Add(new StateVariable
+ {
+ Name = "A_ARG_TYPE_ProtocolInfo",
+ DataType = "string",
+ SendsEvents = false
+ });
+
+ list.Add(new StateVariable
+ {
+ Name = "A_ARG_TYPE_ConnectionID",
+ DataType = "ui4",
+ SendsEvents = false
+ });
+
+ list.Add(new StateVariable
+ {
+ Name = "A_ARG_TYPE_AVTransportID",
+ DataType = "ui4",
+ SendsEvents = false
+ });
+
+ list.Add(new StateVariable
+ {
+ Name = "A_ARG_TYPE_RcsID",
+ DataType = "ui4",
+ SendsEvents = false
+ });
+
+ return list;
+ }
+ }
+}
diff --git a/MediaBrowser.Dlna/ConnectionManager/ControlHandler.cs b/MediaBrowser.Dlna/ConnectionManager/ControlHandler.cs
new file mode 100644
index 000000000..842e9380a
--- /dev/null
+++ b/MediaBrowser.Dlna/ConnectionManager/ControlHandler.cs
@@ -0,0 +1,30 @@
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Dlna.Server;
+using MediaBrowser.Dlna.Service;
+using MediaBrowser.Model.Dlna;
+using MediaBrowser.Model.Logging;
+using System.Collections.Generic;
+using System.Globalization;
+
+namespace MediaBrowser.Dlna.ConnectionManager
+{
+ public class ControlHandler : BaseControlHandler
+ {
+ private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+ private readonly DeviceProfile _profile;
+
+ public ControlHandler(ILogger logger, DeviceProfile profile, IServerConfigurationManager config)
+ : base(config, logger)
+ {
+ _profile = profile;
+ }
+
+ protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams)
+ {
+ var deviceId = "test";
+
+ throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
+ }
+ }
+}
diff --git a/MediaBrowser.Dlna/ConnectionManager/ServiceActionListBuilder.cs b/MediaBrowser.Dlna/ConnectionManager/ServiceActionListBuilder.cs
new file mode 100644
index 000000000..9dbd4e0e2
--- /dev/null
+++ b/MediaBrowser.Dlna/ConnectionManager/ServiceActionListBuilder.cs
@@ -0,0 +1,205 @@
+using MediaBrowser.Dlna.Common;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Dlna.ConnectionManager
+{
+ public class ServiceActionListBuilder
+ {
+ public IEnumerable<ServiceAction> GetActions()
+ {
+ var list = new List<ServiceAction>
+ {
+ GetCurrentConnectionInfo(),
+ GetProtocolInfo(),
+ GetCurrentConnectionIDs(),
+ ConnectionComplete(),
+ PrepareForConnection()
+ };
+
+ return list;
+ }
+
+ private ServiceAction PrepareForConnection()
+ {
+ var action = new ServiceAction
+ {
+ Name = "PrepareForConnection"
+ };
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "RemoteProtocolInfo",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_ProtocolInfo"
+ });
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "PeerConnectionManager",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_ConnectionManager"
+ });
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "PeerConnectionID",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_ConnectionID"
+ });
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "Direction",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_Direction"
+ });
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "ConnectionID",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_ConnectionID"
+ });
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "AVTransportID",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_AVTransportID"
+ });
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "RcsID",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_RcsID"
+ });
+
+ return action;
+ }
+
+ private ServiceAction GetCurrentConnectionInfo()
+ {
+ var action = new ServiceAction
+ {
+ Name = "GetCurrentConnectionInfo"
+ };
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "ConnectionID",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_ConnectionID"
+ });
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "RcsID",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_RcsID"
+ });
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "AVTransportID",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_AVTransportID"
+ });
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "ProtocolInfo",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_ProtocolInfo"
+ });
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "PeerConnectionManager",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_ConnectionManager"
+ });
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "PeerConnectionID",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_ConnectionID"
+ });
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "Direction",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_Direction"
+ });
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "Status",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_ConnectionStatus"
+ });
+
+ return action;
+ }
+
+ private ServiceAction GetProtocolInfo()
+ {
+ var action = new ServiceAction
+ {
+ Name = "GetProtocolInfo"
+ };
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "Source",
+ Direction = "out",
+ RelatedStateVariable = "SourceProtocolInfo"
+ });
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "Sink",
+ Direction = "out",
+ RelatedStateVariable = "SinkProtocolInfo"
+ });
+
+ return action;
+ }
+
+ private ServiceAction GetCurrentConnectionIDs()
+ {
+ var action = new ServiceAction
+ {
+ Name = "GetCurrentConnectionIDs"
+ };
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "ConnectionIDs",
+ Direction = "out",
+ RelatedStateVariable = "CurrentConnectionIDs"
+ });
+
+ return action;
+ }
+
+ private ServiceAction ConnectionComplete()
+ {
+ var action = new ServiceAction
+ {
+ Name = "ConnectionComplete"
+ };
+
+ action.ArgumentList.Add(new Argument
+ {
+ Name = "ConnectionID",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_ConnectionID"
+ });
+
+ return action;
+ }
+ }
+}
diff --git a/MediaBrowser.Dlna/Server/ContentDirectory.cs b/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs
index e2f53aeaf..d1b29502d 100644
--- a/MediaBrowser.Dlna/Server/ContentDirectory.cs
+++ b/MediaBrowser.Dlna/ContentDirectory/ContentDirectory.cs
@@ -10,7 +10,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
-namespace MediaBrowser.Dlna.Server
+namespace MediaBrowser.Dlna.ContentDirectory
{
public class ContentDirectory : IContentDirectory, IDisposable
{
@@ -43,7 +43,7 @@ namespace MediaBrowser.Dlna.Server
_config = config;
_userManager = userManager;
_eventManager = eventManager;
- _logger = logManager.GetLogger("DlnaContentDirectory");
+ _logger = logManager.GetLogger("UpnpContentDirectory");
}
private int SystemUpdateId
@@ -56,12 +56,9 @@ namespace MediaBrowser.Dlna.Server
}
}
- public string GetContentDirectoryXml(IDictionary<string, string> headers)
+ public string GetServiceXml(IDictionary<string, string> headers)
{
- var profile = _dlna.GetProfile(headers) ??
- _dlna.GetDefaultProfile();
-
- return new ContentDirectoryXmlBuilder(profile).GetXml();
+ return new ContentDirectoryXmlBuilder().GetXml();
}
public ControlResponse ProcessControlRequest(ControlRequest request)
diff --git a/MediaBrowser.Dlna/Server/ContentDirectoryXmlBuilder.cs b/MediaBrowser.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs
index 58ccf49bd..0e5a2671c 100644
--- a/MediaBrowser.Dlna/Server/ContentDirectoryXmlBuilder.cs
+++ b/MediaBrowser.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs
@@ -1,98 +1,15 @@
using MediaBrowser.Dlna.Common;
-using MediaBrowser.Model.Dlna;
+using MediaBrowser.Dlna.Service;
using System.Collections.Generic;
-using System.Security;
-using System.Text;
-namespace MediaBrowser.Dlna.Server
+namespace MediaBrowser.Dlna.ContentDirectory
{
public class ContentDirectoryXmlBuilder
{
- private readonly DeviceProfile _profile;
-
- public ContentDirectoryXmlBuilder(DeviceProfile profile)
- {
- _profile = profile;
- }
-
public string GetXml()
{
- var builder = new StringBuilder();
-
- builder.Append("<?xml version=\"1.0\"?>");
- builder.Append("<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">");
-
- builder.Append("<specVersion>");
- builder.Append("<major>1</major>");
- builder.Append("<minor>0</minor>");
- builder.Append("</specVersion>");
-
- AppendActionList(builder);
- AppendServiceStateTable(builder);
-
- builder.Append("</scpd>");
-
- return builder.ToString();
- }
-
- private void AppendActionList(StringBuilder builder)
- {
- builder.Append("<actionList>");
-
- foreach (var item in new ServiceActionListBuilder().GetActions())
- {
- builder.Append("<action>");
-
- builder.Append("<name>" + SecurityElement.Escape(item.Name ?? string.Empty) + "</name>");
-
- builder.Append("<argumentList>");
-
- foreach (var argument in item.ArgumentList)
- {
- builder.Append("<argument>");
-
- builder.Append("<name>" + SecurityElement.Escape(argument.Name ?? string.Empty) + "</name>");
- builder.Append("<direction>" + SecurityElement.Escape(argument.Direction ?? string.Empty) + "</direction>");
- builder.Append("<relatedStateVariable>" + SecurityElement.Escape(argument.RelatedStateVariable ?? string.Empty) + "</relatedStateVariable>");
-
- builder.Append("</argument>");
- }
-
- builder.Append("</argumentList>");
-
- builder.Append("</action>");
- }
-
- builder.Append("</actionList>");
- }
-
- private void AppendServiceStateTable(StringBuilder builder)
- {
- builder.Append("<serviceStateTable>");
-
- foreach (var item in GetStateVariables())
- {
- var sendEvents = item.SendsEvents ? "yes" : "no";
-
- builder.Append("<stateVariable sendEvents=\"" + sendEvents + "\">");
-
- builder.Append("<name>" + SecurityElement.Escape(item.Name ?? string.Empty) + "</name>");
- builder.Append("<dataType>" + SecurityElement.Escape(item.DataType ?? string.Empty) + "</dataType>");
-
- if (item.AllowedValues.Count > 0)
- {
- builder.Append("<allowedValueList>");
- foreach (var allowedValue in item.AllowedValues)
- {
- builder.Append("<allowedValue>" + SecurityElement.Escape(allowedValue) + "</allowedValue>");
- }
- builder.Append("</allowedValueList>");
- }
-
- builder.Append("</stateVariable>");
- }
-
- builder.Append("</serviceStateTable>");
+ return new ServiceXmlBuilder().GetXml(new ServiceActionListBuilder().GetActions(),
+ GetStateVariables());
}
private IEnumerable<StateVariable> GetStateVariables()
@@ -223,13 +140,8 @@ namespace MediaBrowser.Dlna.Server
DataType = "string",
SendsEvents = false
});
-
- return list;
- }
- public override string ToString()
- {
- return GetXml();
+ return list;
}
}
}
diff --git a/MediaBrowser.Dlna/Server/ControlHandler.cs b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
index a3eb7f055..0e4f0d8f9 100644
--- a/MediaBrowser.Dlna/Server/ControlHandler.cs
+++ b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs
@@ -1,15 +1,16 @@
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Drawing;
+using MediaBrowser.Controller.Dto;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Dlna.Didl;
+using MediaBrowser.Dlna.Server;
+using MediaBrowser.Dlna.Service;
using MediaBrowser.Model.Dlna;
-using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Querying;
@@ -21,20 +22,17 @@ using System.Text;
using System.Threading;
using System.Xml;
-namespace MediaBrowser.Dlna.Server
+namespace MediaBrowser.Dlna.ContentDirectory
{
- public class ControlHandler
+ public class ControlHandler : BaseControlHandler
{
- private readonly ILogger _logger;
private readonly ILibraryManager _libraryManager;
private readonly IUserDataManager _userDataManager;
- private readonly IServerConfigurationManager _config;
private readonly User _user;
private const string NS_DC = "http://purl.org/dc/elements/1.1/";
private const string NS_DIDL = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
private const string NS_DLNA = "urn:schemas-dlna-org:metadata-1-0/";
- private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/";
private const string NS_UPNP = "urn:schemas-upnp-org:metadata-1-0/upnp/";
private readonly int _systemUpdateId;
@@ -45,151 +43,45 @@ namespace MediaBrowser.Dlna.Server
private readonly DeviceProfile _profile;
public ControlHandler(ILogger logger, ILibraryManager libraryManager, DeviceProfile profile, string serverAddress, IDtoService dtoService, IImageProcessor imageProcessor, IUserDataManager userDataManager, User user, int systemUpdateId, IServerConfigurationManager config)
+ : base(config, logger)
{
- _logger = logger;
_libraryManager = libraryManager;
_userDataManager = userDataManager;
_user = user;
_systemUpdateId = systemUpdateId;
- _config = config;
_profile = profile;
_didlBuilder = new DidlBuilder(profile, imageProcessor, serverAddress, dtoService);
}
- public ControlResponse ProcessControlRequest(ControlRequest request)
- {
- try
- {
- if (_config.Configuration.DlnaOptions.EnableDebugLogging)
- {
- LogRequest(request);
- }
-
- return ProcessControlRequestInternal(request);
- }
- catch (Exception ex)
- {
- _logger.ErrorException("Error processing control request", ex);
-
- return GetErrorResponse(ex);
- }
- }
-
- private void LogRequest(ControlRequest request)
- {
- var builder = new StringBuilder();
-
- var headers = string.Join(", ", request.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
- builder.AppendFormat("Headers: {0}", headers);
- builder.AppendLine();
- builder.Append(request.InputXml);
-
- _logger.LogMultiline("Control request", LogSeverity.Debug, builder);
- }
-
- private ControlResponse ProcessControlRequestInternal(ControlRequest request)
+ protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams)
{
- var soap = new XmlDocument();
- soap.LoadXml(request.InputXml);
- var sparams = new Headers();
- var body = soap.GetElementsByTagName("Body", NS_SOAPENV).Item(0);
-
- var method = body.FirstChild;
-
- foreach (var p in method.ChildNodes)
- {
- var e = p as XmlElement;
- if (e == null)
- {
- continue;
- }
- sparams.Add(e.LocalName, e.InnerText.Trim());
- }
-
var deviceId = "test";
- IEnumerable<KeyValuePair<string, string>> result;
-
- _logger.Debug("Received control request {0}", method.Name);
-
var user = _user;
- if (string.Equals(method.LocalName, "GetSearchCapabilities", StringComparison.OrdinalIgnoreCase))
- result = HandleGetSearchCapabilities();
- else if (string.Equals(method.LocalName, "GetSortCapabilities", StringComparison.OrdinalIgnoreCase))
- result = HandleGetSortCapabilities();
- else if (string.Equals(method.LocalName, "GetSystemUpdateID", StringComparison.OrdinalIgnoreCase))
- result = HandleGetSystemUpdateID();
- else if (string.Equals(method.LocalName, "Browse", StringComparison.OrdinalIgnoreCase))
- result = HandleBrowse(sparams, user, deviceId);
- else if (string.Equals(method.LocalName, "X_GetFeatureList", StringComparison.OrdinalIgnoreCase))
- result = HandleXGetFeatureList();
- else if (string.Equals(method.LocalName, "X_SetBookmark", StringComparison.OrdinalIgnoreCase))
- result = HandleXSetBookmark(sparams, user);
- else if (string.Equals(method.LocalName, "Search", StringComparison.OrdinalIgnoreCase))
- result = HandleSearch(sparams, user, deviceId);
- else
- throw new ResourceNotFoundException("Unexpected control request name: " + method.LocalName);
+ if (string.Equals(methodName, "GetSearchCapabilities", StringComparison.OrdinalIgnoreCase))
+ return HandleGetSearchCapabilities();
- var env = new XmlDocument();
- env.AppendChild(env.CreateXmlDeclaration("1.0", "utf-8", string.Empty));
- var envelope = env.CreateElement("SOAP-ENV", "Envelope", NS_SOAPENV);
- env.AppendChild(envelope);
- envelope.SetAttribute("encodingStyle", NS_SOAPENV, "http://schemas.xmlsoap.org/soap/encoding/");
+ if (string.Equals(methodName, "GetSortCapabilities", StringComparison.OrdinalIgnoreCase))
+ return HandleGetSortCapabilities();
- var rbody = env.CreateElement("SOAP-ENV:Body", NS_SOAPENV);
- env.DocumentElement.AppendChild(rbody);
+ if (string.Equals(methodName, "GetSystemUpdateID", StringComparison.OrdinalIgnoreCase))
+ return HandleGetSystemUpdateID();
- var response = env.CreateElement(String.Format("u:{0}Response", method.LocalName), method.NamespaceURI);
- rbody.AppendChild(response);
+ if (string.Equals(methodName, "Browse", StringComparison.OrdinalIgnoreCase))
+ return HandleBrowse(methodParams, user, deviceId);
- foreach (var i in result)
- {
- var ri = env.CreateElement(i.Key);
- ri.InnerText = i.Value;
- response.AppendChild(ri);
- }
-
- var controlResponse = new ControlResponse
- {
- Xml = env.OuterXml,
- IsSuccessful = true
- };
+ if (string.Equals(methodName, "X_GetFeatureList", StringComparison.OrdinalIgnoreCase))
+ return HandleXGetFeatureList();
- controlResponse.Headers.Add("EXT", string.Empty);
+ if (string.Equals(methodName, "X_SetBookmark", StringComparison.OrdinalIgnoreCase))
+ return HandleXSetBookmark(methodParams, user);
- return controlResponse;
- }
+ if (string.Equals(methodName, "Search", StringComparison.OrdinalIgnoreCase))
+ return HandleSearch(methodParams, user, deviceId);
- private ControlResponse GetErrorResponse(Exception ex)
- {
- var env = new XmlDocument();
- env.AppendChild(env.CreateXmlDeclaration("1.0", "utf-8", "yes"));
- var envelope = env.CreateElement("SOAP-ENV", "Envelope", NS_SOAPENV);
- env.AppendChild(envelope);
- envelope.SetAttribute("encodingStyle", NS_SOAPENV, "http://schemas.xmlsoap.org/soap/encoding/");
-
- var rbody = env.CreateElement("SOAP-ENV:Body", NS_SOAPENV);
- env.DocumentElement.AppendChild(rbody);
-
- var fault = env.CreateElement("SOAP-ENV", "Fault", NS_SOAPENV);
- var faultCode = env.CreateElement("faultcode");
- faultCode.InnerText = "500";
- fault.AppendChild(faultCode);
- var faultString = env.CreateElement("faultstring");
- faultString.InnerText = ex.ToString();
- fault.AppendChild(faultString);
- var detail = env.CreateDocumentFragment();
- detail.InnerXml = "<detail><UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\"><errorCode>401</errorCode><errorDescription>Invalid Action</errorDescription></UPnPError></detail>";
- fault.AppendChild(detail);
- rbody.AppendChild(fault);
-
- return new ControlResponse
- {
- Xml = env.OuterXml,
- IsSuccessful = false
- };
+ throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
}
private IEnumerable<KeyValuePair<string, string>> HandleXSetBookmark(IDictionary<string, string> sparams, User user)
@@ -224,7 +116,7 @@ namespace MediaBrowser.Dlna.Server
{
var headers = new Headers(true);
headers.Add("Id", _systemUpdateId.ToString(_usCulture));
- return headers;
+ return headers;
}
private IEnumerable<KeyValuePair<string, string>> HandleXGetFeatureList()
diff --git a/MediaBrowser.Dlna/Server/ServiceActionListBuilder.cs b/MediaBrowser.Dlna/ContentDirectory/ServiceActionListBuilder.cs
index 9ccfaf603..cd8119048 100644
--- a/MediaBrowser.Dlna/Server/ServiceActionListBuilder.cs
+++ b/MediaBrowser.Dlna/ContentDirectory/ServiceActionListBuilder.cs
@@ -1,7 +1,7 @@
using MediaBrowser.Dlna.Common;
using System.Collections.Generic;
-namespace MediaBrowser.Dlna.Server
+namespace MediaBrowser.Dlna.ContentDirectory
{
public class ServiceActionListBuilder
{
diff --git a/MediaBrowser.Dlna/Didl/DidlBuilder.cs b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
index 1cd4a4cbd..c60b3a49a 100644
--- a/MediaBrowser.Dlna/Didl/DidlBuilder.cs
+++ b/MediaBrowser.Dlna/Didl/DidlBuilder.cs
@@ -345,7 +345,9 @@ namespace MediaBrowser.Dlna.Didl
/// <param name="filter">The filter.</param>
private void AddCommonFields(BaseItem item, XmlElement element, Filter filter)
{
- if (filter.Contains("dc:title"))
+ // Don't filter on dc:title because not all devices will include it in the filter
+ // MediaMonkey for example won't display content without a title
+ //if (filter.Contains("dc:title"))
{
AddValue(element, "dc", "title", item.Name, NS_DC);
}
@@ -360,9 +362,12 @@ namespace MediaBrowser.Dlna.Didl
}
}
- foreach (var genre in item.Genres)
+ if (filter.Contains("upnp:genre"))
{
- AddValue(element, "upnp", "genre", genre, NS_UPNP);
+ foreach (var genre in item.Genres)
+ {
+ AddValue(element, "upnp", "genre", genre, NS_UPNP);
+ }
}
foreach (var studio in item.Studios)
diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
index d39bcbefe..caef50d36 100644
--- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
+++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
@@ -51,6 +51,10 @@
<Compile Include="..\SharedVersion.cs">
<Link>Properties\SharedVersion.cs</Link>
</Compile>
+ <Compile Include="ConnectionManager\ConnectionManager.cs" />
+ <Compile Include="ConnectionManager\ConnectionManagerXmlBuilder.cs" />
+ <Compile Include="ConnectionManager\ControlHandler.cs" />
+ <Compile Include="ConnectionManager\ServiceActionListBuilder.cs" />
<Compile Include="DlnaManager.cs" />
<Compile Include="Common\Argument.cs" />
<Compile Include="Eventing\EventManager.cs" />
@@ -79,10 +83,13 @@
<Compile Include="Profiles\Windows81Profile.cs" />
<Compile Include="Profiles\WindowsMediaCenterProfile.cs" />
<Compile Include="Profiles\WindowsPhoneProfile.cs" />
- <Compile Include="Server\ContentDirectory.cs" />
- <Compile Include="Server\ControlHandler.cs" />
- <Compile Include="Server\ServiceActionListBuilder.cs" />
- <Compile Include="Server\ContentDirectoryXmlBuilder.cs" />
+ <Compile Include="ContentDirectory\ContentDirectory.cs" />
+ <Compile Include="ContentDirectory\ControlHandler.cs" />
+ <Compile Include="ContentDirectory\ServiceActionListBuilder.cs" />
+ <Compile Include="ContentDirectory\ContentDirectoryXmlBuilder.cs" />
+ <Compile Include="Service\BaseControlHandler.cs" />
+ <Compile Include="Service\ControlErrorHandler.cs" />
+ <Compile Include="Service\ServiceXmlBuilder.cs" />
<Compile Include="Ssdp\Datagram.cs" />
<Compile Include="Server\DescriptionXmlBuilder.cs" />
<Compile Include="Ssdp\SsdpHelper.cs" />
@@ -159,6 +166,7 @@
<EmbeddedResource Include="Images\logo48.jpg" />
<EmbeddedResource Include="Images\logo48.png" />
</ItemGroup>
+ <ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
diff --git a/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs b/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs
index 446f975f3..885c66474 100644
--- a/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs
+++ b/MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs
@@ -185,6 +185,15 @@ namespace MediaBrowser.Dlna.Server
EventSubUrl = "/mediabrowser/dlna/contentdirectory/" + _serverUdn + "/events"
});
+ list.Add(new DeviceService
+ {
+ ServiceType = "urn:schemas-upnp-org:service:ConnectionManager:1",
+ ServiceId = "urn:upnp-org:serviceId:ConnectionManager",
+ ScpdUrl = "/mediabrowser/dlna/connectionmanager/connectionmanager.xml",
+ ControlUrl = "/mediabrowser/dlna/connectionmanager/" + _serverUdn + "/control",
+ EventSubUrl = "/mediabrowser/dlna/connectionmanager/" + _serverUdn + "/events"
+ });
+
return list;
}
diff --git a/MediaBrowser.Dlna/Service/BaseControlHandler.cs b/MediaBrowser.Dlna/Service/BaseControlHandler.cs
new file mode 100644
index 000000000..2185d51a5
--- /dev/null
+++ b/MediaBrowser.Dlna/Service/BaseControlHandler.cs
@@ -0,0 +1,112 @@
+using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
+using MediaBrowser.Dlna.Server;
+using MediaBrowser.Model.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Xml;
+
+namespace MediaBrowser.Dlna.Service
+{
+ public abstract class BaseControlHandler
+ {
+ private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/";
+
+ protected readonly IServerConfigurationManager Config;
+ protected readonly ILogger Logger;
+
+ protected BaseControlHandler(IServerConfigurationManager config, ILogger logger)
+ {
+ Config = config;
+ Logger = logger;
+ }
+
+ public ControlResponse ProcessControlRequest(ControlRequest request)
+ {
+ try
+ {
+ if (Config.Configuration.DlnaOptions.EnableDebugLogging)
+ {
+ LogRequest(request);
+ }
+
+ return ProcessControlRequestInternal(request);
+ }
+ catch (Exception ex)
+ {
+ Logger.ErrorException("Error processing control request", ex);
+
+ return new ControlErrorHandler().GetResponse(ex);
+ }
+ }
+
+ private ControlResponse ProcessControlRequestInternal(ControlRequest request)
+ {
+ var soap = new XmlDocument();
+ soap.LoadXml(request.InputXml);
+ var sparams = new Headers();
+ var body = soap.GetElementsByTagName("Body", NS_SOAPENV).Item(0);
+
+ var method = body.FirstChild;
+
+ foreach (var p in method.ChildNodes)
+ {
+ var e = p as XmlElement;
+ if (e == null)
+ {
+ continue;
+ }
+ sparams.Add(e.LocalName, e.InnerText.Trim());
+ }
+
+ Logger.Debug("Received control request {0}", method.LocalName);
+
+ IEnumerable<KeyValuePair<string, string>> result = GetResult(method.LocalName, sparams);
+
+ var env = new XmlDocument();
+ env.AppendChild(env.CreateXmlDeclaration("1.0", "utf-8", string.Empty));
+ var envelope = env.CreateElement("SOAP-ENV", "Envelope", NS_SOAPENV);
+ env.AppendChild(envelope);
+ envelope.SetAttribute("encodingStyle", NS_SOAPENV, "http://schemas.xmlsoap.org/soap/encoding/");
+
+ var rbody = env.CreateElement("SOAP-ENV:Body", NS_SOAPENV);
+ env.DocumentElement.AppendChild(rbody);
+
+ var response = env.CreateElement(String.Format("u:{0}Response", method.LocalName), method.NamespaceURI);
+ rbody.AppendChild(response);
+
+ foreach (var i in result)
+ {
+ var ri = env.CreateElement(i.Key);
+ ri.InnerText = i.Value;
+ response.AppendChild(ri);
+ }
+
+ var controlResponse = new ControlResponse
+ {
+ Xml = env.OuterXml,
+ IsSuccessful = true
+ };
+
+ controlResponse.Headers.Add("EXT", string.Empty);
+
+ return controlResponse;
+ }
+
+ protected abstract IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, Headers methodParams);
+
+ private void LogRequest(ControlRequest request)
+ {
+ var builder = new StringBuilder();
+
+ var headers = string.Join(", ", request.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value)).ToArray());
+ builder.AppendFormat("Headers: {0}", headers);
+ builder.AppendLine();
+ builder.Append(request.InputXml);
+
+ Logger.LogMultiline("Control request", LogSeverity.Debug, builder);
+ }
+ }
+}
diff --git a/MediaBrowser.Dlna/Service/ControlErrorHandler.cs b/MediaBrowser.Dlna/Service/ControlErrorHandler.cs
new file mode 100644
index 000000000..42b1fcbc9
--- /dev/null
+++ b/MediaBrowser.Dlna/Service/ControlErrorHandler.cs
@@ -0,0 +1,41 @@
+using MediaBrowser.Controller.Dlna;
+using System;
+using System.Xml;
+
+namespace MediaBrowser.Dlna.Service
+{
+ public class ControlErrorHandler
+ {
+ private const string NS_SOAPENV = "http://schemas.xmlsoap.org/soap/envelope/";
+
+ public ControlResponse GetResponse(Exception ex)
+ {
+ var env = new XmlDocument();
+ env.AppendChild(env.CreateXmlDeclaration("1.0", "utf-8", "yes"));
+ var envelope = env.CreateElement("SOAP-ENV", "Envelope", NS_SOAPENV);
+ env.AppendChild(envelope);
+ envelope.SetAttribute("encodingStyle", NS_SOAPENV, "http://schemas.xmlsoap.org/soap/encoding/");
+
+ var rbody = env.CreateElement("SOAP-ENV:Body", NS_SOAPENV);
+ env.DocumentElement.AppendChild(rbody);
+
+ var fault = env.CreateElement("SOAP-ENV", "Fault", NS_SOAPENV);
+ var faultCode = env.CreateElement("faultcode");
+ faultCode.InnerText = "500";
+ fault.AppendChild(faultCode);
+ var faultString = env.CreateElement("faultstring");
+ faultString.InnerText = ex.ToString();
+ fault.AppendChild(faultString);
+ var detail = env.CreateDocumentFragment();
+ detail.InnerXml = "<detail><UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\"><errorCode>401</errorCode><errorDescription>Invalid Action</errorDescription></UPnPError></detail>";
+ fault.AppendChild(detail);
+ rbody.AppendChild(fault);
+
+ return new ControlResponse
+ {
+ Xml = env.OuterXml,
+ IsSuccessful = false
+ };
+ }
+ }
+}
diff --git a/MediaBrowser.Dlna/Service/ServiceXmlBuilder.cs b/MediaBrowser.Dlna/Service/ServiceXmlBuilder.cs
new file mode 100644
index 000000000..fae604f85
--- /dev/null
+++ b/MediaBrowser.Dlna/Service/ServiceXmlBuilder.cs
@@ -0,0 +1,90 @@
+using MediaBrowser.Dlna.Common;
+using System.Collections.Generic;
+using System.Security;
+using System.Text;
+
+namespace MediaBrowser.Dlna.Service
+{
+ public class ServiceXmlBuilder
+ {
+ public string GetXml(IEnumerable<ServiceAction> actions, IEnumerable<StateVariable> stateVariables)
+ {
+ var builder = new StringBuilder();
+
+ builder.Append("<?xml version=\"1.0\"?>");
+ builder.Append("<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">");
+
+ builder.Append("<specVersion>");
+ builder.Append("<major>1</major>");
+ builder.Append("<minor>0</minor>");
+ builder.Append("</specVersion>");
+
+ AppendActionList(builder, actions);
+ AppendServiceStateTable(builder, stateVariables);
+
+ builder.Append("</scpd>");
+
+ return builder.ToString();
+ }
+
+ private void AppendActionList(StringBuilder builder, IEnumerable<ServiceAction> actions)
+ {
+ builder.Append("<actionList>");
+
+ foreach (var item in actions)
+ {
+ builder.Append("<action>");
+
+ builder.Append("<name>" + SecurityElement.Escape(item.Name ?? string.Empty) + "</name>");
+
+ builder.Append("<argumentList>");
+
+ foreach (var argument in item.ArgumentList)
+ {
+ builder.Append("<argument>");
+
+ builder.Append("<name>" + SecurityElement.Escape(argument.Name ?? string.Empty) + "</name>");
+ builder.Append("<direction>" + SecurityElement.Escape(argument.Direction ?? string.Empty) + "</direction>");
+ builder.Append("<relatedStateVariable>" + SecurityElement.Escape(argument.RelatedStateVariable ?? string.Empty) + "</relatedStateVariable>");
+
+ builder.Append("</argument>");
+ }
+
+ builder.Append("</argumentList>");
+
+ builder.Append("</action>");
+ }
+
+ builder.Append("</actionList>");
+ }
+
+ private void AppendServiceStateTable(StringBuilder builder, IEnumerable<StateVariable> stateVariables)
+ {
+ builder.Append("<serviceStateTable>");
+
+ foreach (var item in stateVariables)
+ {
+ var sendEvents = item.SendsEvents ? "yes" : "no";
+
+ builder.Append("<stateVariable sendEvents=\"" + sendEvents + "\">");
+
+ builder.Append("<name>" + SecurityElement.Escape(item.Name ?? string.Empty) + "</name>");
+ builder.Append("<dataType>" + SecurityElement.Escape(item.DataType ?? string.Empty) + "</dataType>");
+
+ if (item.AllowedValues.Count > 0)
+ {
+ builder.Append("<allowedValueList>");
+ foreach (var allowedValue in item.AllowedValues)
+ {
+ builder.Append("<allowedValue>" + SecurityElement.Escape(allowedValue) + "</allowedValue>");
+ }
+ builder.Append("</allowedValueList>");
+ }
+
+ builder.Append("</stateVariable>");
+ }
+
+ builder.Append("</serviceStateTable>");
+ }
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
index 2b2c3d291..06408d525 100644
--- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
+++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs
@@ -267,7 +267,7 @@ namespace MediaBrowser.Server.Implementations.Channels
{
providerStartIndex = query.StartIndex;
- if (!query.Limit.HasValue || query.Limit.Value > channelInfo.MaxPageSize.Value)
+ if (query.Limit.HasValue && query.Limit.Value > channelInfo.MaxPageSize.Value)
{
throw new ArgumentException(string.Format("Channel {0} only supports a maximum of {1} records at a time.", channel.Name, channelInfo.MaxPageSize.Value));
}
diff --git a/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs b/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs
index 0b0f21e2c..110f66476 100644
--- a/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs
+++ b/MediaBrowser.Server.Implementations/Session/HttpSessionController.cs
@@ -63,17 +63,18 @@ namespace MediaBrowser.Server.Implementations.Session
private Task SendMessage(string name, CancellationToken cancellationToken)
{
- return SendMessage(name, new NameValueCollection(), cancellationToken);
+ return SendMessage(name, new Dictionary<string, string>(), cancellationToken);
}
- private Task SendMessage(string name, NameValueCollection args, CancellationToken cancellationToken)
+ private Task SendMessage(string name, Dictionary<string, string> args, CancellationToken cancellationToken)
{
- return SendMessage(new WebSocketMessage<string>
- {
- MessageType = name,
- Data = string.Empty
+ var url = _postUrl + "/" + name + ToQueryString(args);
- }, cancellationToken);
+ return _httpClient.Post(new HttpRequestOptions
+ {
+ Url = url,
+ CancellationToken = cancellationToken
+ });
}
public Task SendSessionEndedNotification(SessionInfoDto sessionInfo, CancellationToken cancellationToken)
@@ -141,12 +142,7 @@ namespace MediaBrowser.Server.Implementations.Session
public Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
{
- return SendMessage(new WebSocketMessage<GeneralCommand>
- {
- MessageType = "GeneralCommand",
- Data = command
-
- }, cancellationToken);
+ return SendMessage(command.Name, command.Arguments, cancellationToken);
}
private string ToQueryString(Dictionary<string, string> nvc)
@@ -154,7 +150,15 @@ namespace MediaBrowser.Server.Implementations.Session
var array = (from item in nvc
select string.Format("{0}={1}", WebUtility.UrlEncode(item.Key), WebUtility.UrlEncode(item.Value)))
.ToArray();
- return "?" + string.Join("&", array);
+
+ var args = string.Join("&", array);
+
+ if (string.IsNullOrEmpty(args))
+ {
+ return args;
+ }
+
+ return "?" + args;
}
}
}
diff --git a/MediaBrowser.Server.Implementations/WebSocket/AlchemyServer.cs b/MediaBrowser.Server.Implementations/WebSocket/AlchemyServer.cs
index e46dab23e..454dff4b9 100644
--- a/MediaBrowser.Server.Implementations/WebSocket/AlchemyServer.cs
+++ b/MediaBrowser.Server.Implementations/WebSocket/AlchemyServer.cs
@@ -154,9 +154,9 @@ namespace MediaBrowser.Server.Implementations.WebSocket
{
if (WebSocketServer != null)
{
- // Calling dispose will also call stop
_logger.Debug("Disposing alchemy server");
- WebSocketServer.Stop();
+
+ WebSocketServer.Dispose();
WebSocketServer = null;
}
}
diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs
index 7ccd92f04..dcb69d49d 100644
--- a/MediaBrowser.ServerApplication/ApplicationHost.cs
+++ b/MediaBrowser.ServerApplication/ApplicationHost.cs
@@ -35,6 +35,8 @@ using MediaBrowser.Controller.Sorting;
using MediaBrowser.Controller.Subtitles;
using MediaBrowser.Controller.Themes;
using MediaBrowser.Dlna;
+using MediaBrowser.Dlna.ConnectionManager;
+using MediaBrowser.Dlna.ContentDirectory;
using MediaBrowser.Dlna.Eventing;
using MediaBrowser.Dlna.Main;
using MediaBrowser.Dlna.Server;
@@ -526,6 +528,9 @@ namespace MediaBrowser.ServerApplication
var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, DtoService, LibraryManager, LogManager, ServerConfigurationManager, UserManager, dlnaEventManager);
RegisterSingleInstance<IContentDirectory>(contentDirectory);
+ var connectionManager = new ConnectionManager(dlnaManager, LogManager, ServerConfigurationManager);
+ RegisterSingleInstance<IConnectionManager>(connectionManager);
+
var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor);
RegisterSingleInstance<ICollectionManager>(collectionManager);