Skip to content

Commit

Permalink
Bug 1884029 - part1 : run postponed tasks when start running the engi…
Browse files Browse the repository at this point in the history
…ne. r=jolin

Instead of hooking them into the init promise, we can simply store the
runnables and exercute them when the engine is ready for use.

Then we don't need to worry about handling those promises and tracking
promises by using a request holder, which makes thing easier.

As those tasks are not urgent, they can definitely be waited until the
engine is ready.

Differential Revision: https://phabricator.services.mozilla.com/D203862
  • Loading branch information
alastor0325 committed Mar 11, 2024
1 parent c9c92ba commit 0742ceb
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 21 deletions.
62 changes: 41 additions & 21 deletions dom/media/ExternalEngineStateMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,8 @@ RefPtr<ShutdownPromise> ExternalEngineStateMachine::Shutdown() {
mSetCDMProxyPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_ABORT_ERR, __func__);
mSetCDMProxyRequest.DisconnectIfExists();

mPendingTasks.Clear();

mEngine->Shutdown();

auto* state = mState.AsShutdownEngine();
Expand Down Expand Up @@ -607,49 +609,58 @@ void ExternalEngineStateMachine::BufferedRangeUpdated() {
}
}

// Note: the variadic only supports passing member variables.
#define PERFORM_WHEN_ALLOW(Func, ...) \
do { \
/* Initialzation is not done yet, postpone the operation */ \
if ((mState.IsInitEngine() || mState.IsRecoverEngine()) && \
mState.AsInitEngine()->mInitPromise) { \
LOG("%s is called before init", __func__); \
mState.AsInitEngine()->mInitPromise->Then( \
OwnerThread(), __func__, \
[self = RefPtr{this}, this]( \
const GenericNonExclusivePromise::ResolveOrRejectValue& aVal) { \
if (aVal.IsResolve()) { \
Func(__VA_ARGS__); \
} \
}); \
return; \
} else if (mState.IsShutdownEngine()) { \
return; \
} \
#define PERFORM_WHEN_ALLOW(Func) \
do { \
if (mState.IsShutdownEngine()) { \
return; \
} \
/* Initialzation is not done yet, postpone the operation */ \
if ((mState.IsInitEngine() || mState.IsRecoverEngine()) && \
mState.AsInitEngine()->mInitPromise) { \
LOG("%s is called before init", __func__); \
mPendingTasks.AppendElement(NewRunnableMethod( \
__func__, this, &ExternalEngineStateMachine::Func)); \
return; \
} \
} while (false)

void ExternalEngineStateMachine::SetPlaybackRate(double aPlaybackRate) {
AssertOnTaskQueue();
// TODO : consider to make `mPlaybackRate` a mirror to fit other usages like
// `mVolume` and `mPreservesPitch`.
mPlaybackRate = aPlaybackRate;
PERFORM_WHEN_ALLOW(SetPlaybackRate, mPlaybackRate);
mEngine->SetPlaybackRate(aPlaybackRate);
PlaybackRateChanged();
}

void ExternalEngineStateMachine::PlaybackRateChanged() {
AssertOnTaskQueue();
PERFORM_WHEN_ALLOW(PlaybackRateChanged);
MOZ_ASSERT(mState.IsReadingMetadata() || mState.IsRunningEngine() ||
mState.IsSeekingData());
mEngine->SetPlaybackRate(mPlaybackRate);
}

void ExternalEngineStateMachine::VolumeChanged() {
AssertOnTaskQueue();
PERFORM_WHEN_ALLOW(VolumeChanged);
MOZ_ASSERT(mState.IsReadingMetadata() || mState.IsRunningEngine() ||
mState.IsSeekingData());
mEngine->SetVolume(mVolume);
}

void ExternalEngineStateMachine::PreservesPitchChanged() {
AssertOnTaskQueue();
PERFORM_WHEN_ALLOW(PreservesPitchChanged);
MOZ_ASSERT(mState.IsReadingMetadata() || mState.IsRunningEngine() ||
mState.IsSeekingData());
mEngine->SetPreservesPitch(mPreservesPitch);
}

void ExternalEngineStateMachine::PlayStateChanged() {
AssertOnTaskQueue();
PERFORM_WHEN_ALLOW(PlayStateChanged);
MOZ_ASSERT(mState.IsReadingMetadata() || mState.IsRunningEngine() ||
mState.IsSeekingData());
if (mPlayState == MediaDecoder::PLAY_STATE_PLAYING) {
mEngine->Play();
} else if (mPlayState == MediaDecoder::PLAY_STATE_PAUSED) {
Expand All @@ -660,6 +671,8 @@ void ExternalEngineStateMachine::PlayStateChanged() {
void ExternalEngineStateMachine::LoopingChanged() {
AssertOnTaskQueue();
PERFORM_WHEN_ALLOW(LoopingChanged);
MOZ_ASSERT(mState.IsReadingMetadata() || mState.IsRunningEngine() ||
mState.IsSeekingData());
mEngine->SetLooping(mLooping);
}

Expand Down Expand Up @@ -775,6 +788,13 @@ void ExternalEngineStateMachine::StartRunningEngine() {
if (HasVideo()) {
RunningEngineUpdate(MediaData::Type::VIDEO_DATA);
}
// Run tasks which was called before the engine is ready.
if (!mPendingTasks.IsEmpty()) {
for (auto& task : mPendingTasks) {
Unused << OwnerThread()->Dispatch(task.forget());
}
mPendingTasks.Clear();
}
}

void ExternalEngineStateMachine::RunningEngineUpdate(MediaData::Type aType) {
Expand Down
6 changes: 6 additions & 0 deletions dom/media/ExternalEngineStateMachine.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ class ExternalEngineStateMachine final
void PreservesPitchChanged() override;
void PlayStateChanged() override;
void LoopingChanged() override;
void PlaybackRateChanged();

// Not supported.
void SetIsLiveStream(bool aIsLiveStream) override {}
Expand Down Expand Up @@ -311,6 +312,11 @@ class ExternalEngineStateMachine final

// It would be set if playback is encrypted.
nsCString mKeySystem;

// This array stores the tasks which needs to be executed only after the
// engine is ready but is called before that. It will be executed when
// starting running the engine.
nsTArray<RefPtr<nsIRunnable>> mPendingTasks;
};

class ExternalPlaybackEngine {
Expand Down

0 comments on commit 0742ceb

Please sign in to comment.