зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
c56eb8ef3c
Коммит
f181df10f9
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче