Bug 1097823 - Replace AudioDecodeRendezvous with promise-y goodness. r=cpearce,karlt
☠☠ backed out by 260568d34eb7 ☠ ☠
authorBobby Holley <bobbyholley@gmail.com>
Sun, 07 Dec 2014 11:21:35 -0800
changeset 244456 ab6ddc8ac28af21ef1b791e08024cce47e1e1d2a
parent 244455 b76636e9f49a3a860deb7915f042b92908dc5c85
child 244457 47c97b8b490c42fdc90abeb3b51916220afed457
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce, karlt
bugs1097823
milestone37.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 1097823 - Replace AudioDecodeRendezvous with promise-y goodness. r=cpearce,karlt
dom/media/MediaDecoderReader.cpp
dom/media/MediaDecoderReader.h
dom/media/MediaPromise.h
dom/media/ogg/OggReader.cpp
dom/media/webaudio/AudioContext.cpp
dom/media/webaudio/AudioContext.h
dom/media/webaudio/BufferDecoder.cpp
dom/media/webaudio/BufferDecoder.h
dom/media/webaudio/MediaBufferDecoder.cpp
dom/media/webaudio/MediaBufferDecoder.h
--- a/dom/media/MediaDecoderReader.cpp
+++ b/dom/media/MediaDecoderReader.cpp
@@ -312,70 +312,9 @@ MediaDecoderReader::Shutdown()
   if (mTaskQueue && !mTaskQueueIsBorrowed) {
     // We may be running in the task queue ourselves, so we don't block this
     // thread on task queue draining, since that would deadlock.
     mTaskQueue->BeginShutdown();
   }
   mTaskQueue = nullptr;
 }
 
-AudioDecodeRendezvous::AudioDecodeRendezvous(MediaDecoderReader *aReader)
-  : mReader(aReader)
-  , mMonitor("AudioDecodeRendezvous")
-  , mHaveResult(false)
-{
-}
-
-AudioDecodeRendezvous::~AudioDecodeRendezvous()
-{
-}
-
-void
-AudioDecodeRendezvous::OnAudioDecoded(AudioData* aSample)
-{
-  MonitorAutoLock mon(mMonitor);
-  mSample = aSample;
-  mStatus = NS_OK;
-  mHaveResult = true;
-  mon.NotifyAll();
-}
-
-void
-AudioDecodeRendezvous::OnAudioNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
-{
-  MonitorAutoLock mon(mMonitor);
-  mSample = nullptr;
-  mStatus = aReason == MediaDecoderReader::DECODE_ERROR ? NS_ERROR_FAILURE : NS_OK;
-  mHaveResult = true;
-  mon.NotifyAll();
-}
-
-void
-AudioDecodeRendezvous::Reset()
-{
-  MonitorAutoLock mon(mMonitor);
-  mHaveResult = false;
-  mStatus = NS_OK;
-  mSample = nullptr;
-}
-
-nsresult
-AudioDecodeRendezvous::RequestAndWait(nsRefPtr<AudioData>& aSample)
-{
-  MonitorAutoLock mon(mMonitor);
-  // XXXbholley: We hackily use the main thread for calling back the rendezvous,
-  // since the decode thread is blocked. This is fine for correctness but not
-  // for jank, and so it goes away in a subsequent patch.
-  nsCOMPtr<nsIThread> mainThread;
-  nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
-  NS_ENSURE_SUCCESS(rv, rv);
-  mReader->RequestAudioData()->Then(mainThread.get(), __func__, this,
-                                    &AudioDecodeRendezvous::OnAudioDecoded,
-                                    &AudioDecodeRendezvous::OnAudioNotDecoded);
-  while (!mHaveResult) {
-    mon.Wait();
-  }
-  mHaveResult = false;
-  aSample = mSample;
-  return mStatus;
-}
-
 } // namespace mozilla
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -329,43 +329,11 @@ public:
 
   // Called during shutdown to break any reference cycles.
   virtual void BreakCycles() = 0;
 
 protected:
   virtual ~RequestSampleCallback() {}
 };
 
-// A RequestSampleCallback implementation that can be passed to the
-// MediaDecoderReader to block the thread requesting an audio sample until
-// the audio decode is complete. This is used to adapt the asynchronous
-// model of the MediaDecoderReader to a synchronous model.
-class AudioDecodeRendezvous {
-public:
-  AudioDecodeRendezvous(MediaDecoderReader *aReader);
-
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioDecodeRendezvous)
-
-  void OnAudioDecoded(AudioData* aSample);
-  void OnAudioNotDecoded(MediaDecoderReader::NotDecodedReason aReason);
-  void Reset();
-
-  // Returns failure on error, or NS_OK.
-  // If *aSample is null, EOS has been reached.
-  nsresult RequestAndWait(nsRefPtr<AudioData>& aSample);
-
-  // Interrupts a call to Wait().
-  void Cancel();
-
-protected:
-  ~AudioDecodeRendezvous();
-
-private:
-  nsRefPtr<MediaDecoderReader> mReader;
-  Monitor mMonitor;
-  nsresult mStatus;
-  nsRefPtr<AudioData> mSample;
-  bool mHaveResult;
-};
-
 } // namespace mozilla
 
 #endif
--- a/dom/media/MediaPromise.h
+++ b/dom/media/MediaPromise.h
@@ -20,17 +20,16 @@
 /* Polyfill __func__ on MSVC for consumers to pass to the MediaPromise API. */
 #ifdef _MSC_VER
 #define __func__ __FUNCTION__
 #endif
 
 namespace mozilla {
 
 extern PRLogModuleInfo* gMediaPromiseLog;
-void EnsureMediaPromiseLog();
 
 #define PROMISE_LOG(x, ...) \
   MOZ_ASSERT(gMediaPromiseLog); \
   PR_LOG(gMediaPromiseLog, PR_LOG_DEBUG, (x, ##__VA_ARGS__))
 
 /*
  * A promise manages an asynchronous request that may or may not be able to be
  * fulfilled immediately. When an API returns a promise, the consumer may attach
@@ -228,18 +227,19 @@ private:
     DispatchAll();
   }
 
 protected:
   bool IsPending() { return mResolveValue.isNothing() && mRejectValue.isNothing(); }
   void DispatchAll()
   {
     mMutex.AssertCurrentThreadOwns();
-    for (size_t i = 0; i < mThenValues.Length(); ++i)
+    for (size_t i = 0; i < mThenValues.Length(); ++i) {
       mThenValues[i]->Dispatch(this);
+    }
     mThenValues.Clear();
   }
 
   ~MediaPromise()
   {
     MOZ_COUNT_DTOR(MediaPromise);
     PROMISE_LOG("MediaPromise::~MediaPromise [this=%p]", this);
     MOZ_ASSERT(!IsPending());
--- a/dom/media/ogg/OggReader.cpp
+++ b/dom/media/ogg/OggReader.cpp
@@ -971,17 +971,17 @@ bool OggReader::ReadOggPage(ogg_page* aP
     NS_ENSURE_TRUE(ret == 0, false);
   }
 
   return true;
 }
 
 ogg_packet* OggReader::NextOggPacket(OggCodecState* aCodecState)
 {
-  NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
+  MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");
 
   if (!aCodecState || !aCodecState->mActive) {
     return nullptr;
   }
 
   ogg_packet* packet;
   while ((packet = aCodecState->PacketOut()) == nullptr) {
     // The codec state does not have any buffered pages, so try to read another
--- a/dom/media/webaudio/AudioContext.cpp
+++ b/dom/media/webaudio/AudioContext.cpp
@@ -469,32 +469,32 @@ AudioContext::DecodeAudioData(const Arra
 
   // 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.
+  // Failed type sniffing will be handled by AsyncDecodeWebAudio.
   nsAutoCString contentType;
   NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr, data, length, contentType);
 
   nsRefPtr<DecodeErrorCallback> failureCallback;
   nsRefPtr<DecodeSuccessCallback> successCallback;
   if (aFailureCallback.WasPassed()) {
     failureCallback = &aFailureCallback.Value();
   }
   if (aSuccessCallback.WasPassed()) {
     successCallback = &aSuccessCallback.Value();
   }
   nsRefPtr<WebAudioDecodeJob> job(
     new WebAudioDecodeJob(contentType, this,
                           promise, successCallback, failureCallback));
-  mDecoder.AsyncDecodeMedia(contentType.get(), data, length, *job);
+  AsyncDecodeWebAudio(contentType.get(), data, length, *job);
   // Transfer the ownership to mDecodeJobs
   mDecodeJobs.AppendElement(job.forget());
 
   return promise.forget();
 }
 
 void
 AudioContext::RemoveFromDecodeQueue(WebAudioDecodeJob* aDecodeJob)
@@ -580,18 +580,16 @@ AudioContext::Shutdown()
 
   // We mute rather than suspending, because the delay between the ::Shutdown
   // call and the CC would make us overbuffer in the MediaStreamGraph.
   // See bug 936784 for details.
   if (!mIsOffline) {
     Mute();
   }
 
-  mDecoder.Shutdown();
-
   // Release references to active nodes.
   // Active AudioNodes don't unregister in destructors, at which point the
   // Node is already unregistered.
   mActiveNodes.Clear();
 
   // For offline contexts, we can destroy the MediaStreamGraph at this point.
   if (mIsOffline && mDestination) {
     mDestination->OfflineShutdown();
@@ -696,17 +694,16 @@ AudioContext::SizeOfIncludingThis(mozill
   // AudioNodes are tracked separately because we do not want the AudioContext
   // to track all of the AudioNodes it creates, so we wouldn't be able to
   // traverse them from here.
 
   size_t amount = aMallocSizeOf(this);
   if (mListener) {
     amount += mListener->SizeOfIncludingThis(aMallocSizeOf);
   }
-  amount += mDecoder.SizeOfExcludingThis(aMallocSizeOf);
   amount += mDecodeJobs.SizeOfExcludingThis(aMallocSizeOf);
   for (uint32_t i = 0; i < mDecodeJobs.Length(); ++i) {
     amount += mDecodeJobs[i]->SizeOfIncludingThis(aMallocSizeOf);
   }
   amount += mActiveNodes.SizeOfExcludingThis(nullptr, aMallocSizeOf);
   amount += mPannerNodes.SizeOfExcludingThis(nullptr, aMallocSizeOf);
   return amount;
 }
--- a/dom/media/webaudio/AudioContext.h
+++ b/dom/media/webaudio/AudioContext.h
@@ -266,17 +266,16 @@ private:
   friend struct ::mozilla::WebAudioDecodeJob;
 
 private:
   // Note that it's important for mSampleRate to be initialized before
   // mDestination, as mDestination's constructor needs to access it!
   const float mSampleRate;
   nsRefPtr<AudioDestinationNode> mDestination;
   nsRefPtr<AudioListener> mListener;
-  MediaBufferDecoder mDecoder;
   nsTArray<nsRefPtr<WebAudioDecodeJob> > mDecodeJobs;
   // See RegisterActiveNode.  These will keep the AudioContext alive while it
   // is rendering and the window remains alive.
   nsTHashtable<nsRefPtrHashKey<AudioNode> > mActiveNodes;
   // Hashsets containing all the PannerNodes, to compute the doppler shift.
   // These are weak pointers.
   nsTHashtable<nsPtrHashKey<PannerNode> > mPannerNodes;
   // Number of channels passed in the OfflineAudioContext ctor.
--- a/dom/media/webaudio/BufferDecoder.cpp
+++ b/dom/media/webaudio/BufferDecoder.cpp
@@ -32,20 +32,20 @@ BufferDecoder::BufferDecoder(MediaResour
 
 BufferDecoder::~BufferDecoder()
 {
   // The dtor may run on any thread, we cannot be sure.
   MOZ_COUNT_DTOR(BufferDecoder);
 }
 
 void
-BufferDecoder::BeginDecoding(nsIThread* aDecodeThread)
+BufferDecoder::BeginDecoding(MediaTaskQueue* aTaskQueueIdentity)
 {
-  MOZ_ASSERT(!mDecodeThread && aDecodeThread);
-  mDecodeThread = aDecodeThread;
+  MOZ_ASSERT(!mTaskQueueIdentity && aTaskQueueIdentity);
+  mTaskQueueIdentity = aTaskQueueIdentity;
 }
 
 ReentrantMonitor&
 BufferDecoder::GetReentrantMonitor()
 {
   return mReentrantMonitor;
 }
 
@@ -61,18 +61,18 @@ BufferDecoder::OnStateMachineThread() co
 {
   // BufferDecoder doesn't have the concept of a state machine.
   return true;
 }
 
 bool
 BufferDecoder::OnDecodeThread() const
 {
-  MOZ_ASSERT(mDecodeThread, "Forgot to call BeginDecoding?");
-  return IsCurrentThread(mDecodeThread);
+  MOZ_ASSERT(mTaskQueueIdentity, "Forgot to call BeginDecoding?");
+  return mTaskQueueIdentity->IsCurrentThreadIn();
 }
 
 MediaResource*
 BufferDecoder::GetResource() const
 {
   return mResource;
 }
 
--- a/dom/media/webaudio/BufferDecoder.h
+++ b/dom/media/webaudio/BufferDecoder.h
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef BUFFER_DECODER_H_
 #define BUFFER_DECODER_H_
 
 #include "AbstractMediaDecoder.h"
+#include "MediaTaskQueue.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ReentrantMonitor.h"
 
 namespace mozilla {
 
 /**
  * This class provides a decoder object which decodes a media file that lives in
  * a memory buffer.
@@ -22,17 +23,17 @@ class BufferDecoder : public AbstractMed
 public:
   // This class holds a weak pointer to MediaResource.  It's the responsibility
   // of the caller to manage the memory of the MediaResource object.
   explicit BufferDecoder(MediaResource* aResource);
 
   NS_DECL_THREADSAFE_ISUPPORTS
 
   // This has to be called before decoding begins
-  void BeginDecoding(nsIThread* aDecodeThread);
+  void BeginDecoding(MediaTaskQueue* aTaskQueueIdentity);
 
   virtual ReentrantMonitor& GetReentrantMonitor() MOZ_FINAL MOZ_OVERRIDE;
 
   virtual bool IsShutdown() const MOZ_FINAL MOZ_OVERRIDE;
 
   virtual bool OnStateMachineThread() const MOZ_FINAL MOZ_OVERRIDE;
 
   virtual bool OnDecodeThread() const MOZ_FINAL MOZ_OVERRIDE;
@@ -78,15 +79,15 @@ public:
 
 private:
   virtual ~BufferDecoder();
 
   // This monitor object is not really used to synchronize access to anything.
   // It's just there in order for us to be able to override
   // GetReentrantMonitor correctly.
   ReentrantMonitor mReentrantMonitor;
-  nsCOMPtr<nsIThread> mDecodeThread;
+  nsRefPtr<MediaTaskQueue> mTaskQueueIdentity;
   nsRefPtr<MediaResource> mResource;
 };
 
 } // namespace mozilla
 
 #endif /* BUFFER_DECODER_H_ */
--- a/dom/media/webaudio/MediaBufferDecoder.cpp
+++ b/dom/media/webaudio/MediaBufferDecoder.cpp
@@ -15,21 +15,19 @@
 #include "BufferMediaResource.h"
 #include "DecoderTraits.h"
 #include "AudioContext.h"
 #include "AudioBuffer.h"
 #include "nsAutoPtr.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptError.h"
 #include "nsMimeTypes.h"
+#include "VideoUtils.h"
 #include "WebAudioUtils.h"
 #include "mozilla/dom/Promise.h"
-#ifdef XP_WIN
-#include "ThreadPoolCOMListener.h"
-#endif
 
 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)
@@ -90,38 +88,37 @@ MOZ_BEGIN_ENUM_CLASS(PhaseEnum, int)
   Done
 MOZ_END_ENUM_CLASS(PhaseEnum)
 
 class MediaDecodeTask : public nsRunnable
 {
 public:
   MediaDecodeTask(const char* aContentType, uint8_t* aBuffer,
                   uint32_t aLength,
-                  WebAudioDecodeJob& aDecodeJob,
-                  nsIThreadPool* aThreadPool)
+                  WebAudioDecodeJob& aDecodeJob)
     : mContentType(aContentType)
     , mBuffer(aBuffer)
     , mLength(aLength)
     , mDecodeJob(aDecodeJob)
     , mPhase(PhaseEnum::Decode)
-    , mThreadPool(aThreadPool)
   {
     MOZ_ASSERT(aBuffer);
     MOZ_ASSERT(NS_IsMainThread());
 
     nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(mDecodeJob.mContext->GetParentObject());
     nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
       do_QueryInterface(pWindow);
     if (scriptPrincipal) {
       mPrincipal = scriptPrincipal->GetPrincipal();
     }
   }
 
   NS_IMETHOD Run();
   bool CreateReader();
+  MediaDecoderReader* Reader() { MOZ_ASSERT(mDecoderReader); return mDecoderReader; }
 
 private:
   void ReportFailureOnMainThread(WebAudioDecodeJob::ErrorCode aErrorCode) {
     if (NS_IsMainThread()) {
       Cleanup();
       mDecodeJob.OnFailure(aErrorCode);
     } else {
       // Take extra care to cleanup on the main thread
@@ -129,16 +126,20 @@ private:
 
       nsCOMPtr<nsIRunnable> event =
         new ReportResultTask(mDecodeJob, &WebAudioDecodeJob::OnFailure, aErrorCode);
       NS_DispatchToMainThread(event);
     }
   }
 
   void Decode();
+  void RequestSample();
+  void SampleDecoded(AudioData* aData);
+  void SampleNotDecoded(MediaDecoderReader::NotDecodedReason aReason);
+  void FinishDecode();
   void AllocateBuffer();
   void CallbackTheResult();
 
   void Cleanup()
   {
     MOZ_ASSERT(NS_IsMainThread());
     // MediaDecoderReader expects that BufferDecoder is alive.
     // Destruct MediaDecoderReader first.
@@ -149,20 +150,21 @@ private:
   }
 
 private:
   nsCString mContentType;
   uint8_t* mBuffer;
   uint32_t mLength;
   WebAudioDecodeJob& mDecodeJob;
   PhaseEnum mPhase;
-  nsCOMPtr<nsIThreadPool> mThreadPool;
   nsCOMPtr<nsIPrincipal> mPrincipal;
   nsRefPtr<BufferDecoder> mBufferDecoder;
   nsRefPtr<MediaDecoderReader> mDecoderReader;
+  MediaInfo mMediaInfo;
+  MediaQueue<AudioData> mAudioQueue;
 };
 
 NS_IMETHODIMP
 MediaDecodeTask::Run()
 {
   MOZ_ASSERT(mBufferDecoder);
   MOZ_ASSERT(mDecoderReader);
   switch (mPhase) {
@@ -200,16 +202,20 @@ MediaDecodeTask::CreateReader()
     return false;
   }
 
   nsresult rv = mDecoderReader->Init(nullptr);
   if (NS_FAILED(rv)) {
     return false;
   }
 
+  if (!mDecoderReader->EnsureTaskQueue()) {
+    return false;
+  }
+
   return true;
 }
 
 class AutoResampler {
 public:
   AutoResampler()
     : mResampler(nullptr)
   {}
@@ -233,58 +239,77 @@ private:
   SpeexResamplerState* mResampler;
 };
 
 void
 MediaDecodeTask::Decode()
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
-  mBufferDecoder->BeginDecoding(NS_GetCurrentThread());
+  mBufferDecoder->BeginDecoding(mDecoderReader->GetTaskQueue());
 
   // Tell the decoder reader that we are not going to play the data directly,
   // and that we should not reject files with more channels than the audio
   // bakend support.
   mDecoderReader->SetIgnoreAudioOutputFormat();
 
-  MediaInfo mediaInfo;
   nsAutoPtr<MetadataTags> tags;
-  nsresult rv = mDecoderReader->ReadMetadata(&mediaInfo, getter_Transfers(tags));
+  nsresult rv = mDecoderReader->ReadMetadata(&mMediaInfo, getter_Transfers(tags));
   if (NS_FAILED(rv)) {
     mDecoderReader->Shutdown();
     ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
     return;
   }
 
   if (!mDecoderReader->HasAudio()) {
     mDecoderReader->Shutdown();
     ReportFailureOnMainThread(WebAudioDecodeJob::NoAudio);
     return;
   }
 
-  MediaQueue<AudioData> audioQueue;
-  nsRefPtr<AudioDecodeRendezvous> barrier(new AudioDecodeRendezvous(mDecoderReader));
-  while (1) {
-    nsRefPtr<AudioData> audio;
-    if (NS_FAILED(barrier->RequestAndWait(audio))) {
-      mDecoderReader->Shutdown();
-      ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
-      return;
-    }
-    if (!audio) {
-      // End of stream.
-      break;
-    }
-    audioQueue.Push(audio);
+  RequestSample();
+}
+
+void
+MediaDecodeTask::RequestSample()
+{
+  mDecoderReader->RequestAudioData()->Then(mDecoderReader->GetTaskQueue(), __func__, this,
+                                           &MediaDecodeTask::SampleDecoded,
+                                           &MediaDecodeTask::SampleNotDecoded);
+}
+
+void
+MediaDecodeTask::SampleDecoded(AudioData* aData)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  mAudioQueue.Push(aData);
+  RequestSample();
+}
+
+void
+MediaDecodeTask::SampleNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
+{
+  MOZ_ASSERT(!NS_IsMainThread());
+  if (aReason == MediaDecoderReader::DECODE_ERROR) {
+    mDecoderReader->Shutdown();
+    ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
+  } else {
+    MOZ_ASSERT(aReason == MediaDecoderReader::END_OF_STREAM);
+    FinishDecode();
   }
+}
+
+void
+MediaDecodeTask::FinishDecode()
+{
   mDecoderReader->Shutdown();
 
-  uint32_t frameCount = audioQueue.FrameCount();
-  uint32_t channelCount = mediaInfo.mAudio.mChannels;
-  uint32_t sampleRate = mediaInfo.mAudio.mRate;
+  uint32_t frameCount = mAudioQueue.FrameCount();
+  uint32_t channelCount = mMediaInfo.mAudio.mChannels;
+  uint32_t sampleRate = mMediaInfo.mAudio.mRate;
 
   if (!frameCount || !channelCount || !sampleRate) {
     ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
     return;
   }
 
   const uint32_t destSampleRate = mDecodeJob.mContext->SampleRate();
   AutoResampler resampler;
@@ -322,17 +347,17 @@ MediaDecodeTask::Decode()
     }
   }
   if (!memoryAllocationSuccess) {
     ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
     return;
   }
 
   nsRefPtr<AudioData> audioData;
