diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 8f92f062c9..13d184b59c 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -59,6 +59,7 @@ + diff --git a/Emby.Server.Implementations/EntryPoints/SystemEvents.cs b/Emby.Server.Implementations/EntryPoints/SystemEvents.cs new file mode 100644 index 0000000000..021ae47ec3 --- /dev/null +++ b/Emby.Server.Implementations/EntryPoints/SystemEvents.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MediaBrowser.Model.System; +using MediaBrowser.Controller.Plugins; +using MediaBrowser.Common; + +namespace Emby.Server.Implementations.EntryPoints +{ + public class SystemEvents : IServerEntryPoint + { + private readonly ISystemEvents _systemEvents; + private readonly IApplicationHost _appHost; + + public SystemEvents(ISystemEvents systemEvents, IApplicationHost appHost) + { + _systemEvents = systemEvents; + _appHost = appHost; + } + + public void Run() + { + _systemEvents.SessionLogoff += _systemEvents_SessionLogoff; + _systemEvents.SystemShutdown += _systemEvents_SystemShutdown; + } + + private void _systemEvents_SessionLogoff(object sender, EventArgs e) + { + if (!_appHost.IsRunningAsService) + { + _appHost.Shutdown(); + } + } + + private void _systemEvents_SystemShutdown(object sender, EventArgs e) + { + _appHost.Shutdown(); + } + + public void Dispose() + { + _systemEvents.SystemShutdown -= _systemEvents_SystemShutdown; + } + } +} diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index a52ac0e607..ba1f23dfea 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -542,8 +542,6 @@ namespace MediaBrowser.MediaEncoding.Encoder // Must consume both or ffmpeg may hang due to deadlocks. See comments below. RedirectStandardOutput = true, - //RedirectStandardError = true, - RedirectStandardInput = false, FileName = FFProbePath, Arguments = string.Format(args, probeSizeArgument, inputPath).Trim(), @@ -554,7 +552,7 @@ namespace MediaBrowser.MediaEncoding.Encoder _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); - using (var processWrapper = new ProcessWrapper(process, this, _logger, false)) + using (var processWrapper = new ProcessWrapper(process, this, _logger)) { await _ffProbeResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); @@ -616,7 +614,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } catch { - StopProcess(processWrapper, 100, true); + StopProcess(processWrapper, 100); throw; } @@ -671,9 +669,7 @@ namespace MediaBrowser.MediaEncoding.Encoder UseShellExecute = false, // Must consume both or ffmpeg may hang due to deadlocks. See comments below. - //RedirectStandardOutput = true, RedirectStandardError = true, - RedirectStandardInput = false, FileName = FFMpegPath, Arguments = string.Format(args, probeSizeArgument, inputPath, videoStream.Index.ToString(CultureInfo.InvariantCulture)).Trim(), @@ -685,7 +681,7 @@ namespace MediaBrowser.MediaEncoding.Encoder _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); var idetFoundInterlaced = false; - using (var processWrapper = new ProcessWrapper(process, this, _logger, false)) + using (var processWrapper = new ProcessWrapper(process, this, _logger)) { try { @@ -728,7 +724,7 @@ namespace MediaBrowser.MediaEncoding.Encoder } catch { - StopProcess(processWrapper, 100, true); + StopProcess(processWrapper, 100); throw; } @@ -945,7 +941,7 @@ namespace MediaBrowser.MediaEncoding.Encoder _logger.Debug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); - using (var processWrapper = new ProcessWrapper(process, this, _logger, false)) + using (var processWrapper = new ProcessWrapper(process, this, _logger)) { await resourcePool.WaitAsync(cancellationToken).ConfigureAwait(false); @@ -965,7 +961,7 @@ namespace MediaBrowser.MediaEncoding.Encoder if (!ranToCompletion) { - StopProcess(processWrapper, 1000, false); + StopProcess(processWrapper, 1000); } } @@ -1043,8 +1039,7 @@ namespace MediaBrowser.MediaEncoding.Encoder FileName = FFMpegPath, Arguments = args, IsHidden = true, - ErrorDialog = false, - RedirectStandardInput = true + ErrorDialog = false }); _logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments); @@ -1053,7 +1048,7 @@ namespace MediaBrowser.MediaEncoding.Encoder bool ranToCompletion = false; - using (var processWrapper = new ProcessWrapper(process, this, _logger, true)) + using (var processWrapper = new ProcessWrapper(process, this, _logger)) { try { @@ -1085,7 +1080,7 @@ namespace MediaBrowser.MediaEncoding.Encoder if (!ranToCompletion) { - StopProcess(processWrapper, 1000, false); + StopProcess(processWrapper, 1000); } } finally @@ -1157,40 +1152,25 @@ namespace MediaBrowser.MediaEncoding.Encoder _runningProcesses.Add(process); } } - private void StopProcess(ProcessWrapper process, int waitTimeMs, bool enableForceKill) + private void StopProcess(ProcessWrapper process, int waitTimeMs) { + try + { + if (process.Process.WaitForExit(waitTimeMs)) + { + return; + } + } + catch (Exception ex) + { + _logger.Error("Error in WaitForExit", ex); + } + try { _logger.Info("Killing ffmpeg process"); - if (process.IsRedirectingStdin) - { - try - { - process.Process.StandardInput.WriteLine("q"); - } - catch (Exception) - { - _logger.Error("Error sending q command to process"); - } - } - - try - { - if (process.Process.WaitForExit(waitTimeMs)) - { - return; - } - } - catch (Exception ex) - { - _logger.Error("Error in WaitForExit", ex); - } - - if (enableForceKill) - { - process.Process.Kill(); - } + process.Process.Kill(); } catch (Exception ex) { @@ -1211,7 +1191,7 @@ namespace MediaBrowser.MediaEncoding.Encoder { if (!process.HasExited) { - StopProcess(process, 500, true); + StopProcess(process, 500); } } } @@ -1252,15 +1232,13 @@ namespace MediaBrowser.MediaEncoding.Encoder public int? ExitCode; private readonly MediaEncoder _mediaEncoder; private readonly ILogger _logger; - public bool IsRedirectingStdin { get; private set; } - public ProcessWrapper(IProcess process, MediaEncoder mediaEncoder, ILogger logger, bool isRedirectingStdin) + public ProcessWrapper(IProcess process, MediaEncoder mediaEncoder, ILogger logger) { Process = process; _mediaEncoder = mediaEncoder; _logger = logger; Process.Exited += Process_Exited; - IsRedirectingStdin = isRedirectingStdin; } void Process_Exited(object sender, EventArgs e) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 5d065f5283..9b31a1012e 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -444,10 +444,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles var process = _processFactory.Create(new ProcessOptions { - RedirectStandardOutput = false, - RedirectStandardError = true, - RedirectStandardInput = true, - CreateNoWindow = true, UseShellExecute = false, FileName = _mediaEncoder.EncoderPath, @@ -459,26 +455,16 @@ namespace MediaBrowser.MediaEncoding.Subtitles _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); - var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-sub-convert-" + Guid.NewGuid() + ".txt"); - _fileSystem.CreateDirectory(Path.GetDirectoryName(logFilePath)); - - var logFileStream = _fileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, - true); - try { process.Start(); } catch (Exception ex) { - logFileStream.Dispose(); - _logger.ErrorException("Error starting ffmpeg", ex); throw; } - - var logTask = process.StandardError.BaseStream.CopyToAsync(logFileStream); var ranToCompletion = process.WaitForExit(60000); @@ -488,19 +474,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles { _logger.Info("Killing ffmpeg subtitle conversion process"); - process.StandardInput.WriteLine("q"); - process.WaitForExit(1000); - - await logTask.ConfigureAwait(false); + process.Kill(); } catch (Exception ex) { _logger.ErrorException("Error killing subtitle conversion process", ex); } - finally - { - logFileStream.Dispose(); - } } var exitCode = ranToCompletion ? process.ExitCode : -1; @@ -533,13 +512,15 @@ namespace MediaBrowser.MediaEncoding.Subtitles if (failed) { - var msg = string.Format("ffmpeg subtitle converted failed for {0}", inputPath); + var msg = string.Format("ffmpeg subtitle conversion failed for {0}", inputPath); _logger.Error(msg); throw new Exception(msg); } await SetAssFont(outputPath).ConfigureAwait(false); + + _logger.Info("ffmpeg subtitle conversion succeeded for {0}", inputPath); } /// @@ -597,10 +578,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles CreateNoWindow = true, UseShellExecute = false, - RedirectStandardOutput = false, - RedirectStandardError = true, - RedirectStandardInput = true, - FileName = _mediaEncoder.EncoderPath, Arguments = processArgs, IsHidden = true, @@ -609,28 +586,17 @@ namespace MediaBrowser.MediaEncoding.Subtitles _logger.Info("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); - var logFilePath = Path.Combine(_appPaths.LogDirectoryPath, "ffmpeg-sub-extract-" + Guid.NewGuid() + ".txt"); - _fileSystem.CreateDirectory(Path.GetDirectoryName(logFilePath)); - - var logFileStream = _fileSystem.GetFileStream(logFilePath, FileOpenMode.Create, FileAccessMode.Write, FileShareMode.Read, - true); - try { process.Start(); } catch (Exception ex) { - logFileStream.Dispose(); - _logger.ErrorException("Error starting ffmpeg", ex); throw; } - // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback - Task.Run(() => StartStreamingLog(process.StandardError.BaseStream, logFileStream)); - var ranToCompletion = process.WaitForExit(300000); if (!ranToCompletion) @@ -639,17 +605,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles { _logger.Info("Killing ffmpeg subtitle extraction process"); - process.StandardInput.WriteLine("q"); - process.WaitForExit(1000); + process.Kill(); } catch (Exception ex) { _logger.ErrorException("Error killing subtitle extraction process", ex); } - finally - { - logFileStream.Dispose(); - } } var exitCode = ranToCompletion ? process.ExitCode : -1; @@ -702,33 +663,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles } } - private async Task StartStreamingLog(Stream source, Stream target) - { - try - { - using (var reader = new StreamReader(source)) - { - while (!reader.EndOfStream) - { - var line = await reader.ReadLineAsync().ConfigureAwait(false); - - var bytes = Encoding.UTF8.GetBytes(Environment.NewLine + line); - - await target.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); - await target.FlushAsync().ConfigureAwait(false); - } - } - } - catch (ObjectDisposedException) - { - // Don't spam the log. This doesn't seem to throw in windows, but sometimes under linux - } - catch (Exception ex) - { - _logger.ErrorException("Error reading ffmpeg log", ex); - } - } - /// /// Sets the ass font. /// diff --git a/MediaBrowser.Model/System/ISystemEvents.cs b/MediaBrowser.Model/System/ISystemEvents.cs index c50f8ce030..dec8ed8c02 100644 --- a/MediaBrowser.Model/System/ISystemEvents.cs +++ b/MediaBrowser.Model/System/ISystemEvents.cs @@ -6,5 +6,7 @@ namespace MediaBrowser.Model.System { event EventHandler Resume; event EventHandler Suspend; + event EventHandler SessionLogoff; + event EventHandler SystemShutdown; } } diff --git a/MediaBrowser.Server.Mono/Program.cs b/MediaBrowser.Server.Mono/Program.cs index 470525eced..7fc3ff22e4 100644 --- a/MediaBrowser.Server.Mono/Program.cs +++ b/MediaBrowser.Server.Mono/Program.cs @@ -1,8 +1,6 @@ using MediaBrowser.Model.Logging; -using MediaBrowser.Server.Implementations; using MediaBrowser.Server.Mono.Native; using MediaBrowser.Server.Startup.Common; -using Microsoft.Win32; using System; using System.Diagnostics; using System.Globalization; @@ -14,7 +12,6 @@ using System.Reflection; using System.Text.RegularExpressions; using System.Threading.Tasks; using Emby.Common.Implementations.EnvironmentInfo; -using Emby.Common.Implementations.IO; using Emby.Common.Implementations.Logging; using Emby.Common.Implementations.Networking; using Emby.Common.Implementations.Security; @@ -84,8 +81,6 @@ namespace MediaBrowser.Server.Mono private static void RunApplication(ServerApplicationPaths appPaths, ILogManager logManager, StartupOptions options) { - Microsoft.Win32.SystemEvents.SessionEnding += SystemEvents_SessionEnding; - // Allow all https requests ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; }); @@ -108,7 +103,7 @@ namespace MediaBrowser.Server.Mono new MemoryStreamProvider(), new NetworkManager(logManager.GetLogger("NetworkManager")), GenerateCertificate, - () => Environment.UserDomainName); + () => Environment.UserName); if (options.ContainsOption("-v")) { @@ -219,19 +214,6 @@ namespace MediaBrowser.Server.Mono public string machine = string.Empty; } - /// - /// Handles the SessionEnding event of the SystemEvents control. - /// - /// The source of the event. - /// The instance containing the event data. - static void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e) - { - if (e.Reason == SessionEndReasons.SystemShutdown) - { - Shutdown(); - } - } - /// /// Handles the UnhandledException event of the CurrentDomain control. /// diff --git a/MediaBrowser.Server.Startup.Common/SystemEvents.cs b/MediaBrowser.Server.Startup.Common/SystemEvents.cs index 088d04a249..8d5cd4ad8c 100644 --- a/MediaBrowser.Server.Startup.Common/SystemEvents.cs +++ b/MediaBrowser.Server.Startup.Common/SystemEvents.cs @@ -9,6 +9,8 @@ namespace MediaBrowser.Server.Startup.Common { public event EventHandler Resume; public event EventHandler Suspend; + public event EventHandler SessionLogoff; + public event EventHandler SystemShutdown; private readonly ILogger _logger; @@ -16,6 +18,20 @@ namespace MediaBrowser.Server.Startup.Common { _logger = logger; Microsoft.Win32.SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; + Microsoft.Win32.SystemEvents.SessionEnding += SystemEvents_SessionEnding; + } + + private void SystemEvents_SessionEnding(object sender, Microsoft.Win32.SessionEndingEventArgs e) + { + switch (e.Reason) + { + case Microsoft.Win32.SessionEndReasons.Logoff: + EventHelper.FireEventIfNotNull(SessionLogoff, this, EventArgs.Empty, _logger); + break; + case Microsoft.Win32.SessionEndReasons.SystemShutdown: + EventHelper.FireEventIfNotNull(SystemShutdown, this, EventArgs.Empty, _logger); + break; + } } private void SystemEvents_PowerModeChanged(object sender, Microsoft.Win32.PowerModeChangedEventArgs e) diff --git a/MediaBrowser.ServerApplication/MainStartup.cs b/MediaBrowser.ServerApplication/MainStartup.cs index c0ebcde74a..f5e7681333 100644 --- a/MediaBrowser.ServerApplication/MainStartup.cs +++ b/MediaBrowser.ServerApplication/MainStartup.cs @@ -368,7 +368,6 @@ namespace MediaBrowser.ServerApplication task = InstallVcredist2013IfNeeded(_appHost, _logger); Task.WaitAll(task); - Microsoft.Win32.SystemEvents.SessionEnding += SystemEvents_SessionEnding; Microsoft.Win32.SystemEvents.SessionSwitch += SystemEvents_SessionSwitch; HideSplashScreen(); @@ -569,19 +568,6 @@ namespace MediaBrowser.ServerApplication } } - /// - /// Handles the SessionEnding event of the SystemEvents control. - /// - /// The source of the event. - /// The instance containing the event data. - static void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e) - { - if (e.Reason == SessionEndReasons.SystemShutdown || !IsRunningAsService) - { - Shutdown(); - } - } - /// /// Handles the UnhandledException event of the CurrentDomain control. ///