Bond_009 5 rokov pred
rodič
commit
be8ba96183

+ 10 - 0
Emby.Dlna/Api/DlnaServerService.cs

@@ -1,6 +1,7 @@
 #pragma warning disable CS1591
 
 using System;
+using System.Diagnostics.CodeAnalysis;
 using System.IO;
 using System.Text;
 using System.Threading.Tasks;
@@ -151,6 +152,7 @@ namespace Emby.Dlna.Api
             return _resultFactory.GetStaticResult(Request, cacheKey, null, cacheLength, XMLContentType, () => Task.FromResult<Stream>(new MemoryStream(bytes)));
         }
 
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public object Get(GetContentDirectory request)
         {
             var xml = ContentDirectory.GetServiceXml();
@@ -158,6 +160,7 @@ namespace Emby.Dlna.Api
             return _resultFactory.GetResult(Request, xml, XMLContentType);
         }
 
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public object Get(GetMediaReceiverRegistrar request)
         {
             var xml = MediaReceiverRegistrar.GetServiceXml();
@@ -165,6 +168,7 @@ namespace Emby.Dlna.Api
             return _resultFactory.GetResult(Request, xml, XMLContentType);
         }
 
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public object Get(GetConnnectionManager request)
         {
             var xml = ConnectionManager.GetServiceXml();
@@ -313,31 +317,37 @@ namespace Emby.Dlna.Api
             return _resultFactory.GetStaticResult(Request, cacheKey, null, cacheLength, contentType, () => Task.FromResult(_dlnaManager.GetIcon(request.Filename).Stream));
         }
 
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public object Subscribe(ProcessContentDirectoryEventRequest request)
         {
             return ProcessEventRequest(ContentDirectory);
         }
 
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public object Subscribe(ProcessConnectionManagerEventRequest request)
         {
             return ProcessEventRequest(ConnectionManager);
         }
 
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public object Subscribe(ProcessMediaReceiverRegistrarEventRequest request)
         {
             return ProcessEventRequest(MediaReceiverRegistrar);
         }
 
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public object Unsubscribe(ProcessContentDirectoryEventRequest request)
         {
             return ProcessEventRequest(ContentDirectory);
         }
 
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public object Unsubscribe(ProcessConnectionManagerEventRequest request)
         {
             return ProcessEventRequest(ConnectionManager);
         }
 
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public object Unsubscribe(ProcessMediaReceiverRegistrarEventRequest request)
         {
             return ProcessEventRequest(MediaReceiverRegistrar);

+ 3 - 0
Emby.Dlna/Api/DlnaService.cs

@@ -1,5 +1,6 @@
 #pragma warning disable CS1591
 
+using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Net;
@@ -52,6 +53,7 @@ namespace Emby.Dlna.Api
             _dlnaManager = dlnaManager;
         }
 
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public object Get(GetProfileInfos request)
         {
             return _dlnaManager.GetProfileInfos().ToArray();
@@ -62,6 +64,7 @@ namespace Emby.Dlna.Api
             return _dlnaManager.GetProfile(request.Id);
         }
 
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public object Get(GetDefaultProfile request)
         {
             return _dlnaManager.GetDefaultProfile();

+ 59 - 52
Emby.Dlna/ContentDirectory/ControlHandler.cs

@@ -78,7 +78,18 @@ namespace Emby.Dlna.ContentDirectory
             _profile = profile;
             _config = config;
 
-            _didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, mediaEncoder);
+            _didlBuilder = new DidlBuilder(
+                profile,
+                user,
+                imageProcessor,
+                serverAddress,
+                accessToken,
+                userDataManager,
+                localization,
+                mediaSourceManager,
+                Logger,
+                mediaEncoder,
+                libraryManager);
         }
 
         /// <inheritdoc />
@@ -153,7 +164,7 @@ namespace Emby.Dlna.ContentDirectory
         {
             var id = sparams["ObjectID"];
 
-            var serverItem = GetItemFromObjectId(id, _user);
+            var serverItem = GetItemFromObjectId(id);
 
             var item = serverItem.Item;
 
@@ -276,7 +287,7 @@ namespace Emby.Dlna.ContentDirectory
 
                     DidlBuilder.WriteXmlRootAttributes(_profile, writer);
 
-                    var serverItem = GetItemFromObjectId(id, _user);
+                    var serverItem = GetItemFromObjectId(id);
                     var item = serverItem.Item;
 
 
@@ -293,7 +304,7 @@ namespace Emby.Dlna.ContentDirectory
                         else
                         {
                             var dlnaOptions = _config.GetDlnaConfiguration();
-                            _didlBuilder.WriteItemElement(dlnaOptions, writer, item, _user, null, null, deviceId, filter);
+                            _didlBuilder.WriteItemElement(writer, item, _user, null, null, deviceId, filter);
                         }
 
                         provided++;
@@ -320,7 +331,7 @@ namespace Emby.Dlna.ContentDirectory
                             }
                             else
                             {
-                                _didlBuilder.WriteItemElement(dlnaOptions, writer, childItem, _user, item, serverItem.StubType, deviceId, filter);
+                                _didlBuilder.WriteItemElement(writer, childItem, _user, item, serverItem.StubType, deviceId, filter);
                             }
                         }
                     }
@@ -387,7 +398,7 @@ namespace Emby.Dlna.ContentDirectory
 
                     DidlBuilder.WriteXmlRootAttributes(_profile, writer);
 
-                    var serverItem = GetItemFromObjectId(sparams["ContainerID"], _user);
+                    var serverItem = GetItemFromObjectId(sparams["ContainerID"]);
 
                     var item = serverItem.Item;
 
@@ -406,7 +417,7 @@ namespace Emby.Dlna.ContentDirectory
                         }
                         else
                         {
-                            _didlBuilder.WriteItemElement(dlnaOptions, writer, i, _user, item, serverItem.StubType, deviceId, filter);
+                            _didlBuilder.WriteItemElement(writer, i, _user, item, serverItem.StubType, deviceId, filter);
                         }
                     }
 
