mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 08:45:46 +00:00
Bug 1586903 - Wait for track listener removals rather than just informing them of shutdown. r=bryce
This does a bit of a cleanup, where changing the notification to waiting for removal is the major task. It also removes the special handling of not informing listeners of shutdown on Cancel(), and a bit of cleanup around MozPromise usage. Differential Revision: https://phabricator.services.mozilla.com/D49416 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
8df4803118
commit
c8ebc1f3f9
@ -1267,25 +1267,26 @@ class MediaRecorder::Session : public PrincipalChangeObserver<MediaStreamTrack>,
|
||||
timeDelta.ToSeconds());
|
||||
|
||||
mShutdownPromise = ShutdownPromise::CreateAndResolve(true, __func__);
|
||||
RefPtr<Session> self = this;
|
||||
|
||||
if (mEncoder) {
|
||||
auto& encoder = mEncoder;
|
||||
encoder->Cancel();
|
||||
|
||||
MOZ_RELEASE_ASSERT(mEncoderListener);
|
||||
auto& encoderListener = mEncoderListener;
|
||||
mShutdownPromise = mShutdownPromise->Then(
|
||||
mEncoderThread, __func__,
|
||||
[encoder, encoderListener]() {
|
||||
encoder->UnregisterListener(encoderListener);
|
||||
encoderListener->Forget();
|
||||
return ShutdownPromise::CreateAndResolve(true, __func__);
|
||||
},
|
||||
[]() {
|
||||
MOZ_ASSERT_UNREACHABLE("Unexpected reject");
|
||||
return ShutdownPromise::CreateAndReject(false, __func__);
|
||||
});
|
||||
mShutdownPromise =
|
||||
mShutdownPromise
|
||||
->Then(mEncoderThread, __func__,
|
||||
[encoder = mEncoder, encoderListener = mEncoderListener] {
|
||||
// Unregister the listener before canceling so that we
|
||||
// don't get the Shutdown notification from Cancel().
|
||||
encoder->UnregisterListener(encoderListener);
|
||||
encoderListener->Forget();
|
||||
return ShutdownPromise::CreateAndResolve(true, __func__);
|
||||
})
|
||||
->Then(mMainThread, __func__,
|
||||
[encoder = mEncoder] { return encoder->Cancel(); })
|
||||
->Then(mEncoderThread, __func__, [] {
|
||||
// Meh, this is just to convert the promise type to match
|
||||
// mShutdownPromise.
|
||||
return ShutdownPromise::CreateAndResolve(true, __func__);
|
||||
});
|
||||
}
|
||||
|
||||
// Remove main thread state. This could be needed if Stop() wasn't called.
|
||||
@ -1303,8 +1304,8 @@ class MediaRecorder::Session : public PrincipalChangeObserver<MediaStreamTrack>,
|
||||
|
||||
// Break the cycle reference between Session and MediaRecorder.
|
||||
mShutdownPromise = mShutdownPromise->Then(
|
||||
GetCurrentThreadSerialEventTarget(), __func__,
|
||||
[self]() {
|
||||
mMainThread, __func__,
|
||||
[self = RefPtr<Session>(this)]() {
|
||||
self->mRecorder->RemoveSession(self);
|
||||
return ShutdownPromise::CreateAndResolve(true, __func__);
|
||||
},
|
||||
@ -1314,10 +1315,11 @@ class MediaRecorder::Session : public PrincipalChangeObserver<MediaStreamTrack>,
|
||||
});
|
||||
|
||||
if (mEncoderThread) {
|
||||
RefPtr<TaskQueue>& encoderThread = mEncoderThread;
|
||||
mShutdownPromise = mShutdownPromise->Then(
|
||||
GetCurrentThreadSerialEventTarget(), __func__,
|
||||
[encoderThread]() { return encoderThread->BeginShutdown(); },
|
||||
mMainThread, __func__,
|
||||
[encoderThread = mEncoderThread]() {
|
||||
return encoderThread->BeginShutdown();
|
||||
},
|
||||
[]() {
|
||||
MOZ_ASSERT_UNREACHABLE("Unexpected reject");
|
||||
return ShutdownPromise::CreateAndReject(false, __func__);
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include "mozilla/dom/VideoStreamTrack.h"
|
||||
#include "mozilla/gfx/Point.h" // IntSize
|
||||
#include "mozilla/Logging.h"
|
||||
#include "mozilla/media/MediaUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StaticPrefs_media.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
@ -56,13 +55,12 @@ class MediaEncoder::AudioTrackListener : public DirectMediaTrackListener {
|
||||
mRemoved(false),
|
||||
mDriftCompensator(aDriftCompensator),
|
||||
mEncoder(aEncoder),
|
||||
mEncoderThread(aEncoderThread) {
|
||||
mEncoderThread(aEncoderThread),
|
||||
mShutdownPromise(mShutdownHolder.Ensure(__func__)) {
|
||||
MOZ_ASSERT(mEncoder);
|
||||
MOZ_ASSERT(mEncoderThread);
|
||||
}
|
||||
|
||||
void NotifyShutdown() { mShutdown = true; }
|
||||
|
||||
void NotifyDirectListenerInstalled(InstallationResult aResult) override {
|
||||
if (aResult == InstallationResult::SUCCESS) {
|
||||
LOG(LogLevel::Info, ("Audio track direct listener installed"));
|
||||
@ -88,10 +86,6 @@ class MediaEncoder::AudioTrackListener : public DirectMediaTrackListener {
|
||||
MOZ_ASSERT(mEncoder);
|
||||
MOZ_ASSERT(mEncoderThread);
|
||||
|
||||
if (mShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mInitialized) {
|
||||
mDriftCompensator->NotifyAudioStart(TimeStamp::Now());
|
||||
mInitialized = true;
|
||||
@ -116,10 +110,6 @@ class MediaEncoder::AudioTrackListener : public DirectMediaTrackListener {
|
||||
MOZ_ASSERT(mEncoder);
|
||||
MOZ_ASSERT(mEncoderThread);
|
||||
|
||||
if (mShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = mEncoderThread->Dispatch(
|
||||
NewRunnableMethod("mozilla::AudioTrackEncoder::NotifyEndOfStream",
|
||||
mEncoder, &AudioTrackEncoder::NotifyEndOfStream));
|
||||
@ -128,13 +118,11 @@ class MediaEncoder::AudioTrackListener : public DirectMediaTrackListener {
|
||||
}
|
||||
|
||||
void NotifyRemoved(MediaTrackGraph* aGraph) override {
|
||||
if (!mShutdown) {
|
||||
nsresult rv = mEncoderThread->Dispatch(
|
||||
NewRunnableMethod("mozilla::AudioTrackEncoder::NotifyEndOfStream",
|
||||
mEncoder, &AudioTrackEncoder::NotifyEndOfStream));
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||
Unused << rv;
|
||||
}
|
||||
nsresult rv = mEncoderThread->Dispatch(
|
||||
NewRunnableMethod("mozilla::AudioTrackEncoder::NotifyEndOfStream",
|
||||
mEncoder, &AudioTrackEncoder::NotifyEndOfStream));
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||
Unused << rv;
|
||||
|
||||
mRemoved = true;
|
||||
|
||||
@ -142,17 +130,23 @@ class MediaEncoder::AudioTrackListener : public DirectMediaTrackListener {
|
||||
mEncoder = nullptr;
|
||||
mEncoderThread = nullptr;
|
||||
}
|
||||
|
||||
mShutdownHolder.Resolve(true, __func__);
|
||||
}
|
||||
|
||||
const RefPtr<GenericNonExclusivePromise>& OnShutdown() const {
|
||||
return mShutdownPromise;
|
||||
}
|
||||
|
||||
private:
|
||||
// True when MediaEncoder has shutdown and destroyed the TaskQueue.
|
||||
Atomic<bool> mShutdown;
|
||||
bool mDirectConnected;
|
||||
bool mInitialized;
|
||||
bool mRemoved;
|
||||
const RefPtr<DriftCompensator> mDriftCompensator;
|
||||
RefPtr<AudioTrackEncoder> mEncoder;
|
||||
RefPtr<TaskQueue> mEncoderThread;
|
||||
MozPromiseHolder<GenericNonExclusivePromise> mShutdownHolder;
|
||||
const RefPtr<GenericNonExclusivePromise> mShutdownPromise;
|
||||
};
|
||||
|
||||
class MediaEncoder::VideoTrackListener : public DirectMediaTrackListener {
|
||||
@ -162,13 +156,12 @@ class MediaEncoder::VideoTrackListener : public DirectMediaTrackListener {
|
||||
mInitialized(false),
|
||||
mRemoved(false),
|
||||
mEncoder(aEncoder),
|
||||
mEncoderThread(aEncoderThread) {
|
||||
mEncoderThread(aEncoderThread),
|
||||
mShutdownPromise(mShutdownHolder.Ensure(__func__)) {
|
||||
MOZ_ASSERT(mEncoder);
|
||||
MOZ_ASSERT(mEncoderThread);
|
||||
}
|
||||
|
||||
void NotifyShutdown() { mShutdown = true; }
|
||||
|
||||
void NotifyDirectListenerInstalled(InstallationResult aResult) override {
|
||||
if (aResult == InstallationResult::SUCCESS) {
|
||||
LOG(LogLevel::Info, ("Video track direct listener installed"));
|
||||
@ -195,10 +188,6 @@ class MediaEncoder::VideoTrackListener : public DirectMediaTrackListener {
|
||||
MOZ_ASSERT(mEncoder);
|
||||
MOZ_ASSERT(mEncoderThread);
|
||||
|
||||
if (mShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
const TimeStamp now = TimeStamp::Now();
|
||||
if (!mInitialized) {
|
||||
nsresult rv = mEncoderThread->Dispatch(NewRunnableMethod<TimeStamp>(
|
||||
@ -223,10 +212,6 @@ class MediaEncoder::VideoTrackListener : public DirectMediaTrackListener {
|
||||
MOZ_ASSERT(mEncoderThread);
|
||||
MOZ_ASSERT(aMedia.GetType() == MediaSegment::VIDEO);
|
||||
|
||||
if (mShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
const VideoSegment& video = static_cast<const VideoSegment&>(aMedia);
|
||||
VideoSegment copy;
|
||||
for (VideoSegment::ConstChunkIterator iter(video); !iter.IsEnded();
|
||||
@ -250,10 +235,6 @@ class MediaEncoder::VideoTrackListener : public DirectMediaTrackListener {
|
||||
MOZ_ASSERT(mEncoder);
|
||||
MOZ_ASSERT(mEncoderThread);
|
||||
|
||||
if (mShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
if (aEnabled) {
|
||||
rv = mEncoderThread->Dispatch(NewRunnableMethod<TimeStamp>(
|
||||
@ -272,10 +253,6 @@ class MediaEncoder::VideoTrackListener : public DirectMediaTrackListener {
|
||||
MOZ_ASSERT(mEncoder);
|
||||
MOZ_ASSERT(mEncoderThread);
|
||||
|
||||
if (mShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv = mEncoderThread->Dispatch(
|
||||
NewRunnableMethod("mozilla::VideoTrackEncoder::NotifyEndOfStream",
|
||||
mEncoder, &VideoTrackEncoder::NotifyEndOfStream));
|
||||
@ -284,13 +261,11 @@ class MediaEncoder::VideoTrackListener : public DirectMediaTrackListener {
|
||||
}
|
||||
|
||||
void NotifyRemoved(MediaTrackGraph* aGraph) override {
|
||||
if (!mShutdown) {
|
||||
nsresult rv = mEncoderThread->Dispatch(
|
||||
NewRunnableMethod("mozilla::VideoTrackEncoder::NotifyEndOfStream",
|
||||
mEncoder, &VideoTrackEncoder::NotifyEndOfStream));
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||
Unused << rv;
|
||||
}
|
||||
nsresult rv = mEncoderThread->Dispatch(
|
||||
NewRunnableMethod("mozilla::VideoTrackEncoder::NotifyEndOfStream",
|
||||
mEncoder, &VideoTrackEncoder::NotifyEndOfStream));
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||
Unused << rv;
|
||||
|
||||
mRemoved = true;
|
||||
|
||||
@ -298,16 +273,22 @@ class MediaEncoder::VideoTrackListener : public DirectMediaTrackListener {
|
||||
mEncoder = nullptr;
|
||||
mEncoderThread = nullptr;
|
||||
}
|
||||
|
||||
mShutdownHolder.Resolve(true, __func__);
|
||||
}
|
||||
|
||||
const RefPtr<GenericNonExclusivePromise>& OnShutdown() const {
|
||||
return mShutdownPromise;
|
||||
}
|
||||
|
||||
private:
|
||||
// True when MediaEncoder has shutdown and destroyed the TaskQueue.
|
||||
Atomic<bool> mShutdown;
|
||||
bool mDirectConnected;
|
||||
bool mInitialized;
|
||||
bool mRemoved;
|
||||
RefPtr<VideoTrackEncoder> mEncoder;
|
||||
RefPtr<TaskQueue> mEncoderThread;
|
||||
MozPromiseHolder<GenericNonExclusivePromise> mShutdownHolder;
|
||||
const RefPtr<GenericNonExclusivePromise> mShutdownPromise;
|
||||
};
|
||||
|
||||
class MediaEncoder::EncoderListener : public TrackEncoderListener {
|
||||
@ -404,7 +385,6 @@ MediaEncoder::MediaEncoder(TaskQueue* aEncoderThread,
|
||||
mInitialized(false),
|
||||
mCompleted(false),
|
||||
mError(false),
|
||||
mCanceled(false),
|
||||
mShutdown(false) {
|
||||
if (mAudioEncoder) {
|
||||
mAudioListener = MakeAndAddRef<AudioTrackListener>(
|
||||
@ -778,43 +758,45 @@ nsresult MediaEncoder::GetEncodedData(
|
||||
return rv;
|
||||
}
|
||||
|
||||
void MediaEncoder::Shutdown() {
|
||||
RefPtr<GenericNonExclusivePromise> MediaEncoder::Shutdown() {
|
||||
MOZ_ASSERT(mEncoderThread->IsCurrentThreadIn());
|
||||
if (mShutdown) {
|
||||
return;
|
||||
if (mShutdownPromise) {
|
||||
return mShutdownPromise;
|
||||
}
|
||||
mShutdown = true;
|
||||
|
||||
LOG(LogLevel::Info, ("MediaEncoder has been shut down."));
|
||||
LOG(LogLevel::Info, ("MediaEncoder is shutting down."));
|
||||
if (mAudioEncoder) {
|
||||
mAudioEncoder->UnregisterListener(mEncoderListener);
|
||||
}
|
||||
if (mAudioListener) {
|
||||
mAudioListener->NotifyShutdown();
|
||||
}
|
||||
if (mVideoEncoder) {
|
||||
mVideoEncoder->UnregisterListener(mEncoderListener);
|
||||
}
|
||||
if (mVideoListener) {
|
||||
mVideoListener->NotifyShutdown();
|
||||
}
|
||||
mEncoderListener->Forget();
|
||||
|
||||
if (mCanceled) {
|
||||
// Shutting down after being canceled. We cannot use the encoder thread.
|
||||
return;
|
||||
AutoTArray<RefPtr<GenericNonExclusivePromise>, 2> shutdownPromises;
|
||||
if (mAudioListener) {
|
||||
shutdownPromises.AppendElement(mAudioListener->OnShutdown());
|
||||
}
|
||||
if (mVideoListener) {
|
||||
shutdownPromises.AppendElement(mVideoListener->OnShutdown());
|
||||
}
|
||||
|
||||
auto listeners(mListeners);
|
||||
for (auto& l : listeners) {
|
||||
// We dispatch here since this method is typically called from
|
||||
// a DataAvailable() handler.
|
||||
nsresult rv = mEncoderThread->Dispatch(
|
||||
NewRunnableMethod("mozilla::MediaEncoderListener::Shutdown", l,
|
||||
&MediaEncoderListener::Shutdown));
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||
Unused << rv;
|
||||
}
|
||||
return mShutdownPromise =
|
||||
GenericNonExclusivePromise::All(mEncoderThread, shutdownPromises)
|
||||
->Then(mEncoderThread, __func__,
|
||||
[self = RefPtr<MediaEncoder>(this), this](
|
||||
const GenericNonExclusivePromise::AllPromiseType::
|
||||
ResolveOrRejectValue& aValue) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(aValue.IsResolve());
|
||||
LOG(LogLevel::Info, ("MediaEncoder has shut down."));
|
||||
mShutdown = true;
|
||||
auto listeners(mListeners);
|
||||
for (auto& l : listeners) {
|
||||
l->Shutdown();
|
||||
}
|
||||
return GenericNonExclusivePromise::CreateAndResolve(
|
||||
true, __func__);
|
||||
});
|
||||
}
|
||||
|
||||
bool MediaEncoder::IsShutdown() {
|
||||
@ -822,26 +804,21 @@ bool MediaEncoder::IsShutdown() {
|
||||
return mShutdown;
|
||||
}
|
||||
|
||||
void MediaEncoder::Cancel() {
|
||||
RefPtr<GenericNonExclusivePromise> MediaEncoder::Cancel() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
Stop();
|
||||
|
||||
RefPtr<MediaEncoder> self = this;
|
||||
nsresult rv = mEncoderThread->Dispatch(NewRunnableFrom([self]() mutable {
|
||||
self->mCanceled = true;
|
||||
|
||||
if (self->mAudioEncoder) {
|
||||
self->mAudioEncoder->Cancel();
|
||||
}
|
||||
if (self->mVideoEncoder) {
|
||||
self->mVideoEncoder->Cancel();
|
||||
}
|
||||
self->Shutdown();
|
||||
return NS_OK;
|
||||
}));
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||
Unused << rv;
|
||||
return InvokeAsync(mEncoderThread, __func__,
|
||||
[self = RefPtr<MediaEncoder>(this), this]() {
|
||||
if (mAudioEncoder) {
|
||||
mAudioEncoder->Cancel();
|
||||
}
|
||||
if (mVideoEncoder) {
|
||||
mVideoEncoder->Cancel();
|
||||
}
|
||||
return Shutdown();
|
||||
});
|
||||
}
|
||||
|
||||
bool MediaEncoder::HasError() {
|
||||
|
@ -175,9 +175,8 @@ class MediaEncoder {
|
||||
|
||||
/**
|
||||
* Cancels the encoding and shuts down the encoder using Shutdown().
|
||||
* Listeners are not notified of the shutdown.
|
||||
*/
|
||||
void Cancel();
|
||||
RefPtr<GenericNonExclusivePromise> Cancel();
|
||||
|
||||
bool HasError();
|
||||
|
||||
@ -240,7 +239,7 @@ class MediaEncoder {
|
||||
* Shuts down the MediaEncoder and cleans up track encoders.
|
||||
* Listeners will be notified of the shutdown unless we were Cancel()ed first.
|
||||
*/
|
||||
void Shutdown();
|
||||
RefPtr<GenericNonExclusivePromise> Shutdown();
|
||||
|
||||
/**
|
||||
* Sets mError to true, notifies listeners of the error if mError changed,
|
||||
@ -283,8 +282,9 @@ class MediaEncoder {
|
||||
bool mInitialized;
|
||||
bool mCompleted;
|
||||
bool mError;
|
||||
bool mCanceled;
|
||||
bool mShutdown;
|
||||
// Set when shutdown starts.
|
||||
RefPtr<GenericNonExclusivePromise> mShutdownPromise;
|
||||
// Get duration from create encoder, for logging purpose
|
||||
double GetEncodeTimeStamp() {
|
||||
TimeDuration decodeTime;
|
||||
|
Loading…
Reference in New Issue
Block a user