9

我正在使用一个 MediaStream 并使用画布和 WebAudio API 合并两个单独的轨道(视频和音频)。MediaStream 本身似乎并没有不同步,但是在将其读入 MediaRecorder 并将其缓冲到视频元素中之后,音频似乎总是比视频播放得早得多以下是似乎有问题的代码:

let stream = new MediaStream();

// Get the mixed sources drawn to the canvas
this.canvas.captureStream().getVideoTracks().forEach(track => {
  stream.addTrack(track);
});

// Add mixed audio tracks to the stream
// https://stackoverflow.com/questions/42138545/webrtc-mix-local-and-remote-audio-steams-and-record
this.audioMixer.dest.stream.getAudioTracks().forEach(track => {
  stream.addTrack(track);
});

// stream = stream;
let mediaRecorder = new MediaRecorder(stream, { mimeType: 'video/webm;codecs=opus,vp8' });

let mediaSource = new MediaSource();
let video = document.createElement('video');
video.src = URL.createObjectURL(mediaSource);
document.body.appendChild(video);
video.controls = true;
video.autoplay = true;

// Source open
mediaSource.onsourceopen = () => {
  let sourceBuffer = mediaSource.addSourceBuffer(mediaRecorder.mimeType);

  mediaRecorder.ondataavailable = (event) => {

    if (event.data.size > 0) {
      const reader = new FileReader();
      reader.readAsArrayBuffer(event.data);
      reader.onloadend = () => {
        sourceBuffer.appendBuffer(reader.result);
        console.log(mediaSource.sourceBuffers);
        console.log(event.data);
      }
    }
  }
  mediaRecorder.start(1000);
}

AudioMixer.js

export default class AudioMixer {

  constructor() {
    // Initialize an audio context
    this.audioContext = new AudioContext();

    // Destination outputs one track of mixed audio
    this.dest = this.audioContext.createMediaStreamDestination();

    // Array of current streams in mixer
    this.sources = [];
  }

  // Add an audio stream to the mixer
  addStream(id, stream) {
    // Get the audio tracks from the stream and add them to the mixer
    let sources = stream.getAudioTracks().map(track => this.audioContext.createMediaStreamSource(new MediaStream([track])));
    sources.forEach(source => {

      // Add it to the current sources being mixed
      this.sources.push(source);
      source.connect(this.dest);

      // Connect to analyser to update volume slider
      let analyser = this.audioContext.createAnalyser();
      source.connect(analyser);
      ...
    });
  }

  // Remove all current sources from the mixer
  flushAll() {
    this.sources.forEach(source => {
      source.disconnect(this.dest);
    });

    this.sources = [];
  }

  // Clean up the audio context for the mixer
  cleanup() {
    this.audioContext.close();
  }
}

我认为这与如何将数据推送到 MediaSource 缓冲区有关,但我不确定。我在做什么使流不同步?

4

3 回答 3

3

对旧帖子的迟到回复,但它可能会帮助某人......

我遇到了完全相同的问题:我有一个视频流,应该辅以音频流。在音频流中不时播放短声音(AudioBuffer)。整个过程是通过 MediaRecorder 记录的。在 Chrome 上一切正常。但在 Android 版 Chrome 上,所有声音都会快速连续播放。“play()”的“when”参数在 Android 上被忽略。(audiocontext.currentTime 随着时间的推移继续增加...... - 这不是重点)。

我的解决方案类似于 Jacob 的评论 2018 年 9 月 2 日 7:41:我创建并连接了一个 48,000 Hz 听不见的正弦波振荡器,它在录制期间在音频流中永久播放。显然,这导致了适当的时间进度。

于 2019-07-31T16:25:57.667 回答
1

发送多个相关 RTP 流的 RTP 端点需要在其他端点同步,必须对所有要同步的流使用相同的 RTCP CNAME。这需要一个短期持久的 RTCP CNAME,它在多个 RTP 流中是通用的,并且可能在多个相关的 RTP 会话中。这种使用的一个常见示例发生在多媒体会话中对音频和视频流进行口型同步时,其中单个参与者必须为其音频 RTP 会话和其视频 RTP 会话使用相同的 RTCP CNAME。另一个示例可能是同步分层音频编解码器的各层,其中每个层都必须使用相同的 RTCP CNAME。

https://datatracker.ietf.org/doc/html/rfc6222#page-2

于 2021-09-13T13:53:50.050 回答
0

Chrome 中有一个错误,它会播放 44100KHz 的缓冲媒体流音频,即使它是用 48000 编码的(这会导致间隙和视频不同步)。所有其他浏览器似乎都可以正常播放。您可以选择将编解码器更改为支持 44.1KHz 编码的编解码器或播放来自网络链接的文件作为源(这样 Chrome 可以正确播放)

于 2020-04-21T09:33:04.837 回答