@@ -512,11 +523,11 @@ namespace Emby.Dlna.ContentDirectory
                 }
                 else if (string.Equals(CollectionType.Folders, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
                 {
-                    return GetFolders(item, user, stubType, sort, startIndex, limit);
+                    return GetFolders(user, startIndex, limit);
                 }
                 else if (string.Equals(CollectionType.LiveTv, collectionFolder.CollectionType, StringComparison.OrdinalIgnoreCase))
                 {
-                    return GetLiveTvChannels(item, user, stubType, sort, startIndex, limit);
+                    return GetLiveTvChannels(user, sort, startIndex, limit);
                 }
             }
 
@@ -547,7 +558,7 @@ namespace Emby.Dlna.ContentDirectory
             return ToResult(queryResult);
         }
 
-        private QueryResult<ServerItem> GetLiveTvChannels(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit)
+        private QueryResult<ServerItem> GetLiveTvChannels(User user, SortCriteria sort, int? startIndex, int? limit)
         {
             var query = new InternalItemsQuery(user)
             {
@@ -579,7 +590,7 @@ namespace Emby.Dlna.ContentDirectory
 
             if (stubType.HasValue && stubType.Value == StubType.Playlists)
             {
-                return GetMusicPlaylists(item, user, query);
+                return GetMusicPlaylists(user, query);
             }
 
             if (stubType.HasValue && stubType.Value == StubType.Albums)
@@ -707,7 +718,7 @@ namespace Emby.Dlna.ContentDirectory
 
             if (stubType.HasValue && stubType.Value == StubType.Collections)
             {
-                return GetMovieCollections(item, user, query);
+                return GetMovieCollections(user, query);
             }
 
             if (stubType.HasValue && stubType.Value == StubType.Favorites)
@@ -720,46 +731,42 @@ namespace Emby.Dlna.ContentDirectory
                 return GetGenres(item, user, query);
             }
 
-            var list = new List<ServerItem>();
-
-            list.Add(new ServerItem(item)
-            {
-                StubType = StubType.ContinueWatching
-            });
-
-            list.Add(new ServerItem(item)
+            var array = new ServerItem[]
             {
-                StubType = StubType.Latest
-            });
-
-            list.Add(new ServerItem(item)
-            {
-                StubType = StubType.Movies
-            });
-
-            list.Add(new ServerItem(item)
-            {
-                StubType = StubType.Collections
-            });
-
-            list.Add(new ServerItem(item)
-            {
-                StubType = StubType.Favorites
-            });
-
-            list.Add(new ServerItem(item)
-            {
-                StubType = StubType.Genres
-            });
+                new ServerItem(item)
+                {
+                    StubType = StubType.ContinueWatching
+                },
+                new ServerItem(item)
+                {
+                    StubType = StubType.Latest
+                },
+                new ServerItem(item)
+                {
+                    StubType = StubType.Movies
+                },
+                new ServerItem(item)
+                {
+                    StubType = StubType.Collections
+                },
+                new ServerItem(item)
+                {
+                    StubType = StubType.Favorites
+                },
+                new ServerItem(item)
+                {
+                    StubType = StubType.Genres
+                }
+            };
 
             return new QueryResult<ServerItem>
             {
-                Items = list,
-                TotalRecordCount = list.Count
+                Items = array,
+                TotalRecordCount = array.Length
             };
         }
 
-        private QueryResult<ServerItem> GetFolders(BaseItem item, User user, StubType? stubType, SortCriteria sort, int? startIndex, int? limit)
+        private QueryResult<ServerItem> GetFolders(User user, int? startIndex, int? limit)
         {
             var folders = _libraryManager.GetUserRootFolder().GetChildren(user, true)
                 .OrderBy(i => i.SortName)
@@ -792,7 +799,7 @@ namespace Emby.Dlna.ContentDirectory
 
             if (stubType.HasValue && stubType.Value == StubType.NextUp)
             {
-                return GetNextUp(item, user, query);
+                return GetNextUp(item, query);
             }
 
             if (stubType.HasValue && stubType.Value == StubType.Latest)
@@ -910,7 +917,7 @@ namespace Emby.Dlna.ContentDirectory
             return ToResult(result);
         }
 
-        private QueryResult<ServerItem> GetMovieCollections(BaseItem parent, User user, InternalItemsQuery query)
+        private QueryResult<ServerItem> GetMovieCollections(User user, InternalItemsQuery query)
         {
             query.Recursive = true;
             //query.Parent = parent;
@@ -1105,7 +1112,7 @@ namespace Emby.Dlna.ContentDirectory
             return ToResult(result);
         }
 
-        private QueryResult<ServerItem> GetMusicPlaylists(BaseItem parent, User user, InternalItemsQuery query)
+        private QueryResult<ServerItem> GetMusicPlaylists(User user, InternalItemsQuery query)
         {
             query.Parent = null;
             query.IncludeItemTypes = new[] { typeof(Playlist).Name };
@@ -1134,7 +1141,7 @@ namespace Emby.Dlna.ContentDirectory
             return ToResult(items);
         }
 
-        private QueryResult<ServerItem> GetNextUp(BaseItem parent, User user, InternalItemsQuery query)
+        private QueryResult<ServerItem> GetNextUp(BaseItem parent, InternalItemsQuery query)
         {
             query.OrderBy = Array.Empty<(string, SortOrder)>();
 
@@ -1289,15 +1296,15 @@ namespace Emby.Dlna.ContentDirectory
             return result;
         }
 
-        private ServerItem GetItemFromObjectId(string id, User user)
+        private ServerItem GetItemFromObjectId(string id)
         {
             return DidlBuilder.IsIdRoot(id)
 
                  ? new ServerItem(_libraryManager.GetUserRootFolder())
-                 : ParseItemId(id, user);
+                 : ParseItemId(id);
         }
 
-        private ServerItem ParseItemId(string id, User user)
+        private ServerItem ParseItemId(string id)
         {
             StubType? stubType = null;
 

+ 91 - 75
Emby.Dlna/Didl/DidlBuilder.cs

@@ -45,6 +45,7 @@ namespace Emby.Dlna.Didl
         private readonly IMediaSourceManager _mediaSourceManager;
         private readonly ILogger _logger;
         private readonly IMediaEncoder _mediaEncoder;
+        private readonly ILibraryManager _libraryManager;
 
         public DidlBuilder(
             DeviceProfile profile,
@@ -56,7 +57,8 @@ namespace Emby.Dlna.Didl
             ILocalizationManager localization,
             IMediaSourceManager mediaSourceManager,
             ILogger logger,
-            IMediaEncoder mediaEncoder)
+            IMediaEncoder mediaEncoder,
+            ILibraryManager libraryManager)
         {
             _profile = profile;
             _user = user;
@@ -68,6 +70,7 @@ namespace Emby.Dlna.Didl
             _mediaSourceManager = mediaSourceManager;
             _logger = logger;
             _mediaEncoder = mediaEncoder;
+            _libraryManager = libraryManager;
         }
 
         public static string NormalizeDlnaMediaUrl(string url)
