jellyfin-server/Emby.Dlna/PlayTo/PlayToManager.cs

261 lines
9.4 KiB
C#
Raw Normal View History

2016-10-29 22:22:20 +00:00
using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Session;
using Microsoft.Extensions.Logging;
2016-10-29 22:22:20 +00:00
using MediaBrowser.Model.Session;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Globalization;
2016-11-08 18:44:23 +00:00
using MediaBrowser.Model.Net;
2016-11-04 08:31:05 +00:00
using MediaBrowser.Model.Threading;
2017-11-23 15:46:16 +00:00
using System.Threading;
2018-09-12 17:26:21 +00:00
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Devices;
2016-10-29 22:22:20 +00:00
2016-10-29 22:34:54 +00:00
namespace Emby.Dlna.PlayTo
2016-10-29 22:22:20 +00:00
{
class PlayToManager : IDisposable
{
private readonly ILogger _logger;
private readonly ISessionManager _sessionManager;
private readonly ILibraryManager _libraryManager;
private readonly IUserManager _userManager;
private readonly IDlnaManager _dlnaManager;
private readonly IServerApplicationHost _appHost;
private readonly IImageProcessor _imageProcessor;
private readonly IHttpClient _httpClient;
private readonly IServerConfigurationManager _config;
private readonly IUserDataManager _userDataManager;
private readonly ILocalizationManager _localization;
private readonly IDeviceDiscovery _deviceDiscovery;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly IMediaEncoder _mediaEncoder;
2016-11-04 08:31:05 +00:00
private readonly ITimerFactory _timerFactory;
2016-10-29 22:22:20 +00:00
2017-01-24 19:54:18 +00:00
private bool _disposed;
2017-11-23 15:46:16 +00:00
private SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1);
private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
2016-10-29 22:22:20 +00:00
2016-11-04 08:31:05 +00:00
public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClient httpClient, IServerConfigurationManager config, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder, ITimerFactory timerFactory)
2016-10-29 22:22:20 +00:00
{
_logger = logger;
_sessionManager = sessionManager;
_libraryManager = libraryManager;
_userManager = userManager;
_dlnaManager = dlnaManager;
_appHost = appHost;
_imageProcessor = imageProcessor;
_deviceDiscovery = deviceDiscovery;
_httpClient = httpClient;
_config = config;
_userDataManager = userDataManager;
_localization = localization;
_mediaSourceManager = mediaSourceManager;
_mediaEncoder = mediaEncoder;
2016-11-04 08:31:05 +00:00
_timerFactory = timerFactory;
2016-10-29 22:22:20 +00:00
}
public void Start()
{
_deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;
}
async void _deviceDiscovery_DeviceDiscovered(object sender, GenericEventArgs<UpnpDeviceInfo> e)
{
2017-01-24 19:54:18 +00:00
if (_disposed)
{
return;
}
2016-10-29 22:22:20 +00:00
var info = e.Argument;
string usn;
if (!info.Headers.TryGetValue("USN", out usn)) usn = string.Empty;
string nt;
if (!info.Headers.TryGetValue("NT", out nt)) nt = string.Empty;
string location = info.Location.ToString();
// It has to report that it's a media renderer
if (usn.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1 &&
nt.IndexOf("MediaRenderer:", StringComparison.OrdinalIgnoreCase) == -1)
{
//_logger.LogDebug("Upnp device {0} does not contain a MediaRenderer device (0).", location);
2016-10-29 22:22:20 +00:00
return;
}
if (_sessionManager.Sessions.Any(i => usn.IndexOf(i.DeviceId, StringComparison.OrdinalIgnoreCase) != -1))
{
return;
}
2017-11-23 15:46:16 +00:00
var cancellationToken = _disposeCancellationTokenSource.Token;
await _sessionLock.WaitAsync(cancellationToken).ConfigureAwait(false);
2016-10-29 22:22:20 +00:00
try
{
2017-11-23 15:46:16 +00:00
if (_disposed)
2016-10-29 22:22:20 +00:00
{
2017-11-23 15:46:16 +00:00
return;
2016-10-29 22:22:20 +00:00
}
2017-11-23 15:46:16 +00:00
await AddDevice(info, location, cancellationToken).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
}
catch (Exception ex)
{
2018-12-20 12:11:26 +00:00
_logger.LogError(ex, "Error creating PlayTo device.");
2017-11-23 15:46:16 +00:00
}
finally
{
_sessionLock.Release();
}
}
2018-09-12 17:26:21 +00:00
private string GetUuid(string usn)
2017-11-23 15:46:16 +00:00
{
2018-09-12 17:26:21 +00:00
var found = false;
var index = usn.IndexOf("uuid:", StringComparison.OrdinalIgnoreCase);
if (index != -1)
{
usn = usn.Substring(index);
found = true;
}
index = usn.IndexOf("::", StringComparison.OrdinalIgnoreCase);
if (index != -1)
2017-11-23 15:46:16 +00:00
{
2018-09-12 17:26:21 +00:00
usn = usn.Substring(0, index);
2017-11-23 15:46:16 +00:00
}
2018-09-12 17:26:21 +00:00
if (found)
2017-11-23 15:46:16 +00:00
{
2018-09-12 17:26:21 +00:00
return usn;
2017-11-23 15:46:16 +00:00
}
2018-09-12 17:26:21 +00:00
return usn.GetMD5().ToString("N");
}
private async Task AddDevice(UpnpDeviceInfo info, string location, CancellationToken cancellationToken)
{
2017-11-23 15:46:16 +00:00
var uri = info.Location;
_logger.LogDebug("Attempting to create PlayToController from location {0}", location);
2017-11-23 15:46:16 +00:00
_logger.LogDebug("Logging session activity from location {0}", location);
2018-09-12 17:26:21 +00:00
string uuid;
if (info.Headers.TryGetValue("USN", out uuid))
2017-11-23 15:46:16 +00:00
{
2018-09-12 17:26:21 +00:00
uuid = GetUuid(uuid);
}
else
{
uuid = location.GetMD5().ToString("N");
2017-11-23 15:46:16 +00:00
}
2018-09-12 17:26:21 +00:00
string deviceName = null;
2017-11-23 15:46:16 +00:00
2018-09-12 17:26:21 +00:00
var sessionInfo = _sessionManager.LogSessionActivity("DLNA", _appHost.ApplicationVersion.ToString(), uuid, deviceName, uri.OriginalString, null);
var controller = sessionInfo.SessionControllers.OfType<PlayToController>().FirstOrDefault();
2016-10-29 22:22:20 +00:00
2017-11-23 15:46:16 +00:00
if (controller == null)
{
2018-09-12 17:26:21 +00:00
var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger, _timerFactory, cancellationToken).ConfigureAwait(false);
deviceName = device.Properties.Name;
_sessionManager.UpdateDeviceName(sessionInfo.Id, deviceName);
2017-11-23 15:46:16 +00:00
string serverAddress;
2018-09-12 17:26:21 +00:00
if (info.LocalIpAddress == null || info.LocalIpAddress.Equals(IpAddressInfo.Any) || info.LocalIpAddress.Equals(IpAddressInfo.IPv6Any))
2016-10-29 22:22:20 +00:00
{
2018-09-12 17:26:21 +00:00
serverAddress = await _appHost.GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
2016-10-29 22:22:20 +00:00
}
2017-11-23 15:46:16 +00:00
else
2017-01-24 19:54:18 +00:00
{
2018-09-12 17:26:21 +00:00
serverAddress = _appHost.GetLocalApiUrl(info.LocalIpAddress);
2017-01-24 19:54:18 +00:00
}
2017-11-23 15:46:16 +00:00
string accessToken = null;
2018-09-12 17:26:21 +00:00
controller = new PlayToController(sessionInfo,
_sessionManager,
_libraryManager,
_logger,
_dlnaManager,
_userManager,
_imageProcessor,
serverAddress,
accessToken,
_deviceDiscovery,
_userDataManager,
_localization,
_mediaSourceManager,
_config,
_mediaEncoder);
sessionInfo.AddController(controller);
2017-11-23 15:46:16 +00:00
controller.Init(device);
var profile = _dlnaManager.GetProfile(device.Properties.ToDeviceIdentification()) ??
_dlnaManager.GetDefaultProfile();
_sessionManager.ReportCapabilities(sessionInfo.Id, new ClientCapabilities
2016-10-29 22:22:20 +00:00
{
2017-11-23 15:46:16 +00:00
PlayableMediaTypes = profile.GetSupportedMediaTypes(),
2017-01-24 19:54:18 +00:00
2017-11-23 15:46:16 +00:00
SupportedCommands = new string[]
2016-10-29 22:22:20 +00:00
{
GeneralCommandType.VolumeDown.ToString(),
GeneralCommandType.VolumeUp.ToString(),
GeneralCommandType.Mute.ToString(),
GeneralCommandType.Unmute.ToString(),
GeneralCommandType.ToggleMute.ToString(),
GeneralCommandType.SetVolume.ToString(),
GeneralCommandType.SetAudioStreamIndex.ToString(),
2018-09-12 17:26:21 +00:00
GeneralCommandType.SetSubtitleStreamIndex.ToString(),
GeneralCommandType.PlayMediaSource.ToString()
2017-11-23 15:46:16 +00:00
},
2016-10-29 22:22:20 +00:00
2018-09-12 17:26:21 +00:00
SupportsMediaControl = true
2017-11-23 15:46:16 +00:00
});
2016-10-29 22:22:20 +00:00
_logger.LogInformation("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName);
2016-10-29 22:22:20 +00:00
}
}
public void Dispose()
{
2018-09-12 17:26:21 +00:00
_deviceDiscovery.DeviceDiscovered -= _deviceDiscovery_DeviceDiscovered;
2017-11-23 15:46:16 +00:00
try
{
_disposeCancellationTokenSource.Cancel();
}
catch
{
}
2017-01-24 19:54:18 +00:00
_disposed = true;
2016-10-29 22:22:20 +00:00
}
}
}