diff --git a/index.bs b/index.bs index d505c3eff..3d39bbaf3 100644 --- a/index.bs +++ b/index.bs @@ -2501,14 +2501,38 @@ returned promise with the rendered result as an interface OfflineAudioContext : BaseAudioContext { constructor(OfflineAudioContextOptions contextOptions); constructor(unsigned long numberOfChannels, unsigned long length, float sampleRate); - Promise startRendering(); + Promise startRendering(optional unsigned long? chunkSize = null); Promise resume(); Promise suspend(double suspendTime); - readonly attribute unsigned long length; + Promise close(); + readonly attribute unsigned long? length; attribute EventHandler oncomplete; }; +{{OfflineAudioContext}} has the following internal slots: +
+ : [[rendering started]] + :: + A boolean flag representing whether the rendering has started. The + initial value is false. + + : [[rendered buffers]] + :: + An ordered list of {{AudioBuffer}}s that are being rendered. The initial + value is an empty list. + + : [[committed frames]] + :: + Tracks the number of frames that the {{OfflineAudioContext}} has + committed to render. The initial value is 0. + + : [[rendered frames]] + :: + Tracks the number of frames that have been rendered. The initial value + is 0. +
+

Constructors

@@ -2597,7 +2621,7 @@ Constructors
         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.
         
@@ -2608,8 +2632,11 @@ Attributes
: length :: - The size of the buffer in sample-frames. This is the same as the - value of the length parameter for the constructor. + The total size of the audio render in sample-frames. This is the same + as the value of the length parameter for the constructor. + + For undefined-length rendering, this attribute SHOULD be set to + null. : oncomplete :: @@ -2622,7 +2649,7 @@ Attributes Methods
- : startRendering() + : startRendering(chunkSize) :: Given the current connections and scheduled changes, starts rendering audio. @@ -2631,9 +2658,7 @@ Methods is via its promise return value, the instance will also fire an event named complete for legacy reasons. -
- Let [[rendering started]] be an internal slot of this {{OfflineAudioContext}}. Initialize this slot to false. - +
When startRendering is called, the following steps MUST be performed on the control thread: @@ -2641,30 +2666,77 @@ Methods
  1. If [=this=]'s [=relevant global object=]'s [=associated Document=] is not [=fully active=] then return [=a promise rejected with=] "{{InvalidStateError}}" {{DOMException}}. -
  2. If the {{[[rendering started]]}} slot on the - {{OfflineAudioContext}} is true, return a rejected - promise with {{InvalidStateError}}, and abort these +
  3. Let promise be a new promise. + +
  4. If the {{[[control thread state]]}} on the + {{OfflineAudioContext}} is {{AudioContextState/closed}}, reject + promise with {{InvalidStateError}} and abort these steps. -
  5. Set the {{[[rendering started]]}} slot of the - {{OfflineAudioContext}} to true. +
  6. If the {{OfflineAudioContext}}'s + {{OfflineAudioContext/length}} is not null and + {{[[committed frames]]}} is greater than or equal to + {{OfflineAudioContext}}'s {{OfflineAudioContext/length}}, reject + promise with {{InvalidStateError}} and abort these + steps. -
  7. Let promise be a new promise. +
  8. Let bufferLength be a number initialized to the + value of the + {{OfflineAudioContext/startRendering(chunkSize)/chunkSize}}. + +
      +
    1. If the {{OfflineAudioContext}}'s + {{OfflineAudioContext/length}} is null: +
        +
      1. If + {{OfflineAudioContext/startRendering(chunkSize)/chunkSize}} + is null, set bufferLength to + render quantum size. +
      +
    2. Otherwise, if the {{OfflineAudioContext}}'s + {{OfflineAudioContext/length}} is not null: +
        +
      1. If + {{OfflineAudioContext/startRendering(chunkSize)/chunkSize}} + is not null and {{[[committed frames]]}} + + {{OfflineAudioContext/startRendering(chunkSize)/chunkSize}} + is less than the {{OfflineAudioContext}}'s + {{OfflineAudioContext/length}}, set bufferLength to + {{OfflineAudioContext/startRendering(chunkSize)/chunkSize}}. +
      2. Otherwise, set bufferLength to + {{OfflineAudioContext/length}} - {{[[committed frames]]}}. +
      +
    + +
  9. Let bufferLength be a number initialized to the + result of + + calculating the buffer length for offline rendering given + the requested chunkSize. -
  10. Create a new {{AudioBuffer}}, with a number of - channels, length and sample rate equal respectively to the - numberOfChannels, length and +
  11. If bufferLength is not a multiple of + render quantum size, round it up to the next multiple of + the render quantum size. + +
  12. Create a new {{AudioBuffer}} buffer, with a number of + channels and sample rate equal respectively to the + numberOfChannels and sampleRate values passed to this instance's - constructor in the contextOptions parameter. - Assign this buffer to an internal slot - [[rendered buffer]] in the {{OfflineAudioContext}}. + constructor in the contextOptions parameter; + and length equal to bufferLength.
  13. If an exception was thrown during the preceding - {{AudioBuffer}} constructor call, reject - promise with this exception. + {{AudioBuffer}} constructor call, reject promise with + this exception and return promise. + +
  14. Set {{[[rendering started]]}} to true. + +
  15. Set {{[[committed frames]]}} to the sum of + {{[[committed frames]]}} and the buffer's + {{AudioBuffer/length}}. -
  16. Otherwise, in the case that the buffer was successfully - constructed, begin offline rendering. +
  17. Append buffer to {{[[rendered buffers]]}} and + begin offline rendering for buffer.
  18. Append promise to {{BaseAudioContext/[[pending promises]]}}. @@ -2672,15 +2744,41 @@ Methods
