Bug 1565956 reorder AudioWorkletNode constructor parameter verification to align with spec r=padenot
authorKarl Tomlinson <karlt+@karlt.net>
Sun, 17 Nov 2019 21:21:31 +0000
changeset 502354 a77200f8f3eb7b00e27169f98d1272ceedab59d6
parent 502353 7553b88698cb6552427de9638bbb63c5776495a5
child 502355 9f72416c9e8a507772a72ac8d6f3d5f48f05e5b5
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1565956
milestone72.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1565956 reorder AudioWorkletNode constructor parameter verification to align with spec r=padenot and update quoted steps. Depends on D53128 Differential Revision: https://phabricator.services.mozilla.com/D53129
dom/media/webaudio/AudioWorkletNode.cpp
--- a/dom/media/webaudio/AudioWorkletNode.cpp
+++ b/dom/media/webaudio/AudioWorkletNode.cpp
@@ -365,108 +365,125 @@ AudioWorkletNode::AudioWorkletNode(Audio
       mInputCount(aOptions.mNumberOfInputs),
       mOutputCount(aOptions.mNumberOfOutputs) {}
 
 /* static */
 already_AddRefed<AudioWorkletNode> AudioWorkletNode::Constructor(
     const GlobalObject& aGlobal, AudioContext& aAudioContext,
     const nsAString& aName, const AudioWorkletNodeOptions& aOptions,
     ErrorResult& aRv) {
-  if (aOptions.mNumberOfInputs == 0 && aOptions.mNumberOfOutputs == 0) {
-    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-    return nullptr;
-  }
-
-  if (aOptions.mOutputChannelCount.WasPassed()) {
-    if (aOptions.mOutputChannelCount.Value().Length() !=
-        aOptions.mNumberOfOutputs) {
-      aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
-      return nullptr;
-    }
-
-    for (uint32_t channelCount : aOptions.mOutputChannelCount.Value()) {
-      if (channelCount == 0 || channelCount > WebAudioUtils::MaxChannelCount) {
-        aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
-        return nullptr;
-      }
-    }
-  }
   /**
-   * 2. If nodeName does not exists as a key in the BaseAudioContext’s node
+   * 1. If nodeName does not exist as a key in the BaseAudioContext’s node
    *    name to parameter descriptor map, throw a NotSupportedError exception
    *    and abort these steps.
    */
   const AudioParamDescriptorMap* parameterDescriptors =
       aAudioContext.GetParamMapForWorkletName(aName);
   if (!parameterDescriptors) {
     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return nullptr;
   }
 
+  // See https://github.com/WebAudio/web-audio-api/issues/2074 for ordering.
+  RefPtr<AudioWorkletNode> audioWorkletNode =
+      new AudioWorkletNode(&aAudioContext, aName, aOptions);
+  audioWorkletNode->Initialize(aOptions, aRv);
+  if (NS_WARN_IF(aRv.Failed())) {
+    return nullptr;
+  }
+
+  /**
+   * 3. Configure input, output and output channels of node with options.
+   */
+  if (aOptions.mNumberOfInputs == 0 && aOptions.mNumberOfOutputs == 0) {
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return nullptr;
+  }
+
+  if (aOptions.mOutputChannelCount.WasPassed()) {
+    /**
+     * 1. If any value in outputChannelCount is zero or greater than the
+     *    implementation’s maximum number of channels, throw a
+     *    NotSupportedError and abort the remaining steps.
+     */
+    for (uint32_t channelCount : aOptions.mOutputChannelCount.Value()) {
+      if (channelCount == 0 || channelCount > WebAudioUtils::MaxChannelCount) {
+        aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+        return nullptr;
+      }
+    }
+    /**
+     * 2. If the length of outputChannelCount does not equal numberOfOutputs,
+     *    throw an IndexSizeError and abort the remaining steps.
+     */
+    if (aOptions.mOutputChannelCount.Value().Length() !=
+        aOptions.mNumberOfOutputs) {
+      aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
+      return nullptr;
+    }
+  }
   // MTG does not support more than UINT16_MAX inputs or outputs.
   if (aOptions.mNumberOfInputs > UINT16_MAX) {
     aRv.ThrowRangeError<MSG_VALUE_OUT_OF_RANGE>(
         NS_LITERAL_STRING("numberOfInputs"));
     return nullptr;
   }
   if (aOptions.mNumberOfOutputs > UINT16_MAX) {
     aRv.ThrowRangeError<MSG_VALUE_OUT_OF_RANGE>(
         NS_LITERAL_STRING("numberOfOutputs"));
     return nullptr;
   }
 
-  RefPtr<AudioWorkletNode> audioWorkletNode =
-      new AudioWorkletNode(&aAudioContext, aName, aOptions);
-
-  audioWorkletNode->Initialize(aOptions, aRv);
-  if (NS_WARN_IF(aRv.Failed())) {
-    return nullptr;
-  }
-
   /**
-   * 7. Let optionsSerialization be the result of StructuredSerialize(options).
+   * 8. Convert options dictionary to optionsObject.
    */
   JSContext* cx = aGlobal.Context();
   JS::Rooted<JS::Value> optionsVal(cx);
   if (NS_WARN_IF(!ToJSValue(cx, aOptions, &optionsVal))) {
     aRv.NoteJSContextException(cx);
     return nullptr;
   }
+  /**
+   * 9. Let serializedOptions be the result of
+   *    StructuredSerialize(optionsObject).
+   */
   // StructuredCloneHolder does not have a move constructor.  Instead allocate
   // memory so that the pointer can be passed to the rendering thread.
-  UniquePtr<StructuredCloneHolder> optionsSerialization =
+  UniquePtr<StructuredCloneHolder> serializedOptions =
       MakeUnique<StructuredCloneHolder>(
           StructuredCloneHolder::CloningSupported,
           StructuredCloneHolder::TransferringNotSupported,
           JS::StructuredCloneScope::SameProcessDifferentThread);
-  optionsSerialization->Write(cx, optionsVal, aRv);
+  serializedOptions->Write(cx, optionsVal, aRv);
   if (NS_WARN_IF(aRv.Failed())) {
     return nullptr;
   }
 
   auto engine =
       new WorkletNodeEngine(audioWorkletNode, aOptions.mOutputChannelCount);
   audioWorkletNode->mTrack = AudioNodeTrack::Create(
       &aAudioContext, engine, AudioNodeTrack::NO_TRACK_FLAGS,
       aAudioContext.Graph());
 
   /**
-   * 10. Queue a control message to create an AudioWorkletProcessor, given
-   *     nodeName, processorPortSerialization, optionsSerialization, and node.
+   * 12. Queue a control message to invoke the constructor of the
+   *     corresponding AudioWorkletProcessor with the processor construction
+   *     data that consists of: nodeName, node, serializedOptions, and
+   *     serializedProcessorPort.
    */
   Worklet* worklet = aAudioContext.GetAudioWorklet(aRv);
   MOZ_ASSERT(worklet, "Worklet already existed and so getter shouldn't fail.");
   auto workletImpl = static_cast<AudioWorkletImpl*>(worklet->Impl());
   audioWorkletNode->mTrack->SendRunnable(NS_NewRunnableFunction(
       "WorkletNodeEngine::ConstructProcessor",
       // MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT.
       // See bug 1535398.
       [track = audioWorkletNode->mTrack,
        workletImpl = RefPtr<AudioWorkletImpl>(workletImpl),
-       name = nsString(aName), options = std::move(optionsSerialization)]()
+       name = nsString(aName), options = std::move(serializedOptions)]()
           MOZ_CAN_RUN_SCRIPT_BOUNDARY {
             auto engine = static_cast<WorkletNodeEngine*>(track->Engine());
             engine->ConstructProcessor(workletImpl, name,
                                        WrapNotNull(options.get()));
           }));
 
   return audioWorkletNode.forget();
 }