如何调用 Windows 辅助功能 API "AccSetRunningUtilityState" 实现音频闪避功能
音频回避是指当自身应用程序,例如辅助功能程序,正在播放音频的时候,降低其他应用程序的音量。这样可以让用户更清楚地听到自身应用程序的音频,例如文字转语音或者导航提示。Windows API 提供了一个函数,AccSetRunningUtilityState,可以让辅助功能程序设置自己的音频回避选项。本文将介绍如何使用这个函数实现音频回避的功能。
AccSetRunningUtilityState 函数
AccSetRunningUtilityState 函数的原型如下:
HRESULT AccSetRunningUtilityState(
[in] HWND hwndApp,
[in] DWORD dwUtilityStateMask,
[in] DWORD dwUtilityState
);
这个函数接受三个参数:
- hwndApp:辅助功能程序的主窗口句柄。这个参数不能为 NULL。
- dwUtilityStateMask:一个掩码,表示要设置的系统值。它可以是下面的值的组合:
- ANRUS_ON_SCREEN_KEYBOARD_ACTIVE:辅助功能程序提供了一个屏幕键盘。
- ANRUS_TOUCH_MODIFICATION_ACTIVE:辅助功能程序正在消费重定向的触摸输入。
- ANRUS_PRIORITY_AUDIO_ACTIVE:辅助功能程序依赖音频(例如文字转语音)来传达重要信息给用户,并且应该在其他系统声音上保持可听性。
- ANRUS_PRIORITY_AUDIO_ACTIVE_NODUCK:辅助功能程序依赖音频(例如文字转语音)来传达重要信息给用户,但不应该相对于其他系统声音发生变化。
- dwUtilityState:dwUtilityStateMask 所指示的系统值的新设置。这个参数可以是零来重置系统值,或者是上面的值的组合。
如果成功,这个函数返回 S_OK,否则返回一个标准的 COM 错误码。
这个函数需要调用进程拥有 UIAccess 或更高的权限。如果调用者没有必要的权限,调用 AccSetRunningUtilityState 会失败,并返回 E_ACCESSDENIED。
在退出之前,辅助功能程序应该重置之前设置的任何系统值。
音频回避选项
为了实现音频回避的功能,我们需要使用 ANRUS_PRIORITY_AUDIO_ACTIVE 和 ANRUS_PRIORITY_AUDIO_ACTIVE_NODUCK 这两个值。它们分别表示:
- ANRUS_PRIORITY_AUDIO_ACTIVE:辅助功能程序正在播放重要的音频,并且希望系统降低其他应用程序的音量。
- ANRUS_PRIORITY_AUDIO_ACTIVE_NODUCK:辅助功能程序正在播放重要的音频,但不希望系统降低其他应用程序的音量。
我们可以根据自己的需求,选择其中一个或者两个都使用。如果我们想要让自己的音频始终保持高于其他应用程序的音量,我们可以同时使用这两个值。如果我们想要让自己的音频在开始播放时降低其他应用程序的音量,然后在停止播放时恢复其他应用程序的音量,我们可以在开始播放时使用 ANRUS_PRIORITY_AUDIO_ACTIVE,然后在停止播放时使用 ANRUS_PRIORITY_AUDIO_ACTIVE_NODUCK。
示例代码
下面是一个使用 C# 编写的示例代码,演示了如何调用 AccSetRunningUtilityState 函数实现音频回避的功能。这个代码定义了一个静态类 AudioDucking,提供了两个静态方法:
- SetAudioDucking:设置音频回避选项为 ANRUS_PRIORITY_AUDIO_ACTIVE,表示辅助功能程序处于活动状态,正在播放重要的音频,并且希望系统降低其他应用程序的音量。
- ResetAudioDucking:设置音频回避选项为 ANRUS_PRIORITY_AUDIO_ACTIVE_NODUCK,表示辅助功能程序已经停止播放重要的音频,或者不希望系统降低其他应用程序的音量。
这两个方法都接受一个参数,即辅助功能程序的主窗口句柄。它们都调用了 AccSetRunningUtilityState 函数,并返回一个布尔值,表示是否成功。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace WinForms
{
public static class AudioDucking
{
private const uint ANRUS_PRIORITY_AUDIO_ACTIVE = 0x0000004;
private const uint ANRUS_PRIORITY_AUDIO_ACTIVE_NODUCK = 0x0000008;
[DllImport("oleacc.dll", SetLastError = true)]
private static extern int AccSetRunningUtilityState(IntPtr hwndApp, uint dwUtilityStateMask, uint dwUtilityState);
public static bool SetAudioDucking(IntPtr hwnd)
{
int result = AccSetRunningUtilityState(hwnd, ANRUS_PRIORITY_AUDIO_ACTIVE | ANRUS_PRIORITY_AUDIO_ACTIVE_NODUCK, ANRUS_PRIORITY_AUDIO_ACTIVE | ANRUS_PRIORITY_AUDIO_ACTIVE_NODUCK);
return result == 0;
}
public static bool ResetAudioDucking(IntPtr hwnd)
{
int result = AccSetRunningUtilityState(hwnd, ANRUS_PRIORITY_AUDIO_ACTIVE | ANRUS_PRIORITY_AUDIO_ACTIVE_NODUCK, ANRUS_PRIORITY_AUDIO_ACTIVE_NODUCK);
return result == 0;
}
}
}
使用方法
为了使用这个示例代码,我们需要在程序中引用 AudioDucking 类,并在合适的时机调用它的方法。例如,如果我们的辅助功能程序是一个文字转语音的应用程序,我们可以在开始播放语音时调用 SetAudioDucking 方法,然后在停止播放语音时调用 ResetAudioDucking 方法。这样就可以实现音频回避的功能,让用户更清楚地听到我们的语音输出。
总结
本文介绍了如何使用 Windows API 中的 AccSetRunningUtilityState 函数实现音频回避的功能。这个函数可以让辅助功能程序设置自己的音频回避选项,从而影响系统对其他应用程序的音量控制。我们还给出了一个使用 C# 编写的示例代码,演示了如何调用这个函数。希望本文对你有所帮助。
参考资料
-
- NVDA Audio Ducking Mode: https://github.com/nvaccess/nvda/blob/master/source/audioDucking.py
- 2.AccSetRunningUtilityState function (oleacc.h): https://learn.microsoft.com/en-us/windows/win32/api/oleacc/nf-oleacc-accsetrunningutilitystate#anrus_priority_audio_active_noduck
知乎: @张赐荣
赐荣博客: www.prc.cx
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2022-05-01 C# 用 lock 线程锁实现对资源的同步访问