diff options
Diffstat (limited to 'MediaBrowser.Controller/LiveTv/LiveStream.cs')
| -rw-r--r-- | MediaBrowser.Controller/LiveTv/LiveStream.cs | 141 |
1 files changed, 138 insertions, 3 deletions
diff --git a/MediaBrowser.Controller/LiveTv/LiveStream.cs b/MediaBrowser.Controller/LiveTv/LiveStream.cs index 0908c3ecc..48468d1a0 100644 --- a/MediaBrowser.Controller/LiveTv/LiveStream.cs +++ b/MediaBrowser.Controller/LiveTv/LiveStream.cs @@ -1,8 +1,11 @@ using System; using System.Collections.Generic; +using System.IO; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Model.Dto; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.System; namespace MediaBrowser.Controller.LiveTv { @@ -10,7 +13,8 @@ namespace MediaBrowser.Controller.LiveTv { public MediaSourceInfo OriginalMediaSource { get; set; } public MediaSourceInfo OpenedMediaSource { get; set; } - public int ConsumerCount { + public int ConsumerCount + { get { return SharedStreamIds.Count; } } public ITunerHost TunerHost { get; set; } @@ -18,11 +22,16 @@ namespace MediaBrowser.Controller.LiveTv public bool EnableStreamSharing { get; set; } public string UniqueId = Guid.NewGuid().ToString("N"); - public List<string> SharedStreamIds = new List<string>(); + public List<string> SharedStreamIds = new List<string>(); + protected readonly IEnvironmentInfo Environment; + protected readonly IFileSystem FileSystem; + const int StreamCopyToBufferSize = 81920; - public LiveStream(MediaSourceInfo mediaSource) + public LiveStream(MediaSourceInfo mediaSource, IEnvironmentInfo environment, IFileSystem fileSystem) { OriginalMediaSource = mediaSource; + Environment = environment; + FileSystem = fileSystem; OpenedMediaSource = mediaSource; EnableStreamSharing = true; } @@ -41,5 +50,131 @@ namespace MediaBrowser.Controller.LiveTv { return Task.FromResult(true); } + + private Stream GetInputStream(string path, long startPosition, bool allowAsyncFileRead) + { + var fileOpenOptions = startPosition > 0 + ? FileOpenOptions.RandomAccess + : FileOpenOptions.SequentialScan; + + if (allowAsyncFileRead) + { + fileOpenOptions |= FileOpenOptions.Asynchronous; + } + + return FileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.ReadWrite, fileOpenOptions); + } + + protected async Task DeleteTempFile(string path, int retryCount = 0) + { + try + { + FileSystem.DeleteFile(path); + return; + } + catch + { + + } + + if (retryCount > 20) + { + return; + } + + await Task.Delay(500).ConfigureAwait(false); + await DeleteTempFile(path, retryCount + 1).ConfigureAwait(false); + } + + protected async Task CopyFileTo(string path, bool allowEndOfFile, Stream outputStream, CancellationToken cancellationToken) + { + var eofCount = 0; + + long startPosition = -25000; + if (startPosition < 0) + { + var length = FileSystem.GetFileInfo(path).Length; + startPosition = Math.Max(length - startPosition, 0); + } + + // use non-async filestream along with read due to https://github.com/dotnet/corefx/issues/6039 + var allowAsyncFileRead = Environment.OperatingSystem != OperatingSystem.Windows; + + using (var inputStream = GetInputStream(path, startPosition, allowAsyncFileRead)) + { + if (startPosition > 0) + { + inputStream.Position = startPosition; + } + + while (eofCount < 20 || !allowEndOfFile) + { + int bytesRead; + if (allowAsyncFileRead) + { + bytesRead = await CopyToInternalAsync(inputStream, outputStream, cancellationToken).ConfigureAwait(false); + } + else + { + bytesRead = await CopyToInternalAsyncWithSyncRead(inputStream, outputStream, cancellationToken).ConfigureAwait(false); + } + + //var position = fs.Position; + //_logger.Debug("Streamed {0} bytes to position {1} from file {2}", bytesRead, position, path); + + if (bytesRead == 0) + { + eofCount++; + await Task.Delay(100, cancellationToken).ConfigureAwait(false); + } + else + { + eofCount = 0; + } + } + } + } + + private async Task<int> CopyToInternalAsyncWithSyncRead(Stream source, Stream destination, CancellationToken cancellationToken) + { + var array = new byte[StreamCopyToBufferSize]; + int bytesRead; + int totalBytesRead = 0; + + while ((bytesRead = source.Read(array, 0, array.Length)) != 0) + { + var bytesToWrite = bytesRead; + + if (bytesToWrite > 0) + { + await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); + + totalBytesRead += bytesRead; + } + } + + return totalBytesRead; + } + + private async Task<int> CopyToInternalAsync(Stream source, Stream destination, CancellationToken cancellationToken) + { + var array = new byte[StreamCopyToBufferSize]; + int bytesRead; + int totalBytesRead = 0; + + while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0) + { + var bytesToWrite = bytesRead; + + if (bytesToWrite > 0) + { + await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToWrite), cancellationToken).ConfigureAwait(false); + + totalBytesRead += bytesRead; + } + } + + return totalBytesRead; + } } } |
