Sfoglia il codice sorgente

Merge pull request #1098 from MediaBrowser/dev

3.0.5607.0
Luke 10 anni fa
parent
commit
b2cbe8b4e1
100 ha cambiato i file con 1131 aggiunte e 894 eliminazioni
  1. 1 3
      MediaBrowser.Api/Images/ImageService.cs
  2. 2 51
      MediaBrowser.Api/Library/LibraryService.cs
  3. 12 31
      MediaBrowser.Api/Playback/BaseStreamingService.cs
  4. 2 1
      MediaBrowser.Api/Playback/Dash/MpegDashService.cs
  5. 2 1
      MediaBrowser.Api/Playback/Hls/BaseHlsService.cs
  6. 2 1
      MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs
  7. 2 1
      MediaBrowser.Api/Playback/Hls/VideoHlsService.cs
  8. 23 14
      MediaBrowser.Api/Playback/MediaInfoService.cs
  9. 2 1
      MediaBrowser.Api/Playback/Progressive/AudioService.cs
  10. 2 1
      MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs
  11. 2 1
      MediaBrowser.Api/Playback/Progressive/VideoService.cs
  12. 1 0
      MediaBrowser.Api/Subtitles/SubtitleService.cs
  13. 4 7
      MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj
  14. 13 30
      MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs
  15. 2 2
      MediaBrowser.Common.Implementations/packages.config
  16. 9 0
      MediaBrowser.Controller/Dlna/ISsdpHandler.cs
  17. 2 1
      MediaBrowser.Controller/Dlna/SsdpMessageEventArgs.cs
  18. 8 30
      MediaBrowser.Controller/Entities/Audio/Audio.cs
  19. 0 47
      MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
  20. 0 32
      MediaBrowser.Controller/Entities/BaseItem.cs
  21. 0 23
      MediaBrowser.Controller/Entities/TV/Episode.cs
  22. 1 43
      MediaBrowser.Controller/Entities/TV/Season.cs
  23. 0 13
      MediaBrowser.Controller/Entities/TV/Series.cs
  24. 12 0
      MediaBrowser.Controller/Entities/User.cs
  25. 1 3
      MediaBrowser.Controller/Entities/UserViewBuilder.cs
  26. 2 0
      MediaBrowser.Controller/MediaBrowser.Controller.csproj
  27. 1 0
      MediaBrowser.Dlna/Channels/DlnaChannelFactory.cs
  28. 0 4
      MediaBrowser.Dlna/Didl/DidlBuilder.cs
  29. 4 2
      MediaBrowser.Dlna/DlnaManager.cs
  30. 18 38
      MediaBrowser.Dlna/Main/DlnaEntryPoint.cs
  31. 6 1
      MediaBrowser.Dlna/MediaBrowser.Dlna.csproj
  32. 8 8
      MediaBrowser.Dlna/PlayTo/Device.cs
  33. 4 3
      MediaBrowser.Dlna/PlayTo/PlayToController.cs
  34. 82 49
      MediaBrowser.Dlna/PlayTo/PlayToManager.cs
  35. 8 8
      MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs
  36. 76 0
      MediaBrowser.Dlna/Profiles/BubbleUpnpProfile.cs
  37. 18 0
      MediaBrowser.Dlna/Profiles/DefaultProfile.cs
  38. 1 8
      MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs
  39. 1 8
      MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs
  40. 1 8
      MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs
  41. 1 8
      MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs
  42. 8 8
      MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs
  43. 8 8
      MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs
  44. 8 8
      MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs
  45. 8 8
      MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs
  46. 76 0
      MediaBrowser.Dlna/Profiles/VlcProfile.cs
  47. 0 1
      MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs
  48. 7 3
      MediaBrowser.Dlna/Profiles/Xbox360Profile.cs
  49. 1 1
      MediaBrowser.Dlna/Profiles/XboxOneProfile.cs
  50. 29 0
      MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml
  51. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Default.xml
  52. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml
  53. 4 2
      MediaBrowser.Dlna/Profiles/Xml/DirecTV HD-DVR.xml
  54. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml
  55. 23 0
      MediaBrowser.Dlna/Profiles/Xml/Generic Device.xml
  56. 4 2
      MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml
  57. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml
  58. 4 2
      MediaBrowser.Dlna/Profiles/Xml/MediaMonkey.xml
  59. 2 1
      MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml
  60. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml
  61. 2 1
      MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml
  62. 2 1
      MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml
  63. 2 1
      MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml
  64. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml
  65. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml
  66. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml
  67. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml
  68. 4 2
      MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml
  69. 29 0
      MediaBrowser.Dlna/Profiles/Xml/Vlc.xml
  70. 4 2
      MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml
  71. 6 6
      MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml
  72. 5 3
      MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml
  73. 4 2
      MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml
  74. 26 7
      MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs
  75. 4 2
      MediaBrowser.Dlna/Service/BaseControlHandler.cs
  76. 57 21
      MediaBrowser.Dlna/Ssdp/Datagram.cs
  77. 18 9
      MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs
  78. 114 30
      MediaBrowser.Dlna/Ssdp/SsdpHandler.cs
  79. 4 2
      MediaBrowser.Dlna/Ssdp/SsdpHelper.cs
  80. 3 25
      MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs
  81. 0 2
      MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs
  82. 160 136
      MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
  83. 0 2
      MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs
  84. 6 0
      MediaBrowser.Model/ApiClient/IApiClient.cs
  85. 2 4
      MediaBrowser.Model/Configuration/ServerConfiguration.cs
  86. 3 1
      MediaBrowser.Model/Configuration/UserConfiguration.cs
  87. 26 1
      MediaBrowser.Model/Dlna/CodecProfile.cs
  88. 0 6
      MediaBrowser.Model/Dlna/ConditionProcessor.cs
  89. 2 5
      MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
  90. 1 4
      MediaBrowser.Model/Dlna/DeviceProfile.cs
  91. 8 8
      MediaBrowser.Model/Dlna/StreamBuilder.cs
  92. 14 16
      MediaBrowser.Providers/Manager/ItemImageProvider.cs
  93. 9 0
      MediaBrowser.Providers/Manager/ProviderUtils.cs
  94. 1 1
      MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
  95. 11 4
      MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs
  96. 1 10
      MediaBrowser.Server.Implementations/Dto/DtoService.cs
  97. 23 5
      MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs
  98. 1 2
      MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs
  99. 4 4
      MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs
  100. 21 25
      MediaBrowser.Server.Implementations/Library/LibraryManager.cs

+ 1 - 3
MediaBrowser.Api/Images/ImageService.cs

@@ -648,10 +648,8 @@ namespace MediaBrowser.Api.Images
 
             var serverFormats = _imageProcessor.GetSupportedImageOutputFormats();
 
-            var clientFormats = GetClientSupportedFormats();
-
             if (serverFormats.Contains(ImageFormat.Webp) &&
-                clientFormats.Contains(ImageFormat.Webp))
+                GetClientSupportedFormats().Contains(ImageFormat.Webp))
             {
                 return ImageFormat.Webp;
             }

+ 2 - 51
MediaBrowser.Api/Library/LibraryService.cs

@@ -617,36 +617,14 @@ namespace MediaBrowser.Api.Library
                                   : (Folder)_libraryManager.RootFolder)
                            : _libraryManager.GetItemById(request.Id);
 
-            var originalItem = item;
-
             while (GetThemeSongIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
             {
                 item = item.Parent;
             }
 
-            var themeSongIds = GetThemeSongIds(item);
-
-            if (themeSongIds.Count == 0 && request.InheritFromParent)
-            {
-                var album = originalItem as MusicAlbum;
-
-                if (album != null)
-                {
-                    var linkedItemWithThemes = album.SoundtrackIds
-                        .Select(i => _libraryManager.GetItemById(i))
-                        .FirstOrDefault(i => GetThemeSongIds(i).Count > 0);
-
-                    if (linkedItemWithThemes != null)
-                    {
-                        themeSongIds = GetThemeSongIds(linkedItemWithThemes);
-                        item = linkedItemWithThemes;
-                    }
-                }
-            }
-
             var dtoOptions = GetDtoOptions(request);
 
-            var dtos = themeSongIds.Select(_libraryManager.GetItemById)
+            var dtos = GetThemeSongIds(item).Select(_libraryManager.GetItemById)
                             .OrderBy(i => i.SortName)
                             .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
 
@@ -682,41 +660,14 @@ namespace MediaBrowser.Api.Library
                                   : (Folder)_libraryManager.RootFolder)
                            : _libraryManager.GetItemById(request.Id);
 
-            var originalItem = item;
-
             while (GetThemeVideoIds(item).Count == 0 && request.InheritFromParent && item.Parent != null)
             {
                 item = item.Parent;
             }
 
-            var themeVideoIds = GetThemeVideoIds(item);
-
-            if (themeVideoIds.Count == 0 && request.InheritFromParent)
-            {
-                var album = originalItem as MusicAlbum;
-
-                if (album == null)
-                {
-                    album = originalItem.Parents.OfType<MusicAlbum>().FirstOrDefault();
-                }
-
-                if (album != null)
-                {
-                    var linkedItemWithThemes = album.SoundtrackIds
-                        .Select(i => _libraryManager.GetItemById(i))
-                        .FirstOrDefault(i => GetThemeVideoIds(i).Count > 0);
-
-                    if (linkedItemWithThemes != null)
-                    {
-                        themeVideoIds = GetThemeVideoIds(linkedItemWithThemes);
-                        item = linkedItemWithThemes;
-                    }
-                }
-            }
-
             var dtoOptions = GetDtoOptions(request);
 
-            var dtos = themeVideoIds.Select(_libraryManager.GetItemById)
+            var dtos = GetThemeVideoIds(item).Select(_libraryManager.GetItemById)
                             .OrderBy(i => i.SortName)
                             .Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user, item));
 

+ 12 - 31
MediaBrowser.Api/Playback/BaseStreamingService.cs

@@ -23,6 +23,7 @@ using System.Linq;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Model.Serialization;
 
 namespace MediaBrowser.Api.Playback
 {
@@ -68,12 +69,14 @@ namespace MediaBrowser.Api.Playback
         protected ISubtitleEncoder SubtitleEncoder { get; private set; }
         protected IMediaSourceManager MediaSourceManager { get; private set; }
         protected IZipClient ZipClient { get; private set; }
+        protected IJsonSerializer JsonSerializer { get; private set; }
 
         /// <summary>
         /// Initializes a new instance of the <see cref="BaseStreamingService" /> class.
         /// </summary>
-        protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient)
+        protected BaseStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer)
         {
+            JsonSerializer = jsonSerializer;
             ZipClient = zipClient;
             MediaSourceManager = mediaSourceManager;
             DeviceManager = deviceManager;
@@ -598,7 +601,7 @@ namespace MediaBrowser.Api.Playback
                 var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
                 var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
 
-                filters.Add(string.Format("scale=trunc(min(iw\\,{0})/2)*2:trunc(min((iw/dar)\\,{1})/2)*2", maxWidthParam, maxHeightParam));
+                filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/2)*2:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2", maxWidthParam, maxHeightParam));
             }
 
             // If a fixed width was requested
@@ -618,7 +621,7 @@ namespace MediaBrowser.Api.Playback
             }
 
             // If a max width was requested
-            else if (request.MaxWidth.HasValue && (!request.MaxHeight.HasValue || state.VideoStream == null))
+            else if (request.MaxWidth.HasValue)
             {
                 var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
 
@@ -626,35 +629,13 @@ namespace MediaBrowser.Api.Playback
             }
 
             // If a max height was requested
-            else if (request.MaxHeight.HasValue && (!request.MaxWidth.HasValue || state.VideoStream == null))
+            else if (request.MaxHeight.HasValue)
             {
                 var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
 
                 filters.Add(string.Format("scale=trunc(oh*a*2)/2:min(ih\\,{0})", maxHeightParam));
             }
 
-            else if (request.MaxWidth.HasValue ||
-                request.MaxHeight.HasValue ||
-                request.Width.HasValue ||
-                request.Height.HasValue)
-            {
-                if (state.VideoStream != null)
-                {
-                    // Need to perform calculations manually
-
-                    // Try to account for bad media info
-                    var currentHeight = state.VideoStream.Height ?? request.MaxHeight ?? request.Height ?? 0;
-                    var currentWidth = state.VideoStream.Width ?? request.MaxWidth ?? request.Width ?? 0;
-
-                    var outputSize = DrawingUtils.Resize(currentWidth, currentHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight);
-
-                    var manualWidthParam = outputSize.Width.ToString(UsCulture);
-                    var manualHeightParam = outputSize.Height.ToString(UsCulture);
-
-                    filters.Add(string.Format("scale=trunc({0}/2)*2:trunc({1}/2)*2", manualWidthParam, manualHeightParam));
-                }
-            }
-
             if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))
             {
                 filters[filters.Count - 1] += ":flags=fast_bilinear";
@@ -1027,7 +1008,7 @@ namespace MediaBrowser.Api.Playback
             // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory.
             state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true);
 
-            var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(Request.AbsoluteUri + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine);
+            var commandLineLogMessageBytes = Encoding.UTF8.GetBytes(Request.AbsoluteUri + Environment.NewLine + Environment.NewLine + JsonSerializer.SerializeToString(state.MediaSource) + Environment.NewLine + Environment.NewLine + commandLineLogMessage + Environment.NewLine + Environment.NewLine);
             await state.LogFileStream.WriteAsync(commandLineLogMessageBytes, 0, commandLineLogMessageBytes.Length, cancellationTokenSource.Token).ConfigureAwait(false);
 
             process.Exited += (sender, args) => OnFfMpegProcessExited(process, transcodingJob, state);
@@ -1105,6 +1086,10 @@ namespace MediaBrowser.Api.Playback
                     }
                 }
             }
