jellyfin/Emby.Dlna/Main/DlnaEntryPoint.cs

419 lines
14 KiB
C#
Raw Normal View History

2016-10-30 00:22:20 +02:00
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
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.Plugins;
using MediaBrowser.Controller.Session;
2018-09-12 19:26:21 +02:00
using MediaBrowser.Controller.TV;
2016-10-30 00:34:54 +02:00
using Emby.Dlna.PlayTo;
using Emby.Dlna.Ssdp;
2016-10-30 00:22:20 +02:00
using MediaBrowser.Model.Logging;
using System;
using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Globalization;
2016-11-04 09:31:05 +01:00
using MediaBrowser.Model.Net;
2016-11-04 20:51:59 +01:00
using MediaBrowser.Model.System;
2016-11-04 09:31:05 +01:00
using MediaBrowser.Model.Threading;
2018-09-12 19:26:21 +02:00
using MediaBrowser.Model.Xml;
2016-10-30 00:22:20 +02:00
using Rssdp;
using Rssdp.Infrastructure;
2017-11-23 16:46:16 +01:00
using System.Threading;
2016-10-30 00:22:20 +02:00
2016-10-30 00:34:54 +02:00
namespace Emby.Dlna.Main
2016-10-30 00:22:20 +02:00
{
2018-09-12 19:26:21 +02:00
public class DlnaEntryPoint : IServerEntryPoint, IRunBeforeStartup
2016-10-30 00:22:20 +02:00
{
private readonly IServerConfigurationManager _config;
private readonly ILogger _logger;
private readonly IServerApplicationHost _appHost;
private PlayToManager _manager;
private readonly ISessionManager _sessionManager;
private readonly IHttpClient _httpClient;
private readonly ILibraryManager _libraryManager;
private readonly IUserManager _userManager;
private readonly IDlnaManager _dlnaManager;
private readonly IImageProcessor _imageProcessor;
private readonly IUserDataManager _userDataManager;
private readonly ILocalizationManager _localization;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly IMediaEncoder _mediaEncoder;
private readonly IDeviceDiscovery _deviceDiscovery;
private SsdpDevicePublisher _Publisher;
2016-11-04 09:31:05 +01:00
private readonly ITimerFactory _timerFactory;
private readonly ISocketFactory _socketFactory;
2016-11-04 20:51:59 +01:00
private readonly IEnvironmentInfo _environmentInfo;
2016-12-04 22:30:38 +01:00
private readonly INetworkManager _networkManager;
2016-11-04 09:31:05 +01:00
2016-11-14 20:48:01 +01:00
private ISsdpCommunicationsServer _communicationsServer;
2018-09-12 19:26:21 +02:00
internal IContentDirectory ContentDirectory { get; private set; }
internal IConnectionManager ConnectionManager { get; private set; }
internal IMediaReceiverRegistrar MediaReceiverRegistrar { get; private set; }
public static DlnaEntryPoint Current;
2016-10-30 00:22:20 +02:00
public DlnaEntryPoint(IServerConfigurationManager config,
ILogManager logManager,
IServerApplicationHost appHost,
ISessionManager sessionManager,
IHttpClient httpClient,
ILibraryManager libraryManager,
IUserManager userManager,
IDlnaManager dlnaManager,
IImageProcessor imageProcessor,
IUserDataManager userDataManager,
2018-09-12 19:26:21 +02:00
ILocalizationManager localizationManager,
2016-10-30 00:22:20 +02:00
IMediaSourceManager mediaSourceManager,
2018-09-12 19:26:21 +02:00
IDeviceDiscovery deviceDiscovery,
IMediaEncoder mediaEncoder,
ISocketFactory socketFactory,
ITimerFactory timerFactory,
IEnvironmentInfo environmentInfo,
INetworkManager networkManager,
IUserViewManager userViewManager,
IXmlReaderSettingsFactory xmlReaderSettingsFactory,
ITVSeriesManager tvSeriesManager)
2016-10-30 00:22:20 +02:00
{
_config = config;
_appHost = appHost;
_sessionManager = sessionManager;
_httpClient = httpClient;
_libraryManager = libraryManager;
_userManager = userManager;
_dlnaManager = dlnaManager;
_imageProcessor = imageProcessor;
_userDataManager = userDataManager;
2018-09-12 19:26:21 +02:00
_localization = localizationManager;
2016-10-30 00:22:20 +02:00
_mediaSourceManager = mediaSourceManager;
_deviceDiscovery = deviceDiscovery;
_mediaEncoder = mediaEncoder;
2016-11-04 09:31:05 +01:00
_socketFactory = socketFactory;
_timerFactory = timerFactory;
2016-11-04 20:51:59 +01:00
_environmentInfo = environmentInfo;
2016-12-04 22:30:38 +01:00
_networkManager = networkManager;
2016-10-30 00:22:20 +02:00
_logger = logManager.GetLogger("Dlna");
2018-09-12 19:26:21 +02:00
ContentDirectory = new ContentDirectory.ContentDirectory(dlnaManager,
userDataManager,
imageProcessor,
libraryManager,
config,
userManager,
_logger,
httpClient,
localizationManager,
mediaSourceManager,
userViewManager,
mediaEncoder,
xmlReaderSettingsFactory,
tvSeriesManager);
ConnectionManager = new ConnectionManager.ConnectionManager(dlnaManager, config, _logger, httpClient, xmlReaderSettingsFactory);
MediaReceiverRegistrar = new MediaReceiverRegistrar.MediaReceiverRegistrar(_logger, httpClient, config, xmlReaderSettingsFactory);
Current = this;
2016-10-30 00:22:20 +02:00
}
public void Run()
{
((DlnaManager)_dlnaManager).InitProfiles();
ReloadComponents();
_config.NamedConfigurationUpdated += _config_NamedConfigurationUpdated;
}
void _config_NamedConfigurationUpdated(object sender, ConfigurationUpdateEventArgs e)
{
if (string.Equals(e.Key, "dlna", StringComparison.OrdinalIgnoreCase))
{
ReloadComponents();
}
}
private async void ReloadComponents()
{
var options = _config.GetDlnaConfiguration();
2018-09-12 19:26:21 +02:00
StartSsdpHandler();
2016-10-30 00:22:20 +02:00
2018-09-12 19:26:21 +02:00
if (options.EnableServer)
2016-10-30 00:22:20 +02:00
{
2018-09-12 19:26:21 +02:00
await StartDevicePublisher(options).ConfigureAwait(false);
2016-10-30 00:22:20 +02:00
}
2018-09-12 19:26:21 +02:00
else
2016-10-30 00:22:20 +02:00
{
2018-09-12 19:26:21 +02:00
DisposeDevicePublisher();
2016-10-30 00:22:20 +02:00
}
2018-09-12 19:26:21 +02:00
if (options.EnablePlayTo)
2016-10-30 00:22:20 +02:00
{
StartPlayToManager();
}
2018-09-12 19:26:21 +02:00
else
2016-10-30 00:22:20 +02:00
{
DisposePlayToManager();
}
}
private void StartSsdpHandler()
{
try
{
2016-11-14 20:48:01 +01:00
if (_communicationsServer == null)
{
var enableMultiSocketBinding = _environmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows;
2016-12-05 19:46:38 +01:00
_communicationsServer = new SsdpCommunicationsServer(_socketFactory, _networkManager, _logger, enableMultiSocketBinding)
2016-11-14 20:48:01 +01:00
{
IsShared = true
};
2016-10-30 00:22:20 +02:00
2018-09-12 19:26:21 +02:00
StartDeviceDiscovery(_communicationsServer);
}
2016-10-30 00:22:20 +02:00
}
catch (Exception ex)
{
_logger.ErrorException("Error starting ssdp handlers", ex);
}
}
private void LogMessage(string msg)
{
2016-11-14 20:48:01 +01:00
_logger.Debug(msg);
2016-10-30 00:22:20 +02:00
}
2016-11-14 20:48:01 +01:00
private void StartDeviceDiscovery(ISsdpCommunicationsServer communicationsServer)
2016-10-30 00:22:20 +02:00
{
try
{
2016-11-14 20:48:01 +01:00
((DeviceDiscovery)_deviceDiscovery).Start(communicationsServer);
2016-10-30 00:22:20 +02:00
}
catch (Exception ex)
{
_logger.ErrorException("Error starting device discovery", ex);
}
}
private void DisposeDeviceDiscovery()
{
try
{
2018-09-12 19:26:21 +02:00
_logger.Info("Disposing DeviceDiscovery");
2016-10-30 00:22:20 +02:00
((DeviceDiscovery)_deviceDiscovery).Dispose();
}
catch (Exception ex)
{
_logger.ErrorException("Error stopping device discovery", ex);
}
}
2018-09-12 19:26:21 +02:00
public async Task StartDevicePublisher(Configuration.DlnaOptions options)
2016-10-30 00:22:20 +02:00
{
2018-09-12 19:26:21 +02:00
if (!options.BlastAliveMessages)
2016-10-30 00:22:20 +02:00
{
2018-09-12 19:26:21 +02:00
return;
2016-10-30 00:22:20 +02:00
}
2018-09-12 19:26:21 +02:00
if (_Publisher != null)
2016-10-30 00:22:20 +02:00
{
2018-09-12 19:26:21 +02:00
return;
2016-10-30 00:22:20 +02:00
}
try
{
2018-09-12 19:26:21 +02:00
_Publisher = new SsdpDevicePublisher(_communicationsServer, _timerFactory, _environmentInfo.OperatingSystemName, _environmentInfo.OperatingSystemVersion);
_Publisher.LogFunction = LogMessage;
_Publisher.SupportPnpRootDevice = false;
2016-10-30 00:22:20 +02:00
await RegisterServerEndpoints().ConfigureAwait(false);
2018-09-12 19:26:21 +02:00
_Publisher.StartBroadcastingAliveMessages(TimeSpan.FromSeconds(options.BlastAliveMessageIntervalSeconds));
2016-10-30 00:22:20 +02:00
}
catch (Exception ex)
{
_logger.ErrorException("Error registering endpoint", ex);
}
}
private async Task RegisterServerEndpoints()
{
2017-11-23 16:46:16 +01:00
var addresses = (await _appHost.GetLocalIpAddresses(CancellationToken.None).ConfigureAwait(false)).ToList();
2016-10-30 00:22:20 +02:00
2016-11-05 00:57:21 +01:00
var udn = CreateUuid(_appHost.SystemId);
2016-10-30 00:22:20 +02:00
foreach (var address in addresses)
{
2018-09-12 19:26:21 +02:00
// TODO: Remove this condition on platforms that support it
//if (address.AddressFamily == IpAddressFamily.InterNetworkV6)
2016-10-30 00:22:20 +02:00
//{
// continue;
//}
var fullService = "urn:schemas-upnp-org:device:MediaServer:1";
2016-11-08 19:44:23 +01:00
_logger.Info("Registering publisher for {0} on {1}", fullService, address.ToString());
2016-10-30 00:22:20 +02:00
var descriptorUri = "/dlna/" + udn + "/description.xml";
2016-11-08 19:44:23 +01:00
var uri = new Uri(_appHost.GetLocalApiUrl(address) + descriptorUri);
2016-10-30 00:22:20 +02:00
var device = new SsdpRootDevice
{
2018-09-12 19:26:21 +02:00
CacheLifetime = TimeSpan.FromSeconds(1800), //How long SSDP clients can cache this info.
2016-10-30 00:22:20 +02:00
Location = uri, // Must point to the URL that serves your devices UPnP description document.
FriendlyName = "Emby Server",
Manufacturer = "Emby",
ModelName = "Emby Server",
Uuid = udn
// This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc.
};
SetProperies(device, fullService);
_Publisher.AddDevice(device);
2018-09-12 19:26:21 +02:00
var embeddedDevices = new []
2016-10-30 00:22:20 +02:00
{
"urn:schemas-upnp-org:service:ContentDirectory:1",
"urn:schemas-upnp-org:service:ConnectionManager:1",
2016-11-15 20:42:43 +01:00
//"urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1"
2016-10-30 00:22:20 +02:00
};
foreach (var subDevice in embeddedDevices)
{
var embeddedDevice = new SsdpEmbeddedDevice
{
FriendlyName = device.FriendlyName,
Manufacturer = device.Manufacturer,
ModelName = device.ModelName,
Uuid = udn
// This must be a globally unique value that survives reboots etc. Get from storage or embedded hardware etc.
};
SetProperies(embeddedDevice, subDevice);
device.AddDevice(embeddedDevice);
}
}
}
private string CreateUuid(string text)
{
2016-11-05 00:57:21 +01:00
Guid guid;
if (!Guid.TryParse(text, out guid))
{
guid = text.GetMD5();
}
return guid.ToString("N");
2016-10-30 00:22:20 +02:00
}
private void SetProperies(SsdpDevice device, string fullDeviceType)
{
var service = fullDeviceType.Replace("urn:", string.Empty).Replace(":1", string.Empty);
var serviceParts = service.Split(':');
var deviceTypeNamespace = serviceParts[0].Replace('.', '-');
device.DeviceTypeNamespace = deviceTypeNamespace;
device.DeviceClass = serviceParts[1];
device.DeviceType = serviceParts[2];
}
private readonly object _syncLock = new object();
private void StartPlayToManager()
{
lock (_syncLock)
{
2018-09-12 19:26:21 +02:00
if (_manager != null)
{
return;
}
2016-10-30 00:22:20 +02:00
try
{
_manager = new PlayToManager(_logger,
_sessionManager,
_libraryManager,
_userManager,
_dlnaManager,
_appHost,
_imageProcessor,
_deviceDiscovery,
_httpClient,
_config,
_userDataManager,
_localization,
_mediaSourceManager,
2016-11-04 09:31:05 +01:00
_mediaEncoder,
_timerFactory);
2016-10-30 00:22:20 +02:00
_manager.Start();
}
catch (Exception ex)
{
_logger.ErrorException("Error starting PlayTo manager", ex);
}
}
}
private void DisposePlayToManager()
{
lock (_syncLock)
{
if (_manager != null)
{
try
{
2018-09-12 19:26:21 +02:00
_logger.Info("Disposing PlayToManager");
2016-10-30 00:22:20 +02:00
_manager.Dispose();
}
catch (Exception ex)
{
_logger.ErrorException("Error disposing PlayTo manager", ex);
}
_manager = null;
}
}
}
public void Dispose()
{
2018-09-12 19:26:21 +02:00
DisposeDevicePublisher();
2016-10-30 00:22:20 +02:00
DisposePlayToManager();
2018-09-12 19:26:21 +02:00
DisposeDeviceDiscovery();
2016-11-14 20:48:01 +01:00
if (_communicationsServer != null)
{
2018-09-12 19:26:21 +02:00
_logger.Info("Disposing SsdpCommunicationsServer");
2016-11-14 20:48:01 +01:00
_communicationsServer.Dispose();
_communicationsServer = null;
}
2018-09-12 19:26:21 +02:00
ContentDirectory = null;
ConnectionManager = null;
MediaReceiverRegistrar = null;
Current = null;
2016-10-30 00:22:20 +02:00
}
2018-09-12 19:26:21 +02:00
public void DisposeDevicePublisher()
2016-10-30 00:22:20 +02:00
{
if (_Publisher != null)
{
2018-09-12 19:26:21 +02:00
_logger.Info("Disposing SsdpDevicePublisher");
2016-10-30 00:22:20 +02:00
_Publisher.Dispose();
2018-09-12 19:26:21 +02:00
_Publisher = null;
2016-10-30 00:22:20 +02:00
}
}
}
}