Bug 1653638 - P2. Use a Controller TaskQueue for running webaudio tasks. r=mjf

We can't create a media decoder on a decoder taskqueue, as this could lead to deadlocks should a decoder attempt to dispatch a synchronous runnable.

Differential Revision: https://phabricator.services.mozilla.com/D85544
This commit is contained in:
Jean-Yves Avenard 2020-08-03 08:01:09 +00:00
Родитель c56eb8ef3c
Коммит f181df10f9
1 изменённых файлов: 58 добавлений и 49 удалений

Просмотреть файл

@ -5,35 +5,37 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "MediaBufferDecoder.h"
#include "mozilla/dom/AudioContextBinding.h"
#include "mozilla/dom/BaseAudioContextBinding.h"
#include "mozilla/dom/DOMException.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/AbstractThread.h"
#include "mozilla/StaticPrefs_media.h"
#include <speex/speex_resampler.h>
#include "nsXPCOMCIDInternal.h"
#include "nsComponentManagerUtils.h"
#include "MediaQueue.h"
#include "AudioBuffer.h"
#include "AudioContext.h"
#include "AudioNodeEngine.h"
#include "BufferMediaResource.h"
#include "DecoderTraits.h"
#include "AudioContext.h"
#include "AudioBuffer.h"
#include "js/MemoryFunctions.h"
#include "MediaContainerType.h"
#include "MediaDataDemuxer.h"
#include "nsContentUtils.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsIScriptError.h"
#include "nsMimeTypes.h"
#include "MediaQueue.h"
#include "PDMFactory.h"
#include "VideoUtils.h"
#include "WebAudioUtils.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/Telemetry.h"
#include "js/MemoryFunctions.h"
#include "mozilla/AbstractThread.h"
#include "mozilla/Logging.h"
#include "mozilla/StaticPrefs_media.h"
#include "mozilla/Telemetry.h"
#include "mozilla/dom/AudioContextBinding.h"
#include "mozilla/dom/BaseAudioContextBinding.h"
#include "mozilla/dom/DOMException.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ScriptSettings.h"
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
#include "nsIScriptError.h"
#include "nsIScriptObjectPrincipal.h"
#include "nsMimeTypes.h"
#include "nsPrintfCString.h"
#include "AudioNodeEngine.h"
#include "nsXPCOMCIDInternal.h"
namespace mozilla {
@ -96,8 +98,10 @@ class MediaDecodeTask final : public Runnable {
MOZ_CAN_RUN_SCRIPT_BOUNDARY
NS_IMETHOD Run() override;
bool Init();
TaskQueue* PDecoderTaskQueue() { return mPDecoderTaskQueue; }
bool OnPDecoderTaskQueue() { return mPDecoderTaskQueue->IsCurrentThreadIn(); }
TaskQueue* PControllerTaskQueue() { return mPControllerTaskQueue; }
bool OnPControllerTaskQueue() const {
return mPControllerTaskQueue->IsCurrentThreadIn();
}
private:
MOZ_CAN_RUN_SCRIPT
@ -154,6 +158,7 @@ class MediaDecodeTask final : public Runnable {
}
mTrackDemuxer = nullptr;
mDemuxer = nullptr;
mPControllerTaskQueue = nullptr;
mPDecoderTaskQueue = nullptr;
}
@ -164,6 +169,7 @@ class MediaDecodeTask final : public Runnable {
const uint32_t mBatchSize;
WebAudioDecodeJob& mDecodeJob;
PhaseEnum mPhase;
RefPtr<TaskQueue> mPControllerTaskQueue;
RefPtr<TaskQueue> mPDecoderTaskQueue;
RefPtr<MediaDataDemuxer> mDemuxer;
RefPtr<MediaTrackDemuxer> mTrackDemuxer;
@ -199,6 +205,9 @@ bool MediaDecodeTask::Init() {
mMainThread = mDecodeJob.mContext->GetOwnerGlobal()->AbstractMainThreadFor(
TaskCategory::Other);
mPControllerTaskQueue =
new TaskQueue(GetMediaThreadPool(MediaThreadType::CONTROLLER),
"MediaBufferDecoder::mPControllerTaskQueue");
mPDecoderTaskQueue =
new TaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
"MediaBufferDecoder::mPDecoderTaskQueue");
@ -232,16 +241,15 @@ class AutoResampler final {
};
void MediaDecodeTask::Decode() {
MOZ_ASSERT(!NS_IsMainThread());
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
mDemuxer->Init()->Then(PDecoderTaskQueue(), __func__, this,
mDemuxer->Init()->Then(PControllerTaskQueue(), __func__, this,
&MediaDecodeTask::OnInitDemuxerCompleted,
&MediaDecodeTask::OnInitDemuxerFailed);
}
void MediaDecodeTask::OnInitDemuxerCompleted() {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
if (!!mDemuxer->GetNumberTracks(TrackInfo::kAudioTrack)) {
mTrackDemuxer = mDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
@ -269,14 +277,14 @@ void MediaDecodeTask::OnInitDemuxerCompleted() {
}
void MediaDecodeTask::OnInitDemuxerFailed(const MediaResult& aError) {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
LOG("MediaDecodeTask: Could not initialize the demuxer.");
ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
}
MediaResult MediaDecodeTask::CreateDecoder(const AudioInfo& info) {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
RefPtr<PDMFactory> pdm = new PDMFactory();
// result may not be updated by PDMFactory::CreateDecoder, as such it must be
@ -298,21 +306,21 @@ MediaResult MediaDecodeTask::CreateDecoder(const AudioInfo& info) {
}
void MediaDecodeTask::InitDecoder() {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
mDecoder->Init()->Then(PDecoderTaskQueue(), __func__, this,
mDecoder->Init()->Then(PControllerTaskQueue(), __func__, this,
&MediaDecodeTask::OnInitDecoderCompleted,
&MediaDecodeTask::OnInitDecoderFailed);
}
void MediaDecodeTask::OnInitDecoderCompleted() {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
DoDemux();
}
void MediaDecodeTask::OnInitDecoderFailed() {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
ShutdownDecoder();
LOG("MediaDecodeTask: Could not initialize the decoder");
@ -320,17 +328,17 @@ void MediaDecodeTask::OnInitDecoderFailed() {
}
void MediaDecodeTask::DoDemux() {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
mTrackDemuxer->GetSamples(mBatchSize)
->Then(PDecoderTaskQueue(), __func__, this,
->Then(PControllerTaskQueue(), __func__, this,
&MediaDecodeTask::OnAudioDemuxCompleted,
&MediaDecodeTask::OnAudioDemuxFailed);
}
void MediaDecodeTask::OnAudioDemuxCompleted(
RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
mRawSamples.AppendElements(aSamples->GetSamples());
@ -338,7 +346,7 @@ void MediaDecodeTask::OnAudioDemuxCompleted(
}
void MediaDecodeTask::OnAudioDemuxFailed(const MediaResult& aError) {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
if (aError.Code() == NS_ERROR_DOM_MEDIA_END_OF_STREAM) {
DoDecode();
@ -350,7 +358,7 @@ void MediaDecodeTask::OnAudioDemuxFailed(const MediaResult& aError) {
}
void MediaDecodeTask::DoDecode() {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
if (mRawSamples.IsEmpty()) {
DoDrain();
@ -366,7 +374,7 @@ void MediaDecodeTask::DoDecode() {
}
mDecoder->DecodeBatch(std::move(rawSampleBatch))
->Then(PDecoderTaskQueue(), __func__, this,
->Then(PControllerTaskQueue(), __func__, this,
&MediaDecodeTask::OnAudioDecodeCompleted,
&MediaDecodeTask::OnAudioDecodeFailed);
@ -374,7 +382,7 @@ void MediaDecodeTask::DoDecode() {
} else {
RefPtr<MediaRawData> sample = std::move(mRawSamples[0]);
mDecoder->Decode(sample)->Then(PDecoderTaskQueue(), __func__, this,
mDecoder->Decode(sample)->Then(PControllerTaskQueue(), __func__, this,
&MediaDecodeTask::OnAudioDecodeCompleted,
&MediaDecodeTask::OnAudioDecodeFailed);
@ -384,7 +392,7 @@ void MediaDecodeTask::DoDecode() {
void MediaDecodeTask::OnAudioDecodeCompleted(
MediaDataDecoder::DecodedData&& aResults) {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
for (auto&& sample : aResults) {
MOZ_ASSERT(sample->mType == MediaData::Type::AUDIO_DATA);
@ -400,7 +408,7 @@ void MediaDecodeTask::OnAudioDecodeCompleted(
}
void MediaDecodeTask::OnAudioDecodeFailed(const MediaResult& aError) {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
ShutdownDecoder();
LOG("MediaDecodeTask: decode audio failed.");
@ -408,16 +416,16 @@ void MediaDecodeTask::OnAudioDecodeFailed(const MediaResult& aError) {
}
void MediaDecodeTask::DoDrain() {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
mDecoder->Drain()->Then(PDecoderTaskQueue(), __func__, this,
mDecoder->Drain()->Then(PControllerTaskQueue(), __func__, this,
&MediaDecodeTask::OnAudioDrainCompleted,
&MediaDecodeTask::OnAudioDrainFailed);
}
void MediaDecodeTask::OnAudioDrainCompleted(
MediaDataDecoder::DecodedData&& aResults) {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
if (aResults.IsEmpty()) {
FinishDecode();
@ -434,7 +442,7 @@ void MediaDecodeTask::OnAudioDrainCompleted(
}
void MediaDecodeTask::OnAudioDrainFailed(const MediaResult& aError) {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
ShutdownDecoder();
LOG("MediaDecodeTask: Drain audio failed");
@ -442,7 +450,7 @@ void MediaDecodeTask::OnAudioDrainFailed(const MediaResult& aError) {
}
void MediaDecodeTask::ShutdownDecoder() {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
if (!mDecoder) {
return;
@ -454,7 +462,7 @@ void MediaDecodeTask::ShutdownDecoder() {
}
void MediaDecodeTask::FinishDecode() {
MOZ_ASSERT(OnPDecoderTaskQueue());
MOZ_ASSERT(OnPControllerTaskQueue());
ShutdownDecoder();
@ -649,10 +657,11 @@ void AsyncDecodeWebAudio(const char* aContentType, uint8_t* aBuffer,
aDecodeJob.mContext->Dispatch(event.forget());
} else {
// If we did this without a temporary:
// task->PDecoderTaskQueue()->Dispatch(task.forget())
// we might evaluate the task.forget() before calling PDecoderTaskQueue().
// task->PControllerTaskQueue()->Dispatch(task.forget())
// we might evaluate the task.forget() before calling
// OnPControllerTaskQueue().
// Enforce a non-crashy order-of-operations.
TaskQueue* taskQueue = task->PDecoderTaskQueue();
TaskQueue* taskQueue = task->PControllerTaskQueue();
nsresult rv = taskQueue->Dispatch(task.forget());
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
Unused << rv;