+            catch (ObjectDisposedException)
+            {
+                // Don't spam the log. This doesn't seem to throw in windows, but sometimes under linux
+            }
             catch (Exception ex)
             {
                 Logger.ErrorException("Error reading ffmpeg log", ex);
@@ -2033,8 +2018,6 @@ namespace MediaBrowser.Api.Playback
                 profile.GetVideoMediaProfile(state.OutputContainer,
                 audioCodec,
                 videoCodec,
-                state.OutputAudioBitrate,
-                state.OutputAudioChannels,
                 state.OutputWidth,
                 state.OutputHeight,
                 state.TargetVideoBitDepth,
@@ -2121,8 +2104,6 @@ namespace MediaBrowser.Api.Playback
                     state.OutputHeight,
                     state.TargetVideoBitDepth,
                     state.OutputVideoBitrate,
-                    state.OutputAudioBitrate,
-                    state.OutputAudioChannels,
                     state.TargetTimestamp,
                     isStaticallyStreamed,
                     state.RunTimeTicks,

+ 2 - 1
MediaBrowser.Api/Playback/Dash/MpegDashService.cs

@@ -8,6 +8,7 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Serialization;
 using ServiceStack;
 using System;
 using System.Collections.Generic;
@@ -53,7 +54,7 @@ namespace MediaBrowser.Api.Playback.Dash
 
     public class MpegDashService : BaseHlsService
     {
-        public MpegDashService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
+        public MpegDashService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
         {
             NetworkManager = networkManager;
         }

+ 2 - 1
MediaBrowser.Api/Playback/Hls/BaseHlsService.cs

@@ -13,6 +13,7 @@ using System.IO;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
+using MediaBrowser.Model.Serialization;
 
 namespace MediaBrowser.Api.Playback.Hls
 {
@@ -21,7 +22,7 @@ namespace MediaBrowser.Api.Playback.Hls
     /// </summary>
     public abstract class BaseHlsService : BaseStreamingService
     {
-        protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
+        protected BaseHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
         {
         }
 

+ 2 - 1
MediaBrowser.Api/Playback/Hls/DynamicHlsService.cs

@@ -10,6 +10,7 @@ using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Serialization;
 using ServiceStack;
 using System;
 using System.Collections.Generic;
@@ -61,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Hls
 
     public class DynamicHlsService : BaseHlsService
     {
-        public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
+        public DynamicHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, INetworkManager networkManager) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
         {
             NetworkManager = networkManager;
         }

+ 2 - 1
MediaBrowser.Api/Playback/Hls/VideoHlsService.cs

@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Serialization;
 using ServiceStack;
 using System;
 
@@ -40,7 +41,7 @@ namespace MediaBrowser.Api.Playback.Hls
     /// </summary>
     public class VideoHlsService : BaseHlsService
     {
-        public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
+        public VideoHlsService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
         {
         }
 

+ 23 - 14
MediaBrowser.Api/Playback/MediaInfoService.cs

@@ -18,16 +18,6 @@ using System.Threading.Tasks;
 
 namespace MediaBrowser.Api.Playback
 {
-    [Route("/Items/{Id}/MediaInfo", "GET", Summary = "Gets live playback media info for an item")]
-    public class GetLiveMediaInfo : IReturn<PlaybackInfoResponse>
-    {
-        [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
-        public string Id { get; set; }
-
-        [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
-        public string UserId { get; set; }
-    }
-
     [Route("/Items/{Id}/PlaybackInfo", "GET", Summary = "Gets live playback media info for an item")]
     public class GetPlaybackInfo : IReturn<PlaybackInfoResponse>
     {
@@ -55,6 +45,19 @@ namespace MediaBrowser.Api.Playback
         public string LiveStreamId { get; set; }
     }
 
+    [Route("/Playback/BitrateTest", "GET")]
+    public class GetBitrateTestBytes : IReturn<PlaybackInfoResponse>
+    {
+        [ApiMember(Name = "Size", Description = "Size", IsRequired = true, DataType = "int", ParameterType = "query", Verb = "GET")]
+        public long Size { get; set; }
+
+        public GetBitrateTestBytes()
+        {
+            // 100k
+            Size = 102400;
+        }
+    }
+    
     [Authenticated]
     public class MediaInfoService : BaseApiService
     {
@@ -73,13 +76,19 @@ namespace MediaBrowser.Api.Playback
             _networkManager = networkManager;
         }
 
-        public async Task<object> Get(GetPlaybackInfo request)
+        public object Get(GetBitrateTestBytes request)
         {
-            var result = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }).ConfigureAwait(false);
-            return ToOptimizedResult(result);
+            var bytes = new byte[request.Size];
+
+            for (var i = 0; i < bytes.Length; i++)
+            {
+                bytes[i] = 0;
+            }
+
+            return ResultFactory.GetResult(bytes, "application/octet-stream");
         }
 
-        public async Task<object> Get(GetLiveMediaInfo request)
+        public async Task<object> Get(GetPlaybackInfo request)
         {
             var result = await GetPlaybackInfo(request.Id, request.UserId, new[] { MediaType.Audio, MediaType.Video }).ConfigureAwait(false);
             return ToOptimizedResult(result);

+ 2 - 1
MediaBrowser.Api/Playback/Progressive/AudioService.cs

@@ -8,6 +8,7 @@ using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Serialization;
 using ServiceStack;
 using System.Collections.Generic;
 
@@ -31,7 +32,7 @@ namespace MediaBrowser.Api.Playback.Progressive
     /// </summary>
     public class AudioService : BaseProgressiveStreamingService
     {
-        public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
+        public AudioService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, imageProcessor, httpClient)
         {
         }
 

+ 2 - 1
MediaBrowser.Api/Playback/Progressive/BaseProgressiveStreamingService.cs

@@ -10,6 +10,7 @@ using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.MediaInfo;
+using MediaBrowser.Model.Serialization;
 using ServiceStack.Web;
 using System;
 using System.Collections.Generic;
@@ -27,7 +28,7 @@ namespace MediaBrowser.Api.Playback.Progressive
         protected readonly IImageProcessor ImageProcessor;
         protected readonly IHttpClient HttpClient;
 
-        protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient)
+        protected BaseProgressiveStreamingService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer)
         {
             ImageProcessor = imageProcessor;
             HttpClient = httpClient;

+ 2 - 1
MediaBrowser.Api/Playback/Progressive/VideoService.cs

@@ -7,6 +7,7 @@ using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Serialization;
 using ServiceStack;
 using System;
 using System.IO;
@@ -61,7 +62,7 @@ namespace MediaBrowser.Api.Playback.Progressive
     /// </summary>
     public class VideoService : BaseProgressiveStreamingService
     {
-        public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, imageProcessor, httpClient)
+        public VideoService(IServerConfigurationManager serverConfig, IUserManager userManager, ILibraryManager libraryManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IFileSystem fileSystem, IDlnaManager dlnaManager, ISubtitleEncoder subtitleEncoder, IDeviceManager deviceManager, IMediaSourceManager mediaSourceManager, IZipClient zipClient, IJsonSerializer jsonSerializer, IImageProcessor imageProcessor, IHttpClient httpClient) : base(serverConfig, userManager, libraryManager, isoManager, mediaEncoder, fileSystem, dlnaManager, subtitleEncoder, deviceManager, mediaSourceManager, zipClient, jsonSerializer, imageProcessor, httpClient)
         {
         }
 

+ 1 - 0
MediaBrowser.Api/Subtitles/SubtitleService.cs

@@ -100,6 +100,7 @@ namespace MediaBrowser.Api.Subtitles
     }
 
     [Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/subtitles.m3u8", "GET", Summary = "Gets an HLS subtitle playlist.")]
+    [Authenticated]
     public class GetSubtitlePlaylist
     {
         /// <summary>

+ 4 - 7
MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj

@@ -48,9 +48,9 @@
     <RunPostBuildEvent>Always</RunPostBuildEvent>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="NLog, Version=3.2.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
+    <Reference Include="NLog, Version=3.2.1.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\NLog.3.2.0.0\lib\net45\NLog.dll</HintPath>
+      <HintPath>..\packages\NLog.3.2.1\lib\net45\NLog.dll</HintPath>
     </Reference>
     <Reference Include="SharpCompress, Version=0.10.2.0, Culture=neutral, PublicKeyToken=beaf6f427e128133, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
@@ -58,11 +58,8 @@
     </Reference>
     <Reference Include="SimpleInjector, Version=2.7.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\SimpleInjector.2.7.0\lib\net45\SimpleInjector.dll</HintPath>
-    </Reference>
-    <Reference Include="SimpleInjector.Diagnostics, Version=2.7.0.0, Culture=neutral, PublicKeyToken=984cb50dea722e99, processorArchitecture=MSIL">
-      <SpecificVersion>False</SpecificVersion>
-      <HintPath>..\packages\SimpleInjector.2.7.0\lib\net45\SimpleInjector.Diagnostics.dll</HintPath>
+      <HintPath>..\packages\SimpleInjector.2.8.0\lib\net45\SimpleInjector.dll</HintPath>
+      <Private>True</Private>
     </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />

+ 13 - 30
MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs

@@ -6,16 +6,29 @@ using System.Linq;
 using System.Net;
 using System.Net.NetworkInformation;
 using System.Net.Sockets;
+using System.Threading;
 
 namespace MediaBrowser.Common.Implementations.Networking
 {
     public abstract class BaseNetworkManager
     {
         protected ILogger Logger { get; private set; }
+        private Timer _clearCacheTimer;
 
         protected BaseNetworkManager(ILogger logger)
         {
             Logger = logger;
+
+            // Can't use network change events due to a crash in Linux
+            _clearCacheTimer = new Timer(ClearCacheTimerCallback, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
+        }
+
+        private void ClearCacheTimerCallback(object state)
+        {
+            lock (_localIpAddressSyncLock)
+            {
+                _localIpAddresses = null;
+            }
         }
 
         private volatile List<string> _localIpAddresses;
@@ -36,7 +49,6 @@ namespace MediaBrowser.Common.Implementations.Networking
                         var addresses = GetLocalIpAddressesInternal().ToList();
 
                         _localIpAddresses = addresses;
-                        BindEvents();
 
                         return addresses;
                     }
@@ -46,35 +58,6 @@ namespace MediaBrowser.Common.Implementations.Networking
             return _localIpAddresses;
         }
 
-        private void BindEvents()
-        {
-            NetworkChange.NetworkAddressChanged -= NetworkChange_NetworkAddressChanged;
-            NetworkChange.NetworkAvailabilityChanged -= NetworkChange_NetworkAvailabilityChanged;
-
-            NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged;
-            NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged;
-        }
-
-        void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
-        {
-            Logger.Debug("NetworkAvailabilityChanged fired. Resetting cached network info.");
-
-            lock (_localIpAddressSyncLock)
-            {
-                _localIpAddresses = null;
-            }
-        }
-
-        void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
-        {
-            Logger.Debug("NetworkAddressChanged fired. Resetting cached network info.");
-
-            lock (_localIpAddressSyncLock)
-            {
-                _localIpAddresses = null;
-            }
-        }
-
         private IEnumerable<string> GetLocalIpAddressesInternal()
         {
             var list = GetIPsDefault()

+ 2 - 2
MediaBrowser.Common.Implementations/packages.config

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="NLog" version="3.2.0.0" targetFramework="net45" />
-  <package id="SimpleInjector" version="2.7.0" targetFramework="net45" />
+  <package id="NLog" version="3.2.1" targetFramework="net45" />
+  <package id="SimpleInjector" version="2.8.0" targetFramework="net45" />
 </packages>

+ 9 - 0
MediaBrowser.Controller/Dlna/ISsdpHandler.cs

@@ -0,0 +1,9 @@
+using System;
+
+namespace MediaBrowser.Controller.Dlna
+{
+    public interface ISsdpHandler
+    {
+        event EventHandler<SsdpMessageEventArgs> MessageReceived;
+    }
+}

+ 2 - 1
MediaBrowser.Dlna/Ssdp/SsdpMessageEventArgs.cs → MediaBrowser.Controller/Dlna/SsdpMessageEventArgs.cs

@@ -2,7 +2,7 @@
 using System.Collections.Generic;
 using System.Net;
 
-namespace MediaBrowser.Dlna.Ssdp
+namespace MediaBrowser.Controller.Dlna
 {
     public class SsdpMessageEventArgs
     {
@@ -13,6 +13,7 @@ namespace MediaBrowser.Dlna.Ssdp
         public Dictionary<string, string> Headers { get; set; }
 
         public IPAddress LocalIp { get; set; }
+        public byte[] Message { get; set; }
 
         public SsdpMessageEventArgs()
         {

+ 8 - 30
MediaBrowser.Controller/Entities/Audio/Audio.cs

@@ -52,34 +52,6 @@ namespace MediaBrowser.Controller.Entities.Audio
         /// <value><c>true</c> if this instance has embedded image; otherwise, <c>false</c>.</value>
         public bool HasEmbeddedImage { get; set; }
 
-        /// <summary>
-        /// Override this to true if class should be grouped under a container in indicies
-        /// The container class should be defined via IndexContainer
-        /// </summary>
-        /// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public override bool GroupInIndex
-        {
-            get
-            {
-                return true;
-            }
-        }
-
-        /// <summary>
-        /// Override this to return the folder that should be used to construct a container
-        /// for this item in an index.  GroupInIndex should be true as well.
-        /// </summary>
-        /// <value>The index container.</value>
-        [IgnoreDataMember]
-        public override Folder IndexContainer
-        {
-            get
-            {
-                return LatestItemsIndexContainer ?? new MusicAlbum { Name = "Unknown Album" };
-            }
-        }
-
         [IgnoreDataMember]
         protected override bool SupportsOwnedItems
         {
@@ -94,7 +66,7 @@ namespace MediaBrowser.Controller.Entities.Audio
         {
             get
             {
-                return Parents.OfType<MusicAlbum>().FirstOrDefault();
+                return AlbumEntity;
             }
         }
 
@@ -148,6 +120,12 @@ namespace MediaBrowser.Controller.Entities.Audio
         /// <value>The album.</value>
         public string Album { get; set; }
 
+        [IgnoreDataMember]
+        public MusicAlbum AlbumEntity
+        {
+            get { return FindParent<MusicAlbum>(); }
+        }
+
         /// <summary>
         /// Gets the type of the media.
         /// </summary>
@@ -177,7 +155,7 @@ namespace MediaBrowser.Controller.Entities.Audio
         /// <returns>System.String.</returns>
         protected override string CreateUserDataKey()
         {
-            var parent = FindParent<MusicAlbum>();
+            var parent = AlbumEntity;
 
             if (parent != null)
             {

+ 0 - 47
MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs

@@ -2,7 +2,6 @@
 using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Users;
-using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Runtime.Serialization;
@@ -14,11 +13,8 @@ namespace MediaBrowser.Controller.Entities.Audio
     /// </summary>
     public class MusicAlbum : Folder, IHasAlbumArtist, IHasArtist, IHasMusicGenres, IHasLookupInfo<AlbumInfo>
     {
-        public List<Guid> SoundtrackIds { get; set; }
-
         public MusicAlbum()
         {
-            SoundtrackIds = new List<Guid>();
             Artists = new List<string>();
             AlbumArtists = new List<string>();
         }
@@ -77,49 +73,6 @@ namespace MediaBrowser.Controller.Entities.Audio
             return Tracks;
         }
 
-        /// <summary>
-        /// Songs will group into us so don't also include us in the index
-        /// </summary>
-        /// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public override bool IncludeInIndex
-        {
-            get
-            {
-                return false;
-            }
-        }
-
-        /// <summary>
-        /// Override this to true if class should be grouped under a container in indicies
-        /// The container class should be defined via IndexContainer
-        /// </summary>
-        /// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public override bool GroupInIndex
-        {
-            get
-            {
-                return true;
-            }
-        }
-
-        /// <summary>
-        /// The unknwon artist
-        /// </summary>
-        private static readonly MusicArtist UnknwonArtist = new MusicArtist { Name = "<Unknown>" };
-
-        /// <summary>
-        /// Override this to return the folder that should be used to construct a container
-        /// for this item in an index.  GroupInIndex should be true as well.
-        /// </summary>
-        /// <value>The index container.</value>
-        [IgnoreDataMember]
-        public override Folder IndexContainer
-        {
-            get { return Parent as MusicArtist ?? UnknwonArtist; }
-        }
-
         public List<string> Artists { get; set; }
 
         /// <summary>

+ 0 - 32
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -906,38 +906,6 @@ namespace MediaBrowser.Controller.Entities
         /// <value>The provider ids.</value>
         public Dictionary<string, string> ProviderIds { get; set; }
 
-        /// <summary>
-        /// Override this to false if class should be ignored for indexing purposes
-        /// </summary>
-        /// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public virtual bool IncludeInIndex
-        {
-            get { return true; }
-        }
-
-        /// <summary>
-        /// Override this to true if class should be grouped under a container in indicies
-        /// The container class should be defined via IndexContainer
-        /// </summary>
-        /// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public virtual bool GroupInIndex
-        {
-            get { return false; }
-        }
-
-        /// <summary>
-        /// Override this to return the folder that should be used to construct a container
-        /// for this item in an index.  GroupInIndex should be true as well.
-        /// </summary>
-        /// <value>The index container.</value>
-        [IgnoreDataMember]
-        public virtual Folder IndexContainer
-        {
-            get { return null; }
-        }
-
         [IgnoreDataMember]
         public virtual Folder LatestItemsIndexContainer
         {

+ 0 - 23
MediaBrowser.Controller/Entities/TV/Episode.cs

@@ -45,16 +45,6 @@ namespace MediaBrowser.Controller.Entities.TV
         /// <value>The index number.</value>
         public int? IndexNumberEnd { get; set; }
 
-        /// <summary>
-        /// We want to group into series not show individually in an index
-        /// </summary>
-        /// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public override bool GroupInIndex
-        {
-            get { return true; }
-        }
-
         [IgnoreDataMember]
         protected override bool SupportsOwnedItems
         {
@@ -91,19 +81,6 @@ namespace MediaBrowser.Controller.Entities.TV
             }
         }
 
-        /// <summary>
-        /// We roll up into series
-        /// </summary>
-        /// <value>The index container.</value>
-        [IgnoreDataMember]
-        public override Folder IndexContainer
-        {
-            get
-            {
-                return Season;
-            }
-        }
-
         [IgnoreDataMember]
         public override Folder LatestItemsIndexContainer
         {

+ 1 - 43
MediaBrowser.Controller/Entities/TV/Season.cs

@@ -1,5 +1,4 @@
-using MediaBrowser.Controller.Localization;
-using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Querying;
 using MediaBrowser.Model.Users;
@@ -15,20 +14,6 @@ namespace MediaBrowser.Controller.Entities.TV
     /// </summary>
     public class Season : Folder, IHasSeries, IHasLookupInfo<SeasonInfo>
     {
-
-        /// <summary>
-        /// Seasons are just containers
-        /// </summary>
-        /// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public override bool IncludeInIndex
-        {
-            get
-            {
-                return false;
-            }
-        }
-
         [IgnoreDataMember]
         public override bool SupportsAddingToPlaylist
         {
@@ -50,33 +35,6 @@ namespace MediaBrowser.Controller.Entities.TV
             get { return Series ?? Parent; }
         }
 
-        /// <summary>
-        /// We want to group into our Series
-        /// </summary>
-        /// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public override bool GroupInIndex
-        {
-            get
-            {
-                return true;
-            }
-        }
-
-        /// <summary>
-        /// Override this to return the folder that should be used to construct a container
-        /// for this item in an index.  GroupInIndex should be true as well.
-        /// </summary>
-        /// <value>The index container.</value>
-        [IgnoreDataMember]
-        public override Folder IndexContainer
-        {
-            get
-            {
-                return Series;
-            }
-        }
-
         // Genre, Rating and Stuido will all be the same
         protected override IEnumerable<string> GetIndexByOptions()
         {

+ 0 - 13
MediaBrowser.Controller/Entities/TV/Series.cs

@@ -94,19 +94,6 @@ namespace MediaBrowser.Controller.Entities.TV
             }
         }
 
-        /// <summary>
-        /// Series aren't included directly in indices - Their Episodes will roll up to them
-        /// </summary>
-        /// <value><c>true</c> if [include in index]; otherwise, <c>false</c>.</value>
-        [IgnoreDataMember]
-        public override bool IncludeInIndex
-        {
-            get
-            {
-                return false;
-            }
-        }
-
         /// <summary>
         /// Gets the user data key.
         /// </summary>

+ 12 - 0
MediaBrowser.Controller/Entities/User.cs

@@ -283,5 +283,17 @@ namespace MediaBrowser.Controller.Entities
 
             return hour >= schedule.StartHour && hour <= schedule.EndHour;
         }
+
+        public bool IsFolderGrouped(Guid id)
+        {
+            var config = Configuration;
+
+            if (config.ExcludeFoldersFromGrouping != null)
+            {
+                return !config.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).Contains(id);
+            }
+
+            return config.GroupedFolders.Select(i => new Guid(i)).Contains(id);
+        }
     }
 }

+ 1 - 3
MediaBrowser.Controller/Entities/UserViewBuilder.cs

@@ -1754,12 +1754,10 @@ namespace MediaBrowser.Controller.Entities
 
         private IEnumerable<Folder> GetMediaFolders(User user)
         {
-            var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList();
-
             return user.RootFolder
                 .GetChildren(user, true, true)
                 .OfType<Folder>()
-                .Where(i => !excludeFolderIds.Contains(i.Id) && !UserView.IsExcludedFromGrouping(i));
+                .Where(i => user.IsFolderGrouped(i.Id) && !UserView.IsExcludedFromGrouping(i));
         }
 
         private IEnumerable<Folder> GetMediaFolders(User user, IEnumerable<string> viewTypes)

+ 2 - 0
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -116,7 +116,9 @@
     <Compile Include="Dlna\IDlnaManager.cs" />
     <Compile Include="Dlna\IEventManager.cs" />
     <Compile Include="Dlna\IMediaReceiverRegistrar.cs" />
+    <Compile Include="Dlna\ISsdpHandler.cs" />
     <Compile Include="Dlna\IUpnpService.cs" />
+    <Compile Include="Dlna\SsdpMessageEventArgs.cs" />
     <Compile Include="Drawing\IImageProcessor.cs" />
     <Compile Include="Drawing\ImageCollageOptions.cs" />
     <Compile Include="Drawing\ImageProcessingOptions.cs" />

+ 1 - 0
MediaBrowser.Dlna/Channels/DlnaChannelFactory.cs

@@ -2,6 +2,7 @@
 using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Dlna.ContentDirectory;
 using MediaBrowser.Dlna.PlayTo;

+ 0 - 4
MediaBrowser.Dlna/Didl/DidlBuilder.cs

@@ -149,8 +149,6 @@ namespace MediaBrowser.Dlna.Didl
                 targetHeight,
                 streamInfo.TargetVideoBitDepth,
                 streamInfo.TargetVideoBitrate,
-                streamInfo.TargetAudioChannels,
-                streamInfo.TargetAudioBitrate,
                 streamInfo.TargetTimestamp,
                 streamInfo.IsDirectStream,
                 streamInfo.RunTimeTicks,
@@ -276,11 +274,9 @@ namespace MediaBrowser.Dlna.Didl
                 streamInfo.AudioCodec,
                 streamInfo.VideoCodec,
                 streamInfo.TargetAudioBitrate,
-                targetChannels,
                 targetWidth,
                 targetHeight,
                 streamInfo.TargetVideoBitDepth,
-                streamInfo.TargetVideoBitrate,
                 streamInfo.TargetVideoProfile,
                 streamInfo.TargetVideoLevel,
                 streamInfo.TargetFramerate,

+ 4 - 2
MediaBrowser.Dlna/DlnaManager.cs

@@ -482,7 +482,7 @@ namespace MediaBrowser.Dlna
             var profile = GetProfile(headers) ??
                           GetDefaultProfile();
 
-            return new DescriptionXmlBuilder(profile, serverUuId, serverAddress, _appHost.FriendlyName).GetXml();
+            return new DescriptionXmlBuilder(profile, serverUuId, serverAddress, _appHost.FriendlyName, serverUuId.GetMD5().ToString("N")).GetXml();
         }
 
         public ImageStream GetIcon(string filename)
@@ -544,7 +544,9 @@ namespace MediaBrowser.Dlna
                 new DirectTvProfile(),
                 new DishHopperJoeyProfile(),
                 new DefaultProfile(),
-                new PopcornHourProfile()
+                new PopcornHourProfile(),
+                new VlcProfile(),
+                new BubbleUpnpProfile()
             };
 
             foreach (var item in list)

+ 18 - 38
MediaBrowser.Dlna/Main/DlnaEntryPoint.cs

@@ -37,13 +37,26 @@ namespace MediaBrowser.Dlna.Main
         private readonly ILocalizationManager _localization;
         private readonly IMediaSourceManager _mediaSourceManager;
 
-        private SsdpHandler _ssdpHandler;
+        private readonly SsdpHandler _ssdpHandler;
         private DeviceDiscovery _deviceDiscovery;
 
         private readonly List<string> _registeredServerIds = new List<string>();
         private bool _dlnaServerStarted;
 
-        public DlnaEntryPoint(IServerConfigurationManager config, ILogManager logManager, IServerApplicationHost appHost, INetworkManager network, ISessionManager sessionManager, IHttpClient httpClient, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IImageProcessor imageProcessor, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager)
+        public DlnaEntryPoint(IServerConfigurationManager config, 
+            ILogManager logManager, 
+            IServerApplicationHost appHost, 
+            INetworkManager network, 
+            ISessionManager sessionManager, 
+            IHttpClient httpClient, 
+            ILibraryManager libraryManager, 
+            IUserManager userManager, 
+            IDlnaManager dlnaManager, 
+            IImageProcessor imageProcessor, 
+            IUserDataManager userDataManager, 
+            ILocalizationManager localization, 
+            IMediaSourceManager mediaSourceManager, 
+            ISsdpHandler ssdpHandler)
         {
             _config = config;
             _appHost = appHost;
@@ -57,6 +70,7 @@ namespace MediaBrowser.Dlna.Main
             _userDataManager = userDataManager;
             _localization = localization;
             _mediaSourceManager = mediaSourceManager;
+            _ssdpHandler = (SsdpHandler)ssdpHandler;
             _logger = logManager.GetLogger("Dlna");
         }
 
@@ -109,8 +123,6 @@ namespace MediaBrowser.Dlna.Main
         {
             try
             {
-                _ssdpHandler = new SsdpHandler(_logger, _config, GenerateServerSignature());
-
                 _ssdpHandler.Start();
 
                 _deviceDiscovery = new DeviceDiscovery(_logger, _config, _ssdpHandler, _appHost);
@@ -123,7 +135,7 @@ namespace MediaBrowser.Dlna.Main
             }
         }
 
-        private void DisposeSsdpHandler()
+        private void DisposeDeviceDiscovery()
         {
             try
             {
@@ -133,15 +145,6 @@ namespace MediaBrowser.Dlna.Main
             {
                 _logger.ErrorException("Error disposing device discovery", ex);
             }
-
-            try
-            {
-                _ssdpHandler.Dispose();
-            }
-            catch (Exception ex)
-            {
-                _logger.ErrorException("Error disposing ssdp handler", ex);
-            }
         }
 
         public void StartDlnaServer()
@@ -184,29 +187,6 @@ namespace MediaBrowser.Dlna.Main
             }
         }
 
-        private string GenerateServerSignature()
-        {
-            var os = Environment.OSVersion;
-            var pstring = os.Platform.ToString();
-            switch (os.Platform)
-            {
-                case PlatformID.Win32NT:
-                case PlatformID.Win32S:
-                case PlatformID.Win32Windows:
-                    pstring = "WIN";
-                    break;
-            }
-
-            return String.Format(
-              "{0}{1}/{2}.{3} UPnP/1.0 DLNADOC/1.5 MediaBrowser/{4}",
-              pstring,
-              IntPtr.Size * 8,
-              os.Version.Major,
-              os.Version.Minor,
-              _appHost.ApplicationVersion
-              );
-        }
-
         private readonly object _syncLock = new object();
         private void StartPlayToManager()
         {
@@ -260,7 +240,7 @@ namespace MediaBrowser.Dlna.Main
         {
             DisposeDlnaServer();
             DisposePlayToManager();
-            DisposeSsdpHandler();
+            DisposeDeviceDiscovery();
         }
 
         public void DisposeDlnaServer()

+ 6 - 1
MediaBrowser.Dlna/MediaBrowser.Dlna.csproj

@@ -77,10 +77,12 @@
     <Compile Include="Common\DeviceService.cs" />
     <Compile Include="Didl\DidlBuilder.cs" />
     <Compile Include="PlayTo\PlayToController.cs" />
+    <Compile Include="Profiles\BubbleUpnpProfile.cs" />
     <Compile Include="Profiles\DefaultProfile.cs" />
     <Compile Include="Profiles\DirectTvProfile.cs" />
     <Compile Include="Profiles\DishHopperJoeyProfile.cs" />
     <Compile Include="Profiles\PopcornHourProfile.cs" />
+    <Compile Include="Profiles\VlcProfile.cs" />
     <Compile Include="Ssdp\DeviceDiscoveryInfo.cs" />
     <Compile Include="Ssdp\Extensions.cs" />
     <Compile Include="PlayTo\PlaybackProgressEventArgs.cs" />
@@ -135,7 +137,6 @@
     <Compile Include="Server\Headers.cs" />
     <Compile Include="Server\UpnpDevice.cs" />
     <Compile Include="Ssdp\SsdpMessageBuilder.cs" />
-    <Compile Include="Ssdp\SsdpMessageEventArgs.cs" />
     <Compile Include="Ssdp\SsdpHandler.cs" />
   </ItemGroup>
   <ItemGroup>
@@ -205,6 +206,10 @@
     <EmbeddedResource Include="Images\people480.jpg" />
     <EmbeddedResource Include="Images\people480.png" />
   </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Profiles\Xml\BubbleUPnp.xml" />
+    <EmbeddedResource Include="Profiles\Xml\Vlc.xml" />
+  </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.

+ 8 - 8
MediaBrowser.Dlna/PlayTo/Device.cs

@@ -296,7 +296,7 @@ namespace MediaBrowser.Dlna.PlayTo
             }
 
             var post = AvCommands.BuildPost(command, service.ServiceType, url, dictionary);
-            await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header)
+            await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header)
                 .ConfigureAwait(false);
 
             await Task.Delay(50).ConfigureAwait(false);
@@ -463,10 +463,10 @@ namespace MediaBrowser.Dlna.PlayTo
 
             if (service == null)
             {
-                throw new InvalidOperationException("Unable to find service");
+                return;
             }
 
-            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
+            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType), true)
                 .ConfigureAwait(false);
 
             if (result == null || result.Document == null)
@@ -496,10 +496,10 @@ namespace MediaBrowser.Dlna.PlayTo
 
             if (service == null)
             {
-                throw new InvalidOperationException("Unable to find service");
+                return;
             }
 
-            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
+            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType), true)
                 .ConfigureAwait(false);
 
             if (result == null || result.Document == null)
@@ -521,7 +521,7 @@ namespace MediaBrowser.Dlna.PlayTo
             if (service == null)
                 return null;
 
-            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType))
+            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, AvCommands.BuildPost(command, service.ServiceType), false)
                 .ConfigureAwait(false);
 
             if (result == null || result.Document == null)
@@ -558,7 +558,7 @@ namespace MediaBrowser.Dlna.PlayTo
                 throw new InvalidOperationException("Unable to find service");
             }
 
