|
|
@ -1,5 +1,3 @@
|
|
|
|
#nullable disable
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#pragma warning disable CS1591
|
|
|
|
#pragma warning disable CS1591
|
|
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using System;
|
|
|
@ -25,7 +23,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
private readonly ILogger _logger;
|
|
|
|
private readonly ILogger _logger;
|
|
|
|
|
|
|
|
|
|
|
|
private readonly object _timerLock = new object();
|
|
|
|
private readonly object _timerLock = new object();
|
|
|
|
private Timer _timer;
|
|
|
|
private Timer? _timer;
|
|
|
|
private int _muteVol;
|
|
|
|
private int _muteVol;
|
|
|
|
private int _volume;
|
|
|
|
private int _volume;
|
|
|
|
private DateTime _lastVolumeRefresh;
|
|
|
|
private DateTime _lastVolumeRefresh;
|
|
|
@ -40,13 +38,13 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
_logger = logger;
|
|
|
|
_logger = logger;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public event EventHandler<PlaybackStartEventArgs> PlaybackStart;
|
|
|
|
public event EventHandler<PlaybackStartEventArgs>? PlaybackStart;
|
|
|
|
|
|
|
|
|
|
|
|
public event EventHandler<PlaybackProgressEventArgs> PlaybackProgress;
|
|
|
|
public event EventHandler<PlaybackProgressEventArgs>? PlaybackProgress;
|
|
|
|
|
|
|
|
|
|
|
|
public event EventHandler<PlaybackStoppedEventArgs> PlaybackStopped;
|
|
|
|
public event EventHandler<PlaybackStoppedEventArgs>? PlaybackStopped;
|
|
|
|
|
|
|
|
|
|
|
|
public event EventHandler<MediaChangedEventArgs> MediaChanged;
|
|
|
|
public event EventHandler<MediaChangedEventArgs>? MediaChanged;
|
|
|
|
|
|
|
|
|
|
|
|
public DeviceInfo Properties { get; set; }
|
|
|
|
public DeviceInfo Properties { get; set; }
|
|
|
|
|
|
|
|
|
|
|
@ -75,13 +73,13 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
|
|
|
|
|
|
|
|
public bool IsStopped => TransportState == TransportState.STOPPED;
|
|
|
|
public bool IsStopped => TransportState == TransportState.STOPPED;
|
|
|
|
|
|
|
|
|
|
|
|
public Action OnDeviceUnavailable { get; set; }
|
|
|
|
public Action? OnDeviceUnavailable { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
private TransportCommands AvCommands { get; set; }
|
|
|
|
private TransportCommands? AvCommands { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
private TransportCommands RendererCommands { get; set; }
|
|
|
|
private TransportCommands? RendererCommands { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public UBaseObject CurrentMediaInfo { get; private set; }
|
|
|
|
public UBaseObject? CurrentMediaInfo { get; private set; }
|
|
|
|
|
|
|
|
|
|
|
|
public void Start()
|
|
|
|
public void Start()
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -131,7 +129,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
_volumeRefreshActive = true;
|
|
|
|
_volumeRefreshActive = true;
|
|
|
|
|
|
|
|
|
|
|
|
var time = immediate ? 100 : 10000;
|
|
|
|
var time = immediate ? 100 : 10000;
|
|
|
|
_timer.Change(time, Timeout.Infinite);
|
|
|
|
_timer?.Change(time, Timeout.Infinite);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -149,7 +147,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
|
|
|
|
|
|
|
|
_volumeRefreshActive = false;
|
|
|
|
_volumeRefreshActive = false;
|
|
|
|
|
|
|
|
|
|
|
|
_timer.Change(Timeout.Infinite, Timeout.Infinite);
|
|
|
|
_timer?.Change(Timeout.Infinite, Timeout.Infinite);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -199,7 +197,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private DeviceService GetServiceRenderingControl()
|
|
|
|
private DeviceService? GetServiceRenderingControl()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var services = Properties.Services;
|
|
|
|
var services = Properties.Services;
|
|
|
|
|
|
|
|
|
|
|
@ -207,7 +205,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
services.FirstOrDefault(s => (s.ServiceType ?? string.Empty).StartsWith("urn:schemas-upnp-org:service:RenderingControl", StringComparison.OrdinalIgnoreCase));
|
|
|
|
services.FirstOrDefault(s => (s.ServiceType ?? string.Empty).StartsWith("urn:schemas-upnp-org:service:RenderingControl", StringComparison.OrdinalIgnoreCase));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private DeviceService GetAvTransportService()
|
|
|
|
private DeviceService? GetAvTransportService()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var services = Properties.Services;
|
|
|
|
var services = Properties.Services;
|
|
|
|
|
|
|
|
|
|
|
@ -240,7 +238,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
Properties.BaseUrl,
|
|
|
|
Properties.BaseUrl,
|
|
|
|
service,
|
|
|
|
service,
|
|
|
|
command.Name,
|
|
|
|
command.Name,
|
|
|
|
rendererCommands.BuildPost(command, service.ServiceType, value),
|
|
|
|
rendererCommands!.BuildPost(command, service.ServiceType, value), // null checked above
|
|
|
|
cancellationToken: cancellationToken)
|
|
|
|
cancellationToken: cancellationToken)
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
|
@ -265,12 +263,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var service = GetServiceRenderingControl();
|
|
|
|
var service = GetServiceRenderingControl() ?? throw new InvalidOperationException("Unable to find service");
|
|
|
|
|
|
|
|
|
|
|
|
if (service is null)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
throw new InvalidOperationException("Unable to find service");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set it early and assume it will succeed
|
|
|
|
// Set it early and assume it will succeed
|
|
|
|
// Remote control will perform better
|
|
|
|
// Remote control will perform better
|
|
|
@ -281,7 +274,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
Properties.BaseUrl,
|
|
|
|
Properties.BaseUrl,
|
|
|
|
service,
|
|
|
|
service,
|
|
|
|
command.Name,
|
|
|
|
command.Name,
|
|
|
|
rendererCommands.BuildPost(command, service.ServiceType, value),
|
|
|
|
rendererCommands!.BuildPost(command, service.ServiceType, value), // null checked above
|
|
|
|
cancellationToken: cancellationToken)
|
|
|
|
cancellationToken: cancellationToken)
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -296,26 +289,20 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var service = GetAvTransportService();
|
|
|
|
var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
|
|
|
|
|
|
|
|
|
|
|
|
if (service is null)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
throw new InvalidOperationException("Unable to find service");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
await new DlnaHttpClient(_logger, _httpClientFactory)
|
|
|
|
await new DlnaHttpClient(_logger, _httpClientFactory)
|
|
|
|
.SendCommandAsync(
|
|
|
|
.SendCommandAsync(
|
|
|
|
Properties.BaseUrl,
|
|
|
|
Properties.BaseUrl,
|
|
|
|
service,
|
|
|
|
service,
|
|
|
|
command.Name,
|
|
|
|
command.Name,
|
|
|
|
avCommands.BuildPost(command, service.ServiceType, string.Format(CultureInfo.InvariantCulture, "{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"),
|
|
|
|
avCommands!.BuildPost(command, service.ServiceType, string.Format(CultureInfo.InvariantCulture, "{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"), // null checked above
|
|
|
|
cancellationToken: cancellationToken)
|
|
|
|
cancellationToken: cancellationToken)
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
|
|
RestartTimer(true);
|
|
|
|
RestartTimer(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public async Task SetAvTransport(string url, string header, string metaData, CancellationToken cancellationToken)
|
|
|
|
public async Task SetAvTransport(string url, string? header, string metaData, CancellationToken cancellationToken)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var avCommands = await GetAVProtocolAsync(cancellationToken).ConfigureAwait(false);
|
|
|
|
var avCommands = await GetAVProtocolAsync(cancellationToken).ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
|
@ -335,14 +322,8 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
{ "CurrentURIMetaData", CreateDidlMeta(metaData) }
|
|
|
|
{ "CurrentURIMetaData", CreateDidlMeta(metaData) }
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var service = GetAvTransportService();
|
|
|
|
var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
|
|
|
|
|
|
|
|
var post = avCommands!.BuildPost(command, service.ServiceType, url, dictionary); // null checked above
|
|
|
|
if (service is null)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
throw new InvalidOperationException("Unable to find service");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary);
|
|
|
|
|
|
|
|
await new DlnaHttpClient(_logger, _httpClientFactory)
|
|
|
|
await new DlnaHttpClient(_logger, _httpClientFactory)
|
|
|
|
.SendCommandAsync(
|
|
|
|
.SendCommandAsync(
|
|
|
|
Properties.BaseUrl,
|
|
|
|
Properties.BaseUrl,
|
|
|
@ -372,7 +353,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
* SetNextAvTransport is used to specify to the DLNA device what is the next track to play.
|
|
|
|
* 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.
|
|
|
|
* 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)
|
|
|
|
public async Task SetNextAvTransport(string url, string? header, string metaData, CancellationToken cancellationToken = default)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var avCommands = await GetAVProtocolAsync(cancellationToken).ConfigureAwait(false);
|
|
|
|
var avCommands = await GetAVProtocolAsync(cancellationToken).ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
|
@ -380,7 +361,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
|
|
|
|
|
|
|
|
_logger.LogDebug("{PropertyName} - SetNextAvTransport Uri: {Url} DlnaHeaders: {Header}", Properties.Name, url, header);
|
|
|
|
_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));
|
|
|
|
var command = avCommands?.ServiceActions.FirstOrDefault(c => string.Equals(c.Name, "SetNextAVTransportURI", StringComparison.OrdinalIgnoreCase));
|
|
|
|
if (command is null)
|
|
|
|
if (command is null)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
return;
|
|
|
@ -392,14 +373,8 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
{ "NextURIMetaData", CreateDidlMeta(metaData) }
|
|
|
|
{ "NextURIMetaData", CreateDidlMeta(metaData) }
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var service = GetAvTransportService();
|
|
|
|
var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
|
|
|
|
|
|
|
|
var post = avCommands!.BuildPost(command, service.ServiceType, url, dictionary); // null checked above
|
|
|
|
if (service is null)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
throw new InvalidOperationException("Unable to find service");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary);
|
|
|
|
|
|
|
|
await new DlnaHttpClient(_logger, _httpClientFactory)
|
|
|
|
await new DlnaHttpClient(_logger, _httpClientFactory)
|
|
|
|
.SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header, cancellationToken)
|
|
|
|
.SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header, cancellationToken)
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
.ConfigureAwait(false);
|
|
|
@ -423,12 +398,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
return Task.CompletedTask;
|
|
|
|
return Task.CompletedTask;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var service = GetAvTransportService();
|
|
|
|
var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
|
|
|
|
if (service is null)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
throw new InvalidOperationException("Unable to find service");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync(
|
|
|
|
return new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync(
|
|
|
|
Properties.BaseUrl,
|
|
|
|
Properties.BaseUrl,
|
|
|
|
service,
|
|
|
|
service,
|
|
|
@ -460,14 +430,13 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var service = GetAvTransportService();
|
|
|
|
var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
|
|
|
|
|
|
|
|
|
|
|
|
await new DlnaHttpClient(_logger, _httpClientFactory)
|
|
|
|
await new DlnaHttpClient(_logger, _httpClientFactory)
|
|
|
|
.SendCommandAsync(
|
|
|
|
.SendCommandAsync(
|
|
|
|
Properties.BaseUrl,
|
|
|
|
Properties.BaseUrl,
|
|
|
|
service,
|
|
|
|
service,
|
|
|
|
command.Name,
|
|
|
|
command.Name,
|
|
|
|
avCommands.BuildPost(command, service.ServiceType, 1),
|
|
|
|
avCommands!.BuildPost(command, service.ServiceType, 1), // null checked above
|
|
|
|
cancellationToken: cancellationToken)
|
|
|
|
cancellationToken: cancellationToken)
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
|
@ -484,14 +453,13 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var service = GetAvTransportService();
|
|
|
|
var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
|
|
|
|
|
|
|
|
|
|
|
|
await new DlnaHttpClient(_logger, _httpClientFactory)
|
|
|
|
await new DlnaHttpClient(_logger, _httpClientFactory)
|
|
|
|
.SendCommandAsync(
|
|
|
|
.SendCommandAsync(
|
|
|
|
Properties.BaseUrl,
|
|
|
|
Properties.BaseUrl,
|
|
|
|
service,
|
|
|
|
service,
|
|
|
|
command.Name,
|
|
|
|
command.Name,
|
|
|
|
avCommands.BuildPost(command, service.ServiceType, 1),
|
|
|
|
avCommands!.BuildPost(command, service.ServiceType, 1), // null checked above
|
|
|
|
cancellationToken: cancellationToken)
|
|
|
|
cancellationToken: cancellationToken)
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
.ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
|
@ -500,7 +468,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
RestartTimer(true);
|
|
|
|
RestartTimer(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async void TimerCallback(object sender)
|
|
|
|
private async void TimerCallback(object? sender)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (_disposed)
|
|
|
|
if (_disposed)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -623,7 +591,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
Properties.BaseUrl,
|
|
|
|
Properties.BaseUrl,
|
|
|
|
service,
|
|
|
|
service,
|
|
|
|
command.Name,
|
|
|
|
command.Name,
|
|
|
|
rendererCommands.BuildPost(command, service.ServiceType),
|
|
|
|
rendererCommands!.BuildPost(command, service.ServiceType), // null checked above
|
|
|
|
cancellationToken: cancellationToken).ConfigureAwait(false);
|
|
|
|
cancellationToken: cancellationToken).ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
|
|
if (result is null || result.Document is null)
|
|
|
|
if (result is null || result.Document is null)
|
|
|
@ -673,7 +641,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
Properties.BaseUrl,
|
|
|
|
Properties.BaseUrl,
|
|
|
|
service,
|
|
|
|
service,
|
|
|
|
command.Name,
|
|
|
|
command.Name,
|
|
|
|
rendererCommands.BuildPost(command, service.ServiceType),
|
|
|
|
rendererCommands!.BuildPost(command, service.ServiceType), // null checked above
|
|
|
|
cancellationToken: cancellationToken).ConfigureAwait(false);
|
|
|
|
cancellationToken: cancellationToken).ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
|
|
if (result is null || result.Document is null)
|
|
|
|
if (result is null || result.Document is null)
|
|
|
@ -728,7 +696,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task<UBaseObject> GetMediaInfo(TransportCommands avCommands, CancellationToken cancellationToken)
|
|
|
|
private async Task<UBaseObject?> GetMediaInfo(TransportCommands avCommands, CancellationToken cancellationToken)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMediaInfo");
|
|
|
|
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMediaInfo");
|
|
|
|
if (command is null)
|
|
|
|
if (command is null)
|
|
|
@ -798,7 +766,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task<(bool Success, UBaseObject Track)> GetPositionInfo(TransportCommands avCommands, CancellationToken cancellationToken)
|
|
|
|
private async Task<(bool Success, UBaseObject? Track)> GetPositionInfo(TransportCommands avCommands, CancellationToken cancellationToken)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetPositionInfo");
|
|
|
|
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetPositionInfo");
|
|
|
|
if (command is null)
|
|
|
|
if (command is null)
|
|
|
@ -871,7 +839,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
return (true, null);
|
|
|
|
return (true, null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
XElement uPnpResponse = null;
|
|
|
|
XElement? uPnpResponse = null;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
try
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -895,7 +863,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
return (true, uTrack);
|
|
|
|
return (true, uTrack);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private XElement ParseResponse(string xml)
|
|
|
|
private XElement? ParseResponse(string xml)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// Handle different variations sent back by devices.
|
|
|
|
// Handle different variations sent back by devices.
|
|
|
|
try
|
|
|
|
try
|
|
|
@ -929,7 +897,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static UBaseObject CreateUBaseObject(XElement container, string trackUri)
|
|
|
|
private static UBaseObject CreateUBaseObject(XElement? container, string? trackUri)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
ArgumentNullException.ThrowIfNull(container);
|
|
|
|
ArgumentNullException.ThrowIfNull(container);
|
|
|
|
|
|
|
|
|
|
|
@ -972,7 +940,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
return new string[4];
|
|
|
|
return new string[4];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task<TransportCommands> GetAVProtocolAsync(CancellationToken cancellationToken)
|
|
|
|
private async Task<TransportCommands?> GetAVProtocolAsync(CancellationToken cancellationToken)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (AvCommands is not null)
|
|
|
|
if (AvCommands is not null)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -1004,7 +972,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
return AvCommands;
|
|
|
|
return AvCommands;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async Task<TransportCommands> GetRenderingProtocolAsync(CancellationToken cancellationToken)
|
|
|
|
private async Task<TransportCommands?> GetRenderingProtocolAsync(CancellationToken cancellationToken)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (RendererCommands is not null)
|
|
|
|
if (RendererCommands is not null)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -1054,7 +1022,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
return baseUrl + url;
|
|
|
|
return baseUrl + url;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClientFactory httpClientFactory, ILogger logger, CancellationToken cancellationToken)
|
|
|
|
public static async Task<Device?> CreateuPnpDeviceAsync(Uri url, IHttpClientFactory httpClientFactory, ILogger logger, CancellationToken cancellationToken)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
var ssdpHttpClient = new DlnaHttpClient(logger, httpClientFactory);
|
|
|
|
var ssdpHttpClient = new DlnaHttpClient(logger, httpClientFactory);
|
|
|
|
|
|
|
|
|
|
|
@ -1287,7 +1255,7 @@ namespace Emby.Dlna.PlayTo
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_timer = null;
|
|
|
|
_timer = null;
|
|
|
|
Properties = null;
|
|
|
|
Properties = null!;
|
|
|
|
|
|
|
|
|
|
|
|
_disposed = true;
|
|
|
|
_disposed = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|