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 +