diff --git a/MediaBrowser.Api/Dlna/DlnaServerService.cs b/MediaBrowser.Api/Dlna/DlnaServerService.cs new file mode 100644 index 0000000000..922c67aa2d --- /dev/null +++ b/MediaBrowser.Api/Dlna/DlnaServerService.cs @@ -0,0 +1,89 @@ +using MediaBrowser.Controller.Dlna; +using ServiceStack; +using ServiceStack.Web; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace MediaBrowser.Api.Dlna +{ + [Route("/Dlna/{UuId}/description.xml", "GET", Summary = "Gets dlna server info")] + [Route("/Dlna/{UuId}/description", "GET", Summary = "Gets dlna server info")] + public class GetDescriptionXml + { + [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")] + public string UuId { get; set; } + } + + [Route("/Dlna/{UuId}/contentdirectory.xml", "GET", Summary = "Gets dlna content directory xml")] + [Route("/Dlna/{UuId}/contentdirectory", "GET", Summary = "Gets the content directory xml")] + public class GetContentDirectory + { + [ApiMember(Name = "UuId", Description = "Server UuId", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")] + public string UuId { get; set; } + } + + [Route("/Dlna/{UuId}/control", "POST", Summary = "Processes a control request")] + public class ProcessControlRequest : 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; } + } + + public class DlnaServerService : BaseApiService + { + private readonly IDlnaManager _dlnaManager; + + public DlnaServerService(IDlnaManager dlnaManager) + { + _dlnaManager = dlnaManager; + } + + public object Get(GetDescriptionXml request) + { + var xml = _dlnaManager.GetServerDescriptionXml(GetRequestHeaders(), request.UuId); + + return ResultFactory.GetResult(xml, "text/xml"); + } + + public object Get(GetContentDirectory request) + { + var xml = _dlnaManager.GetContentDirectoryXml(GetRequestHeaders()); + + return ResultFactory.GetResult(xml, "text/xml"); + } + + public object Post(ProcessControlRequest request) + { + var response = PostAsync(request).Result; + + return ResultFactory.GetResult(response.Xml, "text/xml"); + } + + private async Task PostAsync(ProcessControlRequest request) + { + using (var reader = new StreamReader(request.RequestStream)) + { + return _dlnaManager.ProcessControlRequest(new ControlRequest + { + Headers = GetRequestHeaders(), + InputXml = await reader.ReadToEndAsync().ConfigureAwait(false) + }); + } + } + + private IDictionary GetRequestHeaders() + { + var headers = new Dictionary(); + + foreach (var key in Request.Headers.AllKeys) + { + headers[key] = Request.Headers[key]; + } + + return headers; + } + } +} diff --git a/MediaBrowser.Api/DlnaService.cs b/MediaBrowser.Api/Dlna/DlnaService.cs similarity index 98% rename from MediaBrowser.Api/DlnaService.cs rename to MediaBrowser.Api/Dlna/DlnaService.cs index 792a7ff43f..9e6ca3aea9 100644 --- a/MediaBrowser.Api/DlnaService.cs +++ b/MediaBrowser.Api/Dlna/DlnaService.cs @@ -4,7 +4,7 @@ using ServiceStack; using System.Collections.Generic; using System.Linq; -namespace MediaBrowser.Api +namespace MediaBrowser.Api.Dlna { [Route("/Dlna/ProfileInfos", "GET", Summary = "Gets a list of profiles")] public class GetProfileInfos : IReturn> diff --git a/MediaBrowser.Api/MediaBrowser.Api.csproj b/MediaBrowser.Api/MediaBrowser.Api.csproj index c03eddf99e..edbae3903e 100644 --- a/MediaBrowser.Api/MediaBrowser.Api.csproj +++ b/MediaBrowser.Api/MediaBrowser.Api.csproj @@ -66,7 +66,8 @@ Properties\SharedVersion.cs - + + diff --git a/MediaBrowser.Api/Playback/BaseStreamingService.cs b/MediaBrowser.Api/Playback/BaseStreamingService.cs index bb55b893a2..4b0406cde8 100644 --- a/MediaBrowser.Api/Playback/BaseStreamingService.cs +++ b/MediaBrowser.Api/Playback/BaseStreamingService.cs @@ -1341,6 +1341,12 @@ namespace MediaBrowser.Api.Playback RequestedUrl = url }; + if (!string.IsNullOrWhiteSpace(request.AudioCodec)) + { + state.SupportedAudioCodecs = request.AudioCodec.Split(',').Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); + state.Request.AudioCodec = state.SupportedAudioCodecs.FirstOrDefault(); + } + var item = string.IsNullOrEmpty(request.MediaSourceId) ? DtoService.GetItemByDtoId(request.Id) : DtoService.GetItemByDtoId(request.MediaSourceId); @@ -1492,10 +1498,10 @@ namespace MediaBrowser.Api.Playback videoRequest.VideoCodec = "copy"; } - //if (state.AudioStream != null && CanStreamCopyAudio(request, state.AudioStream)) - //{ - // request.AudioCodec = "copy"; - //} + if (state.AudioStream != null && CanStreamCopyAudio(request, state.AudioStream, state.SupportedAudioCodecs)) + { + request.AudioCodec = "copy"; + } } return state; @@ -1587,10 +1593,10 @@ namespace MediaBrowser.Api.Playback return SupportsAutomaticVideoStreamCopy; } - private bool CanStreamCopyAudio(StreamRequest request, MediaStream audioStream) + private bool CanStreamCopyAudio(StreamRequest request, MediaStream audioStream, List supportedAudioCodecs) { // Source and target codecs must match - if (string.IsNullOrEmpty(request.AudioCodec) || !string.Equals(request.AudioCodec, audioStream.Codec, StringComparison.OrdinalIgnoreCase)) + if (string.IsNullOrEmpty(audioStream.Codec) || !supportedAudioCodecs.Contains(audioStream.Codec, StringComparer.OrdinalIgnoreCase)) { return false; } @@ -1623,7 +1629,7 @@ namespace MediaBrowser.Api.Playback } } - return SupportsAutomaticVideoStreamCopy; + return true; } protected virtual bool SupportsAutomaticVideoStreamCopy diff --git a/MediaBrowser.Api/Playback/StreamState.cs b/MediaBrowser.Api/Playback/StreamState.cs index ce7d79917a..e41f296638 100644 --- a/MediaBrowser.Api/Playback/StreamState.cs +++ b/MediaBrowser.Api/Playback/StreamState.cs @@ -67,10 +67,13 @@ namespace MediaBrowser.Api.Playback public string AudioSync = "1"; public string VideoSync = "vfr"; + public List SupportedAudioCodecs { get; set; } + public StreamState(ILiveTvManager liveTvManager, ILogger logger) { _liveTvManager = liveTvManager; _logger = logger; + SupportedAudioCodecs = new List(); } public string InputAudioSync { get; set; } diff --git a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs index ac6b9290ef..e15c32518e 100644 --- a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs +++ b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs @@ -15,6 +15,44 @@ namespace MediaBrowser.Common.Implementations.Networking /// /// IPAddress. public IEnumerable GetLocalIpAddresses() + { + var list = GetIPsDefault().Where(i => !IPAddress.IsLoopback(i)).Select(i => i.ToString()).ToList(); + + if (list.Count > 0) + { + return list; + } + + return GetLocalIpAddressesFallback(); + } + + private IEnumerable GetIPsDefault() + { + foreach (var adapter in NetworkInterface.GetAllNetworkInterfaces()) + { + var props = adapter.GetIPProperties(); + var gateways = from ga in props.GatewayAddresses + where !ga.Address.Equals(IPAddress.Any) + select true; + + if (!gateways.Any()) + { + continue; + } + + foreach (var uni in props.UnicastAddresses) + { + var address = uni.Address; + if (address.AddressFamily != AddressFamily.InterNetwork) + { + continue; + } + yield return address; + } + } + } + + private IEnumerable GetLocalIpAddressesFallback() { var host = Dns.GetHostEntry(Dns.GetHostName()); @@ -25,7 +63,7 @@ namespace MediaBrowser.Common.Implementations.Networking .Select(i => i.ToString()) .Reverse(); } - + /// /// Gets a random port number that is currently available /// @@ -50,6 +88,7 @@ namespace MediaBrowser.Common.Implementations.Networking .Select(i => BitConverter.ToString(i.GetPhysicalAddress().GetAddressBytes())) .FirstOrDefault(); } + /// /// Parses the specified endpointstring. /// diff --git a/MediaBrowser.Controller/Dlna/ControlRequest.cs b/MediaBrowser.Controller/Dlna/ControlRequest.cs new file mode 100644 index 0000000000..74e68b7d01 --- /dev/null +++ b/MediaBrowser.Controller/Dlna/ControlRequest.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +namespace MediaBrowser.Controller.Dlna +{ + public class ControlRequest + { + public IDictionary Headers { get; set; } + + public string InputXml { get; set; } + + public ControlRequest() + { + Headers = new Dictionary(); + } + } + + public class ControlResponse + { + public IDictionary Headers { get; set; } + + public string Xml { get; set; } + + public ControlResponse() + { + Headers = new Dictionary(); + } + } +} diff --git a/MediaBrowser.Controller/Dlna/IDlnaManager.cs b/MediaBrowser.Controller/Dlna/IDlnaManager.cs index 521d17e01f..bcccaaa2e9 100644 --- a/MediaBrowser.Controller/Dlna/IDlnaManager.cs +++ b/MediaBrowser.Controller/Dlna/IDlnaManager.cs @@ -55,5 +55,27 @@ namespace MediaBrowser.Controller.Dlna /// The device information. /// DeviceProfile. DeviceProfile GetProfile(DeviceIdentification deviceInfo); + + /// + /// Gets the server description XML. + /// + /// The headers. + /// The server uu identifier. + /// System.String. + string GetServerDescriptionXml(IDictionary headers, string serverUuId); + + /// + /// Gets the content directory XML. + /// + /// The headers. + /// System.String. + string GetContentDirectoryXml(IDictionary headers); + + /// + /// Processes the control request. + /// + /// The request. + /// ControlResponse. + ControlResponse ProcessControlRequest(ControlRequest request); } } diff --git a/MediaBrowser.Controller/LiveTv/LiveStreamInfo.cs b/MediaBrowser.Controller/LiveTv/LiveStreamInfo.cs index 8e1f94178d..019c9d31a5 100644 --- a/MediaBrowser.Controller/LiveTv/LiveStreamInfo.cs +++ b/MediaBrowser.Controller/LiveTv/LiveStreamInfo.cs @@ -1,4 +1,6 @@ - +using MediaBrowser.Model.Entities; +using System.Collections.Generic; + namespace MediaBrowser.Controller.LiveTv { public class LiveStreamInfo @@ -20,5 +22,22 @@ namespace MediaBrowser.Controller.LiveTv /// /// The identifier. public string Id { get; set; } + + /// + /// Gets or sets the media container. + /// + /// The media container. + public string MediaContainer { get; set; } + + /// + /// Gets or sets the media streams. + /// + /// The media streams. + public List MediaStreams { get; set; } + + public LiveStreamInfo() + { + MediaStreams = new List(); + } } } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 3082d12ca5..692a7a92eb 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -78,6 +78,7 @@ + diff --git a/MediaBrowser.Dlna/Common/Argument.cs b/MediaBrowser.Dlna/Common/Argument.cs new file mode 100644 index 0000000000..a3ff8ecc88 --- /dev/null +++ b/MediaBrowser.Dlna/Common/Argument.cs @@ -0,0 +1,12 @@ + +namespace MediaBrowser.Dlna.Common +{ + public class Argument + { + public string Name { get; set; } + + public string Direction { get; set; } + + public string RelatedStateVariable { get; set; } + } +} diff --git a/MediaBrowser.Dlna/PlayTo/DeviceIcon.cs b/MediaBrowser.Dlna/Common/DeviceIcon.cs similarity index 91% rename from MediaBrowser.Dlna/PlayTo/DeviceIcon.cs rename to MediaBrowser.Dlna/Common/DeviceIcon.cs index a46abdd745..bec10dcc5a 100644 --- a/MediaBrowser.Dlna/PlayTo/DeviceIcon.cs +++ b/MediaBrowser.Dlna/Common/DeviceIcon.cs @@ -1,5 +1,5 @@  -namespace MediaBrowser.Dlna.PlayTo +namespace MediaBrowser.Dlna.Common { public class DeviceIcon { diff --git a/MediaBrowser.Dlna/PlayTo/DeviceService.cs b/MediaBrowser.Dlna/Common/DeviceService.cs similarity index 52% rename from MediaBrowser.Dlna/PlayTo/DeviceService.cs rename to MediaBrowser.Dlna/Common/DeviceService.cs index 082128b225..8f8b175a42 100644 --- a/MediaBrowser.Dlna/PlayTo/DeviceService.cs +++ b/MediaBrowser.Dlna/Common/DeviceService.cs @@ -1,5 +1,5 @@  -namespace MediaBrowser.Dlna.PlayTo +namespace MediaBrowser.Dlna.Common { public class DeviceService { @@ -13,15 +13,6 @@ namespace MediaBrowser.Dlna.PlayTo public string EventSubUrl { get; set; } - public DeviceService(string serviceType, string serviceId, string scpdUrl, string controlUrl, string eventSubUrl) - { - ServiceType = serviceType; - ServiceId = serviceId; - ScpdUrl = scpdUrl; - ControlUrl = controlUrl; - EventSubUrl = eventSubUrl; - } - public override string ToString() { return string.Format("{0}", ServiceId); diff --git a/MediaBrowser.Dlna/Common/ServiceAction.cs b/MediaBrowser.Dlna/Common/ServiceAction.cs new file mode 100644 index 0000000000..7685e217e8 --- /dev/null +++ b/MediaBrowser.Dlna/Common/ServiceAction.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; + +namespace MediaBrowser.Dlna.Common +{ + public class ServiceAction + { + public string Name { get; set; } + + public List ArgumentList { get; set; } + + public override string ToString() + { + return Name; + } + + public ServiceAction() + { + ArgumentList = new List(); + } + } +} diff --git a/MediaBrowser.Dlna/Common/StateVariable.cs b/MediaBrowser.Dlna/Common/StateVariable.cs new file mode 100644 index 0000000000..21771e7b8e --- /dev/null +++ b/MediaBrowser.Dlna/Common/StateVariable.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace MediaBrowser.Dlna.Common +{ + public class StateVariable + { + public string Name { get; set; } + + public string DataType { get; set; } + + public bool SendsEvents { get; set; } + + public List AllowedValues { get; set; } + + public override string ToString() + { + return Name; + } + + public StateVariable() + { + AllowedValues = new List(); + } + } +} diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs index 7a8fd41830..624f23f7f2 100644 --- a/MediaBrowser.Dlna/DlnaManager.cs +++ b/MediaBrowser.Dlna/DlnaManager.cs @@ -1,9 +1,9 @@ -using System.Text; -using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; using MediaBrowser.Common.IO; using MediaBrowser.Controller.Dlna; using MediaBrowser.Dlna.Profiles; +using MediaBrowser.Dlna.Server; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Serialization; @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; using System.Text.RegularExpressions; namespace MediaBrowser.Dlna @@ -476,5 +477,26 @@ namespace MediaBrowser.Dlna internal DeviceProfileInfo Info { get; set; } internal string Path { get; set; } } + + public string GetServerDescriptionXml(IDictionary headers, string serverUuId) + { + var profile = GetProfile(headers) ?? + GetDefaultProfile(); + + return new DescriptionXmlBuilder(profile, serverUuId).GetXml(); + } + + public string GetContentDirectoryXml(IDictionary headers) + { + var profile = GetProfile(headers) ?? + GetDefaultProfile(); + + return new ContentDirectoryXmlBuilder(profile).GetXml(); + } + + public ControlResponse ProcessControlRequest(ControlRequest request) + { + return new ControlHandler(_logger).ProcessControlRequest(request); + } } } \ No newline at end of file diff --git a/MediaBrowser.Dlna/Images/logo-120.jpg b/MediaBrowser.Dlna/Images/logo-120.jpg new file mode 100644 index 0000000000..1de803c8fa Binary files /dev/null and b/MediaBrowser.Dlna/Images/logo-120.jpg differ diff --git a/MediaBrowser.Dlna/Images/logo-120.png b/MediaBrowser.Dlna/Images/logo-120.png new file mode 100644 index 0000000000..2dd04d4681 Binary files /dev/null and b/MediaBrowser.Dlna/Images/logo-120.png differ diff --git a/MediaBrowser.Dlna/Images/logo-48.jpg b/MediaBrowser.Dlna/Images/logo-48.jpg new file mode 100644 index 0000000000..f1e7302aae Binary files /dev/null and b/MediaBrowser.Dlna/Images/logo-48.jpg differ diff --git a/MediaBrowser.Dlna/Images/logo-48.png b/MediaBrowser.Dlna/Images/logo-48.png new file mode 100644 index 0000000000..3b13d141ce Binary files /dev/null and b/MediaBrowser.Dlna/Images/logo-48.png differ diff --git a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj index d1fed45729..0980ee81db 100644 --- a/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj +++ b/MediaBrowser.Dlna/MediaBrowser.Dlna.csproj @@ -52,13 +52,13 @@ Properties\SharedVersion.cs - + Code - + @@ -68,20 +68,25 @@ - + + + + + + - + - + @@ -141,6 +146,12 @@ + + + + + +