- From: Jussi Kalliokoski <jussi.kalliokoski@gmail.com>
- Date: Sun, 9 Nov 2014 15:09:23 +0200
- To: Joseph Berkovitz <joe@noteflight.com>
- Cc: Audio WG <public-audio@w3.org>
- Message-ID: <CAJhzemW8J+-NH22PNZMH0uM-QWmsV4NRRtFCpbxBFRSmg7tzsQ@mail.gmail.com>
On Thu, Nov 6, 2014 at 7:09 PM, Joseph Berkovitz <joe@noteflight.com> wrote: > Hi group, > > There’s an issue noted in the AudioWorker proposal (issue #113) that I > want to highlight as a discussion point, so some public exchange can happen > prior to the next revised AudioWorker proposal from Chris. (One was already > expected in order to deal with dynamic input/output counts.) The > discussion so far has been limited to the github issue thread but it feels > worthy of broader attention. > > The issue is this: the createAudioWorker factory method on AudioContext > takes a script URL. Currently it returns a Node (see > http://cwilso.github.io/web-audio-api/#widl-AudioContext-createAudioWorker-AudioWorkerNode-DOMString-scriptURL-unsigned-long-numberOfInputChannels-unsigned-long-numberOfOutputChannels > ). > > That script could take an arbitrary amount of time to load, so the > returned Node would not be functional at the time of its instantiation. It > also might not be able to expose AudioParams at that time, if such > parameters are defined by executing the loaded script (as has been > proposed). In response Chris W suggested that this factory method might > return a Promise, not the actual Node. > > The Promise makes sense given the asynchrony of script loading, but the > need to employ a Promise here makes it hard to synchronously construct a > graph or subgraph using an AudioWorker node as part of that graph. This is > a very big leap away from the way one uses native nodes, working against > the notion of architectural layering built on top of the AudioWorker > concept. It imposes both script-loading overhead and the use of callbacks > on every instantiation of a node using some given script. > > This is not necessarily so bad for use cases in which a fairly static > graph is built once, for the duration of some audio session. But it’s more > serious w/r/t use cases that incorporate many individual AudioWorker > instances in small subgraphs built on demand (e.g. game sound effects or > musical notes in a synth). It makes it hard to factor out a one-time > asynchronous operation that loads assets (in this case, the script) from > repeated instantiation of objects (the nodes) that employ those same assets. > > Ideas to date (forgive me if I left yours out, and please re-propose it) > have included: > > - Don’t return a Promise. Continue to have createAudioWorker() return an > AudioWorkerNode, synchronously. This node presumably isn’t ready to > function yet, but it could be inserted into the graph. Script loading would > happen later, after which the node would initialize (possibly posting a > message back to the main thread to signal this). This is a bit like what > happens with other nodes that have delayed initialization e.g. HRTF > spatialization. However it might leave important script-determined details > like input/output count up in the air until the script has loaded and run. > > - Have createAudioWorker() return Promises that yield individual nodes, > and live with the potential delays and inconvenience to developers. Script > loading and execution takes place each time a node is needed. Developers > could preload scripts into local Blobs or data URLs to minimize delays. > > - Have createAudioWorker() return a Promise that yields a factory object > with a method that synchronously creates nodes, with each node having its > own AudioWorkerGlobalScope based on the already-loaded script. Script > *loading* would thus occur once per factory instance, but script > *execution* would occur once per node instance. (this is my proposal, > though I have little idea of what any implementation objections would be.) > > - Have createAudioWorker() return a Promise that yields a factory object > containing a live AudioWorkerGlobalScope, and allow further nodes to be > instantiated which share this same scope. Script loading and execution both > occur once per factory, because the scope is shared. However this > programming model does not isolate node instances’ state from each other. > (This is my understanding of a proposal that Jussi made, I haven’t been > able to track down the original. Jussi has said that some simple use of > closures would make the state bookkeeping easy but I don’t think an example > was provided.) > FWIW, I just made a complete example on how to implement a Sine node on top of my proposal: https://gist.github.com/jussi-kalliokoski/aa84fbb4cde7fc54ff01 > > It would be great to surface some thinking on this via email, so that when > we do discuss it on a telcon we’ll have already seen what the landscape > looks like. > > Best, > > . . . . . ...Joe > > PS if you want to debate some other aspect of AudioWorkers, it would be > great to start a new thread instead of using this one. > >
Received on Sunday, 9 November 2014 13:09:50 UTC