张赐荣——一位视障程序员。
赐荣小站: www.prc.cx

張賜榮

张赐荣的技术博客

博客园 首页 新随笔 联系 订阅 管理

如何调用 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# 编写的示例代码,演示了如何调用这个函数。希望本文对你有所帮助。

参考资料

posted on 2023-05-01 16:05  张赐荣  阅读(54)  评论(0编辑  收藏  举报

感谢访问张赐荣的技术分享博客!
博客地址:https://cnblogs.com/netlog/
知乎主页:https://www.zhihu.com/people/tzujung-chang
个人网站:https://prc.cx/