Bug 1007223 - r=ehsan
authorPaul Adenot <paul@paul.cx>
Tue, 13 May 2014 14:09:44 +0200
changeset 204821 e08a482fcead72cabb1253b23997b52cb3fa8bc2
parent 204820 8dd41701dd923842a97194fe385b58d1252a5752
child 204822 d1b03ddc31613b0090c1815bfaeaa49215254287
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan
bugs1007223
milestone32.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 1007223 - r=ehsan
content/media/webaudio/AudioContext.cpp
content/media/webaudio/MediaBufferDecoder.cpp
content/media/webaudio/MediaBufferDecoder.h
content/media/webaudio/test/test_mediaDecoding.html
--- a/content/media/webaudio/AudioContext.cpp
+++ b/content/media/webaudio/AudioContext.cpp
@@ -425,32 +425,39 @@ AudioContext::Listener()
   return mListener;
 }
 
 void
 AudioContext::DecodeAudioData(const ArrayBuffer& aBuffer,
                               DecodeSuccessCallback& aSuccessCallback,
                               const Optional<OwningNonNull<DecodeErrorCallback> >& aFailureCallback)
 {
+  AutoJSAPI jsapi;
+  JSContext* cx = jsapi.cx();
+  JSAutoCompartment ac(cx, aBuffer.Obj());
+
+  // Neuter the array buffer
+  size_t length = aBuffer.Length();
+  JS::RootedObject obj(cx, aBuffer.Obj());
+
+  uint8_t* data = static_cast<uint8_t*>(JS_StealArrayBufferContents(cx, obj));
+
   // Sniff the content of the media.
   // Failed type sniffing will be handled by AsyncDecodeMedia.
   nsAutoCString contentType;
-  NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr,
-                  aBuffer.Data(), aBuffer.Length(),
-                  contentType);
+  NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr, data, length, contentType);
 
   nsRefPtr<DecodeErrorCallback> failureCallback;
   if (aFailureCallback.WasPassed()) {
     failureCallback = &aFailureCallback.Value();
   }
   nsRefPtr<WebAudioDecodeJob> job(
-    new WebAudioDecodeJob(contentType, this, aBuffer,
+    new WebAudioDecodeJob(contentType, this,
                           &aSuccessCallback, failureCallback));
-  mDecoder.AsyncDecodeMedia(contentType.get(),
-                            aBuffer.Data(), aBuffer.Length(), *job);
+  mDecoder.AsyncDecodeMedia(contentType.get(), data, length, *job);
   // Transfer the ownership to mDecodeJobs
   mDecodeJobs.AppendElement(job);
 }
 
 void
 AudioContext::RemoveFromDecodeQueue(WebAudioDecodeJob* aDecodeJob)
 {
   mDecodeJobs.RemoveElement(aDecodeJob);
--- a/content/media/webaudio/MediaBufferDecoder.cpp
+++ b/content/media/webaudio/MediaBufferDecoder.cpp
@@ -25,31 +25,28 @@ namespace mozilla {
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(WebAudioDecodeJob)
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WebAudioDecodeJob)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutput)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuccessCallback)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mFailureCallback)
-  tmp->mArrayBuffer = nullptr;
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WebAudioDecodeJob)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutput)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuccessCallback)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFailureCallback)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WebAudioDecodeJob)
-  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mArrayBuffer)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebAudioDecodeJob, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebAudioDecodeJob, Release)
 
 using namespace dom;
 
 class ReportResultTask : public nsRunnable
 {
 public:
@@ -138,16 +135,17 @@ private:
 
   void Cleanup()
   {
     MOZ_ASSERT(NS_IsMainThread());
     // MediaDecoderReader expects that BufferDecoder is alive.
     // Destruct MediaDecoderReader first.
     mDecoderReader = nullptr;
     mBufferDecoder = nullptr;
+    JS_free(nullptr, mBuffer);
   }
 
 private:
   nsCString mContentType;
   uint8_t* mBuffer;
   uint32_t mLength;
   WebAudioDecodeJob& mDecodeJob;
   PhaseEnum mPhase;
@@ -477,41 +475,34 @@ MediaBufferDecoder::EnsureThreadPoolInit
       return false;
     }
   }
   return true;
 }
 
 WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType,
                                      AudioContext* aContext,
-                                     const ArrayBuffer& aBuffer,
                                      DecodeSuccessCallback* aSuccessCallback,
                                      DecodeErrorCallback* aFailureCallback)
   : mContentType(aContentType)
   , mWriteIndex(0)
   , mContext(aContext)
   , mSuccessCallback(aSuccessCallback)
   , mFailureCallback(aFailureCallback)
 {
   MOZ_ASSERT(aContext);
   MOZ_ASSERT(aSuccessCallback);
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_COUNT_CTOR(WebAudioDecodeJob);
-
-  mArrayBuffer = aBuffer.Obj();
-
-  mozilla::HoldJSObjects(this);
 }
 
 WebAudioDecodeJob::~WebAudioDecodeJob()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_COUNT_DTOR(WebAudioDecodeJob);
-  mArrayBuffer = nullptr;
-  mozilla::DropJSObjects(this);
 }
 
 void
 WebAudioDecodeJob::OnSuccess(ErrorCode aErrorCode)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aErrorCode == NoError);
 
--- a/content/media/webaudio/MediaBufferDecoder.h
+++ b/content/media/webaudio/MediaBufferDecoder.h
@@ -27,17 +27,16 @@ class DecodeSuccessCallback;
 }
 
 struct WebAudioDecodeJob MOZ_FINAL
 {
   // You may omit both the success and failure callback, or you must pass both.
   // The callbacks are only necessary for asynchronous operation.
   WebAudioDecodeJob(const nsACString& aContentType,
                     dom::AudioContext* aContext,
-                    const dom::ArrayBuffer& aBuffer,
                     dom::DecodeSuccessCallback* aSuccessCallback = nullptr,
                     dom::DecodeErrorCallback* aFailureCallback = nullptr);
   ~WebAudioDecodeJob();
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebAudioDecodeJob)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebAudioDecodeJob)
 
   enum ErrorCode {
@@ -54,17 +53,16 @@ struct WebAudioDecodeJob MOZ_FINAL
   void OnSuccess(ErrorCode /* ignored */);
   void OnFailure(ErrorCode aErrorCode);
 
   bool AllocateBuffer();
 
   size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
-  JS::Heap<JSObject*> mArrayBuffer;
   nsCString mContentType;
   uint32_t mWriteIndex;
   nsRefPtr<dom::AudioContext> mContext;
   nsRefPtr<dom::DecodeSuccessCallback> mSuccessCallback;
   nsRefPtr<dom::DecodeErrorCallback> mFailureCallback; // can be null
   nsRefPtr<dom::AudioBuffer> mOutput;
   FallibleTArray<ChannelBuffer> mChannelBuffers;
 };
--- a/content/media/webaudio/test/test_mediaDecoding.html
+++ b/content/media/webaudio/test/test_mediaDecoding.html
@@ -306,28 +306,31 @@ function runResampling(test, response, c
     checkResampledBuffer(asyncResult, test, callback);
   }, function onFailure() {
     ok(false, "Expected successful decode with resample");
     callback();
   });
 }
 
 function runTest(test, response, callback) {
+  // We need to copy the array here, because decodeAudioData is going to neuter
+  // the array.
+  var compressedAudio = response.slice(0);
   var expectCallback = false;
   var cx = new OfflineAudioContext(test.numberOfChannels || 1,
                                    test.frames || 1, test.sampleRate);
   cx.decodeAudioData(response, function onSuccess(asyncResult) {
     ok(expectCallback, "Success callback should fire asynchronously");
     ok(test.valid, "Did expect success for test " + test.url);
 
     checkAudioBuffer(asyncResult, test);
 
     test.expectedBuffer = asyncResult;
     test.nativeContext = cx;
-    runResampling(test, response, callback);
+    runResampling(test, compressedAudio, callback);
   }, function onFailure() {
     ok(expectCallback, "Failure callback should fire asynchronously");
     ok(!test.valid, "Did expect failure for test " + test.url);
     callback();
   });
   expectCallback = true;
 }