Skip to content
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 90 additions & 18 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -2500,9 +2500,10 @@ returned promise with the rendered result as an
interface OfflineAudioContext : BaseAudioContext {
constructor(OfflineAudioContextOptions contextOptions);
constructor(unsigned long numberOfChannels, unsigned long length, float sampleRate);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we make length nullable I think it would become length?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the discussion in the spec issue, was using length the final resolution?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The discussion has stalled since my last comment. AFAIU, it seems that everyone agreed on using length, but there is some divergence on how it should be used. Should it be optional or nullable?

I'd rather have length be nullable instead of optional. This way callers need to be a little more intentional when creating indefinite-length OfflineAudioContexts. What do you think?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then let's clarify the resolution first. I'd really liked to have a WG decision on this:

IIUC your design is to make length required, and the proposal from @karlt is to make it optional?

@karlt @padenot Can you all chime in here so we can make a decision?

Promise<AudioBuffer> startRendering();
Promise<AudioBuffer> startRendering(unsigned long chunkSize);
Comment thread
gabrielsanbrito marked this conversation as resolved.
Outdated
Promise<undefined> resume();
Promise<undefined> suspend(double suspendTime);
Promise<undefined> close();
readonly attribute unsigned long length;
attribute EventHandler oncomplete;
};
Expand Down Expand Up @@ -2596,7 +2597,7 @@ Constructors</h4>