-            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
+            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType), false)
                 .ConfigureAwait(false);
 
             if (result == null || result.Document == null)
@@ -589,7 +589,7 @@ namespace MediaBrowser.Dlna.PlayTo
                 throw new InvalidOperationException("Unable to find service");
             }
 
-            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType))
+            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, RendererCommands.BuildPost(command, service.ServiceType), false)
                 .ConfigureAwait(false);
 
             if (result == null || result.Document == null)

+ 4 - 3
MediaBrowser.Dlna/PlayTo/PlayToController.cs

@@ -509,8 +509,6 @@ namespace MediaBrowser.Dlna.PlayTo
                     streamInfo.TargetHeight,
                     streamInfo.TargetVideoBitDepth,
                     streamInfo.TargetVideoBitrate,
-                    streamInfo.TargetAudioChannels,
-                    streamInfo.TargetAudioBitrate,
                     streamInfo.TargetTimestamp,
                     streamInfo.IsDirectStream,
                     streamInfo.RunTimeTicks,
@@ -770,8 +768,11 @@ namespace MediaBrowser.Dlna.PlayTo
 
                     await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl).ConfigureAwait(false);
 
-                    if (newItem.StreamInfo.IsDirectStream)
+                    if (newItem.StreamInfo.IsDirectStream && newPosition > 0)
                     {
+                        // This is rather arbitrary, but give the player time to start playing
+                        await Task.Delay(2000).ConfigureAwait(false);
+
                         await _device.Seek(TimeSpan.FromTicks(newPosition)).ConfigureAwait(false);
                     }
                 }

+ 82 - 49
MediaBrowser.Dlna/PlayTo/PlayToManager.cs

@@ -13,6 +13,7 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Net;
+using System.Threading;
 
 namespace MediaBrowser.Dlna.PlayTo
 {
@@ -34,6 +35,9 @@ namespace MediaBrowser.Dlna.PlayTo
         private readonly DeviceDiscovery _deviceDiscovery;
         private readonly IMediaSourceManager _mediaSourceManager;
 
+        private readonly List<string> _nonRendererUrls = new List<string>();
+        private Timer _clearNonRenderersTimer;
+
         public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, DeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager)
         {
             _logger = logger;
@@ -53,9 +57,19 @@ namespace MediaBrowser.Dlna.PlayTo
 
         public void Start()
         {
+            _clearNonRenderersTimer = new Timer(OnClearUrlTimerCallback, null, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(10));
+
             _deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;
         }
 
+        private void OnClearUrlTimerCallback(object state)
+        {
+            lock (_nonRendererUrls)
+            {
+                _nonRendererUrls.Clear();
+            }
+        }
+
         async void _deviceDiscovery_DeviceDiscovered(object sender, SsdpMessageEventArgs e)
         {
             var localIp = e.LocalIp;
@@ -68,7 +82,7 @@ namespace MediaBrowser.Dlna.PlayTo
 
             string location;
             if (!e.Headers.TryGetValue("Location", out location)) location = string.Empty;
-            
+
             // It has to report that it's a media renderer
             if (usn.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1 &&
                      nt.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1)
@@ -85,61 +99,74 @@ namespace MediaBrowser.Dlna.PlayTo
             {
                 var uri = new Uri(location);
 
-                // TODO: Cache list of non-renderers by url to avoid repeating calls
+                lock (_nonRendererUrls)
+                {
+                    if (_nonRendererUrls.Contains(location, StringComparer.OrdinalIgnoreCase))
+                    {
+                        return;
+                    }
+                }
+
                 var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger).ConfigureAwait(false);
 
-                if (device.RendererCommands != null)
+                if (device.RendererCommands == null)
                 {
-                    var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, _appHost.ApplicationVersion.ToString(), device.Properties.UUID, device.Properties.Name, uri.OriginalString, null)
-                        .ConfigureAwait(false);
+                    lock (_nonRendererUrls)
+                    {
+                        _nonRendererUrls.Add(location);
+                        return;
+                    }
+                }
+
+                var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, _appHost.ApplicationVersion.ToString(), device.Properties.UUID, device.Properties.Name, uri.OriginalString, null)
+                    .ConfigureAwait(false);
 
-                    var controller = sessionInfo.SessionController as PlayToController;
+                var controller = sessionInfo.SessionController as PlayToController;
 
-                    if (controller == null)
+                if (controller == null)
+                {
+                    var serverAddress = GetServerAddress(localIp);
+                    string accessToken = null;
+
+                    sessionInfo.SessionController = controller = new PlayToController(sessionInfo,
+                        _sessionManager,
+                        _libraryManager,
+                        _logger,
+                        _dlnaManager,
+                        _userManager,
+                        _imageProcessor,
+                        serverAddress,
+                        accessToken,
+                        _deviceDiscovery,
+                        _userDataManager,
+                        _localization,
+                        _mediaSourceManager);
+
+                    controller.Init(device);
+
+                    var profile = _dlnaManager.GetProfile(device.Properties.ToDeviceIdentification()) ??
+                                  _dlnaManager.GetDefaultProfile();
+
+                    _sessionManager.ReportCapabilities(sessionInfo.Id, new ClientCapabilities
                     {
-                        var serverAddress = GetServerAddress(localIp);
-                        string accessToken = null;
-
-                        sessionInfo.SessionController = controller = new PlayToController(sessionInfo,
-                            _sessionManager,
-                            _libraryManager,
-                            _logger,
-                            _dlnaManager,
-                            _userManager,
-                            _imageProcessor,
-                            serverAddress,
-                            accessToken,
-                            _deviceDiscovery,
-                            _userDataManager,
-                            _localization,
-                            _mediaSourceManager);
-
-                        controller.Init(device);
-                        
-                        var profile = _dlnaManager.GetProfile(device.Properties.ToDeviceIdentification()) ??
-                                      _dlnaManager.GetDefaultProfile();
-
-                        _sessionManager.ReportCapabilities(sessionInfo.Id, new ClientCapabilities
+                        PlayableMediaTypes = profile.GetSupportedMediaTypes(),
+
+                        SupportedCommands = new List<string>
                         {
-                            PlayableMediaTypes = profile.GetSupportedMediaTypes(),
-
-                            SupportedCommands = new List<string>
-                            {
-                                GeneralCommandType.VolumeDown.ToString(),
-                                GeneralCommandType.VolumeUp.ToString(),
-                                GeneralCommandType.Mute.ToString(),
-                                GeneralCommandType.Unmute.ToString(),
-                                GeneralCommandType.ToggleMute.ToString(),
-                                GeneralCommandType.SetVolume.ToString(),
-                                GeneralCommandType.SetAudioStreamIndex.ToString(),
-                                GeneralCommandType.SetSubtitleStreamIndex.ToString()
-                            },
-
-                            SupportsMediaControl = true
-                        });
-
-                        _logger.Info("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName);
-                    }
+                            GeneralCommandType.VolumeDown.ToString(),
+                            GeneralCommandType.VolumeUp.ToString(),
+                            GeneralCommandType.Mute.ToString(),
+                            GeneralCommandType.Unmute.ToString(),
+                            GeneralCommandType.ToggleMute.ToString(),
+                            GeneralCommandType.SetVolume.ToString(),
+                            GeneralCommandType.SetAudioStreamIndex.ToString(),
+                            GeneralCommandType.SetSubtitleStreamIndex.ToString()
+                        },
+
+                        SupportsMediaControl = true
+                    });
+
+                    _logger.Info("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName);
                 }
             }
             catch (Exception ex)
@@ -156,6 +183,12 @@ namespace MediaBrowser.Dlna.PlayTo
         public void Dispose()
         {
             _deviceDiscovery.DeviceDiscovered -= _deviceDiscovery_DeviceDiscovered;
+
+            if (_clearNonRenderersTimer != null)
+            {
+                _clearNonRenderersTimer.Dispose();
+                _clearNonRenderersTimer = null;
+            }
         }
     }
 }

