简体   繁体   English

Web浏览器中的高质量音频录制

[英]High Quality Audio Recording in Web Browser

One line version: 一行版本:

What open source software (WAMI-Recorder)/web browser (via getUserMedia) will give me the best quality audio recordings? 什么开源软件(WAMI-Recorder)/网络浏览器(通过getUserMedia)会给我最优质的录音?

High quality would be defined as (44.1 or 48 sample rate) and 16 bit sample size. 高质量定义为(44.1或48个采样率)和16位样本大小。

More Information: 更多信息:

So currently my solution is WAMI-Recorder, but I am wondering if the HTML5 specification has matured to a point in browser such that I can record without Flash and get equal or higher quality audio recordings. 所以目前我的解决方案是WAMI-Recorder,但我想知道HTML5规范是否已经成熟到浏览器中的某个点,这样我就可以在没有Flash的情况下进行录制并获得相同或更高质量的录音。 Currently it looks like WAMI maxes out at 22050. 目前,看起来WAMI最高可达22050。

I do not need cross browser support as this is for internal business use. 我不需要跨浏览器支持,因为这是供内部业务使用。

A non-Flash solution would also be preferred. 非Flash解决方案也是首选。

I found something here . 我发现了一些在这里 hope it will help you to record audio 希望它能帮助你录制音频

<html>
  <body>
    <audio controls autoplay></audio>
    <script type="text/javascript" src="recorder.js"> </script>

    <input onclick="startRecording()" type="button" value="start recording" />
    <input onclick="stopRecording()" type="button" value="stop recording and play" />

    <script>
      var onFail = function(e) {
        console.log('Rejected!', e);
      };

      var onSuccess = function(s) {
        var context = new webkitAudioContext();
        var mediaStreamSource = context.createMediaStreamSource(s);
        recorder = new Recorder(mediaStreamSource);
        recorder.record();

        // audio loopback
        // mediaStreamSource.connect(context.destination);
      }

      window.URL = window.URL || window.webkitURL;
      navigator.getUserMedia  = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;

      var recorder;
      var audio = document.querySelector('audio');

      function startRecording() {
        if (navigator.getUserMedia) {
          navigator.getUserMedia({audio: true}, onSuccess, onFail);
        } else {
          console.log('navigator.getUserMedia not present');
        }
      }

      function stopRecording() {
        recorder.stop();
        recorder.exportWAV(function(s) {
          audio.src = window.URL.createObjectURL(s);
        });
      }
    </script>
  </body>
</html>

download the sample https://github.com/rokgregoric/html5record/archive/master.zip 下载示例https://github.com/rokgregoric/html5record/archive/master.zip

Save this files and use 保存这些文件并使用

//HTML FILE // HTML文件

    <html>
        <body>
            <audio controls autoplay></audio>
            <script type="text/javascript" src="recorder.js"> </script>
                    <fieldset><legend>RECORD AUDIO</legend>
            <input onclick="startRecording()" type="button" value="start recording" />
            <input onclick="stopRecording()" type="button" value="stop recording and play" />
                    </fieldset>
            <script>
                var onFail = function(e) {
                    console.log('Rejected!', e);
                };

                var onSuccess = function(s) {
                    var context = new webkitAudioContext();
                    var mediaStreamSource = context.createMediaStreamSource(s);
                    recorder = new Recorder(mediaStreamSource);
                    recorder.record();

                    // audio loopback
                    // mediaStreamSource.connect(context.destination);
                }

                window.URL = window.URL || window.webkitURL;
                navigator.getUserMedia  = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;

                var recorder;
                var audio = document.querySelector('audio');

                function startRecording() {
                    if (navigator.getUserMedia) {
                        navigator.getUserMedia({audio: true}, onSuccess, onFail);
                    } else {
                        console.log('navigator.getUserMedia not present');
                    }
                }

                function stopRecording() {
                    recorder.stop();
                    recorder.exportWAV(function(s) {

                                    audio.src = window.URL.createObjectURL(s);
                    });
                }
            </script>
        </body>
    </html>

