javascript – 使用MediaRecorder录制5秒音频片段,然后上传到服务器

我想记录5秒长的用户麦克风段,并将每个段上传到服务器.我尝试使用MediaRecorder并且我以5秒的时间间隔调用了start()和stop()方法,但是当我连接这些录音时,它们之间会发出“掉落”的声音.所以我尝试使用start()方法的timeslice参数记录5秒段:

navigator.mediaDevices.getUserMedia({ audio: { channelCount: 2, volume: 1.0, echoCancellation: false, noiseSuppression: false } }).then(function(stream) {
  const Recorder = new MediaRecorder(stream, { audioBitsPerSecond: 128000, mimeType: "audio/ogg; codecs=opus" });
  Recorder.start(5000); 
  Recorder.addEventListener("dataavailable", function(event) {
    const audioBlob = new Blob([event.data], { type: 'audio/ogg' });
    upload(audioBlob);
  });
});

但只有第一段是可玩的.我该怎么做,或者我怎样才能使所有blob都可玩?
我必须记录然后上传每个段.我不能制作一个blob数组(因为用户可以记录24小时的数据甚至更多,并且数据需要在用户录制时上传到服务器上 – 延迟5秒).

谢谢!

解决方法:

您必须了解媒体文件的构建方式.
不仅可以将一些原始数据直接转换为音频或视频.

它将取决于所选择的格式,但基本情况是您拥有所谓的元数据,就像描述文件结构的字典一样.

这些元数据对于软件来说是必需的,然后软件将读取文件以了解它应如何解析文件中包含的实际数据.

MediaRecorder API在这里处于一个奇怪的位置,因为它必须能够同时写入这些元数据,并且还要添加未确定的数据(它是一个实时记录器).

那么接下来会发生的是,浏览器会将主要元数据放在文件的开头,以便他们能够简单地将新数据推送到文件中,并且仍然是一个有效的文件(即使有些信息如持续时间也会失踪).

现在,您在datavailableEvent.data中获得的内容只是生成的整个文件的一部分.
第一个通常包含元数据和一些其他数据,具体取决于事件被告知触发的时间,但下一部分不一定包含任何元数据.

因此,您不能仅将这些部分作为独立文件获取,因为生成的唯一文件是由所有这些部分组成的文件,在单个Blob中连接在一起.

那么,对于你的问题,你有不同的方法:

>您可以在一个时间间隔内向服务器发送从录像机获得的最新切片,并合并这些服务器端.

const recorder = new MediaRecorder(stream);
const chunks = [];
recorder.ondataavailable = e => chunks.push(e.data);
recorder.start(); // you don't need the timeslice argument
setInterval(()=>{
  // here we both empty the 'chunks' array, and send its content to the server
  sendToServer(new Blob(chunks.splice(0,chunks.length)))
}, 5000);

在服务器端,您可以将新发送的数据附加到正在记录的文件中.
>另一种方法是生成许多小型独立文件,为此,您只需在一个时间间隔内生成一个新的MediaRecorder:

function record_and_send(stream) {
   const recorder = new MediaRecorder(stream);
   const chunks = [];
   recorder.ondataavailable = e => chunks.push(e.data);
   recorder.onstop = e => sendToServer(new Blob(chunks));
   setTimeout(()=> recorder.stop(), 5000); // we'll have a 5s media file
   recorder.start();
}
// generate a new file every 5s
setInterval(record_and_send, 5000);

这样做,每个文件将是独立的,持续时间约为5秒,您将能够逐个播放这些文件.
现在,如果你只希望在服务器上存储一个文件,仍然使用这种方法,你可以很好地在服务器端将这些文件合并在一起,例如使用像ffmpeg这样的工具.

上一篇:Mongo 的相关增删改查


下一篇:源码解析为什么spring 被@Repository注解标识注入后是代理类