From f7bb3fd5bd5332e983e241b6da4644ec1f360c2e Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Fri, 24 Jul 2015 14:28:17 +0200 Subject: [PATCH] Bug 1156472 - Part 7 - Allow to un-capture an HTMLMediaElement. r=pehrsons,jwwang --- dom/html/HTMLMediaElement.cpp | 18 +++++++++++++++- dom/media/DecodedStream.cpp | 8 +++++++ dom/media/DecodedStream.h | 1 + dom/media/MediaDecoder.cpp | 7 +++++++ dom/media/MediaDecoder.h | 2 ++ dom/media/MediaDecoderStateMachine.cpp | 29 ++++++++++++++++++++++++++ dom/media/MediaDecoderStateMachine.h | 3 +++ 7 files changed, 67 insertions(+), 1 deletion(-) diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 790103de8c1d..aa5738059be0 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -4708,7 +4708,23 @@ NS_IMETHODIMP HTMLMediaElement::WindowAudioCaptureChanged() mCaptureStreamPort = msg->ConnectToCaptureStream(id, mPlaybackStream->GetStream()); } } else { - // TODO: uncapture + mAudioCapturedByWindow = false; + if (mDecoder) { + ProcessedMediaStream* ps = + mCaptureStreamPort->GetSource()->AsProcessedStream(); + MOZ_ASSERT(ps); + + for (uint32_t i = 0; i < mOutputStreams.Length(); i++) { + if (mOutputStreams[i].mStream->GetStream() == ps) { + mOutputStreams.RemoveElementAt(i); + break; + } + } + + mDecoder->RemoveOutputStream(ps); + } + mCaptureStreamPort->Destroy(); + mCaptureStreamPort = nullptr; } } diff --git a/dom/media/DecodedStream.cpp b/dom/media/DecodedStream.cpp index dcc950228f72..913f68203e21 100644 --- a/dom/media/DecodedStream.cpp +++ b/dom/media/DecodedStream.cpp @@ -289,6 +289,14 @@ DecodedStream::OutputStreams() return mOutputStreams; } +bool +DecodedStream::HasConsumers() const +{ + MOZ_ASSERT(NS_IsMainThread()); + ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); + return mOutputStreams.IsEmpty(); +} + ReentrantMonitor& DecodedStream::GetReentrantMonitor() const { diff --git a/dom/media/DecodedStream.h b/dom/media/DecodedStream.h index 8b25b95c9f7d..ebad8330c865 100644 --- a/dom/media/DecodedStream.h +++ b/dom/media/DecodedStream.h @@ -114,6 +114,7 @@ public: int64_t AudioEndTime() const; int64_t GetPosition() const; bool IsFinished() const; + bool HasConsumers() const; // Return true if stream is finished. bool SendData(double aVolume, bool aIsSameOrigin); diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp index 59f7e5fcc59b..3f0cdadc6a19 100644 --- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -326,6 +326,13 @@ void MediaDecoder::AddOutputStream(ProcessedMediaStream* aStream, mDecoderStateMachine->AddOutputStream(aStream, aFinishWhenEnded); } +void MediaDecoder::RemoveOutputStream(MediaStream* aStream) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mDecoderStateMachine, "Must be called after Load()."); + mDecoderStateMachine->RemoveOutputStream(aStream); +} + double MediaDecoder::GetDuration() { MOZ_ASSERT(NS_IsMainThread()); diff --git a/dom/media/MediaDecoder.h b/dom/media/MediaDecoder.h index c2a01bb07465..d216bf9c7666 100644 --- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -399,6 +399,8 @@ public: // The stream is initially blocked. The decoder is responsible for unblocking // it while it is playing back. virtual void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded); + // Remove an output stream added with AddOutputStream. + virtual void RemoveOutputStream(MediaStream* aStream); // Return the duration of the video in seconds. virtual double GetDuration(); diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index 08929dd14976..ac546d835cf4 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -3140,6 +3140,25 @@ void MediaDecoderStateMachine::DispatchAudioCaptured() OwnerThread()->Dispatch(r.forget()); } +void MediaDecoderStateMachine::DispatchAudioUncaptured() +{ + nsRefPtr self = this; + nsCOMPtr r = NS_NewRunnableFunction([self] () -> void + { + MOZ_ASSERT(self->OnTaskQueue()); + ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor()); + if (self->mAudioCaptured) { + // Start again the audio sink + self->mAudioCaptured = false; + if (self->IsPlaying()) { + self->StartAudioThread(); + } + self->ScheduleStateMachine(); + } + }); + OwnerThread()->Dispatch(r.forget()); +} + void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded) { @@ -3149,6 +3168,16 @@ void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream, DispatchAudioCaptured(); } +void MediaDecoderStateMachine::RemoveOutputStream(MediaStream* aStream) +{ + MOZ_ASSERT(NS_IsMainThread()); + DECODER_LOG("RemoveOutputStream=%p!", aStream); + mDecodedStream->Remove(aStream); + if (!mDecodedStream->HasConsumers()) { + DispatchAudioUncaptured(); + } +} + } // namespace mozilla // avoid redefined macro in unified build diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index ac5bc525ad2e..f6d5cfa98015 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -148,6 +148,8 @@ public: }; void AddOutputStream(ProcessedMediaStream* aStream, bool aFinishWhenEnded); + // Remove an output stream added with AddOutputStream. + void RemoveOutputStream(MediaStream* aStream); // Set/Unset dormant state. void SetDormant(bool aDormant); @@ -159,6 +161,7 @@ private: void InitializationTask(); void DispatchAudioCaptured(); + void DispatchAudioUncaptured(); void Shutdown(); public: