Re: asynchronous vs synchronous instantiation of AudioWorkerNodes

Mostly, I wanted to be clear that the idea of having a worker node
constructor that returned a promise was a bad idea imo, after consideration.

Your proposal

- 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.


Would probably be okay (with the caveat that "synchronously creates nodes"
still means the node needs to instantiate on the other thread to actually
start processing audio); it makes yet another layer of indirection, which
I'm not overly fond of, but could be okay; I haven't looked at the
cross-thread implications yet.  I'm a bit worried it's one more scope to
manage, but I'd be interested to see what it would look like.  Presumably
the model there is any custom worker node types you might want to use
later, you'd need to call their factory constructors first.

In this case, the only problem is we STILL can't replicate the current
behavior (since AudioContext construction isn't asynchronous) - we really
need a synchronous bit that enables node creation (and subsequent
AudioParam usage) in the main thread, and the async "load up the worker
scripts" in the audio thread to be independent.  Otherwise, you can't do:

var ac = new AudioContext();
...some synchronous steps??
var gain = ac.createMyCustomGainNode();
gain.gain.value = 0.5;

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.


On Thu, Nov 6, 2014 at 2:18 PM, Joseph Berkovitz <joe@noteflight.com> wrote:

>
> On Nov 6, 2014, at 4:50 PM, Chris Wilson <cwilso@google.com> wrote:
>
> *Conclusion:*
> Keeping in mind your custom code can encapsulate the worker scripts, I
> think it's better if we just presume that "component" scripts will be
> main-thread scripts that package up (as blob, e.g.) the worker script, and
> then encapsulate a factory method or object constructor.
>
> E.g.:
>
> <script src="worker-based-gain.js"></js>  <!-- packages up the worker, and
> exposes MyGainNode constructor -->
> <script>
>     var gain = new MyGainNode( audioContext );
>     gain.gain.value = 0.5;
> </script>
>
>
> OK, so IIRC your suggestion corresponds to this proposal in my list, yes?
>
> - 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).
>>
>
> As a best practice you are suggesting that a library that “fronts” for
> custom nodes can do some local caching of worker scripts as Blobs, etc.
> which will minimize the delay between the node’s instantiation and its
> subsequent loading of the script and processing audio. It seems to me that
> this still means that JS loading/parsing (albeit from some kind of local
> storage) is taking place on a per-node basis.
>
> That may be workable, but could you please explain why the two proposals
> in which a node factory is created from a preloaded script don’t work for
> you? It would seem desirable to separate worker-script loading from worker
> node instantiation if at all possible, much as the API separates buffer
> loading from buffer node creation.
>
> …Joe
>

Received on Thursday, 6 November 2014 22:43:34 UTC