Skip to content

Commit a331281

Browse files
rtoysvgeesusKorilakkuma
authored
Fix #1933: Use FrozenArray for AudioWorkletProcessor process() (#2250)
* Fix #1933: Use FrozeArray for AudioWorkletProcessor process() Instead of `sequence<sequence<Float32Array>>`, use `FrozenArray<FrozenArray<Float32Array>>`. Define a callback function as well. * Address review comments from karlt. Rename AudioWorkletProcessorCallback to AudioWorletProcessCallback The third parameter is an object, not frozen array. * Replace process() method with callback sections Several changes here in no particular order: - Tell bikeshed that `object` is the webidl concept - Fix parameter names for the process callback (plurals, as used in the descriptions) - Rename the dfn for "Processing an input buffer" from "process" to "processing-input-buffer". - Fix up links to `process()` to point to the right place. - The old section on the process method is broken up into two sections. The main one is renaming it to "callback AudioWorkletProcessCallback". This contains most fo the main text. A subsection then describes the parameters to the callback. * Update expected errors The callback idea fixes the errors from defining the process method. * Address some review comments * Describe what happens to inputs/outputs if things change Add text to say inputs/outputs are recycled unless the topology changes (number of channels, array is transferred). Then new arrays are allocated. * Address some review comments Still need description of how parameters are frozen. * Update README.md * Fix typo in "messsage" (#2255) * chore: Fix markdown for bold (#2258) * Update implementation-report.html Update for Safari and for Edge * Update implementation-report.html Update IDL results for newer browsers * Update implementation-report.html Update summaries for new browsers. Fails = 6573 - passes * Update implementation-report.html Date * Fix typo "atleast" (#2259) This isn't really a typo but an issue with bikeshed not leaving a space at line breaks. See speced/bikeshed#1470. * Address #2185: Fix duplicated IDs for decode callbacks (#2253) * Address #2185: Duplicate IDs for Decode callbacks The decode callbacks were multiply defining their arguments. Instead, just have the descriptions of the arguments just link back to the IDL that defines the args. * Update expected errors * Fix #2262: Clone bikeshed and install it (#2263) As a workaround, clone the bikeshed repo and install bikeshed from the repo. Ideally, want just want to use the version with pip3 instead of cloning the current version of bikeshed, but that's producing unexpected errors. We'll do this for now and recheck at some later date when bikeshed is updated and revert to the old version. * Fix #2257: Make channel ordering table visible in dark mode (#2264) When using dark mode, use a different background color for the even rows of the channel ordering table so that the entries are visible. While we're at it, make the headings for the audio node properties table, the audio param values table, and the enumeration description table look a little better in dark mode. This is done by specifying a brighter green to make it a bit more legible. * Add ECMAScript algorithm to freeze parameters. * Some cleanups. Co-authored-by: Chris Lilley <[email protected]> Co-authored-by: Tomohiro IKEDA <[email protected]>
1 parent b01e2a1 commit a331281

File tree

2 files changed

+103
-82
lines changed

2 files changed

+103
-82
lines changed

