继续播放麦克风音频

时间:2017-09-05 16:50:15

标签: javascript dom audio html5-audio audio-streaming

我看到很多关于如何录制音频然后停止录制,然后播放音频或将其保存到文件的问题,但这些都不是我想要的。

tl; dr这里是我的问题,简而言之:“如何立即播放用户麦克风录制的音频?”也就是说,我想要保存录音并在用户点击“播放”按钮时播放,我想要将录音保存到在用户计算机上的文件,我想要使用WebRTC在任何地方传输音频。我只想和我的麦克风说话,听到我的声音从扬声器中传出来。

我要做的就是制作一个非常简单的“回声”页面,它可以立即播放从麦克风录制的音频。我开始使用mediaRecorder对象,但这不起作用,而且我可以说它是用于录制完整音频文件的,所以我切换到基于AudioContext的方法。 一个非常简单的页面看起来像这样:

<!DOCTYPE html>
<head>
    <script type="text/javascript" src="mcve.js"></script>
</head>
<body>
    <audio id="speaker" volume="1.0"></audio>
</body>

,脚本如下所示:

if (navigator.mediaDevices) {
    var constrains = {audio: true};

    navigator.mediaDevices.getUserMedia(constrains).then(
        function (stream) {
            var context = new AudioContext();
            var source = context.createMediaStreamSource(stream);
            var proc = context.createScriptProcessor(2048, 2, 2);

            source.connect(proc);

            proc.onaudioprocess = function(e) {
                console.log("audio data collected");
                let audioData = new Blob(e.inputBuffer.getChannelData(0), {type: 'audio/ogg' } )
                    || new Blob(new Float32Array(2048), {type: 'audio/ogg'});

                var speaker = document.getElementById('speaker');

                let url = URL.createObjectURL(audioData);
                speaker.src = url;
                speaker.load();
                speaker.play().then(
                    () => { console.log("Playback success!"); }, 
                    (error) => { console.log("Playback failure... ", error); }
                );
            };
        }
    ).catch( (error) => {
        console.error("couldn't get user media.");
    });
}

它可以记录非平凡的音频数据(即并非每个集合都以Blob调用的new Float32Array(2048)结束,但它无法播放。它永远不会遇到“无法获得用户媒体”的捕获,但总是会遇到“回放失败......”。错误打印如下:

DOMException [NotSupportedError: "The media resource indicated by the src attribute or assigned media provider object was not suitable."
code: 9
nsresult: 0x806e0003]

此外,消息Media resource blob:null/<long uuid> could not be decoded.会重复打印到控制台。

这里有两件事情可以发生,我可以告诉他们(可能两者):

  1. 我没有对音频进行编码。我不确定这是否是一个问题,因为我认为从麦克风收集的数据自动带有'ogg'编码,我尝试将type的{​​{1}}属性留空无济于事。如果这是错的,我不知道如何编码Blob事件给我的一大块音频,这就是我需要知道的。
  2. audioprocess元素基本上无法播放音频片段,即使编码正确也是如此。也许没有完整的文件,有一些违反编码标准的缺失或无关的元数据,并阻止浏览器理解我。如果是这种情况,也许我需要一个不同的元素,甚至是一个完全脚本化的解决方案。或者我应该为每个音频数据块就地构建一个类似文件的对象?
  3. 我已经在MDN和SO答案的示例中构建了这个代码,我应该提到我已经在this example demo测试了我的麦克风,它看起来效果很好。

    此处的最终目标是通过websocket将此音频流式传输到服务器并将其转发给其他用户。如果可能的话,我不要想要使用WebRTC,因为我不想仅限于网络客户端 - 一旦它工作正常,我也会创建一个桌面客户端。 / p>

1 个答案:

答案 0 :(得分:0)

检查来自 https://jsfiddle.net/greggman/g88v7p8c/ 的示例 https://stackoverflow.com/a/38280110/351900

需要从 HTTPS 运行

navigator.getUserMedia = navigator.getUserMedia ||navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
    
var aCtx;
var analyser;
var microphone;
if (navigator.getUserMedia) {
  navigator.getUserMedia(
    {audio: true}, 
    function(stream) {
      aCtx = new AudioContext();
      microphone = aCtx.createMediaStreamSource(stream);
      var destination=aCtx.destination;
      microphone.connect(destination);
    },
    function(){ console.log("Error 003.")}
  );
}