+
+ To calculate the buffer length for offline rendering + given a requested chunkSize, the following steps + MUST be performed on the control thread: +
    +
  1. If the {{OfflineAudioContext}}'s + {{OfflineAudioContext/length}} is null: +
      +
    1. If chunkSize is null, return + the render quantum size. +
    2. Otherwise, return chunkSize. +
    +
  2. Otherwise, if the {{OfflineAudioContext}}'s + {{OfflineAudioContext/length}} is not null: +
      +
    1. If chunkSize is not null and + {{[[committed frames]]}} + chunkSize is less than + the {{OfflineAudioContext}}'s + {{OfflineAudioContext/length}}, return chunkSize. +
    2. Otherwise, return + {{OfflineAudioContext/length}} - {{[[committed frames]]}}. +
    +
+
+
- To begin offline rendering, the following steps MUST - happen on a rendering thread that is created for the - occasion. + To begin offline rendering for an {{AudioBuffer}} + buffer, the following steps MUST happen on a rendering + thread that is created for the occasion.
    +
  1. Given the current connections and scheduled changes, start - rendering length sample-frames of audio into - {{[[rendered buffer]]}} + rendering buffer's {{AudioBuffer/length}} + sample-frames of audio into buffer.
  2. For every render quantum, check and {{OfflineAudioContext/suspend()|suspend}} @@ -2695,21 +2793,42 @@ Methods
    1. Resolve the promise created by {{startRendering()}} - with {{[[rendered buffer]]}}. + with buffer. + +
    2. Remove the promise from + {{BaseAudioContext/[[pending promises]]}}. -
    3. [=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]]}}. +
    4. Remove buffer from {{[[rendered buffers]]}}. + +
    5. Set {{[[rendered frames]]}} to the sum of + {{[[rendered frames]]}} and the {{AudioBuffer/length}} + of buffer. + +
    6. If {{OfflineAudioContext/length}} is not null: + +
        +
      1. If {{[[rendered frames]]}} is greater than or + equal to {{OfflineAudioContext/length}}, + Queue a control message to close the + {{OfflineAudioContext}}. + +
      2. [=Queue a media element task=] to + [=fire an event=] named + {{OfflineAudioContext/complete}} at the + {{OfflineAudioContext}} using + {{OfflineAudioCompletionEvent}} whose + `renderedBuffer` property is set to + buffer. +
-
- No parameters. -
+
+            chunkSize: The number of sample-frames to render during this call.
+        
Return type: {{Promise}}<{{AudioBuffer}}>
@@ -2804,6 +2923,71 @@ Methods
Return type: {{Promise}}<{{undefined}}>
+ + : close() + :: + Closes the {{OfflineAudioContext}}. This will not automatically release + all {{AudioContext}}-created objects, but will suspend the progression + of the {{AudioContext}}'s {{BaseAudioContext/currentTime}}, and stop + processing audio data. + +
+ When close is called, execute these steps: + + 1. If [=this=]'s [=relevant global object=]'s + [=associated Document=] is not [=fully active=] then return + [=a promise rejected with=] "{{InvalidStateError}}" + {{DOMException}}. + + 1. Let promise be a new Promise. + + 1. If the {{[[control thread state]]}} flag on the + {{OfflineAudioContext}} is closed reject the + promise with {{InvalidStateError}}, abort these steps, + returning promise. + + 1. Set the {{[[control thread state]]}} flag on the + {{OfflineAudioContext}} to closed. + + 1. Queue a control message to close the + {{OfflineAudioContext}}. + + 1. Return promise. +
+ +
+ Running a control message to close an {{OfflineAudioContext}} + means running these steps on the rendering thread: + + 1. Set the {{[[rendering thread state]]}} to suspended. +
+ This will stop rendering. +
+ + 1. If this control message is being run in a reaction to the + document being unloaded, abort this algorithm. +
+ There is no need to notify the control thread in this case. +
+ + 1. + queue a media element task to execute the following steps: + + 1. Resolve promise. + 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. + queue a media element task to + fire an event named + {{BaseAudioContext/statechange}} at the + {{OfflineAudioContext}}. +
+

@@ -2815,7 +2999,7 @@ This specifies the options to use in constructing an dictionary OfflineAudioContextOptions { unsigned long numberOfChannels = 1; - required unsigned long length; + unsigned long? length = null; required float sampleRate; (AudioContextRenderSizeCategory or unsigned long) renderSizeHint = "default"; };