DeviceDiscovery.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using MediaBrowser.Controller.Configuration;
  5. using MediaBrowser.Model.Dlna;
  6. using MediaBrowser.Model.Events;
  7. using MediaBrowser.Model.Net;
  8. using Microsoft.Extensions.Logging;
  9. using Rssdp;
  10. using Rssdp.Infrastructure;
  11. namespace Emby.Dlna.Ssdp
  12. {
  13. public class DeviceDiscovery : IDeviceDiscovery
  14. {
  15. private bool _disposed;
  16. private readonly ILogger _logger;
  17. private readonly IServerConfigurationManager _config;
  18. private event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscoveredInternal;
  19. private int _listenerCount;
  20. private object _syncLock = new object();
  21. public event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscovered
  22. {
  23. add
  24. {
  25. lock (_syncLock)
  26. {
  27. _listenerCount++;
  28. DeviceDiscoveredInternal += value;
  29. }
  30. StartInternal();
  31. }
  32. remove
  33. {
  34. lock (_syncLock)
  35. {
  36. _listenerCount--;
  37. DeviceDiscoveredInternal -= value;
  38. }
  39. }
  40. }
  41. public event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceLeft;
  42. private SsdpDeviceLocator _deviceLocator;
  43. private readonly ISocketFactory _socketFactory;
  44. private ISsdpCommunicationsServer _commsServer;
  45. public DeviceDiscovery(
  46. ILoggerFactory loggerFactory,
  47. IServerConfigurationManager config,
  48. ISocketFactory socketFactory)
  49. {
  50. _logger = loggerFactory.CreateLogger(nameof(DeviceDiscovery));
  51. _config = config;
  52. _socketFactory = socketFactory;
  53. }
  54. // Call this method from somewhere in your code to start the search.
  55. public void Start(ISsdpCommunicationsServer communicationsServer)
  56. {
  57. _commsServer = communicationsServer;
  58. StartInternal();
  59. }
  60. private void StartInternal()
  61. {
  62. lock (_syncLock)
  63. {
  64. if (_listenerCount > 0 && _deviceLocator == null)
  65. {
  66. _deviceLocator = new SsdpDeviceLocator(_commsServer);
  67. // (Optional) Set the filter so we only see notifications for devices we care about
  68. // (can be any search target value i.e device type, uuid value etc - any value that appears in the
  69. // DiscoverdSsdpDevice.NotificationType property or that is used with the searchTarget parameter of the Search method).
  70. //_DeviceLocator.NotificationFilter = "upnp:rootdevice";
  71. // Connect our event handler so we process devices as they are found
  72. _deviceLocator.DeviceAvailable += deviceLocator_DeviceAvailable;
  73. _deviceLocator.DeviceUnavailable += _DeviceLocator_DeviceUnavailable;
  74. var dueTime = TimeSpan.FromSeconds(5);
  75. var interval = TimeSpan.FromSeconds(_config.GetDlnaConfiguration().ClientDiscoveryIntervalSeconds);
  76. _deviceLocator.RestartBroadcastTimer(dueTime, interval);
  77. }
  78. }
  79. }
  80. // Process each found device in the event handler
  81. void deviceLocator_DeviceAvailable(object sender, DeviceAvailableEventArgs e)
  82. {
  83. var originalHeaders = e.DiscoveredDevice.ResponseHeaders;
  84. var headerDict = originalHeaders == null ? new Dictionary<string, KeyValuePair<string, IEnumerable<string>>>() : originalHeaders.ToDictionary(i => i.Key, StringComparer.OrdinalIgnoreCase);
  85. var headers = headerDict.ToDictionary(i => i.Key, i => i.Value.Value.FirstOrDefault(), StringComparer.OrdinalIgnoreCase);
  86. var args = new GenericEventArgs<UpnpDeviceInfo>
  87. {
  88. Argument = new UpnpDeviceInfo
  89. {
  90. Location = e.DiscoveredDevice.DescriptionLocation,
  91. Headers = headers,
  92. LocalIpAddress = e.LocalIpAddress
  93. }
  94. };
  95. DeviceDiscoveredInternal?.Invoke(this, args);
  96. }
  97. private void _DeviceLocator_DeviceUnavailable(object sender, DeviceUnavailableEventArgs e)
  98. {
  99. var originalHeaders = e.DiscoveredDevice.ResponseHeaders;
  100. var headerDict = originalHeaders == null ? new Dictionary<string, KeyValuePair<string, IEnumerable<string>>>() : originalHeaders.ToDictionary(i => i.Key, StringComparer.OrdinalIgnoreCase);
  101. var headers = headerDict.ToDictionary(i => i.Key, i => i.Value.Value.FirstOrDefault(), StringComparer.OrdinalIgnoreCase);
  102. var args = new GenericEventArgs<UpnpDeviceInfo>
  103. {
  104. Argument = new UpnpDeviceInfo
  105. {
  106. Location = e.DiscoveredDevice.DescriptionLocation,
  107. Headers = headers
  108. }
  109. };
  110. DeviceLeft?.Invoke(this, args);
  111. }
  112. public void Dispose()
  113. {
  114. if (!_disposed)
  115. {
  116. _disposed = true;
  117. if (_deviceLocator != null)
  118. {
  119. _deviceLocator.Dispose();
  120. _deviceLocator = null;
  121. }
  122. }
  123. }
  124. }
  125. }