W3C home > Mailing lists > Public > public-audio@w3.org > July to September 2013

Re: Proposal for fixing race conditions

From: Chris Rogers <crogers@google.com>
Date: Thu, 4 Jul 2013 12:21:52 -0700
Message-ID: <CA+EzO0mKhg21e3iy1o48Bps0bdnG9PPmxwACtVto37OzOZzEfQ@mail.gmail.com>
To: "Robert O'Callahan" <robert@ocallahan.org>
Cc: Joseph Berkovitz <joe@noteflight.com>, "public-audio@w3.org" <public-audio@w3.org>, Dave Herman <dherman@ccs.neu.edu>, "Mark S. Miller" <erights@google.com>
On Wed, Jul 3, 2013 at 10:09 PM, Robert O'Callahan <robert@ocallahan.org>wrote:

> On Thu, Jul 4, 2013 at 12:14 PM, Chris Rogers <crogers@google.com> wrote:
>
>> For any practical and real-world use cases using the API, there aren't
>> really any problems any more than already exist today with raciness of
>> asynchronous callbacks/event-handlers.  We already live in a world where
>> XHR completions, setInterval/setTimeout, requestAnimationFrame, file/blob
>> async requests, receiving responses from web workers, events from
>> HTMLMediaElement, and many others can all occur in unpredictable orders and
>> at unpredictable times.  Even something like rendering the contents of a
>> video stream from <video> into a canvas and then reading the pixels back is
>> going to involve lots of raciness in terms of exactly what frame you're
>> reading at any given time.
>>
>
> The nondeterminism arising from those APIs is limited in carefully
> specified ways. For example, when drawing a <video> into a canvas, the
> frame may be chosen nondeterministically, but you never get half of one
> frame and half of the next, or whatever else happens to be in the
> framebuffer while you're reading it. Likewise, the ordering of HTML5 task
> dispatch is nondeterministic, but also carefully constrained. In
> particular, each task executes as an atomic unit and is not interleaved
> with other tasks.
>
> We should discuss very specific real-world use cases because I think we're
>> in pretty good shape here.
>>
>
> Suppose someone writes the following code:
>   var audioBuffer =
> audioContext.createBuffer(1,10000,audioContext.sampleRate);
>   var audioBufferSourceNode = audioContext.createBufferSource();
>   audioBufferSourceNode.start(audioContext.currentTime + 0.1);
>   for (var i  = 0; i < 10000; ++i) {
>     audioBuffer.getChannelData(0)[i] = ...;
>   }
>

This is an extremely contrived example, and is not even close to real-world
calling patterns and use cases.  With any of the racy APIs I mentioned
above, there are dozens of ways to write buggy code that make assumptions
about timing and order of async callbacks which produce unpredictable
behavior.

I would be much more concerned if the example you showed actually
illustrated a calling pattern that anybody would actually use in the
real-world.

In the two years since the Web Audio API has been used by many developers
large and small, this type of issue you're describing has simply never come
up.  We're talking about developer experience on a range of devices,
browsers, and multiple operating systems:
Mac/Windows/Linux/ChromeOS/Android/iOS




> The spec doesn't say what happens in this situation.
>

First of all I repeat that this is not a sensible calling pattern that
developers ever use, but what's the worst that can happen?  A jangled audio
stream emanating from the speakers?  Yes, this is true, but there are
uncountable ways that any API including this one can be misused to create a
mess of sound.


> That's probably because with the Webkit/Blink implementation, as I
> understand it, almost anything can happen. On a fast-enough machine, most
> of the time, the sound will probably play as expected. On a slow machine,
> or if you hit a GC or a page fault, or if the memory subsystem is
> particularly lazy, you could get zeroes interspersed with the data you
> wanted. The unpredictability of this code (especially given it "usually
> works"), is a big problem.
>

We're talking about real-time systems here.  Performance issues can come up
already with the ScriptProcessorNode and the Mozilla audio data API.
 Depending on how fast the machine is and what other activities it's doing,
GC, etc. there can be gaps, stutters, and glitches with small buffer sizes,
etc.  Additionally, if you mix in setTimeout with a ScriptProcessorNode or
the audio data API you can get all kinds of raciness and jankiness with
regards to the timing of musical events.  I consider that to be a mis-use
of the APIs and a bad way to write audio code, but there's nothing stopping
developers from mixing these APIs together and creating these kinds of
messes.

Actually, that's why the Web Audio API is mostly based around processing in
its own thread using native code, to minimize these types of issues which
occur with the ScriptProcessorNode and the Mozilla audio data API.  It
helps insulate the developer from GC and other unpredictable activity on
the main JS thread.  I think that's a strong aspect of its design.

In the end, all the way down at the driver level which all browsers must
talk to, a continuous audio stream is supposed to be delivered to the
hardware.  But there are potentially racy things that can happen here
because we're dealing with producer/consumer models with DMA engines, ring
or double buffers, with client code feeding the buffer which the DMA engine
is right on the cutting edge of consuming.  Yes glitches can happen here
too and can vary depending on system stress, memory paging activities, etc.
Received on Thursday, 4 July 2013 19:22:20 UTC

This archive was generated by hypermail 2.3.1 : Tuesday, 6 January 2015 21:50:10 UTC