+ 8 - 8
MediaBrowser.Dlna/PlayTo/SsdpHttpClient.cs

@@ -1,7 +1,7 @@
-using System;
-using MediaBrowser.Common.Net;
+using MediaBrowser.Common.Net;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Dlna.Common;
+using System;
 using System.Globalization;
 using System.IO;
 using System.Text;
@@ -13,7 +13,7 @@ namespace MediaBrowser.Dlna.PlayTo
     public class SsdpHttpClient
     {
         private const string USERAGENT = "Microsoft-Windows/6.2 UPnP/1.0 Microsoft-DLNA DLNADOC/1.50";
-        private const string FriendlyName = "MediaBrowser";
+        private const string FriendlyName = "Emby";
 
         private readonly IHttpClient _httpClient;
         private readonly IServerConfigurationManager _config;
@@ -28,9 +28,10 @@ namespace MediaBrowser.Dlna.PlayTo
             DeviceService service, 
             string command, 
             string postData, 
+            bool logRequest = true,
             string header = null)
         {
-            var response = await PostSoapDataAsync(NormalizeServiceUrl(baseUrl, service.ControlUrl), "\"" + service.ServiceType + "#" + command + "\"", postData, header)
+            var response = await PostSoapDataAsync(NormalizeServiceUrl(baseUrl, service.ControlUrl), "\"" + service.ServiceType + "#" + command + "\"", postData, header, logRequest)
                 .ConfigureAwait(false);
 
             using (var stream = response.Content)
@@ -69,7 +70,6 @@ namespace MediaBrowser.Dlna.PlayTo
             {
                 Url = url,
                 UserAgent = USERAGENT,
-                LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
                 LogErrorResponseBody = true
             };
 
@@ -87,7 +87,6 @@ namespace MediaBrowser.Dlna.PlayTo
             {
                 Url = url,
                 UserAgent = USERAGENT,
-                LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
                 LogErrorResponseBody = true
             };
 
@@ -105,7 +104,8 @@ namespace MediaBrowser.Dlna.PlayTo
         private Task<HttpResponseInfo> PostSoapDataAsync(string url, 
             string soapAction, 
             string postData, 
-            string header = null)
+            string header,
+            bool logRequest)
         {
             if (!soapAction.StartsWith("\""))
                 soapAction = "\"" + soapAction + "\"";
@@ -114,7 +114,7 @@ namespace MediaBrowser.Dlna.PlayTo
             {
                 Url = url,
                 UserAgent = USERAGENT,
-                LogRequest = _config.GetDlnaConfiguration().EnableDebugLogging,
+                LogRequest = logRequest || _config.GetDlnaConfiguration().EnableDebugLogging,
                 LogErrorResponseBody = true
             };
 

+ 76 - 0
MediaBrowser.Dlna/Profiles/BubbleUpnpProfile.cs

@@ -0,0 +1,76 @@
+using System.Xml.Serialization;
+using MediaBrowser.Model.Dlna;
+
+namespace MediaBrowser.Dlna.Profiles
+{
+    [XmlRoot("Profile")]
+    public class BubbleUpnpProfile : DefaultProfile
+    {
+        public BubbleUpnpProfile()
+        {
+            Name = "BubbleUPnp";
+
+            TimelineOffsetSeconds = 5;
+
+            Identification = new DeviceIdentification
+            {
+                ModelName = "BubbleUPnp",
+
+                Headers = new[]
+                {
+                    new HttpHeaderInfo {Name = "User-Agent", Value = "BubbleUPnp", Match = HeaderMatchType.Substring}
+                }
+            };
+
+            TranscodingProfiles = new[]
+            {
+                new TranscodingProfile
+                {
+                    Container = "mp3",
+                    Type = DlnaProfileType.Audio,
+                    AudioCodec = "mp3"
+                },
+                new TranscodingProfile
+                {
+                    Container = "ts",
+                    Type = DlnaProfileType.Video,
+                    VideoCodec = "h264",
+                    AudioCodec = "aac"
+                },
+                new TranscodingProfile
+                {
+                    Container = "jpeg",
+                    Type = DlnaProfileType.Photo
+                }
+            };
+
+            DirectPlayProfiles = new[]
+            {
+                new DirectPlayProfile
+                {
+                    Container = "avi,mpeg,mkv,ts,mp4,mov,m4v,asf,webm,ogg,ogv,iso",
+                    Type = DlnaProfileType.Video
+                },
+
+                new DirectPlayProfile
+                {
+                    Container = "mp3,flac,asf,off,oga,aac",
+                    Type = DlnaProfileType.Audio
+                },
+
+                new DirectPlayProfile
+                {
+                    Type = DlnaProfileType.Photo,
+
+                    Container = "jpeg,png,gif,bmp,tiff"
+                }
+            };
+
+            ResponseProfiles = new ResponseProfile[] { };
+
+            ContainerProfiles = new ContainerProfile[] { };
+
+            CodecProfiles = new CodecProfile[] { };
+        }
+    }
+}

+ 18 - 0
MediaBrowser.Dlna/Profiles/DefaultProfile.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Model.Dlna;
+using System.Linq;
 using System.Xml.Serialization;
 
 namespace MediaBrowser.Dlna.Profiles
@@ -75,6 +76,23 @@ namespace MediaBrowser.Dlna.Profiles
                     Type = DlnaProfileType.Video
                 }
             };
+
+            AddXmlRootAttribute("xmlns", "urn:schemas-upnp-org:device-1-0");
+            AddXmlRootAttribute("xmlns:dlna", "urn:schemas-dlna-org:device-1-0");
+        }
+
+        public void AddXmlRootAttribute(string name, string value)
+        {
+            var atts = XmlRootAttributes ?? new XmlAttribute[] { };
+            var list = atts.ToList();
+
+            list.Add(new XmlAttribute
+            {
+                Name = name,
+                Value = value
+            });
+
+            XmlRootAttributes = list.ToArray();
         }
     }
 }

+ 1 - 8
MediaBrowser.Dlna/Profiles/PanasonicVieraProfile.cs

@@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
                }
             };
 
-            XmlRootAttributes = new[]
-            {
-                new XmlAttribute
-                {
-                    Name = "xmlns:pv",
-                    Value = "http://www.pv.com/pvns/"
-                }
-            };
+            AddXmlRootAttribute("xmlns:pv", "http://www.pv.com/pvns/");
 
             TimelineOffsetSeconds = 10;
 

+ 1 - 8
MediaBrowser.Dlna/Profiles/SamsungSmartTvProfile.cs

@@ -27,14 +27,7 @@ namespace MediaBrowser.Dlna.Profiles
                 }
             };
 
-            XmlRootAttributes = new[]
-            {
-                new XmlAttribute
-                {
-                    Name = "xmlns:sec",
-                    Value = "http://www.sec.co.kr/"
-                }
-            };
+            AddXmlRootAttribute("xmlns:sec", "http://www.sec.co.kr/");
 
             TranscodingProfiles = new[]
            {

+ 1 - 8
MediaBrowser.Dlna/Profiles/SonyBlurayPlayer2013Profile.cs

@@ -17,14 +17,7 @@ namespace MediaBrowser.Dlna.Profiles
                 ModelNumber = "BDP-2013"
             };
 
-            XmlRootAttributes = new[]
-            {
-                new XmlAttribute
-                {
-                    Name = "xmlns:av",
-                    Value = "urn:schemas-sony-com:av"
-                }
-            };
+            AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
 
             ModelName = "Windows Media Player Sharing";
             ModelNumber = "3.0";

+ 1 - 8
MediaBrowser.Dlna/Profiles/SonyBlurayPlayerProfile.cs

@@ -33,14 +33,7 @@ namespace MediaBrowser.Dlna.Profiles
                 }
             };
 
-            XmlRootAttributes = new[]
-            {
-                new XmlAttribute
-                {
-                    Name = "xmlns:av",
-                    Value = "urn:schemas-sony-com:av"
-                }
-            };
+            AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
 
             ModelName = "Windows Media Player Sharing";
             ModelNumber = "3.0";

+ 8 - 8
MediaBrowser.Dlna/Profiles/SonyBravia2010Profile.cs

@@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
                 }
             };
 
-            XmlRootAttributes = new[]
-            {
-                new XmlAttribute
-                {
-                    Name = "xmlns:av",
-                    Value = "urn:schemas-sony-com:av"
-                }
-            };
+            AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
 
             AlbumArtPn = "JPEG_TN";
 
@@ -47,6 +40,7 @@ namespace MediaBrowser.Dlna.Profiles
                 "http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=81500000000000000000000000000000,http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_SM;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=00D00000000000000000000000000000,http-get:*:video/mpeg:DLNA.ORG_PN=MPEG_PS_PAL;DLNA.ORG_OP=11;DLNA.ORG_FLAGS=81500000000000000000000000000000";
 
             EnableSingleAlbumArtLimit = true;
+            EnableAlbumArtInDidl = true;
             
             TranscodingProfiles = new[]
             {
@@ -293,6 +287,12 @@ namespace MediaBrowser.Dlna.Profiles
                             Condition = ProfileConditionType.LessThanEqual,
                             Property = ProfileConditionValue.Height,
                             Value = "1080"
+                        },
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.VideoFramerate,
+                            Value = "30"
                         }
                     }
                 },

+ 8 - 8
MediaBrowser.Dlna/Profiles/SonyBravia2011Profile.cs

@@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
                 }
             };
 
-            XmlRootAttributes = new[]
-            {
-                new XmlAttribute
-                {
-                    Name = "xmlns:av",
-                    Value = "urn:schemas-sony-com:av"
-                }
-            };
+            AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
 
             AlbumArtPn = "JPEG_TN";
 
@@ -44,6 +37,7 @@ namespace MediaBrowser.Dlna.Profiles
             ManufacturerUrl = "http://www.microsoft.com/";
             SonyAggregationFlags = "10";
             EnableSingleAlbumArtLimit = true;
+            EnableAlbumArtInDidl = true;
 
             TranscodingProfiles = new[]
             {
@@ -310,6 +304,12 @@ namespace MediaBrowser.Dlna.Profiles
                             Condition = ProfileConditionType.LessThanEqual,
                             Property = ProfileConditionValue.Height,
                             Value = "1080"
+                        },
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.VideoFramerate,
+                            Value = "30"
                         }
                     }
                 },

+ 8 - 8
MediaBrowser.Dlna/Profiles/SonyBravia2012Profile.cs

@@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
                 }
             };
 
-            XmlRootAttributes = new[]
-            {
-                new XmlAttribute
-                {
-                    Name = "xmlns:av",
-                    Value = "urn:schemas-sony-com:av"
-                }
-            };
+            AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
 
             AlbumArtPn = "JPEG_TN";
 
@@ -44,6 +37,7 @@ namespace MediaBrowser.Dlna.Profiles
             ManufacturerUrl = "http://www.microsoft.com/";
             SonyAggregationFlags = "10";
             EnableSingleAlbumArtLimit = true;
+            EnableAlbumArtInDidl = true;
 
             TranscodingProfiles = new[]
             {
@@ -250,6 +244,12 @@ namespace MediaBrowser.Dlna.Profiles
                             Condition = ProfileConditionType.LessThanEqual,
                             Property = ProfileConditionValue.Height,
                             Value = "1080"
+                        },
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.VideoFramerate,
+                            Value = "30"
                         }
                     }
                 },

+ 8 - 8
MediaBrowser.Dlna/Profiles/SonyBravia2013Profile.cs

@@ -26,14 +26,7 @@ namespace MediaBrowser.Dlna.Profiles
                 }
             };
 
-            XmlRootAttributes = new[]
-            {
-                new XmlAttribute
-                {
-                    Name = "xmlns:av",
-                    Value = "urn:schemas-sony-com:av"
-                }
-            };
+            AddXmlRootAttribute("xmlns:av", "urn:schemas-sony-com:av");
 
             AlbumArtPn = "JPEG_TN";
 
@@ -44,6 +37,7 @@ namespace MediaBrowser.Dlna.Profiles
             ManufacturerUrl = "http://www.microsoft.com/";
             SonyAggregationFlags = "10";
             EnableSingleAlbumArtLimit = true;
+            EnableAlbumArtInDidl = true;
 
             TranscodingProfiles = new[]
             {
@@ -284,6 +278,12 @@ namespace MediaBrowser.Dlna.Profiles
                             Condition = ProfileConditionType.LessThanEqual,
                             Property = ProfileConditionValue.Height,
                             Value = "1080"
+                        },
+                        new ProfileCondition
+                        {
+                            Condition = ProfileConditionType.LessThanEqual,
+                            Property = ProfileConditionValue.VideoFramerate,
+                            Value = "30"
                         }
                     }
                 }

+ 76 - 0
MediaBrowser.Dlna/Profiles/VlcProfile.cs

@@ -0,0 +1,76 @@
+using System.Xml.Serialization;
+using MediaBrowser.Model.Dlna;
+
+namespace MediaBrowser.Dlna.Profiles
+{
+    [XmlRoot("Profile")]
+    public class VlcProfile : DefaultProfile
+    {
+        public VlcProfile()
+        {
+            Name = "Vlc";
+
+            TimelineOffsetSeconds = 5;
+
+            Identification = new DeviceIdentification
+            {
+                ModelName = "Vlc",
+
+                Headers = new[]
+                {
+                    new HttpHeaderInfo {Name = "User-Agent", Value = "vlc", Match = HeaderMatchType.Substring}
+                }
+            };
+
+            TranscodingProfiles = new[]
+            {
+                new TranscodingProfile
+                {
+                    Container = "mp3",
+                    Type = DlnaProfileType.Audio,
+                    AudioCodec = "mp3"
+                },
+                new TranscodingProfile
+                {
+                    Container = "ts",
+                    Type = DlnaProfileType.Video,
+                    VideoCodec = "h264",
+                    AudioCodec = "aac"
+                },
+                new TranscodingProfile
+                {
+                    Container = "jpeg",
+                    Type = DlnaProfileType.Photo
+                }
+            };
+
+            DirectPlayProfiles = new[]
+            {
+                new DirectPlayProfile
+                {
+                    Container = "avi,mpeg,mkv,ts,mp4,mov,m4v,asf,webm,ogg,ogv,iso",
+                    Type = DlnaProfileType.Video
+                },
+
+                new DirectPlayProfile
+                {
+                    Container = "mp3,flac,asf,off,oga,aac",
+                    Type = DlnaProfileType.Audio
+                },
+
+                new DirectPlayProfile
+                {
+                    Type = DlnaProfileType.Photo,
+
+                    Container = "jpeg,png,gif,bmp,tiff"
+                }
+            };
+
+            ResponseProfiles = new ResponseProfile[] { };
+
+            ContainerProfiles = new ContainerProfile[] { };
+
+            CodecProfiles = new CodecProfile[] { };
+        }
+    }
+}

+ 0 - 1
MediaBrowser.Dlna/Profiles/WdtvLiveProfile.cs

@@ -11,7 +11,6 @@ namespace MediaBrowser.Dlna.Profiles
             Name = "WDTV Live";
 
             TimelineOffsetSeconds = 5;
-            IgnoreTranscodeByteRangeRequests = true;
 
             Identification = new DeviceIdentification
             {

+ 7 - 3
MediaBrowser.Dlna/Profiles/Xbox360Profile.cs

@@ -18,12 +18,13 @@ namespace MediaBrowser.Dlna.Profiles
 
             ModelNumber = "12.0";
 
-            FriendlyName = "${HostName} : 1";
+            FriendlyName = "${HostName}: Emby:";
 
-            ModelUrl = "http://www.microsoft.com/";
+            ModelUrl = "http://go.microsoft.com/fwlink/?LinkId=105926";
             Manufacturer = "Microsoft Corporation";
-            ManufacturerUrl = "http://www.microsoft.com/";
+            ManufacturerUrl = "http://www.microsoft.com";
             XDlnaDoc = "DMS-1.50";
+            ModelDescription = null;
 
             TimelineOffsetSeconds = 40;
             RequiresPlainFolders = true;
@@ -311,6 +312,9 @@ namespace MediaBrowser.Dlna.Profiles
                     }
                 }
             };
+
+            XmlRootAttributes = new XmlAttribute[] { };
+            AddXmlRootAttribute("xmlns", "urn:schemas-upnp-org:device-1-0");
         }
     }
 }

+ 1 - 1
MediaBrowser.Dlna/Profiles/XboxOneProfile.cs

