diff options
Diffstat (limited to 'Emby.Dlna')
| -rw-r--r-- | Emby.Dlna/Configuration/DlnaOptions.cs | 4 | ||||
| -rw-r--r-- | Emby.Dlna/ContentDirectory/ContentDirectoryService.cs | 4 | ||||
| -rw-r--r-- | Emby.Dlna/ContentDirectory/ControlHandler.cs | 23 | ||||
| -rw-r--r-- | Emby.Dlna/ContentDirectory/ServerItem.cs | 2 | ||||
| -rw-r--r-- | Emby.Dlna/ControlResponse.cs | 6 | ||||
| -rw-r--r-- | Emby.Dlna/Didl/DidlBuilder.cs | 2 | ||||
| -rw-r--r-- | Emby.Dlna/DlnaManager.cs | 70 | ||||
| -rw-r--r-- | Emby.Dlna/Emby.Dlna.csproj | 7 | ||||
| -rw-r--r-- | Emby.Dlna/EventSubscriptionResponse.cs | 6 | ||||
| -rw-r--r-- | Emby.Dlna/Eventing/DlnaEventManager.cs | 18 | ||||
| -rw-r--r-- | Emby.Dlna/Main/DlnaEntryPoint.cs | 13 | ||||
| -rw-r--r-- | Emby.Dlna/PlayTo/Device.cs | 57 | ||||
| -rw-r--r-- | Emby.Dlna/PlayTo/MediaChangedEventArgs.cs | 10 | ||||
| -rw-r--r-- | Emby.Dlna/PlayTo/PlayToController.cs | 41 | ||||
| -rw-r--r-- | Emby.Dlna/PlayTo/PlayToManager.cs | 4 | ||||
| -rw-r--r-- | Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs | 7 | ||||
| -rw-r--r-- | Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs | 7 | ||||
| -rw-r--r-- | Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs | 7 | ||||
| -rw-r--r-- | Emby.Dlna/Service/BaseControlHandler.cs | 8 | ||||
| -rw-r--r-- | Emby.Dlna/Service/ControlErrorHandler.cs | 6 |
20 files changed, 179 insertions, 123 deletions
diff --git a/Emby.Dlna/Configuration/DlnaOptions.cs b/Emby.Dlna/Configuration/DlnaOptions.cs index 5ceeb55300..91fac4bef5 100644 --- a/Emby.Dlna/Configuration/DlnaOptions.cs +++ b/Emby.Dlna/Configuration/DlnaOptions.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 namespace Emby.Dlna.Configuration @@ -74,7 +72,7 @@ namespace Emby.Dlna.Configuration /// <summary> /// Gets or sets the default user account that the dlna server uses. /// </summary> - public string DefaultUserId { get; set; } + public string? DefaultUserId { get; set; } /// <summary> /// Gets or sets a value indicating whether playTo device profiles should be created. diff --git a/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs b/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs index 7b8c504409..9020dea994 100644 --- a/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs +++ b/Emby.Dlna/ContentDirectory/ContentDirectoryService.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; @@ -140,7 +138,7 @@ namespace Emby.Dlna.ContentDirectory /// </summary> /// <param name="profile">The <see cref="DeviceProfile"/>.</param> /// <returns>The <see cref="User"/>.</returns> - private User GetUser(DeviceProfile profile) + private User? GetUser(DeviceProfile profile) { if (!string.IsNullOrEmpty(profile.UserId)) { diff --git a/Emby.Dlna/ContentDirectory/ControlHandler.cs b/Emby.Dlna/ContentDirectory/ControlHandler.cs index 27c5b22680..ac336e5dcc 100644 --- a/Emby.Dlna/ContentDirectory/ControlHandler.cs +++ b/Emby.Dlna/ContentDirectory/ControlHandler.cs @@ -288,21 +288,14 @@ namespace Emby.Dlna.ContentDirectory /// <returns>The xml feature list.</returns> private static string WriteFeatureListXml() { - // TODO: clean this up - var builder = new StringBuilder(); - - builder.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); - builder.Append("<Features xmlns=\"urn:schemas-upnp-org:av:avs\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:schemas-upnp-org:av:avs http://www.upnp.org/schemas/av/avs.xsd\">"); - - builder.Append("<Feature name=\"samsung.com_BASICVIEW\" version=\"1\">"); - builder.Append("<container id=\"I\" type=\"object.item.imageItem\"/>"); - builder.Append("<container id=\"A\" type=\"object.item.audioItem\"/>"); - builder.Append("<container id=\"V\" type=\"object.item.videoItem\"/>"); - builder.Append("</Feature>"); - - builder.Append("</Features>"); - - return builder.ToString(); + return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + + "<Features xmlns=\"urn:schemas-upnp-org:av:avs\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:schemas-upnp-org:av:avs http://www.upnp.org/schemas/av/avs.xsd\">" + + "<Feature name=\"samsung.com_BASICVIEW\" version=\"1\">" + + "<container id=\"I\" type=\"object.item.imageItem\"/>" + + "<container id=\"A\" type=\"object.item.audioItem\"/>" + + "<container id=\"V\" type=\"object.item.videoItem\"/>" + + "</Feature>" + + "</Features>"; } /// <summary> diff --git a/Emby.Dlna/ContentDirectory/ServerItem.cs b/Emby.Dlna/ContentDirectory/ServerItem.cs index 34244000c1..ff30e6e4af 100644 --- a/Emby.Dlna/ContentDirectory/ServerItem.cs +++ b/Emby.Dlna/ContentDirectory/ServerItem.cs @@ -17,7 +17,7 @@ namespace Emby.Dlna.ContentDirectory { Item = item; - if (item is IItemByName && !(item is Folder)) + if (item is IItemByName && item is not Folder) { StubType = Dlna.ContentDirectory.StubType.Folder; } diff --git a/Emby.Dlna/ControlResponse.cs b/Emby.Dlna/ControlResponse.cs index a7f2d4a73b..8b09588424 100644 --- a/Emby.Dlna/ControlResponse.cs +++ b/Emby.Dlna/ControlResponse.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System.Collections.Generic; @@ -8,9 +6,11 @@ namespace Emby.Dlna { public class ControlResponse { - public ControlResponse() + public ControlResponse(string xml, bool isSuccessful) { Headers = new Dictionary<string, string>(); + Xml = xml; + IsSuccessful = isSuccessful; } public IDictionary<string, string> Headers { get; } diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs index 2982ce97e1..c000784997 100644 --- a/Emby.Dlna/Didl/DidlBuilder.cs +++ b/Emby.Dlna/Didl/DidlBuilder.cs @@ -748,7 +748,7 @@ namespace Emby.Dlna.Didl AddValue(writer, "upnp", "publisher", studio, NsUpnp); } - if (!(item is Folder)) + if (item is not Folder) { if (filter.Contains("dc:description")) { diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs index a1b1067040..af70793ccf 100644 --- a/Emby.Dlna/DlnaManager.cs +++ b/Emby.Dlna/DlnaManager.cs @@ -1,7 +1,4 @@ -#nullable disable - #pragma warning disable CS1591 - using System; using System.Collections.Generic; using System.Globalization; @@ -14,9 +11,9 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using Emby.Dlna.Profiles; using Emby.Dlna.Server; +using Jellyfin.Extensions.Json; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Json; using MediaBrowser.Controller; using MediaBrowser.Controller.Dlna; using MediaBrowser.Controller.Drawing; @@ -96,12 +93,14 @@ namespace Emby.Dlna } } + /// <inheritdoc /> public DeviceProfile GetDefaultProfile() { return new DefaultProfile(); } - public DeviceProfile GetProfile(DeviceIdentification deviceInfo) + /// <inheritdoc /> + public DeviceProfile? GetProfile(DeviceIdentification deviceInfo) { if (deviceInfo == null) { @@ -111,13 +110,13 @@ namespace Emby.Dlna var profile = GetProfiles() .FirstOrDefault(i => i.Identification != null && IsMatch(deviceInfo, i.Identification)); - if (profile != null) + if (profile == null) { - _logger.LogDebug("Found matching device profile: {ProfileName}", profile.Name); + LogUnmatchedProfile(deviceInfo); } else { - LogUnmatchedProfile(deviceInfo); + _logger.LogDebug("Found matching device profile: {ProfileName}", profile.Name); } return profile; @@ -187,7 +186,8 @@ namespace Emby.Dlna } } - public DeviceProfile GetProfile(IHeaderDictionary headers) + /// <inheritdoc /> + public DeviceProfile? GetProfile(IHeaderDictionary headers) { if (headers == null) { @@ -195,15 +195,13 @@ namespace Emby.Dlna } var profile = GetProfiles().FirstOrDefault(i => i.Identification != null && IsMatch(headers, i.Identification)); - - if (profile != null) + if (profile == null) { - _logger.LogDebug("Found matching device profile: {0}", profile.Name); + _logger.LogDebug("No matching device profile found. {@Headers}", headers); } else { - var headerString = string.Join(", ", headers.Select(i => string.Format(CultureInfo.InvariantCulture, "{0}={1}", i.Key, i.Value))); - _logger.LogDebug("No matching device profile found. {0}", headerString); + _logger.LogDebug("Found matching device profile: {0}", profile.Name); } return profile; @@ -253,19 +251,19 @@ namespace Emby.Dlna return xmlFies .Select(i => ParseProfileFile(i, type)) .Where(i => i != null) - .ToList(); + .ToList()!; // We just filtered out all the nulls } catch (IOException) { - return new List<DeviceProfile>(); + return Array.Empty<DeviceProfile>(); } } - private DeviceProfile ParseProfileFile(string path, DeviceProfileType type) + private DeviceProfile? ParseProfileFile(string path, DeviceProfileType type) { lock (_profiles) { - if (_profiles.TryGetValue(path, out Tuple<InternalProfileInfo, DeviceProfile> profileTuple)) + if (_profiles.TryGetValue(path, out Tuple<InternalProfileInfo, DeviceProfile>? profileTuple)) { return profileTuple.Item2; } @@ -293,7 +291,8 @@ namespace Emby.Dlna } } - public DeviceProfile GetProfile(string id) + /// <inheritdoc /> + public DeviceProfile? GetProfile(string id) { if (string.IsNullOrEmpty(id)) { @@ -322,6 +321,7 @@ namespace Emby.Dlna } } + /// <inheritdoc /> public IEnumerable<DeviceProfileInfo> GetProfileInfos() { return GetProfileInfosInternal().Select(i => i.Info); @@ -329,17 +329,14 @@ namespace Emby.Dlna private InternalProfileInfo GetInternalProfileInfo(FileSystemMetadata file, DeviceProfileType type) { - return new InternalProfileInfo - { - Path = file.FullName, - - Info = new DeviceProfileInfo + return new InternalProfileInfo( + new DeviceProfileInfo { Id = file.FullName.ToLowerInvariant().GetMD5().ToString("N", CultureInfo.InvariantCulture), Name = _fileSystem.GetFileNameWithoutExtension(file), Type = type - } - }; + }, + file.FullName); } private async Task ExtractSystemProfilesAsync() @@ -359,7 +356,8 @@ namespace Emby.Dlna systemProfilesPath, Path.GetFileName(name.AsSpan()).Slice(namespaceName.Length)); - using (var stream = _assembly.GetManifestResourceStream(name)) + // The stream should exist as we just got its name from GetManifestResourceNames + using (var stream = _assembly.GetManifestResourceStream(name)!) { var fileInfo = _fileSystem.GetFileInfo(path); @@ -380,6 +378,7 @@ namespace Emby.Dlna Directory.CreateDirectory(UserProfilesPath); } + /// <inheritdoc /> public void DeleteProfile(string id) { var info = GetProfileInfosInternal().First(i => string.Equals(id, i.Info.Id, StringComparison.OrdinalIgnoreCase)); @@ -397,6 +396,7 @@ namespace Emby.Dlna } } + /// <inheritdoc /> public void CreateProfile(DeviceProfile profile) { profile = ReserializeProfile(profile); @@ -412,6 +412,7 @@ namespace Emby.Dlna SaveProfile(profile, path, DeviceProfileType.User); } + /// <inheritdoc /> public void UpdateProfile(DeviceProfile profile) { profile = ReserializeProfile(profile); @@ -470,9 +471,11 @@ namespace Emby.Dlna var json = JsonSerializer.Serialize(profile, _jsonOptions); - return JsonSerializer.Deserialize<DeviceProfile>(json, _jsonOptions); + // Output can't be null if the input isn't null + return JsonSerializer.Deserialize<DeviceProfile>(json, _jsonOptions)!; } + /// <inheritdoc /> public string GetServerDescriptionXml(IHeaderDictionary headers, string serverUuId, string serverAddress) { var profile = GetDefaultProfile(); @@ -482,6 +485,7 @@ namespace Emby.Dlna return new DescriptionXmlBuilder(profile, serverUuId, serverAddress, _appHost.FriendlyName, serverId).GetXml(); } + /// <inheritdoc /> public ImageStream GetIcon(string filename) { var format = filename.EndsWith(".png", StringComparison.OrdinalIgnoreCase) @@ -499,9 +503,15 @@ namespace Emby.Dlna private class InternalProfileInfo { - internal DeviceProfileInfo Info { get; set; } + internal InternalProfileInfo(DeviceProfileInfo info, string path) + { + Info = info; + Path = path; + } + + internal DeviceProfileInfo Info { get; } - internal string Path { get; set; } + internal string Path { get; } } } diff --git a/Emby.Dlna/Emby.Dlna.csproj b/Emby.Dlna/Emby.Dlna.csproj index a40578e403..970c16d2e6 100644 --- a/Emby.Dlna/Emby.Dlna.csproj +++ b/Emby.Dlna/Emby.Dlna.csproj @@ -20,8 +20,7 @@ <TargetFramework>net5.0</TargetFramework> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> <GenerateDocumentationFile>true</GenerateDocumentationFile> - <TreatWarningsAsErrors>true</TreatWarningsAsErrors> - <Nullable>enable</Nullable> + <AnalysisMode>AllDisabledByDefault</AnalysisMode> </PropertyGroup> <!-- Code Analyzers--> @@ -31,10 +30,6 @@ <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" /> </ItemGroup> - <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> - <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> - </PropertyGroup> - <ItemGroup> <EmbeddedResource Include="Images\logo120.jpg" /> <EmbeddedResource Include="Images\logo120.png" /> diff --git a/Emby.Dlna/EventSubscriptionResponse.cs b/Emby.Dlna/EventSubscriptionResponse.cs index 8c82dcbf68..635d2c47a1 100644 --- a/Emby.Dlna/EventSubscriptionResponse.cs +++ b/Emby.Dlna/EventSubscriptionResponse.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System.Collections.Generic; @@ -8,8 +6,10 @@ namespace Emby.Dlna { public class EventSubscriptionResponse { - public EventSubscriptionResponse() + public EventSubscriptionResponse(string content, string contentType) { + Content = content; + ContentType = contentType; Headers = new Dictionary<string, string>(); } diff --git a/Emby.Dlna/Eventing/DlnaEventManager.cs b/Emby.Dlna/Eventing/DlnaEventManager.cs index 2e672b886b..3c91360904 100644 --- a/Emby.Dlna/Eventing/DlnaEventManager.cs +++ b/Emby.Dlna/Eventing/DlnaEventManager.cs @@ -51,11 +51,7 @@ namespace Emby.Dlna.Eventing return GetEventSubscriptionResponse(subscriptionId, requestedTimeoutString, timeoutSeconds); } - return new EventSubscriptionResponse - { - Content = string.Empty, - ContentType = "text/plain" - }; + return new EventSubscriptionResponse(string.Empty, "text/plain"); } public EventSubscriptionResponse CreateEventSubscription(string notificationType, string requestedTimeoutString, string callbackUrl) @@ -103,20 +99,12 @@ namespace Emby.Dlna.Eventing _subscriptions.TryRemove(subscriptionId, out _); - return new EventSubscriptionResponse - { - Content = string.Empty, - ContentType = "text/plain" - }; + return new EventSubscriptionResponse(string.Empty, "text/plain"); } private EventSubscriptionResponse GetEventSubscriptionResponse(string subscriptionId, string requestedTimeoutString, int timeoutSeconds) { - var response = new EventSubscriptionResponse - { - Content = string.Empty, - ContentType = "text/plain" - }; + var response = new EventSubscriptionResponse(string.Empty, "text/plain"); response.Headers["SID"] = subscriptionId; response.Headers["TIMEOUT"] = string.IsNullOrEmpty(requestedTimeoutString) ? ("SECOND-" + timeoutSeconds.ToString(_usCulture)) : requestedTimeoutString; diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs index 0309926abb..5d252d8dc4 100644 --- a/Emby.Dlna/Main/DlnaEntryPoint.cs +++ b/Emby.Dlna/Main/DlnaEntryPoint.cs @@ -27,11 +27,9 @@ using MediaBrowser.Controller.TV; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Net; -using MediaBrowser.Model.System; using Microsoft.Extensions.Logging; using Rssdp; using Rssdp.Infrastructure; -using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; namespace Emby.Dlna.Main { @@ -204,8 +202,8 @@ namespace Emby.Dlna.Main { if (_communicationsServer == null) { - var enableMultiSocketBinding = OperatingSystem.Id == OperatingSystemId.Windows || - OperatingSystem.Id == OperatingSystemId.Linux; + var enableMultiSocketBinding = OperatingSystem.IsWindows() || + OperatingSystem.IsLinux(); _communicationsServer = new SsdpCommunicationsServer(_socketFactory, _networkManager, _logger, enableMultiSocketBinding) { @@ -268,7 +266,12 @@ namespace Emby.Dlna.Main try { - _publisher = new SsdpDevicePublisher(_communicationsServer, _networkManager, OperatingSystem.Name, Environment.OSVersion.VersionString, _config.GetDlnaConfiguration().SendOnlyMatchedHost) + _publisher = new SsdpDevicePublisher( + _communicationsServer, + _networkManager, + MediaBrowser.Common.System.OperatingSystem.Name, + Environment.OSVersion.VersionString, + _config.GetDlnaConfiguration().SendOnlyMatchedHost) { LogFunction = LogMessage, SupportPnpRootDevice = false diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs index 5fa1fd5896..11fcd81cff 100644 --- a/Emby.Dlna/PlayTo/Device.cs +++ b/Emby.Dlna/PlayTo/Device.cs @@ -370,6 +370,42 @@ namespace Emby.Dlna.PlayTo RestartTimer(true); } + /* + * SetNextAvTransport is used to specify to the DLNA device what is the next track to play. + * Without that information, the next track command on the device does not work. + */ + public async Task SetNextAvTransport(string url, string header, string metaData, CancellationToken cancellationToken = default) + { + var avCommands = await GetAVProtocolAsync(cancellationToken).ConfigureAwait(false); + + url = url.Replace("&", "&", StringComparison.Ordinal); + + _logger.LogDebug("{PropertyName} - SetNextAvTransport Uri: {Url} DlnaHeaders: {Header}", Properties.Name, url, header); + + var command = avCommands.ServiceActions.FirstOrDefault(c => string.Equals(c.Name, "SetNextAVTransportURI", StringComparison.OrdinalIgnoreCase)); + if (command == null) + { + return; + } + + var dictionary = new Dictionary<string, string> + { + { "NextURI", url }, + { "NextURIMetaData", CreateDidlMeta(metaData) } + }; + + var service = GetAvTransportService(); + + if (service == null) + { + throw new InvalidOperationException("Unable to find service"); + } + + var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary); + await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header, cancellationToken) + .ConfigureAwait(false); + } + private static string CreateDidlMeta(string value) { if (string.IsNullOrEmpty(value)) @@ -1224,10 +1260,7 @@ namespace Emby.Dlna.PlayTo return; } - PlaybackStart?.Invoke(this, new PlaybackStartEventArgs - { - MediaInfo = mediaInfo - }); + PlaybackStart?.Invoke(this, new PlaybackStartEventArgs(mediaInfo)); } private void OnPlaybackProgress(UBaseObject mediaInfo) @@ -1237,27 +1270,17 @@ namespace Emby.Dlna.PlayTo return; } - PlaybackProgress?.Invoke(this, new PlaybackProgressEventArgs - { - MediaInfo = mediaInfo - }); + PlaybackProgress?.Invoke(this, new PlaybackProgressEventArgs(mediaInfo)); } private void OnPlaybackStop(UBaseObject mediaInfo) { - PlaybackStopped?.Invoke(this, new PlaybackStoppedEventArgs - { - MediaInfo = mediaInfo - }); + PlaybackStopped?.Invoke(this, new PlaybackStoppedEventArgs(mediaInfo)); } private void OnMediaChanged(UBaseObject old, UBaseObject newMedia) { - MediaChanged?.Invoke(this, new MediaChangedEventArgs - { - OldMediaInfo = old, - NewMediaInfo = newMedia - }); + MediaChanged?.Invoke(this, new MediaChangedEventArgs(old, newMedia)); } /// <inheritdoc /> diff --git a/Emby.Dlna/PlayTo/MediaChangedEventArgs.cs b/Emby.Dlna/PlayTo/MediaChangedEventArgs.cs index 2bc4d8cc24..0f7a524d62 100644 --- a/Emby.Dlna/PlayTo/MediaChangedEventArgs.cs +++ b/Emby.Dlna/PlayTo/MediaChangedEventArgs.cs @@ -1,6 +1,4 @@ -#nullable disable - -#pragma warning disable CS1591 +#pragma warning disable CS1591 using System; @@ -8,6 +6,12 @@ namespace Emby.Dlna.PlayTo { public class MediaChangedEventArgs : EventArgs { + public MediaChangedEventArgs(UBaseObject oldMediaInfo, UBaseObject newMediaInfo) + { + OldMediaInfo = oldMediaInfo; + NewMediaInfo = newMediaInfo; + } + public UBaseObject OldMediaInfo { get; set; } public UBaseObject NewMediaInfo { get; set; } diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs index 1e6a5fadbf..0e49fd2c02 100644 --- a/Emby.Dlna/PlayTo/PlayToController.cs +++ b/Emby.Dlna/PlayTo/PlayToController.cs @@ -104,6 +104,22 @@ namespace Emby.Dlna.PlayTo _deviceDiscovery.DeviceLeft += OnDeviceDiscoveryDeviceLeft; } + /* + * Send a message to the DLNA device to notify what is the next track in the playlist. + */ + private async Task SendNextTrackMessage(int currentPlayListItemIndex, CancellationToken cancellationToken) + { + if (currentPlayListItemIndex >= 0 && currentPlayListItemIndex < _playlist.Count - 1) + { + // The current playing item is indeed in the play list and we are not yet at the end of the playlist. + var nextItemIndex = currentPlayListItemIndex + 1; + var nextItem = _playlist[nextItemIndex]; + + // Send the SetNextAvTransport message. + await _device.SetNextAvTransport(nextItem.StreamUrl, GetDlnaHeaders(nextItem), nextItem.Didl, cancellationToken).ConfigureAwait(false); + } + } + private void OnDeviceUnavailable() { try @@ -158,6 +174,15 @@ namespace Emby.Dlna.PlayTo var newItemProgress = GetProgressInfo(streamInfo); await _sessionManager.OnPlaybackStart(newItemProgress).ConfigureAwait(false); + + // Send a message to the DLNA device to notify what is the next track in the playlist. + var currentItemIndex = _playlist.FindIndex(item => item.StreamInfo.ItemId == streamInfo.ItemId); + if (currentItemIndex >= 0) + { + _currentPlaylistIndex = currentItemIndex; + } + + await SendNextTrackMessage(currentItemIndex, CancellationToken.None); } catch (Exception ex) { @@ -427,6 +452,11 @@ namespace Emby.Dlna.PlayTo var newItem = CreatePlaylistItem(info.Item, user, newPosition, info.MediaSourceId, info.AudioStreamIndex, info.SubtitleStreamIndex); await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl, CancellationToken.None).ConfigureAwait(false); + + // Send a message to the DLNA device to notify what is the next track in the play list. + var newItemIndex = _playlist.FindIndex(item => item.StreamUrl == newItem.StreamUrl); + await SendNextTrackMessage(newItemIndex, CancellationToken.None); + return; } @@ -625,6 +655,9 @@ namespace Emby.Dlna.PlayTo await _device.SetAvTransport(currentitem.StreamUrl, GetDlnaHeaders(currentitem), currentitem.Didl, cancellationToken).ConfigureAwait(false); + // Send a message to the DLNA device to notify what is the next track in the play list. + await SendNextTrackMessage(index, cancellationToken); + var streamInfo = currentitem.StreamInfo; if (streamInfo.StartPositionTicks > 0 && EnableClientSideSeek(streamInfo)) { @@ -738,6 +771,10 @@ namespace Emby.Dlna.PlayTo await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl, CancellationToken.None).ConfigureAwait(false); + // Send a message to the DLNA device to notify what is the next track in the play list. + var newItemIndex = _playlist.FindIndex(item => item.StreamUrl == newItem.StreamUrl); + await SendNextTrackMessage(newItemIndex, CancellationToken.None); + if (EnableClientSideSeek(newItem.StreamInfo)) { await SeekAfterTransportChange(newPosition, CancellationToken.None).ConfigureAwait(false); @@ -763,6 +800,10 @@ namespace Emby.Dlna.PlayTo await _device.SetAvTransport(newItem.StreamUrl, GetDlnaHeaders(newItem), newItem.Didl, CancellationToken.None).ConfigureAwait(false); + // Send a message to the DLNA device to notify what is the next track in the play list. + var newItemIndex = _playlist.FindIndex(item => item.StreamUrl == newItem.StreamUrl); + await SendNextTrackMessage(newItemIndex, CancellationToken.None); + if (EnableClientSideSeek(newItem.StreamInfo) && newPosition > 0) { await SeekAfterTransportChange(newPosition, CancellationToken.None).ConfigureAwait(false); diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs index 35bf5927c4..7927f5f8f9 100644 --- a/Emby.Dlna/PlayTo/PlayToManager.cs +++ b/Emby.Dlna/PlayTo/PlayToManager.cs @@ -173,7 +173,9 @@ namespace Emby.Dlna.PlayTo uuid = uri.ToString().GetMD5().ToString("N", CultureInfo.InvariantCulture); } - var sessionInfo = _sessionManager.LogSessionActivity("DLNA", _appHost.ApplicationVersionString, uuid, null, uri.OriginalString, null); + var sessionInfo = await _sessionManager + .LogSessionActivity("DLNA", _appHost.ApplicationVersionString, uuid, null, uri.OriginalString, null) + .ConfigureAwait(false); var controller = sessionInfo.SessionControllers.OfType<PlayToController>().FirstOrDefault(); diff --git a/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs b/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs index c7d2b28df8..c95d8b1e84 100644 --- a/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs +++ b/Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; @@ -8,6 +6,11 @@ namespace Emby.Dlna.PlayTo { public class PlaybackProgressEventArgs : EventArgs { + public PlaybackProgressEventArgs(UBaseObject mediaInfo) + { + MediaInfo = mediaInfo; + } + public UBaseObject MediaInfo { get; set; } } } diff --git a/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs b/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs index f8a14f411f..619c861ed9 100644 --- a/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs +++ b/Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; @@ -8,6 +6,11 @@ namespace Emby.Dlna.PlayTo { public class PlaybackStartEventArgs : EventArgs { + public PlaybackStartEventArgs(UBaseObject mediaInfo) + { + MediaInfo = mediaInfo; + } + public UBaseObject MediaInfo { get; set; } } } diff --git a/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs b/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs index 6661f92ac7..d0ec250591 100644 --- a/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs +++ b/Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs @@ -1,5 +1,3 @@ -#nullable disable - #pragma warning disable CS1591 using System; @@ -8,6 +6,11 @@ namespace Emby.Dlna.PlayTo { public class PlaybackStoppedEventArgs : EventArgs { + public PlaybackStoppedEventArgs(UBaseObject mediaInfo) + { + MediaInfo = mediaInfo; + } + public UBaseObject MediaInfo { get; set; } } } diff --git a/Emby.Dlna/Service/BaseControlHandler.cs b/Emby.Dlna/Service/BaseControlHandler.cs index 904c23d997..581e4a2861 100644 --- a/Emby.Dlna/Service/BaseControlHandler.cs +++ b/Emby.Dlna/Service/BaseControlHandler.cs @@ -6,9 +6,9 @@ using System.IO; using System.Text; using System.Threading.Tasks; using System.Xml; +using Diacritics.Extensions; using Emby.Dlna.Didl; using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Extensions; using Microsoft.Extensions.Logging; namespace Emby.Dlna.Service @@ -95,11 +95,7 @@ namespace Emby.Dlna.Service var xml = builder.ToString().Replace("xmlns:m=", "xmlns:u=", StringComparison.Ordinal); - var controlResponse = new ControlResponse - { - Xml = xml, - IsSuccessful = true - }; + var controlResponse = new ControlResponse(xml, true); controlResponse.Headers.Add("EXT", string.Empty); diff --git a/Emby.Dlna/Service/ControlErrorHandler.cs b/Emby.Dlna/Service/ControlErrorHandler.cs index f2b5dd9ca8..3e2cd6d2e4 100644 --- a/Emby.Dlna/Service/ControlErrorHandler.cs +++ b/Emby.Dlna/Service/ControlErrorHandler.cs @@ -46,11 +46,7 @@ namespace Emby.Dlna.Service writer.WriteEndDocument(); } - return new ControlResponse - { - Xml = builder.ToString(), - IsSuccessful = false - }; + return new ControlResponse(builder.ToString(), false); } } } |
