Diving into Firefox Media Code

I've spent the better part of this weekend working on bug 686137: Setting audio.mozFrameBufferLength has no effect on MozAudioAvailable.frameBuffer.length.

Whats going on in this regression is easy to spot. The default frameBufferLength for a given Audio stream is 1024 * the number of channels. ( for example, stereo has 2). When a media element sets up it calculates the default FrameBufferLength.  On an audio element, you can set the mozFrameBufferLength attribute to change it from the default value. The range of values is from 512 to 16384. If one were to listen to the "MozAudioAvailable" event after changing the length, you'd notice that the value reported by the event is incorrect. Here's a test case of it not working.

I spent some time looking through the audio code for clues on what was causing this issue but ultimately made no progress. After this, I decided to find out where and when this regression got into the code. I started with the major releases. Testing showed me this bug was not present in Firefox 4 but appeared in Firefox 5. Next, I tested in the betas and found it appeared somewhere between beta 7 and the full Firefox 5 release. This narrowed down to a roughly 30 day span in April, 2011. Testing against each nightly revealed the bug appeared on the night of April 11, 2011. It was difficult work looking through the lists of commits, but I eventually found the culprit: bug 638807, Conveniently titled: Data race on nsBuiltinDecoder::mFrameBufferLength. Now I knew exactly which files to focus my attention on.

I started looking through the diff of the patch that was landed, to try to find clues to why this issue was arising, but that proved fruitless.  The new code was placed there in an attempt to stop a data race on the value. Whatever had been done wasn't revealing anything obvious to me. I decided to fire up gdb and start setting up breakpoints to see what was going on.

This is where thing get interesting. I noticed a couple things. The first thing I noticed was that when the audio element started up, the frameBufferLength value gets set by calling nsBuiltinDecoder::RequestFrameBufferLength. From there it's passed into nsBuiltinDecoderStateMachine::setFrameBufferLength, which then sets it inside of nsAudioAvailabaleEventManager::setSignalBufferLength. The second thing I noticed was that setting mozFrameBufferLength set the frameBufferLength inside of nsMediaDecoder::RequestFrameBufferLength.

I'm not 100% sure if my account of events above is correct, but if it is, that means there's a bit of a disconnect between the elements reported FrameBufferLength, and the one being used internally by the decoder and the AudioAvailableEventManager.  I'm not entirely sure yet how to fix it, but I will keep working on finding the solution. It's in there somewhere...