@@ -14,7 +14,7 @@ namespace MediaBrowser.Dlna.Profiles
 
             Identification = new DeviceIdentification
             {
-                FriendlyName = "XboxOne",
+                ModelName = "Xbox One",
 
                 Headers = new[]
                 {

File diff suppressed because it is too large
+ 29 - 0
MediaBrowser.Dlna/Profiles/Xml/BubbleUPnp.xml


+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Default.xml

@@ -8,7 +8,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -27,7 +26,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
     <DirectPlayProfile container="mp3,wma" type="Audio" />
     <DirectPlayProfile container="avi,mp4" type="Video" />

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Denon AVR.xml

@@ -13,7 +13,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -32,7 +31,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
     <DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
   </DirectPlayProfiles>

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/DirecTV HD-DVR.xml

@@ -14,7 +14,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -33,7 +32,10 @@
   <RequiresPlainVideoItems>true</RequiresPlainVideoItems>
   <RequiresPlainFolders>true</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
     <DirectPlayProfile container="mpeg" audioCodec="mp2" videoCodec="mpeg2video" type="Video" />
     <DirectPlayProfile container="jpeg,jpg" type="Photo" />

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Dish Hopper-Joey.xml

@@ -15,7 +15,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -34,7 +33,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
     <DirectPlayProfile container="mp4,mkv,mpeg,ts" audioCodec="mp3,ac3,aac,he-aac,pcm" videoCodec="h264,mpeg2video" type="Video" />
     <DirectPlayProfile container="mp3" audioCodec="mp3" type="Audio" />

File diff suppressed because it is too large
+ 23 - 0
MediaBrowser.Dlna/Profiles/Xml/Generic Device.xml


+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/LG Smart TV.xml

@@ -14,7 +14,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -33,7 +32,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
     <DirectPlayProfile container="ts" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />
     <DirectPlayProfile container="mkv" audioCodec="aac,ac3,mp3" videoCodec="h264" type="Video" />

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Linksys DMA2100.xml

@@ -12,7 +12,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -31,7 +30,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
     <DirectPlayProfile container="mp3,flac,m4a,wma" type="Audio" />
     <DirectPlayProfile container="avi,mp4,mkv,ts" type="Video" />

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/MediaMonkey.xml

@@ -14,7 +14,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio</SupportedMediaTypes>
@@ -33,7 +32,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
     <DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
     <DirectPlayProfile container="mp4" audioCodec="mp4" type="Audio" />

+ 2 - 1
MediaBrowser.Dlna/Profiles/Xml/Panasonic Viera.xml

@@ -15,7 +15,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -35,6 +34,8 @@
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
     <XmlAttribute name="xmlns:pv" value="http://www.pv.com/pvns/" />
   </XmlRootAttributes>
   <DirectPlayProfiles>

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Popcorn Hour.xml

@@ -8,7 +8,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -27,7 +26,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
     <DirectPlayProfile container="mp4,mov" audioCodec="aac" videoCodec="h264,mpeg4" type="Video" />
     <DirectPlayProfile container="ts" audioCodec="aac,ac3,eac3,mp3,mp2,pcm" videoCodec="h264" type="Video" />

+ 2 - 1
MediaBrowser.Dlna/Profiles/Xml/Samsung Smart TV.xml

@@ -14,7 +14,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -34,6 +33,8 @@
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
     <XmlAttribute name="xmlns:sec" value="http://www.sec.co.kr/" />
   </XmlRootAttributes>
   <DirectPlayProfiles>

+ 2 - 1
MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player 2013.xml

@@ -14,7 +14,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>3.0</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -34,6 +33,8 @@
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
   </XmlRootAttributes>
   <DirectPlayProfiles>

+ 2 - 1
MediaBrowser.Dlna/Profiles/Xml/Sony Blu-ray Player.xml

@@ -16,7 +16,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>3.0</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -36,6 +35,8 @@
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
   </XmlRootAttributes>
   <DirectPlayProfiles>

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2010).xml

@@ -15,8 +15,7 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>3.0</ModelNumber>
   <ModelUrl>http://www.microsoft.com/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
-  <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+  <EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <AlbumArtPn>JPEG_TN</AlbumArtPn>
@@ -36,6 +35,8 @@
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
   </XmlRootAttributes>
   <DirectPlayProfiles>
@@ -79,6 +80,7 @@
       <Conditions>
         <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
         <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+        <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
       </Conditions>
     </CodecProfile>
     <CodecProfile type="VideoAudio" codec="ac3">

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2011).xml

@@ -15,8 +15,7 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>3.0</ModelNumber>
   <ModelUrl>http://www.microsoft.com/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
-  <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+  <EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <AlbumArtPn>JPEG_TN</AlbumArtPn>
@@ -36,6 +35,8 @@
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
   </XmlRootAttributes>
   <DirectPlayProfiles>
@@ -82,6 +83,7 @@
       <Conditions>
         <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
         <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+        <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
       </Conditions>
     </CodecProfile>
     <CodecProfile type="VideoAudio" codec="ac3">

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2012).xml

@@ -15,8 +15,7 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>3.0</ModelNumber>
   <ModelUrl>http://www.microsoft.com/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
-  <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+  <EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <AlbumArtPn>JPEG_TN</AlbumArtPn>
@@ -36,6 +35,8 @@
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
   </XmlRootAttributes>
   <DirectPlayProfiles>
@@ -67,6 +68,7 @@
       <Conditions>
         <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
         <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+        <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
       </Conditions>
     </CodecProfile>
     <CodecProfile type="VideoAudio" codec="ac3">

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Sony Bravia (2013).xml

@@ -15,8 +15,7 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>3.0</ModelNumber>
   <ModelUrl>http://www.microsoft.com/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
-  <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
+  <EnableAlbumArtInDidl>true</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
   <AlbumArtPn>JPEG_TN</AlbumArtPn>
@@ -36,6 +35,8 @@
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
   <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
     <XmlAttribute name="xmlns:av" value="urn:schemas-sony-com:av" />
   </XmlRootAttributes>
   <DirectPlayProfiles>
@@ -72,6 +73,7 @@
       <Conditions>
         <ProfileCondition condition="LessThanEqual" property="Width" value="1920" isRequired="true" />
         <ProfileCondition condition="LessThanEqual" property="Height" value="1080" isRequired="true" />
+        <ProfileCondition condition="LessThanEqual" property="VideoFramerate" value="30" isRequired="true" />
       </Conditions>
     </CodecProfile>
   </CodecProfiles>

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/Sony PlayStation 3.xml

@@ -15,7 +15,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>true</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -35,7 +34,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
     <DirectPlayProfile container="avi" audioCodec="mp2,mp3" videoCodec="mpeg4" type="Video" />
     <DirectPlayProfile container="ts" audioCodec="ac3,mp2,mp3,aac" videoCodec="mpeg1video,mpeg2video,h264" type="Video" />

File diff suppressed because it is too large
+ 29 - 0
MediaBrowser.Dlna/Profiles/Xml/Vlc.xml


+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/WDTV Live.xml

@@ -15,7 +15,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>true</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -34,7 +33,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
     <DirectPlayProfile container="avi" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video,mpeg4,h264,vc1" type="Video" />
     <DirectPlayProfile container="mpeg" audioCodec="ac3,dca,mp2,mp3,pcm" videoCodec="mpeg1video,mpeg2video" type="Video" />

+ 6 - 6
MediaBrowser.Dlna/Profiles/Xml/Xbox 360.xml

@@ -8,14 +8,12 @@
       <HttpHeaderInfo name="User-Agent" value="Xenon" match="Substring" />
     </Headers>
   </Identification>
-  <FriendlyName>${HostName} : 1</FriendlyName>
+  <FriendlyName>${HostName}: Emby:</FriendlyName>
   <Manufacturer>Microsoft Corporation</Manufacturer>
-  <ManufacturerUrl>http://www.microsoft.com/</ManufacturerUrl>
+  <ManufacturerUrl>http://www.microsoft.com</ManufacturerUrl>
   <ModelName>Windows Media Player Sharing</ModelName>
-  <ModelDescription>Emby</ModelDescription>
   <ModelNumber>12.0</ModelNumber>
-  <ModelUrl>http://www.microsoft.com/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
+  <ModelUrl>http://go.microsoft.com/fwlink/?LinkId=105926</ModelUrl>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -34,7 +32,9 @@
   <RequiresPlainVideoItems>true</RequiresPlainVideoItems>
   <RequiresPlainFolders>true</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>true</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
     <DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />
     <DirectPlayProfile container="avi" audioCodec="aac" videoCodec="h264" type="Video" />

+ 5 - 3
MediaBrowser.Dlna/Profiles/Xml/Xbox One.xml

@@ -2,7 +2,7 @@
 <Profile xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <Name>Xbox One</Name>
   <Identification>
-    <FriendlyName>XboxOne</FriendlyName>
+    <ModelName>Xbox One</ModelName>
     <Headers>
       <HttpHeaderInfo name="FriendlyName.DLNA.ORG" value="XboxOne" match="Substring" />
       <HttpHeaderInfo name="User-Agent" value="NSPlayer/12" match="Substring" />
@@ -15,7 +15,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio,Photo,Video</SupportedMediaTypes>
@@ -34,7 +33,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
     <DirectPlayProfile container="ts" audioCodec="ac3" videoCodec="h264" type="Video" />
     <DirectPlayProfile container="avi" audioCodec="ac3,mp3" videoCodec="mpeg4" type="Video" />

+ 4 - 2
MediaBrowser.Dlna/Profiles/Xml/foobar2000.xml

@@ -14,7 +14,6 @@
   <ModelDescription>Emby</ModelDescription>
   <ModelNumber>Emby</ModelNumber>
   <ModelUrl>http://emby.media/</ModelUrl>
-  <IgnoreTranscodeByteRangeRequests>false</IgnoreTranscodeByteRangeRequests>
   <EnableAlbumArtInDidl>false</EnableAlbumArtInDidl>
   <EnableSingleAlbumArtLimit>false</EnableSingleAlbumArtLimit>
   <SupportedMediaTypes>Audio</SupportedMediaTypes>
@@ -33,7 +32,10 @@
   <RequiresPlainVideoItems>false</RequiresPlainVideoItems>
   <RequiresPlainFolders>false</RequiresPlainFolders>
   <EnableMSMediaReceiverRegistrar>false</EnableMSMediaReceiverRegistrar>
-  <XmlRootAttributes />
+  <XmlRootAttributes>
+    <XmlAttribute name="xmlns" value="urn:schemas-upnp-org:device-1-0" />
+    <XmlAttribute name="xmlns:dlna" value="urn:schemas-dlna-org:device-1-0" />
+  </XmlRootAttributes>
   <DirectPlayProfiles>
     <DirectPlayProfile container="mp3" audioCodec="mp2,mp3" type="Audio" />
     <DirectPlayProfile container="mp4" audioCodec="mp4" type="Audio" />

+ 26 - 7
MediaBrowser.Dlna/Server/DescriptionXmlBuilder.cs

@@ -18,8 +18,9 @@ namespace MediaBrowser.Dlna.Server
         private readonly string _serverUdn;
         private readonly string _serverAddress;
         private readonly string _serverName;
+        private readonly string _serverId;
 
-        public DescriptionXmlBuilder(DeviceProfile profile, string serverUdn, string serverAddress, string serverName)
+        public DescriptionXmlBuilder(DeviceProfile profile, string serverUdn, string serverAddress, string serverName, string serverId)
         {
             if (string.IsNullOrWhiteSpace(serverUdn))
             {
@@ -35,6 +36,7 @@ namespace MediaBrowser.Dlna.Server
             _serverUdn = serverUdn;
             _serverAddress = serverAddress;
             _serverName = serverName;
+            _serverId = serverId;
         }
 
         private bool EnableAbsoluteUrls
@@ -48,7 +50,7 @@ namespace MediaBrowser.Dlna.Server
 
             builder.Append("<?xml version=\"1.0\"?>");
 
-            builder.Append("<root xmlns=\"urn:schemas-upnp-org:device-1-0\" xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\"");
+            builder.Append("<root");
             foreach (var att in _profile.XmlRootAttributes)
             {
                 builder.AppendFormat(" {0}=\"{1}\"", att.Name, att.Value);
@@ -72,7 +74,7 @@ namespace MediaBrowser.Dlna.Server
             builder.Append("<device>");
             AppendDeviceProperties(builder);
 
-            AppendIconList(builder);
+            //AppendIconList(builder);
             AppendServiceList(builder);
             builder.Append("</device>");
         }
@@ -80,20 +82,37 @@ namespace MediaBrowser.Dlna.Server
         private void AppendDeviceProperties(StringBuilder builder)
         {
             builder.Append("<UDN>uuid:" + SecurityElement.Escape(_serverUdn) + "</UDN>");
-            builder.Append("<dlna:X_DLNACAP>" + SecurityElement.Escape(_profile.XDlnaCap ?? string.Empty) + "</dlna:X_DLNACAP>");
+
+            if (!string.IsNullOrWhiteSpace(_profile.XDlnaCap))
+            {
+                builder.Append("<dlna:X_DLNACAP>" + SecurityElement.Escape(_profile.XDlnaCap ?? string.Empty) + "</dlna:X_DLNACAP>");
+            }
 
             builder.Append("<dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\">M-DMS-1.50</dlna:X_DLNADOC>");
             builder.Append("<dlna:X_DLNADOC xmlns:dlna=\"urn:schemas-dlna-org:device-1-0\">" + SecurityElement.Escape(_profile.XDlnaDoc ?? string.Empty) + "</dlna:X_DLNADOC>");
-
+            
             builder.Append("<friendlyName>" + SecurityElement.Escape(GetFriendlyName()) + "</friendlyName>");
             builder.Append("<deviceType>urn:schemas-upnp-org:device:MediaServer:1</deviceType>");
             builder.Append("<manufacturer>" + SecurityElement.Escape(_profile.Manufacturer ?? string.Empty) + "</manufacturer>");
             builder.Append("<manufacturerURL>" + SecurityElement.Escape(_profile.ManufacturerUrl ?? string.Empty) + "</manufacturerURL>");
             builder.Append("<modelName>" + SecurityElement.Escape(_profile.ModelName ?? string.Empty) + "</modelName>");
-            builder.Append("<modelDescription>" + SecurityElement.Escape(_profile.ModelDescription ?? string.Empty) + "</modelDescription>");
+
+            if (!string.IsNullOrWhiteSpace(_profile.ModelDescription))
+            {
+                builder.Append("<modelDescription>" + SecurityElement.Escape(_profile.ModelDescription ?? string.Empty) + "</modelDescription>");
+            }
+            
             builder.Append("<modelNumber>" + SecurityElement.Escape(_profile.ModelNumber ?? string.Empty) + "</modelNumber>");
             builder.Append("<modelURL>" + SecurityElement.Escape(_profile.ModelUrl ?? string.Empty) + "</modelURL>");
-            builder.Append("<serialNumber>" + SecurityElement.Escape(_profile.SerialNumber ?? string.Empty) + "</serialNumber>");
+
+            if (string.IsNullOrWhiteSpace(_profile.SerialNumber))
+            {
+                builder.Append("<serialNumber>" + SecurityElement.Escape(_serverId) + "</serialNumber>");
+            }
+            else
+            {
+                builder.Append("<serialNumber>" + SecurityElement.Escape(_profile.SerialNumber) + "</serialNumber>");
+            }
 
             builder.Append("<presentationURL>" + SecurityElement.Escape(_serverAddress) + "</presentationURL>");
 

+ 4 - 2
MediaBrowser.Dlna/Service/BaseControlHandler.cs

@@ -27,14 +27,16 @@ namespace MediaBrowser.Dlna.Service
         {
             try
             {
-                if (Config.GetDlnaConfiguration().EnableDebugLogging)
+                var enableDebugLogging = Config.GetDlnaConfiguration().EnableDebugLogging;
+
+                if (enableDebugLogging)
                 {
                     LogRequest(request);
                 }
 
                 var response = ProcessControlRequestInternal(request);
 
-                if (Config.GetDlnaConfiguration().EnableDebugLogging)
+                if (enableDebugLogging)
                 {
                     LogResponse(response);
                 }

+ 57 - 21
MediaBrowser.Dlna/Ssdp/Datagram.cs

@@ -12,13 +12,15 @@ namespace MediaBrowser.Dlna.Ssdp
         public EndPoint FromEndPoint { get; private set; }
         public string Message { get; private set; }
         public bool IgnoreBindFailure { get; private set; }
+        public bool EnableDebugLogging { get; private set; }
 
         private readonly ILogger _logger;
 
-        public Datagram(EndPoint toEndPoint, EndPoint fromEndPoint, ILogger logger, string message, bool ignoreBindFailure)
+        public Datagram(EndPoint toEndPoint, EndPoint fromEndPoint, ILogger logger, string message, bool ignoreBindFailure, bool enableDebugLogging)
         {
             Message = message;
             _logger = logger;
+            EnableDebugLogging = enableDebugLogging;
             IgnoreBindFailure = ignoreBindFailure;
             FromEndPoint = fromEndPoint;
             ToEndPoint = toEndPoint;
@@ -27,59 +29,93 @@ namespace MediaBrowser.Dlna.Ssdp
         public void Send()
         {
             var msg = Encoding.ASCII.GetBytes(Message);
-            try
+
+            var socket = CreateSocket();
+
+            if (socket == null)
             {
-                var client = CreateSocket();
+                return;
+            }
 
-                if (FromEndPoint != null)
+            if (FromEndPoint != null)
+            {
+                try
                 {
-                    try
+                    socket.Bind(FromEndPoint);
+                }
+                catch (Exception ex)
+                {
+                    if (EnableDebugLogging)
                     {
-                        client.Bind(FromEndPoint);
+                        _logger.ErrorException("Error binding datagram socket", ex);
                     }
-                    catch
+
+                    if (!IgnoreBindFailure)
                     {
-                        if (!IgnoreBindFailure) throw;
+                        CloseSocket(socket, false);
+
+                        return;
                     }
                 }
+            }
 
-                client.BeginSendTo(msg, 0, msg.Length, SocketFlags.None, ToEndPoint, result =>
+            try
+            {
+                socket.BeginSendTo(msg, 0, msg.Length, SocketFlags.None, ToEndPoint, result =>
                 {
                     try
                     {
-                        client.EndSend(result);
+                        socket.EndSend(result);
                     }
                     catch (Exception ex)
                     {
-                        if (!IgnoreBindFailure)
+                        if (!IgnoreBindFailure || EnableDebugLogging)
                         {
                             _logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
                         }
                     }
                     finally
                     {
-                        try
-                        {
-                            client.Close();
-                        }
-                        catch (Exception)
-                        {
-                        }
+                        CloseSocket(socket, true);
                     }
                 }, null);
             }
             catch (Exception ex)
             {
                 _logger.ErrorException("Error sending Datagram to {0} from {1}: " + Message, ex, ToEndPoint, FromEndPoint == null ? "" : FromEndPoint.ToString());
+                CloseSocket(socket, false);
+            }
+        }
+
+        private void CloseSocket(Socket socket, bool logError)
+        {
+            try
+            {
+                socket.Close();
+            }
+            catch (Exception ex)
+            {
+                if (logError && EnableDebugLogging)
+                {
+                    _logger.ErrorException("Error closing datagram socket", ex);
+                }
             }
         }
 
         private Socket CreateSocket()
         {
-            var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
+            try
+            {
+                var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
 
-            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
-            return socket;
+                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
+                return socket;
+            }
+            catch (Exception ex)
+            {
+                _logger.ErrorException("Error creating socket", ex);
+                return null;
+            }
         }
     }
 }

+ 18 - 9
MediaBrowser.Dlna/Ssdp/DeviceDiscovery.cs

@@ -1,7 +1,7 @@
 using MediaBrowser.Common.Events;
-using MediaBrowser.Common.Net;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Model.Logging;
 using System;
 using System.Collections.Generic;
@@ -142,7 +142,10 @@ namespace MediaBrowser.Dlna.Ssdp
                             args.EndPoint = endPoint;
                             args.LocalIp = localIp;
 
-                            TryCreateDevice(args);
+                            if (!_ssdpHandler.IsSelfNotification(args))
+                            {
+                                TryCreateDevice(args);
+                            }
                         }
                     }
 
@@ -183,7 +186,6 @@ namespace MediaBrowser.Dlna.Ssdp
                 }
 
             }, _tokenSource.Token, TaskCreationOptions.LongRunning);
