MediaRecorder实时音频分块录制与服务器端保存:解决文件损坏问题

admin 百科 14

MediaRecorder实时音频分块录制与服务器端保存:解决文件损坏问题-第1张图片-佛山资讯网

在使用MediaRecorder进行实时音频录制并分块上传至服务器时,常见的错误是生成的音频文件无法播放。本文将深入探讨导致此问题的原因,即MediaRecorder的`mimeType`配置不当以及服务器端文件写入方式不正确。我们将提供一套完整的解决方案,包括客户端JavaScript的MediaRecorder初始化配置、数据处理以及服务器端PHP的正确文件追加逻辑,确保实时录制的音频能够成功保存并播放。

实时音频录制问题剖析:为什么文件会损坏?

当开发者尝试通过JavaScript的MediaRecorder API实时捕获麦克风音频,将其分块编码为Base64,并通过POST请求发送到服务器,再由服务器解码并写入文件时,经常会遇到保存的.ogg或其它格式音频文件损坏、无法播放的问题。

核心原因通常有两个:

  1. MediaRecorder的MIME类型配置错误: 许多开发者误以为可以在生成Blob时指定媒体类型(new Blob(chunks, { 'type' : 'audio/ogg; codecs=opus' })),但实际上,MediaRecorder在初始化时就需要明确其将输出的数据格式和编码器。如果MediaRecorder不知道它应该生成什么类型的媒体数据,它可能会使用默认设置,这与你期望的Blob类型不匹配,导致数据流不连续或格式不正确。
  2. 服务器端文件写入方式不当: 在实时分块上传场景中,每一块数据都是整个音频流的一部分。如果服务器端每次都使用file_put_contents()直接覆盖文件,那么最终文件中只会保留最后一块数据,导致文件不完整或损坏。正确的做法是每次接收到数据时,将其追加到现有文件中。

客户端(JavaScript)的正确实现

要解决MediaRecorder的MIME类型配置问题,我们需要在实例化MediaRecorder对象时,通过第二个参数传入一个配置对象,其中包含mimeType属性。

以下是修正后的JavaScript客户端代码示例:

var mediaRecorder = null;
let chunks = [];

if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
   console.log('getUserMedia supported.');
   navigator.mediaDevices.getUserMedia(
      {
         audio: true
      })
      .then(function(stream) {
        // 关键:在MediaRecorder构造函数中指定mimeType
        const mrOptions = { mimeType: 'audio/ogg; codecs=opus' };
        mediaRecorder = new MediaRecorder(stream, mrOptions);

        // 每2秒触发一次ondataavailable事件,收集数据块
        mediaRecorder.start(2000); 

        mediaRecorder.ondataavailable = function(e) {
            // 确保e.data中有数据
            if (e.data.size > 0) {
                chunks.push(e.data);
                // 使用MediaRecorder实例的mimeType来创建Blob
                const blob = new Blob(chunks, { type : mediaRecorder.mimeType });
                chunks = []; // 清空chunks,准备接收下一个数据块

                var reader = new FileReader();
                reader.readAsDataURL(blob); 
                reader.onloadend = function() {
                    // 提取Base64编码的数据
                    var data = reader.result.split(";base64,")[1]; 
                    // 发送数据到服务器
                    requestp2("a.php", "data=" + encodeURIComponent(data));
                }
            }
        };

        mediaRecorder.onstop = function() {
            console.log("录制停止");
            // 可以在这里处理最后剩余的chunks,如果需要
        };

      })
      .catch(function(err) {
         console.log('获取麦克风权限失败: ' + err);
      }
   );
} else {
   console.log('当前浏览器不支持getUserMedia!');
}

/**
 * 封装的POST请求函数
 * @param {string} path 请求路径
 * @param {string} data 要发送的数据
 */
function requestp2(path, data) {
    var http = new XMLHttpRequest();
    http.open('POST', path, true);
    http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    http.onreadystatechange = function() {
        if (http.readyState === 4 && http.status === 200) {
            console.log("数据发送成功", http.responseText);
        } else if (http.readyState === 4 && http.status !== 200) {
            console.error("数据发送失败", http.status);
        }
    };
    http.send(data);
}

登录后复制

代码解释:

标签: php javascript java 编码 浏览器 app ai 音乐 stream 并发请求 php脚本 为什么

发布评论 0条评论)

还木有评论哦,快来抢沙发吧~