Bug 1371719 - Don't create a MediaStreamGraph without doing anything with it. r?jesup
The MediaStreamGraph relies on having at least one message sent to its message
queue on creation, or it will just sit there and do nothing, and block shutdown
because its not running its rendering loop, so it's not progressing in the
MediaStreamGraph life cycle state machine.
This patch makes sure the `captureStream` will succeed before creating an MSG.
MozReview-Commit-ID: CN1arWydmxC
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -3345,41 +3345,52 @@ HTMLMediaElement::AddCaptureMediaTrackTo
}
LOG(LogLevel::Debug,
("Created %s track %p with id %d from track %p through MediaInputPort %p",
inputTrack->AsAudioStreamTrack() ? "audio" : "video",
track.get(), destinationTrackID, inputTrack, port.get()));
}
+bool
+HTMLMediaElement::CanBeCaptured(bool aCaptureAudio)
+{
+ // Don't bother capturing when the document has gone away
+ nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
+ if (!window) {
+ return false;
+ }
+
+ // Prevent capturing restricted video
+ if (!aCaptureAudio && ContainsRestrictedContent()) {
+ return false;
+ }
+ return true;
+}
+
already_AddRefed<DOMMediaStream>
HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
bool aCaptureAudio,
MediaStreamGraph* aGraph)
{
MOZ_RELEASE_ASSERT(aGraph);
+ MOZ_ASSERT(CanBeCaptured(aCaptureAudio));
MarkAsContentSource(CallerAPI::CAPTURE_STREAM);
MarkAsTainted();
- nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
- if (!window) {
- return nullptr;
- }
- if (!aCaptureAudio && ContainsRestrictedContent()) {
- return nullptr;
- }
-
+ // We don't support routing to a different graph.
if (!mOutputStreams.IsEmpty() &&
aGraph != mOutputStreams[0].mStream->GetInputStream()->Graph()) {
return nullptr;
}
OutputMediaStream* out = mOutputStreams.AppendElement();
MediaStreamTrackSourceGetter* getter = new CaptureStreamTrackSourceGetter(this);
+ nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
out->mStream = DOMMediaStream::CreateTrackUnionStreamAsInput(window, aGraph, getter);
out->mStream->SetInactiveOnFinish();
out->mFinishWhenEnded = aFinishWhenEnded;
out->mCapturingAudioOnly = aCaptureAudio;
if (aCaptureAudio) {
if (mSrcStream) {
// We don't support applying volume and mute to the captured stream, when
@@ -3476,16 +3487,23 @@ HTMLMediaElement::CaptureAudio(ErrorResu
}
already_AddRefed<DOMMediaStream>
HTMLMediaElement::MozCaptureStream(ErrorResult& aRv)
{
MediaStreamGraph::GraphDriverType graphDriverType =
HasAudio() ? MediaStreamGraph::AUDIO_THREAD_DRIVER
: MediaStreamGraph::SYSTEM_THREAD_DRIVER;
+
+
+ nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
+ if (!window) {
+ return nullptr;
+ }
+
MediaStreamGraph* graph =
MediaStreamGraph::GetInstance(graphDriverType, mAudioChannel);
RefPtr<DOMMediaStream> stream =
CaptureStreamInternal(false, false, graph);
if (!stream) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
@@ -3495,16 +3513,22 @@ HTMLMediaElement::MozCaptureStream(Error
}
already_AddRefed<DOMMediaStream>
HTMLMediaElement::MozCaptureStreamUntilEnded(ErrorResult& aRv)
{
MediaStreamGraph::GraphDriverType graphDriverType =
HasAudio() ? MediaStreamGraph::AUDIO_THREAD_DRIVER
: MediaStreamGraph::SYSTEM_THREAD_DRIVER;
+
+ nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
+ if (!window) {
+ return nullptr;
+ }
+
MediaStreamGraph* graph =
MediaStreamGraph::GetInstance(graphDriverType, mAudioChannel);
RefPtr<DOMMediaStream> stream =
CaptureStreamInternal(true, false, graph);
if (!stream) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -1274,16 +1274,19 @@ protected:
bool IsAllowedToPlay();
// If the network state is empty and then we would trigger DoLoad().
void MaybeDoLoad();
// Anything we need to check after played success and not related with spec.
void UpdateCustomPolicyAfterPlayed();
+ // True if this element can be captured, false otherwise.
+ bool CanBeCaptured(bool aCaptureAudio);
+
class nsAsyncEventRunner;
class nsNotifyAboutPlayingRunner;
class nsResolveOrRejectPendingPlayPromisesRunner;
using nsGenericHTMLElement::DispatchEvent;
// For nsAsyncEventRunner.
nsresult DispatchEvent(const nsAString& aName);
// Open unsupported types media with the external app when the media element