@@ -75,7 +78,7 @@ namespace Emby.Dlna.Didl
             return url + "&dlnaheaders=true";
         }
 
-        public string GetItemDidl(DlnaOptions options, BaseItem item, User user, BaseItem context, string deviceId, Filter filter, StreamInfo streamInfo)
+        public string GetItemDidl(BaseItem item, User user, BaseItem context, string deviceId, Filter filter, StreamInfo streamInfo)
         {
             var settings = new XmlWriterSettings
             {
@@ -100,7 +103,7 @@ namespace Emby.Dlna.Didl
 
                     WriteXmlRootAttributes(_profile, writer);
 
-                    WriteItemElement(options, writer, item, user, context, null, deviceId, filter, streamInfo);
+                    WriteItemElement(writer, item, user, context, null, deviceId, filter, streamInfo);
 
                     writer.WriteFullEndElement();
                     //writer.WriteEndDocument();
@@ -127,7 +130,6 @@ namespace Emby.Dlna.Didl
         }
 
         public void WriteItemElement(
-            DlnaOptions options,
             XmlWriter writer,
             BaseItem item,
             User user,
@@ -164,25 +166,23 @@ namespace Emby.Dlna.Didl
             // refID?
             // storeAttribute(itemNode, object, ClassProperties.REF_ID, false);
 
-            var hasMediaSources = item as IHasMediaSources;
-
-            if (hasMediaSources != null)
+            if (item is IHasMediaSources)
             {
                 if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
                 {
-                    AddAudioResource(options, writer, item, deviceId, filter, streamInfo);
+                    AddAudioResource(writer, item, deviceId, filter, streamInfo);
                 }
                 else if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase))
                 {
-                    AddVideoResource(options, writer, item, deviceId, filter, streamInfo);
+                    AddVideoResource(writer, item, deviceId, filter, streamInfo);
                 }
             }
 
-            AddCover(item, context, null, writer);
+            AddCover(item, null, writer);
             writer.WriteFullEndElement();
         }
 
-        private void AddVideoResource(DlnaOptions options, XmlWriter writer, BaseItem video, string deviceId, Filter filter, StreamInfo streamInfo = null)
+        private void AddVideoResource(XmlWriter writer, BaseItem video, string deviceId, Filter filter, StreamInfo streamInfo = null)
         {
             if (streamInfo == null)
             {
@@ -226,7 +226,7 @@ namespace Emby.Dlna.Didl
 
             foreach (var contentFeature in contentFeatureList)
             {
-                AddVideoResource(writer, video, deviceId, filter, contentFeature, streamInfo);
+                AddVideoResource(writer, filter, contentFeature, streamInfo);
             }
 
             var subtitleProfiles = streamInfo.GetSubtitleProfiles(_mediaEncoder, false, _serverAddress, _accessToken);
@@ -283,7 +283,10 @@ namespace Emby.Dlna.Didl
             else
             {
                 writer.WriteStartElement(string.Empty, "res", NS_DIDL);
-                var protocolInfo = string.Format("http-get:*:text/{0}:*", info.Format.ToLowerInvariant());
+                var protocolInfo = string.Format(
+                    CultureInfo.InvariantCulture,
+                    "http-get:*:text/{0}:*",
+                    info.Format.ToLowerInvariant());
                 writer.WriteAttributeString("protocolInfo", protocolInfo);
 
                 writer.WriteString(info.Url);
@@ -293,7 +296,7 @@ namespace Emby.Dlna.Didl
             return true;
         }
 
-        private void AddVideoResource(XmlWriter writer, BaseItem video, string deviceId, Filter filter, string contentFeatures, StreamInfo streamInfo)
+        private void AddVideoResource(XmlWriter writer, Filter filter, string contentFeatures, StreamInfo streamInfo)
         {
             writer.WriteStartElement(string.Empty, "res", NS_DIDL);
 
@@ -335,7 +338,13 @@ namespace Emby.Dlna.Didl
             {
                 if (targetWidth.HasValue && targetHeight.HasValue)
                 {
-                    writer.WriteAttributeString("resolution", string.Format("{0}x{1}", targetWidth.Value, targetHeight.Value));
+                    writer.WriteAttributeString(
+                        "resolution",
+                        string.Format(
+                            CultureInfo.InvariantCulture,
+                            "{0}x{1}",
+                            targetWidth.Value,
+                            targetHeight.Value));
                 }
             }
 
@@ -369,17 +378,19 @@ namespace Emby.Dlna.Didl
                 streamInfo.TargetVideoCodecTag,
                 streamInfo.IsTargetAVC);
 
-            var filename = url.Substring(0, url.IndexOf('?'));
+            var filename = url.Substring(0, url.IndexOf('?', StringComparison.Ordinal));
 
             var mimeType = mediaProfile == null || string.IsNullOrEmpty(mediaProfile.MimeType)
                ? MimeTypes.GetMimeType(filename)
                : mediaProfile.MimeType;
 
-            writer.WriteAttributeString("protocolInfo", string.Format(
-                "http-get:*:{0}:{1}",
-                mimeType,
-                contentFeatures
-                ));
+            writer.WriteAttributeString(
+                "protocolInfo",
+                string.Format(
+                    CultureInfo.InvariantCulture,
+                    "http-get:*:{0}:{1}",
+                    mimeType,
+                    contentFeatures));
 
             writer.WriteString(url);
 
@@ -420,7 +431,10 @@ namespace Emby.Dlna.Didl
                 if (item.ParentIndexNumber.HasValue && item.ParentIndexNumber.Value == 0
                     && season.IndexNumber.HasValue && season.IndexNumber.Value != 0)
                 {
-                    return string.Format(_localization.GetLocalizedString("ValueSpecialEpisodeName"), item.Name);
+                    return string.Format(
+                        CultureInfo.InvariantCulture,
+                        _localization.GetLocalizedString("ValueSpecialEpisodeName"),
+                        item.Name);
                 }
 
                 if (item.IndexNumber.HasValue)
@@ -439,7 +453,7 @@ namespace Emby.Dlna.Didl
             return item.Name;
         }
 
-        private void AddAudioResource(DlnaOptions options, XmlWriter writer, BaseItem audio, string deviceId, Filter filter, StreamInfo streamInfo = null)
+        private void AddAudioResource(XmlWriter writer, BaseItem audio, string deviceId, Filter filter, StreamInfo streamInfo = null)
         {
             writer.WriteStartElement(string.Empty, "res", NS_DIDL);
 
@@ -505,7 +519,7 @@ namespace Emby.Dlna.Didl
                 targetSampleRate,
                 targetAudioBitDepth);
 
-            var filename = url.Substring(0, url.IndexOf('?'));
+            var filename = url.Substring(0, url.IndexOf('?', StringComparison.Ordinal));
 
             var mimeType = mediaProfile == null || string.IsNullOrEmpty(mediaProfile.MimeType)
                 ? MimeTypes.GetMimeType(filename)
@@ -521,11 +535,13 @@ namespace Emby.Dlna.Didl
                 streamInfo.RunTimeTicks ?? 0,
                 streamInfo.TranscodeSeekInfo);
 
