瀏覽代碼

support system wake on recording schedule

Luke Pulverenti 9 年之前
父節點
當前提交
657e90c98b

+ 1 - 0
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -266,6 +266,7 @@
     <Compile Include="Playlists\IPlaylistManager.cs" />
     <Compile Include="Playlists\Playlist.cs" />
     <Compile Include="Plugins\ILocalizablePlugin.cs" />
+    <Compile Include="Power\IPowerManagement.cs" />
     <Compile Include="Providers\AlbumInfo.cs" />
     <Compile Include="Providers\ArtistInfo.cs" />
     <Compile Include="Providers\BookInfo.cs" />

+ 13 - 0
MediaBrowser.Controller/Power/IPowerManagement.cs

@@ -0,0 +1,13 @@
+using System;
+
+namespace MediaBrowser.Controller.Power
+{
+    public interface IPowerManagement
+    {
+        /// <summary>
+        /// Schedules the wake.
+        /// </summary>
+        /// <param name="utcTime">The UTC time.</param>
+        void ScheduleWake(DateTime utcTime);
+    }
+}

+ 3 - 2
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs

@@ -28,6 +28,7 @@ using System.Threading;
 using System.Threading.Tasks;
 using CommonIO;
 using MediaBrowser.Common.Extensions;
+using MediaBrowser.Controller.Power;
 
 namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
 {
@@ -55,7 +56,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
 
         public static EmbyTV Current;
 
-        public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder)
+        public EmbyTV(IApplicationHost appHost, ILogger logger, IJsonSerializer jsonSerializer, IHttpClient httpClient, IServerConfigurationManager config, ILiveTvManager liveTvManager, IFileSystem fileSystem, ISecurityManager security, ILibraryManager libraryManager, ILibraryMonitor libraryMonitor, IProviderManager providerManager, IFileOrganizationService organizationService, IMediaEncoder mediaEncoder, IPowerManagement powerManagement)
         {
             Current = this;
 
@@ -75,7 +76,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
 
             _recordingProvider = new ItemDataProvider<RecordingInfo>(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "recordings"), (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase));
             _seriesTimerProvider = new SeriesTimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "seriestimers"));
-            _timerProvider = new TimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "timers"));
+            _timerProvider = new TimerManager(fileSystem, jsonSerializer, _logger, Path.Combine(DataPath, "timers"), powerManagement, _logger);
             _timerProvider.TimerFired += _timerProvider_TimerFired;
         }
 

+ 28 - 2
MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs

@@ -8,19 +8,23 @@ using System.Collections.Concurrent;
 using System.Linq;
 using System.Threading;
 using CommonIO;
-using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Power;
 
 namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
 {
     public class TimerManager : ItemDataProvider<TimerInfo>
     {
         private readonly ConcurrentDictionary<string, Timer> _timers = new ConcurrentDictionary<string, Timer>(StringComparer.OrdinalIgnoreCase);
+        private readonly IPowerManagement _powerManagement;
+        private readonly ILogger _logger;
 
         public event EventHandler<GenericEventArgs<TimerInfo>> TimerFired;
 
-        public TimerManager(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath)
+        public TimerManager(IFileSystem fileSystem, IJsonSerializer jsonSerializer, ILogger logger, string dataPath, IPowerManagement powerManagement, ILogger logger1)
             : base(fileSystem, jsonSerializer, logger, dataPath, (r1, r2) => string.Equals(r1.Id, r2.Id, StringComparison.OrdinalIgnoreCase))
         {
+            _powerManagement = powerManagement;
+            _logger = logger1;
         }
 
         public void RestartTimers()
@@ -58,6 +62,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             {
                 var timespan = RecordingHelper.GetStartTime(item) - DateTime.UtcNow;
                 timer.Change(timespan, TimeSpan.Zero);
+                ScheduleWake(item);
             }
             else
             {
@@ -74,6 +79,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
 
             base.Add(item);
             AddTimer(item);
+            ScheduleWake(item);
         }
 
         private void AddTimer(TimerInfo item)
@@ -91,6 +97,26 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV
             StartTimer(item, timerLength);
         }
 
+        private void ScheduleWake(TimerInfo info)
+        {
+            var startDate = RecordingHelper.GetStartTime(info).AddMinutes(-5);
+            _logger.Info("Scheduling system wake timer at {0} (UTC)", startDate);
+
+            try
+            {
+                _powerManagement.ScheduleWake(startDate);
+                _logger.Info("Scheduled system wake timer at {0} (UTC)", startDate);
+            }
+            catch (NotImplementedException)
+            {
+
+            }
+            catch (Exception ex)
+            {
+                _logger.ErrorException("Error scheduling wake timer", ex);
+            }
+        }
+
         public void StartTimer(TimerInfo item, TimeSpan length)
         {
             StopTimer(item);

+ 14 - 0
MediaBrowser.Server.Mono/Native/BaseMonoApp.cs

@@ -8,6 +8,7 @@ using System;
 using System.Collections.Generic;
 using System.Reflection;
 using System.Text.RegularExpressions;
+using MediaBrowser.Controller.Power;
 
 namespace MediaBrowser.Server.Mono.Native
 {
@@ -203,5 +204,18 @@ namespace MediaBrowser.Server.Mono.Native
             public string sysname = string.Empty;
             public string machine = string.Empty;
         }
+
+        public IPowerManagement GetPowerManagement()
+        {
+            return new NullPowerManagement();
+        }
+    }
+
+    public class NullPowerManagement : IPowerManagement
+    {
+        public void ScheduleWake(DateTime utcTime)
+        {
+            throw new NotImplementedException();
+        }
     }
 }

