jellyfin-server/Emby.Dlna/Ssdp/DeviceDiscovery.cs

152 lines
5.3 KiB
C#
Raw Normal View History

#nullable disable
#pragma warning disable CS1591
using System;
2016-10-29 22:22:20 +00:00
using System.Collections.Generic;
using System.Linq;
using Jellyfin.Data.Events;
2019-01-13 19:16:19 +00:00
using MediaBrowser.Controller.Configuration;
2016-10-29 22:22:20 +00:00
using MediaBrowser.Model.Dlna;
using Rssdp;
2016-11-14 19:48:01 +00:00
using Rssdp.Infrastructure;
2016-10-29 22:22:20 +00:00
2016-10-29 22:34:54 +00:00
namespace Emby.Dlna.Ssdp
2016-10-29 22:22:20 +00:00
{
public sealed class DeviceDiscovery : IDeviceDiscovery, IDisposable
2016-10-29 22:22:20 +00:00
{
private readonly object _syncLock = new object();
2016-10-29 22:22:20 +00:00
private readonly IServerConfigurationManager _config;
2020-08-20 15:01:04 +00:00
private SsdpDeviceLocator _deviceLocator;
private ISsdpCommunicationsServer _commsServer;
2018-09-12 17:26:21 +00:00
private int _listenerCount;
private bool _disposed;
2020-08-20 15:01:04 +00:00
public DeviceDiscovery(IServerConfigurationManager config)
{
_config = config;
}
private event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscoveredInternal;
2019-11-01 20:22:35 +00:00
/// <inheritdoc />
2018-09-12 17:26:21 +00:00
public event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscovered
{
add
{
lock (_syncLock)
{
_listenerCount++;
DeviceDiscoveredInternal += value;
}
2019-11-01 20:22:35 +00:00
2018-09-12 17:26:21 +00:00
StartInternal();
}
2018-09-12 17:26:21 +00:00
remove
{
lock (_syncLock)
{
_listenerCount--;
DeviceDiscoveredInternal -= value;
}
}
}
2019-11-01 20:22:35 +00:00
/// <inheritdoc />
2016-10-29 22:22:20 +00:00
public event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceLeft;
// Call this method from somewhere in your code to start the search.
2016-11-14 19:48:01 +00:00
public void Start(ISsdpCommunicationsServer communicationsServer)
2016-10-29 22:22:20 +00:00
{
2018-09-12 17:26:21 +00:00
_commsServer = communicationsServer;
StartInternal();
}
private void StartInternal()
{
lock (_syncLock)
{
2022-12-05 14:01:13 +00:00
if (_listenerCount > 0 && _deviceLocator is null && _commsServer is not null)
2018-09-12 17:26:21 +00:00
{
_deviceLocator = new SsdpDeviceLocator(
_commsServer,
Environment.OSVersion.Platform.ToString(),
// Can not use VersionString here since that includes OS and version
Environment.OSVersion.Version.ToString());
2016-10-29 22:22:20 +00:00
2019-01-07 23:27:46 +00:00
// (Optional) Set the filter so we only see notifications for devices we care about
// (can be any search target value i.e device type, uuid value etc - any value that appears in the
2018-09-12 17:26:21 +00:00
// DiscoverdSsdpDevice.NotificationType property or that is used with the searchTarget parameter of the Search method).
2020-06-14 09:11:11 +00:00
// _DeviceLocator.NotificationFilter = "upnp:rootdevice";
2016-10-29 22:22:20 +00:00
2018-09-12 17:26:21 +00:00
// Connect our event handler so we process devices as they are found
2019-11-01 20:22:35 +00:00
_deviceLocator.DeviceAvailable += OnDeviceLocatorDeviceAvailable;
_deviceLocator.DeviceUnavailable += OnDeviceLocatorDeviceUnavailable;
2016-10-29 22:22:20 +00:00
2018-09-12 17:26:21 +00:00
var dueTime = TimeSpan.FromSeconds(5);
var interval = TimeSpan.FromSeconds(_config.GetDlnaConfiguration().ClientDiscoveryIntervalSeconds);
2017-02-05 20:44:08 +00:00
2018-09-12 17:26:21 +00:00
_deviceLocator.RestartBroadcastTimer(dueTime, interval);
}
}
2016-10-29 22:22:20 +00:00
}
// Process each found device in the event handler
2019-11-01 20:22:35 +00:00
private void OnDeviceLocatorDeviceAvailable(object sender, DeviceAvailableEventArgs e)
2016-10-29 22:22:20 +00:00
{
var originalHeaders = e.DiscoveredDevice.ResponseHeaders;
2022-12-05 14:00:20 +00:00
var headerDict = originalHeaders is null ? new Dictionary<string, KeyValuePair<string, IEnumerable<string>>>() : originalHeaders.ToDictionary(i => i.Key, StringComparer.OrdinalIgnoreCase);
2016-10-29 22:22:20 +00:00
var headers = headerDict.ToDictionary(i => i.Key, i => i.Value.Value.FirstOrDefault(), StringComparer.OrdinalIgnoreCase);
var args = new GenericEventArgs<UpnpDeviceInfo>(
new UpnpDeviceInfo
2016-10-29 22:22:20 +00:00
{
Location = e.DiscoveredDevice.DescriptionLocation,
2017-01-24 19:54:18 +00:00
Headers = headers,
2023-02-17 18:27:36 +00:00
RemoteIPAddress = e.RemoteIPAddress
});
2016-10-29 22:22:20 +00:00
DeviceDiscoveredInternal?.Invoke(this, args);
2016-10-29 22:22:20 +00:00
}
2019-11-01 20:22:35 +00:00
private void OnDeviceLocatorDeviceUnavailable(object sender, DeviceUnavailableEventArgs e)
2016-10-29 22:22:20 +00:00
{
var originalHeaders = e.DiscoveredDevice.ResponseHeaders;
2022-12-05 14:00:20 +00:00
var headerDict = originalHeaders is null ? new Dictionary<string, KeyValuePair<string, IEnumerable<string>>>() : originalHeaders.ToDictionary(i => i.Key, StringComparer.OrdinalIgnoreCase);
2016-10-29 22:22:20 +00:00
var headers = headerDict.ToDictionary(i => i.Key, i => i.Value.Value.FirstOrDefault(), StringComparer.OrdinalIgnoreCase);
var args = new GenericEventArgs<UpnpDeviceInfo>(
new UpnpDeviceInfo
2016-10-29 22:22:20 +00:00
{
Location = e.DiscoveredDevice.DescriptionLocation,
Headers = headers
});
2016-10-29 22:22:20 +00:00
DeviceLeft?.Invoke(this, args);
2016-10-29 22:22:20 +00:00
}
/// <inheritdoc />
2016-10-29 22:22:20 +00:00
public void Dispose()
{
if (!_disposed)
{
_disposed = true;
2022-12-05 14:01:13 +00:00
if (_deviceLocator is not null)
2017-02-07 07:33:24 +00:00
{
_deviceLocator.Dispose();
_deviceLocator = null;
}
2016-10-29 22:22:20 +00:00
}
}
}
}