-            writer.WriteAttributeString("protocolInfo", string.Format(
-                "http-get:*:{0}:{1}",
-                mimeType,
-                contentFeatures
-                ));
+            writer.WriteAttributeString(
+                "protocolInfo",
+                string.Format(
+                    CultureInfo.InvariantCulture,
+                    "http-get:*:{0}:{1}",
+                    mimeType,
+                    contentFeatures));
 
             writer.WriteString(url);
 
@@ -548,7 +564,7 @@ namespace Emby.Dlna.Didl
 
             var clientId = GetClientId(folder, stubType);
 
-            if (string.Equals(requestedId, "0"))
+            if (string.Equals(requestedId, "0", StringComparison.Ordinal))
             {
                 writer.WriteAttributeString("id", "0");
                 writer.WriteAttributeString("parentID", "-1");
@@ -577,7 +593,7 @@ namespace Emby.Dlna.Didl
 
             AddGeneralProperties(folder, stubType, context, writer, filter);
 
-            AddCover(folder, context, stubType, writer);
+            AddCover(folder, stubType, writer);
 
             writer.WriteFullEndElement();
         }
@@ -610,7 +626,10 @@ namespace Emby.Dlna.Didl
 
             if (playbackPositionTicks > 0)
             {
-                var elementValue = string.Format("BM={0}", Convert.ToInt32(TimeSpan.FromTicks(playbackPositionTicks).TotalSeconds).ToString(_usCulture));
+                var elementValue = string.Format(
+                    CultureInfo.InvariantCulture,
+                    "BM={0}",
+                    Convert.ToInt32(TimeSpan.FromTicks(playbackPositionTicks).TotalSeconds));
                 AddValue(writer, "sec", "dcmInfo", elementValue, secAttribute.Value);
             }
         }
@@ -763,37 +782,37 @@ namespace Emby.Dlna.Didl
 
         private void AddPeople(BaseItem item, XmlWriter writer)
         {
-            //var types = new[]
-            //{
-            //    PersonType.Director,
-            //    PersonType.Writer,
-            //    PersonType.Producer,
-            //    PersonType.Composer,
-            //    "Creator"
-            //};
+            var types = new[]
+            {
+                PersonType.Director,
+                PersonType.Writer,
+                PersonType.Producer,
+                PersonType.Composer,
+                "Creator"
+            };
 
-            //var people = _libraryManager.GetPeople(item);
+            var people = _libraryManager.GetPeople(item);
 
-            //var index = 0;
+            var index = 0;
 
-            //// Seeing some LG models locking up due content with large lists of people
-            //// The actual issue might just be due to processing a more metadata than it can handle
-            //var limit = 6;
+            // Seeing some LG models locking up due content with large lists of people
+            // The actual issue might just be due to processing a more metadata than it can handle
+            var limit = 6;
 
-            //foreach (var actor in people)
-            //{
-            //    var type = types.FirstOrDefault(i => string.Equals(i, actor.Type, StringComparison.OrdinalIgnoreCase) || string.Equals(i, actor.Role, StringComparison.OrdinalIgnoreCase))
-            //        ?? PersonType.Actor;
+            foreach (var actor in people)
+            {
+                var type = types.FirstOrDefault(i => string.Equals(i, actor.Type, StringComparison.OrdinalIgnoreCase) || string.Equals(i, actor.Role, StringComparison.OrdinalIgnoreCase))
+                    ?? PersonType.Actor;
 
-            //    AddValue(writer, "upnp", type.ToLowerInvariant(), actor.Name, NS_UPNP);
+                AddValue(writer, "upnp", type.ToLowerInvariant(), actor.Name, NS_UPNP);
 
-            //    index++;
+                index++;
 
-            //    if (index >= limit)
-            //    {
-            //        break;
-            //    }
-            //}
+                if (index >= limit)
+                {
+                    break;
+                }
+            }
         }
 
         private void AddGeneralProperties(BaseItem item, StubType? itemStubType, BaseItem context, XmlWriter writer, Filter filter)
@@ -870,7 +889,7 @@ namespace Emby.Dlna.Didl
             }
         }
 
-        private void AddCover(BaseItem item, BaseItem context, StubType? stubType, XmlWriter writer)
+        private void AddCover(BaseItem item, StubType? stubType, XmlWriter writer)
         {
             ImageDownloadInfo imageInfo = GetImageInfo(item);
 
@@ -915,17 +934,8 @@ namespace Emby.Dlna.Didl
 
         }
 
