Bug 868485 - Part 1: Implement the mixToMono behavior for createBuffer; r=roc
authorEhsan Akhgari <ehsan@mozilla.com>
Sun, 05 May 2013 11:15:58 -0400
changeset 130892 3370e2c73ceaa575ba4afe19a70ea09e8ad75002
parent 130891 cdc859533b8d767d143f9f7671b96ba06bd4b1a0
child 130893 f958d3fee49fb9b9d9da8057577b12ada918c678
push id24637
push userphilringnalda@gmail.com
push dateMon, 06 May 2013 00:15:12 +0000
treeherdermozilla-central@b109e2dbf03b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs868485
milestone23.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 868485 - Part 1: Implement the mixToMono behavior for createBuffer; r=roc
content/media/webaudio/AudioBuffer.cpp
content/media/webaudio/AudioBuffer.h
content/media/webaudio/AudioContext.cpp
--- a/content/media/webaudio/AudioBuffer.cpp
+++ b/content/media/webaudio/AudioBuffer.cpp
@@ -8,16 +8,18 @@
 #include "mozilla/dom/AudioBufferBinding.h"
 #include "nsContentUtils.h"
 #include "AudioContext.h"
 #include "jsfriendapi.h"
 #include "mozilla/ErrorResult.h"
 #include "AudioSegment.h"
 #include "nsIScriptError.h"
 #include "nsPIDOMWindow.h"
+#include "AudioChannelFormat.h"
+#include "mozilla/PodOperations.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AudioBuffer)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mJSChannels)
   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
@@ -111,17 +113,17 @@ AudioBuffer::RestoreJSChannelData(JSCont
 
   return true;
 }
 
 void
 AudioBuffer::SetRawChannelContents(JSContext* aJSContext, uint32_t aChannel,
                                    float* aContents)
 {
-  memcpy(JS_GetFloat32ArrayData(mJSChannels[aChannel]), aContents, sizeof(float)*mLength);
+  PodCopy(JS_GetFloat32ArrayData(mJSChannels[aChannel]), aContents, mLength);
 }
 
 JSObject*
 AudioBuffer::GetChannelData(JSContext* aJSContext, uint32_t aChannel,
                             ErrorResult& aRv)
 {
   if (aChannel >= NumberOfChannels()) {
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
@@ -189,10 +191,37 @@ AudioBuffer::GetThreadSharedChannelsForR
     // Steal JS data
     mSharedChannels =
       StealJSArrayDataIntoThreadSharedFloatArrayBufferList(aJSContext, mJSChannels);
   }
 
   return mSharedChannels;
 }
 
+void
+AudioBuffer::MixToMono(JSContext* aJSContext)
+{
+  if (mJSChannels.Length() == 1) {
+    // The buffer is already mono
+    return;
+  }
+
+  // Prepare the input channels
+  nsAutoTArray<const void*, GUESS_AUDIO_CHANNELS> channels;
+  channels.SetLength(mJSChannels.Length());
+  for (uint32_t i = 0; i < mJSChannels.Length(); ++i) {
+    channels[i] = JS_GetFloat32ArrayData(mJSChannels[i]);
+  }
+
+  // Prepare the output channels
+  float* downmixBuffer = new float[mLength];
+
+  // Perform the down-mix
+  AudioChannelsDownMix(channels, &downmixBuffer, 1, mLength);
+
+  // Truncate the shared channels and copy the downmixed data over
+  mJSChannels.SetLength(1);
+  SetRawChannelContents(aJSContext, 0, downmixBuffer);
+  delete[] downmixBuffer;
+}
+
 }
 }
--- a/content/media/webaudio/AudioBuffer.h
+++ b/content/media/webaudio/AudioBuffer.h
@@ -103,16 +103,18 @@ public:
   // This replaces the contents of the JS array for the given channel.
   // This function needs to be called on an AudioBuffer which has not been
   // handed off to the content yet, and right after the object has been
   // initialized.
   void SetRawChannelContents(JSContext* aJSContext,
                              uint32_t aChannel,
                              float* aContents);
 
+  void MixToMono(JSContext* aJSContext);
+
 protected:
   bool RestoreJSChannelData(JSContext* aJSContext);
   void ClearJSChannels();
 
   nsRefPtr<AudioContext> mContext;
   // Float32Arrays
   AutoFallibleTArray<JSObject*,2> mJSChannels;
 
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -109,31 +109,33 @@ AudioContext::CreateBuffer(JSContext* aJ
 
   return buffer.forget();
 }
 
 already_AddRefed<AudioBuffer>
 AudioContext::CreateBuffer(JSContext* aJSContext, ArrayBuffer& aBuffer,
                           bool aMixToMono, ErrorResult& aRv)
 {
-  // TODO: handle aMixToMono
-
   // Sniff the content of the media.
   // Failed type sniffing will be handled by SyncDecodeMedia.
   nsAutoCString contentType;
   NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr,
                   aBuffer.Data(), aBuffer.Length(),
                   contentType);
 
   WebAudioDecodeJob job(contentType, aBuffer, this);
 
   if (mDecoder.SyncDecodeMedia(contentType.get(),
                                job.mBuffer, job.mLength, job) &&
       job.mOutput) {
-    return job.mOutput.forget();
+    nsRefPtr<AudioBuffer> buffer = job.mOutput.forget();
+    if (aMixToMono) {
+      buffer->MixToMono(aJSContext);
+    }
+    return buffer.forget();
   }
 
   return nullptr;
 }
 
 namespace {
 
 bool IsValidBufferSize(uint32_t aBufferSize) {