//JS FILES RECORDER.JS
(function(window){

  var WORKER_PATH = 'recorderWorker.js';
  var Recorder = function(source, cfg){
    var config = cfg || {};
    var bufferLen = config.bufferLen || 4096;
    this.context = source.context;
    this.node = this.context.createJavaScriptNode(bufferLen, 2, 2);
    var worker = new Worker(config.workerPath || WORKER_PATH);
    worker.postMessage({
      command: 'init',
      config: {
        sampleRate: this.context.sampleRate
      }
    });
    var recording = false,
      currCallback;

    this.node.onaudioprocess = function(e){
      if (!recording) return;
      worker.postMessage({
        command: 'record',
        buffer: [
          e.inputBuffer.getChannelData(0),
          e.inputBuffer.getChannelData(1)
        ]
      });
    }

    this.configure = function(cfg){
      for (var prop in cfg){
        if (cfg.hasOwnProperty(prop)){
          config[prop] = cfg[prop];
        }
      }
    }

    this.record = function(){

      recording = true;
    }

    this.stop = function(){

      recording = false;
    }

    this.clear = function(){
      worker.postMessage({ command: 'clear' });
    }

    this.getBuffer = function(cb) {
      currCallback = cb || config.callback;
      worker.postMessage({ command: 'getBuffer' })
    }

    this.exportWAV = function(cb, type){
      currCallback = cb || config.callback;
      type = type || config.type || 'audio/wav';
      if (!currCallback) throw new Error('Callback not set');
      worker.postMessage({
        command: 'exportWAV',
        type: type
      });
    }

    worker.onmessage = function(e){
      var blob = e.data;
      currCallback(blob);
    }

    source.connect(this.node);
    this.node.connect(this.context.destination);    //this should not be necessary
  };

  Recorder.forceDownload = function(blob, filename){
    var url = (window.URL || window.webkitURL).createObjectURL(blob);
    var link = window.document.createElement('a');
    link.href = url;
    link.download = filename || 'output.wav';
    var click = document.createEvent("Event");
    click.initEvent("click", true, true);
    link.dispatchEvent(click);
  }

  window.Recorder = Recorder;

})(window);

//ADDITIONAL JS recorderWorker.js
var recLength = 0,
  recBuffersL = [],
  recBuffersR = [],
  sampleRate;
this.onmessage = function(e){
  switch(e.data.command){
    case 'init':
      init(e.data.config);
      break;
    case 'record':
      record(e.data.buffer);
      break;
    case 'exportWAV':
      exportWAV(e.data.type);
      break;
    case 'getBuffer':
      getBuffer();
      break;
    case 'clear':
      clear();
      break;
  }
};

function init(config){
  sampleRate = config.sampleRate;
}

function record(inputBuffer){

  recBuffersL.push(inputBuffer[0]);
  recBuffersR.push(inputBuffer[1]);
  recLength += inputBuffer[0].length;
}

function exportWAV(type){
  var bufferL = mergeBuffers(recBuffersL, recLength);
  var bufferR = mergeBuffers(recBuffersR, recLength);
  var interleaved = interleave(bufferL, bufferR);
  var dataview = encodeWAV(interleaved);
  var audioBlob = new Blob([dataview], { type: type });

  this.postMessage(audioBlob);
}

function getBuffer() {
  var buffers = [];
  buffers.push( mergeBuffers(recBuffersL, recLength) );
  buffers.push( mergeBuffers(recBuffersR, recLength) );
  this.postMessage(buffers);
}

function clear(){
  recLength = 0;
  recBuffersL = [];
  recBuffersR = [];
}

function mergeBuffers(recBuffers, recLength){
  var result = new Float32Array(recLength);
  var offset = 0;
  for (var i = 0; i < recBuffers.length; i++){
    result.set(recBuffers[i], offset);
    offset += recBuffers[i].length;
  }
  return result;
}

function interleave(inputL, inputR){
  var length = inputL.length + inputR.length;
  var result = new Float32Array(length);

  var index = 0,
    inputIndex = 0;

  while (index < length){
    result[index++] = inputL[inputIndex];
    result[index++] = inputR[inputIndex];
    inputIndex++;
  }
  return result;
}

