b=906966 limit ScriptProcessorNode input channel count through channelCount and channelCountMode r=ehsan
authorKarl Tomlinson <karlt+@karlt.net>
Thu, 05 Sep 2013 07:44:37 +1200
changeset 145565 15a71c6cb0d3ab794fee0b4307ef108162e66f05
parent 145564 4d5107aea7080cbc0e7e4ac11e37da2f81caeffe
child 145566 0783c819410df43f5dd5caa6b1db64e3ad31f109
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersehsan
bugs906966
milestone26.0a1
b=906966 limit ScriptProcessorNode input channel count through channelCount and channelCountMode r=ehsan
content/media/webaudio/ScriptProcessorNode.cpp
content/media/webaudio/ScriptProcessorNode.h
content/media/webaudio/test/test_scriptProcessorNodeChannelCount.html
--- a/content/media/webaudio/ScriptProcessorNode.cpp
+++ b/content/media/webaudio/ScriptProcessorNode.cpp
@@ -208,20 +208,21 @@ public:
                             AudioDestinationNode* aDestination,
                             uint32_t aBufferSize,
                             uint32_t aNumberOfInputChannels)
     : AudioNodeEngine(aNode)
     , mSharedBuffers(aNode->GetSharedBuffers())
     , mSource(nullptr)
     , mDestination(static_cast<AudioNodeStream*> (aDestination->Stream()))
     , mBufferSize(aBufferSize)
-    , mDefaultNumberOfInputChannels(aNumberOfInputChannels)
     , mInputWriteIndex(0)
     , mSeenNonSilenceInput(false)
   {
+    mInputChannels.SetLength(aNumberOfInputChannels);
+    AllocateInputBlock();
   }
 
   void SetSourceStream(AudioNodeStream* aSource)
   {
     mSource = aSource;
   }
 
   virtual void ProduceAudioBlock(AudioNodeStream* aStream,
@@ -232,26 +233,25 @@ public:
     MutexAutoLock lock(NodeMutex());
 
     // If our node is dead, just output silence.
     if (!Node()) {
       aOutput->SetNull(WEBAUDIO_BLOCK_SIZE);
       return;
     }
 
-    EnsureInputChannels(aInput.mChannelData.Length());
-
     // First, record our input buffer
     for (uint32_t i = 0; i < mInputChannels.Length(); ++i) {
       if (aInput.IsNull()) {
         PodZero(mInputChannels[i] + mInputWriteIndex,
                 aInput.GetDuration());
       } else {
         mSeenNonSilenceInput = true;
         MOZ_ASSERT(aInput.GetDuration() == WEBAUDIO_BLOCK_SIZE, "sanity check");
+        MOZ_ASSERT(aInput.mChannelData.Length() == mInputChannels.Length());
         AudioBlockCopyChannelWithScale(static_cast<const float*>(aInput.mChannelData[i]),
                                        aInput.mVolume,
                                        mInputChannels[i] + mInputWriteIndex);
       }
     }
     mInputWriteIndex += aInput.GetDuration();
 
     // Now, see if we have data to output
@@ -272,35 +272,16 @@ private:
   {
     for (unsigned i = 0; i < mInputChannels.Length(); ++i) {
       if (!mInputChannels[i]) {
         mInputChannels[i] = new float[mBufferSize];
       }
     }
   }
 
-  void EnsureInputChannels(uint32_t aNumberOfChannels)
-  {
-    if (aNumberOfChannels == 0) {
-      aNumberOfChannels = mDefaultNumberOfInputChannels;
-    }
-    if (mInputChannels.Length() == 0) {
-      mInputChannels.SetLength(aNumberOfChannels);
-      AllocateInputBlock();
-    } else if (aNumberOfChannels < mInputChannels.Length()) {
-      mInputChannels.SetLength(aNumberOfChannels);
-    } else if (aNumberOfChannels > mInputChannels.Length()) {
-      uint32_t oldLength = mInputChannels.Length();
-      mInputChannels.SetLength(aNumberOfChannels);
-      for (uint32_t i = oldLength; i < aNumberOfChannels; ++i) {
-        mInputChannels[i] = new float[mBufferSize];
-      }
-    }
-  }
-
   void SendBuffersToMainThread(AudioNodeStream* aStream)
   {
     MOZ_ASSERT(!NS_IsMainThread());
 
     // we now have a full input buffer ready to be sent to the main thread.
     TrackTicks playbackTick = mSource->GetCurrentPosition();
     // Add the duration of the current sample
     playbackTick += WEBAUDIO_BLOCK_SIZE;
@@ -406,17 +387,16 @@ private:
 
   friend class ScriptProcessorNode;
 
   SharedBuffers* mSharedBuffers;
   AudioNodeStream* mSource;
   AudioNodeStream* mDestination;
   InputChannels mInputChannels;
   const uint32_t mBufferSize;
-  const uint32_t mDefaultNumberOfInputChannels;
   // The write index into the current input buffer
   uint32_t mInputWriteIndex;
   bool mSeenNonSilenceInput;
 };
 
 ScriptProcessorNode::ScriptProcessorNode(AudioContext* aContext,
                                          uint32_t aBufferSize,
                                          uint32_t aNumberOfInputChannels,
--- a/content/media/webaudio/ScriptProcessorNode.h
+++ b/content/media/webaudio/ScriptProcessorNode.h
@@ -54,16 +54,31 @@ public:
   virtual void Disconnect(uint32_t aOutput, ErrorResult& aRv) MOZ_OVERRIDE
   {
     AudioNode::Disconnect(aOutput, aRv);
     if (!aRv.Failed()) {
       mPlayingRef.Drop(this);
     }
   }
 
+  virtual void SetChannelCount(uint32_t aChannelCount, ErrorResult& aRv) MOZ_OVERRIDE
+  {
+    if (aChannelCount != ChannelCount()) {
+      aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    }
+    return;
+  }
+  virtual void SetChannelCountModeValue(ChannelCountMode aMode, ErrorResult& aRv) MOZ_OVERRIDE
+  {
+    if (aMode != ChannelCountMode::Explicit) {
+      aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    }
+    return;
+  }
+
   uint32_t BufferSize() const
   {
     return mBufferSize;
   }
 
   SharedBuffers* GetSharedBuffers() const
   {
     return mSharedBuffers;
--- a/content/media/webaudio/test/test_scriptProcessorNodeChannelCount.html
+++ b/content/media/webaudio/test/test_scriptProcessorNodeChannelCount.html
@@ -27,19 +27,24 @@ addLoadEvent(function() {
 
   var monoBuffer = context.createBuffer(1, 2048, context.sampleRate);
   for (var i = 0; i < 2048; ++i) {
     monoBuffer.getChannelData(0)[i] = 1;
   }
 
   var source = context.createBufferSource();
 
-  var sp = context.createScriptProcessor(2048);
-  sp.channelCount = 3;
+  var sp = context.createScriptProcessor(2048, 3);
+  expectException(function() { sp.channelCount = 2; },
+                  DOMException.NOT_SUPPORTED_ERR);
   sp.channelCountMode = "explicit";
+  expectException(function() { sp.channelCountMode = "max"; },
+                  DOMException.NOT_SUPPORTED_ERR);
+  expectException(function() { sp.channelCountMode = "clamped-max"; },
+                  DOMException.NOT_SUPPORTED_ERR);
   sp.channelInterpretation = "discrete";
   source.start(0);
   source.buffer = buffer;
   source.connect(sp);
   sp.connect(context.destination);
 
   var monoSource = context.createBufferSource();
   monoSource.buffer = monoBuffer;