到目前为止,只有 <video>
和 <audio>
才能使用 HTMLMediaElement.setSinkId()
设置目的地音频输出设备。在 Web Audio 中,AudioContext 使用默认设备,用户需要手动更改系统音频输出设备。
从 Chrome 110 开始,您可以使用 AudioContext.setSinkId()
以编程方式将 Web Audio 中的音频输出定向到任何允许的设备。
这在各种实时通信场景中特别有用。例如,Web 应用可以使用此接口以编程方式将输出定向到特定音频输出设备,例如蓝牙耳机或免提电话。
将音频输出路由到特定设备
首先,您需要获取要用作目标位置的音频输出设备的标识符。使用 navigator.mediaDevices.enumerateDevices()
获取可用媒体设备的列表,仅过滤音频输出设备,然后获取所选音频输出设备的 deviceId
属性。空字符串 ""
值也可以用作 deviceId
的默认设备。
获取音频输出设备的标识符后,创建 AudioContext
并调用 audioContext.setSinkId(deviceId)
。成功时,当音频路由到所选的已连接输出设备时,返回的 promise 会解析。如果 AudioContext 已关闭,则可能会失败。
以下示例展示了如何根据需要请求麦克风访问权限,以及如何将 Web Audio 中的音频输出定向到第一个可用的输出设备。
const permission = await navigator.permissions.query({ name: "microphone" });
if (permission.state == "prompt") {
// More audio outputs are available when user grants access to the mic.
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
stream.getTracks().forEach((track) => track.stop());
}
// Request a list of media devices and filter audio output devices.
const devices = await navigator.mediaDevices.enumerateDevices();
const audioOutputs = devices.filter(device => device.kind == "audiooutput");
const audioContext = new AudioContext();
// Pick the first available audio output.
const deviceId = audioOutputs[0].deviceId;
await audioContext.setSinkId(deviceId);
请注意,您还可以在创建 AudioContext
时将 deviceId
作为 sinkId
参数传递。
const audioContext = new AudioContext({ sinkId: deviceId });
使用静音的 AudioContext 渲染音频
您现在可以在 Web Audio 中指定“静音输出设备”,以最大限度地降低功耗。这次,请将 { type: "none" }
传递给 AudioContext.setSinkId()
,而不是字符串值。
请注意,通过 audioContext.currentTime
访问的音频时钟仍会继续推进以渲染音频图表。此静音 AudioContext 的主要目标是在不产生可听声音的情况下渲染音频图表。主要用例是分析麦克风输入,而不会发出声音。
// Silent Web Audio output.
await audioContext.setSinkId({ type: "none" });
功能检测
如需检查是否支持 AudioContext.setSinkId()
,请使用以下命令:
if ("setSinkId" in AudioContext.prototype) {
// AudioContext.setSinkId() is supported.
}
示例
您可以访问 https://sinkid.glitch.me/ 演示版,试用 AudioContext.setSinkId()
。
浏览器支持
AudioContext.setSinkId()
适用于 Chrome 110 或更高版本。
反馈
Chrome 团队和 Web 标准社区希望了解您使用 AudioContext.setSinkId()
的体验。如需提供反馈,请对现有问题发表评论或提交新的 GitHub 问题。
实用链接
致谢
感谢 Hongchan Choi 和 Michael Wilson 审核本文。
日历图片由 Unsplash 用户 Steve Harvey 拍摄。