fix: 优化视频/音频检测
This commit is contained in:
117
NativeMethods.cs
117
NativeMethods.cs
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Media.Control;
|
||||
|
||||
namespace TimerApp
|
||||
{
|
||||
@@ -59,12 +60,15 @@ namespace TimerApp
|
||||
private static bool _mediaPlaying;
|
||||
private static long _mediaLastUpdateMs = -1;
|
||||
private static int _mediaUpdateInProgress;
|
||||
private const int MediaCacheWhenPlayingMs = 500;
|
||||
private const int MediaCacheWhenNotPlayingMs = 1200;
|
||||
|
||||
private static void EnsureMediaPlaybackStatusFresh()
|
||||
{
|
||||
long now = Environment.TickCount64;
|
||||
long last = Interlocked.Read(ref _mediaLastUpdateMs);
|
||||
if (last >= 0 && now - last < 3000)
|
||||
int cacheMs = Volatile.Read(ref _mediaPlaying) ? MediaCacheWhenPlayingMs : MediaCacheWhenNotPlayingMs;
|
||||
if (last >= 0 && now - last < cacheMs)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -74,13 +78,24 @@ namespace TimerApp
|
||||
return;
|
||||
}
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
bool playing = false;
|
||||
try
|
||||
{
|
||||
await Task.Yield();
|
||||
playing = TryIsAudioPlaying();
|
||||
playing = RunOnStaThread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return TryIsSystemMediaSessionPlayingAsync().GetAwaiter().GetResult();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
playing = playing || TryIsAudioPlaying();
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -96,6 +111,11 @@ namespace TimerApp
|
||||
}
|
||||
|
||||
private static bool TryIsAudioPlaying()
|
||||
{
|
||||
return TryIsAudioPlaying(ERole.eMultimedia) || TryIsAudioPlaying(ERole.eConsole) || TryIsAudioPlaying(ERole.eCommunications);
|
||||
}
|
||||
|
||||
private static bool TryIsAudioPlaying(ERole role)
|
||||
{
|
||||
object? deviceEnumeratorObj = null;
|
||||
IMMDeviceEnumerator? deviceEnumerator = null;
|
||||
@@ -115,7 +135,7 @@ namespace TimerApp
|
||||
return false;
|
||||
deviceEnumerator = (IMMDeviceEnumerator)deviceEnumeratorObj;
|
||||
|
||||
Marshal.ThrowExceptionForHR(deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, out device));
|
||||
Marshal.ThrowExceptionForHR(deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, role, out device));
|
||||
|
||||
Guid iid = typeof(IAudioSessionManager2).GUID;
|
||||
Marshal.ThrowExceptionForHR(device.Activate(ref iid, CLSCTX.CLSCTX_ALL, IntPtr.Zero, out sessionManagerObj));
|
||||
@@ -141,7 +161,7 @@ namespace TimerApp
|
||||
if (sessionControl is IAudioMeterInformation meter)
|
||||
{
|
||||
Marshal.ThrowExceptionForHR(meter.GetPeakValue(out float peak));
|
||||
if (peak > 0.001f)
|
||||
if (peak > 0.0001f)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -170,6 +190,82 @@ namespace TimerApp
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<bool> TryIsSystemMediaSessionPlayingAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
GlobalSystemMediaTransportControlsSessionManager manager = await GlobalSystemMediaTransportControlsSessionManager.RequestAsync();
|
||||
|
||||
GlobalSystemMediaTransportControlsSession? current = manager.GetCurrentSession();
|
||||
if (IsPlaying(current))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (GlobalSystemMediaTransportControlsSession session in manager.GetSessions())
|
||||
{
|
||||
if (IsPlaying(session))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsPlaying(GlobalSystemMediaTransportControlsSession? session)
|
||||
{
|
||||
if (session is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
GlobalSystemMediaTransportControlsSessionPlaybackInfo? info = session.GetPlaybackInfo();
|
||||
return info is not null && info.PlaybackStatus == GlobalSystemMediaTransportControlsSessionPlaybackStatus.Playing;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool RunOnStaThread(Func<bool> action)
|
||||
{
|
||||
bool result = false;
|
||||
Exception? error = null;
|
||||
|
||||
Thread thread = new Thread(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
result = action();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex;
|
||||
}
|
||||
});
|
||||
|
||||
thread.IsBackground = true;
|
||||
thread.SetApartmentState(ApartmentState.STA);
|
||||
thread.Start();
|
||||
thread.Join();
|
||||
|
||||
if (error is not null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static readonly Guid CLSID_MMDeviceEnumerator = new Guid("BCDE0395-E52F-467C-8E3D-C4579291692E");
|
||||
|
||||
private enum EDataFlow
|
||||
@@ -244,8 +340,15 @@ namespace TimerApp
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
private interface IAudioSessionControl
|
||||
{
|
||||
int NotImpl1();
|
||||
int GetState(out AudioSessionState state);
|
||||
int NotImpl1();
|
||||
int NotImpl2();
|
||||
int NotImpl3();
|
||||
int NotImpl4();
|
||||
int NotImpl5();
|
||||
int NotImpl6();
|
||||
int NotImpl7();
|
||||
int NotImpl8();
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
|
||||
Reference in New Issue
Block a user