-        private void AddEmbeddedImageAsCover(string name, XmlWriter writer)
-        {
-            writer.WriteStartElement("upnp", "albumArtURI", NS_UPNP);
-            writer.WriteAttributeString("dlna", "profileID", NS_DLNA, _profile.AlbumArtPn);
-            writer.WriteString(_serverAddress + "/Dlna/icons/people480.jpg");
-            writer.WriteFullEndElement();
-
-            writer.WriteElementString("upnp", "icon", NS_UPNP, _serverAddress + "/Dlna/icons/people48.jpg");
-        }
-
-        private void AddImageResElement(BaseItem item,
+        private void AddImageResElement(
+            BaseItem item,
             XmlWriter writer,
             int maxWidth,
             int maxHeight,
@@ -951,13 +961,17 @@ namespace Emby.Dlna.Didl
             var contentFeatures = new ContentFeatureBuilder(_profile)
                 .BuildImageHeader(format, width, height, imageInfo.IsDirectStream, org_Pn);
 
-            writer.WriteAttributeString("protocolInfo", string.Format(
-                "http-get:*:{0}:{1}",
-                MimeTypes.GetMimeType("file." + format),
-                contentFeatures
-                ));
+            writer.WriteAttributeString(
+                "protocolInfo",
+                string.Format(
+                    CultureInfo.InvariantCulture,
+                    "http-get:*:{0}:{1}",
+                    MimeTypes.GetMimeType("file." + format),
+                    contentFeatures));
 
-            writer.WriteAttributeString("resolution", string.Format("{0}x{1}", width, height));
+            writer.WriteAttributeString(
+                "resolution",
+                string.Format(CultureInfo.InvariantCulture, "{0}x{1}", width, height));
 
             writer.WriteString(albumartUrlInfo.Url);
 
@@ -1096,7 +1110,9 @@ namespace Emby.Dlna.Didl
 
         private ImageUrlInfo GetImageUrl(ImageDownloadInfo info, int maxWidth, int maxHeight, string format)
         {
-            var url = string.Format("{0}/Items/{1}/Images/{2}/0/{3}/{4}/{5}/{6}/0/0",
+            var url = string.Format(
+                CultureInfo.InvariantCulture,
+                "{0}/Items/{1}/Images/{2}/0/{3}/{4}/{5}/{6}/0/0",
                 _serverAddress,
                 info.ItemId.ToString("N", CultureInfo.InvariantCulture),
                 info.Type,

+ 1 - 1
Emby.Dlna/Didl/StringWriterWithEncoding.cs

@@ -53,6 +53,6 @@ namespace Emby.Dlna.Didl
             _encoding = encoding;
         }
 
-        public override Encoding Encoding => (null == _encoding) ? base.Encoding : _encoding;
+        public override Encoding Encoding => _encoding ?? base.Encoding;
     }
 }

+ 2 - 2
Emby.Dlna/Emby.Dlna.csproj

@@ -15,14 +15,14 @@
     <TargetFramework>netstandard2.1</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
-    <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release'" >true</TreatWarningsAsErrors>
+    <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Debug'" >true</TreatWarningsAsErrors>
   </PropertyGroup>
 
   <!-- Code Analyzers-->
   <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
     <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
     <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
-    <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
+    <!-- <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />-->
     <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
   </ItemGroup>
 

+ 15 - 4
Emby.Dlna/PlayTo/Device.cs

@@ -346,7 +346,12 @@ namespace Emby.Dlna.PlayTo
                 throw new InvalidOperationException("Unable to find service");
             }
 
-            return new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1));
+            return new SsdpHttpClient(_httpClient).SendCommandAsync(
+                Properties.BaseUrl,
+                service,
+                command.Name,
+                avCommands.BuildPost(command, service.ServiceType, 1),
+                cancellationToken: cancellationToken);
         }
 
         public async Task SetPlay(CancellationToken cancellationToken)
@@ -588,8 +593,14 @@ namespace Emby.Dlna.PlayTo
                 return null;
             }
 
-            var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType), false)
-                .ConfigureAwait(false);
+            var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(
+                Properties.BaseUrl,
+                service,
+                command.Name,
+                avCommands.BuildPost(command,
+                service.ServiceType),
+                false,
+                cancellationToken: cancellationToken).ConfigureAwait(false);
 
             if (result == null || result.Document == null)
             {
@@ -599,7 +610,7 @@ namespace Emby.Dlna.PlayTo
             var transportState =
                 result.Document.Descendants(uPnpNamespaces.AvTransport + "GetTransportInfoResponse").Select(i => i.Element("CurrentTransportState")).FirstOrDefault(i => i != null);
 
-            var transportStateValue = transportState == null ? null : transportState.Value;
+            var transportStateValue = transportState?.Value;
 
             if (transportStateValue != null
                 && Enum.TryParse(transportStateValue, true, out TRANSPORTSTATE state))

+ 79 - 71
Emby.Dlna/PlayTo/PlayToController.cs

@@ -27,6 +27,8 @@ namespace Emby.Dlna.PlayTo
 {
     public class PlayToController : ISessionController, IDisposable
     {
+        private static readonly CultureInfo _usCulture = CultureInfo.ReadOnly(new CultureInfo("en-US"));
+
         private Device _device;
         private readonly SessionInfo _session;
         private readonly ISessionManager _sessionManager;
@@ -45,9 +47,10 @@ namespace Emby.Dlna.PlayTo
         private readonly string _serverAddress;
         private readonly string _accessToken;
 
-        public bool IsSessionActive => !_disposed && _device != null;
+        private readonly List<PlaylistItem> _playlist = new List<PlaylistItem>();
+        private int _currentPlaylistIndex;
 
-        public bool SupportsMediaControl => IsSessionActive;
+        private bool _disposed;
 
         public PlayToController(
             SessionInfo session,
@@ -83,18 +86,22 @@ namespace Emby.Dlna.PlayTo
             _mediaEncoder = mediaEncoder;
         }
 
+        public bool IsSessionActive => !_disposed && _device != null;
+
+        public bool SupportsMediaControl => IsSessionActive;
+
         public void Init(Device device)
         {
             _device = device;
             _device.OnDeviceUnavailable = OnDeviceUnavailable;
-            _device.PlaybackStart += _device_PlaybackStart;
-            _device.PlaybackProgress += _device_PlaybackProgress;
-            _device.PlaybackStopped += _device_PlaybackStopped;
-            _device.MediaChanged += _device_MediaChanged;
+            _device.PlaybackStart += OnDevicePlaybackStart;
+            _device.PlaybackProgress += OnDevicePlaybackProgress;
+            _device.PlaybackStopped += DevicePlaybackStopped;
+            _device.MediaChanged += OnDeviceMediaChanged;
 
             _device.Start();
 
-            _deviceDiscovery.DeviceLeft += _deviceDiscovery_DeviceLeft;
+            _deviceDiscovery.DeviceLeft += OnDeviceDiscoveryDeviceLeft;
         }
 
         private void OnDeviceUnavailable()
@@ -110,7 +117,7 @@ namespace Emby.Dlna.PlayTo
             }
         }
 
-        void _deviceDiscovery_DeviceLeft(object sender, GenericEventArgs<UpnpDeviceInfo> e)
+        private void OnDeviceDiscoveryDeviceLeft(object sender, GenericEventArgs<UpnpDeviceInfo> e)
         {
             var info = e.Argument;
 
@@ -125,7 +132,7 @@ namespace Emby.Dlna.PlayTo
             }
         }
 
