本文介绍了JavaScript获得Audio.setSinkId的权限的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在chrome应用程序的音频元素中更改sinkId.

代码:

 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: ""}
 

我不知道

  • 音频"不可用(但实际上应该可用)
  • 我需要安全的连接(但是如何在chrome应用程序中获取此连接?)

解决方案

根据规范,应该有一个 Permissions.request() 方法,该方法应接受 PermissionDescriptor 对象,该对象本身应支持 权限名称 ,其值为 "speaker" .

因此,按照规格,这将为我们提供

 await navigator.permissions.request( { name: "speaker" } );
 const all_devices = await navigator.mediaDevices.enumerateDevices();
 const audio_outs = all_devices.filter( ({ kind }) => kind === "audiooutput" );
 // ...
 audioElem.setSinkId( audio_outs[ n ].deviceId );



但是截至2019年12月的今天,没有浏览器支持任何一种...

Chrome(这是目前唯一支持MediaElement.setSinkId()的Chrome)确实公开了chrome://flags/#enable-experimental-web-platform-features下的Permission.request()方法,但它们仍不支持 PermissionName "speaker"./p>

因此,我们仍然需要请求"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时,它甚至会有可能在非-安全上下文.

I'm trying to change the sinkId at an Audio-Element in a chrome app.

Code:

var audio = new Audio();
audio.setSinkId("communications");

I'll get this error:

DOMException: No permission to use requested device

So to get the permission I tried to do that:

navigator.webkitGetUserMedia({
    audio: true
}, (stream) => {
    console.log("stream: ", stream);
}, (error) => {
    console.log("error: ", error);
});

But now I get this:

error:
NavigatorUserMediaError {name: "InvalidStateError", message: "", constraintName: ""}

I don't know, whether

  • 'audio' is not available (but actually it should)
  • I need a secure connection (but how do I get this at a chrome app?)

解决方案

Per specs, there should be a Permissions.request() method, which should accept a PermissionDescriptor object which itself should support a PermissionName of value "speaker".

So per specs, that would give us

 await navigator.permissions.request( { name: "speaker" } );
 const all_devices = await navigator.mediaDevices.enumerateDevices();
 const audio_outs = all_devices.filter( ({ kind }) => kind === "audiooutput" );
 // ...
 audioElem.setSinkId( audio_outs[ n ].deviceId );



But as of today december of 2019, no browser supports any of this...

Chrome (which is the only one currently supporting MediaElement.setSinkId()) does expose the Permission.request() method under chrome://flags/#enable-experimental-web-platform-features, but they still don't support the PermissionName "speaker" yet.

So we still need the less than optimal workaround of requesting for the "microphone" one instead.

(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: Note that if/when browsers were supporting the specs defined API, then it would even be possible to run this code on non-secure contexts.

这篇关于JavaScript获得Audio.setSinkId的权限的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-06 02:13