diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 774e51bd35..9c17c8d9b1 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -266,6 +266,7 @@
+
diff --git a/MediaBrowser.Controller/Power/IPowerManagement.cs b/MediaBrowser.Controller/Power/IPowerManagement.cs
new file mode 100644
index 0000000000..faa2896952
--- /dev/null
+++ b/MediaBrowser.Controller/Power/IPowerManagement.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace MediaBrowser.Controller.Power
+{
+ public interface IPowerManagement
+ {
+ ///
+ /// Schedules the wake.
+ ///
+ /// The UTC time.
+ void ScheduleWake(DateTime utcTime);
+ }
+}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index dbab7fef7a..e78da617a1 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/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(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;
}
diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
index 80bb671fa7..ca20379b66 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/TimerManager.cs
+++ b/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
{
private readonly ConcurrentDictionary _timers = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
+ private readonly IPowerManagement _powerManagement;
+ private readonly ILogger _logger;
public event EventHandler> 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);
diff --git a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs b/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
index 31d4592c8e..e57a651c00 100644
--- a/MediaBrowser.Server.Mono/Native/BaseMonoApp.cs
+++ b/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();
+ }
}
}
diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
index fb11b8d657..00ba2d172f 100644
--- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs
+++ b/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(new SharingManager(sharingRepo, ServerConfigurationManager, LibraryManager, this));
diff --git a/MediaBrowser.Server.Startup.Common/INativeApp.cs b/MediaBrowser.Server.Startup.Common/INativeApp.cs
index 597caf34cc..75b38d0c4c 100644
--- a/MediaBrowser.Server.Startup.Common/INativeApp.cs
+++ b/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.
///
void PreventSystemStandby();
+
+ ///
+ /// Gets the power management.
+ ///
+ /// IPowerManagement.
+ IPowerManagement GetPowerManagement();
}
}
diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
index c629831923..80e56d6e11 100644
--- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
+++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj
@@ -120,6 +120,7 @@
+
diff --git a/MediaBrowser.ServerApplication/Native/WindowsApp.cs b/MediaBrowser.ServerApplication/Native/WindowsApp.cs
index ceab5379d5..9ef9c7d501 100644
--- a/MediaBrowser.ServerApplication/Native/WindowsApp.cs
+++ b/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();
+ }
}
}
diff --git a/MediaBrowser.ServerApplication/Native/WindowsPowerManagement.cs b/MediaBrowser.ServerApplication/Native/WindowsPowerManagement.cs
new file mode 100644
index 0000000000..6bd78553b6
--- /dev/null
+++ b/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());
+ }
+ }
+ }
+ }
+}