现在有一个媒体捕捉输出工作组他们确实定义了一个扩展MediaDevices
界面添加了一个selectAudioOutput()处理内部权限请求的方法。
这个方法会返回一个设备信息您可以从中提取对象deviceId
你会传递给HTMLMediaElement.setSinkId()
.
const deviceInfo = await navigator.mediaDevices.selectAudioOuput();
audio_elem.setSinkId(deviceInfo.deviceId);
另请注意,关于重命名此内容的讨论非常活跃setSinkId
方法setAudioOutput
,所以当浏览器开始实现这一切时,它可能会再次改变。
Firefox 93开始公开此方法,在media.setsinkid.enabled
flag.
或者应该有一个Permissions.request()方法,它应该接受权限描述符本身应该支持的对象权限名称有价值的"speaker-selection"
.
这样我们就可以得到
await navigator.permissions.request( { name: "speaker-selection" } );
const all_devices = await navigator.mediaDevices.enumerateDevices();
const audio_outs = all_devices.filter( ({ kind }) => kind === "audiooutput" );
// ...
audioElem.setSinkId( audio_outs[ n ].deviceId );
但截至2021年8月的今天,似乎仍然没有浏览器支持这一点。
Chrome(目前唯一支持MediaElement.setSinkId()
)确实暴露了Permission.request()
下的方法chrome://flags/#enable-experimental-web-platform-features
,但他们仍然不支持权限名称 "speaker-selection"
yet.
所以我们仍然需要请求的不太理想的解决方法"microphone"
一个代替。
(async () => {
const query = await navigator.permissions.query( { name: "microphone" } );
switch( query.state ) {
case "denied": throw new Error('denied');
case "prompt":
await queryUserMedia();
await getListOfDevices();
break;
case "granted": await getListOfDevices();
}
function queryUserMedia() {
return navigator.mediaDevices.getUserMedia( { audio: true } );
}
async function getListOfDevices() {
const all_devs = await navigator.mediaDevices.enumerateDevices();
const audioouts = all_devs.filter( ({ kind }) => kind === "audiooutput" );
const options = audioouts.map( ( dev, index ) => {
const name = dev.label || ('audio out ' + index );
return new Option( name , dev.deviceId );
} );
sel.append.apply( sel, options );
sel.onchange = e => aud.setSinkId( sel.value );
}
})().catch( console.error );
作为小提琴,因为 Stack-Snippets iframe 不允许使用麦克风。
PS:请注意,如果/当浏览器支持规范定义的 API,那么它甚至会有可能 to 在非安全上下文中运行此代码.