<pre class=argumentdef for="OfflineAudioContext/constructor(numberOfChannels, length, sampleRate)">
numberOfChannels: Determines how many channels the buffer will have. See {{BaseAudioContext/createBuffer()}} for the supported number of channels.
length: Determines the size of the buffer in sample-frames.
length: Determines the total size of the audio render in sample-frames.
sampleRate: Describes the sample-rate of the [=linear PCM=] audio data in the buffer in sample-frames per second. See [[#sample-rates]] for the required supported range.
</pre>
</dl>
Expand All @@ -2607,9 +2608,11 @@ Attributes</h4>
<dl dfn-type=attribute dfn-for="OfflineAudioContext">
: <dfn>length</dfn>
::
The size of the buffer in sample-frames. This is the same as the
The total size of the audio render in sample-frames. This is the same as the
value of the <code>length</code> parameter for the constructor.

For undefined-length rendering, this attribute SHOULD be set to positive infinity.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO - since we have an explicit close() in this change, rendering indefinitely can be done by calling startRendering(chunkSize) repeatedly.

Probably this is aligned with what @karlt proposed?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if understand this comment :/ Would you mind clarifying?

When I wrote this, I intended to have length be Infinity (after the last update it should be null) because an undefined render session has no defined length.

Do you mean that we shouldn't set length to null in the undefined length scenario and this should be tracked via an internal slot? For example, we need this info when determining the size of the returned AudioBuffer. The OfflineAudioContext needs to know whether we are in an undefined-length render or not:

<li> Otherwise, if {{OfflineAudioContext/length}} is
<code>null</code>, set <var>bufferLength</var> to the
<a>render quantum size</a>.


: <dfn>oncomplete</dfn>
::
The event type of this event handler is <dfn event>complete</dfn>. The event
Expand All @@ -2621,7 +2624,7 @@ Attributes</h4>
Methods</h4>

<dl dfn-type=method dfn-for="OfflineAudioContext">
: <dfn>startRendering()</dfn>
: <dfn>startRendering(chunkSize)</dfn>
::
Given the current connections and scheduled changes, starts
rendering audio.
Expand All @@ -2640,21 +2643,29 @@ Methods</h4>
<ol>
<li>If [=this=]'s [=relevant global object=]'s [=associated Document=] is not [=fully active=] then return [=a promise rejected with=] "{{InvalidStateError}}" {{DOMException}}.

<li>If the {{[[rendering started]]}} slot on the
{{OfflineAudioContext}} is <em>true</em>, return a rejected
promise with {{InvalidStateError}}, and abort these
steps.

<li>Set the {{[[rendering started]]}} slot of the
{{OfflineAudioContext}} to <em>true</em>.

<li>Let <var>promise</var> be a new promise.

<lI>Let <var>bufferLength</var> be a number initialized to the value of {{OfflineAudioContext/length}}.

<ol>
<li> If {{OfflineAudioContext/startRendering(chunkSize)/chunkSize}} is provided:
<ol>
<li> Let <var>renderedFrames</var> be the number of sample-frames already rendered by the {{OfflineAudioContext}}.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want renderedFrames to be an internal slot; then we can also specify when and how it is updated.

<li> If <var>renderedFrames</var> + {{OfflineAudioContext/startRendering(chunkSize)/chunkSize}} <= {{OfflineAudioContext/length}}, set <var>bufferLength</var> to {{OfflineAudioContext/startRendering(chunkSize)/chunkSize}}.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Let's explain this logic in descriptive prose rather than using abbreviated math.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Does it look good now? I was not sure if it was needed to make changes to the addition/subtraction.

<li> Otherwise, set <var>bufferLength</var> to {{OfflineAudioContext/length}} - <var>renderedFrames</var>.
</ol>
<li> Otherwise, if {{OfflineAudioContext/length}} is positive infinity, set <var>bufferLength</var> to the <a>render quantum size</a>.
</ol>

<li>Create a new {{AudioBuffer}}, with a number of
channels, length and sample rate equal respectively to the
<code>numberOfChannels</code>, <code>length</code> and
channels and sample rate equal respectively to the
<code>numberOfChannels</code> and
<code>sampleRate</code> values passed to this instance's
constructor in the <code>contextOptions</code> parameter.
constructor in the <code>contextOptions</code> parameter;
and length equal to <var>bufferLength</var>.
Assign this buffer to an internal slot
<dfn attribute for="OfflineAudioContext">[[rendered buffer]]</dfn> in the {{OfflineAudioContext}}.

Expand All @@ -2677,9 +2688,12 @@ Methods</h4>
occasion.

<ol>
<li>Let <var>nFrames</var> be a number initialized to the value
Comment thread
gabrielsanbrito marked this conversation as resolved.
Outdated
of the length of {{[[rendered buffer]]}}.

<li>Given the current connections and scheduled changes, start
rendering <code>length</code> sample-frames of audio into
{{[[rendered buffer]]}}
rendering <var>nFrames</var> sample-frames of audio into
{{[[rendered buffer]]}}.

<li>For every <a>render quantum</a>, check and
{{OfflineAudioContext/suspend()|suspend}}
Expand All @@ -2696,7 +2710,8 @@ Methods</h4>
<li>Resolve the <var ignore>promise</var> created by {{startRendering()}}
with {{[[rendered buffer]]}}.

<li>[=Queue a media element task=] to [=fire an event=] named
<li>If {{OfflineAudioContext/length}} is not positive infinity,
[=Queue a media element task=] to [=fire an event=] named
{{OfflineAudioContext/complete}} at the {{OfflineAudioContext}} using
{{OfflineAudioCompletionEvent}} whose `renderedBuffer` property is set to
{{[[rendered buffer]]}}.
Expand All @@ -2706,9 +2721,9 @@ Methods</h4>
</ol>
</div>

<div>
<em>No parameters.</em>
</div>
<pre class=argumentdef for="OfflineAudioContext/startRendering()">
chunkSize: The size of the desired {{AudioBuffer}}.
Comment thread
gabrielsanbrito marked this conversation as resolved.
Outdated
</pre>
<div>
<em>Return type:</em> {{Promise}}&lt;{{AudioBuffer}}&gt;
</div>
Expand Down Expand Up @@ -2803,6 +2818,63 @@ Methods</h4>
<div>
<em>Return type:</em> {{Promise}}&lt;{{undefined}}&gt;
</div>

: <dfn>close()</dfn>
::
Closes the {{AudioContext}}. This will not automatically release
Comment thread
gabrielsanbrito marked this conversation as resolved.
Outdated
all {{AudioContext}}-created objects, but will suspend the
progression of the {{AudioContext}}'s
{{BaseAudioContext/currentTime}}, and stop
processing audio data.

<div algorithm="OfflineAudioContext.close()">
<span class="synchronous">When close is called, execute these steps:</span>

1. If [=this=]'s [=relevant global object=]'s [=associated Document=] is not [=fully active=] then return [=a promise rejected with=] "{{InvalidStateError}}" {{DOMException}}.

1. Let <var>promise</var> be a new Promise.

1. If the {{[[control thread state]]}} flag on the
{{OfflineAudioContext}} is <code>closed</code> reject the promise
with {{InvalidStateError}}, abort these steps,
returning <var>promise</var>.

1. Set the {{[[control thread state]]}} flag on the {{OfflineAudioContext}} to
<code>closed</code>.

1. <a>Queue a control message</a> to close the {{OfflineAudioContext}}.

1. Return <em>promise</em>.
</div>

<div algorithm="run a control message to close an OfflineAudioContext">
Running a <a>control message</a> to close an
{{OfflineAudioContext}} means running these steps on the
<a>rendering thread</a>:

1. Set the {{[[rendering thread state]]}} to <code>suspended</code>.
<div class="note">
This will stop rendering.
</div>

1. If this <a>control message</a> is being run in a reaction to the
document being unloaded, abort this algorithm.
<div class="note">
There is no need to notify the control thread in this case.
</div>

1. <a href="https://html.spec.whatwg.org/multipage/media.html#queue-a-media-element-task">
queue a media element task</a> to execute the following steps:

1. Resolve <em>promise</em>.
1. If the {{BaseAudioContext/state}} attribute of the {{OfflineAudioContext}} is not already "{{AudioContextState/closed}}":
1. Set the {{BaseAudioContext/state}} attribute of the {{OfflineAudioContext}} to "{{AudioContextState/closed}}".

1. <a href="https://html.spec.whatwg.org/multipage/media.html#queue-a-media-element-task">
queue a media element task</a> to <a spec="dom" lt="fire an event">fire
an event</a> named {{BaseAudioContext/statechange}} at the {{OfflineAudioContext}}.
</div>

</dl>

<h4 dictionary id="OfflineAudioContextOptions">
Expand Down
Loading