-  while ((audioData = audioQueue.PopFront())) {
+  while ((audioData = mAudioQueue.PopFront())) {
     audioData->EnsureAudioBuffer(); // could lead to a copy :(
     AudioDataValue* bufferData = static_cast<AudioDataValue*>
       (audioData->mAudioBuffer->Data());
 
     if (sampleRate != destSampleRate) {
       const uint32_t maxOutSamples = resampledFrames - mDecodeJob.mWriteIndex;
 
       for (uint32_t i = 0; i < audioData->mChannels; ++i) {
@@ -435,85 +460,42 @@ WebAudioDecodeJob::AllocateBuffer()
   for (uint32_t i = 0; i < mChannelBuffers.Length(); ++i) {
     mOutput->SetRawChannelContents(i, mChannelBuffers[i]);
   }
 
   return true;
 }
 
 void
-MediaBufferDecoder::AsyncDecodeMedia(const char* aContentType, uint8_t* aBuffer,
-                                     uint32_t aLength,
-                                     WebAudioDecodeJob& aDecodeJob)
+AsyncDecodeWebAudio(const char* aContentType, uint8_t* aBuffer,
+                    uint32_t aLength, WebAudioDecodeJob& aDecodeJob)
 {
   // Do not attempt to decode the media if we were not successful at sniffing
   // the content type.
   if (!*aContentType ||
       strcmp(aContentType, APPLICATION_OCTET_STREAM) == 0) {
     nsCOMPtr<nsIRunnable> event =
       new ReportResultTask(aDecodeJob,
                            &WebAudioDecodeJob::OnFailure,
                            WebAudioDecodeJob::UnknownContent);
     JS_free(nullptr, aBuffer);
     NS_DispatchToMainThread(event);
     return;
   }
 
-  if (!EnsureThreadPoolInitialized()) {
-    nsCOMPtr<nsIRunnable> event =
-      new ReportResultTask(aDecodeJob,
-                           &WebAudioDecodeJob::OnFailure,
-                           WebAudioDecodeJob::UnknownError);
-    JS_free(nullptr, aBuffer);
-    NS_DispatchToMainThread(event);
-    return;
-  }
-
-  MOZ_ASSERT(mThreadPool);
-
-  nsRefPtr<MediaDecodeTask> task =
-    new MediaDecodeTask(aContentType, aBuffer, aLength, aDecodeJob, mThreadPool);
+  RefPtr<MediaDecodeTask> task =
+    new MediaDecodeTask(aContentType, aBuffer, aLength, aDecodeJob);
   if (!task->CreateReader()) {
     nsCOMPtr<nsIRunnable> event =
       new ReportResultTask(aDecodeJob,
                            &WebAudioDecodeJob::OnFailure,
                            WebAudioDecodeJob::UnknownError);
     NS_DispatchToMainThread(event);
   } else {
-    mThreadPool->Dispatch(task, nsIThreadPool::DISPATCH_NORMAL);
-  }
-}
-
-bool
-MediaBufferDecoder::EnsureThreadPoolInitialized()
-{
-  if (!mThreadPool) {
-    mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
-    if (!mThreadPool) {
-      return false;
-    }
-    mThreadPool->SetName(NS_LITERAL_CSTRING("MediaBufferDecoder"));
-#ifdef XP_WIN
-  // Ensure MSCOM is initialized on the thread pools threads.
-  nsCOMPtr<nsIThreadPoolListener> listener = new MSCOMInitThreadPoolListener();
-  nsresult rv = mThreadPool->SetListener(listener);
-  NS_ENSURE_SUCCESS(rv, nullptr);
-#endif
-  }
-  return true;
-}
-
-void
-MediaBufferDecoder::Shutdown() {
-  if (mThreadPool) {
-    // Setting threadLimit to 0 causes threads to exit when all events have
-    // been run, like nsIThreadPool::Shutdown(), but doesn't run a nested event
-    // loop nor wait until this has happened.
-    mThreadPool->SetThreadLimit(0);
-    mThreadPool = nullptr;
+    task->Reader()->GetTaskQueue()->Dispatch(task);
   }
 }
 
 WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType,
                                      AudioContext* aContext,
                                      Promise* aPromise,
                                      DecodeSuccessCallback* aSuccessCallback,
                                      DecodeErrorCallback* aFailureCallback)
--- a/dom/media/webaudio/MediaBufferDecoder.h
+++ b/dom/media/webaudio/MediaBufferDecoder.h
@@ -4,17 +4,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef MediaBufferDecoder_h_
 #define MediaBufferDecoder_h_
 
 #include "nsWrapperCache.h"
 #include "nsCOMPtr.h"
-#include "nsIThreadPool.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "mozilla/dom/TypedArray.h"
 #include "mozilla/MemoryReporting.h"
 
 namespace mozilla {
 
 namespace dom {
@@ -65,39 +64,15 @@ struct WebAudioDecodeJob MOZ_FINAL
   nsRefPtr<dom::DecodeErrorCallback> mFailureCallback; // can be null
   nsRefPtr<dom::AudioBuffer> mOutput;
   FallibleTArray<ChannelBuffer> mChannelBuffers;
 
 private:
   ~WebAudioDecodeJob();
 };
 
-/**
- * This class is used to decode media buffers on a dedicated threadpool.
- *
- * This class manages the resources that it uses internally (such as the
- * thread-pool) and provides a clean external interface.
- */
-class MediaBufferDecoder
-{
-public:
-  void AsyncDecodeMedia(const char* aContentType, uint8_t* aBuffer,
-                        uint32_t aLength, WebAudioDecodeJob& aDecodeJob);
-
-  ~MediaBufferDecoder() { Shutdown(); }
-  void Shutdown();
-
-  size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
-  {
-    return 0;
-  }
-
-private:
-  bool EnsureThreadPoolInitialized();
-
-private:
-  nsCOMPtr<nsIThreadPool> mThreadPool;
-};
+void AsyncDecodeWebAudio(const char* aContentType, uint8_t* aBuffer,
+                         uint32_t aLength, WebAudioDecodeJob& aDecodeJob);
 
 }
 
 #endif