-        async void _device_MediaChanged(object sender, MediaChangedEventArgs e)
+        private async void OnDeviceMediaChanged(object sender, MediaChangedEventArgs e)
         {
             if (_disposed)
             {
@@ -137,15 +144,15 @@ namespace Emby.Dlna.PlayTo
                 var streamInfo = StreamParams.ParseFromUrl(e.OldMediaInfo.Url, _libraryManager, _mediaSourceManager);
                 if (streamInfo.Item != null)
                 {
-                    var positionTicks = GetProgressPositionTicks(e.OldMediaInfo, streamInfo);
+                    var positionTicks = GetProgressPositionTicks(streamInfo);
 
-                    ReportPlaybackStopped(e.OldMediaInfo, streamInfo, positionTicks);
+                    ReportPlaybackStopped(streamInfo, positionTicks);
                 }
 
                 streamInfo = StreamParams.ParseFromUrl(e.NewMediaInfo.Url, _libraryManager, _mediaSourceManager);
                 if (streamInfo.Item == null) return;
 
-                var newItemProgress = GetProgressInfo(e.NewMediaInfo, streamInfo);
+                var newItemProgress = GetProgressInfo(streamInfo);
 
                 await _sessionManager.OnPlaybackStart(newItemProgress).ConfigureAwait(false);
             }
@@ -155,7 +162,7 @@ namespace Emby.Dlna.PlayTo
             }
         }
 
-        async void _device_PlaybackStopped(object sender, PlaybackStoppedEventArgs e)
+        private async void DevicePlaybackStopped(object sender, PlaybackStoppedEventArgs e)
         {
             if (_disposed)
             {
@@ -168,9 +175,9 @@ namespace Emby.Dlna.PlayTo
 
                 if (streamInfo.Item == null) return;
 
-                var positionTicks = GetProgressPositionTicks(e.MediaInfo, streamInfo);
+                var positionTicks = GetProgressPositionTicks(streamInfo);
 
-                ReportPlaybackStopped(e.MediaInfo, streamInfo, positionTicks);
+                ReportPlaybackStopped(streamInfo, positionTicks);
 
                 var mediaSource = await streamInfo.GetMediaSource(CancellationToken.None).ConfigureAwait(false);
 
@@ -194,7 +201,7 @@ namespace Emby.Dlna.PlayTo
                 }
                 else
                 {
-                    Playlist.Clear();
+                    _playlist.Clear();
                 }
             }
             catch (Exception ex)
@@ -203,7 +210,7 @@ namespace Emby.Dlna.PlayTo
             }
         }
 
-        private async void ReportPlaybackStopped(uBaseObject mediaInfo, StreamParams streamInfo, long? positionTicks)
+        private async void ReportPlaybackStopped(StreamParams streamInfo, long? positionTicks)
         {
             try
             {
@@ -222,7 +229,7 @@ namespace Emby.Dlna.PlayTo
             }
         }
 
-        async void _device_PlaybackStart(object sender, PlaybackStartEventArgs e)
+        private async void OnDevicePlaybackStart(object sender, PlaybackStartEventArgs e)
         {
             if (_disposed)
             {
@@ -235,7 +242,7 @@ namespace Emby.Dlna.PlayTo
 
                 if (info.Item != null)
                 {
-                    var progress = GetProgressInfo(e.MediaInfo, info);
+                    var progress = GetProgressInfo(info);
 
                     await _sessionManager.OnPlaybackStart(progress).ConfigureAwait(false);
                 }
@@ -246,7 +253,7 @@ namespace Emby.Dlna.PlayTo
             }
         }
 
-        async void _device_PlaybackProgress(object sender, PlaybackProgressEventArgs e)
+        private async void OnDevicePlaybackProgress(object sender, PlaybackProgressEventArgs e)
         {
             if (_disposed)
             {
@@ -266,7 +273,7 @@ namespace Emby.Dlna.PlayTo
 
                 if (info.Item != null)
                 {
-                    var progress = GetProgressInfo(e.MediaInfo, info);
+                    var progress = GetProgressInfo(info);
 
                     await _sessionManager.OnPlaybackProgress(progress).ConfigureAwait(false);
                 }
@@ -277,7 +284,7 @@ namespace Emby.Dlna.PlayTo
             }
         }
 
-        private long? GetProgressPositionTicks(uBaseObject mediaInfo, StreamParams info)
+        private long? GetProgressPositionTicks(StreamParams info)
         {
             var ticks = _device.Position.Ticks;
 
@@ -289,13 +296,13 @@ namespace Emby.Dlna.PlayTo
             return ticks;
         }
 
-        private PlaybackStartInfo GetProgressInfo(uBaseObject mediaInfo, StreamParams info)
+        private PlaybackStartInfo GetProgressInfo(StreamParams info)
         {
             return new PlaybackStartInfo
             {
                 ItemId = info.ItemId,
                 SessionId = _session.Id,
-                PositionTicks = GetProgressPositionTicks(mediaInfo, info),
+                PositionTicks = GetProgressPositionTicks(info),
                 IsMuted = _device.IsMuted,
                 IsPaused = _device.IsPaused,
                 MediaSourceId = info.MediaSourceId,
@@ -310,9 +317,7 @@ namespace Emby.Dlna.PlayTo
             };
         }
 
