Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/webaudio/MediaBufferDecoder.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim:set ts=2 sw=2 sts=2 et cindent: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "MediaBufferDecoder.h"
8
#include "mozilla/dom/AudioContextBinding.h"
9
#include "mozilla/dom/BaseAudioContextBinding.h"
10
#include "mozilla/dom/DOMException.h"
11
#include "mozilla/dom/ScriptSettings.h"
12
#include "mozilla/AbstractThread.h"
13
#include <speex/speex_resampler.h>
14
#include "nsXPCOMCIDInternal.h"
15
#include "nsComponentManagerUtils.h"
16
#include "MediaFormatReader.h"
17
#include "MediaQueue.h"
18
#include "BufferMediaResource.h"
19
#include "DecoderTraits.h"
20
#include "AudioContext.h"
21
#include "AudioBuffer.h"
22
#include "MediaContainerType.h"
23
#include "nsContentUtils.h"
24
#include "nsIScriptObjectPrincipal.h"
25
#include "nsIScriptError.h"
26
#include "nsMimeTypes.h"
27
#include "VideoUtils.h"
28
#include "WebAudioUtils.h"
29
#include "mozilla/dom/Promise.h"
30
#include "mozilla/Telemetry.h"
31
#include "nsPrintfCString.h"
32
#include "AudioNodeEngine.h"
33
34
namespace mozilla {
35
36
extern LazyLogModule gMediaDecoderLog;
37
38
using namespace dom;
39
40
class ReportResultTask final : public Runnable
41
{
42
public:
43
  ReportResultTask(WebAudioDecodeJob& aDecodeJob,
44
                   WebAudioDecodeJob::ResultFn aFunction,
45
                   WebAudioDecodeJob::ErrorCode aErrorCode)
46
    : Runnable("ReportResultTask")
47
    , mDecodeJob(aDecodeJob)
48
    , mFunction(aFunction)
49
    , mErrorCode(aErrorCode)
50
0
  {
51
0
    MOZ_ASSERT(aFunction);
52
0
  }
53
54
  NS_IMETHOD Run() override
55
0
  {
56
0
    MOZ_ASSERT(NS_IsMainThread());
57
0
58
0
    (mDecodeJob.*mFunction)(mErrorCode);
59
0
60
0
    return NS_OK;
61
0
  }
62
63
private:
64
  // Note that the mDecodeJob member will probably die when mFunction is run.
65
  // Therefore, it is not safe to do anything fancy with it in this class.
66
  // Really, this class is only used because nsRunnableMethod doesn't support
67
  // methods accepting arguments.
68
  WebAudioDecodeJob& mDecodeJob;
69
  WebAudioDecodeJob::ResultFn mFunction;
70
  WebAudioDecodeJob::ErrorCode mErrorCode;
71
};
72
73
enum class PhaseEnum : int
74
{
75
  Decode,
76
  AllocateBuffer,
77
  Done
78
};
79
80
class MediaDecodeTask final : public Runnable
81
{
82
public:
83
  MediaDecodeTask(const MediaContainerType& aContainerType,
84
                  uint8_t* aBuffer,
85
                  uint32_t aLength,
86
                  WebAudioDecodeJob& aDecodeJob)
87
    : Runnable("MediaDecodeTask")
88
    , mContainerType(aContainerType)
89
    , mBuffer(aBuffer)
90
    , mLength(aLength)
91
    , mDecodeJob(aDecodeJob)
92
    , mPhase(PhaseEnum::Decode)
93
    , mFirstFrameDecoded(false)
94
0
  {
95
0
    MOZ_ASSERT(aBuffer);
96
0
    MOZ_ASSERT(NS_IsMainThread());
97
0
  }
98
99
  NS_IMETHOD Run() override;
100
  bool CreateReader();
101
  MediaFormatReader* Reader()
102
0
  {
103
0
    MOZ_ASSERT(mDecoderReader);
104
0
    return mDecoderReader;
105
0
  }
106
107
private:
108
0
  void ReportFailureOnMainThread(WebAudioDecodeJob::ErrorCode aErrorCode) {
109
0
    if (NS_IsMainThread()) {
110
0
      Cleanup();
111
0
      mDecodeJob.OnFailure(aErrorCode);
112
0
    } else {
113
0
      // Take extra care to cleanup on the main thread
114
0
      mMainThread->Dispatch(NewRunnableMethod(
115
0
        "MediaDecodeTask::Cleanup", this, &MediaDecodeTask::Cleanup));
116
0
117
0
      nsCOMPtr<nsIRunnable> event =
118
0
        new ReportResultTask(mDecodeJob, &WebAudioDecodeJob::OnFailure, aErrorCode);
119
0
      mMainThread->Dispatch(event.forget());
120
0
    }
121
0
  }
122
123
  void Decode();
124
  void OnMetadataRead(MetadataHolder&& aMetadata);
125
  void OnMetadataNotRead(const MediaResult& aError);
126
  void RequestSample();
127
  void SampleDecoded(RefPtr<AudioData> aData);
128
  void SampleNotDecoded(const MediaResult& aError);
129
  void FinishDecode();
130
  void AllocateBuffer();
131
  void CallbackTheResult();
132
133
  void Cleanup()
134
0
  {
135
0
    MOZ_ASSERT(NS_IsMainThread());
136
0
    mDecoderReader = nullptr;
137
0
    JS_free(nullptr, mBuffer);
138
0
  }
139
140
private:
141
  MediaContainerType mContainerType;
142
  uint8_t* mBuffer;
143
  uint32_t mLength;
144
  WebAudioDecodeJob& mDecodeJob;
145
  PhaseEnum mPhase;
146
  RefPtr<MediaFormatReader> mDecoderReader;
147
  MediaInfo mMediaInfo;
148
  MediaQueue<AudioData> mAudioQueue;
149
  RefPtr<AbstractThread> mMainThread;
150
  bool mFirstFrameDecoded;
151
};
152
153
NS_IMETHODIMP
154
MediaDecodeTask::Run()
155
0
{
156
0
  MOZ_ASSERT(mDecoderReader);
157
0
  switch (mPhase) {
158
0
  case PhaseEnum::Decode:
159
0
    Decode();
160
0
    break;
161
0
  case PhaseEnum::AllocateBuffer:
162
0
    AllocateBuffer();
163
0
    break;
164
0
  case PhaseEnum::Done:
165
0
    break;
166
0
  }
167
0
168
0
  return NS_OK;
169
0
}
170
171
bool
172
MediaDecodeTask::CreateReader()
173
0
{
174
0
  MOZ_ASSERT(NS_IsMainThread());
175
0
176
0
  RefPtr<BufferMediaResource> resource =
177
0
    new BufferMediaResource(static_cast<uint8_t*>(mBuffer), mLength);
178
0
179
0
  mMainThread =
180
0
    mDecodeJob.mContext->GetOwnerGlobal()->AbstractMainThreadFor(TaskCategory::Other);
181
0
182
0
  // If you change this list to add support for new decoders, please consider
183
0
  // updating HTMLMediaElement::CreateDecoder as well.
184
0
185
0
  MediaFormatReaderInit init;
186
0
  init.mResource = resource;
187
0
  mDecoderReader = DecoderTraits::CreateReader(mContainerType, init);
188
0
189
0
  if (!mDecoderReader) {
190
0
    return false;
191
0
  }
192
0
193
0
  nsresult rv = mDecoderReader->Init();
194
0
  if (NS_FAILED(rv)) {
195
0
    return false;
196
0
  }
197
0
198
0
  return true;
199
0
}
200
201
class AutoResampler final
202
{
203
public:
204
  AutoResampler()
205
    : mResampler(nullptr)
206
0
  {}
207
  ~AutoResampler()
208
0
  {
209
0
    if (mResampler) {
210
0
      speex_resampler_destroy(mResampler);
211
0
    }
212
0
  }
213
  operator SpeexResamplerState*() const
214
0
  {
215
0
    MOZ_ASSERT(mResampler);
216
0
    return mResampler;
217
0
  }
218
  void operator=(SpeexResamplerState* aResampler)
219
0
  {
220
0
    mResampler = aResampler;
221
0
  }
222
223
private:
224
  SpeexResamplerState* mResampler;
225
};
226
227
void
228
MediaDecodeTask::Decode()
229
0
{
230
0
  MOZ_ASSERT(!NS_IsMainThread());
231
0
232
0
233
0
  mDecoderReader->AsyncReadMetadata()->Then(mDecoderReader->OwnerThread(), __func__, this,
234
0
                                       &MediaDecodeTask::OnMetadataRead,
235
0
                                       &MediaDecodeTask::OnMetadataNotRead);
236
0
}
237
238
void
239
MediaDecodeTask::OnMetadataRead(MetadataHolder&& aMetadata)
240
0
{
241
0
  mMediaInfo = *aMetadata.mInfo;
242
0
  if (!mMediaInfo.HasAudio()) {
243
0
    mDecoderReader->Shutdown();
244
0
    ReportFailureOnMainThread(WebAudioDecodeJob::NoAudio);
245
0
    return;
246
0
  }
247
0
248
0
  nsCString codec;
249
0
  if (!mMediaInfo.mAudio.GetAsAudioInfo()->mMimeType.IsEmpty()) {
250
0
    codec = nsPrintfCString("webaudio; %s", mMediaInfo.mAudio.GetAsAudioInfo()->mMimeType.get());
251
0
  } else {
252
0
    codec = nsPrintfCString("webaudio;resource; %s",
253
0
                            mContainerType.Type().AsString().Data());
254
0
  }
255
0
256
0
  nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction(
257
0
    "MediaDecodeTask::OnMetadataRead", [codec]() -> void {
258
0
      MOZ_ASSERT(!codec.IsEmpty());
259
0
      MOZ_LOG(gMediaDecoderLog,
260
0
              LogLevel::Debug,
261
0
              ("Telemetry (WebAudio) MEDIA_CODEC_USED= '%s'", codec.get()));
262
0
      Telemetry::Accumulate(Telemetry::HistogramID::MEDIA_CODEC_USED, codec);
263
0
    });
264
0
  SystemGroup::Dispatch(TaskCategory::Other, task.forget());
265
0
266
0
  RequestSample();
267
0
}
268
269
void
270
MediaDecodeTask::OnMetadataNotRead(const MediaResult& aReason)
271
0
{
272
0
  mDecoderReader->Shutdown();
273
0
  ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
274
0
}
275
276
void
277
MediaDecodeTask::RequestSample()
278
0
{
279
0
  mDecoderReader->RequestAudioData()->Then(mDecoderReader->OwnerThread(), __func__, this,
280
0
                                           &MediaDecodeTask::SampleDecoded,
281
0
                                           &MediaDecodeTask::SampleNotDecoded);
282
0
}
283
284
void
285
MediaDecodeTask::SampleDecoded(RefPtr<AudioData> aData)
286
0
{
287
0
  MOZ_ASSERT(!NS_IsMainThread());
288
0
  mAudioQueue.Push(aData);
289
0
  if (!mFirstFrameDecoded) {
290
0
    mDecoderReader->ReadUpdatedMetadata(&mMediaInfo);
291
0
    mFirstFrameDecoded = true;
292
0
  }
293
0
  RequestSample();
294
0
}
295
296
void
297
MediaDecodeTask::SampleNotDecoded(const MediaResult& aError)
298
0
{
299
0
  MOZ_ASSERT(!NS_IsMainThread());
300
0
  if (aError == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
301
0
    FinishDecode();
302
0
  } else {
303
0
    mDecoderReader->Shutdown();
304
0
    ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
305
0
  }
306
0
}
307
308
void
309
MediaDecodeTask::FinishDecode()
310
0
{
311
0
  mDecoderReader->Shutdown();
312
0
313
0
  uint32_t frameCount = mAudioQueue.FrameCount();
314
0
  uint32_t channelCount = mMediaInfo.mAudio.mChannels;
315
0
  uint32_t sampleRate = mMediaInfo.mAudio.mRate;
316
0
317
0
  if (!frameCount || !channelCount || !sampleRate) {
318
0
    ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
319
0
    return;
320
0
  }
321
0
322
0
  const uint32_t destSampleRate = mDecodeJob.mContext->SampleRate();
323
0
  AutoResampler resampler;
324
0
325
0
  uint32_t resampledFrames = frameCount;
326
0
  if (sampleRate != destSampleRate) {
327
0
    resampledFrames = static_cast<uint32_t>(
328
0
        static_cast<uint64_t>(destSampleRate) *
329
0
        static_cast<uint64_t>(frameCount) /
330
0
        static_cast<uint64_t>(sampleRate)
331
0
      );
332
0
333
0
    resampler = speex_resampler_init(channelCount,
334
0
                                     sampleRate,
335
0
                                     destSampleRate,
336
0
                                     SPEEX_RESAMPLER_QUALITY_DEFAULT, nullptr);
337
0
    speex_resampler_skip_zeros(resampler);
338
0
    resampledFrames += speex_resampler_get_output_latency(resampler);
339
0
  }
340
0
341
0
  // Allocate contiguous channel buffers.  Note that if we end up resampling,
342
0
  // we may write fewer bytes than mResampledFrames to the output buffer, in
343
0
  // which case writeIndex will tell us how many valid samples we have.
344
0
  mDecodeJob.mBuffer.mChannelData.SetLength(channelCount);
345
0
#if AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_FLOAT32
346
0
  // This buffer has separate channel arrays that could be transferred to
347
0
  // JS_NewArrayBufferWithContents(), but AudioBuffer::RestoreJSChannelData()
348
0
  // does not yet take advantage of this.
349
0
  RefPtr<ThreadSharedFloatArrayBufferList> buffer =
350
0
    ThreadSharedFloatArrayBufferList::
351
0
    Create(channelCount, resampledFrames, fallible);
352
0
  if (!buffer) {
353
0
    ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
354
0
    return;
355
0
  }
356
0
  for (uint32_t i = 0; i < channelCount; ++i) {
357
0
    mDecodeJob.mBuffer.mChannelData[i] = buffer->GetData(i);
358
0
  }
359
#else
360
  RefPtr<SharedBuffer> buffer =
361
    SharedBuffer::Create(sizeof(AudioDataValue) *
362
                         resampledFrames * channelCount);
363
  if (!buffer) {
364
    ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
365
    return;
366
  }
367
  auto data = static_cast<AudioDataValue*>(floatBuffer->Data());
368
  for (uint32_t i = 0; i < channelCount; ++i) {
369
    mDecodeJob.mBuffer.mChannelData[i] = data;
370
    data += resampledFrames;
371
  }
372
#endif
373
  mDecodeJob.mBuffer.mBuffer = buffer.forget();
374
0
  mDecodeJob.mBuffer.mVolume = 1.0f;
375
0
  mDecodeJob.mBuffer.mBufferFormat = AUDIO_OUTPUT_FORMAT;
376
0
377
0
  uint32_t writeIndex = 0;
378
0
  RefPtr<AudioData> audioData;
379
0
  while ((audioData = mAudioQueue.PopFront())) {
380
0
    audioData->EnsureAudioBuffer(); // could lead to a copy :(
381
0
    const AudioDataValue* bufferData = static_cast<AudioDataValue*>
382
0
      (audioData->mAudioBuffer->Data());
383
0
384
0
    if (sampleRate != destSampleRate) {
385
0
      const uint32_t maxOutSamples = resampledFrames - writeIndex;
386
0
387
0
      for (uint32_t i = 0; i < audioData->mChannels; ++i) {
388
0
        uint32_t inSamples = audioData->mFrames;
389
0
        uint32_t outSamples = maxOutSamples;
390
0
        AudioDataValue* outData = mDecodeJob.mBuffer.
391
0
          ChannelDataForWrite<AudioDataValue>(i) + writeIndex;
392
0
393
0
        WebAudioUtils::SpeexResamplerProcess(
394
0
            resampler, i, &bufferData[i * audioData->mFrames], &inSamples,
395
0
            outData, &outSamples);
396
0
397
0
        if (i == audioData->mChannels - 1) {
398
0
          writeIndex += outSamples;
399
0
          MOZ_ASSERT(writeIndex <= resampledFrames);
400
0
          MOZ_ASSERT(inSamples == audioData->mFrames);
401
0
        }
402
0
      }
403
0
    } else {
404
0
      for (uint32_t i = 0; i < audioData->mChannels; ++i) {
405
0
        AudioDataValue* outData = mDecodeJob.mBuffer.
406
0
          ChannelDataForWrite<AudioDataValue>(i) + writeIndex;
407
0
        PodCopy(outData, &bufferData[i * audioData->mFrames],
408
0
                audioData->mFrames);
409
0
410
0
        if (i == audioData->mChannels - 1) {
411
0
          writeIndex += audioData->mFrames;
412
0
        }
413
0
      }
414
0
    }
415
0
  }
416
0
417
0
  if (sampleRate != destSampleRate) {
418
0
    uint32_t inputLatency = speex_resampler_get_input_latency(resampler);
419
0
    const uint32_t maxOutSamples = resampledFrames - writeIndex;
420
0
    for (uint32_t i = 0; i < channelCount; ++i) {
421
0
      uint32_t inSamples = inputLatency;
422
0
      uint32_t outSamples = maxOutSamples;
423
0
      AudioDataValue* outData =
424
0
        mDecodeJob.mBuffer.ChannelDataForWrite<AudioDataValue>(i) + writeIndex;
425
0
426
0
      WebAudioUtils::SpeexResamplerProcess(
427
0
          resampler, i, (AudioDataValue*)nullptr, &inSamples,
428
0
          outData, &outSamples);
429
0
430
0
      if (i == channelCount - 1) {
431
0
        writeIndex += outSamples;
432
0
        MOZ_ASSERT(writeIndex <= resampledFrames);
433
0
        MOZ_ASSERT(inSamples == inputLatency);
434
0
      }
435
0
    }
436
0
  }
437
0
438
0
  mDecodeJob.mBuffer.mDuration = writeIndex;
439
0
  mPhase = PhaseEnum::AllocateBuffer;
440
0
  mMainThread->Dispatch(do_AddRef(this));
441
0
}
442
443
void
444
MediaDecodeTask::AllocateBuffer()
445
0
{
446
0
  MOZ_ASSERT(NS_IsMainThread());
447
0
448
0
  if (!mDecodeJob.AllocateBuffer()) {
449
0
    ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
450
0
    return;
451
0
  }
452
0
453
0
  mPhase = PhaseEnum::Done;
454
0
  CallbackTheResult();
455
0
}
456
457
void
458
MediaDecodeTask::CallbackTheResult()
459
0
{
460
0
  MOZ_ASSERT(NS_IsMainThread());
461
0
462
0
  Cleanup();
463
0
464
0
  // Now, we're ready to call the script back with the resulting buffer
465
0
  mDecodeJob.OnSuccess(WebAudioDecodeJob::NoError);
466
0
}
467
468
bool
469
WebAudioDecodeJob::AllocateBuffer()
470
0
{
471
0
  MOZ_ASSERT(!mOutput);
472
0
  MOZ_ASSERT(NS_IsMainThread());
473
0
474
0
  // Now create the AudioBuffer
475
0
  mOutput = AudioBuffer::Create(mContext->GetOwner(),
476
0
                                mContext->SampleRate(), std::move(mBuffer));
477
0
  return mOutput != nullptr;
478
0
}
479
480
void
481
AsyncDecodeWebAudio(const char* aContentType, uint8_t* aBuffer,
482
                    uint32_t aLength, WebAudioDecodeJob& aDecodeJob)
483
0
{
484
0
  Maybe<MediaContainerType> containerType = MakeMediaContainerType(aContentType);
485
0
  // Do not attempt to decode the media if we were not successful at sniffing
486
0
  // the container type.
487
0
  if (!*aContentType ||
488
0
      strcmp(aContentType, APPLICATION_OCTET_STREAM) == 0 ||
489
0
      !containerType) {
490
0
    nsCOMPtr<nsIRunnable> event =
491
0
      new ReportResultTask(aDecodeJob,
492
0
                           &WebAudioDecodeJob::OnFailure,
493
0
                           WebAudioDecodeJob::UnknownContent);
494
0
    JS_free(nullptr, aBuffer);
495
0
    aDecodeJob.mContext->Dispatch(event.forget());
496
0
    return;
497
0
  }
498
0
499
0
  RefPtr<MediaDecodeTask> task =
500
0
    new MediaDecodeTask(*containerType, aBuffer, aLength, aDecodeJob);
501
0
  if (!task->CreateReader()) {
502
0
    nsCOMPtr<nsIRunnable> event =
503
0
      new ReportResultTask(aDecodeJob,
504
0
                           &WebAudioDecodeJob::OnFailure,
505
0
                           WebAudioDecodeJob::UnknownError);
506
0
    aDecodeJob.mContext->Dispatch(event.forget());
507
0
  } else {
508
0
    // If we did this without a temporary:
509
0
    //   task->Reader()->OwnerThread()->Dispatch(task.forget())
510
0
    // we might evaluate the task.forget() before calling Reader(). Enforce
511
0
    // a non-crashy order-of-operations.
512
0
    TaskQueue* taskQueue = task->Reader()->OwnerThread();
513
0
    nsresult rv = taskQueue->Dispatch(task.forget());
514
0
    MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
515
0
    Unused << rv;
516
0
  }
517
0
}
518
519
WebAudioDecodeJob::WebAudioDecodeJob(AudioContext* aContext,
520
                                     Promise* aPromise,
521
                                     DecodeSuccessCallback* aSuccessCallback,
522
                                     DecodeErrorCallback* aFailureCallback)
523
  : mContext(aContext)
524
  , mPromise(aPromise)
525
  , mSuccessCallback(aSuccessCallback)
526
  , mFailureCallback(aFailureCallback)
527
0
{
528
0
  MOZ_ASSERT(aContext);
529
0
  MOZ_ASSERT(NS_IsMainThread());
530
0
  MOZ_COUNT_CTOR(WebAudioDecodeJob);
531
0
}
532
533
WebAudioDecodeJob::~WebAudioDecodeJob()
534
0
{
535
0
  MOZ_ASSERT(NS_IsMainThread());
536
0
  MOZ_COUNT_DTOR(WebAudioDecodeJob);
537
0
}
538
539
void
540
WebAudioDecodeJob::OnSuccess(ErrorCode aErrorCode)
541
0
{
542
0
  MOZ_ASSERT(NS_IsMainThread());
543
0
  MOZ_ASSERT(aErrorCode == NoError);
544
0
545
0
  if (mSuccessCallback) {
546
0
    ErrorResult rv;
547
0
    mSuccessCallback->Call(*mOutput, rv);
548
0
    // Ignore errors in calling the callback, since there is not much that we can
549
0
    // do about it here.
550
0
    rv.SuppressException();
551
0
  }
552
0
  mPromise->MaybeResolve(mOutput);
553
0
554
0
  mContext->RemoveFromDecodeQueue(this);
555
0
556
0
}
557
558
void
559
WebAudioDecodeJob::OnFailure(ErrorCode aErrorCode)
560
0
{
561
0
  MOZ_ASSERT(NS_IsMainThread());
562
0
563
0
  const char* errorMessage;
564
0
  switch (aErrorCode) {
565
0
  case UnknownContent:
566
0
    errorMessage = "MediaDecodeAudioDataUnknownContentType";
567
0
    break;
568
0
  case InvalidContent:
569
0
    errorMessage = "MediaDecodeAudioDataInvalidContent";
570
0
    break;
571
0
  case NoAudio:
572
0
    errorMessage = "MediaDecodeAudioDataNoAudio";
573
0
    break;
574
0
  case NoError:
575
0
    MOZ_FALLTHROUGH_ASSERT("Who passed NoError to OnFailure?");
576
0
    // Fall through to get some sort of a sane error message if this actually
577
0
    // happens at runtime.
578
0
  case UnknownError:
579
0
    MOZ_FALLTHROUGH;
580
0
  default:
581
0
    errorMessage = "MediaDecodeAudioDataUnknownError";
582
0
    break;
583
0
  }
584
0
585
0
  nsIDocument* doc = nullptr;
586
0
  if (nsPIDOMWindowInner* pWindow = mContext->GetParentObject()) {
587
0
    doc = pWindow->GetExtantDoc();
588
0
  }
589
0
  nsContentUtils::ReportToConsole(nsIScriptError::errorFlag,
590
0
                                  NS_LITERAL_CSTRING("Media"),
591
0
                                  doc,
592
0
                                  nsContentUtils::eDOM_PROPERTIES,
593
0
                                  errorMessage);
594
0
595
0
  // Ignore errors in calling the callback, since there is not much that we can
596
0
  // do about it here.
597
0
  if (mFailureCallback) {
598
0
    nsAutoCString errorString(errorMessage);
599
0
    RefPtr<DOMException> exception =
600
0
      DOMException::Create(NS_ERROR_DOM_ENCODING_NOT_SUPPORTED_ERR,
601
0
                           errorString);
602
0
    mFailureCallback->Call(*exception);
603
0
  }
604
0
605
0
  mPromise->MaybeReject(NS_ERROR_DOM_ENCODING_NOT_SUPPORTED_ERR);
606
0
607
0
  mContext->RemoveFromDecodeQueue(this);
608
0
}
609
610
size_t
611
WebAudioDecodeJob::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
612
0
{
613
0
  size_t amount = 0;
614
0
  if (mSuccessCallback) {
615
0
    amount += mSuccessCallback->SizeOfIncludingThis(aMallocSizeOf);
616
0
  }
617
0
  if (mFailureCallback) {
618
0
    amount += mFailureCallback->SizeOfIncludingThis(aMallocSizeOf);
619
0
  }
620
0
  if (mOutput) {
621
0
    amount += mOutput->SizeOfIncludingThis(aMallocSizeOf);
622
0
  }
623
0
  amount += mBuffer.SizeOfExcludingThis(aMallocSizeOf, false);
624
0
  return amount;
625
0
}
626
627
size_t
628
WebAudioDecodeJob::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
629
0
{
630
0
  return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
631
0
}
632
633
} // namespace mozilla