- From: Chris Wilson <cwilso@google.com>
- Date: Sat, 8 Nov 2014 07:07:24 -0800
- To: Joseph Berkovitz <joe@noteflight.com>
- Cc: "Robert O'Callahan" <robert@ocallahan.org>, Audio WG <public-audio@w3.org>
- Message-ID: <CAJK2wqV_Jw+ubCxzb=f48rpLATm+Cwrow+4mV_MWOUOcMN0mjA@mail.gmail.com>
I'll attempt an approach that enables state-sharing across instances in the next edit (when I take on dynamic channels and inputs/outputs). It's going to be a couple of weeks due to Chrome Dev Summit and Thanksgiving. It will be a bit more complex, since you can't just tack expandos onto the params object; params needs to be read-only, since the members are "owned" by the AudioParam setup in the main thread (need to avoid conflicts). Will have to do something like that that be a sub-object of a node state object. On Fri, Nov 7, 2014 at 10:12 AM, Joseph Berkovitz <joe@noteflight.com> wrote: > On Nov 6, 2014, at 7:42 PM, Robert O'Callahan <robert@ocallahan.org> > wrote: > > On Fri, Nov 7, 2014 at 6:09 AM, Joseph Berkovitz <joe@noteflight.com> > wrote: > >> - 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... [snip] >> >> - 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.) >> > > I prefer the latter, although the former works too. The ability to share > resources easily in the latter approach seems worth having. > > > I am starting to feel that a Jussi-style proposal is better myself, > although I originally felt otherwise. For instance, a node with substantial > preloaded data (as today’s native HRTF implementation) would surely not > want to load it up once per node. > > Also, the value of preloading the script in my first proposal feels > questionable if the script still has to be parsed and then fired up into a > private scope on every node instantiation. In the latter approach, scripts > are loaded, parsed and activated once and then it’s all over. Seems cleaner. > > On Nov 6, 2014, at 7:44 PM, Robert O'Callahan <robert@ocallahan.org> > wrote: > > On Fri, Nov 7, 2014 at 11:43 AM, Chris Wilson <cwilso@google.com> wrote: > >> I DON'T like the proposal of sharing the scope across node instances, >> because I don't see how you could store state then; but on the other hand, >> some state MIGHT want to be shared across nodes (e.g. HRTF database). >> Hmm. Complexifies the design quite a bit to have a global scope and a node >> scope, though. >> > > One option would be to have the spec *required* that > AudioProcessEvent.parameters is the same object every time the event fires > for a given Node. Then the worker script can attach its own per-node state > to the parameters object (using regular JS expandos). > > > I agree with RoC’s direction: something like this can make the design > reasonably simple and make it clear to developers. I’ve arrived at a > slightly different flavor of this idea, which I’ll try to describe here. > > The spec could state that the “target” and “currentTarget” properties of > all events delivered to this script are an object of type > AudioWorkerProcessor. This object's identity must be preserved across *all > events that pertain to any given node*. You can think of it as an > audio-thread proxy for the node; it is also considered to be the dispatcher > of node-related audio events. > > The IDL for it might look like this: > > interface AudioWorkerProcessor : EventTarget > { > attribute object data; // this is initially an empty object; > the script can store arbitrary state in its properties > void postMessage(…); // posts a message back to the main-thread > AudioWorkerNode > void terminate(); // kills audio-engine reference to > node resources; no further events will be dispatched and GC is enabled > }; > > In this scheme, the AudioWorkerGlobalScope handlers onmessage and > onaudioprocess continue to be common to all nodes, but they deliver events > that have different AudioWorkerProcessors as targets. > > If you don’t like common handlers, a variation of this approach could move > onaudioprocess and onmessage into the AudioWorkerProcessor as EventHandler > attributes. A shared oncreate handler in the AudioWorkerGlobalScope would > then set up these handlers for each node, when it was created. (This would > even allow different nodes created by the same script to behave > differently, if the oncreate event were able to communicate some > node-construction parameter from the main thread.) > > For this to work, I think the Promise from the original > createAudioWorker() needs to yield something like this: > > interface AudioWorkerNodeFactory > { > AudioWorkerNode createAudioWorkerNode(…); > } > > I’m not being fussy about all of these names, by the way, I assume they’d > all need to be improved. > > …Joe > >
Received on Saturday, 8 November 2014 15:07:51 UTC