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

tl; dr这是我的问题,简而言之:"How can I immediately play audio recorded from the user's microphone?"也就是说,我不想保存录音并在用户点击"Play"按钮时播放它,我不想将录音保存到用户计算机上的文件中而且我不想使用WebRTC在任何地方传输音频 . 我只是想和我的麦克风说话,听到我的声音从扬声器中传出来 .

我所要做的就是制作一个非常简单的"echo"页面,它可以立即播放从麦克风录下的音频 . 我开始使用一个 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.");
    });
}

它可以记录非平凡的音频数据(即并非每个集合都会被 new Float32Array(2048) 调用 Blob ),但它无法播放 . 它永远不会击中"could not get user media"捕获,但它始终击中"Playback Failure..."捕获 . 错误打印如下:

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. 重复打印到控制台 .

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

  • 我'm not encoding the audio. I'我不确定这是否是一个问题,因为我认为从麦克风收集的数据自动带有'ogg'编码,并且我试图将我的 Blob 空白的 type 属性保留无效 . 如果这是's wrong, I don'知道如何编码 audioprocess 事件给我的一大块音频,那就是我需要知道的 .

  • <audio> 元素基本上无法播放音频片段,即使编码正确也是如此 . 也许没有一个完整的文件,'s some missing or extraneous metadata that violates encoding standards and is preventing the browser from understanding me. If this is the case, maybe I need a different element, or even an entirely scripted solution. Or perhaps I' m应该为每个音频数据块就地构建一个类似文件的对象?

我've built this code on examples from MDN and SO answers, and I should mention I'已经在this example demo测试了我的麦克风,它似乎完美无缺 .

这里的最终目标是通过websocket将此音频流式传输到服务器并将其转发给其他用户 . 如果可能的话,我不想使用WebRTC,因为我没有工作,我也会制作桌面客户端 .