content/media/webaudio/MediaBufferDecoder.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "MediaBufferDecoder.h"
michael@0 8 #include "BufferDecoder.h"
michael@0 9 #include "mozilla/dom/AudioContextBinding.h"
michael@0 10 #include <speex/speex_resampler.h>
michael@0 11 #include "nsXPCOMCIDInternal.h"
michael@0 12 #include "nsComponentManagerUtils.h"
michael@0 13 #include "MediaDecoderReader.h"
michael@0 14 #include "BufferMediaResource.h"
michael@0 15 #include "DecoderTraits.h"
michael@0 16 #include "AudioContext.h"
michael@0 17 #include "AudioBuffer.h"
michael@0 18 #include "nsIScriptObjectPrincipal.h"
michael@0 19 #include "nsIScriptError.h"
michael@0 20 #include "nsMimeTypes.h"
michael@0 21 #include "nsCxPusher.h"
michael@0 22 #include "WebAudioUtils.h"
michael@0 23
michael@0 24 namespace mozilla {
michael@0 25
michael@0 26 NS_IMPL_CYCLE_COLLECTION_CLASS(WebAudioDecodeJob)
michael@0 27
michael@0 28 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WebAudioDecodeJob)
michael@0 29 NS_IMPL_CYCLE_COLLECTION_UNLINK(mContext)
michael@0 30 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOutput)
michael@0 31 NS_IMPL_CYCLE_COLLECTION_UNLINK(mSuccessCallback)
michael@0 32 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFailureCallback)
michael@0 33 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
michael@0 34
michael@0 35 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WebAudioDecodeJob)
michael@0 36 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
michael@0 37 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOutput)
michael@0 38 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSuccessCallback)
michael@0 39 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFailureCallback)
michael@0 40 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
michael@0 41 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
michael@0 42
michael@0 43 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(WebAudioDecodeJob)
michael@0 44 NS_IMPL_CYCLE_COLLECTION_TRACE_END
michael@0 45 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebAudioDecodeJob, AddRef)
michael@0 46 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebAudioDecodeJob, Release)
michael@0 47
michael@0 48 using namespace dom;
michael@0 49
michael@0 50 class ReportResultTask : public nsRunnable
michael@0 51 {
michael@0 52 public:
michael@0 53 ReportResultTask(WebAudioDecodeJob& aDecodeJob,
michael@0 54 WebAudioDecodeJob::ResultFn aFunction,
michael@0 55 WebAudioDecodeJob::ErrorCode aErrorCode)
michael@0 56 : mDecodeJob(aDecodeJob)
michael@0 57 , mFunction(aFunction)
michael@0 58 , mErrorCode(aErrorCode)
michael@0 59 {
michael@0 60 MOZ_ASSERT(aFunction);
michael@0 61 }
michael@0 62
michael@0 63 NS_IMETHOD Run()
michael@0 64 {
michael@0 65 MOZ_ASSERT(NS_IsMainThread());
michael@0 66
michael@0 67 (mDecodeJob.*mFunction)(mErrorCode);
michael@0 68
michael@0 69 return NS_OK;
michael@0 70 }
michael@0 71
michael@0 72 private:
michael@0 73 // Note that the mDecodeJob member will probably die when mFunction is run.
michael@0 74 // Therefore, it is not safe to do anything fancy with it in this class.
michael@0 75 // Really, this class is only used because nsRunnableMethod doesn't support
michael@0 76 // methods accepting arguments.
michael@0 77 WebAudioDecodeJob& mDecodeJob;
michael@0 78 WebAudioDecodeJob::ResultFn mFunction;
michael@0 79 WebAudioDecodeJob::ErrorCode mErrorCode;
michael@0 80 };
michael@0 81
michael@0 82 MOZ_BEGIN_ENUM_CLASS(PhaseEnum, int)
michael@0 83 Decode,
michael@0 84 AllocateBuffer,
michael@0 85 Done
michael@0 86 MOZ_END_ENUM_CLASS(PhaseEnum)
michael@0 87
michael@0 88 class MediaDecodeTask : public nsRunnable
michael@0 89 {
michael@0 90 public:
michael@0 91 MediaDecodeTask(const char* aContentType, uint8_t* aBuffer,
michael@0 92 uint32_t aLength,
michael@0 93 WebAudioDecodeJob& aDecodeJob,
michael@0 94 nsIThreadPool* aThreadPool)
michael@0 95 : mContentType(aContentType)
michael@0 96 , mBuffer(aBuffer)
michael@0 97 , mLength(aLength)
michael@0 98 , mDecodeJob(aDecodeJob)
michael@0 99 , mPhase(PhaseEnum::Decode)
michael@0 100 , mThreadPool(aThreadPool)
michael@0 101 {
michael@0 102 MOZ_ASSERT(aBuffer);
michael@0 103 MOZ_ASSERT(NS_IsMainThread());
michael@0 104
michael@0 105 nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(mDecodeJob.mContext->GetParentObject());
michael@0 106 nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
michael@0 107 do_QueryInterface(pWindow);
michael@0 108 if (scriptPrincipal) {
michael@0 109 mPrincipal = scriptPrincipal->GetPrincipal();
michael@0 110 }
michael@0 111 }
michael@0 112
michael@0 113 NS_IMETHOD Run();
michael@0 114 bool CreateReader();
michael@0 115
michael@0 116 private:
michael@0 117 void ReportFailureOnMainThread(WebAudioDecodeJob::ErrorCode aErrorCode) {
michael@0 118 if (NS_IsMainThread()) {
michael@0 119 Cleanup();
michael@0 120 mDecodeJob.OnFailure(aErrorCode);
michael@0 121 } else {
michael@0 122 // Take extra care to cleanup on the main thread
michael@0 123 NS_DispatchToMainThread(NS_NewRunnableMethod(this, &MediaDecodeTask::Cleanup),
michael@0 124 NS_DISPATCH_NORMAL);
michael@0 125
michael@0 126 nsCOMPtr<nsIRunnable> event =
michael@0 127 new ReportResultTask(mDecodeJob, &WebAudioDecodeJob::OnFailure, aErrorCode);
michael@0 128 NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
michael@0 129 }
michael@0 130 }
michael@0 131
michael@0 132 void Decode();
michael@0 133 void AllocateBuffer();
michael@0 134 void CallbackTheResult();
michael@0 135
michael@0 136 void Cleanup()
michael@0 137 {
michael@0 138 MOZ_ASSERT(NS_IsMainThread());
michael@0 139 // MediaDecoderReader expects that BufferDecoder is alive.
michael@0 140 // Destruct MediaDecoderReader first.
michael@0 141 mDecoderReader = nullptr;
michael@0 142 mBufferDecoder = nullptr;
michael@0 143 JS_free(nullptr, mBuffer);
michael@0 144 }
michael@0 145
michael@0 146 private:
michael@0 147 nsCString mContentType;
michael@0 148 uint8_t* mBuffer;
michael@0 149 uint32_t mLength;
michael@0 150 WebAudioDecodeJob& mDecodeJob;
michael@0 151 PhaseEnum mPhase;
michael@0 152 nsCOMPtr<nsIThreadPool> mThreadPool;
michael@0 153 nsCOMPtr<nsIPrincipal> mPrincipal;
michael@0 154 nsRefPtr<BufferDecoder> mBufferDecoder;
michael@0 155 nsAutoPtr<MediaDecoderReader> mDecoderReader;
michael@0 156 };
michael@0 157
michael@0 158 NS_IMETHODIMP
michael@0 159 MediaDecodeTask::Run()
michael@0 160 {
michael@0 161 MOZ_ASSERT(mBufferDecoder);
michael@0 162 MOZ_ASSERT(mDecoderReader);
michael@0 163 switch (mPhase) {
michael@0 164 case PhaseEnum::Decode:
michael@0 165 Decode();
michael@0 166 break;
michael@0 167 case PhaseEnum::AllocateBuffer:
michael@0 168 AllocateBuffer();
michael@0 169 break;
michael@0 170 case PhaseEnum::Done:
michael@0 171 break;
michael@0 172 }
michael@0 173
michael@0 174 return NS_OK;
michael@0 175 }
michael@0 176
michael@0 177 bool
michael@0 178 MediaDecodeTask::CreateReader()
michael@0 179 {
michael@0 180 MOZ_ASSERT(NS_IsMainThread());
michael@0 181
michael@0 182 nsRefPtr<BufferMediaResource> resource =
michael@0 183 new BufferMediaResource(static_cast<uint8_t*> (mBuffer),
michael@0 184 mLength, mPrincipal, mContentType);
michael@0 185
michael@0 186 MOZ_ASSERT(!mBufferDecoder);
michael@0 187 mBufferDecoder = new BufferDecoder(resource);
michael@0 188
michael@0 189 // If you change this list to add support for new decoders, please consider
michael@0 190 // updating HTMLMediaElement::CreateDecoder as well.
michael@0 191
michael@0 192 mDecoderReader = DecoderTraits::CreateReader(mContentType, mBufferDecoder);
michael@0 193
michael@0 194 if (!mDecoderReader) {
michael@0 195 return false;
michael@0 196 }
michael@0 197
michael@0 198 nsresult rv = mDecoderReader->Init(nullptr);
michael@0 199 if (NS_FAILED(rv)) {
michael@0 200 return false;
michael@0 201 }
michael@0 202
michael@0 203 return true;
michael@0 204 }
michael@0 205
michael@0 206 class AutoResampler {
michael@0 207 public:
michael@0 208 AutoResampler()
michael@0 209 : mResampler(nullptr)
michael@0 210 {}
michael@0 211 ~AutoResampler()
michael@0 212 {
michael@0 213 if (mResampler) {
michael@0 214 speex_resampler_destroy(mResampler);
michael@0 215 }
michael@0 216 }
michael@0 217 operator SpeexResamplerState*() const
michael@0 218 {
michael@0 219 MOZ_ASSERT(mResampler);
michael@0 220 return mResampler;
michael@0 221 }
michael@0 222 void operator=(SpeexResamplerState* aResampler)
michael@0 223 {
michael@0 224 mResampler = aResampler;
michael@0 225 }
michael@0 226
michael@0 227 private:
michael@0 228 SpeexResamplerState* mResampler;
michael@0 229 };
michael@0 230
michael@0 231 void
michael@0 232 MediaDecodeTask::Decode()
michael@0 233 {
michael@0 234 MOZ_ASSERT(!NS_IsMainThread());
michael@0 235
michael@0 236 mBufferDecoder->BeginDecoding(NS_GetCurrentThread());
michael@0 237
michael@0 238 // Tell the decoder reader that we are not going to play the data directly,
michael@0 239 // and that we should not reject files with more channels than the audio
michael@0 240 // bakend support.
michael@0 241 mDecoderReader->SetIgnoreAudioOutputFormat();
michael@0 242
michael@0 243 MediaInfo mediaInfo;
michael@0 244 nsAutoPtr<MetadataTags> tags;
michael@0 245 nsresult rv = mDecoderReader->ReadMetadata(&mediaInfo, getter_Transfers(tags));
michael@0 246 if (NS_FAILED(rv)) {
michael@0 247 ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
michael@0 248 return;
michael@0 249 }
michael@0 250
michael@0 251 if (!mDecoderReader->HasAudio()) {
michael@0 252 ReportFailureOnMainThread(WebAudioDecodeJob::NoAudio);
michael@0 253 return;
michael@0 254 }
michael@0 255
michael@0 256 while (mDecoderReader->DecodeAudioData()) {
michael@0 257 // consume all of the buffer
michael@0 258 continue;
michael@0 259 }
michael@0 260
michael@0 261 MediaQueue<AudioData>& audioQueue = mDecoderReader->AudioQueue();
michael@0 262 uint32_t frameCount = audioQueue.FrameCount();
michael@0 263 uint32_t channelCount = mediaInfo.mAudio.mChannels;
michael@0 264 uint32_t sampleRate = mediaInfo.mAudio.mRate;
michael@0 265
michael@0 266 if (!frameCount || !channelCount || !sampleRate) {
michael@0 267 ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
michael@0 268 return;
michael@0 269 }
michael@0 270
michael@0 271 const uint32_t destSampleRate = mDecodeJob.mContext->SampleRate();
michael@0 272 AutoResampler resampler;
michael@0 273
michael@0 274 uint32_t resampledFrames = frameCount;
michael@0 275 if (sampleRate != destSampleRate) {
michael@0 276 resampledFrames = static_cast<uint32_t>(
michael@0 277 static_cast<uint64_t>(destSampleRate) *
michael@0 278 static_cast<uint64_t>(frameCount) /
michael@0 279 static_cast<uint64_t>(sampleRate)
michael@0 280 );
michael@0 281
michael@0 282 resampler = speex_resampler_init(channelCount,
michael@0 283 sampleRate,
michael@0 284 destSampleRate,
michael@0 285 SPEEX_RESAMPLER_QUALITY_DEFAULT, nullptr);
michael@0 286 speex_resampler_skip_zeros(resampler);
michael@0 287 resampledFrames += speex_resampler_get_output_latency(resampler);
michael@0 288 }
michael@0 289
michael@0 290 // Allocate the channel buffers. Note that if we end up resampling, we may
michael@0 291 // write fewer bytes than mResampledFrames to the output buffer, in which
michael@0 292 // case mWriteIndex will tell us how many valid samples we have.
michael@0 293 static const fallible_t fallible = fallible_t();
michael@0 294 bool memoryAllocationSuccess = true;
michael@0 295 if (!mDecodeJob.mChannelBuffers.SetLength(channelCount)) {
michael@0 296 memoryAllocationSuccess = false;
michael@0 297 } else {
michael@0 298 for (uint32_t i = 0; i < channelCount; ++i) {
michael@0 299 mDecodeJob.mChannelBuffers[i] = new(fallible) float[resampledFrames];
michael@0 300 if (!mDecodeJob.mChannelBuffers[i]) {
michael@0 301 memoryAllocationSuccess = false;
michael@0 302 break;
michael@0 303 }
michael@0 304 }
michael@0 305 }
michael@0 306 if (!memoryAllocationSuccess) {
michael@0 307 ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
michael@0 308 return;
michael@0 309 }
michael@0 310
michael@0 311 nsAutoPtr<AudioData> audioData;
michael@0 312 while ((audioData = audioQueue.PopFront())) {
michael@0 313 audioData->EnsureAudioBuffer(); // could lead to a copy :(
michael@0 314 AudioDataValue* bufferData = static_cast<AudioDataValue*>
michael@0 315 (audioData->mAudioBuffer->Data());
michael@0 316
michael@0 317 if (sampleRate != destSampleRate) {
michael@0 318 const uint32_t maxOutSamples = resampledFrames - mDecodeJob.mWriteIndex;
michael@0 319
michael@0 320 for (uint32_t i = 0; i < audioData->mChannels; ++i) {
michael@0 321 uint32_t inSamples = audioData->mFrames;
michael@0 322 uint32_t outSamples = maxOutSamples;
michael@0 323
michael@0 324 WebAudioUtils::SpeexResamplerProcess(
michael@0 325 resampler, i, &bufferData[i * audioData->mFrames], &inSamples,
michael@0 326 mDecodeJob.mChannelBuffers[i] + mDecodeJob.mWriteIndex,
michael@0 327 &outSamples);
michael@0 328
michael@0 329 if (i == audioData->mChannels - 1) {
michael@0 330 mDecodeJob.mWriteIndex += outSamples;
michael@0 331 MOZ_ASSERT(mDecodeJob.mWriteIndex <= resampledFrames);
michael@0 332 MOZ_ASSERT(inSamples == audioData->mFrames);
michael@0 333 }
michael@0 334 }
michael@0 335 } else {
michael@0 336 for (uint32_t i = 0; i < audioData->mChannels; ++i) {
michael@0 337 ConvertAudioSamples(&bufferData[i * audioData->mFrames],
michael@0 338 mDecodeJob.mChannelBuffers[i] + mDecodeJob.mWriteIndex,
michael@0 339 audioData->mFrames);
michael@0 340
michael@0 341 if (i == audioData->mChannels - 1) {
michael@0 342 mDecodeJob.mWriteIndex += audioData->mFrames;
michael@0 343 }
michael@0 344 }
michael@0 345 }
michael@0 346 }
michael@0 347
michael@0 348 if (sampleRate != destSampleRate) {
michael@0 349 uint32_t inputLatency = speex_resampler_get_input_latency(resampler);
michael@0 350 const uint32_t maxOutSamples = resampledFrames - mDecodeJob.mWriteIndex;
michael@0 351 for (uint32_t i = 0; i < channelCount; ++i) {
michael@0 352 uint32_t inSamples = inputLatency;
michael@0 353 uint32_t outSamples = maxOutSamples;
michael@0 354
michael@0 355 WebAudioUtils::SpeexResamplerProcess(
michael@0 356 resampler, i, (AudioDataValue*)nullptr, &inSamples,
michael@0 357 mDecodeJob.mChannelBuffers[i] + mDecodeJob.mWriteIndex,
michael@0 358 &outSamples);
michael@0 359
michael@0 360 if (i == channelCount - 1) {
michael@0 361 mDecodeJob.mWriteIndex += outSamples;
michael@0 362 MOZ_ASSERT(mDecodeJob.mWriteIndex <= resampledFrames);
michael@0 363 MOZ_ASSERT(inSamples == inputLatency);
michael@0 364 }
michael@0 365 }
michael@0 366 }
michael@0 367
michael@0 368 mPhase = PhaseEnum::AllocateBuffer;
michael@0 369 NS_DispatchToMainThread(this);
michael@0 370 }
michael@0 371
michael@0 372 void
michael@0 373 MediaDecodeTask::AllocateBuffer()
michael@0 374 {
michael@0 375 MOZ_ASSERT(NS_IsMainThread());
michael@0 376
michael@0 377 if (!mDecodeJob.AllocateBuffer()) {
michael@0 378 ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
michael@0 379 return;
michael@0 380 }
michael@0 381
michael@0 382 mPhase = PhaseEnum::Done;
michael@0 383 CallbackTheResult();
michael@0 384 }
michael@0 385
michael@0 386 void
michael@0 387 MediaDecodeTask::CallbackTheResult()
michael@0 388 {
michael@0 389 MOZ_ASSERT(NS_IsMainThread());
michael@0 390
michael@0 391 Cleanup();
michael@0 392
michael@0 393 // Now, we're ready to call the script back with the resulting buffer
michael@0 394 mDecodeJob.OnSuccess(WebAudioDecodeJob::NoError);
michael@0 395 }
michael@0 396
michael@0 397 bool
michael@0 398 WebAudioDecodeJob::AllocateBuffer()
michael@0 399 {
michael@0 400 MOZ_ASSERT(!mOutput);
michael@0 401 MOZ_ASSERT(NS_IsMainThread());
michael@0 402
michael@0 403 // First, get a JSContext
michael@0 404 AutoPushJSContext cx(mContext->GetJSContext());
michael@0 405 if (!cx) {
michael@0 406 return false;
michael@0 407 }
michael@0 408 // Now create the AudioBuffer
michael@0 409 ErrorResult rv;
michael@0 410 mOutput = AudioBuffer::Create(mContext, mChannelBuffers.Length(),
michael@0 411 mWriteIndex, mContext->SampleRate(), cx, rv);
michael@0 412 if (rv.Failed()) {
michael@0 413 return false;
michael@0 414 }
michael@0 415
michael@0 416 for (uint32_t i = 0; i < mChannelBuffers.Length(); ++i) {
michael@0 417 mOutput->SetRawChannelContents(cx, i, mChannelBuffers[i]);
michael@0 418 }
michael@0 419
michael@0 420 return true;
michael@0 421 }
michael@0 422
michael@0 423 void
michael@0 424 MediaBufferDecoder::AsyncDecodeMedia(const char* aContentType, uint8_t* aBuffer,
michael@0 425 uint32_t aLength,
michael@0 426 WebAudioDecodeJob& aDecodeJob)
michael@0 427 {
michael@0 428 // Do not attempt to decode the media if we were not successful at sniffing
michael@0 429 // the content type.
michael@0 430 if (!*aContentType ||
michael@0 431 strcmp(aContentType, APPLICATION_OCTET_STREAM) == 0) {
michael@0 432 nsCOMPtr<nsIRunnable> event =
michael@0 433 new ReportResultTask(aDecodeJob,
michael@0 434 &WebAudioDecodeJob::OnFailure,
michael@0 435 WebAudioDecodeJob::UnknownContent);
michael@0 436 NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
michael@0 437 return;
michael@0 438 }
michael@0 439
michael@0 440 if (!EnsureThreadPoolInitialized()) {
michael@0 441 nsCOMPtr<nsIRunnable> event =
michael@0 442 new ReportResultTask(aDecodeJob,
michael@0 443 &WebAudioDecodeJob::OnFailure,
michael@0 444 WebAudioDecodeJob::UnknownError);
michael@0 445 NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
michael@0 446 return;
michael@0 447 }
michael@0 448
michael@0 449 MOZ_ASSERT(mThreadPool);
michael@0 450
michael@0 451 nsRefPtr<MediaDecodeTask> task =
michael@0 452 new MediaDecodeTask(aContentType, aBuffer, aLength, aDecodeJob, mThreadPool);
michael@0 453 if (!task->CreateReader()) {
michael@0 454 nsCOMPtr<nsIRunnable> event =
michael@0 455 new ReportResultTask(aDecodeJob,
michael@0 456 &WebAudioDecodeJob::OnFailure,
michael@0 457 WebAudioDecodeJob::UnknownError);
michael@0 458 NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
michael@0 459 } else {
michael@0 460 mThreadPool->Dispatch(task, nsIThreadPool::DISPATCH_NORMAL);
michael@0 461 }
michael@0 462 }
michael@0 463
michael@0 464 bool
michael@0 465 MediaBufferDecoder::EnsureThreadPoolInitialized()
michael@0 466 {
michael@0 467 if (!mThreadPool) {
michael@0 468 mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
michael@0 469 if (!mThreadPool) {
michael@0 470 return false;
michael@0 471 }
michael@0 472 mThreadPool->SetName(NS_LITERAL_CSTRING("MediaBufferDecoder"));
michael@0 473 }
michael@0 474 return true;
michael@0 475 }
michael@0 476
michael@0 477 void
michael@0 478 MediaBufferDecoder::Shutdown() {
michael@0 479 if (mThreadPool) {
michael@0 480 // Setting threadLimit to 0 causes threads to exit when all events have
michael@0 481 // been run, like nsIThreadPool::Shutdown(), but doesn't run a nested event
michael@0 482 // loop nor wait until this has happened.
michael@0 483 mThreadPool->SetThreadLimit(0);
michael@0 484 mThreadPool = nullptr;
michael@0 485 }
michael@0 486 }
michael@0 487
michael@0 488 WebAudioDecodeJob::WebAudioDecodeJob(const nsACString& aContentType,
michael@0 489 AudioContext* aContext,
michael@0 490 DecodeSuccessCallback* aSuccessCallback,
michael@0 491 DecodeErrorCallback* aFailureCallback)
michael@0 492 : mContentType(aContentType)
michael@0 493 , mWriteIndex(0)
michael@0 494 , mContext(aContext)
michael@0 495 , mSuccessCallback(aSuccessCallback)
michael@0 496 , mFailureCallback(aFailureCallback)
michael@0 497 {
michael@0 498 MOZ_ASSERT(aContext);
michael@0 499 MOZ_ASSERT(aSuccessCallback);
michael@0 500 MOZ_ASSERT(NS_IsMainThread());
michael@0 501 MOZ_COUNT_CTOR(WebAudioDecodeJob);
michael@0 502 }
michael@0 503
michael@0 504 WebAudioDecodeJob::~WebAudioDecodeJob()
michael@0 505 {
michael@0 506 MOZ_ASSERT(NS_IsMainThread());
michael@0 507 MOZ_COUNT_DTOR(WebAudioDecodeJob);
michael@0 508 }
michael@0 509
michael@0 510 void
michael@0 511 WebAudioDecodeJob::OnSuccess(ErrorCode aErrorCode)
michael@0 512 {
michael@0 513 MOZ_ASSERT(NS_IsMainThread());
michael@0 514 MOZ_ASSERT(aErrorCode == NoError);
michael@0 515
michael@0 516 // Ignore errors in calling the callback, since there is not much that we can
michael@0 517 // do about it here.
michael@0 518 ErrorResult rv;
michael@0 519 mSuccessCallback->Call(*mOutput, rv);
michael@0 520
michael@0 521 mContext->RemoveFromDecodeQueue(this);
michael@0 522 }
michael@0 523
michael@0 524 void
michael@0 525 WebAudioDecodeJob::OnFailure(ErrorCode aErrorCode)
michael@0 526 {
michael@0 527 MOZ_ASSERT(NS_IsMainThread());
michael@0 528
michael@0 529 const char* errorMessage;
michael@0 530 switch (aErrorCode) {
michael@0 531 case NoError:
michael@0 532 MOZ_ASSERT(false, "Who passed NoError to OnFailure?");
michael@0 533 // Fall through to get some sort of a sane error message if this actually
michael@0 534 // happens at runtime.
michael@0 535 case UnknownError:
michael@0 536 errorMessage = "MediaDecodeAudioDataUnknownError";
michael@0 537 break;
michael@0 538 case UnknownContent:
michael@0 539 errorMessage = "MediaDecodeAudioDataUnknownContentType";
michael@0 540 break;
michael@0 541 case InvalidContent:
michael@0 542 errorMessage = "MediaDecodeAudioDataInvalidContent";
michael@0 543 break;
michael@0 544 case NoAudio:
michael@0 545 errorMessage = "MediaDecodeAudioDataNoAudio";
michael@0 546 break;
michael@0 547 }
michael@0 548
michael@0 549 nsCOMPtr<nsPIDOMWindow> pWindow = do_QueryInterface(mContext->GetParentObject());
michael@0 550 nsIDocument* doc = nullptr;
michael@0 551 if (pWindow) {
michael@0 552 doc = pWindow->GetExtantDoc();
michael@0 553 }
michael@0 554 nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
michael@0 555 NS_LITERAL_CSTRING("Media"),
michael@0 556 doc,
michael@0 557 nsContentUtils::eDOM_PROPERTIES,
michael@0 558 errorMessage);
michael@0 559
michael@0 560 // Ignore errors in calling the callback, since there is not much that we can
michael@0 561 // do about it here.
michael@0 562 if (mFailureCallback) {
michael@0 563 ErrorResult rv;
michael@0 564 mFailureCallback->Call(rv);
michael@0 565 }
michael@0 566
michael@0 567 mContext->RemoveFromDecodeQueue(this);
michael@0 568 }
michael@0 569
michael@0 570 size_t
michael@0 571 WebAudioDecodeJob::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
michael@0 572 {
michael@0 573 size_t amount = 0;
michael@0 574 amount += mContentType.SizeOfExcludingThisMustBeUnshared(aMallocSizeOf);
michael@0 575 if (mSuccessCallback) {
michael@0 576 amount += mSuccessCallback->SizeOfIncludingThis(aMallocSizeOf);
michael@0 577 }
michael@0 578 if (mFailureCallback) {
michael@0 579 amount += mFailureCallback->SizeOfIncludingThis(aMallocSizeOf);
michael@0 580 }
michael@0 581 if (mOutput) {
michael@0 582 amount += mOutput->SizeOfIncludingThis(aMallocSizeOf);
michael@0 583 }
michael@0 584 amount += mChannelBuffers.SizeOfExcludingThis(aMallocSizeOf);
michael@0 585 for (uint32_t i = 0; i < mChannelBuffers.Length(); ++i) {
michael@0 586 amount += mChannelBuffers[i].SizeOfExcludingThis(aMallocSizeOf);
michael@0 587 }
michael@0 588 return amount;
michael@0 589 }
michael@0 590
michael@0 591 }
michael@0 592

mercurial