Search code examples
goffmpegwebrtc

Pion WebRTC Audio stream cutting out while video works


I am trying to send an MP4 video through Pion WebRTC to the browser.

Using FFmpeg, I split it into an Opus OGG stream and an Annex-B H.264 video stream. While the video works fine, the audio keeps cutting in and out. It plays fine for a few seconds, then stops for a second, and continues.

This is the FFmpeg command I use for audio:

ffmpeg -i demo.mp4 -c:a libopus -vn -page_duration 20000 demo.ogg

And this is my transmitter (shortened):

var lastGranule uint64
for {
    pageData, pageHeader, err := ogg.ParseNextPage() // Uses Pion OggReader

    // Taken from the play-from-disk example
    sampleCount := float64(pageHeader.GranulePosition - lastGranule)
    lastGranule = pageHeader.GranulePosition
    sampleDuration := time.Duration((sampleCount/48000)*1000) * time.Millisecond

    err = audioTrack.WriteSample(media.Sample{Data: pageData, Duration: sampleDuration})
    util.HandleError(err)

    time.Sleep(sampleDuration)
}

I tried hardcoding the delay to 15ms, which fixes the issue that it's cutting out, but then it randomly plays way too fast or starts skipping. Since I had glitchy video before updating my FFmpeg command (add keyframes and remove b-frames), I assume this is also an encoder problem.

What could be the cause for this?

Update: Using WebRTC logging in Chrome, I discovered the following log lines that occurred frequently:

[27216:21992:0809/141533.175:WARNING:rtcp_receiver.cc(452)] 30 RTCP blocks were skipped due to being malformed or of unrecognized/unsupported type, during the past 10 second period.

This is probably the reason for the cutouts, although I can't figure out why it receives malformed data.


Solution

  • The problem in the end was an inaccuracy in the Sleep time caused by issue #44343 in Go itself. It caused the samples not to be sent at a constant rate, but at a rate that randomly was between 5 and 15ms off, resulting in a choppy stream.

    Sean DuBois and me fixed this in the latest play-from-disk and play-from-disk-h264 examples in the Pion repository by replacing the for-loop and Sleep() with a Ticker, which is more accurate.