【问题标题】:MediaDevices.getUserMedia() How can I set audio constraints (sampling rate/bit depth)?MediaDevices.getUserMedia() 如何设置音频约束(采样率/位深度)?
【发布时间】:2020-10-05 02:36:43
【问题描述】:

使用浏览器Web API,我想设置MediaDevices.getUserMedia constraints 属性,适合录制音频语音(语音消息),例如设置这些参数:

  • 单声道
  • 16 位
  • 16KHz

这是我的代码:

   const mediaStreamConstraints = {
       audio: {
         channelCount: 1,
         sampleRate: 16000,
         sampleSize: 16,
         volume: 1
       },

       video: false
   }

   navigator.mediaDevices.getUserMedia(mediaStreamConstraints)
     .catch( err => serverlog(`ERROR mediaDevices.getUserMedia: ${err}`) )
     .then( stream => {

        // audio recorded as Blob 
        // and the binary data are sent via socketio to a nodejs server
        // that store blob as a file (e.g. audio/inp/audiofile.webm)

      } )

抓取并存储录制的剪辑(使用MediaRecorder API),最终发送到nodejs服务器,将blob保存为文件并进行处理(应用程序是语音机器人)。

出了点问题,WebM 保存的文件没有所需的参数:

$ mediainfo audio/inp/audiofile.webm
General
Complete name                            : audio/inp/audiofile.webm
Format                                   : WebM
Format version                           : Version 4 / Version 2
File size                                : 2.04 KiB
Writing application                      : Chrome
Writing library                          : Chrome
IsTruncated                              : Yes

Audio
ID                                       : 1
Format                                   : Opus
Codec ID                                 : A_OPUS
Channel(s)                               : 1 channel
Channel positions                        : Front: C
Sampling rate                            : 48.0 kHz
Bit depth                                : 32 bits
Compression mode                         : Lossy
Language                                 : English
Default                                  : Yes
Forced                                   : No

例如

Sampling rate                            : 48.0 kHz
Bit depth                                : 32 bits

但约束意味着不同的值:

Sampling rate                            : 16 kHz
Bit depth                                : 16 bits

还有 blob,用新的 Audio(audioUrl(blob)).play() 播放,不播放。诡异的。但是,如果约束只是:

const mediaStreamConstraints = { audio: true }

我检查了浏览器控制台,没有看到navigator.mediaDevices.getUserMedia(mediaStreamConstraints) API 调用的任何错误。

顺便说一句,我在这里遵循了指南:

请注意,我的用户代理是:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36(我使用的是最新的 Brave 浏览器版本)。


在我看来,浏览器不允许任何音频约束设置:

  • 破坏了音频块,
  • 没有引发错误异常(我同时捕获了navigator.mediaDevices.getUserMedia()new MediaRecorder(...)。这不是最后一个错误吗?

我的问题是:

有什么方法可以根据要求获得采样率/位深度?

或者音频格式是“硬编码”/由浏览器实现决定的?


顺便说一句,音频参数格式的原因是因为我想最小化音频 blob 大小以最小化浏览器客户端和服务器之间的 websocket 通信中的带宽,优化语音(语音消息)的音频 blob 交换

【问题讨论】:

    标签: audio browser audio-recording getusermedia mediadevices


    【解决方案1】:

    首先检查浏览器的功能:

    let stream = await navigator.mediaDevices.getUserMedia({audio: true});
    let track = stream.getAudioTracks()[0];
    console.log(track.getCapabilities());
    

    演示输出:

    autoGainControl: (2) [true, false]
    channelCount: {max: 2, min: 1}
    deviceId: "default"
    echoCancellation: (2) [true, false]
    groupId: "1e76386ad54f9ad3548f6f6c14c08e7eff6753f9362d93d8620cc48f546604f5"
    latency: {max: 0.01, min: 0.01}
    noiseSuppression: (2) [true, false]
    sampleRate: {max: 48000, min: 48000}
    sampleSize: {max: 16, min: 16}
    

    【讨论】:

      【解决方案2】:

      在实例化 MediaRecorder 之前,尝试在流中的音频媒体轨道上设置音频约束。

      类似这样的东西,没有调试:

      const constraints = {
         audio: {
           channelCount: 1,
           sampleRate: 16000,
           sampleSize: 16,
           volume: 1
         },
      
      navigator.mediaDevices.getUserMedia({audio:true})
       .catch( err => serverlog(`ERROR mediaDevices.getUserMedia: ${err}`) )
       .then( stream => {
      
          const audioTracks = stream.getAudioTracks()
          if (audioTracks.length !== 1) throw new Error ('too many tracks???')
          const audioTrack = audioTracks[0]       
          audioTrack.applyConstraints (constraints)
          .then (()=> {
      
               const mediaRecorder = new MediaRecorder(stream)
               /* etc etc etc */
            } )
          .catch(console.error) /* you might get constraint failure here. */
        } )
      

      话虽如此,Opus 音频编解码器在将语音压缩到合理大小方面做得很好。仅仅因为它 sez 48kHz x 32bits 并不意味着它使用那么多带宽;音频信号被压缩。

      并且,在最新版本的 Google Chrome 和/或 Firefox 上试用。这种媒体内容正在积极开发中。

      【讨论】:

      • 感谢您的帮助!因此,您的建议是在 getUserMedia 流上的 audioTrack 级别设置约束。好的,我会尽快尝试,我会反馈。但是为什么你认为这会解决?你就这样成功了吗?顺便说一句,您不同意我所展示的约束设置失败是 WebAPI 错误吗?
      • @GiorgioRobino - 关于没有抛出异常 - 我认为他们对“约束”一词的使用有点误导。我的理解是,这些更像是“请求”。系统将尝试满足他们,但它可能无法满足。但是,如果您使用“精确”指定“约束”,例如sampleRate: {exact: 16000},那么如果无法将采样率设置为 16000,则会产生错误。
      【解决方案3】:

      O.Jones 的答案在正确的轨道上,但可以通过在抓取 userMedia 对象时直接设置约束来更简洁。

      const constraints = {
          audio: {
              channelCount: 1,
              sampleRate: 16000,
              sampleSize: 16,
              volume: 1
          }
      }
      
      navigator.mediaDevices.getUserMedia({audio: constraints}) 
          .then( stream => {
              // Do something with the stream...
          })
          .catch( err => serverlog(`ERROR mediaDevices.getUserMedia: ${err}`) )
      

      【讨论】:

        猜你喜欢
        • 2011-05-08
        • 1970-01-01
        • 2012-07-22
        • 1970-01-01
        • 1970-01-01
        • 2014-01-02
        • 2017-03-04
        • 2011-10-08
        • 2011-01-06
        相关资源
        最近更新 更多