function floatTo16BitPCM(output, offset, input){
  for (var i = 0; i < input.length; i++, offset+=2){
    var s = Math.max(-1, Math.min(1, input[i]));
    output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
  }
}

function writeString(view, offset, string){
  for (var i = 0; i < string.length; i++){
    view.setUint8(offset + i, string.charCodeAt(i));
  }
}

function encodeWAV(samples){
  var buffer = new ArrayBuffer(44 + samples.length * 2);
  var view = new DataView(buffer);

  /* RIFF identifier */
  writeString(view, 0, 'RIFF');
  /* file length */
  view.setUint32(4, 32 + samples.length * 2, true);
  /* RIFF type */
  writeString(view, 8, 'WAVE');
  /* format chunk identifier */
  writeString(view, 12, 'fmt ');
  /* format chunk length */
  view.setUint32(16, 16, true);
  /* sample format (raw) */
  view.setUint16(20, 1, true);
  /* channel count */
  view.setUint16(22, 2, true);
  /* sample rate */
  view.setUint32(24, sampleRate, true);
  /* byte rate (sample rate * block align) */
  view.setUint32(28, sampleRate * 4, true);
  /* block align (channel count * bytes per sample) */
  view.setUint16(32, 4, true);
  /* bits per sample */
  view.setUint16(34, 16, true);
  /* data chunk identifier */
  writeString(view, 36, 'data');
  /* data chunk length */
  view.setUint32(40, samples.length * 2, true);

  floatTo16BitPCM(view, 44, samples);

  return view;
}

The WebRTC project is the only available solution for high quality audio that I know of. WebRTC项目是我所知道的唯一可用于高质量音频的解决方案。 There is currently a stable version for chrome. 目前有一个稳定的chrome版本。 I believe firefox is still in the beta stage. 我相信firefox仍处于测试阶段。 As WebRTC matures I am sure all browsers will provide support for this. 随着WebRTC的成熟,我相信所有浏览器都会为此提供支持。

http://www.webrtc.org/ http://www.webrtc.org/

Check this tutorial on how to capture audio and video using HTML5. 查看本教程,了解如何使用HTML5捕获音频和视频。

http://www.html5rocks.com/en/tutorials/getusermedia/intro/ http://www.html5rocks.com/en/tutorials/getusermedia/intro/

I don't see any reference about the sample rate or the sample size in the API's, but I would assume that will be possible. 我没有看到关于API中的采样率或样本大小的任何参考,但我认为这是可能的。

Your major problem could be the implementation status by different browser vendors. 您的主要问题可能是不同浏览器供应商的实施状态。

If you use Chrome Web Browser, and as you ask for High Quality Audio Recording, you probably be better to build a native client module, you may take a look here (chrome developper native client dev guide): 如果您使用Chrome Web浏览器,并且当您要求高质量音频录制时,您可能最好构建本机客户端模块,您可以在这里查看 (chrome developper native client dev guide):

Selecting a sample frame count for an audio stream involves a tradeoff between latency and CPU usage. 选择音频流的样本帧计数涉及延迟和CPU使用之间的权衡。 If you want your module to have short audio latency so that it can rapidly change what's playing in the audio stream, you should request a small sample frame count. 如果您希望模块具有较短的音频延迟,以便能够快速更改音频流中播放的内容,则应该请求少量样本帧计数。

[...] [...]

After the module obtains a sample frame count, it can create an audio configuration resource. 模块获得样本帧计数后,可以创建音频配置资源。 Currently the Pepper audio API supports audio streams with the configuration settings shown above 目前,Pepper音频API支持使用上面显示的配置设置的音频流

And here you will find audio configuration which fit your requirements 在这里,您将找到符合您要求的音频配置

The Pepper audio API currently lets Native Client modules play audio streams with the following configurations: Pepper音频API目前允许Native Client模块使用以下配置播放音频流:

sample rate: 44,100 Hz or 48,000 Hz 采样率:44,100 Hz或48,000 Hz

bit depth: 16 位深度:16

channels: 2 (stereo) 频道:2(立体声)

This official link could be also helpful. 这个官方链接也可能有所帮助。

Regards 问候

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM