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:
Andreas Pehrson 2019-10-17 09:31:07 +00:00
Родитель 8df4803118
Коммит c8ebc1f3f9
3 изменённых файлов: 94 добавлений и 115 удалений

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

@ -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;