SatIpDiscovery.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. using System;
  2. using System.Linq;
  3. using System.Threading;
  4. using System.Threading.Tasks;
  5. using System.Xml;
  6. using MediaBrowser.Common.Configuration;
  7. using MediaBrowser.Common.Net;
  8. using MediaBrowser.Controller.Configuration;
  9. using MediaBrowser.Controller.Dlna;
  10. using MediaBrowser.Controller.LiveTv;
  11. using MediaBrowser.Controller.Plugins;
  12. using MediaBrowser.Model.LiveTv;
  13. using MediaBrowser.Model.Logging;
  14. using MediaBrowser.Model.Serialization;
  15. using MediaBrowser.Model.Extensions;
  16. using System.Xml.Linq;
  17. using MediaBrowser.Model.Events;
  18. namespace MediaBrowser.Server.Implementations.LiveTv.TunerHosts.SatIp
  19. {
  20. public class SatIpDiscovery : IServerEntryPoint
  21. {
  22. private readonly IDeviceDiscovery _deviceDiscovery;
  23. private readonly IServerConfigurationManager _config;
  24. private readonly ILogger _logger;
  25. private readonly ILiveTvManager _liveTvManager;
  26. private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
  27. private readonly IHttpClient _httpClient;
  28. private readonly IJsonSerializer _json;
  29. private int _tunerCountDVBS=0;
  30. private int _tunerCountDVBC=0;
  31. private int _tunerCountDVBT=0;
  32. private bool _supportsDVBS=false;
  33. private bool _supportsDVBC=false;
  34. private bool _supportsDVBT=false;
  35. public static SatIpDiscovery Current;
  36. public SatIpDiscovery(IDeviceDiscovery deviceDiscovery, IServerConfigurationManager config, ILogger logger, ILiveTvManager liveTvManager, IHttpClient httpClient, IJsonSerializer json)
  37. {
  38. _deviceDiscovery = deviceDiscovery;
  39. _config = config;
  40. _logger = logger;
  41. _liveTvManager = liveTvManager;
  42. _httpClient = httpClient;
  43. _json = json;
  44. Current = this;
  45. }
  46. public void Run()
  47. {
  48. _deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;
  49. }
  50. void _deviceDiscovery_DeviceDiscovered(object sender, GenericEventArgs<UpnpDeviceInfo> e)
  51. {
  52. var info = e.Argument;
  53. string st = null;
  54. string nt = null;
  55. info.Headers.TryGetValue("ST", out st);
  56. info.Headers.TryGetValue("NT", out nt);
  57. if (string.Equals(st, "urn:ses-com:device:SatIPServer:1", StringComparison.OrdinalIgnoreCase) ||
  58. string.Equals(nt, "urn:ses-com:device:SatIPServer:1", StringComparison.OrdinalIgnoreCase))
  59. {
  60. string location;
  61. if (info.Headers.TryGetValue("Location", out location) && !string.IsNullOrWhiteSpace(location))
  62. {
  63. _logger.Debug("SAT IP found at {0}", location);
  64. // Just get the beginning of the url
  65. Uri uri;
  66. if (Uri.TryCreate(location, UriKind.Absolute, out uri))
  67. {
  68. var apiUrl = location.Replace(uri.LocalPath, String.Empty, StringComparison.OrdinalIgnoreCase)
  69. .TrimEnd('/');
  70. AddDevice(apiUrl, location);
  71. }
  72. }
  73. }
  74. }
  75. private async void AddDevice(string deviceUrl, string infoUrl)
  76. {
  77. await _semaphore.WaitAsync().ConfigureAwait(false);
  78. try
  79. {
  80. var options = GetConfiguration();
  81. if (options.TunerHosts.Any(i => string.Equals(i.Type, SatIpHost.DeviceType, StringComparison.OrdinalIgnoreCase) && UriEquals(i.Url, deviceUrl)))
  82. {
  83. return;
  84. }
  85. _logger.Debug("Will attempt to add SAT device {0}", deviceUrl);
  86. var info = await GetInfo(infoUrl, CancellationToken.None).ConfigureAwait(false);
  87. var existing = GetConfiguration().TunerHosts
  88. .FirstOrDefault(i => string.Equals(i.Type, SatIpHost.DeviceType, StringComparison.OrdinalIgnoreCase) && string.Equals(i.DeviceId, info.DeviceId, StringComparison.OrdinalIgnoreCase));
  89. if (existing == null)
  90. {
  91. //if (string.IsNullOrWhiteSpace(info.M3UUrl))
  92. //{
  93. // return;
  94. //}
  95. await _liveTvManager.SaveTunerHost(new TunerHostInfo
  96. {
  97. Type = SatIpHost.DeviceType,
  98. Url = deviceUrl,
  99. InfoUrl = infoUrl,
  100. DataVersion = 1,
  101. DeviceId = info.DeviceId,
  102. FriendlyName = info.FriendlyName,
  103. Tuners = info.Tuners,
  104. M3UUrl = info.M3UUrl,
  105. IsEnabled = true
  106. }, true).ConfigureAwait(false);
  107. }
  108. else
  109. {
  110. existing.Url = deviceUrl;
  111. existing.InfoUrl = infoUrl;
  112. existing.M3UUrl = info.M3UUrl;
  113. existing.FriendlyName = info.FriendlyName;
  114. existing.Tuners = info.Tuners;
  115. await _liveTvManager.SaveTunerHost(existing, false).ConfigureAwait(false);
  116. }
  117. }
  118. catch (OperationCanceledException)
  119. {
  120. }
  121. catch (NotImplementedException)
  122. {
  123. }
  124. catch (Exception ex)
  125. {
  126. _logger.ErrorException("Error saving device", ex);
  127. }
  128. finally
  129. {
  130. _semaphore.Release();
  131. }
  132. }
  133. private bool UriEquals(string savedUri, string location)
  134. {
  135. return string.Equals(NormalizeUrl(location), NormalizeUrl(savedUri), StringComparison.OrdinalIgnoreCase);
  136. }
  137. private string NormalizeUrl(string url)
  138. {
  139. if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
  140. {
  141. url = "http://" + url;
  142. }
  143. url = url.TrimEnd('/');
  144. // Strip off the port
  145. return new Uri(url).GetComponents(UriComponents.AbsoluteUri & ~UriComponents.Port, UriFormat.UriEscaped);
  146. }
  147. private LiveTvOptions GetConfiguration()
  148. {
  149. return _config.GetConfiguration<LiveTvOptions>("livetv");
  150. }
  151. public void Dispose()
  152. {
  153. }
  154. private void ReadCapability(string capability)
  155. {
  156. string[] cap = capability.Split('-');
  157. switch (cap[0].ToLower())
  158. {
  159. case "dvbs":
  160. case "dvbs2":
  161. {
  162. // Optional that you know what an device Supports can you add an flag
  163. _supportsDVBS = true;
  164. for (int i = 0; i < int.Parse(cap[1]); i++)
  165. {
  166. //ToDo Create Digital Recorder / Tuner Capture Instance here for each with index FE param in Sat>Ip Spec for direct communication with this instance
  167. }
  168. _tunerCountDVBS = int.Parse(cap[1]);
  169. break;
  170. }
  171. case "dvbc":
  172. case "dvbc2":
  173. {
  174. // Optional that you know what an device Supports can you add an flag
  175. _supportsDVBC = true;
  176. for (int i = 0; i < int.Parse(cap[1]); i++)
  177. {
  178. //ToDo Create Digital Recorder / Tuner Capture Instance here for each with index FE param in Sat>Ip Spec for direct communication with this instance
  179. }
  180. _tunerCountDVBC = int.Parse(cap[1]);
  181. break;
  182. }
  183. case "dvbt":
  184. case "dvbt2":
  185. {
  186. // Optional that you know what an device Supports can you add an flag
  187. _supportsDVBT = true;
  188. for (int i = 0; i < int.Parse(cap[1]); i++)
  189. {
  190. //ToDo Create Digital Recorder / Tuner Capture Instance here for each with index FE param in Sat>Ip Spec for direct communication with this instance
  191. }
  192. _tunerCountDVBT = int.Parse(cap[1]);
  193. break;
  194. }
  195. }
  196. }
  197. public async Task<SatIpTunerHostInfo> GetInfo(string url, CancellationToken cancellationToken)
  198. {
  199. Uri locationUri = new Uri(url);
  200. string devicetype = "";
  201. string friendlyname = "";
  202. string uniquedevicename = "";
  203. string manufacturer = "";
  204. string manufacturerurl = "";
  205. string modelname = "";
  206. string modeldescription = "";
  207. string modelnumber = "";
  208. string modelurl = "";
  209. string serialnumber = "";
  210. string presentationurl = "";
  211. //string capabilities = "";
  212. string m3u = "";
  213. var document = XDocument.Load(locationUri.AbsoluteUri);
  214. var xnm = new XmlNamespaceManager(new NameTable());
  215. XNamespace n1 = "urn:ses-com:satip";
  216. XNamespace n0 = "urn:schemas-upnp-org:device-1-0";
  217. xnm.AddNamespace("root", n0.NamespaceName);
  218. xnm.AddNamespace("satip:", n1.NamespaceName);
  219. if (document.Root != null)
  220. {
  221. var deviceElement = document.Root.Element(n0 + "device");
  222. if (deviceElement != null)
  223. {
  224. var devicetypeElement = deviceElement.Element(n0 + "deviceType");
  225. if (devicetypeElement != null)
  226. devicetype = devicetypeElement.Value;
  227. var friendlynameElement = deviceElement.Element(n0 + "friendlyName");
  228. if (friendlynameElement != null)
  229. friendlyname = friendlynameElement.Value;
  230. var manufactureElement = deviceElement.Element(n0 + "manufacturer");
  231. if (manufactureElement != null)
  232. manufacturer = manufactureElement.Value;
  233. var manufactureurlElement = deviceElement.Element(n0 + "manufacturerURL");
  234. if (manufactureurlElement != null)
  235. manufacturerurl = manufactureurlElement.Value;
  236. var modeldescriptionElement = deviceElement.Element(n0 + "modelDescription");
  237. if (modeldescriptionElement != null)
  238. modeldescription = modeldescriptionElement.Value;
  239. var modelnameElement = deviceElement.Element(n0 + "modelName");
  240. if (modelnameElement != null)
  241. modelname = modelnameElement.Value;
  242. var modelnumberElement = deviceElement.Element(n0 + "modelNumber");
  243. if (modelnumberElement != null)
  244. modelnumber = modelnumberElement.Value;
  245. var modelurlElement = deviceElement.Element(n0 + "modelURL");
  246. if (modelurlElement != null)
  247. modelurl = modelurlElement.Value;
  248. var serialnumberElement = deviceElement.Element(n0 + "serialNumber");
  249. if (serialnumberElement != null)
  250. serialnumber = serialnumberElement.Value;
  251. var uniquedevicenameElement = deviceElement.Element(n0 + "UDN");
  252. if (uniquedevicenameElement != null) uniquedevicename = uniquedevicenameElement.Value;
  253. var presentationUrlElement = deviceElement.Element(n0 + "presentationURL");
  254. if (presentationUrlElement != null) presentationurl = presentationUrlElement.Value;
  255. var capabilitiesElement = deviceElement.Element(n1 + "X_SATIPCAP");
  256. if (capabilitiesElement != null)
  257. {
  258. //_capabilities = capabilitiesElement.Value;
  259. if (capabilitiesElement.Value.Contains(','))
  260. {
  261. string[] capabilities = capabilitiesElement.Value.Split(',');
  262. foreach (var capability in capabilities)
  263. {
  264. ReadCapability(capability);
  265. }
  266. }
  267. else
  268. {
  269. ReadCapability(capabilitiesElement.Value);
  270. }
  271. }
  272. else
  273. {
  274. _supportsDVBS = true;
  275. _tunerCountDVBS =1;
  276. }
  277. var m3uElement = deviceElement.Element(n1 + "X_SATIPM3U");
  278. if (m3uElement != null) m3u = m3uElement.Value;
  279. }
  280. }
  281. var result = new SatIpTunerHostInfo
  282. {
  283. Url = url,
  284. Id = uniquedevicename,
  285. IsEnabled = true,
  286. Type = SatIpHost.DeviceType,
  287. Tuners = _tunerCountDVBS,
  288. TunersAvailable = _tunerCountDVBS,
  289. M3UUrl = m3u
  290. };
  291. result.FriendlyName = friendlyname;
  292. if (string.IsNullOrWhiteSpace(result.Id))
  293. {
  294. throw new NotImplementedException();
  295. }
  296. else if (!result.M3UUrl.StartsWith("http", StringComparison.OrdinalIgnoreCase))
  297. {
  298. var fullM3uUrl = url.Substring(0, url.LastIndexOf('/'));
  299. result.M3UUrl = fullM3uUrl + "/" + result.M3UUrl.TrimStart('/');
  300. }
  301. _logger.Debug("SAT device result: {0}", _json.SerializeToString(result));
  302. return result;
  303. }
  304. }
  305. public class SatIpTunerHostInfo : TunerHostInfo
  306. {
  307. public int TunersAvailable { get; set; }
  308. }
  309. }