【问题标题】:JavaScript get permission for Audio.setSinkIdJavaScript 获得 Audio.setSinkId 的权限
【发布时间】:2018-07-28 23:30:19
【问题描述】:

我正在尝试在 chrome 应用中的 Audio-Element 处更改 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 应用中获得这个连接?)

【问题讨论】:

标签: javascript google-chrome audio google-chrome-app


【解决方案1】:

现在有一个mediacapture-output WG,他们确实为MediaDevices 接口定义了一个扩展,该接口添加了一个处理内部权限请求的selectAudioOutput() 方法。
此方法将返回一个 deviceInfo 对象,您可以从中提取您将传递给 HTMLMediaElement.setSinkId()deviceId

const deviceInfo = await navigator.mediaDevices.selectAudioOuput();
audio_elem.setSinkId(deviceInfo.deviceId);

另请注意,关于将此 setSinkId 方法重命名为 setAudioOutput 的讨论非常活跃,因此当浏览器开始实现所有这些时,它可能会再次更改。

Firefox 93 开始在 media.setsinkid.enabled 标志下公开此方法。



或者应该有一个Permissions.request() 方法,它应该接受一个PermissionDescriptor 对象,该对象本身应该支持一个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 );


但截至 2021 年 8 月的今天,似乎仍然没有浏览器支持这一点。

Chrome(目前唯一支持MediaElement.setSinkId())确实在chrome://flags/#enable-experimental-web-platform-features 下公开了Permission.request() 方法,但它们仍然不支持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 possiblerun this code on non-secure contexts

【讨论】:

  • 无赖!我真的希望我只是读错了这个规范。无论如何,感谢您确认今天不支持它。我现在会坚持使用getUserMedia()
  • 您是否偶然有一个指向 Chromium 错误的链接,所以我们可以关注它?另外,我在这里对类似的问题提出了赏金:stackoverflow.com/q/59131286/362536
  • 已经看到其他问题了.. 不幸的是,我想不出比我在 cmets 中的糟糕建议更好的了... 对于 crbugs,here 是关于实现 request 和 @ 的问题987654351@ 但我认为"speaker" 还没有在任何地方被跟踪(唯一提到searching for it 是这个unrelated crbug
  • 规范现在将此权限称为speaker-selection 并开始实施(例如出现在 Firefox 92 中)
  • 啊现在我明白了,navigator.mediaDevices.selectAudioOutput 现在出现在 media.setsinkid.enabled 标志上。你知道我们是否可以关注@HamishWillee
猜你喜欢
  • 1970-01-01
  • 2017-08-04
  • 2012-05-27
  • 2019-09-19
  • 1970-01-01
  • 2012-05-30
  • 2021-01-22
  • 2015-11-12
  • 2021-02-14
相关资源
最近更新 更多