content/media/webaudio/MediaBufferDecoder.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/media/webaudio/MediaBufferDecoder.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,592 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "MediaBufferDecoder.h"
    1.11 +#include "BufferDecoder.h"
    1.12 +#include "mozilla/dom/AudioContextBinding.h"
    1.13 +#include <speex/speex_resampler.h>
    1.14 +#include "nsXPCOMCIDInternal.h"
    1.15 +#include "nsComponentManagerUtils.h"
    1.16 +#include "MediaDecoderReader.h"
    1.17 +#include "BufferMediaResource.h"
    1.18 +#include "DecoderTraits.h"
    1.19 +#include "AudioContext.h"
    1.20 +#include "AudioBuffer.h"
    1.21 +#include "nsIScriptObjectPrincipal.h"
    1.22 +#include "nsIScriptError.h"
    1.23 +#include "nsMimeTypes.h"
    1.24 +#include "nsCxPusher.h"
    1.25 +#include "WebAudioUtils.h"
    1.26 +
    1.27 +namespace mozilla {
    1.28 +
    1.29 +NS_IMPL_CYCLE_COLLECTION_CLASS(WebAudioDecodeJob)
    1.30 +
    1.31 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WebAudioDecodeJob)
    1.32 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
    1.33 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutput)
    1.34 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuccessCallback)
    1.35 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mFailureCallback)
    1.36 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    1.37 +
    1.38 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WebAudioDecodeJob)
    1.39 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
    1.40 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutput)
    1.41 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuccessCallback)
    1.42 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFailureCallback)
    1.43 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
    1.44 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    1.45 +
    1.46 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WebAudioDecodeJob)
    1.47 +NS_IMPL_CYCLE_COLLECTION_TRACE_END
    1.48 +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebAudioDecodeJob, AddRef)
    1.49 +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebAudioDecodeJob, Release)
    1.50 +
    1.51 +using namespace dom;
    1.52 +
    1.53 +class ReportResultTask : public nsRunnable
    1.54 +{
    1.55 +public:
    1.56 +  ReportResultTask(WebAudioDecodeJob& aDecodeJob,
    1.57 +                   WebAudioDecodeJob::ResultFn aFunction,
    1.58 +                   WebAudioDecodeJob::ErrorCode aErrorCode)
    1.59 +    : mDecodeJob(aDecodeJob)
    1.60 +    , mFunction(aFunction)
    1.61 +    , mErrorCode(aErrorCode)
    1.62 +  {
    1.63 +    MOZ_ASSERT(aFunction);
    1.64 +  }
    1.65 +
    1.66 +  NS_IMETHOD Run()
    1.67 +  {
    1.68 +    MOZ_ASSERT(NS_IsMainThread());
    1.69 +
    1.70 +    (mDecodeJob.*mFunction)(mErrorCode);
    1.71 +
    1.72 +    return NS_OK;
    1.73 +  }
    1.74 +
    1.75 +private:
    1.76 +  // Note that the mDecodeJob member will probably die when mFunction is run.
    1.77 +  // Therefore, it is not safe to do anything fancy with it in this class.
    1.78 +  // Really, this class is only used because nsRunnableMethod doesn't support
    1.79 +  // methods accepting arguments.
    1.80 +  WebAudioDecodeJob& mDecodeJob;
    1.81 +  WebAudioDecodeJob::ResultFn mFunction;
    1.82 +  WebAudioDecodeJob::ErrorCode mErrorCode;
    1.83 +};
    1.84 +
    1.85 +MOZ_BEGIN_ENUM_CLASS(PhaseEnum, int)
    1.86 +  Decode,
    1.87 +  AllocateBuffer,
    1.88 +  Done
    1.89 +MOZ_END_ENUM_CLASS(PhaseEnum)
    1.90 +
    1.91 +class MediaDecodeTask : public nsRunnable
    1.92 +{
    1.93 +public:
    1.94 +  MediaDecodeTask(const char* aContentType, uint8_t* aBuffer,
    1.95 +                  uint32_t aLength,
    1.96 +                  WebAudioDecodeJob& aDecodeJob,
    1.97 +                  nsIThreadPool* aThreadPool)
    1.98 +    : mContentType(aContentType)
    1.99 +    , mBuffer(aBuffer)
   1.100 +    , mLength(aLength)
   1.101 +    , mDecodeJob(aDecodeJob)
   1.102 +    , mPhase(PhaseEnum::Decode)
   1.103 +    , mThreadPool(aThreadPool)
   1.104 +  {
   1.105 +    MOZ_ASSERT(aBuffer);
   1.106 +    MOZ_ASSERT(NS_IsMainThread());
   1.107 +
   1.108 +    nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(mDecodeJob.mContext->GetParentObject());
   1.109 +    nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
   1.110 +      do_QueryInterface(pWindow);
   1.111 +    if (scriptPrincipal) {
   1.112 +      mPrincipal = scriptPrincipal->GetPrincipal();
   1.113 +    }
   1.114 +  }
   1.115 +
   1.116 +  NS_IMETHOD Run();
   1.117 +  bool CreateReader();
   1.118 +
   1.119 +private:
   1.120 +  void ReportFailureOnMainThread(WebAudioDecodeJob::ErrorCode aErrorCode) {
   1.121 +    if (NS_IsMainThread()) {
   1.122 +      Cleanup();
   1.123 +      mDecodeJob.OnFailure(aErrorCode);
   1.124 +    } else {
   1.125 +      // Take extra care to cleanup on the main thread
   1.126 +      NS_DispatchToMainThread(NS_NewRunnableMethod(this, &MediaDecodeTask::Cleanup),
   1.127 +                              NS_DISPATCH_NORMAL);
   1.128 +
   1.129 +      nsCOMPtr<nsIRunnable> event =
   1.130 +        new ReportResultTask(mDecodeJob, &WebAudioDecodeJob::OnFailure, aErrorCode);
   1.131 +      NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
   1.132 +    }
   1.133 +  }
   1.134 +
   1.135 +  void Decode();
   1.136 +  void AllocateBuffer();
   1.137 +  void CallbackTheResult();
   1.138 +
   1.139 +  void Cleanup()
   1.140 +  {
   1.141 +    MOZ_ASSERT(NS_IsMainThread());
   1.142 +    // MediaDecoderReader expects that BufferDecoder is alive.
   1.143 +    // Destruct MediaDecoderReader first.
   1.144 +    mDecoderReader = nullptr;
   1.145 +    mBufferDecoder = nullptr;
   1.146 +    JS_free(nullptr, mBuffer);
   1.147 +  }
   1.148 +
   1.149 +private:
   1.150 +  nsCString mContentType;
   1.151 +  uint8_t* mBuffer;
   1.152 +  uint32_t mLength;
   1.153 +  WebAudioDecodeJob& mDecodeJob;
   1.154 +  PhaseEnum mPhase;
   1.155 +  nsCOMPtr<nsIThreadPool> mThreadPool;
   1.156 +  nsCOMPtr<nsIPrincipal> mPrincipal;
   1.157 +  nsRefPtr<BufferDecoder> mBufferDecoder;
   1.158 +  nsAutoPtr<MediaDecoderReader> mDecoderReader;
   1.159 +};
   1.160 +
   1.161 +NS_IMETHODIMP
   1.162 +MediaDecodeTask::Run()
   1.163 +{
   1.164 +  MOZ_ASSERT(mBufferDecoder);
   1.165 +  MOZ_ASSERT(mDecoderReader);
   1.166 +  switch (mPhase) {
   1.167 +  case PhaseEnum::Decode:
   1.168 +    Decode();
   1.169 +    break;
   1.170 +  case PhaseEnum::AllocateBuffer:
   1.171 +    AllocateBuffer();
   1.172 +    break;
   1.173 +  case PhaseEnum::Done:
   1.174 +    break;
   1.175 +  }
   1.176 +
   1.177 +  return NS_OK;
   1.178 +}
   1.179 +
   1.180 +bool
   1.181 +MediaDecodeTask::CreateReader()
   1.182 +{
   1.183 +  MOZ_ASSERT(NS_IsMainThread());
   1.184 +
   1.185 +  nsRefPtr<BufferMediaResource> resource =
   1.186 +    new BufferMediaResource(static_cast<uint8_t*> (mBuffer),
   1.187 +                            mLength, mPrincipal, mContentType);
   1.188 +
   1.189 +  MOZ_ASSERT(!mBufferDecoder);
   1.190 +  mBufferDecoder = new BufferDecoder(resource);
   1.191 +
   1.192 +  // If you change this list to add support for new decoders, please consider
   1.193 +  // updating HTMLMediaElement::CreateDecoder as well.
   1.194 +
   1.195 +  mDecoderReader = DecoderTraits::CreateReader(mContentType, mBufferDecoder);
   1.196 +
   1.197 +  if (!mDecoderReader) {
   1.198 +    return false;
   1.199 +  }
   1.200 +
   1.201 +  nsresult rv = mDecoderReader->Init(nullptr);
   1.202 +  if (NS_FAILED(rv)) {
   1.203 +    return false;
   1.204 +  }
   1.205 +
   1.206 +  return true;
   1.207 +}
   1.208 +
   1.209 +class AutoResampler {
   1.210 +public:
   1.211 +  AutoResampler()
   1.212 +    : mResampler(nullptr)
   1.213 +  {}
   1.214 +  ~AutoResampler()
   1.215 +  {
   1.216 +    if (mResampler) {
   1.217 +      speex_resampler_destroy(mResampler);
   1.218 +    }
   1.219 +  }
   1.220 +  operator SpeexResamplerState*() const
   1.221 +  {
   1.222 +    MOZ_ASSERT(mResampler);
   1.223 +    return mResampler;
   1.224 +  }
   1.225 +  void operator=(SpeexResamplerState* aResampler)
   1.226 +  {
   1.227 +    mResampler = aResampler;
   1.228 +  }
   1.229 +
   1.230 +private:
   1.231 +  SpeexResamplerState* mResampler;
   1.232 +};
   1.233 +
   1.234 +void
   1.235 +MediaDecodeTask::Decode()
   1.236 +{
   1.237 +  MOZ_ASSERT(!NS_IsMainThread());
   1.238 +
   1.239 +  mBufferDecoder->BeginDecoding(NS_GetCurrentThread());
   1.240 +
   1.241 +  // Tell the decoder reader that we are not going to play the data directly,
   1.242 +  // and that we should not reject files with more channels than the audio
   1.243 +  // bakend support.
   1.244 +  mDecoderReader->SetIgnoreAudioOutputFormat();
   1.245 +
   1.246 +  MediaInfo mediaInfo;
   1.247 +  nsAutoPtr<MetadataTags> tags;
   1.248 +  nsresult rv = mDecoderReader->ReadMetadata(&mediaInfo, getter_Transfers(tags));
   1.249 +  if (NS_FAILED(rv)) {
   1.250 +    ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
   1.251 +    return;
   1.252 +  }
   1.253 +
   1.254 +  if (!mDecoderReader->HasAudio()) {
   1.255 +    ReportFailureOnMainThread(WebAudioDecodeJob::NoAudio);
   1.256 +    return;
   1.257 +  }
   1.258 +
   1.259 +  while (mDecoderReader->DecodeAudioData()) {
   1.260 +    // consume all of the buffer
   1.261 +    continue;
   1.262 +  }
   1.263 +
   1.264 +  MediaQueue<AudioData>& audioQueue = mDecoderReader->AudioQueue();
   1.265 +  uint32_t frameCount = audioQueue.FrameCount();
   1.266 +  uint32_t channelCount = mediaInfo.mAudio.mChannels;
   1.267 +  uint32_t sampleRate = mediaInfo.mAudio.mRate;
   1.268 +
   1.269 +  if (!frameCount || !channelCount || !sampleRate) {
   1.270 +    ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
   1.271 +    return;
   1.272 +  }
   1.273 +
   1.274 +  const uint32_t destSampleRate = mDecodeJob.mContext->SampleRate();
   1.275 +  AutoResampler resampler;
   1.276 +
   1.277 +  uint32_t resampledFrames = frameCount;
   1.278 +  if (sampleRate != destSampleRate) {
   1.279 +    resampledFrames = static_cast<uint32_t>(
   1.280 +        static_cast<uint64_t>(destSampleRate) *
   1.281 +        static_cast<uint64_t>(frameCount) /
   1.282 +        static_cast<uint64_t>(sampleRate)
   1.283 +      );
   1.284 +
   1.285 +    resampler = speex_resampler_init(channelCount,
   1.286 +                                     sampleRate,
   1.287 +                                     destSampleRate,
   1.288 +                                     SPEEX_RESAMPLER_QUALITY_DEFAULT, nullptr);
   1.289 +    speex_resampler_skip_zeros(resampler);
   1.290 +    resampledFrames += speex_resampler_get_output_latency(resampler);
   1.291 +  }
   1.292 +
   1.293 +  // Allocate the channel buffers.  Note that if we end up resampling, we may
   1.294 +  // write fewer bytes than mResampledFrames to the output buffer, in which
   1.295 +  // case mWriteIndex will tell us how many valid samples we have.
   1.296 +  static const fallible_t fallible = fallible_t();
   1.297 +  bool memoryAllocationSuccess = true;
   1.298 +  if (!mDecodeJob.mChannelBuffers.SetLength(channelCount)) {
   1.299 +    memoryAllocationSuccess = false;
   1.300 +  } else {
   1.301 +    for (uint32_t i = 0; i < channelCount; ++i) {
   1.302 +      mDecodeJob.mChannelBuffers[i] = new(fallible) float[resampledFrames];
   1.303 +      if (!mDecodeJob.mChannelBuffers[i]) {
   1.304 +        memoryAllocationSuccess = false;
   1.305 +        break;
   1.306 +      }
   1.307 +    }
   1.308 +  }
   1.309 +  if (!memoryAllocationSuccess) {
   1.310 +    ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
   1.311 +    return;
   1.312 +  }
   1.313 +
   1.314 +  nsAutoPtr<AudioData> audioData;
   1.315 +  while ((audioData = audioQueue.PopFront())) {
   1.316 +    audioData->EnsureAudioBuffer(); // could lead to a copy :(
   1.317 +    AudioDataValue* bufferData = static_cast<AudioDataValue*>
   1.318 +      (audioData->mAudioBuffer->Data());
   1.319 +
   1.320 +    if (sampleRate != destSampleRate) {
   1.321 +      const uint32_t maxOutSamples = resampledFrames - mDecodeJob.mWriteIndex;
   1.322 +
   1.323 +      for (uint32_t i = 0; i < audioData->mChannels; ++i) {
   1.324 +        uint32_t inSamples = audioData->mFrames;
   1.325 +        uint32_t outSamples = maxOutSamples;
   1.326 +
   1.327 +        WebAudioUtils::SpeexResamplerProcess(
   1.328 +            resampler, i, &bufferData[i * audioData->mFrames], &inSamples,
   1.329 +            mDecodeJob.mChannelBuffers[i] + mDecodeJob.mWriteIndex,
   1.330 +            &outSamples);
   1.331 +
   1.332 +        if (i == audioData->mChannels - 1) {
   1.333 +          mDecodeJob.mWriteIndex += outSamples;
   1.334 +          MOZ_ASSERT(mDecodeJob.mWriteIndex <= resampledFrames);
   1.335 +          MOZ_ASSERT(inSamples == audioData->mFrames);
   1.336 +        }
   1.337 +      }
   1.338 +    } else {
   1.339 +      for (uint32_t i = 0; i < audioData->mChannels; ++i) {
   1.340 +        ConvertAudioSamples(&bufferData[i * audioData->mFrames],
   1.341 +                            mDecodeJob.mChannelBuffers[i] + mDecodeJob.mWriteIndex,
   1.342 +                            audioData->mFrames);
   1.343 +
   1.344 +        if (i == audioData->mChannels - 1) {
   1.345 +          mDecodeJob.mWriteIndex += audioData->mFrames;
   1.346 +        }
   1.347 +      }
   1.348 +    }
   1.349 +  }
   1.350 +
   1.351 +  if (sampleRate != destSampleRate) {
   1.352 +    uint32_t inputLatency = speex_resampler_get_input_latency(resampler);
   1.353 +    const uint32_t maxOutSamples = resampledFrames - mDecodeJob.mWriteIndex;
   1.354 +    for (uint32_t i = 0; i < channelCount; ++i) {
   1.355 +      uint32_t inSamples = inputLatency;
   1.356 +      uint32_t outSamples = maxOutSamples;
   1.357 +
   1.358 +      WebAudioUtils::SpeexResamplerProcess(
   1.359 +          resampler, i, (AudioDataValue*)nullptr, &inSamples,
   1.360 +          mDecodeJob.mChannelBuffers[i] + mDecodeJob.mWriteIndex,
   1.361 +          &outSamples);
   1.362 +
   1.363 +      if (i == channelCount - 1) {
   1.364 +        mDecodeJob.mWriteIndex += outSamples;
   1.365 +        MOZ_ASSERT(mDecodeJob.mWriteIndex <= resampledFrames);
   1.366 +        MOZ_ASSERT(inSamples == inputLatency);
   1.367 +      }
   1.368 +    }
   1.369 +  }
   1.370 +
   1.371 +  mPhase = PhaseEnum::AllocateBuffer;
   1.372 +  NS_DispatchToMainThread(this);
   1.373 +}
   1.374 +
   1.375 +void
   1.376 +MediaDecodeTask::AllocateBuffer()
   1.377 +{
   1.378 +  MOZ_ASSERT(NS_IsMainThread());
   1.379 +
   1.380 +  if (!mDecodeJob.AllocateBuffer()) {
   1.381 +    ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
   1.382 +    return;
   1.383 +  }
   1.384 +
   1.385 +  mPhase = PhaseEnum::Done;
   1.386 +  CallbackTheResult();
   1.387 +}
   1.388 +
   1.389 +void
   1.390 +MediaDecodeTask::CallbackTheResult()
   1.391 +{
   1.392 +  MOZ_ASSERT(NS_IsMainThread());
   1.393 +
   1.394 +  Cleanup();
   1.395 +
   1.396 +  // Now, we're ready to call the script back with the resulting buffer
   1.397 +  mDecodeJob.OnSuccess(WebAudioDecodeJob::NoError);
   1.398 +}
   1.399 +
   1.400 +bool
   1.401 +WebAudioDecodeJob::AllocateBuffer()
   1.402 +{
   1.403 +  MOZ_ASSERT(!mOutput);
   1.404 +  MOZ_ASSERT(NS_IsMainThread());
   1.405 +
   1.406 +  // First, get a JSContext
   1.407 +  AutoPushJSContext cx(mContext->GetJSContext());
   1.408 +  if (!cx) {
   1.409 +    return false;
   1.410 +  }
   1.411 +  // Now create the AudioBuffer
   1.412 +  ErrorResult rv;
   1.413 +  mOutput = AudioBuffer::Create(mContext, mChannelBuffers.Length(),
   1.414 +                                mWriteIndex, mContext->SampleRate(), cx, rv);
   1.415 +  if (rv.Failed()) {
   1.416 +    return false;
   1.417 +  }
   1.418 +
   1.419 +  for (uint32_t i = 0; i < mChannelBuffers.Length(); ++i) {
   1.420 +    mOutput->SetRawChannelContents(cx, i, mChannelBuffers[i]);
   1.421 +  }
   1.422 +
   1.423 +  return true;
   1.424 +}
   1.425 +
   1.426 +void
   1.427 +MediaBufferDecoder::AsyncDecodeMedia(const char* aContentType, uint8_t* aBuffer,
   1.428 +                                     uint32_t aLength,
   1.429 +                                     WebAudioDecodeJob& aDecodeJob)
   1.430 +{
   1.431 +  // Do not attempt to decode the media if we were not successful at sniffing
   1.432 +  // the content type.
   1.433 +  if (!*aContentType ||
   1.434 +      strcmp(aContentType, APPLICATION_OCTET_STREAM) == 0) {
   1.435 +    nsCOMPtr<nsIRunnable> event =
   1.436 +      new ReportResultTask(aDecodeJob,
   1.437 +                           &WebAudioDecodeJob::OnFailure,
   1.438 +                           WebAudioDecodeJob::UnknownContent);
   1.439 +    NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
   1.440 +    return;
   1.441 +  }
   1.442 +
   1.443 +  if (!EnsureThreadPoolInitialized()) {
   1.444 +    nsCOMPtr<nsIRunnable> event =
   1.445 +      new ReportResultTask(aDecodeJob,
   1.446 +                           &WebAudioDecodeJob::OnFailure,
   1.447 +                           WebAudioDecodeJob::UnknownError);
   1.448 +    NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
   1.449 +    return;
   1.450 +  }
   1.451 +
   1.452 +  MOZ_ASSERT(mThreadPool);
   1.453 +
   1.454 +  nsRefPtr<MediaDecodeTask> task =
   1.455 +    new MediaDecodeTask(aContentType, aBuffer, aLength, aDecodeJob, mThreadPool);
   1.456 +  if (!task->CreateReader()) {
   1.457 +    nsCOMPtr<nsIRunnable> event =
   1.458 +      new ReportResultTask(aDecodeJob,
   1.459 +                           &WebAudioDecodeJob::OnFailure,
   1.460 +                           WebAudioDecodeJob::UnknownError);
   1.461 +    NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
   1.462 +  } else {
   1.463 +    mThreadPool->Dispatch(task, nsIThreadPool::DISPATCH_NORMAL);
   1.464 +  }
   1.465 +}
   1.466 +
   1.467 +bool
   1.468 +MediaBufferDecoder::EnsureThreadPoolInitialized()
   1.469 +{
   1.470 +  if (!mThreadPool) {
   1.471 +    mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
   1.472 +    if (!mThreadPool) {
   1.473 +      return false;
   1.474 +    }
   1.475 +    mThreadPool->SetName(NS_LITERAL_CSTRING("MediaBufferDecoder"));
   1.476 +  }
   1.477 +  return true;
   1.478 +}
   1.479 +
   1.480 +void
   1.481 +MediaBufferDecoder::Shutdown() {
   1.482 +  if (mThreadPool) {
   1.483 +    // Setting threadLimit to 0 causes threads to exit when all events have
   1.484 +    // been run, like nsIThreadPool::Shutdown(), but doesn't run a nested event
   1.485 +    // loop nor wait until this has happened.
   1.486 +    mThreadPool->SetThreadLimit(0);
   1.487 +    mThreadPool = nullptr;
   1.488 +  }
   1.489 +}
   1.490 +
   1.491 +WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType,
   1.492 +                                     AudioContext* aContext,
   1.493 +                                     DecodeSuccessCallback* aSuccessCallback,
   1.494 +                                     DecodeErrorCallback* aFailureCallback)
   1.495 +  : mContentType(aContentType)
   1.496 +  , mWriteIndex(0)
   1.497 +  , mContext(aContext)
   1.498 +  , mSuccessCallback(aSuccessCallback)
   1.499 +  , mFailureCallback(aFailureCallback)
   1.500 +{
   1.501 +  MOZ_ASSERT(aContext);
   1.502 +  MOZ_ASSERT(aSuccessCallback);
   1.503 +  MOZ_ASSERT(NS_IsMainThread());
   1.504 +  MOZ_COUNT_CTOR(WebAudioDecodeJob);
   1.505 +}
   1.506 +
   1.507 +WebAudioDecodeJob::~WebAudioDecodeJob()
   1.508 +{
   1.509 +  MOZ_ASSERT(NS_IsMainThread());
   1.510 +  MOZ_COUNT_DTOR(WebAudioDecodeJob);
   1.511 +}
   1.512 +
   1.513 +void
   1.514 +WebAudioDecodeJob::OnSuccess(ErrorCode aErrorCode)
   1.515 +{
   1.516 +  MOZ_ASSERT(NS_IsMainThread());
   1.517 +  MOZ_ASSERT(aErrorCode == NoError);
   1.518 +
   1.519 +  // Ignore errors in calling the callback, since there is not much that we can
   1.520 +  // do about it here.
   1.521 +  ErrorResult rv;
   1.522 +  mSuccessCallback->Call(*mOutput, rv);
   1.523 +
   1.524 +  mContext->RemoveFromDecodeQueue(this);
   1.525 +}
   1.526 +
   1.527 +void
   1.528 +WebAudioDecodeJob::OnFailure(ErrorCode aErrorCode)
   1.529 +{
   1.530 +  MOZ_ASSERT(NS_IsMainThread());
   1.531 +
   1.532 +  const char* errorMessage;
   1.533 +  switch (aErrorCode) {
   1.534 +  case NoError:
   1.535 +    MOZ_ASSERT(false, "Who passed NoError to OnFailure?");
   1.536 +    // Fall through to get some sort of a sane error message if this actually
   1.537 +    // happens at runtime.
   1.538 +  case UnknownError:
   1.539 +    errorMessage = "MediaDecodeAudioDataUnknownError";
   1.540 +    break;
   1.541 +  case UnknownContent:
   1.542 +    errorMessage = "MediaDecodeAudioDataUnknownContentType";
   1.543 +    break;
   1.544 +  case InvalidContent:
   1.545 +    errorMessage = "MediaDecodeAudioDataInvalidContent";
   1.546 +    break;
   1.547 +  case NoAudio:
   1.548 +    errorMessage = "MediaDecodeAudioDataNoAudio";
   1.549 +    break;
   1.550 +  }
   1.551 +
   1.552 +  nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(mContext->GetParentObject());
   1.553 +  nsIDocument* doc = nullptr;
   1.554 +  if (pWindow) {
   1.555 +    doc = pWindow->GetExtantDoc();
   1.556 +  }
   1.557 +  nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
   1.558 +                                  NS_LITERAL_CSTRING("Media"),
   1.559 +                                  doc,
   1.560 +                                  nsContentUtils::eDOM_PROPERTIES,
   1.561 +                                  errorMessage);
   1.562 +
   1.563 +  // Ignore errors in calling the callback, since there is not much that we can
   1.564 +  // do about it here.
   1.565 +  if (mFailureCallback) {
   1.566 +    ErrorResult rv;
   1.567 +    mFailureCallback->Call(rv);
   1.568 +  }
   1.569 +
   1.570 +  mContext->RemoveFromDecodeQueue(this);
   1.571 +}
   1.572 +
   1.573 +size_t
   1.574 +WebAudioDecodeJob::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
   1.575 +{
   1.576 +  size_t amount = 0;
   1.577 +  amount += mContentType.SizeOfExcludingThisMustBeUnshared(aMallocSizeOf);
   1.578 +  if (mSuccessCallback) {
   1.579 +    amount += mSuccessCallback->SizeOfIncludingThis(aMallocSizeOf);
   1.580 +  }
   1.581 +  if (mFailureCallback) {
   1.582 +    amount += mFailureCallback->SizeOfIncludingThis(aMallocSizeOf);
   1.583 +  }
   1.584 +  if (mOutput) {
   1.585 +    amount += mOutput->SizeOfIncludingThis(aMallocSizeOf);
   1.586 +  }
   1.587 +  amount += mChannelBuffers.SizeOfExcludingThis(aMallocSizeOf);
   1.588 +  for (uint32_t i = 0; i < mChannelBuffers.Length(); ++i) {
   1.589 +    amount += mChannelBuffers[i].SizeOfExcludingThis(aMallocSizeOf);
   1.590 +  }
   1.591 +  return amount;
   1.592 +}
   1.593 +
   1.594 +}
   1.595 +

mercurial