-        #region SendCommands
-
-        public async Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken)
+        public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken)
         {
             _logger.LogDebug("{0} - Received PlayRequest: {1}", this._session.DeviceName, command.PlayCommand);
 
@@ -350,11 +355,12 @@ namespace Emby.Dlna.PlayTo
 
             if (command.PlayCommand == PlayCommand.PlayLast)
             {
-                Playlist.AddRange(playlist);
+                _playlist.AddRange(playlist);
             }
+
             if (command.PlayCommand == PlayCommand.PlayNext)
             {
-                Playlist.AddRange(playlist);
+                _playlist.AddRange(playlist);
             }
 
             if (!command.ControllingUserId.Equals(Guid.Empty))
@@ -363,7 +369,7 @@ namespace Emby.Dlna.PlayTo
                        _session.DeviceName, _session.RemoteEndPoint, user);
             }
 
-            await PlayItems(playlist).ConfigureAwait(false);
+            return PlayItems(playlist, cancellationToken);
         }
 
         private Task SendPlaystateCommand(PlaystateRequest command, CancellationToken cancellationToken)
@@ -371,7 +377,7 @@ namespace Emby.Dlna.PlayTo
             switch (command.Command)
             {
                 case PlaystateCommand.Stop:
-                    Playlist.Clear();
+                    _playlist.Clear();
                     return _device.SetStop(CancellationToken.None);
 
                 case PlaystateCommand.Pause:
@@ -387,10 +393,10 @@ namespace Emby.Dlna.PlayTo
                     return Seek(command.SeekPositionTicks ?? 0);
 
                 case PlaystateCommand.NextTrack:
-                    return SetPlaylistIndex(_currentPlaylistIndex + 1);
+                    return SetPlaylistIndex(_currentPlaylistIndex + 1, cancellationToken);
 
                 case PlaystateCommand.PreviousTrack:
-                    return SetPlaylistIndex(_currentPlaylistIndex - 1);
+                    return SetPlaylistIndex(_currentPlaylistIndex - 1, cancellationToken);
             }
 
             return Task.CompletedTask;
@@ -426,14 +432,6 @@ namespace Emby.Dlna.PlayTo
             return info.IsDirectStream;
         }
 
-        #endregion
-
-        #region Playlist
-
-        private int _currentPlaylistIndex;
-        private readonly List<PlaylistItem> _playlist = new List<PlaylistItem>();
-        private List<PlaylistItem> Playlist => _playlist;
-
         private void AddItemFromId(Guid id, List<BaseItem> list)
         {
             var item = _libraryManager.GetItemById(id);
@@ -451,7 +449,7 @@ namespace Emby.Dlna.PlayTo
                 _dlnaManager.GetDefaultProfile();
 
             var mediaSources = item is IHasMediaSources
-                ? (_mediaSourceManager.GetStaticMediaSources(item, true, user))
+                ? _mediaSourceManager.GetStaticMediaSources(item, true, user)
                 : new List<MediaSourceInfo>();
 
             var playlistItem = GetPlaylistItem(item, mediaSources, profile, _session.DeviceId, mediaSourceId, audioStreamIndex, subtitleStreamIndex);
@@ -459,8 +457,19 @@ namespace Emby.Dlna.PlayTo
 
             playlistItem.StreamUrl = DidlBuilder.NormalizeDlnaMediaUrl(playlistItem.StreamInfo.ToUrl(_serverAddress, _accessToken));
 
-            var itemXml = new DidlBuilder(profile, user, _imageProcessor, _serverAddress, _accessToken, _userDataManager, _localization, _mediaSourceManager, _logger, _mediaEncoder)
-                .GetItemDidl(_config.GetDlnaConfiguration(), item, user, null, _session.DeviceId, new Filter(), playlistItem.StreamInfo);
+            var itemXml = new DidlBuilder(
+                profile,
+                user,
+                _imageProcessor,
+                _serverAddress,
+                _accessToken,
+                _userDataManager,
+                _localization,
+                _mediaSourceManager,
+                _logger,
+                _mediaEncoder,
+                _libraryManager)
+                .GetItemDidl(item, user, null, _session.DeviceId, new Filter(), playlistItem.StreamInfo);
 
             playlistItem.Didl = itemXml;
 
@@ -570,30 +579,31 @@ namespace Emby.Dlna.PlayTo
         /// Plays the items.
         /// </summary>
         /// <param name="items">The items.</param>
-        /// <returns></returns>
-        private async Task<bool> PlayItems(IEnumerable<PlaylistItem> items)
+        /// <param name="cancellationToken">The cancellation token.</param>
+        /// <returns><c>true</c> on success.</returns>
+        private async Task<bool> PlayItems(IEnumerable<PlaylistItem> items, CancellationToken cancellationToken = default)
         {
-            Playlist.Clear();
-            Playlist.AddRange(items);
-            _logger.LogDebug("{0} - Playing {1} items", _session.DeviceName, Playlist.Count);
+            _playlist.Clear();
+            _playlist.AddRange(items);
+            _logger.LogDebug("{0} - Playing {1} items", _session.DeviceName, _playlist.Count);
 
-            await SetPlaylistIndex(0).ConfigureAwait(false);
+            await SetPlaylistIndex(0, cancellationToken).ConfigureAwait(false);
             return true;
         }
 
-        private async Task SetPlaylistIndex(int index)
+        private async Task SetPlaylistIndex(int index, CancellationToken cancellationToken = default)
         {
-            if (index < 0 || index >= Playlist.Count)
+            if (index < 0 || index >= _playlist.Count)
             {
-                Playlist.Clear();
-                await _device.SetStop(CancellationToken.None);
+                _playlist.Clear();
+                await _device.SetStop(cancellationToken).ConfigureAwait(false);
                 return;
             }
 
             _currentPlaylistIndex = index;
-            var currentitem = Playlist[index];
+            var currentitem = _playlist[index];
 
-            await _device.SetAvTransport(currentitem.StreamUrl, GetDlnaHeaders(currentitem), currentitem.Didl, CancellationToken.None);
+            await _device.SetAvTransport(currentitem.StreamUrl, GetDlnaHeaders(currentitem), currentitem.Didl, cancellationToken).ConfigureAwait(false);
 
             var streamInfo = currentitem.StreamInfo;
             if (streamInfo.StartPositionTicks > 0 && EnableClientSideSeek(streamInfo))
@@ -602,10 +612,7 @@ namespace Emby.Dlna.PlayTo
             }
         }
 
