Hus*_*012 5 javascript audio google-chrome google-chrome-app
我正在尝试更改sinkIdchrome 应用程序中的音频元素。
代码:
var audio = new Audio();
audio.setSinkId("communications");
Run Code Online (Sandbox Code Playgroud)
我会收到这个错误:
DOMException: No permission to use requested device
因此,为了获得许可,我尝试这样做:
navigator.webkitGetUserMedia({
audio: true
}, (stream) => {
console.log("stream: ", stream);
}, (error) => {
console.log("error: ", error);
});
Run Code Online (Sandbox Code Playgroud)
但现在我明白了:
error:
NavigatorUserMediaError {name: "InvalidStateError", message: "", constraintName: ""}
Run Code Online (Sandbox Code Playgroud)
不知道有没有
现在有一个mediacapture-output WG,他们确实为MediaDevices接口定义了一个扩展,它添加了一个selectAudioOutput()处理内部权限请求的方法。
此方法将返回一个deviceInfo对象,您可以从中提取deviceId要传递给HTMLMediaElement.setSinkId().
const deviceInfo = await navigator.mediaDevices.selectAudioOuput();
audio_elem.setSinkId(deviceInfo.deviceId);
Run Code Online (Sandbox Code Playgroud)
另请注意,有关将此setSinkId方法重命名为 的积极讨论setAudioOutput,因此当浏览器开始实施所有这些时,它可能会再次更改。
Firefox 93 开始在media.setsinkid.enabled标志下公开此方法。
或者应该有一个Permissions.request()方法,它应该接受一个PermissionDescriptor对象,该对象本身应该支持value的PermissionName"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 );
Run Code Online (Sandbox Code Playgroud)
但截至今天 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 );
Run Code Online (Sandbox Code Playgroud)
作为一个小提琴,因为 Stack-Snippets iframes 不允许使用麦克风。
PS:请注意,如果/当浏览器中支持定义的API规格,那就甚至有可能到运行在非安全环境这段代码。