最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

【未解决】MediaStreamRecorder中stop后还会执行ondataavailable

JS crifan 2076浏览 0评论

折腾:

【未解决】换用MediaStreamRecorder实现麦克风录音且支持多个浏览器和wav格式

期间,遇到一个奇怪的现象:

代码:

<code>
    function testMediaStreamRecorder(mediaStream){
        console.log("testMediaStreamRecorder: mediaStream=%o", mediaStream);

        var mediaStreamRecorder = new MediaStreamRecorder(mediaStream);
        console.log("mediaStreamRecorder=%o", mediaStreamRecorder);

        const AUDIO_TYPE = {
            webm: {
                mimeType: 'audio/webm',
                suffix: ".webm"
            },
            wav: {
                mimeType: 'audio/wav',
                suffix: ".wav"
            },
            pcm: {
                mimeType: 'audio/pcm',
                suffix: ".pcm"
            },
            ogg: {
                mimeType: 'audio/ogg',
                suffix: ".ogg"
            }
        }

        // var curAudioType = AUDIO_TYPE.webm;
        var curAudioType = AUDIO_TYPE.wav;
        // var curAudioType = AUDIO_TYPE.pcm;
        // var curAudioType = AUDIO_TYPE.ogg;
        console.log("curAudioType=%o", curAudioType);

        mediaStreamRecorder.mimeType = curAudioType.mimeType;

        mediaStreamRecorder.ondataavailable = function (recordedBlob) {
            console.log("mediaStreamRecorder.ondataavailable: recordedBlob=%o", recordedBlob);

            const blobUrl = URL.createObjectURL(recordedBlob);
            console.log("blobUrl=%o", blobUrl);

            playRecordedAudio(blobUrl);

            downloadRecordedAudio(blobUrl, curAudioType.suffix);
        };

        $( "#stopSpeak" ).on( "click", function() {
            console.log("#stopSpeak clicked");

            mediaStreamRecorder.stop();
        });

        if ((curAudioType == AUDIO_TYPE.wav) || (curAudioType == AUDIO_TYPE.pcm)) {
            // mediaStreamRecorder.recorderType = StereoAudioRecorder;
            // console.log("set recorderType to StereoAudioRecorder when wav");

            console.log("seems wav type need trigger then can start record");

            $( "#startSpeak" ).on( "click", function() {
                console.log("#startSpeak clicked");
    
                mediaStreamRecorder.start();
            });
        } else {
            console.log("directly start by code");
            mediaStreamRecorder.start();
        }

        console.log("mediaStreamRecorder started");
    }
</code>

是通过点击按钮去触发录音了,但是ondataavailable会被执行多次:

所以,看起来和之前的AudioContext:

<code>    function testAudioContext(mediaStream){
        console.log("testAudioContext: mediaStream=%o", mediaStream);

        var audioContext = new AudioContext();
        console.log("audioContext=%o", audioContext);
        var mediaInputSrc = audioContext.createMediaStreamSource(mediaStream)
        console.log("mediaInputSrc=%o", mediaInputSrc);
        var processor = audioContext.createScriptProcessor(1024,1,1);
        console.log("processor=%o", processor);
    
        mediaInputSrc.connect(processor);
        processor.connect(audioContext.destination);
        console.log("audioContext.destination=%o", audioContext.destination);

        $( "#startSpeak" ).on( "click", function() {
            console.log("#startSpeak clicked");

            audioContext.resume().then(() =&gt; {
                console.log('Playback resumed successfully');
            });
        });

        processor.onaudioprocess = function(e) {
            console.log("Audio processor onaudioprocess");
            // Do something with the data, i.e Convert this to WAV
            console.log(e.inputBuffer);
        };
    }
</code>

很像啊。

然后看到其demo:

MediaStreamRecorder/audio-recorder.html at master · streamproc/MediaStreamRecorder

<code>            &lt;select id="audio-recorderType" style="font-size:22px;vertical-align: middle;margin-right: 5px;"&gt;

                &lt;option&gt;[Best Available Recorder]&lt;/option&gt;
                &lt;option&gt;MediaRecorder API&lt;/option&gt;
                &lt;option&gt;WebAudio API (WAV)&lt;/option&gt;
                &lt;option&gt;WebAudio API (PCM)&lt;/option&gt;
            &lt;/select&gt;
</code>

想起来了:

如果此处用的audio/wav,则内部是用WebAudio API (WAV)的接口

-》该接口就是这么使用的。

-〉好像就会多次调用这个ondataavailable?

去搜搜:

WebAudio API ondataavailable

Stream capturing with MediaRecorder · TryCatch

还是应该改为:

ondataavailable:只是保存数据

stop:才去处理数据

结果用了代码:

<code>
    function testMediaStreamRecorder(mediaStream){
        console.log("testMediaStreamRecorder: mediaStream=%o", mediaStream);

        var mediaStreamRecorder = new MediaStreamRecorder(mediaStream);
        console.log("mediaStreamRecorder=%o", mediaStreamRecorder);

        const AUDIO_TYPE = {
            webm: {
                mimeType: 'audio/webm',
                suffix: ".webm"
            },
            wav: {
                mimeType: 'audio/wav',
                suffix: ".wav"
            },
            pcm: {
                mimeType: 'audio/pcm',
                suffix: ".pcm"
            },
            ogg: {
                mimeType: 'audio/ogg',
                suffix: ".ogg"
            }
        }

        // var curAudioType = AUDIO_TYPE.webm;
        var curAudioType = AUDIO_TYPE.wav;
        // var curAudioType = AUDIO_TYPE.pcm;
        // var curAudioType = AUDIO_TYPE.ogg;
        console.log("curAudioType=%o", curAudioType);

        const recordedBlobChunks = [];

        mediaStreamRecorder.mimeType = curAudioType.mimeType;

        mediaStreamRecorder.ondataavailable = function (recordedBlob) {
            console.log("mediaStreamRecorder.ondataavailable: recordedBlob=%o", recordedBlob);
            if (recordedBlob.size &gt; 0) {
                recordedBlobChunks.push(recordedBlob);
                console.log("recordedBlobChunks=%o", recordedBlobChunks);
            }
        };

        $( "#stopSpeak" ).on( "click", function() {
            console.log("#stopSpeak clicked");

            mediaStreamRecorder.stop();
        });

        mediaStreamRecorder.stop = function() {
            console.log("mediaStreamRecorder stoped");

            console.log("recordedBlobChunks=%o", recordedBlobChunks);

            const recordedBlob = new Blob(recordedBlobChunks);
            console.log("recordedBlob=%o", recordedBlob);
            const blobUrl = URL.createObjectURL(recordedBlob);
            console.log("blobUrl=%o", blobUrl);

            playRecordedAudio(blobUrl);

            downloadRecordedAudio(blobUrl, curAudioType.suffix);
        };

        if ((curAudioType == AUDIO_TYPE.wav) || (curAudioType == AUDIO_TYPE.pcm)) {
            // mediaStreamRecorder.recorderType = StereoAudioRecorder;
            // console.log("set recorderType to StereoAudioRecorder when wav");

            console.log("seems wav type need trigger then can start record");

            $( "#startSpeak" ).on( "click", function() {
                console.log("#startSpeak clicked");
    
                mediaStreamRecorder.start();
                console.log("mediaStreamRecorder started by button click");
            });
        } else {
            mediaStreamRecorder.start();
            console.log("directly mediaStreamRecorder started by code");
        }
    }
</code>

也还是有问题:

stop后,还是会执行:ondataavailable

WebAudio API ondataavailable after stop

WebAudio still ondataavailable after stop

WebAudio ondataavailable

官网的api,好像是这个:

MediaRecorder.ondataavailable – Web APIs | MDN

那在stop后,不应该还继续会调用到ondataavailable才对啊

突然发现,貌似是自己的此处代码中的:

<code>mediaStreamRecorder.stop = function() {
</code>

应该改为:

<code>mediaStreamRecorder.onstop = function() {
</code>

才对啊

另看到示例代码:

https://github.com/streamproc/MediaStreamRecorder/blob/master/demos/audio-recorder.html

中有:

<code>            document.querySelector('#stop-recording').onclick = function() {

                this.disabled = true;
                mediaRecorder.stop();
                mediaRecorder.stream.stop();
                document.querySelector('#pause-recording').disabled = true;
                document.querySelector('#start-recording').disabled = false;
            };
</code>

即:除了

mediaRecorder.stop()

还要:

mediaRecorder.stream.stop();

或许就是我此处只mediaRecorder.stop(),但是还会ondataavailable的原因?

去加上试试

但是加了onstop后,的确就不再继续ondataavailable了

但是点击下载,却没有下载到wav文件,而是index.html文件

看来是没有执行到onstop

然后另外,再去参考

https://github.com/streamproc/MediaStreamRecorder/blob/master/demos/audio-recorder.html

好像就没有stop或onstop的event函数

WebRTC Audio Recording using MediaStreamRecorder

的确是:此处demo中没有写stop的event,只有

mediaRecorder.start(3000);

每隔3秒保存一次

但是官网

https://github.com/streamproc/MediaStreamRecorder#record-audiowav

已经说了用:

How to manually stop recordings?

mediaRecorder.stop();

了啊

也有

https://github.com/streamproc/MediaStreamRecorder#onstop

onstop的

后来明白了之前为何stop后还继续ondataavailable

因为:

<code>mediaStreamRecorder.stop = function() {
</code>

就是重写了stop函数,没有真正的调用原先的mediaStreamRecorder的stop。

但是此处代码:

<code>        mediaStreamRecorder.ondataavailable = function (recordedBlob) {
            console.log("mediaStreamRecorder.ondataavailable: recordedBlob=%o", recordedBlob);
            if (recordedBlob.size &gt; 0) {
                recordedBlobChunks.push(recordedBlob);
                console.log("recordedBlobChunks=%o", recordedBlobChunks);
            }
        };

        mediaStreamRecorder.onstop = function() {
            console.log("mediaStreamRecorder.onstop");

            console.log("recordedBlobChunks=%o", recordedBlobChunks);

            const recordedBlob = new Blob(recordedBlobChunks);
            console.log("recordedBlob=%o", recordedBlob);
            const blobUrl = URL.createObjectURL(recordedBlob);
            console.log("blobUrl=%o", blobUrl);

            playRecordedAudio(blobUrl);

            downloadRecordedAudio(blobUrl, curAudioType.suffix);
        };

        $( "#stopSpeak" ).on( "click", function() {
            console.log("#stopSpeak clicked");

            console.log("now call mediaStreamRecorder.stop");
            mediaStreamRecorder.stop();
        });
</code>

却没有执行到mediaStreamRecorder.onstop

转载请注明:在路上 » 【未解决】MediaStreamRecorder中stop后还会执行ondataavailable

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
89 queries in 0.184 seconds, using 22.07MB memory