-
         }
 
         private Socket GetMulticastSocket(IPAddress localIpAddress, EndPoint localEndpoint)
@@ -203,18 +205,25 @@ namespace MediaBrowser.Dlna.Ssdp
             string nts;
             args.Headers.TryGetValue("NTS", out nts);
 
+            if (String.Equals(nts, "ssdp:byebye", StringComparison.OrdinalIgnoreCase))
+            {
+                if (String.Equals(args.Method, "NOTIFY", StringComparison.OrdinalIgnoreCase))
+                {
+                    if (!_disposed)
+                    {
+                        EventHelper.FireEventIfNotNull(DeviceLeft, this, args, _logger);
+                    }
+                }
+
+                return;
+            }
+
             string usn;
             if (!args.Headers.TryGetValue("USN", out usn)) usn = string.Empty;
 
             string nt;
             if (!args.Headers.TryGetValue("NT", out nt)) nt = string.Empty;
 
-            // Ignore when a device is indicating it's shutting down
-            if (string.Equals(nts, "ssdp:byebye", StringComparison.OrdinalIgnoreCase))
-            {
-                return;
-            }
-
             // Need to be able to download device description
             string location;
             if (!args.Headers.TryGetValue("Location", out location) ||

+ 114 - 30
MediaBrowser.Dlna/Ssdp/SsdpHandler.cs

@@ -1,6 +1,8 @@
-using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common;
+using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Events;
 using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Dlna.Server;
 using MediaBrowser.Model.Logging;
 using System;
@@ -16,7 +18,7 @@ using System.Threading.Tasks;
 
 namespace MediaBrowser.Dlna.Ssdp
 {
-    public class SsdpHandler : IDisposable
+    public class SsdpHandler : IDisposable, ISsdpHandler
     {
         private Socket _socket;
 
@@ -39,13 +41,39 @@ namespace MediaBrowser.Dlna.Ssdp
         private bool _isDisposed;
         private readonly ConcurrentDictionary<Guid, List<UpnpDevice>> _devices = new ConcurrentDictionary<Guid, List<UpnpDevice>>();
 
-        public SsdpHandler(ILogger logger, IServerConfigurationManager config, string serverSignature)
+        private readonly IApplicationHost _appHost;
+
+        public SsdpHandler(ILogger logger, IServerConfigurationManager config, IApplicationHost appHost)
         {
             _logger = logger;
             _config = config;
-            _serverSignature = serverSignature;
+            _appHost = appHost;
 
             _config.NamedConfigurationUpdated += _config_ConfigurationUpdated;
+            _serverSignature = GenerateServerSignature();
+        }
+
+        private string GenerateServerSignature()
+        {
+            var os = Environment.OSVersion;
+            var pstring = os.Platform.ToString();
+            switch (os.Platform)
+            {
+                case PlatformID.Win32NT:
+                case PlatformID.Win32S:
+                case PlatformID.Win32Windows:
+                    pstring = "WIN";
+                    break;
+            }
+
+            return String.Format(
+              "{0}{1}/{2}.{3} UPnP/1.0 DLNADOC/1.5 Emby/{4}",
+              pstring,
+              IntPtr.Size * 8,
+              os.Version.Major,
+              os.Version.Minor,
+              _appHost.ApplicationVersion
+              );
         }
 
         void _config_ConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e)
@@ -60,24 +88,21 @@ namespace MediaBrowser.Dlna.Ssdp
 
         private async void OnMessageReceived(SsdpMessageEventArgs args)
         {
-            if (string.Equals(args.Method, "M-SEARCH", StringComparison.OrdinalIgnoreCase))
-            {
-                var headers = args.Headers;
+            var headers = args.Headers;
+            string st;
 
+            if (string.Equals(args.Method, "M-SEARCH", StringComparison.OrdinalIgnoreCase) && headers.TryGetValue("st", out st))
+            {
                 TimeSpan delay = GetSearchDelay(headers);
-                
+
                 if (_config.GetDlnaConfiguration().EnableDebugLogging)
                 {
                     _logger.Debug("Delaying search response by {0} seconds", delay.TotalSeconds);
                 }
-                
+
                 await Task.Delay(delay).ConfigureAwait(false);
 
-                string st;
-                if (headers.TryGetValue("st", out st))
-                {
-                    RespondToSearch(args.EndPoint, st);
-                }
+                RespondToSearch(args.EndPoint, st);
             }
 
             EventHelper.FireEventIfNotNull(MessageReceived, this, args, _logger);
@@ -117,7 +142,7 @@ namespace MediaBrowser.Dlna.Ssdp
             values["MX"] = "3";
 
             // UDP is unreliable, so send 3 requests at a time (per Upnp spec, sec 1.1.2)
-            SendDatagram("M-SEARCH * HTTP/1.1", values, localIp, 1);
+            SendDatagram("M-SEARCH * HTTP/1.1", values, localIp, 2);
         }
 
         public void SendDatagram(string header,
@@ -138,9 +163,11 @@ namespace MediaBrowser.Dlna.Ssdp
             var msg = new SsdpMessageBuilder().BuildMessage(header, values);
             var queued = false;
 
+            var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
+
             for (var i = 0; i < sendCount; i++)
             {
-                var dgram = new Datagram(endpoint, localAddress, _logger, msg, ignoreBindFailure);
+                var dgram = new Datagram(endpoint, localAddress, _logger, msg, ignoreBindFailure, enableDebugLogging);
 
                 if (_messageQueue.Count == 0)
                 {
@@ -184,10 +211,9 @@ namespace MediaBrowser.Dlna.Ssdp
 
         private void RespondToSearch(EndPoint endpoint, string deviceType)
         {
-            if (_config.GetDlnaConfiguration().EnableDebugLogging)
-            {
-                _logger.Debug("RespondToSearch");
-            }
+            var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
+
+            var isLogged = false;
 
             const string header = "HTTP/1.1 200 OK";
 
@@ -196,6 +222,15 @@ namespace MediaBrowser.Dlna.Ssdp
                 if (string.Equals(deviceType, "ssdp:all", StringComparison.OrdinalIgnoreCase) ||
                     string.Equals(deviceType, d.Type, StringComparison.OrdinalIgnoreCase))
                 {
+                    if (!isLogged)
+                    {
+                        if (enableDebugLogging)
+                        {
+                            _logger.Debug("Responding to search from {0} for {1}", endpoint, deviceType);
+                        }
+                        isLogged = true;
+                    }
+
                     var values = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
 
                     values["CACHE-CONTROL"] = "max-age = 600";
@@ -210,7 +245,7 @@ namespace MediaBrowser.Dlna.Ssdp
                     SendDatagram(header, values, endpoint, new IPEndPoint(d.Address, 0), true, 1);
                     //SendDatagram(header, values, endpoint, null, true);
 
-                    if (_config.GetDlnaConfiguration().EnableDebugLogging)
+                    if (enableDebugLogging)
                     {
                         _logger.Debug("{1} - Responded to a {0} request to {2}", d.Type, endpoint, d.Address.ToString());
                     }
@@ -288,7 +323,9 @@ namespace MediaBrowser.Dlna.Ssdp
 
                 var received = (byte[])result.AsyncState;
 
-                if (_config.GetDlnaConfiguration().EnableDebugLogging)
+                var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
+
+                if (enableDebugLogging)
                 {
                     _logger.Debug(Encoding.ASCII.GetString(received));
                 }
@@ -296,7 +333,12 @@ namespace MediaBrowser.Dlna.Ssdp
                 var args = SsdpHelper.ParseSsdpResponse(received);
                 args.EndPoint = endpoint;
 
-                if (_config.GetDlnaConfiguration().EnableDebugLogging)
+                if (IsSelfNotification(args))
+                {
+                    return;
+                }
+
+                if (enableDebugLogging)
                 {
                     var headerTexts = args.Headers.Select(i => string.Format("{0}={1}", i.Key, i.Value));
                     var headerText = string.Join(",", headerTexts.ToArray());
@@ -317,6 +359,44 @@ namespace MediaBrowser.Dlna.Ssdp
             }
         }
 
+        internal bool IsSelfNotification(SsdpMessageEventArgs args)
+        {
+            // Avoid responding to self search messages
+            //string serverId;
+            //if (args.Headers.TryGetValue("X-EMBYSERVERID", out serverId) &&
+            //    string.Equals(serverId, _appHost.SystemId, StringComparison.OrdinalIgnoreCase))
+            //{
+            //    return true;
+            //}
+
+            string server;
+            args.Headers.TryGetValue("SERVER", out server);
+
+            if (string.Equals(server, _serverSignature, StringComparison.OrdinalIgnoreCase))
+            {
+                return true;
+            }
+            return false;
+            //string usn;
+            //args.Headers.TryGetValue("USN", out usn);
+
+            //if (string.IsNullOrWhiteSpace(usn))
+            //{
+            //    return false;
+            //}
+
+            //_logger.Debug("IsSelfNotification test: " + usn);
+
+            //return RegisteredDevices.Any(i =>
+            //{
+            //    var isSameDevice = string.Equals(usn, i.USN, StringComparison.OrdinalIgnoreCase) ||
+            //           i.USN.IndexOf(usn, StringComparison.OrdinalIgnoreCase) != 1 ||
+            //           usn.IndexOf(i.USN, StringComparison.OrdinalIgnoreCase) != 1;
+
+            //    return isSameDevice;
+            //});
+        }
+
         public void Dispose()
         {
             _config.NamedConfigurationUpdated -= _config_ConfigurationUpdated;
@@ -371,17 +451,19 @@ namespace MediaBrowser.Dlna.Ssdp
 
         private void NotifyAll()
         {
-            if (_config.GetDlnaConfiguration().EnableDebugLogging)
+            var enableDebugLogging = _config.GetDlnaConfiguration().EnableDebugLogging;
+
+            if (enableDebugLogging)
             {
                 _logger.Debug("Sending alive notifications");
             }
             foreach (var d in RegisteredDevices)
             {
-                NotifyDevice(d, "alive", 1);
+                NotifyDevice(d, "alive", 1, enableDebugLogging);
             }
         }
 
-        private void NotifyDevice(UpnpDevice dev, string type, int sendCount)
+        private void NotifyDevice(UpnpDevice dev, string type, int sendCount, bool logMessage)
         {
             const string header = "NOTIFY * HTTP/1.1";
 
@@ -396,7 +478,7 @@ namespace MediaBrowser.Dlna.Ssdp
             values["NT"] = dev.Type;
             values["USN"] = dev.USN;
 
-            if (_config.GetDlnaConfiguration().EnableDebugLogging)
+            if (logMessage)
             {
                 _logger.Debug("{0} said {1}", dev.USN, type);
             }
@@ -429,7 +511,7 @@ namespace MediaBrowser.Dlna.Ssdp
 
                 foreach (var d in dl.ToList())
                 {
-                    NotifyDevice(d, "byebye", 2);
+                    NotifyDevice(d, "byebye", 2, true);
                 }
 
                 _logger.Debug("Unregistered mount {0}", uuid);
@@ -440,13 +522,15 @@ namespace MediaBrowser.Dlna.Ssdp
         private int _aliveNotifierIntervalMs;
         private void ReloadAliveNotifier()
         {
-            if (!_config.GetDlnaConfiguration().BlastAliveMessages)
+            var config = _config.GetDlnaConfiguration();
+
+            if (!config.BlastAliveMessages)
             {
                 DisposeNotificationTimer();
                 return;
             }
 
-            var intervalMs = _config.GetDlnaConfiguration().BlastAliveMessageIntervalSeconds * 1000;
+            var intervalMs = config.BlastAliveMessageIntervalSeconds * 1000;
 
             if (_notificationTimer == null || _aliveNotifierIntervalMs != intervalMs)
             {

+ 4 - 2
MediaBrowser.Dlna/Ssdp/SsdpHelper.cs

@@ -1,4 +1,5 @@
-using System;
+using MediaBrowser.Controller.Dlna;
+using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Text;
@@ -34,7 +35,8 @@ namespace MediaBrowser.Dlna.Ssdp
                     return new SsdpMessageEventArgs
                     {
                         Method = method,
-                        Headers = headers
+                        Headers = headers,
+                        Message = data
                     };
                 }
             }

+ 3 - 25
MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs

@@ -840,7 +840,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
                 var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
 
-                filters.Add(string.Format("scale=trunc(min(iw\\,{0})/2)*2:trunc(min((iw/dar)\\,{1})/2)*2", maxWidthParam, maxHeightParam));
+                filters.Add(string.Format("scale=trunc(min(max(iw\\,ih*dar)\\,min({0}\\,{1}*dar))/2)*2:trunc(min(max(iw/dar\\,ih)\\,min({0}/dar\\,{1}))/2)*2", maxWidthParam, maxHeightParam));
             }
 
             // If a fixed width was requested
@@ -860,7 +860,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             }
 
             // If a max width was requested
-            else if (request.MaxWidth.HasValue && (!request.MaxHeight.HasValue || state.VideoStream == null))
+            else if (request.MaxWidth.HasValue)
             {
                 var maxWidthParam = request.MaxWidth.Value.ToString(UsCulture);
 
@@ -868,35 +868,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
             }
 
             // If a max height was requested
-            else if (request.MaxHeight.HasValue && (!request.MaxWidth.HasValue || state.VideoStream == null))
+            else if (request.MaxHeight.HasValue)
             {
                 var maxHeightParam = request.MaxHeight.Value.ToString(UsCulture);
 
                 filters.Add(string.Format("scale=trunc(oh*a*2)/2:min(ih\\,{0})", maxHeightParam));
             }
 
-            else if (request.MaxWidth.HasValue ||
-                request.MaxHeight.HasValue ||
-                request.Width.HasValue ||
-                request.Height.HasValue)
-            {
-                if (state.VideoStream != null)
-                {
-                    // Need to perform calculations manually
-
-                    // Try to account for bad media info
-                    var currentHeight = state.VideoStream.Height ?? request.MaxHeight ?? request.Height ?? 0;
-                    var currentWidth = state.VideoStream.Width ?? request.MaxWidth ?? request.Width ?? 0;
-
-                    var outputSize = DrawingUtils.Resize(currentWidth, currentHeight, request.Width, request.Height, request.MaxWidth, request.MaxHeight);
-
-                    var manualWidthParam = outputSize.Width.ToString(UsCulture);
-                    var manualHeightParam = outputSize.Height.ToString(UsCulture);
-
-                    filters.Add(string.Format("scale=trunc({0}/2)*2:trunc({1}/2)*2", manualWidthParam, manualHeightParam));
-                }
-            }
-
             var output = string.Empty;
 
             if (state.SubtitleStream != null && state.SubtitleStream.IsTextSubtitleStream)

+ 0 - 2
MediaBrowser.MediaEncoding/Encoder/EncodingJobFactory.cs

@@ -716,8 +716,6 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 profile.GetVideoMediaProfile(outputContainer,
                 audioCodec,
                 videoCodec,
-                state.OutputAudioBitrate,
-                state.OutputAudioChannels,
                 state.OutputWidth,
                 state.OutputHeight,
                 state.TargetVideoBitDepth,

+ 160 - 136
MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs

@@ -199,82 +199,83 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
             await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
 
-            var processWrapper = new ProcessWrapper(process, this);
-
-            try
-            {
-                StartProcess(processWrapper);
-            }
-            catch (Exception ex)
+            using (var processWrapper = new ProcessWrapper(process, this))
             {
-                _ffProbeResourcePool.Release();
+                try
+                {
+                    StartProcess(processWrapper);
+                }
+                catch (Exception ex)
+                {
+                    _ffProbeResourcePool.Release();
 
-                _logger.ErrorException("Error starting ffprobe", ex);
+                    _logger.ErrorException("Error starting ffprobe", ex);
 
-                throw;
-            }
+                    throw;
+                }
 
-            try
-            {
-                process.BeginErrorReadLine();
+                try
+                {
+                    process.BeginErrorReadLine();
 
-                var result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
+                    var result = _jsonSerializer.DeserializeFromStream<InternalMediaInfoResult>(process.StandardOutput.BaseStream);
 
-                if (result != null)
-                {
-                    if (result.streams != null)
+                    if (result != null)
                     {
-                        // Normalize aspect ratio if invalid
-                        foreach (var stream in result.streams)
+                        if (result.streams != null)
                         {
-                            if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
-                            {
-                                stream.display_aspect_ratio = string.Empty;
-                            }
-                            if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
+                            // Normalize aspect ratio if invalid
+                            foreach (var stream in result.streams)
                             {
-                                stream.sample_aspect_ratio = string.Empty;
+                                if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
+                                {
+                                    stream.display_aspect_ratio = string.Empty;
+                                }
+                                if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase))
+                                {
+                                    stream.sample_aspect_ratio = string.Empty;
+                                }
                             }
                         }
-                    }
 
-                    var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
+                        var mediaInfo = new ProbeResultNormalizer(_logger, FileSystem).GetMediaInfo(result, videoType, isAudio, primaryPath, protocol);
 
-                    if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue)
-                    {
-                        foreach (var stream in mediaInfo.MediaStreams)
+                        if (extractKeyFrameInterval && mediaInfo.RunTimeTicks.HasValue)
                         {
-                            if (stream.Type == MediaStreamType.Video && string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase))
+                            foreach (var stream in mediaInfo.MediaStreams)
                             {
-                                try
-                                {
-                                    //stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken)
-                                    //            .ConfigureAwait(false);
-                                }
-                                catch (OperationCanceledException)
-                                {
-
-                                }
-                                catch (Exception ex)
+                                if (stream.Type == MediaStreamType.Video && string.Equals(stream.Codec, "h264", StringComparison.OrdinalIgnoreCase))
                                 {
-                                    _logger.ErrorException("Error getting key frame interval", ex);
+                                    try
+                                    {
+                                        //stream.KeyFrames = await GetKeyFrames(inputPath, stream.Index, cancellationToken)
+                                        //            .ConfigureAwait(false);
+                                    }
+                                    catch (OperationCanceledException)
+                                    {
+
+                                    }
+                                    catch (Exception ex)
+                                    {
+                                        _logger.ErrorException("Error getting key frame interval", ex);
+                                    }
                                 }
                             }
                         }
-                    }
 
-                    return mediaInfo;
+                        return mediaInfo;
+                    }
                 }
-            }
-            catch
-            {
-                StopProcess(processWrapper, 100, true);
+                catch
+                {
+                    StopProcess(processWrapper, 100, true);
 
-                throw;
-            }
-            finally
-            {
-                _ffProbeResourcePool.Release();
+                    throw;
+                }
+                finally
+                {
+                    _ffProbeResourcePool.Release();
+                }
             }
 
             throw new ApplicationException(string.Format("FFProbe failed for {0}", inputPath));
@@ -307,31 +308,32 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
             _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
 
-            var processWrapper = new ProcessWrapper(process, this);
-
-            StartProcess(processWrapper);
+            using (var processWrapper = new ProcessWrapper(process, this))
+            {
+                StartProcess(processWrapper);
 
-            var lines = new List<int>();
+                var lines = new List<int>();
 
-            try
-            {
-                process.BeginErrorReadLine();
+                try
+                {
+                    process.BeginErrorReadLine();
 
-                await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false);
-            }
-            catch (OperationCanceledException)
-            {
-                if (cancellationToken.IsCancellationRequested)
+                    await StartReadingOutput(process.StandardOutput.BaseStream, lines, 120000, cancellationToken).ConfigureAwait(false);
+                }
+                catch (OperationCanceledException)
                 {
-                    throw;
+                    if (cancellationToken.IsCancellationRequested)
+                    {
+                        throw;
+                    }
+                }
+                finally
+                {
+                    StopProcess(processWrapper, 100, true);
                 }
-            }
-            finally
-            {
-                StopProcess(processWrapper, 100, true);
-            }
 
-            return lines;
+                return lines;
+            }
         }
 
         private async Task StartReadingOutput(Stream source, List<int> lines, int timeoutMs, CancellationToken cancellationToken)
@@ -490,51 +492,53 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
             await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
 
-            var processWrapper = new ProcessWrapper(process, this);
-            bool ranToCompletion;
+            using (var processWrapper = new ProcessWrapper(process, this))
+            {
+                bool ranToCompletion;
 
-            var memoryStream = new MemoryStream();
+                var memoryStream = new MemoryStream();
 
-            try
-            {
-                StartProcess(processWrapper);
+                try
+                {
+                    StartProcess(processWrapper);
 
 #pragma warning disable 4014
-                // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
-                process.StandardOutput.BaseStream.CopyToAsync(memoryStream);
+                    // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback
+                    process.StandardOutput.BaseStream.CopyToAsync(memoryStream);
 #pragma warning restore 4014
 
-                // MUST read both stdout and stderr asynchronously or a deadlock may occurr
-                process.BeginErrorReadLine();
+                    // MUST read both stdout and stderr asynchronously or a deadlock may occurr
+                    process.BeginErrorReadLine();
 
-                ranToCompletion = process.WaitForExit(10000);
+                    ranToCompletion = process.WaitForExit(10000);
 
-                if (!ranToCompletion)
+                    if (!ranToCompletion)
+                    {
+                        StopProcess(processWrapper, 1000, false);
+                    }
+
+                }
+                finally
                 {
-                    StopProcess(processWrapper, 1000, false);
+                    resourcePool.Release();
                 }
 
-            }
-            finally
-            {
-                resourcePool.Release();
-            }
+                var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
 
-            var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
+                if (exitCode == -1 || memoryStream.Length == 0)
+                {
+                    memoryStream.Dispose();
 
-            if (exitCode == -1 || memoryStream.Length == 0)
-            {
-                memoryStream.Dispose();
+                    var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath);
 
-                var msg = string.Format("ffmpeg image extraction failed for {0}", inputPath);
+                    _logger.Error(msg);
 
-                _logger.Error(msg);
+                    throw new ApplicationException(msg);
+                }
 
-                throw new ApplicationException(msg);
+                memoryStream.Position = 0;
+                return memoryStream;
             }
-
-            memoryStream.Position = 0;
-            return memoryStream;
         }
 
         public string GetTimeParameter(long ticks)
@@ -603,55 +607,56 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
             bool ranToCompletion = false;
 
-            var processWrapper = new ProcessWrapper(process, this);
-
-            try
+            using (var processWrapper = new ProcessWrapper(process, this))
             {
-                StartProcess(processWrapper);
+                try
+                {
+                    StartProcess(processWrapper);
 
-                // Need to give ffmpeg enough time to make all the thumbnails, which could be a while,
-                // but we still need to detect if the process hangs.
-                // Making the assumption that as long as new jpegs are showing up, everything is good.
+                    // Need to give ffmpeg enough time to make all the thumbnails, which could be a while,
+                    // but we still need to detect if the process hangs.
+                    // Making the assumption that as long as new jpegs are showing up, everything is good.
 
-                bool isResponsive = true;
-                int lastCount = 0;
+                    bool isResponsive = true;
+                    int lastCount = 0;
 
-                while (isResponsive)
-                {
-                    if (process.WaitForExit(30000))
+                    while (isResponsive)
                     {
-                        ranToCompletion = true;
-                        break;
-                    }
+                        if (process.WaitForExit(30000))
+                        {
+                            ranToCompletion = true;
+                            break;
+                        }
+
+                        cancellationToken.ThrowIfCancellationRequested();
 
-                    cancellationToken.ThrowIfCancellationRequested();
+                        var jpegCount = Directory.GetFiles(targetDirectory)
+                            .Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase));
 
-                    var jpegCount = Directory.GetFiles(targetDirectory)
-                        .Count(i => string.Equals(Path.GetExtension(i), ".jpg", StringComparison.OrdinalIgnoreCase));
+                        isResponsive = (jpegCount > lastCount);
+                        lastCount = jpegCount;
+                    }
 
-                    isResponsive = (jpegCount > lastCount);
-                    lastCount = jpegCount;
+                    if (!ranToCompletion)
+                    {
+                        StopProcess(processWrapper, 1000, false);
+                    }
                 }