-        #endregion
-
-        private bool _disposed;
-
+        /// <inheritdoc />
         public void Dispose()
         {
             Dispose(true);
@@ -624,19 +631,17 @@ namespace Emby.Dlna.PlayTo
                 _device.Dispose();
             }
 
-            _device.PlaybackStart -= _device_PlaybackStart;
-            _device.PlaybackProgress -= _device_PlaybackProgress;
-            _device.PlaybackStopped -= _device_PlaybackStopped;
-            _device.MediaChanged -= _device_MediaChanged;
-            _deviceDiscovery.DeviceLeft -= _deviceDiscovery_DeviceLeft;
+            _device.PlaybackStart -= OnDevicePlaybackStart;
+            _device.PlaybackProgress -= OnDevicePlaybackProgress;
+            _device.PlaybackStopped -= DevicePlaybackStopped;
+            _device.MediaChanged -= OnDeviceMediaChanged;
+            _deviceDiscovery.DeviceLeft -= OnDeviceDiscoveryDeviceLeft;
             _device.OnDeviceUnavailable = null;
             _device = null;
 
             _disposed = true;
         }
 
-        private static readonly CultureInfo _usCulture = CultureInfo.ReadOnly(new CultureInfo("en-US"));
-
         private Task SendGeneralCommand(GeneralCommand command, CancellationToken cancellationToken)
         {
             if (Enum.TryParse(command.Name, true, out GeneralCommandType commandType))
@@ -713,7 +718,7 @@ namespace Emby.Dlna.PlayTo
 
                 if (info.Item != null)
                 {
-                    var newPosition = GetProgressPositionTicks(media, info) ?? 0;
+                    var newPosition = GetProgressPositionTicks(info) ?? 0;
 
                     var user = !_session.UserId.Equals(Guid.Empty) ? _userManager.GetUserById(_session.UserId) : null;
                     var newItem = CreatePlaylistItem(info.Item, user, newPosition, info.MediaSourceId, newIndex, info.SubtitleStreamIndex);
@@ -738,7 +743,7 @@ namespace Emby.Dlna.PlayTo
 
                 if (info.Item != null)
                 {
-                    var newPosition = GetProgressPositionTicks(media, info) ?? 0;
+                    var newPosition = GetProgressPositionTicks(info) ?? 0;
 
                     var user = !_session.UserId.Equals(Guid.Empty) ? _userManager.GetUserById(_session.UserId) : null;
                     var newItem = CreatePlaylistItem(info.Item, user, newPosition, info.MediaSourceId, info.AudioStreamIndex, newIndex);
@@ -852,8 +857,11 @@ namespace Emby.Dlna.PlayTo
                     return request;
                 }
 
-                var index = url.IndexOf('?');
-                if (index == -1) return request;
+                var index = url.IndexOf('?', StringComparison.Ordinal);
+                if (index == -1)
+                {
+                    return request;
+                }
 
                 var query = url.Substring(index + 1);
                 Dictionary<string, string> values = QueryHelpers.ParseQuery(query).ToDictionary(kv => kv.Key, kv => kv.Value.ToString());

+ 5 - 1
Emby.Dlna/PlayTo/PlayToManager.cs

@@ -23,7 +23,7 @@ using Microsoft.Extensions.Logging;
 
 namespace Emby.Dlna.PlayTo
 {
-    public class PlayToManager : IDisposable
+    public sealed class PlayToManager : IDisposable
     {
         private readonly ILogger _logger;
         private readonly ISessionManager _sessionManager;
@@ -231,6 +231,7 @@ namespace Emby.Dlna.PlayTo
             }
         }
 
+        /// <inheritdoc />
         public void Dispose()
         {
             _deviceDiscovery.DeviceDiscovered -= OnDeviceDiscoveryDeviceDiscovered;
@@ -244,6 +245,9 @@ namespace Emby.Dlna.PlayTo
 
             }
 
+            _sessionLock.Dispose();
+            _disposeCancellationTokenSource.Dispose();
+
             _disposed = true;
         }
     }

+ 3 - 7
Emby.Dlna/PlayTo/SsdpHttpClient.cs

@@ -32,18 +32,15 @@ namespace Emby.Dlna.PlayTo
             DeviceService service,
             string command,
             string postData,
-            bool logRequest = true,
-            string header = null)
+            string header = null,
+            CancellationToken cancellationToken = default)
         {
-            var cancellationToken = CancellationToken.None;
-
             var url = NormalizeServiceUrl(baseUrl, service.ControlUrl);
             using (var response = await PostSoapDataAsync(
                 url,
                 $"\"{service.ServiceType}#{command}\"",
                 postData,
                 header,
-                logRequest,
                 cancellationToken)
                 .ConfigureAwait(false))
             using (var stream = response.Content)
@@ -63,7 +60,7 @@ namespace Emby.Dlna.PlayTo
                 return serviceUrl;
             }
 
-            if (!serviceUrl.StartsWith("/"))
+            if (!serviceUrl.StartsWith("/", StringComparison.Ordinal))
             {
                 serviceUrl = "/" + serviceUrl;
             }
@@ -127,7 +124,6 @@ namespace Emby.Dlna.PlayTo
             string soapAction,
             string postData,
             string header,
-            bool logRequest,
             CancellationToken cancellationToken)
         {
             if (soapAction[0] != '\"')

+ 6 - 6
Emby.Notifications/Api/NotificationsService.cs

@@ -134,19 +134,19 @@ namespace Emby.Notifications.Api
             _userManager = userManager;
         }
 
-        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request")]
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public object Get(GetNotificationTypes request)
         {
             return _notificationManager.GetNotificationTypes();
         }
 
-        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request")]
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public object Get(GetNotificationServices request)
         {
             return _notificationManager.GetNotificationServices().ToList();
         }
 
-        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request")]
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public object Get(GetNotificationsSummary request)
         {
             return new NotificationsSummary
@@ -170,17 +170,17 @@ namespace Emby.Notifications.Api
             return _notificationManager.SendNotification(notification, CancellationToken.None);
         }
 
-        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request")]
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public void Post(MarkRead request)
         {
         }
 
-        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request")]
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public void Post(MarkUnread request)
         {
         }
 
-        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request")]
+        [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "request", Justification = "Required for ServiceStack")]
         public object Get(GetNotifications request)
         {
             return new NotificationResult();