diff --git a/MediaBrowser.Api/ApiEntryPoint.cs b/MediaBrowser.Api/ApiEntryPoint.cs index 763535129a..a212d3f3a7 100644 --- a/MediaBrowser.Api/ApiEntryPoint.cs +++ b/MediaBrowser.Api/ApiEntryPoint.cs @@ -462,7 +462,7 @@ namespace MediaBrowser.Api Logger.LogInformation("Transcoding kill timer stopped for JobId {0} PlaySessionId {1}. Killing transcoding", job.Id, job.PlaySessionId); - KillTranscodingJob(job, true, path => true); + KillTranscodingJob(job, true, path => true).GetAwaiter().GetResult(); } /// @@ -472,9 +472,9 @@ namespace MediaBrowser.Api /// The play session identifier. /// The delete files. /// Task. - internal void KillTranscodingJobs(string deviceId, string playSessionId, Func deleteFiles) + internal Task KillTranscodingJobs(string deviceId, string playSessionId, Func deleteFiles) { - KillTranscodingJobs(j => + return KillTranscodingJobs(j => { if (!string.IsNullOrWhiteSpace(playSessionId)) { @@ -492,7 +492,7 @@ namespace MediaBrowser.Api /// The kill job. /// The delete files. /// Task. - private void KillTranscodingJobs(Func killJob, Func deleteFiles) + private Task KillTranscodingJobs(Func killJob, Func deleteFiles) { var jobs = new List(); @@ -505,13 +505,18 @@ namespace MediaBrowser.Api if (jobs.Count == 0) { - return; + return Task.CompletedTask; } - foreach (var job in jobs) + IEnumerable GetKillJobs() { - KillTranscodingJob(job, false, deleteFiles); + foreach (var job in jobs) + { + yield return KillTranscodingJob(job, false, deleteFiles); + } } + + return Task.WhenAll(GetKillJobs()); } /// @@ -520,7 +525,7 @@ namespace MediaBrowser.Api /// The job. /// if set to true [close live stream]. /// The delete. - private async void KillTranscodingJob(TranscodingJob job, bool closeLiveStream, Func delete) + private async Task KillTranscodingJob(TranscodingJob job, bool closeLiveStream, Func delete) { job.DisposeKillTimer(); @@ -577,7 +582,7 @@ namespace MediaBrowser.Api if (delete(job.Path)) { - DeletePartialStreamFiles(job.Path, job.Type, 0, 1500); + await DeletePartialStreamFiles(job.Path, job.Type, 0, 1500).ConfigureAwait(false); } if (closeLiveStream && !string.IsNullOrWhiteSpace(job.LiveStreamId)) @@ -588,12 +593,12 @@ namespace MediaBrowser.Api } catch (Exception ex) { - Logger.LogError(ex, "Error closing live stream for {path}", job.Path); + Logger.LogError(ex, "Error closing live stream for {Path}", job.Path); } } } - private async void DeletePartialStreamFiles(string path, TranscodingJobType jobType, int retryCount, int delayMs) + private async Task DeletePartialStreamFiles(string path, TranscodingJobType jobType, int retryCount, int delayMs) { if (retryCount >= 10) { @@ -623,7 +628,7 @@ namespace MediaBrowser.Api { Logger.LogError(ex, "Error deleting partial stream file(s) {path}", path); - DeletePartialStreamFiles(path, jobType, retryCount + 1, 500); + await DeletePartialStreamFiles(path, jobType, retryCount + 1, 500).ConfigureAwait(false); } catch (Exception ex) { @@ -650,8 +655,7 @@ namespace MediaBrowser.Api var name = Path.GetFileNameWithoutExtension(outputFilePath); var filesToDelete = _fileSystem.GetFilePaths(directory) - .Where(f => f.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1) - .ToList(); + .Where(f => f.IndexOf(name, StringComparison.OrdinalIgnoreCase) != -1); Exception e = null; diff --git a/MediaBrowser.Api/UserLibrary/PlaystateService.cs b/MediaBrowser.Api/UserLibrary/PlaystateService.cs index 72a9430921..5240144f11 100644 --- a/MediaBrowser.Api/UserLibrary/PlaystateService.cs +++ b/MediaBrowser.Api/UserLibrary/PlaystateService.cs @@ -366,9 +366,9 @@ namespace MediaBrowser.Api.UserLibrary /// Posts the specified request. /// /// The request. - public void Delete(OnPlaybackStopped request) + public Task Delete(OnPlaybackStopped request) { - Post(new ReportPlaybackStopped + return Post(new ReportPlaybackStopped { ItemId = new Guid(request.Id), PositionTicks = request.PositionTicks, @@ -379,20 +379,18 @@ namespace MediaBrowser.Api.UserLibrary }); } - public void Post(ReportPlaybackStopped request) + public async Task Post(ReportPlaybackStopped request) { Logger.LogDebug("ReportPlaybackStopped PlaySessionId: {0}", request.PlaySessionId ?? string.Empty); if (!string.IsNullOrWhiteSpace(request.PlaySessionId)) { - ApiEntryPoint.Instance.KillTranscodingJobs(_authContext.GetAuthorizationInfo(Request).DeviceId, request.PlaySessionId, s => true); + await ApiEntryPoint.Instance.KillTranscodingJobs(_authContext.GetAuthorizationInfo(Request).DeviceId, request.PlaySessionId, s => true); } request.SessionId = GetSession(_sessionContext).Id; - var task = _sessionManager.OnPlaybackStopped(request); - - Task.WaitAll(task); + await _sessionManager.OnPlaybackStopped(request); } /// @@ -403,10 +401,10 @@ namespace MediaBrowser.Api.UserLibrary { var task = MarkUnplayed(request); - return ToOptimizedResult(task.Result); + return ToOptimizedResult(task); } - private async Task MarkUnplayed(MarkUnplayedItem request) + private UserItemDataDto MarkUnplayed(MarkUnplayedItem request) { var user = _userManager.GetUserById(request.UserId); diff --git a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs index b231938b5e..cf239671fa 100644 --- a/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/BaseEncoder.cs @@ -76,24 +76,26 @@ namespace MediaBrowser.MediaEncoding.Encoder var commandLineArgs = GetCommandLineArguments(encodingJob); - Process process = Process.Start(new ProcessStartInfo + Process process = new Process { - WindowStyle = ProcessWindowStyle.Hidden, - CreateNoWindow = true, - UseShellExecute = false, - - // Must consume both stdout and stderr or deadlocks may occur - //RedirectStandardOutput = true, - RedirectStandardError = true, - RedirectStandardInput = true, + StartInfo = new ProcessStartInfo + { + WindowStyle = ProcessWindowStyle.Hidden, + CreateNoWindow = true, + UseShellExecute = false, - FileName = MediaEncoder.EncoderPath, - Arguments = commandLineArgs, + // Must consume both stdout and stderr or deadlocks may occur + //RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, - ErrorDialog = false - }); + FileName = MediaEncoder.EncoderPath, + Arguments = commandLineArgs, - process.EnableRaisingEvents = true; + ErrorDialog = false + }, + EnableRaisingEvents = true + }; var workingDirectory = GetWorkingDirectory(options); if (!string.IsNullOrWhiteSpace(workingDirectory)) @@ -132,50 +134,42 @@ namespace MediaBrowser.MediaEncoding.Encoder cancellationToken.Register(async () => await Cancel(process, encodingJob)); - // MUST read both stdout and stderr asynchronously or a deadlock may occur - //process.BeginOutputReadLine(); - // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback new JobLogger(Logger).StartStreamingLog(encodingJob, process.StandardError.BaseStream, encodingJob.LogFileStream); - // Wait for the file to or for the process to stop - Task file = WaitForFileAsync(encodingJob.OutputFilePath); - await Task.WhenAny(encodingJob.TaskCompletionSource.Task, file).ConfigureAwait(false); - - return encodingJob; - } + Logger.LogInformation("test0"); - public static Task WaitForFileAsync(string path) - { - if (File.Exists(path)) + if (File.Exists(encodingJob.OutputFilePath)) { - return Task.CompletedTask; + return encodingJob; } - var tcs = new TaskCompletionSource(); - FileSystemWatcher watcher = new FileSystemWatcher(Path.GetDirectoryName(path)); + Logger.LogInformation("test1"); - watcher.Created += (s, e) => + using (var watcher = new FileSystemWatcher(Path.GetDirectoryName(encodingJob.OutputFilePath))) { - if (e.Name == Path.GetFileName(path)) - { - watcher.Dispose(); - tcs.TrySetResult(true); - } - }; + var tcs = new TaskCompletionSource(); + string fileName = Path.GetFileName(encodingJob.OutputFilePath); - watcher.Renamed += (s, e) => - { - if (e.Name == Path.GetFileName(path)) + watcher.Created += (s, e) => { - watcher.Dispose(); - tcs.TrySetResult(true); - } - }; + if (e.Name == fileName) + { + tcs.TrySetResult(true); + } + }; - watcher.EnableRaisingEvents = true; + watcher.EnableRaisingEvents = true; - return tcs.Task; + Logger.LogInformation("test2"); + + // Wait for the file to or for the process to stop + await Task.WhenAny(encodingJob.TaskCompletionSource.Task, tcs.Task).ConfigureAwait(false); + + Logger.LogInformation("test3"); + + return encodingJob; + } } private async Task Cancel(Process process, EncodingJob job)