refactor: 移除媒体检测逻辑,简化代码体积
This commit is contained in:
@@ -22,9 +22,8 @@ namespace TimerApp
|
|||||||
|
|
||||||
// 状态检测缓存
|
// 状态检测缓存
|
||||||
private int _checkTickCounter;
|
private int _checkTickCounter;
|
||||||
private const int CheckIntervalTicks = 3; // 每3秒检查一次空闲/媒体状态
|
private const int CheckIntervalTicks = 3; // 每3秒检查一次空闲状态
|
||||||
private long _cachedIdleMs;
|
private long _cachedIdleMs;
|
||||||
private bool _cachedMediaPlaying;
|
|
||||||
|
|
||||||
// 配置 (默认值)
|
// 配置 (默认值)
|
||||||
public TimeSpan WorkDuration { get; set; } = TimeSpan.FromMinutes(20);
|
public TimeSpan WorkDuration { get; set; } = TimeSpan.FromMinutes(20);
|
||||||
@@ -47,7 +46,6 @@ namespace TimerApp
|
|||||||
|
|
||||||
public ActivityMonitor()
|
public ActivityMonitor()
|
||||||
{
|
{
|
||||||
SystemEvents.PowerModeChanged += OnPowerModeChanged;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
@@ -126,7 +124,7 @@ namespace TimerApp
|
|||||||
{
|
{
|
||||||
// 在锁外执行耗时的系统检测
|
// 在锁外执行耗时的系统检测
|
||||||
long idleMs = 0;
|
long idleMs = 0;
|
||||||
bool? newMediaPlaying = null;
|
bool shouldUpdate = false;
|
||||||
|
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
@@ -139,27 +137,25 @@ namespace TimerApp
|
|||||||
{
|
{
|
||||||
_checkTickCounter = 0;
|
_checkTickCounter = 0;
|
||||||
// 需要更新,但在锁外进行
|
// 需要更新,但在锁外进行
|
||||||
newMediaPlaying = true;
|
shouldUpdate = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果不需要更新,直接使用缓存值
|
// 如果不需要更新,直接使用缓存值
|
||||||
if (newMediaPlaying == null)
|
if (!shouldUpdate)
|
||||||
{
|
{
|
||||||
idleMs = _cachedIdleMs;
|
idleMs = _cachedIdleMs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在锁外执行实际的检测
|
// 在锁外执行实际的检测
|
||||||
if (newMediaPlaying == true)
|
if (shouldUpdate)
|
||||||
{
|
{
|
||||||
idleMs = NativeMethods.GetIdleTime();
|
idleMs = NativeMethods.GetIdleTime();
|
||||||
bool playing = NativeMethods.IsMediaPlaying();
|
|
||||||
|
|
||||||
// 更新缓存
|
// 更新缓存
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
_cachedIdleMs = idleMs;
|
_cachedIdleMs = idleMs;
|
||||||
_cachedMediaPlaying = playing;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +166,6 @@ namespace TimerApp
|
|||||||
|
|
||||||
// 使用(可能是新更新的)缓存值
|
// 使用(可能是新更新的)缓存值
|
||||||
idleMs = _cachedIdleMs;
|
idleMs = _cachedIdleMs;
|
||||||
bool isMediaPlaying = _cachedMediaPlaying;
|
|
||||||
TimeSpan idleTime = TimeSpan.FromMilliseconds(idleMs);
|
TimeSpan idleTime = TimeSpan.FromMilliseconds(idleMs);
|
||||||
|
|
||||||
if (CurrentState == MonitorState.Resting)
|
if (CurrentState == MonitorState.Resting)
|
||||||
@@ -196,12 +191,13 @@ namespace TimerApp
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 工作/空闲模式逻辑
|
// 工作/空闲模式逻辑
|
||||||
if (idleTime > IdleThreshold || isMediaPlaying)
|
bool isUserInactive = idleTime > IdleThreshold;
|
||||||
|
|
||||||
|
if (isUserInactive)
|
||||||
{
|
{
|
||||||
// 用户离开了或正在播放视频
|
// 用户确实离开了 -> 进入空闲状态
|
||||||
if (CurrentState == MonitorState.Working)
|
if (CurrentState == MonitorState.Working)
|
||||||
{
|
{
|
||||||
// 如果空闲时间超过阈值,状态变为空闲
|
|
||||||
ChangeState(MonitorState.Idle);
|
ChangeState(MonitorState.Idle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,24 +207,17 @@ namespace TimerApp
|
|||||||
{
|
{
|
||||||
_accumulatedWorkTime = TimeSpan.Zero;
|
_accumulatedWorkTime = TimeSpan.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果正在播放视频,不累加工作时间,但保持当前状态
|
|
||||||
if (isMediaPlaying && CurrentState == MonitorState.Working)
|
|
||||||
{
|
|
||||||
TimeSpan remainingWork = WorkDuration - _accumulatedWorkTime;
|
|
||||||
WorkProgressChanged?.Invoke(this, remainingWork);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 用户在活动且没有播放视频
|
// 用户在活动
|
||||||
if (CurrentState == MonitorState.Idle)
|
if (CurrentState == MonitorState.Idle)
|
||||||
{
|
{
|
||||||
// 从空闲变为工作
|
// 从空闲变为工作
|
||||||
ChangeState(MonitorState.Working);
|
ChangeState(MonitorState.Working);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 累加工作时间
|
// 正常工作:累加时间
|
||||||
_accumulatedWorkTime += TimeSpan.FromSeconds(1);
|
_accumulatedWorkTime += TimeSpan.FromSeconds(1);
|
||||||
|
|
||||||
// 检查是否达到工作时长
|
// 检查是否达到工作时长
|
||||||
@@ -277,13 +266,6 @@ namespace TimerApp
|
|||||||
_accumulatedWorkTime = TimeSpan.Zero;
|
_accumulatedWorkTime = TimeSpan.Zero;
|
||||||
_isPaused = false;
|
_isPaused = false;
|
||||||
|
|
||||||
// Ensure task is running
|
|
||||||
if (_cts == null || _cts.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
// Re-start if stopped (though Restart implies it's running)
|
|
||||||
// Usually Start() calls ResetWork, so we just reset here
|
|
||||||
}
|
|
||||||
|
|
||||||
// Force state to Working since user manually restarted
|
// Force state to Working since user manually restarted
|
||||||
ChangeState(MonitorState.Working);
|
ChangeState(MonitorState.Working);
|
||||||
|
|
||||||
@@ -322,18 +304,10 @@ namespace TimerApp
|
|||||||
if (_disposed) return;
|
if (_disposed) return;
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
|
|
||||||
SystemEvents.PowerModeChanged -= OnPowerModeChanged;
|
// SystemEvents.PowerModeChanged -= OnPowerModeChanged;
|
||||||
Stop();
|
Stop();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.Mode == PowerModes.Resume)
|
|
||||||
{
|
|
||||||
// 系统唤醒时,强制重置媒体播放检测状态,
|
|
||||||
// 避免因检测线程挂起导致一直误报“正在播放”而无法进入工作状态。
|
|
||||||
NativeMethods.InvalidateMediaCache();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,10 +25,6 @@ namespace TimerApp
|
|||||||
public static extern bool ReleaseCapture();
|
public static extern bool ReleaseCapture();
|
||||||
[DllImport("user32.dll")]
|
[DllImport("user32.dll")]
|
||||||
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
|
public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
|
||||||
[DllImport("user32.dll")]
|
|
||||||
static extern bool CreateCaret(IntPtr hWnd, IntPtr hBitmap, int nWidth, int nHeight);
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
static extern bool ShowCaret(IntPtr hWnd);
|
|
||||||
|
|
||||||
private const int WM_NCLBUTTONDOWN = 0xA1;
|
private const int WM_NCLBUTTONDOWN = 0xA1;
|
||||||
private const int HT_CAPTION = 0x2;
|
private const int HT_CAPTION = 0x2;
|
||||||
@@ -611,6 +607,7 @@ namespace TimerApp
|
|||||||
private void toolStripMenuItemExit_Click(object sender, EventArgs e)
|
private void toolStripMenuItemExit_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
_monitor.Stop();
|
_monitor.Stop();
|
||||||
|
_monitor.Dispose();
|
||||||
notifyIcon1.Visible = false;
|
notifyIcon1.Visible = false;
|
||||||
notifyIcon1.Dispose();
|
notifyIcon1.Dispose();
|
||||||
Application.Exit();
|
Application.Exit();
|
||||||
|
|||||||
335
NativeMethods.cs
335
NativeMethods.cs
@@ -2,7 +2,6 @@ using System;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Windows.Media.Control;
|
|
||||||
|
|
||||||
namespace TimerApp
|
namespace TimerApp
|
||||||
{
|
{
|
||||||
@@ -47,346 +46,12 @@ namespace TimerApp
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================
|
|
||||||
// Media Detection Logic (Refactored)
|
|
||||||
// ==========================================
|
|
||||||
|
|
||||||
private static volatile bool _isMediaPlayingCaught;
|
|
||||||
private static Thread? _mediaMonitorThread;
|
|
||||||
private static readonly CancellationTokenSource _cts = new CancellationTokenSource();
|
|
||||||
private static readonly AutoResetEvent _checkSignal = new AutoResetEvent(false);
|
|
||||||
|
|
||||||
static NativeMethods()
|
static NativeMethods()
|
||||||
{
|
{
|
||||||
// 在静态构造函数中启动后台监控线程
|
|
||||||
StartMediaMonitor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 检测是否有媒体正在播放(视频或音频)
|
|
||||||
/// 直接返回缓存的状态,无阻塞
|
|
||||||
/// </summary>
|
|
||||||
public static bool IsMediaPlaying()
|
|
||||||
{
|
|
||||||
return _isMediaPlayingCaught;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 强制立即进行一次检测
|
|
||||||
/// </summary>
|
|
||||||
public static void InvalidateMediaCache()
|
|
||||||
{
|
|
||||||
// 唤醒后台线程立即检测
|
|
||||||
_checkSignal.Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用退出时清理资源 (可选调用)
|
|
||||||
/// </summary>
|
|
||||||
public static void Shutdown()
|
public static void Shutdown()
|
||||||
{
|
{
|
||||||
_cts.Cancel();
|
|
||||||
_checkSignal.Set(); // Wake up to exit
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void StartMediaMonitor()
|
|
||||||
{
|
|
||||||
if (_mediaMonitorThread != null) return;
|
|
||||||
|
|
||||||
_mediaMonitorThread = new Thread(MediaMonitorLoop)
|
|
||||||
{
|
|
||||||
IsBackground = true,
|
|
||||||
Name = "TimerApp_MediaMonitor",
|
|
||||||
Priority = ThreadPriority.BelowNormal
|
|
||||||
};
|
|
||||||
_mediaMonitorThread.SetApartmentState(ApartmentState.STA); // COM requirement
|
|
||||||
_mediaMonitorThread.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void MediaMonitorLoop()
|
|
||||||
{
|
|
||||||
while (!_cts.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
bool isPlaying = false;
|
|
||||||
|
|
||||||
// 1. Check System Media Transport Controls (WinRT)
|
|
||||||
// 需要在 STA 线程中小心处理 Task
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 使用 Task.Run 确保在一个干净的上下文执行异步任务,然后同步等待结果
|
|
||||||
// 注意:因为我们本身就在 STA 线程,直接 .Result 可能会有风险,
|
|
||||||
// 但对于 GSMTC API,只要没有 SynchronizationContext 绑定到此线程通常是安全的。
|
|
||||||
// 这里为了稳妥,我们捕获任何异常。
|
|
||||||
isPlaying = CheckSystemMediaTransportControls();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Ignored
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Check Legacy Audio Session API (COM)
|
|
||||||
if (!isPlaying)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
isPlaying = TryIsAudioPlaying();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Ignored
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update volatile cache
|
|
||||||
_isMediaPlayingCaught = isPlaying;
|
|
||||||
|
|
||||||
// Wait for next check (default 1s, or wake up immediately on Invalidate)
|
|
||||||
_checkSignal.WaitOne(1000);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Prevent thread crash
|
|
||||||
Thread.Sleep(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool CheckSystemMediaTransportControls()
|
|
||||||
{
|
|
||||||
// 同步等待异步方法,因为我们在专用线程上,且没有 UI SyncContext,这是安全的
|
|
||||||
return CheckSystemMediaTransportControlsAsync().GetAwaiter().GetResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task<bool> CheckSystemMediaTransportControlsAsync()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// RequestAsync 可能在某些系统上较慢
|
|
||||||
var manager = await GlobalSystemMediaTransportControlsSessionManager.RequestAsync();
|
|
||||||
|
|
||||||
var current = manager.GetCurrentSession();
|
|
||||||
if (IsPlaying(current)) return true;
|
|
||||||
|
|
||||||
foreach (var session in manager.GetSessions())
|
|
||||||
{
|
|
||||||
if (IsPlaying(session)) return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsPlaying(GlobalSystemMediaTransportControlsSession? session)
|
|
||||||
{
|
|
||||||
if (session == null) return false;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var info = session.GetPlaybackInfo();
|
|
||||||
return info != null && info.PlaybackStatus == GlobalSystemMediaTransportControlsSessionPlaybackStatus.Playing;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==========================================
|
|
||||||
// COM Audio Detection
|
|
||||||
// ==========================================
|
|
||||||
|
|
||||||
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;
|
|
||||||
IMMDevice? device = null;
|
|
||||||
object? sessionManagerObj = null;
|
|
||||||
IAudioSessionManager2? sessionManager = null;
|
|
||||||
IAudioSessionEnumerator? sessionEnumerator = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Type? enumeratorType = Type.GetTypeFromCLSID(CLSID_MMDeviceEnumerator);
|
|
||||||
if (enumeratorType is null) return false;
|
|
||||||
|
|
||||||
deviceEnumeratorObj = Activator.CreateInstance(enumeratorType);
|
|
||||||
if (deviceEnumeratorObj is null) return false;
|
|
||||||
deviceEnumerator = (IMMDeviceEnumerator)deviceEnumeratorObj;
|
|
||||||
|
|
||||||
// GetDefaultAudioEndpoint can fail if no audio device is present
|
|
||||||
int hr = deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, role, out device);
|
|
||||||
if (hr != 0) return false; // S_OK = 0
|
|
||||||
|
|
||||||
Guid iid = typeof(IAudioSessionManager2).GUID;
|
|
||||||
hr = device.Activate(ref iid, CLSCTX.CLSCTX_ALL, IntPtr.Zero, out sessionManagerObj);
|
|
||||||
if (hr != 0 || sessionManagerObj is null) return false;
|
|
||||||
|
|
||||||
sessionManager = (IAudioSessionManager2)sessionManagerObj;
|
|
||||||
|
|
||||||
hr = sessionManager.GetSessionEnumerator(out sessionEnumerator);
|
|
||||||
if (hr != 0) return false;
|
|
||||||
|
|
||||||
hr = sessionEnumerator.GetCount(out int count);
|
|
||||||
if (hr != 0) return false;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
IAudioSessionControl? sessionControl = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
hr = sessionEnumerator.GetSession(i, out sessionControl);
|
|
||||||
if (hr != 0 || sessionControl is null) continue;
|
|
||||||
|
|
||||||
hr = sessionControl.GetState(out AudioSessionState state);
|
|
||||||
if (hr != 0) continue;
|
|
||||||
|
|
||||||
if (state == AudioSessionState.Active)
|
|
||||||
{
|
|
||||||
if (sessionControl is IAudioMeterInformation meter)
|
|
||||||
{
|
|
||||||
hr = meter.GetPeakValue(out float peak);
|
|
||||||
if (hr == 0 && peak > 0.000001f) // Slightly relaxed threshold
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Cannot check peak, assume active means playing
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (sessionControl != null) Marshal.FinalReleaseComObject(sessionControl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (sessionEnumerator != null) Marshal.FinalReleaseComObject(sessionEnumerator);
|
|
||||||
if (sessionManager != null) Marshal.FinalReleaseComObject(sessionManager); // Corrected variable usage
|
|
||||||
if (sessionManagerObj != null) Marshal.FinalReleaseComObject(sessionManagerObj);
|
|
||||||
if (device != null) Marshal.FinalReleaseComObject(device);
|
|
||||||
if (deviceEnumeratorObj != null) Marshal.FinalReleaseComObject(deviceEnumeratorObj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly Guid CLSID_MMDeviceEnumerator = new Guid("BCDE0395-E52F-467C-8E3D-C4579291692E");
|
|
||||||
|
|
||||||
private enum EDataFlow
|
|
||||||
{
|
|
||||||
eRender = 0,
|
|
||||||
eCapture = 1,
|
|
||||||
eAll = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum ERole
|
|
||||||
{
|
|
||||||
eConsole = 0,
|
|
||||||
eMultimedia = 1,
|
|
||||||
eCommunications = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum AudioSessionState
|
|
||||||
{
|
|
||||||
Inactive = 0,
|
|
||||||
Active = 1,
|
|
||||||
Expired = 2
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
private enum CLSCTX : uint
|
|
||||||
{
|
|
||||||
CLSCTX_INPROC_SERVER = 0x1,
|
|
||||||
CLSCTX_INPROC_HANDLER = 0x2,
|
|
||||||
CLSCTX_LOCAL_SERVER = 0x4,
|
|
||||||
CLSCTX_REMOTE_SERVER = 0x10,
|
|
||||||
CLSCTX_ALL = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
|
|
||||||
}
|
|
||||||
|
|
||||||
[ComImport]
|
|
||||||
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6")]
|
|
||||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
||||||
private interface IMMDeviceEnumerator
|
|
||||||
{
|
|
||||||
int NotImpl1();
|
|
||||||
[PreserveSig]
|
|
||||||
int GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, out IMMDevice ppDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
[ComImport]
|
|
||||||
[Guid("D666063F-1587-4E43-81F1-B948E807363F")]
|
|
||||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
||||||
private interface IMMDevice
|
|
||||||
{
|
|
||||||
[PreserveSig]
|
|
||||||
int Activate(ref Guid iid, CLSCTX dwClsCtx, IntPtr pActivationParams, [MarshalAs(UnmanagedType.IUnknown)] out object ppInterface);
|
|
||||||
}
|
|
||||||
|
|
||||||
[ComImport]
|
|
||||||
[Guid("77AA99A0-1BD6-484F-8BC7-2C654C9A9B6F")]
|
|
||||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
||||||
private interface IAudioSessionManager2
|
|
||||||
{
|
|
||||||
int NotImpl1();
|
|
||||||
int NotImpl2();
|
|
||||||
[PreserveSig]
|
|
||||||
int GetSessionEnumerator(out IAudioSessionEnumerator sessionEnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
[ComImport]
|
|
||||||
[Guid("E2F5BB11-0570-40CA-ACDD-3AA01277DEE8")]
|
|
||||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
||||||
private interface IAudioSessionEnumerator
|
|
||||||
{
|
|
||||||
[PreserveSig]
|
|
||||||
int GetCount(out int sessionCount);
|
|
||||||
[PreserveSig]
|
|
||||||
int GetSession(int sessionCount, out IAudioSessionControl session);
|
|
||||||
}
|
|
||||||
|
|
||||||
[ComImport]
|
|
||||||
[Guid("F4B1A599-7266-4319-A8CA-E70ACB11E8CD")]
|
|
||||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
||||||
private interface IAudioSessionControl
|
|
||||||
{
|
|
||||||
[PreserveSig]
|
|
||||||
int GetState(out AudioSessionState state);
|
|
||||||
int NotImpl1();
|
|
||||||
int NotImpl2();
|
|
||||||
int NotImpl3();
|
|
||||||
int NotImpl4();
|
|
||||||
int NotImpl5();
|
|
||||||
int NotImpl6();
|
|
||||||
int NotImpl7();
|
|
||||||
int NotImpl8();
|
|
||||||
}
|
|
||||||
|
|
||||||
[ComImport]
|
|
||||||
[Guid("C02216F6-8C67-4B5B-9D00-D008E73E0064")]
|
|
||||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
||||||
private interface IAudioMeterInformation
|
|
||||||
{
|
|
||||||
[PreserveSig]
|
|
||||||
int GetPeakValue(out float peak);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net9.0-windows10.0.19041.0</TargetFramework>
|
<TargetFramework>net9.0-windows</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
|||||||
Reference in New Issue
Block a user