You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
jellyfin/Emby.Dlna/PlayTo/PlayToManager.cs

232 lines
8.8 KiB

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 MediaBrowser.Model.Logging;
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;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Threading;
namespace Emby.Dlna.PlayTo
{
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;
private readonly ITimerFactory _timerFactory;
private readonly List<string> _nonRendererUrls = new List<string>();
private DateTime _lastRendererClear;
private bool _disposed;
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)
{
_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;
_timerFactory = timerFactory;
}
public void Start()
{
_deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;
}
async void _deviceDiscovery_DeviceDiscovered(object sender, GenericEventArgs<UpnpDeviceInfo> e)
{
if (_disposed)
{
return;
}
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)
{
return;
}
if (_sessionManager.Sessions.Any(i => usn.IndexOf(i.DeviceId, StringComparison.OrdinalIgnoreCase) != -1))
{
return;
}
try
{
lock (_nonRendererUrls)
{
if ((DateTime.UtcNow - _lastRendererClear).TotalMinutes >= 10)
{
_nonRendererUrls.Clear();
_lastRendererClear = DateTime.UtcNow;
}
if (_nonRendererUrls.Contains(location, StringComparer.OrdinalIgnoreCase))
{
return;
}
}
var uri = info.Location;
_logger.Debug("Attempting to create PlayToController from location {0}", location);
var device = await Device.CreateuPnpDeviceAsync(uri, _httpClient, _config, _logger, _timerFactory).ConfigureAwait(false);
if (device.RendererCommands == null)
{
lock (_nonRendererUrls)
{
_nonRendererUrls.Add(location);
return;
}
}
if (_disposed)
{
return;
}
_logger.Debug("Logging session activity from location {0}", location);
var sessionInfo = await _sessionManager.LogSessionActivity(device.Properties.ClientType, _appHost.ApplicationVersion.ToString(), device.Properties.UUID, device.Properties.Name, uri.OriginalString, null)
.ConfigureAwait(false);
var controller = sessionInfo.SessionController as PlayToController;
if (controller == null)
{
if (_disposed)
{
return;
}
string serverAddress;
if (info.LocalIpAddress == null || info.LocalIpAddress.Equals(IpAddressInfo.Any) || info.LocalIpAddress.Equals(IpAddressInfo.IPv6Loopback))
{
serverAddress = await GetServerAddress(null).ConfigureAwait(false);
}
else
{
serverAddress = await GetServerAddress(info.LocalIpAddress).ConfigureAwait(false);
}
string accessToken = null;
sessionInfo.SessionController = controller = new PlayToController(sessionInfo,
_sessionManager,
_libraryManager,
_logger,
_dlnaManager,
_userManager,
_imageProcessor,
serverAddress,
accessToken,
_deviceDiscovery,
_userDataManager,
_localization,
_mediaSourceManager,
_config,
_mediaEncoder);
controller.Init(device);
var profile = _dlnaManager.GetProfile(device.Properties.ToDeviceIdentification()) ??
_dlnaManager.GetDefaultProfile();
_sessionManager.ReportCapabilities(sessionInfo.Id, new ClientCapabilities
{
PlayableMediaTypes = profile.GetSupportedMediaTypes(),
SupportedCommands = new string[]
{
GeneralCommandType.VolumeDown.ToString(),
GeneralCommandType.VolumeUp.ToString(),
GeneralCommandType.Mute.ToString(),
GeneralCommandType.Unmute.ToString(),
GeneralCommandType.ToggleMute.ToString(),
GeneralCommandType.SetVolume.ToString(),
GeneralCommandType.SetAudioStreamIndex.ToString(),
GeneralCommandType.SetSubtitleStreamIndex.ToString()
},
SupportsMediaControl = true
});
_logger.Info("DLNA Session created for {0} - {1}", device.Properties.Name, device.Properties.ModelName);
}
}
catch (Exception ex)
{
_logger.ErrorException("Error creating PlayTo device.", ex);
lock (_nonRendererUrls)
{
_nonRendererUrls.Add(location);
}
}
}
private Task<string> GetServerAddress(IpAddressInfo address)
{
if (address == null)
{
return _appHost.GetLocalApiUrl();
}
return Task.FromResult(_appHost.GetLocalApiUrl(address));
}
public void Dispose()
{
_disposed = true;
_deviceDiscovery.DeviceDiscovered -= _deviceDiscovery_DeviceDiscovered;
GC.SuppressFinalize(this);
}
}
}