diff --git a/dom/media/mediasink/VideoSink.cpp b/dom/media/mediasink/VideoSink.cpp index 8df554672917..5fa85d658336 100644 --- a/dom/media/mediasink/VideoSink.cpp +++ b/dom/media/mediasink/VideoSink.cpp @@ -166,6 +166,25 @@ VideoSink::Start(int64_t aStartTime, const MediaInfo& aInfo) if (mHasVideo) { mEndPromise = mEndPromiseHolder.Ensure(__func__); + + // If the underlying MediaSink has an end promise for the video track (which + // happens when mAudioSink refers to a DecodedStream), we must wait for it + // to complete before resolving our own end promise. Otherwise, MDSM might + // stop playback before DecodedStream plays to the end and cause + // test_streams_element_capture.html to time out. + RefPtr p = mAudioSink->OnEnded(TrackInfo::kVideoTrack); + if (p) { + RefPtr self = this; + mVideoSinkEndRequest.Begin(p->Then(mOwnerThread, __func__, + [self] () { + self->mVideoSinkEndRequest.Complete(); + self->TryUpdateRenderedVideoFrames(); + }, [self] () { + self->mVideoSinkEndRequest.Complete(); + self->TryUpdateRenderedVideoFrames(); + })); + } + ConnectListener(); // Run the render loop at least once so we can resolve the end promise // when video duration is 0. @@ -185,6 +204,7 @@ VideoSink::Stop() mUpdateScheduler.Reset(); if (mHasVideo) { DisconnectListener(); + mVideoSinkEndRequest.DisconnectIfExists(); mEndPromiseHolder.ResolveIfExists(true, __func__); mEndPromise = nullptr; } @@ -389,7 +409,9 @@ VideoSink::UpdateRenderedVideoFrames() } // All frames are rendered, Let's resolve the promise. - if (VideoQueue().IsFinished() && VideoQueue().GetSize() <= 1) { + if (VideoQueue().IsFinished() && + VideoQueue().GetSize() <= 1 && + !mVideoSinkEndRequest.Exists()) { mEndPromiseHolder.ResolveIfExists(true, __func__); }