+ 2 - 0
MediaBrowser.Server.Startup.Common/ApplicationHost.cs

@@ -534,6 +534,8 @@ namespace MediaBrowser.Server.Startup.Common
             EncodingManager = new EncodingManager(FileSystemManager, Logger, MediaEncoder, ChapterManager);
             RegisterSingleInstance(EncodingManager);
 
+            RegisterSingleInstance(NativeApp.GetPowerManagement());
+            
             var sharingRepo = new SharingRepository(LogManager, ApplicationPaths);
             await sharingRepo.Initialize().ConfigureAwait(false);
             RegisterSingleInstance<ISharingManager>(new SharingManager(sharingRepo, ServerConfigurationManager, LibraryManager, this));

+ 7 - 0
MediaBrowser.Server.Startup.Common/INativeApp.cs

@@ -2,6 +2,7 @@
 using MediaBrowser.Model.Logging;
 using System.Collections.Generic;
 using System.Reflection;
+using MediaBrowser.Controller.Power;
 
 namespace MediaBrowser.Server.Startup.Common
 {
@@ -90,5 +91,11 @@ namespace MediaBrowser.Server.Startup.Common
         /// Prevents the system stand by.
         /// </summary>
         void PreventSystemStandby();
+
+        /// <summary>
+        /// Gets the power management.
+        /// </summary>
+        /// <returns>IPowerManagement.</returns>
+        IPowerManagement GetPowerManagement();
     }
 }

+ 1 - 0
MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj

@@ -120,6 +120,7 @@
     <Compile Include="Native\Standby.cs" />
     <Compile Include="Native\ServerAuthorization.cs" />
     <Compile Include="Native\WindowsApp.cs" />
+    <Compile Include="Native\WindowsPowerManagement.cs" />
     <Compile Include="Networking\CertificateGenerator.cs" />
     <Compile Include="Networking\NativeMethods.cs" />
     <Compile Include="Networking\NetworkManager.cs" />

+ 6 - 0
MediaBrowser.ServerApplication/Native/WindowsApp.cs

@@ -6,6 +6,7 @@ using MediaBrowser.ServerApplication.Networking;
 using System.Collections.Generic;
 using System.Reflection;
 using CommonIO;
+using MediaBrowser.Controller.Power;
 
 namespace MediaBrowser.ServerApplication.Native
 {
@@ -117,5 +118,10 @@ namespace MediaBrowser.ServerApplication.Native
         {
             Standby.PreventSystemStandby();
         }
+
+        public IPowerManagement GetPowerManagement()
+        {
+            return new WindowsPowerManagement();
+        }
     }
 }

+ 40 - 0
MediaBrowser.ServerApplication/Native/WindowsPowerManagement.cs

@@ -0,0 +1,40 @@
+using System;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+using System.Threading;
+using MediaBrowser.Controller.Power;
+using Microsoft.Win32.SafeHandles;
+
+namespace MediaBrowser.ServerApplication.Native
+{
+    public class WindowsPowerManagement : IPowerManagement
+    {
+        [DllImport("kernel32.dll")]
+        public static extern SafeWaitHandle CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName);
+
+        [DllImport("kernel32.dll", SetLastError = true)]
+        [return: MarshalAs(UnmanagedType.Bool)]
+        public static extern bool SetWaitableTimer(SafeWaitHandle hTimer, [In] ref long pDueTime, int lPeriod, IntPtr pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, bool fResume);
+
+        public void ScheduleWake(DateTime utcTime)
+        {
+            long duetime = utcTime.ToFileTime();
+
+            using (SafeWaitHandle handle = CreateWaitableTimer(IntPtr.Zero, true, "MyWaitabletimer"))
+            {
+                if (SetWaitableTimer(handle, ref duetime, 0, IntPtr.Zero, IntPtr.Zero, true))
+                {
+                    using (EventWaitHandle wh = new EventWaitHandle(false, EventResetMode.AutoReset))
+                    {
+                        wh.SafeWaitHandle = handle;
+                        wh.WaitOne();
+                    }
+                }
+                else
+                {
+                    throw new Win32Exception(Marshal.GetLastWin32Error());
+                }
+            }
+        }
+    }
+}