Bug 1299515 - Plumb MediaStreamTrack enabled state to sources. r?jib
MozReview-Commit-ID: Eg1g9JtLmOz
--- a/dom/html/HTMLCanvasElement.cpp
+++ b/dom/html/HTMLCanvasElement.cpp
@@ -715,16 +715,24 @@ public:
if (!mCaptureStream) {
NS_ERROR("No stream");
return;
}
mCaptureStream->StopCapture();
}
+ void Disable() override
+ {
+ }
+
+ void Enable() override
+ {
+ }
+
private:
virtual ~CanvasCaptureTrackSource() {}
RefPtr<CanvasCaptureMediaStream> mCaptureStream;
};
NS_IMPL_ADDREF_INHERITED(CanvasCaptureTrackSource,
MediaStreamTrackSource)
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -3243,16 +3243,32 @@ public:
* Do not keep the track source alive. The source lifetime is controlled by
* its associated tracks.
*/
bool KeepsSourceAlive() const override
{
return false;
}
+ /**
+ * Do not keep the track source on. It is controlled by its associated tracks.
+ */
+ bool Enabled() const override
+ {
+ return false;
+ }
+
+ void Disable() override
+ {
+ }
+
+ void Enable() override
+ {
+ }
+
void PrincipalChanged() override
{
if (!mCapturedTrackSource) {
// This could happen during shutdown.
return;
}
mPrincipal = mCapturedTrackSource->GetPrincipal();
@@ -3336,16 +3352,24 @@ public:
void Stop() override
{
// We don't notify the source that a track was stopped since it will keep
// producing tracks until the element ends. The decoder also needs the
// tracks it created to be live at the source since the decoder's clock is
// based on MediaStreams during capture.
}
+ void Disable() override
+ {
+ }
+
+ void Enable() override
+ {
+ }
+
void NotifyDecoderPrincipalChanged() override
{
nsCOMPtr<nsIPrincipal> newPrincipal = mElement->GetCurrentPrincipal();
if (nsContentUtils::CombineResourcePrincipals(&mPrincipal, newPrincipal)) {
PrincipalChanged();
}
}
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -183,16 +183,29 @@ public:
/**
* Posts a task to stop the device associated with aTrackID and notifies the
* associated window listener that a track was stopped.
* Should this track be the last live one to be stopped, we'll also clean up.
*/
void StopTrack(TrackID aTrackID);
/**
+ * Posts a task to disable the device associated with aTrackID and notifies
+ * the associated window listener that a track has been disabled.
+ */
+ void DisableTrack(TrackID aTrackID);
+
+
+ /**
+ * Posts a task to enable the device associated with aTrackID and notifies
+ * the associated window listener that a track has been enabled.
+ */
+ void EnableTrack(TrackID aTrackID);
+
+ /**
* Stops all screen/app/window/audioCapture sharing, but not camera or
* microphone.
*/
void StopSharing();
MediaStream* Stream() const
{
return mStream;
@@ -1114,16 +1127,30 @@ public:
void Stop() override
{
if (mListener) {
mListener->StopTrack(mTrackID);
mListener = nullptr;
}
}
+ void Disable() override
+ {
+ if (mListener) {
+ mListener->DisableTrack(mTrackID);
+ }
+ }
+
+ void Enable() override
+ {
+ if (mListener) {
+ mListener->EnableTrack(mTrackID);
+ }
+ }
+
protected:
~LocalTrackSource() {}
RefPtr<SourceListener> mListener;
const MediaSourceEnum mSource;
const TrackID mTrackID;
const RefPtr<const PeerIdentity> mPeerIdentity;
};
@@ -3806,16 +3833,112 @@ SourceListener::StopTrack(TrackID aTrack
if (!mWindowListener) {
MOZ_ASSERT(false, "Should still have window listener");
return;
}
mWindowListener->NotifySourceTrackStopped();
}
void
+SourceListener::DisableTrack(TrackID aTrackID)
+{
+ MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
+
+ if (!Activated()) {
+ MOZ_ASSERT(false, "No device to disable");
+ return;
+ }
+
+ RefPtr<MediaDevice> device;
+
+ switch (aTrackID) {
+ case kAudioTrack: {
+ LOG(("SourceListener %p disabling audio track %d", this, aTrackID));
+ if (!mAudioDevice) {
+ NS_ASSERTION(false, "Can't disable audio. No device.");
+ return;
+ }
+ if (mAudioStopped) {
+ // Audio stopped. Disabling is pointless.
+ return;
+ }
+ device = mAudioDevice;
+ break;
+ }
+ case kVideoTrack: {
+ LOG(("SourceListener %p disabling video track %d", this, aTrackID));
+ if (!mVideoDevice) {
+ NS_ASSERTION(false, "Can't disable video. No device.");
+ return;
+ }
+ if (mVideoStopped) {
+ // Video stopped. Disabling is pointless.
+ return;
+ }
+ device = mVideoDevice;
+ break;
+ }
+ default: {
+ MOZ_ASSERT(false, "Unknown track id");
+ return;
+ }
+ }
+
+ // XXX Later patch
+}
+
+void
+SourceListener::EnableTrack(TrackID aTrackID)
+{
+ MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
+
+ if (!Activated()) {
+ MOZ_ASSERT(false, "No device to enable");
+ return;
+ }
+
+ RefPtr<MediaDevice> device;
+
+ switch (aTrackID) {
+ case kAudioTrack: {
+ LOG(("SourceListener %p enabling audio track %d", this, aTrackID));
+ if (!mAudioDevice) {
+ NS_ASSERTION(false, "Can't enable audio. No device.");
+ return;
+ }
+ if (mAudioStopped) {
+ // Audio stopped. Enabling is pointless.
+ return;
+ }
+ device = mAudioDevice;
+ break;
+ }
+ case kVideoTrack: {
+ LOG(("SourceListener %p enabling video track %d", this, aTrackID));
+ if (!mVideoDevice) {
+ NS_ASSERTION(false, "Can't enable video. No device.");
+ return;
+ }
+ if (mVideoStopped) {
+ // Video stopped. Enabling is pointless.
+ return;
+ }
+ device = mVideoDevice;
+ break;
+ }
+ default: {
+ MOZ_ASSERT(false, "Unknown track id");
+ return;
+ }
+ }
+
+ // XXX Later patch
+}
+
+void
SourceListener::StopSharing()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_RELEASE_ASSERT(mWindowListener);
if (mStopped) {
return;
}
--- a/dom/media/MediaStreamTrack.cpp
+++ b/dom/media/MediaStreamTrack.cpp
@@ -217,16 +217,17 @@ void
MediaStreamTrack::SetEnabled(bool aEnabled)
{
LOG(LogLevel::Info, ("MediaStreamTrack %p %s",
this, aEnabled ? "Enabled" : "Disabled"));
mEnabled = aEnabled;
GetOwnedStream()->SetTrackEnabled(mTrackID, mEnabled ? DisabledTrackMode::ENABLED
: DisabledTrackMode::SILENCE_BLACK);
+ GetSource().SinkEnabledStateChanged();
}
void
MediaStreamTrack::Stop()
{
LOG(LogLevel::Info, ("MediaStreamTrack %p Stop()", this));
if (Ended()) {
--- a/dom/media/MediaStreamTrack.h
+++ b/dom/media/MediaStreamTrack.h
@@ -69,16 +69,31 @@ public:
* registered alive.
* Return false to allow the source to stop.
*
* Typically MediaStreamTrack::Sink returns true and other Sinks
* (like HTMLMediaElement::StreamCaptureTrackSource) return false.
*/
virtual bool KeepsSourceAlive() const = 0;
+ /**
+ * Return true to ensure that the MediaStreamTrackSource where this Sink is
+ * registered is kept turned on and active.
+ * Return false to allow the source to pause, and any underlying devices to
+ * temporarily stop.
+ *
+ * When the underlying enabled state of the sink changes,
+ * call MediaStreamTrackSource::SinkEnabledStateChanged().
+ *
+ * Typically MediaStreamTrack returns the track's enabled state and other
+ * Sinks (like HTMLMediaElement::StreamCaptureTrackSource) return false so
+ * control over device state remains with tracks and their enabled state.
+ */
+ virtual bool Enabled() const = 0;
+
virtual void PrincipalChanged() = 0;
virtual void MutedChanged(bool aNewState) = 0;
};
MediaStreamTrackSource(nsIPrincipal* aPrincipal,
const nsString& aLabel)
: mPrincipal(aPrincipal),
mLabel(aLabel),
@@ -152,16 +167,43 @@ public:
/**
* Called by the source interface when all registered sinks with
* KeepsSourceAlive() == true have unregistered.
*/
virtual void Stop() = 0;
/**
+ * Called by the source interface when all registered sinks with
+ * KeepsSourceAlive() == true become disabled.
+ */
+ virtual void Disable() = 0;
+
+ /**
+ * Called by the source interface when at least one registered sink with
+ * KeepsSourceAlive() == true become enabled.
+ */
+ virtual void Enable() = 0;
+
+ /**
+ * Called when a Sink's Enabled() state changed. Will iterate through all
+ * sinks and notify the source of the aggregated enabled state.
+ *
+ * Note that a Sink with KeepsSourceAlive() == false counts as disabled.
+ */
+ void SinkEnabledStateChanged()
+ {
+ if (IsEnabled()) {
+ Enable();
+ } else {
+ Disable();
+ }
+ }
+
+ /**
* Called by each MediaStreamTrack clone on initialization.
*/
void RegisterSink(Sink* aSink)
{
MOZ_ASSERT(NS_IsMainThread());
if (mStopped) {
return;
}
@@ -200,16 +242,26 @@ protected:
for (const WeakPtr<Sink>& sink : mSinks) {
if (sink && sink->KeepsSourceAlive()) {
return true;
}
}
return false;
}
+ bool IsEnabled()
+ {
+ for (const WeakPtr<Sink>& sink : mSinks) {
+ if (sink && sink->KeepsSourceAlive() && sink->Enabled()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Called by a sub class when the principal has changed.
* Notifies all sinks.
*/
void PrincipalChanged()
{
MOZ_ASSERT(NS_IsMainThread());
nsTArray<WeakPtr<Sink>> sinks(mSinks);
@@ -267,16 +319,18 @@ public:
MediaSourceEnum::Other)
: MediaStreamTrackSource(aPrincipal, nsString())
, mMediaSource(aMediaSource)
{}
MediaSourceEnum GetMediaSource() const override { return mMediaSource; }
void Stop() override {}
+ void Disable() override {}
+ void Enable() override {}
protected:
~BasicTrackSource() {}
const MediaSourceEnum mMediaSource;
};
/**
@@ -337,17 +391,17 @@ public:
virtual const AudioStreamTrack* AsAudioStreamTrack() const { return nullptr; }
virtual const VideoStreamTrack* AsVideoStreamTrack() const { return nullptr; }
// WebIDL
virtual void GetKind(nsAString& aKind) = 0;
void GetId(nsAString& aID) const;
virtual void GetLabel(nsAString& aLabel, CallerType /* aCallerType */) { GetSource().GetLabel(aLabel); }
- bool Enabled() { return mEnabled; }
+ bool Enabled() const override { return mEnabled; }
void SetEnabled(bool aEnabled);
bool Muted() { return mMuted; }
void Stop();
void GetConstraints(dom::MediaTrackConstraints& aResult);
void GetSettings(dom::MediaTrackSettings& aResult, CallerType aCallerType);
already_AddRefed<Promise>
ApplyConstraints(const dom::MediaTrackConstraints& aConstraints,
--- a/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
+++ b/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
@@ -44,16 +44,24 @@ public:
return MediaSourceEnum::AudioCapture;
}
void Stop() override
{
Destroy();
}
+ void Disable() override
+ {
+ }
+
+ void Enable() override
+ {
+ }
+
private:
~AudioDestinationTrackSource() = default;
RefPtr<MediaStreamAudioDestinationNode> mNode;
};
NS_IMPL_ADDREF_INHERITED(AudioDestinationTrackSource,
MediaStreamTrackSource)
--- a/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp
+++ b/media/webrtc/signaling/gtest/mediapipeline_unittest.cpp
@@ -67,16 +67,25 @@ public:
{
}
virtual mozilla::dom::MediaSourceEnum GetMediaSource() const override
{
return mozilla::dom::MediaSourceEnum::Microphone;
}
+
+ virtual void Disable() override
+ {
+ }
+
+ virtual void Enable() override
+ {
+ }
+
virtual void Stop() override
{
}
};
class FakeAudioStreamTrack : public mozilla::dom::AudioStreamTrack {
--- a/media/webrtc/signaling/src/peerconnection/RemoteTrackSource.h
+++ b/media/webrtc/signaling/src/peerconnection/RemoteTrackSource.h
@@ -35,16 +35,24 @@ public:
}
void Stop() override
{
// XXX (Bug 1314270): Implement rejection logic if necessary when we have
// clarity in the spec.
}
+ void Disable() override
+ {
+ }
+
+ void Enable() override
+ {
+ }
+
void SetPrincipal(nsIPrincipal* aPrincipal)
{
mPrincipal = aPrincipal;
PrincipalChanged();
}
protected:
virtual ~RemoteTrackSource() {}