LiveStream.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. #nullable disable
  2. #pragma warning disable CS1591
  3. using System;
  4. using System.Globalization;
  5. using System.IO;
  6. using System.Threading;
  7. using System.Threading.Tasks;
  8. using MediaBrowser.Common.Configuration;
  9. using MediaBrowser.Controller.Library;
  10. using MediaBrowser.Model.Dto;
  11. using MediaBrowser.Model.IO;
  12. using MediaBrowser.Model.LiveTv;
  13. using Microsoft.Extensions.Logging;
  14. namespace Emby.Server.Implementations.LiveTv.TunerHosts
  15. {
  16. public class LiveStream : ILiveStream
  17. {
  18. private readonly IConfigurationManager _configurationManager;
  19. public LiveStream(
  20. MediaSourceInfo mediaSource,
  21. TunerHostInfo tuner,
  22. IFileSystem fileSystem,
  23. ILogger logger,
  24. IConfigurationManager configurationManager,
  25. IStreamHelper streamHelper)
  26. {
  27. OriginalMediaSource = mediaSource;
  28. FileSystem = fileSystem;
  29. MediaSource = mediaSource;
  30. Logger = logger;
  31. EnableStreamSharing = true;
  32. UniqueId = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
  33. if (tuner is not null)
  34. {
  35. TunerHostId = tuner.Id;
  36. }
  37. _configurationManager = configurationManager;
  38. StreamHelper = streamHelper;
  39. ConsumerCount = 1;
  40. SetTempFilePath("ts");
  41. }
  42. protected IFileSystem FileSystem { get; }
  43. protected IStreamHelper StreamHelper { get; }
  44. protected ILogger Logger { get; }
  45. protected CancellationTokenSource LiveStreamCancellationTokenSource { get; } = new CancellationTokenSource();
  46. protected string TempFilePath { get; set; }
  47. public MediaSourceInfo OriginalMediaSource { get; set; }
  48. public MediaSourceInfo MediaSource { get; set; }
  49. public int ConsumerCount { get; set; }
  50. public string OriginalStreamId { get; set; }
  51. public bool EnableStreamSharing { get; set; }
  52. public string UniqueId { get; }
  53. public string TunerHostId { get; }
  54. public DateTime DateOpened { get; protected set; }
  55. protected void SetTempFilePath(string extension)
  56. {
  57. TempFilePath = Path.Combine(_configurationManager.GetTranscodePath(), UniqueId + "." + extension);
  58. }
  59. public virtual Task Open(CancellationToken openCancellationToken)
  60. {
  61. DateOpened = DateTime.UtcNow;
  62. return Task.CompletedTask;
  63. }
  64. public Task Close()
  65. {
  66. EnableStreamSharing = false;
  67. Logger.LogInformation("Closing {Type}", GetType().Name);
  68. LiveStreamCancellationTokenSource.Cancel();
  69. return Task.CompletedTask;
  70. }
  71. public Stream GetStream()
  72. {
  73. var stream = new FileStream(
  74. TempFilePath,
  75. FileMode.Open,
  76. FileAccess.Read,
  77. FileShare.ReadWrite,
  78. IODefaults.FileStreamBufferSize,
  79. FileOptions.SequentialScan | FileOptions.Asynchronous);
  80. bool seekFile = (DateTime.UtcNow - DateOpened).TotalSeconds > 10;
  81. if (seekFile)
  82. {
  83. TrySeek(stream, -20000);
  84. }
  85. return stream;
  86. }
  87. protected async Task DeleteTempFiles(string path, int retryCount = 0)
  88. {
  89. if (retryCount == 0)
  90. {
  91. Logger.LogInformation("Deleting temp file {FilePath}", path);
  92. }
  93. try
  94. {
  95. FileSystem.DeleteFile(path);
  96. }
  97. catch (Exception ex)
  98. {
  99. Logger.LogError(ex, "Error deleting file {FilePath}", path);
  100. if (retryCount <= 40)
  101. {
  102. await Task.Delay(500).ConfigureAwait(false);
  103. await DeleteTempFiles(path, retryCount + 1).ConfigureAwait(false);
  104. }
  105. }
  106. }
  107. private void TrySeek(Stream stream, long offset)
  108. {
  109. if (!stream.CanSeek)
  110. {
  111. return;
  112. }
  113. try
  114. {
  115. stream.Seek(offset, SeekOrigin.End);
  116. }
  117. catch (IOException)
  118. {
  119. }
  120. catch (ArgumentException)
  121. {
  122. }
  123. catch (Exception ex)
  124. {
  125. Logger.LogError(ex, "Error seeking stream");
  126. }
  127. }
  128. }
  129. }