我正在尝试更改 sinkId
在 chrome 应用程序中的音频元素处。
代码:
var audio = new Audio();
audio.setSinkId("communications");
我会收到这个错误:
DOMException: No permission to use requested device
因此,为了获得许可,我尝试这样做:
navigator.webkitGetUserMedia({
audio: true
}, (stream) => {
console.log("stream: ", stream);
}, (error) => {
console.log("error: ", error);
});
但现在我明白了:
error:
NavigatorUserMediaError {name: "InvalidStateError", message: "", constraintName: ""}
不知道是不是
最佳答案
现在有一个mediacapture-output WG他们确实定义了 MediaDevices
的扩展。添加 selectAudioOutput()
的接口(interface)处理内部权限请求的方法。
此方法将返回一个 deviceInfo 对象,您可以从中提取 deviceId
你会传递给 HTMLMediaElement.setSinkId()
.
const deviceInfo = await navigator.mediaDevices.selectAudioOuput();
audio_elem.setSinkId(deviceInfo.deviceId);
另请注意,关于重命名此 setSinkId
的讨论非常活跃。方法 setAudioOutput
,所以当浏览器开始实现这一切时,它可能会再次改变。Firefox 93 开始公开此方法,位于
media.setsinkid.enabled
下。旗帜。或者应该有一个
Permissions.request()
方法,它应该接受一个 PermissionDescriptor 对象,该对象本身应该支持 PermissionName值(value) "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
下的方法,但他们仍然不支持 PermissionName "speaker-selection"
然而。所以我们仍然需要请求
"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 );
As a fiddle since Stack-Snippets iframes won't allow for the use of the microphone.Ps:请注意,如果/当浏览器支持规范定义的 API 时,它甚至会 be possible至run this code on non-secure contexts .
关于JavaScript 获得 Audio.setSinkId 的权限,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48854159/