зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1500049 - Wait for MediaCacheStreams to close properly before finishing MediaDecoder shutdown. r=bryce
Differential Revision: https://phabricator.services.mozilla.com/D52052 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
b59f1080f0
Коммит
4c3bf72271
|
@ -221,13 +221,27 @@ void ChannelMediaDecoder::Shutdown() {
|
||||||
mResourceCallback->Disconnect();
|
mResourceCallback->Disconnect();
|
||||||
MediaDecoder::Shutdown();
|
MediaDecoder::Shutdown();
|
||||||
|
|
||||||
// Force any outstanding seek and byterange requests to complete
|
|
||||||
// to prevent shutdown from deadlocking.
|
|
||||||
if (mResource) {
|
if (mResource) {
|
||||||
mResource->Close();
|
// Force any outstanding seek and byterange requests to complete
|
||||||
|
// to prevent shutdown from deadlocking.
|
||||||
|
mResourceClosePromise = mResource->Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChannelMediaDecoder::ShutdownInternal() {
|
||||||
|
if (!mResourceClosePromise) {
|
||||||
|
MediaShutdownManager::Instance().Unregister(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mResourceClosePromise->Then(
|
||||||
|
AbstractMainThread(), __func__,
|
||||||
|
[self = RefPtr<ChannelMediaDecoder>(this)] {
|
||||||
|
MediaShutdownManager::Instance().Unregister(self);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult ChannelMediaDecoder::Load(nsIChannel* aChannel,
|
nsresult ChannelMediaDecoder::Load(nsIChannel* aChannel,
|
||||||
bool aIsPrivateBrowsing,
|
bool aIsPrivateBrowsing,
|
||||||
nsIStreamListener** aStreamListener) {
|
nsIStreamListener** aStreamListener) {
|
||||||
|
|
|
@ -59,6 +59,7 @@ class ChannelMediaDecoder
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
void ShutdownInternal() override;
|
||||||
void OnPlaybackEvent(MediaPlaybackEvent&& aEvent) override;
|
void OnPlaybackEvent(MediaPlaybackEvent&& aEvent) override;
|
||||||
void DurationChanged() override;
|
void DurationChanged() override;
|
||||||
void MetadataLoaded(UniquePtr<MediaInfo> aInfo, UniquePtr<MetadataTags> aTags,
|
void MetadataLoaded(UniquePtr<MediaInfo> aInfo, UniquePtr<MetadataTags> aTags,
|
||||||
|
@ -156,6 +157,10 @@ class ChannelMediaDecoder
|
||||||
// True if we've been notified that the ChannelMediaResource has
|
// True if we've been notified that the ChannelMediaResource has
|
||||||
// a principal.
|
// a principal.
|
||||||
bool mInitialChannelPrincipalKnown = false;
|
bool mInitialChannelPrincipalKnown = false;
|
||||||
|
|
||||||
|
// Set in Shutdown() when we start closing mResource, if mResource is set.
|
||||||
|
// Must resolve before we unregister the shutdown blocker.
|
||||||
|
RefPtr<GenericPromise> mResourceClosePromise;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -589,15 +589,15 @@ nsresult ChannelMediaResource::SetupChannelHeaders(int64_t aOffset) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult ChannelMediaResource::Close() {
|
RefPtr<GenericPromise> ChannelMediaResource::Close() {
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||||
|
|
||||||
if (!mClosed) {
|
if (!mClosed) {
|
||||||
CloseChannel();
|
CloseChannel();
|
||||||
mCacheStream.Close();
|
|
||||||
mClosed = true;
|
mClosed = true;
|
||||||
|
return mCacheStream.Close();
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return GenericPromise::CreateAndResolve(true, __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIPrincipal> ChannelMediaResource::GetCurrentPrincipal() {
|
already_AddRefed<nsIPrincipal> ChannelMediaResource::GetCurrentPrincipal() {
|
||||||
|
|
|
@ -117,7 +117,7 @@ class ChannelMediaResource
|
||||||
|
|
||||||
// Main thread
|
// Main thread
|
||||||
nsresult Open(nsIStreamListener** aStreamListener) override;
|
nsresult Open(nsIStreamListener** aStreamListener) override;
|
||||||
nsresult Close() override;
|
RefPtr<GenericPromise> Close() override;
|
||||||
void Suspend(bool aCloseImmediately) override;
|
void Suspend(bool aCloseImmediately) override;
|
||||||
void Resume() override;
|
void Resume() override;
|
||||||
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
|
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
|
||||||
|
|
|
@ -148,7 +148,9 @@ nsresult CloneableWithRangeMediaResource::Open(
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult CloneableWithRangeMediaResource::Close() { return NS_OK; }
|
RefPtr<GenericPromise> CloneableWithRangeMediaResource::Close() {
|
||||||
|
return GenericPromise::CreateAndResolve(true, __func__);
|
||||||
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIPrincipal>
|
already_AddRefed<nsIPrincipal>
|
||||||
CloneableWithRangeMediaResource::GetCurrentPrincipal() {
|
CloneableWithRangeMediaResource::GetCurrentPrincipal() {
|
||||||
|
|
|
@ -27,7 +27,7 @@ class CloneableWithRangeMediaResource : public BaseMediaResource {
|
||||||
|
|
||||||
// Main thread
|
// Main thread
|
||||||
nsresult Open(nsIStreamListener** aStreamListener) override;
|
nsresult Open(nsIStreamListener** aStreamListener) override;
|
||||||
nsresult Close() override;
|
RefPtr<GenericPromise> Close() override;
|
||||||
void Suspend(bool aCloseImmediately) override {}
|
void Suspend(bool aCloseImmediately) override {}
|
||||||
void Resume() override {}
|
void Resume() override {}
|
||||||
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
|
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
|
||||||
|
|
|
@ -95,7 +95,7 @@ nsresult FileMediaResource::Open(nsIStreamListener** aStreamListener) {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult FileMediaResource::Close() {
|
RefPtr<GenericPromise> FileMediaResource::Close() {
|
||||||
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
|
||||||
|
|
||||||
// Since mChennel is only accessed by main thread, there is no necessary to
|
// Since mChennel is only accessed by main thread, there is no necessary to
|
||||||
|
@ -105,7 +105,7 @@ nsresult FileMediaResource::Close() {
|
||||||
mChannel = nullptr;
|
mChannel = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return GenericPromise::CreateAndResolve(true, __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsIPrincipal> FileMediaResource::GetCurrentPrincipal() {
|
already_AddRefed<nsIPrincipal> FileMediaResource::GetCurrentPrincipal() {
|
||||||
|
|
|
@ -23,7 +23,7 @@ class FileMediaResource : public BaseMediaResource {
|
||||||
|
|
||||||
// Main thread
|
// Main thread
|
||||||
nsresult Open(nsIStreamListener** aStreamListener) override;
|
nsresult Open(nsIStreamListener** aStreamListener) override;
|
||||||
nsresult Close() override;
|
RefPtr<GenericPromise> Close() override;
|
||||||
void Suspend(bool aCloseImmediately) override {}
|
void Suspend(bool aCloseImmediately) override {}
|
||||||
void Resume() override {}
|
void Resume() override {}
|
||||||
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
|
already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
|
||||||
|
|
|
@ -161,7 +161,7 @@ class MediaCache {
|
||||||
// file backing will be provided.
|
// file backing will be provided.
|
||||||
static RefPtr<MediaCache> GetMediaCache(int64_t aContentLength);
|
static RefPtr<MediaCache> GetMediaCache(int64_t aContentLength);
|
||||||
|
|
||||||
nsIEventTarget* OwnerThread() const { return sThread; }
|
nsISerialEventTarget* OwnerThread() const { return sThread; }
|
||||||
|
|
||||||
// Brutally flush the cache contents. Main thread only.
|
// Brutally flush the cache contents. Main thread only.
|
||||||
void Flush();
|
void Flush();
|
||||||
|
@ -2196,17 +2196,18 @@ bool MediaCacheStream::AreAllStreamsForResourceSuspended(AutoLock& aLock) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaCacheStream::Close() {
|
RefPtr<GenericPromise> MediaCacheStream::Close() {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
if (!mMediaCache) {
|
if (!mMediaCache) {
|
||||||
return;
|
return GenericPromise::CreateAndResolve(true, __func__);
|
||||||
}
|
}
|
||||||
OwnerThread()->Dispatch(NS_NewRunnableFunction(
|
|
||||||
"MediaCacheStream::Close",
|
return InvokeAsync(OwnerThread(), "MediaCacheStream::Close",
|
||||||
[this, client = RefPtr<ChannelMediaResource>(mClient)]() {
|
[this, client = RefPtr<ChannelMediaResource>(mClient)] {
|
||||||
AutoLock lock(mMediaCache->Monitor());
|
AutoLock lock(mMediaCache->Monitor());
|
||||||
CloseInternal(lock);
|
CloseInternal(lock);
|
||||||
}));
|
return GenericPromise::CreateAndResolve(true, __func__);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MediaCacheStream::CloseInternal(AutoLock& aLock) {
|
void MediaCacheStream::CloseInternal(AutoLock& aLock) {
|
||||||
|
@ -2734,7 +2735,7 @@ void MediaCacheStream::InitAsCloneInternal(MediaCacheStream* aOriginal) {
|
||||||
lock.NotifyAll();
|
lock.NotifyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsIEventTarget* MediaCacheStream::OwnerThread() const {
|
nsISerialEventTarget* MediaCacheStream::OwnerThread() const {
|
||||||
return mMediaCache->OwnerThread();
|
return mMediaCache->OwnerThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -217,12 +217,12 @@ class MediaCacheStream : public DecoderDoctorLifeLogger<MediaCacheStream> {
|
||||||
// on this class.
|
// on this class.
|
||||||
void InitAsClone(MediaCacheStream* aOriginal);
|
void InitAsClone(MediaCacheStream* aOriginal);
|
||||||
|
|
||||||
nsIEventTarget* OwnerThread() const;
|
nsISerialEventTarget* OwnerThread() const;
|
||||||
|
|
||||||
// These are called on the main thread.
|
// These are called on the main thread.
|
||||||
// This must be called (and return) before the ChannelMediaResource
|
// This must be called (and resolve) before the ChannelMediaResource
|
||||||
// used to create this MediaCacheStream is deleted.
|
// used to create this MediaCacheStream is deleted.
|
||||||
void Close();
|
RefPtr<GenericPromise> Close();
|
||||||
// This returns true when the stream has been closed.
|
// This returns true when the stream has been closed.
|
||||||
bool IsClosed(AutoLock&) const { return mClosed; }
|
bool IsClosed(AutoLock&) const { return mClosed; }
|
||||||
// Returns true when this stream is can be shared by a new resource load.
|
// Returns true when this stream is can be shared by a new resource load.
|
||||||
|
|
|
@ -390,7 +390,7 @@ void MediaDecoder::Shutdown() {
|
||||||
nsCOMPtr<nsIRunnable> r =
|
nsCOMPtr<nsIRunnable> r =
|
||||||
NS_NewRunnableFunction("MediaDecoder::Shutdown", [self]() {
|
NS_NewRunnableFunction("MediaDecoder::Shutdown", [self]() {
|
||||||
self->mVideoFrameContainer = nullptr;
|
self->mVideoFrameContainer = nullptr;
|
||||||
MediaShutdownManager::Instance().Unregister(self);
|
self->ShutdownInternal();
|
||||||
});
|
});
|
||||||
mAbstractMainThread->Dispatch(r.forget());
|
mAbstractMainThread->Dispatch(r.forget());
|
||||||
}
|
}
|
||||||
|
@ -531,11 +531,16 @@ void MediaDecoder::OnStoreDecoderBenchmark(const VideoInfo& aInfo) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MediaDecoder::ShutdownInternal() {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
MediaShutdownManager::Instance().Unregister(this);
|
||||||
|
}
|
||||||
|
|
||||||
void MediaDecoder::FinishShutdown() {
|
void MediaDecoder::FinishShutdown() {
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
SetStateMachine(nullptr);
|
SetStateMachine(nullptr);
|
||||||
mVideoFrameContainer = nullptr;
|
mVideoFrameContainer = nullptr;
|
||||||
MediaShutdownManager::Instance().Unregister(this);
|
ShutdownInternal();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult MediaDecoder::InitializeStateMachine() {
|
nsresult MediaDecoder::InitializeStateMachine() {
|
||||||
|
|
|
@ -403,6 +403,11 @@ class MediaDecoder : public DecoderDoctorLifeLogger<MediaDecoder> {
|
||||||
|
|
||||||
void SetStateMachineParameters();
|
void SetStateMachineParameters();
|
||||||
|
|
||||||
|
// Called when MediaDecoder shutdown is finished. Subclasses use this to clean
|
||||||
|
// up internal structures, and unregister potential shutdown blockers when
|
||||||
|
// they're done.
|
||||||
|
virtual void ShutdownInternal();
|
||||||
|
|
||||||
bool IsShutdown() const;
|
bool IsShutdown() const;
|
||||||
|
|
||||||
// Called to notify the decoder that the duration has changed.
|
// Called to notify the decoder that the duration has changed.
|
||||||
|
|
|
@ -60,8 +60,11 @@ class MediaResource : public DecoderDoctorLifeLogger<MediaResource> {
|
||||||
|
|
||||||
// Close the resource, stop any listeners, channels, etc.
|
// Close the resource, stop any listeners, channels, etc.
|
||||||
// Cancels any currently blocking Read request and forces that request to
|
// Cancels any currently blocking Read request and forces that request to
|
||||||
// return an error.
|
// return an error. This must be called (and resolve) before the MediaResource
|
||||||
virtual nsresult Close() { return NS_OK; }
|
// is deleted.
|
||||||
|
virtual RefPtr<GenericPromise> Close() {
|
||||||
|
return GenericPromise::CreateAndResolve(true, __func__);
|
||||||
|
}
|
||||||
|
|
||||||
// These methods are called off the main thread.
|
// These methods are called off the main thread.
|
||||||
// Read up to aCount bytes from the stream. The read starts at
|
// Read up to aCount bytes from the stream. The read starts at
|
||||||
|
|
|
@ -24,11 +24,11 @@ mozilla::LogModule* GetSourceBufferResourceLog() {
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
nsresult SourceBufferResource::Close() {
|
RefPtr<GenericPromise> SourceBufferResource::Close() {
|
||||||
MOZ_ASSERT(OnThread());
|
MOZ_ASSERT(OnThread());
|
||||||
SBR_DEBUG("Close");
|
SBR_DEBUG("Close");
|
||||||
mClosed = true;
|
mClosed = true;
|
||||||
return NS_OK;
|
return GenericPromise::CreateAndResolve(true, __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult SourceBufferResource::ReadAt(int64_t aOffset, char* aBuffer,
|
nsresult SourceBufferResource::ReadAt(int64_t aOffset, char* aBuffer,
|
||||||
|
|
|
@ -36,7 +36,7 @@ class SourceBufferResource final
|
||||||
public DecoderDoctorLifeLogger<SourceBufferResource> {
|
public DecoderDoctorLifeLogger<SourceBufferResource> {
|
||||||
public:
|
public:
|
||||||
SourceBufferResource();
|
SourceBufferResource();
|
||||||
nsresult Close() override;
|
RefPtr<GenericPromise> Close() override;
|
||||||
nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount,
|
nsresult ReadAt(int64_t aOffset, char* aBuffer, uint32_t aCount,
|
||||||
uint32_t* aBytes) override;
|
uint32_t* aBytes) override;
|
||||||
// Memory-based and no locks, caching discouraged.
|
// Memory-based and no locks, caching discouraged.
|
||||||
|
|
Загрузка…
Ссылка в новой задаче