LCOV - code coverage report
Current view: top level - dom/media/webaudio - MediaBufferDecoder.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 286 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 36 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13