-
-                if (!ranToCompletion)
+                finally
                 {
-                    StopProcess(processWrapper, 1000, false);
+                    resourcePool.Release();
                 }
-            }
-            finally
-            {
-                resourcePool.Release();
-            }
 
-            var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
+                var exitCode = ranToCompletion ? processWrapper.ExitCode ?? 0 : -1;
 
-            if (exitCode == -1)
-            {
-                var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument);
+                if (exitCode == -1)
+                {
+                    var msg = string.Format("ffmpeg image extraction failed for {0}", inputArgument);
 
-                _logger.Error(msg);
+                    _logger.Error(msg);
 
-                throw new ApplicationException(msg);
+                    throw new ApplicationException(msg);
+                }
             }
         }
 
@@ -781,7 +786,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
             }
         }
 
-        private class ProcessWrapper
+        private class ProcessWrapper : IDisposable
         {
             public readonly Process Process;
             public bool HasExited;
@@ -810,6 +815,25 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
                 process.Dispose();
             }
+
+            private bool _disposed;
+            private readonly object _syncLock = new object();
+            public void Dispose()
+            {
+                lock (_syncLock)
+                {
+                    if (!_disposed)
+                    {
+                        if (Process != null)
+                        {
+                            Process.Exited -= Process_Exited;
+                            Process.Dispose();
+                        }
+                    }
+
+                    _disposed = true;
+                }
+            }
         }
     }
 }

+ 0 - 2
MediaBrowser.MediaEncoding/Encoder/VideoEncoder.cs

@@ -1,8 +1,6 @@
 using MediaBrowser.Common.IO;
-using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.LiveTv;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.Session;
 using MediaBrowser.Model.Dlna;

+ 6 - 0
MediaBrowser.Model/ApiClient/IApiClient.cs

@@ -1499,5 +1499,11 @@ namespace MediaBrowser.Model.ApiClient
         /// <param name="itemIds">The item ids.</param>
         /// <returns>Task.</returns>
         Task CancelSyncLibraryItems(string targetId, IEnumerable<string> itemIds);
+        /// <summary>
+        /// Gets the supported bitrate.
+        /// </summary>
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns>Task&lt;System.Int32&gt;.</returns>
+        Task<int> GetSupportedBitrate(CancellationToken cancellationToken);
     }
 }

+ 2 - 4
MediaBrowser.Model/Configuration/ServerConfiguration.cs

@@ -158,7 +158,7 @@ namespace MediaBrowser.Model.Configuration
         /// different directories and files.
         /// </summary>
         /// <value>The file watcher delay.</value>
-        public int RealtimeMonitorDelay { get; set; }
+        public int RealtimeLibraryMonitorDelay { get; set; }
 
         /// <summary>
         /// Gets or sets a value indicating whether [enable dashboard response caching].
@@ -233,7 +233,7 @@ namespace MediaBrowser.Model.Configuration
             // 5 minutes
             MinResumeDurationSeconds = 300;
 
-            RealtimeMonitorDelay = 30;
+            RealtimeLibraryMonitorDelay = 40;
 
             EnableInternetProviders = true;
             FindInternetTrailers = true;
@@ -261,8 +261,6 @@ namespace MediaBrowser.Model.Configuration
                 "Chromecast",
                 "iOS",
                 "Unknown app",
-                "MediaPortal",
-                "Media Portal",
                 "iPad",
                 "iPhone",
                 "Windows Phone"

+ 3 - 1
MediaBrowser.Model/Configuration/UserConfiguration.cs

@@ -32,6 +32,7 @@ namespace MediaBrowser.Model.Configuration
         public string[] DisplayChannelsWithinViews { get; set; }
 
         public string[] ExcludeFoldersFromGrouping { get; set; }
+        public string[] GroupedFolders { get; set; }
 
         public SubtitlePlaybackMode SubtitleMode { get; set; }
         public bool DisplayCollectionsView { get; set; }
@@ -62,12 +63,13 @@ namespace MediaBrowser.Model.Configuration
             OrderedViews = new string[] { };
             DisplayChannelsWithinViews = new string[] { };
 
-            ExcludeFoldersFromGrouping = new string[] { };
             PlainFolderViews = new string[] { };
             DisplayCollectionsView = true;
 
             IncludeTrailersInSuggestions = true;
             EnableCinemaMode = true;
+
+            GroupedFolders = new string[] { };
         }
     }
 }

+ 26 - 1
MediaBrowser.Model/Dlna/CodecProfile.cs

@@ -14,6 +14,9 @@ namespace MediaBrowser.Model.Dlna
         [XmlAttribute("codec")]
         public string Codec { get; set; }
 
+        [XmlAttribute("container")]
+        public string Container { get; set; }
+
         public CodecProfile()
         {
             Conditions = new ProfileCondition[] {};
@@ -29,8 +32,30 @@ namespace MediaBrowser.Model.Dlna
             return list;
         }
 