expected-errs.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,4 @@ LINE: Can't find the 'destinationNode' argument of method 'AudioNode/disconnect(
55
LINE: Can't find the 'destinationNode' argument of method 'AudioNode/disconnect(destinationParam, output)' in the argumentdef block.
66
LINE: Can't find the 'destinationNode' argument of method 'AudioNode/disconnect(destinationParam, output)' in the argumentdef block.
77
LINE: Can't find the 'input' argument of method 'AudioNode/disconnect(destinationParam, output)' in the argumentdef block.
8-
LINE: Can't find method '['AudioWorkletProcessor/process(inputs, outputs, parameters))']'.
9-
LINE: No 'idl' refs found for 'process(inputs, outputs, parameters))'.
108
✔ Successfully generated, but fatal errors were suppressed

index.bs

Lines changed: 103 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,10 @@ Markup Shorthands: markdown on, dfn on, css off
4343
spec: ECMAScript; url: https://tc39.github.io/ecma262/#sec-data-blocks; type: dfn; text: data block;
4444
url: https://www.w3.org/TR/mediacapture-streams/#dom-mediadevices-getusermedia; type: method; for: MediaDevices; text: getUserMedia()
4545
</pre>
46-
46+
<!-- We want {{object}} to go to the WebIDL object -->
47+
<pre class=link-defaults>
48+
spec:webidl; type:interface; text:object
49+
</pre>
4750
<link rel="preload" href="https://www.w3.org/scripts/MathJax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML" as="script">
4851
<link rel="preload" href="https://www.w3.org/scripts/MathJax/2.7.5/jax/output/HTML-CSS/jax.js?rev=2.7.5" as="script">
4952
<link rel="preload" href="https://www.w3.org/scripts/MathJax/2.7.5/jax/output/HTML-CSS/fonts/STIX/fontdata.js?rev=2.7.5" as="script">
@@ -10372,13 +10375,18 @@ and the definition of the class manifests the actual audio processing.
1037210375
Note that the an {{AudioWorkletProcessor}} construction can only happen as a
1037310376
result of an {{AudioWorkletNode}} contruction.
1037410377

10375-
<pre class="idl">
10378+
<xmp class="idl">
1037610379
[Exposed=AudioWorklet]
1037710380
interface AudioWorkletProcessor {
1037810381
constructor ();
1037910382
readonly attribute MessagePort port;
1038010383
};
10381-
</pre>
10384+
10385+
callback AudioWorkletProcessCallback =
10386+
boolean (FrozenArray<FrozenArray<Float32Array>> inputs,
10387+
FrozenArray<FrozenArray<Float32Array>> outputs,
10388+
object parameters);
10389+
</xmp>
1038210390

1038310391
{{AudioWorkletProcessor}} has two internal slots:
1038410392

@@ -10389,7 +10397,7 @@ interface AudioWorkletProcessor {
1038910397

1039010398
: <dfn>[[callable process]]</dfn>
1039110399
::
10392-
A boolean flag representing whether {{AudioWorkletProcessor/process()}} is
10400+
A boolean flag representing whether [=process()=] is
1039310401
a valid function that can be invoked.
1039410402
</dl>
1039510403

@@ -10470,86 +10478,57 @@ Constructors</h5>
1047010478
resources to be [[html#ports-and-garbage-collection|collected]].
1047110479
</dl>
1047210480

10473-
<h5 id="AudioWorkletProcessor-methods">
10474-
Methods</h5>
10481+
<h5 id="callback-audioworketprocess-callback">
10482+
Callback {{AudioWorkletProcessCallback}}</h5>
1047510483

1047610484
Users can define a custom audio processor by extending
10477-
{{AudioWorkletProcessor}}. The subclass MUST define a method
10478-
named {{process()}} that implements the audio processing
10485+
{{AudioWorkletProcessor}}. The subclass MUST define an {{AudioWorkletProcessCallback}}
10486+
named <code><dfn>process()</dfn></code> that implements the audio processing
1047910487
algorithm and may have a static property named
1048010488
<code><dfn>parameterDescriptors</dfn></code> which is an iterable
1048110489
of {{AudioParamDescriptor}}s.
1048210490

10483-
<dl dfn-type=method dfn-for="AudioWorkletProcessor">
10484-
: <dfn>process(inputs, outputs, parameters)</dfn>
10485-
::
10486-
Implements the audio processing algorithm for the
10487-
{{AudioWorkletProcessor}}.
10491+
The [=process()=] callback function is handled as specified when <a href="#rendering-a-graph">rendering a graph</a>.
1048810492

10489-
The {{process()}} method is called
10490-
synchronously by the audio <a>rendering thread</a> at
10491-
every <a>render quantum</a>, if {{AudioWorkletNode}} is
10493+
<div class="note">
10494+
The return value of this callback controls the lifetime
10495+
of the {{AudioWorkletProcessor}}'s associated
10496+
{{AudioWorkletNode}}.
10497+
10498+
This lifetime policy can support a variety of approaches
10499+
found in built-in nodes, including the following:
10500+
10501+
* Nodes that transform their inputs, and are active only
10502+
while connected inputs and/or script references exist. Such
10503+
nodes SHOULD return <code>false</code> from
10504+
[=process()=] which allows the presence or absence of
10505+
connected inputs to determine whether the {{AudioWorkletNode}} is
1049210506
[=actively processing=].
1049310507

10494-
<div class="note">
10495-
The return value of this method controls the lifetime
10496-
of the {{AudioWorkletProcessor}}'s associated
10497-
{{AudioWorkletNode}}.
10498-
10499-
This lifetime policy can support a variety of approaches
10500-
found in built-in nodes, including the following:
10501-
10502-
* Nodes that transform their inputs, and are active only
10503-
while connected inputs and/or script references exist. Such
10504-
nodes SHOULD return <code>false</code> from
10505-
{{process()}} which allows the presence or absence of
10506-
connected inputs to determine whether the {{AudioWorkletNode}} is
10507-
[=actively processing=].
10508-
10509-
* Nodes that transform their inputs, but which remain active
10510-
for a <a>tail-time</a> after their inputs are disconnected. In
10511-
this case, {{process()}} SHOULD return
10512-
`true` for some period of time after
10513-
<code>inputs</code> is found to contain zero channels. The
10514-
current time may be obtained from the global scope's
10515-
{{AudioWorkletGlobalScope/currentTime}} to
10516-
measure the start and end of this tail-time interval, or the
10517-
interval could be calculated dynamically depending on the
10518-
processor's internal state.
10519-
10520-
* Nodes that act as sources of output, typically with a
10521-
lifetime. Such nodes SHOULD return `true` from
10522-
{{process()}} until the point at which they are no
10523-
longer producing an output.
10524-
10525-
Note that the preceding definition implies that when no
10526-
return value is provided from an implementation of
10527-
{{process()}}, the effect is identical to returning
10528-
<code>false</code> (since the effective return value is the falsy
10529-
value {{undefined}}). This is a reasonable behavior for
10530-
any {{AudioWorkletProcessor}} that is active only when it has
10531-
active inputs.
10532-
</div>
10533-
10534-
<pre class=argumentdef for="AudioWorkletProcessor/process(inputs, outputs, parameters))">
10535-
inputs:
10536-
The input audio buffer from the incoming connections provided by the user agent. It has type <code>sequence&lt;sequence&lt;Float32Array>></code>.<code class="nobreak">inputs[n][m]</code> is a {{Float32Array}} of audio samples for the \(m\)th channel of the \(n\)th input. While the number of inputs is fixed at construction, the number of channels can be changed dynamically based on [=computedNumberOfChannels=].
10537-
10538-
If there are no [=actively processing=] {{AudioNode}}s connected to the \(n\)th input of the {{AudioWorkletNode}} for the current render quantum, then the content of <code>inputs[n]</code> is an empty array, indicating that zero channels of input are available. This is the only circumstance under which the number of elements of <code>inputs[n]</code> can be zero.
10539-
10540-
outputs:
10541-
The output audio buffer that is to be consumed by the user agent. It has type <code>sequence&lt;sequence&lt;Float32Array>></code>.<code class="nobreak">outputs[n][m]</code> is a {{Float32Array}} object containing the audio samples for \(m\)th channel of \(n\)th output. Each of the {{Float32Array}}s are zero-filled. The number of channels in the output will match [=computedNumberOfChannels=] only when the node has a single output.
10542-
10543-
parameters:
10544-
An [=ordered map=] of <var>name</var><var>parameterValues</var>. <code>parameters["<var>name</var>"]</code> returns <var>parameterValues</var>, which is a {{Float32Array}} with the automation values of the <var>name</var> {{AudioParam}}.
10545-
10546-
For each array, the array contains the [=computedValue=] of the parameter for all frames in the [=render quantum=]. However, if no automation is scheduled during this render quantum, the array MAY have length 1 with the array element being the constant value of the {{AudioParam}} for the [=render quantum=].
10547-
</pre>
10548-
10549-
<div>
10550-
<em>Return type:</em> {{boolean}}
10551-
</div>
10552-
</dl>
10508+
* Nodes that transform their inputs, but which remain active
10509+
for a <a>tail-time</a> after their inputs are disconnected. In
10510+
this case, [=process()=] SHOULD return
10511+
`true` for some period of time after
10512+
<code>inputs</code> is found to contain zero channels. The
10513+
current time may be obtained from the global scope's
10514+
{{AudioWorkletGlobalScope/currentTime}} to
10515+
measure the start and end of this tail-time interval, or the
10516+
interval could be calculated dynamically depending on the
10517+
processor's internal state.
10518+
10519+
* Nodes that act as sources of output, typically with a
10520+
lifetime. Such nodes SHOULD return `true` from
10521+
[=process()=] until the point at which they are no
10522+
longer producing an output.
10523+
10524+
Note that the preceding definition implies that when no
10525+
return value is provided from an implementation of
10526+
[=process()=], the effect is identical to returning
10527+
<code>false</code> (since the effective return value is the falsy
10528+
value {{undefined}}). This is a reasonable behavior for
10529+
any {{AudioWorkletProcessor}} that is active only when it has
10530+
active inputs.
10531+
</div>
1055310532

1055410533
The example below shows how {{AudioParam}} can be defined and used in an
1055510534
{{AudioWorkletProcessor}}.
@@ -10584,6 +10563,51 @@ class MyProcessor extends AudioWorkletProcessor {
1058410563
}
1058510564
</xmp>
1058610565

10566+
<h6 id="audioworkletprocess-callback-parameters" callback lt="AudioWorkletProcessCallback()">
10567+
Callback {{AudioWorkletProcessCallback}} Parameters
10568+
</h6>
10569+
The following describes the parameters to the {{AudioWorkletProcessCallback}} function.
10570+
10571+
In general, the {{AudioWorkletProcessCallback/inputs!!argument}} and
10572+
{{AudioWorkletProcessCallback/outputs!!argument}} arrays will be reused
10573+
between calls so that no memory allocation is done. However, if the
10574+
topology changes, because, say, the number of channels in the input or the
10575+
output changes, new arrays are reallocated. New arrays are also
10576+
reallocated if any part of the
10577+
{{AudioWorkletProcessCallback/inputs!!argument}} or
10578+
{{AudioWorkletProcessCallback/outputs!!argument}} arrays are
10579+
transferred.
10580+
10581+
<dl dfn-type=argument dfn-for="AudioWorkletProcessCallback">
10582+
: {{AudioWorkletProcessCallback/inputs!!argument}}, of type <code>{{FrozenArray}}&lt;{{FrozenArray}}&lt;{{Float32Array}}&gt;&gt;</code>
10583+
:: The input audio buffer from the incoming connections provided by the user agent. <code class="nobreak">inputs[n][m]</code> is a {{Float32Array}} of audio samples for the \(m\)th channel of the \(n\)th input. While the number of inputs is fixed at construction, the number of channels can be changed dynamically based on [=computedNumberOfChannels=].
10584+
10585+
If there are no [=actively processing=] {{AudioNode}}s connected to the \(n\)th input of the {{AudioWorkletNode}} for the current render quantum, then the content of <code>inputs[n]</code> is an empty array, indicating that zero channels of input are available. This is the only circumstance under which the number of elements of <code>inputs[n]</code> can be zero.
10586+
10587+
: {{AudioWorkletProcessCallback/outputs!!argument}}, of type <code>{{FrozenArray}}&lt;{{FrozenArray}}&lt;{{Float32Array}}>></code>
10588+
:: The output audio buffer that is to be consumed by the user agent. <code class="nobreak">outputs[n][m]</code> is a {{Float32Array}} object containing the audio samples for \(m\)th channel of \(n\)th output. Each of the {{Float32Array}}s are zero-filled. The number of channels in the output will match [=computedNumberOfChannels=] only when the node has a single output.
10589+
10590+
: {{AudioWorkletProcessCallback/parameters!!argument}}, of type {{object}}
10591+
:: An [=ordered map=] of <var>name</var><var>parameterValues</var>. <code>parameters["<var>name</var>"]</code> returns <var>parameterValues</var>, which is a {{FrozenArray}}&lt;{{Float32Array}}> with the automation values of the <var>name</var> {{AudioParam}}.
10592+
10593+
For each array, the array contains the [=computedValue=] of the parameter for all frames in the [=render quantum=]. However, if no automation is scheduled during this render quantum, the array MAY have length 1 with the array element being the constant value of the {{AudioParam}} for the [=render quantum=].
10594+
10595+
This object is frozen according the the following steps
10596+
<div algorithm="freeze parameter object">
10597+
1. Let |parameter| be the [=ordered map=] of the name and parameter values.
10598+
1. <a href="http://www.ecma-international.org/ecma-262/#sec-setintegritylevel">SetIntegrityLevel</a>(|parameter|, frozen)
10599+
</div>
10600+
10601+
This frozen [=ordered map=] computed in the algorithm is passed to the
10602+
{{AudioWorkletProcessCallback/parameters!!argument}}
10603+
argument.
10604+
10605+
Note: This means the object cannot be modified and
10606+
hence the same object can be used for successive calls
10607+
unless length of an array changes.
10608+
10609+
</dl>
10610+
1058710611
<h5 dictionary lt="AudioParamDescriptor">
1058810612
{{AudioParamDescriptor}}</h5>
1058910613

@@ -11233,16 +11257,15 @@ operation such as resolution of {{Promise}}s in the {{AudioWorkletGlobalScope}}.
1123311257
argument of [=input buffer=], output buffer and
1123411258
[=input AudioParam buffer=]. A buffer containing copies of the
1123511259
elements of the {{Float32Array}}s passed via the
11236-
<a href="#dom-audioworkletprocessor-process-inputs-outputs-parameters-outputs">
11237-
outputs</a> parameter to <var>processFunction</var> is
11260+
{{AudioWorkletProcessCallback/outputs!!argument}} parameter to <var>processFunction</var> is
1123811261
<a href="#available-for-reading">made available for reading</a>.
1123911262

1124011263
1. At the conclusion of <var>processFunction</var>,
1124111264
<a href="https://tc39.github.io/ecma262/#sec-toboolean"><code>ToBoolean</code></a>
1124211265
is applied to the return value and the result is
1124311266
assigned to the associated {{AudioWorkletProcessor}}'s
1124411267
<a>active source</a> flag. This in turn affects whether
11245-
subsequent invocations of {{process()}} occur, and has
11268+
subsequent invocations of [=process()=] occur, and has
1124611269
an impact on the lifetime of the node.
1124711270

1124811271
1. Else if {{[[callable process]]}} is `false`,
@@ -11263,7 +11286,7 @@ operation such as resolution of {{Promise}}s in the {{AudioWorkletGlobalScope}}.
1126311286
5. If this {{AudioNode}} is a <a>destination node</a>,
1126411287
[=Recording the input|record the input=] of this {{AudioNode}}.
1126511288

11266-
6. Else, <a>process</a> the <a>input buffer</a>, and
11289+
6. Else, [=processing-input-buffer|process=] the <a>input buffer</a>, and
1126711290
[=Making a buffer available for reading|make available for reading=] the
1126811291
resulting buffer.
1126911292

@@ -11301,7 +11324,7 @@ usage.
1130111324
running the algorithm for this {{AudioNode}} to produce 128
1130211325
sample-frames.
1130311326

11304-
<dfn lt="process">Processing an input buffer</dfn> means
11327+
<dfn lt="processing-input-buffer">Processing an input buffer</dfn> means
1130511328
running the algorithm for an {{AudioNode}}, using an <a>input
1130611329
buffer</a> and the value(s) of the {{AudioParam}}(s) of this
1130711330
{{AudioNode}} as the input for this algorithm.

0 commit comments

Comments
 (0)