W3C home > Mailing lists > Public > public-audio@w3.org > October to December 2012

Re: AudioBuffer mutability

From: Robert O'Callahan <robert@ocallahan.org>
Date: Tue, 30 Oct 2012 10:41:04 +1300
Message-ID: <CAOp6jLaLtH038U-nK+5vZc7nY_TpXTEbS306TooKG06GsSTBgA@mail.gmail.com>
To: Chris Rogers <crogers@google.com>
Cc: public-audio@w3.org
On Tue, Oct 30, 2012 at 7:20 AM, Chris Rogers <crogers@google.com> wrote:

> Hi Robert, the answer is that for efficiency the AudioBufferSourceNode is
> expected to *directly* read the data stored in the AudioBuffer.  As a
> consequence of this, then any changes to the AudioBuffer after start() is
> called can affect the result.  As you point out this is an inherently racy
> affair, but for all practical purposes is a non-issue because, in general,
> it's not useful to modify the data dynamically in this way.  In over two
> years of developer use of this API, using it for a great variety of uses
> cases, this issue has not been a problem because people know to not modify
> the buffer.


Elsewhere in the Web platform we have worked hard to ensure that races on
shared memory cannot be exposed like this. Not even Web Workers has any
features that allow it. Not only does this avoid exposing Web authors to
various kinds of subtle bugs, but it also means that the Web platform can
be implemented efficiently on hardware and software platforms that don't
support parallelism with mutable shared memory. (There are experimental
browsers around that are actually trying to do this.) I don't think we
should abandon that position lightly.

I'm not confident that the history of Web Audio so far guarantees that
people won't run into problems in the future (either accidentally or
deliberately). For example, a clever developer might realize that by
modifying the contents of a playing AudioBuffer they can affect what gets
played with minimum latency. I believe PulseAudio actually offers that as a
feature, and some RTC implementations do tricks like that to try to handle
late-arriving audio packets.

So, what I think the specification should say is that the behavior is
> undefined if the buffer is modified after start().  It's very important to
> *not* require any buffer copies in AudioBufferSourceNode for efficiency.
>  Developers are free to make their own copies of the buffers, modify them,
> and use them in other calls to start().
>

Undefined behavior should always be avoided if at all possible. As far as I
can tell we haven't even tried to avoid it. We shouldn't be lazy about this.

I think in this case this problem is actually easy to solve without even
changing the API. The typed array spec defines a "neuter" operation on
ArrayBuffers that makes the underlying data inaccessible through the
ArrayBuffer and any objects (such as Float32Array) that depend on the
ArrayBuffer:
http://www.khronos.org/registry/typedarray/specs/latest/#9.2
This is used by Web Workers to enable safe zero-copy transfer of ownership
of the data from one thread to another. We could say that, for a given
AudioBuffer B, the first time start() is called on an AudioBufferSourceNode
whose 'buffer' is B, B's channel ArrayBuffers are neutered. Any future
attempts to modify the data will then fail, probably with an "array index
out of bounds" error.

How does that sound?

Rob
-- 
Jesus called them together and said, “You know that the rulers of the
Gentiles lord it over them, and their high officials exercise authority
over them. Not so with you. Instead, whoever wants to become great among
you must be your servant, and whoever wants to be first must be your
slave — just
as the Son of Man did not come to be served, but to serve, and to give his
life as a ransom for many.” [Matthew 20:25-28]
Received on Monday, 29 October 2012 21:41:33 UTC

This archive was generated by hypermail 2.4.0 : Friday, 17 January 2020 19:03:14 UTC