-        public bool ContainsCodec(string codec)
+        public List<string> GetContainers()
+        {
+            List<string> list = new List<string>();
+            foreach (string i in (Container ?? string.Empty).Split(','))
+            {
+                if (!string.IsNullOrEmpty(i)) list.Add(i);
+            }
+            return list;
+        }
+
+        private bool ContainsContainer(string container)
+        {
+            List<string> containers = GetContainers();
+
+            return containers.Count == 0 || ListHelper.ContainsIgnoreCase(containers, container ?? string.Empty);
+        }
+
+        public bool ContainsCodec(string codec, string container)
         {
+            if (!ContainsContainer(container))
+            {
+                return false;
+            }
+
             List<string> codecs = GetCodecs();
 
             return codecs.Count == 0 || ListHelper.ContainsIgnoreCase(codecs, codec);

+ 0 - 6
MediaBrowser.Model/Dlna/ConditionProcessor.cs

@@ -7,8 +7,6 @@ namespace MediaBrowser.Model.Dlna
     public class ConditionProcessor
     {
         public bool IsVideoConditionSatisfied(ProfileCondition condition,
-            int? audioBitrate,
-            int? audioChannels,
             int? width,
             int? height,
             int? bitDepth,
@@ -44,10 +42,6 @@ namespace MediaBrowser.Model.Dlna
                     return IsConditionSatisfied(condition, videoProfile);
                 case ProfileConditionValue.PacketLength:
                     return IsConditionSatisfied(condition, packetLength);
-                case ProfileConditionValue.AudioBitrate:
-                    return IsConditionSatisfied(condition, audioBitrate);
-                case ProfileConditionValue.AudioChannels:
-                    return IsConditionSatisfied(condition, audioChannels);
                 case ProfileConditionValue.VideoBitDepth:
                     return IsConditionSatisfied(condition, bitDepth);
                 case ProfileConditionValue.VideoBitrate:

+ 2 - 5
MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs

@@ -1,4 +1,5 @@
 using MediaBrowser.Model.MediaInfo;
+using System;
 using System.Collections.Generic;
 
 namespace MediaBrowser.Model.Dlna
@@ -105,8 +106,6 @@ namespace MediaBrowser.Model.Dlna
             int? height,
             int? bitDepth,
             int? videoBitrate,
-            int? audioChannels,
-            int? audioBitrate,
             TransportStreamTimestamp timestamp,
             bool isDirectStream,
             long? runtimeTicks,
@@ -147,8 +146,6 @@ namespace MediaBrowser.Model.Dlna
             ResponseProfile mediaProfile = _profile.GetVideoMediaProfile(container,
                 audioCodec,
                 videoCodec,
-                audioBitrate,
-                audioChannels,
                 width,
                 height,
                 bitDepth,
@@ -168,7 +165,7 @@ namespace MediaBrowser.Model.Dlna
 
             if (mediaProfile != null && !string.IsNullOrEmpty(mediaProfile.OrgPn))
             {
-                orgPnValues.Add(mediaProfile.OrgPn);
+                orgPnValues.AddRange(mediaProfile.OrgPn.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
             }
             else
             {

+ 1 - 4
MediaBrowser.Model/Dlna/DeviceProfile.cs

@@ -34,7 +34,6 @@ namespace MediaBrowser.Model.Dlna
         public string ModelNumber { get; set; }
         public string ModelUrl { get; set; }
         public string SerialNumber { get; set; }
-        public bool IgnoreTranscodeByteRangeRequests { get; set; }
 
         public bool EnableAlbumArtInDidl { get; set; }
         public bool EnableSingleAlbumArtLimit { get; set; }
@@ -272,8 +271,6 @@ namespace MediaBrowser.Model.Dlna
         public ResponseProfile GetVideoMediaProfile(string container, 
             string audioCodec,
             string videoCodec,
-            int? audioBitrate,
-            int? audioChannels,
             int? width,
             int? height,
             int? bitDepth,
@@ -321,7 +318,7 @@ namespace MediaBrowser.Model.Dlna
                 var anyOff = false;
                 foreach (ProfileCondition c in i.Conditions)
                 {
-                    if (!conditionProcessor.IsVideoConditionSatisfied(c, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
+                    if (!conditionProcessor.IsVideoConditionSatisfied(c, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
                     {
                         anyOff = true;
                         break;

+ 8 - 8
MediaBrowser.Model/Dlna/StreamBuilder.cs

@@ -131,7 +131,7 @@ namespace MediaBrowser.Model.Dlna
                     List<ProfileCondition> conditions = new List<ProfileCondition>();
                     foreach (CodecProfile i in options.Profile.CodecProfiles)
                     {
-                        if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec))
+                        if (i.Type == CodecType.Audio && i.ContainsCodec(audioCodec, item.Container))
                         {
                             foreach (ProfileCondition c in i.Conditions)
                             {
@@ -206,7 +206,7 @@ namespace MediaBrowser.Model.Dlna
                 List<CodecProfile> audioCodecProfiles = new List<CodecProfile>();
                 foreach (CodecProfile i in options.Profile.CodecProfiles)
                 {
-                    if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec))
+                    if (i.Type == CodecType.Audio && i.ContainsCodec(transcodingProfile.AudioCodec, transcodingProfile.Container))
                     {
                         audioCodecProfiles.Add(i);
                     }
@@ -423,7 +423,7 @@ namespace MediaBrowser.Model.Dlna
                 List<ProfileCondition> videoTranscodingConditions = new List<ProfileCondition>();
                 foreach (CodecProfile i in options.Profile.CodecProfiles)
                 {
-                    if (i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec))
+                    if (i.Type == CodecType.Video && i.ContainsCodec(transcodingProfile.VideoCodec, transcodingProfile.Container))
                     {
                         foreach (ProfileCondition c in i.Conditions)
                         {
@@ -437,7 +437,7 @@ namespace MediaBrowser.Model.Dlna
                 List<ProfileCondition> audioTranscodingConditions = new List<ProfileCondition>();
                 foreach (CodecProfile i in options.Profile.CodecProfiles)
                 {
-                    if (i.Type == CodecType.VideoAudio && i.ContainsCodec(transcodingProfile.AudioCodec))
+                    if (i.Type == CodecType.VideoAudio && i.ContainsCodec(transcodingProfile.AudioCodec, transcodingProfile.Container))
                     {
                         foreach (ProfileCondition c in i.Conditions)
                         {
@@ -578,7 +578,7 @@ namespace MediaBrowser.Model.Dlna
             // Check container conditions
             foreach (ProfileCondition i in conditions)
             {
-                if (!conditionProcessor.IsVideoConditionSatisfied(i, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
+                if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
                 {
                     LogConditionFailure(profile, "VideoContainerProfile", i, mediaSource);
 
@@ -600,7 +600,7 @@ namespace MediaBrowser.Model.Dlna
             conditions = new List<ProfileCondition>();
             foreach (CodecProfile i in profile.CodecProfiles)
             {
-                if (i.Type == CodecType.Video && i.ContainsCodec(videoCodec))
+                if (i.Type == CodecType.Video && i.ContainsCodec(videoCodec, container))
                 {
                     foreach (ProfileCondition c in i.Conditions)
                     {
@@ -611,7 +611,7 @@ namespace MediaBrowser.Model.Dlna
 
             foreach (ProfileCondition i in conditions)
             {
-                if (!conditionProcessor.IsVideoConditionSatisfied(i, audioBitrate, audioChannels, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
+                if (!conditionProcessor.IsVideoConditionSatisfied(i, width, height, bitDepth, videoBitrate, videoProfile, videoLevel, videoFramerate, packetLength, timestamp, isAnamorphic, isCabac, refFrames, numVideoStreams, numAudioStreams))
                 {
                     LogConditionFailure(profile, "VideoCodecProfile", i, mediaSource);
 
@@ -635,7 +635,7 @@ namespace MediaBrowser.Model.Dlna
                 conditions = new List<ProfileCondition>();
                 foreach (CodecProfile i in profile.CodecProfiles)
                 {
-                    if (i.Type == CodecType.VideoAudio && i.ContainsCodec(audioCodec))
+                    if (i.Type == CodecType.VideoAudio && i.ContainsCodec(audioCodec, container))
                     {
                         foreach (ProfileCondition c in i.Conditions)
                         {

+ 14 - 16
MediaBrowser.Providers/Manager/ItemImageProvider.cs

@@ -38,13 +38,16 @@ namespace MediaBrowser.Providers.Manager
         {
             var hasChanges = false;
 
-            var images = providers.OfType<ILocalImageFileProvider>()
-                .SelectMany(i => i.GetImages(item, directoryService))
-                .ToList();
-
-            if (MergeImages(item, images))
+            if (!(item is Photo))
             {
-                hasChanges = true;
+                var images = providers.OfType<ILocalImageFileProvider>()
+                    .SelectMany(i => i.GetImages(item, directoryService))
+                    .ToList();
+
+                if (MergeImages(item, images))
+                {
+                    hasChanges = true;
+                }
             }
 
             return hasChanges;
@@ -419,19 +422,14 @@ namespace MediaBrowser.Providers.Manager
             var changed = false;
 
             var newImages = images.Where(i => i.Type == type).ToList();
-            if (newImages.Count > 0)
-            {
-                var newImageFileInfos = images.Where(i => i.Type == type)
+
+            var newImageFileInfos = newImages
                     .Select(i => i.FileInfo)
                     .ToList();
 
-                if (newImageFileInfos.Count > 0)
-                {
-                    if (item.AddImages(type, newImageFileInfos))
-                    {
-                        changed = true;
-                    }
-                }
+            if (item.AddImages(type, newImageFileInfos))
+            {
+                changed = true;
             }
 
             return changed;

+ 9 - 0
MediaBrowser.Providers/Manager/ProviderUtils.cs

@@ -14,6 +14,15 @@ namespace MediaBrowser.Providers.Manager
             bool replaceData, 
             bool mergeMetadataSettings)
         {
+            if (source == null)
+            {
+                throw new ArgumentNullException("source");
+            }
+            if (target == null)
+            {
+                throw new ArgumentNullException("target");
+            }
+
             if (!lockedFields.Contains(MetadataFields.Name))
             {
                 if (replaceData || string.IsNullOrEmpty(target.Name))

+ 1 - 1
MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs

@@ -93,7 +93,7 @@ namespace MediaBrowser.Providers.MediaInfo
 
         private string GetAudioImagePath(Audio item)
         {
-            var album = item.Parent as MusicAlbum;
+            var album = item.AlbumEntity;
 
             var filename = item.Album ?? string.Empty;
             filename += string.Join(",", item.Artists.ToArray());

+ 11 - 4
MediaBrowser.Providers/TV/TvdbEpisodeProvider.cs

@@ -5,6 +5,7 @@ using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.Logging;
 using MediaBrowser.Model.Providers;
 using System;
 using System.Collections.Generic;
@@ -29,12 +30,14 @@ namespace MediaBrowser.Providers.TV
         private readonly IFileSystem _fileSystem;
         private readonly IServerConfigurationManager _config;
         private readonly IHttpClient _httpClient;
+        private readonly ILogger _logger;
 
-        public TvdbEpisodeProvider(IFileSystem fileSystem, IServerConfigurationManager config, IHttpClient httpClient)
+        public TvdbEpisodeProvider(IFileSystem fileSystem, IServerConfigurationManager config, IHttpClient httpClient, ILogger logger)
         {
             _fileSystem = fileSystem;
             _config = config;
             _httpClient = httpClient;
+            _logger = logger;
             Current = this;
         }
 
@@ -100,7 +103,8 @@ namespace MediaBrowser.Providers.TV
 
                 try
                 {
-                    result.Item = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds, cancellationToken);
+                    result.Item = FetchEpisodeData(searchInfo, identity, seriesDataPath, searchInfo.SeriesProviderIds,
+                        cancellationToken);
                     result.HasMetadata = result.Item != null;
                 }
                 catch (FileNotFoundException)
@@ -112,6 +116,10 @@ namespace MediaBrowser.Providers.TV
                     // Don't fail the provider because this will just keep on going and going.
                 }
             }
+            else
+            {
+                _logger.Debug("No series identity found for {0}", searchInfo.Name);
+            }
 
             return result;
         }
@@ -265,7 +273,6 @@ namespace MediaBrowser.Providers.TV
 
                 FetchMainEpisodeInfo(episode, file, cancellationToken);
                 usingAbsoluteData = true;
-                success = true;
             }
 
             var end = identity.IndexNumberEnd ?? episodeNumber;
@@ -298,7 +305,7 @@ namespace MediaBrowser.Providers.TV
                 episodeNumber++;
             }
 
-            return success ? episode : null;
+            return episode;
         }
 
         private readonly CultureInfo _usCulture = new CultureInfo("en-US");

+ 1 - 10
MediaBrowser.Server.Implementations/Dto/DtoService.cs

@@ -1193,7 +1193,7 @@ namespace MediaBrowser.Server.Implementations.Dto
             {
                 dto.Album = audio.Album;
 
-                var albumParent = audio.FindParent<MusicAlbum>();
+                var albumParent = audio.AlbumEntity;
 
                 if (albumParent != null)
                 {
@@ -1208,15 +1208,6 @@ namespace MediaBrowser.Server.Implementations.Dto
                 //}
             }
 
-            var album = item as MusicAlbum;
-
-            if (album != null)
-            {
-                dto.SoundtrackIds = album.SoundtrackIds
-                    .Select(i => i.ToString("N"))
-                    .ToArray();
-            }
-
             var hasArtist = item as IHasArtist;
             if (hasArtist != null)
             {

+ 23 - 5
MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs

@@ -1,5 +1,6 @@
 using MediaBrowser.Controller;
 using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Plugins;
 using MediaBrowser.Model.Logging;
 using Mono.Nat;
@@ -7,6 +8,7 @@ using System;
 using System.Collections.Generic;
 using System.Globalization;
 using System.IO;
+using System.Net;
 using System.Text;
 using System.Threading;
 
@@ -17,15 +19,17 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
         private readonly IServerApplicationHost _appHost;
         private readonly ILogger _logger;
         private readonly IServerConfigurationManager _config;
+        private readonly ISsdpHandler _ssdp;
 
         private Timer _timer;
         private bool _isStarted;
 
-        public ExternalPortForwarding(ILogManager logmanager, IServerApplicationHost appHost, IServerConfigurationManager config)
+        public ExternalPortForwarding(ILogManager logmanager, IServerApplicationHost appHost, IServerConfigurationManager config, ISsdpHandler ssdp)
         {
             _logger = logmanager.GetLogger("PortMapper");
             _appHost = appHost;
             _config = config;
+            _ssdp = ssdp;
         }
 
         private string _lastConfigIdentifier;
@@ -75,10 +79,10 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
         private void Start()
         {
             _logger.Debug("Starting NAT discovery");
-            //NatUtility.EnabledProtocols = new List<NatProtocol>
-            //{
-            //    NatProtocol.Pmp
-            //};
+            NatUtility.EnabledProtocols = new List<NatProtocol>
+            {
+                NatProtocol.Pmp
+            };
             NatUtility.DeviceFound += NatUtility_DeviceFound;
 
             // Mono.Nat does never rise this event. The event is there however it is useless. 
@@ -93,11 +97,23 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
 
             _timer = new Timer(s => _createdRules = new List<string>(), null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
 
+            _ssdp.MessageReceived += _ssdp_MessageReceived;
+
             _lastConfigIdentifier = GetConfigIdentifier();
 
             _isStarted = true;
         }
 
+        void _ssdp_MessageReceived(object sender, SsdpMessageEventArgs e)
+        {
+            var endpoint = e.EndPoint as IPEndPoint;
+
+            if (endpoint != null && e.LocalIp != null)
+            {
+                NatUtility.Handle(e.LocalIp, e.Message, endpoint, NatProtocol.Upnp);
+            }
+        }
+
         void NatUtility_UnhandledException(object sender, UnhandledExceptionEventArgs e)
         {
             var ex = e.ExceptionObject as Exception;
@@ -183,6 +199,8 @@ namespace MediaBrowser.Server.Implementations.EntryPoints
                 _timer = null;
             }
 
+            _ssdp.MessageReceived -= _ssdp_MessageReceived;
+
             try
             {
                 // This is not a significant improvement

+ 1 - 2
MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs

@@ -8,7 +8,6 @@ using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.FileOrganization;
 using MediaBrowser.Model.Logging;
-using MediaBrowser.Naming.IO;
 using MediaBrowser.Server.Implementations.Library;
 using MediaBrowser.Server.Implementations.Logging;
 using System;
@@ -60,7 +59,7 @@ namespace MediaBrowser.Server.Implementations.FileOrganization
             var namingOptions = ((LibraryManager) _libraryManager).GetNamingOptions();
             var resolver = new Naming.TV.EpisodeResolver(namingOptions, new PatternsLogger());
 
-            var episodeInfo = resolver.Resolve(path, FileInfoType.File) ??
+            var episodeInfo = resolver.Resolve(path, false) ??
                 new Naming.TV.EpisodeInfo();
 
             var seriesName = episodeInfo.SeriesName;

+ 4 - 4
MediaBrowser.Server.Implementations/IO/LibraryMonitor.cs

@@ -84,7 +84,7 @@ namespace MediaBrowser.Server.Implementations.IO
             // This is an arbitraty amount of time, but delay it because file system writes often trigger events after RemoveTempIgnore has been called. 
             // Seeing long delays in some situations, especially over the network.
             // Seeing delays up to 40 seconds, but not going to ignore changes for that long.
-            await Task.Delay(1500).ConfigureAwait(false);
+            await Task.Delay(5000).ConfigureAwait(false);
 
             string val;
             _tempIgnoredPaths.TryRemove(path, out val);
@@ -437,11 +437,11 @@ namespace MediaBrowser.Server.Implementations.IO
             {
                 if (_updateTimer == null)
                 {
-                    _updateTimer = new Timer(TimerStopped, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeMonitorDelay), TimeSpan.FromMilliseconds(-1));
+                    _updateTimer = new Timer(TimerStopped, null, TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeLibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
                 }
                 else
                 {
-                    _updateTimer.Change(TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeMonitorDelay), TimeSpan.FromMilliseconds(-1));
+                    _updateTimer.Change(TimeSpan.FromSeconds(ConfigurationManager.Configuration.RealtimeLibraryMonitorDelay), TimeSpan.FromMilliseconds(-1));
                 }
             }
         }
@@ -560,7 +560,7 @@ namespace MediaBrowser.Server.Implementations.IO
         /// <returns>Task.</returns>
         private async Task ProcessPathChanges(List<string> paths)
         {
-            var itemsToRefresh = paths.Select(Path.GetDirectoryName)
+            var itemsToRefresh = paths
                 .Select(GetAffectedBaseItem)
                 .Where(item => item != null)
                 .Distinct()

+ 21 - 25
MediaBrowser.Server.Implementations/Library/LibraryManager.cs

@@ -1,4 +1,5 @@
-using MediaBrowser.Common.Extensions;
+using Interfaces.IO;
+using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.IO;
 using MediaBrowser.Common.Progress;
 using MediaBrowser.Common.ScheduledTasks;
@@ -17,7 +18,6 @@ using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Logging;
 using MediaBrowser.Naming.Audio;
 using MediaBrowser.Naming.Common;
-using MediaBrowser.Naming.IO;
 using MediaBrowser.Naming.TV;
 using MediaBrowser.Naming.Video;
 using MediaBrowser.Server.Implementations.Library.Validators;
@@ -1594,6 +1594,8 @@ namespace MediaBrowser.Server.Implementations.Library
                 .FirstOrDefault(i => !string.IsNullOrWhiteSpace(i));
         }
 
+        private readonly TimeSpan _viewRefreshInterval = TimeSpan.FromHours(24);
+
         public async Task<UserView> GetNamedView(User user,
             string name,
             string viewType,
@@ -1645,13 +1647,18 @@ namespace MediaBrowser.Server.Implementations.Library
 
             if (!refresh && item != null)
             {
-                refresh = (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 24;
+                refresh = (DateTime.UtcNow - item.DateLastSaved) >= _viewRefreshInterval;
             }
 
             if (refresh)
             {
                 await item.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None).ConfigureAwait(false);
-                _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions());
+                _providerManagerFactory().QueueRefresh(item.Id, new MetadataRefreshOptions
+                {
+                    // Not sure why this is necessary but need to figure it out
+                    // View images are not getting utilized without this
+                    ForceSave = true
+                });
             }
 
             return item;
@@ -1731,7 +1738,7 @@ namespace MediaBrowser.Server.Implementations.Library
                 await item.UpdateToRepository(ItemUpdateType.MetadataEdit, cancellationToken).ConfigureAwait(false);
             }
 
-            var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved).TotalHours >= 24;
+            var refresh = isNew || (DateTime.UtcNow - item.DateLastSaved) >= _viewRefreshInterval;
 
             if (refresh)
             {
@@ -1767,14 +1774,13 @@ namespace MediaBrowser.Server.Implementations.Library
             var resolver = new EpisodeResolver(GetNamingOptions(),
                 new PatternsLogger());
 
-            var fileType = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd || episode.VideoType == VideoType.HdDvd ?
-                FileInfoType.Directory :
-                FileInfoType.File;
+            var isFolder = episode.VideoType == VideoType.BluRay || episode.VideoType == VideoType.Dvd ||
+                           episode.VideoType == VideoType.HdDvd;
 
             var locationType = episode.LocationType;
 
             var episodeInfo = locationType == LocationType.FileSystem || locationType == LocationType.Offline ?
-                resolver.Resolve(episode.Path, fileType) :
+                resolver.Resolve(episode.Path, isFolder) :
                 new Naming.TV.EpisodeInfo();
 
             if (episodeInfo == null)
@@ -1928,10 +1934,10 @@ namespace MediaBrowser.Server.Implementations.Library
 
             var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
 
-            var videos = videoListResolver.Resolve(fileSystemChildren.Select(i => new PortableFileInfo
+            var videos = videoListResolver.Resolve(fileSystemChildren.Select(i => new FileMetadata
             {
-                FullName = i.FullName,
-                Type = GetFileType(i)
+                Id = i.FullName,
+                IsFolder = ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
 
             }).ToList());
 
@@ -1962,16 +1968,6 @@ namespace MediaBrowser.Server.Implementations.Library
             }).OrderBy(i => i.Path).ToList();
         }
 
-        private FileInfoType GetFileType(FileSystemInfo info)
-        {
-            if ((info.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
-            {
-                return FileInfoType.Directory;
-            }
-
-            return FileInfoType.File;
-        }
-
         public IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemInfo> fileSystemChildren, IDirectoryService directoryService)
         {
             var files = fileSystemChildren.OfType<DirectoryInfo>()
@@ -1981,10 +1977,10 @@ namespace MediaBrowser.Server.Implementations.Library
 
             var videoListResolver = new VideoListResolver(GetNamingOptions(), new PatternsLogger());
 
-            var videos = videoListResolver.Resolve(fileSystemChildren.Select(i => new PortableFileInfo
+            var videos = videoListResolver.Resolve(fileSystemChildren.Select(i => new FileMetadata
             {
-                FullName = i.FullName,
-                Type = GetFileType(i)
+                Id = i.FullName,
+                IsFolder = ((i.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
 
             }).ToList());
 

Some files were not shown because too many files changed in this diff