微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用mediarecorder API的播放确实很奇怪:不同的设备在不同的设备上丢失了

如何解决使用mediarecorder API的播放确实很奇怪:不同的设备在不同的设备上丢失了

我正在开发一个在浏览器中运行的应用程序,用户可以在其中记录自己的声音。使用MediaRecorder API,我可以获取记录并将其发布到我的服务器上。如果用户暂停并重新开始录制,则会出现问题。发生这种情况时,他们第一次从服务器上获得播放效果很好,但是当重播时,仅播放最后一段。如果我重新加载网页并重试,则第一次获取完整的录音时,再一次,它只是最后一个片段。

它正在使用opus编解码器,因此我尝试在VLC中播放它。在那里,我仅获得第一段,而随后的任何段都没有。最后,我尝试了转换为MP3,当我这样做时-MP3拥有整个录音!所以整个事情都被保存了,但是不知何故,这些段似乎存储在文件中并弄乱了重播。在每种情况下,只有一小段正在播放。我不得不说我对如何攻击这个感到茫然。玩家显示的时间是第一段的时间,无论播放的是第一段,第二段还是整段。有什么想法吗?

已编辑以提供可行的示例

如何测试:将此代码放在可以提供服务的地方并打开它(我使用基于chrome的浏览器)。单击开始以开始录制,然后单击暂停,然后再次单击开始以继续录制,然后再次暂停以停止。然后单击设置以加载录音,并收听录音。第一次收听时,我会得到完整的录音,尽管播放计时器只显示第一段。随后的播放仅播放最后一段。再次按下设置按钮将使其播放整个录音,但是仅第一次播放。

    <!doctype html>
    <html>
      <head>
        <script>
          var audio = null;
          function init() {
          audio = new Recording();
          audio.prepareAudio();
          }
    class Recording {
        recordButton;
        pauseButton;
        recorder;
        mimeType;
        audioChunks;

        constructor() {
            this.mimeType = this.recorder = null;
            this.recordButton = this.pauseButton = null;
            this.audioChunks = [];
        }

        getRecorder() {
            return new Promise(async resolve => {
                const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
                const mediaRecorder = new MediaRecorder(stream);

                var _this = this;
                mediaRecorder.addEventListener('dataavailable',event => {
                    _this.audioChunks.push(event.data);
                });

                const start = () => {
                    mediaRecorder.start();
                };

                const pause = () =>
                      new Promise(resolve => {
                          mediaRecorder.addEventListener('stop',() => {
                              resolve(_this.audioChunks);
                          });
                          mediaRecorder.stop();
                          _this.mimeType = mediaRecorder.mimeType;
                      });

                resolve({ start,pause });
            });
        }

        get codec() {
            if (!this.mimeType) return null;
            let split = this.mimeType.split('=');
            return (split.length > 1) ? split[1] : split;
        }

        prepareAudio() {
            this.recordButton = document.querySelector('#record');
            this.pauseButton = document.querySelector('#pause');

            var _this = this;
            this.recordButton.addEventListener('click',async () => {
                _this.recordButton.setAttribute('disabled',true);
                _this.pauseButton.removeAttribute('disabled');
                if (!_this.recorder) {
                    _this.recorder = await this.getRecorder();
                }
                _this.recorder.start();
            });

            this.pauseButton.addEventListener('click',async () => {
                _this.recordButton.removeAttribute('disabled');
                _this.pauseButton.setAttribute('disabled',true);
                await _this.recorder.pause();
            });
        }

        data() {
            return new Promise((resolve,reject) => {
                const reader = new FileReader();
                let codec = this.audioChunks[0].type;
                let audioBlob = new Blob(this.audioChunks,{type: this.codec || codec});
                reader.readAsDataURL(audioBlob);
                reader.onload = () => resolve({codec: codec,data: reader.result.split(',')[1]});
            });
        }

        blobUrl() {
                let codec = this.audioChunks[0].type;
                let audioBlob = new Blob(this.audioChunks,{type: this.codec || codec});
                let blobUrl = URL.createObjectURL(audioBlob);
                let player = document.getElementById('play-blob');
                player.src = blobUrl;
                player.disabled = false;
                return blobUrl;
          }
    }
        </script>     
      </head>
      <body onload="init()">
        <div>
          <button id="record" class="button fill" >Start</button>
          <br />
          <button id="pause" class="button fill" >Pause</button>
          <br />
          <button class="button fill" onclick="audio.blobUrl()">setup</button>
        </div>
        <audio id="play-blob" controls></audio>
      </body>
    </html>

解决方法

这不是一个完整的答案,但是我对正在发生的事情了解得更多。音频播放器(至少对于我正在使用的Chrome和Firefox版本(最新))似乎无法正确处理流音频。当源被加载时,它不知道长度(当然)。当创建具有多个片段( new Blob([segment1,segment2,...]))的Blob时,第一次将持续时间设为无穷大,并播放整个剪辑。在随后的播放中,剪辑时间以最长片段的长度给出,仅播放最后一个片段。音频对象将持续时间作为最长片段的长度。

我还通过使用howler更换音频设备解决了眼前的问题。就像我反复期望的那样播放整个剪辑。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。