MediaStreamGraph underruns from time to time

RESOLVED DUPLICATE of bug 848953

Status

()

defect
RESOLVED DUPLICATE of bug 848953
6 years ago
6 years ago

People

(Reporter: Ehsan, Assigned: padenot)

Tracking

Trunk
x86
macOS
Points:
---
Dependency tree / graph

Firefox Tracking Flags

(Not tracked)

Details

Attachments

(1 attachment)

Reporter

Description

6 years ago
Posted file Test case
See the testcase that I'm attaching to the bug.  In Firefox, the playback is choppy, but in Chrome you can hear a smooth beep sound.

Paul, can you look into this please?  I'm not sure where to start debugging this.
Sure, I'll have a look tomorrow.
I also find that the playback does not always start immediately. Bind the above test case to an onclick in a button. Press many times and it gets more and more sluggish. Not sure if it is related.
Reporter

Comment 3

6 years ago
(In reply to comment #2)
> I also find that the playback does not always start immediately. Bind the above
> test case to an onclick in a button. Press many times and it gets more and more
> sluggish. Not sure if it is related.

Can you please file another bug on that?  Thanks!

Comment 4

6 years ago
Confirmed on Ubuntu 12.04 (Linux).
Also confirmed when loading a sound from a file (got sine wave from http://www.audiocheck.net/audiofrequencysignalgenerator_sinetone.php), but does not occur when opening this file directly in Firefox (thus playing it with <audio>). It's hardly noticeable in music (to me).
What happens is that we don't feed the audio data fast enough to the AudioStream.

The way it works is that we have a callback firing periodically when new audio data are needed.
We copy audio data from the internal AudioStream buffer to the buffer the callback gives us as argument [1].
If no audio data are available in the AudioStream, we just write silence [2], and this is called an "underrun". If everything is fine, |underrunFrames| should be 0, and the |memcpy| call an noop.

Simply putting:

> if (underrunFrames) {
>    printf("underrun: %d\n", underrunFrames);
> }

there [2] is enough to make sure the glitches you hear are underruns.

I believe that when we will end up driving the MediaStreamGraph with the cubeb callback, that _should_ take care of this issue, but in the mean time, we could probably do something.

[1]: http://mxr.mozilla.org/mozilla-central/source/content/media/AudioStream.cpp#990
[2]: http://mxr.mozilla.org/mozilla-central/source/content/media/AudioStream.cpp#1078
Reporter

Comment 6

6 years ago
Is there a bug on file for calling into MSG from the cubeb callback?  This is highly noticeable when playing back multiple buffers...
Ehsan, the details are here: https://wiki.mozilla.org/Gecko:MediaStreamLatency, in the "Desirable state" section. afaik, no bugs are file about this, but we talked about it at the last work week. I could certainly hack up a patch to avoid the underruns, though, if needed, à la bug 793274.
Reporter

Comment 8

6 years ago
(In reply to comment #7)
> Ehsan, the details are here: https://wiki.mozilla.org/Gecko:MediaStreamLatency,
> in the "Desirable state" section. afaik, no bugs are file about this, but we
> talked about it at the last work week.

Yeah, just wanted to make sure I'm not missing discussions happening in another bug.  :-)  Filed bug 848954.

> I could certainly hack up a patch to
> avoid the underruns, though, if needed, à la bug 793274.

That would be great.  This is something that we're going to need to fix by GDC, and calling MSG from the cubeb callback seems like something that may not happen that soon.
What happens here is that the MSG sometimes write a little bit less than what is needed for the callback to have enough data to ensure a smooth playback. From what I've observed, this is something between 1 and 150 frames, with most of the underruns between 1 and 10 frames.

I've tested gUM, and it happens as well, but went (I believe) unnoticed because, of the poor mic quality (in comparison to a generated sinusoid that we use in this test case).

I've tested with mozCaptureStream, and a pure sine sound [1], and did a bit of bisection on nightlies:
- at the time of landing (2012-5-1), the stream capture kinda works, but glitches a lot: underruns, brutal gain change.
- it gets way better with bug 750258 around on the 2012-5-8's nightly, but I still hear underruns from time to time.
- from this point onward, no improvement.

Basically, this does not seem to have worked glitch-free in Nightly in the past. I've tested both on Mac and Linux.

Then, I'm wondering why we are not using the audio stream clock so we actually know where we are, instead of relying on timestamps. I was surprised to see that since bug 750258 landed, |MediaStreamGraphImpl::GetAudioPosition| is unused, I thought we prefer using the audio clock when we have one available.

And since the MediaStreamGraph seems to write to the audio stream close to exactly the number of frames that is needed (based on the sample rate and the timestamps), this is rather unsafe and it is normal that it underruns every now and then.

[1]: http://paul.cx/public/mozCaptureStream.html
Summary: Simple audio playback is choppy → MediaStreamGraph underruns from time to time
I did write code to use GetAudioPosition but we'd deadlock on some platforms, so I took it out. IIRC the problem was that we'd write audio to the stream but GetAudioPosition wouldn't advance, so we'd assume we didn't need to write more and nothing would ever get played. I assume there's some magic amount (per-platform) of audio we needed to write to get things moving. This may not be an issue anymore now that we're on libcubeb everywhere.
Yes, that was one of the major problems with the sydneyaudio push-based API.  cubeb solves it by requiring the appropriate amount of data to be continuously supplied via the data callback.
I'll try to reenable it then, we will see if it improves the situation.
Nope, it does not help much. Or, more likely, my code is wrong.

I just tried to replace the timestamp stuff in |nextCurrentTime| by a call to |MediaStreamGraphImpl::GetAudioPosition|, add the driver latency, add the |BufferedAudioStream| latency, so we get the time the audio written in the stream would be heard. Maybe we should do something else.

The more I think about it, the more I tend to think this would be better fixed by running the graph in the callback.
Reporter

Comment 15

6 years ago
OK, sounds good to me!
Status: NEW → RESOLVED
Last Resolved: 6 years ago
Resolution: --- → DUPLICATE
Duplicate of bug: 848953
Reporter

Comment 16

6 years ago
Mass moving Web Audio bugs to the Web Audio component.  Filter on duckityduck.
Component: Video/Audio → Web Audio
You need to log in before you can comment on or make changes to this bug.