Bug 1208371 - Implement DOMMediaStream::Clone() r?smaug,jib,roc
--- a/dom/media/DOMMediaStream.cpp
+++ b/dom/media/DOMMediaStream.cpp
@@ -364,25 +364,25 @@ DOMMediaStream::Destroy()
mPlaybackPort->Destroy();
mPlaybackPort = nullptr;
}
if (mOwnedPort) {
mOwnedPort->Destroy();
mOwnedPort = nullptr;
}
if (mPlaybackStream) {
- mPlaybackStream->Destroy();
+ mPlaybackStream->UnregisterUser();
mPlaybackStream = nullptr;
}
if (mOwnedStream) {
- mOwnedStream->Destroy();
+ mOwnedStream->UnregisterUser();
mOwnedStream = nullptr;
}
if (mInputStream) {
- mInputStream->Destroy();
+ mInputStream->UnregisterUser();
mInputStream = nullptr;
}
}
JSObject*
DOMMediaStream::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return dom::MediaStreamBinding::Wrap(aCx, this, aGivenProto);
@@ -568,16 +568,94 @@ DOMMediaStream::RemoveTrack(MediaStreamT
// end.
toRemove->BlockTrackId(aTrack.mTrackID);
DebugOnly<bool> removed = mTracks.RemoveElement(toRemove);
MOZ_ASSERT(removed);
LOG(LogLevel::Debug, ("DOMMediaStream %p Removed track %p", this, &aTrack));
}
+already_AddRefed<DOMMediaStream>
+DOMMediaStream::Clone()
+{
+ class ClonedStreamSourceGetter : public MediaStreamTrackSourceGetter
+ {
+ public:
+ ClonedStreamSourceGetter(DOMMediaStream* aStream)
+ : mStream(aStream) {}
+
+ already_AddRefed<MediaStreamTrackSource>
+ GetMediaStreamTrackSource(TrackID aInputTrackID) override
+ {
+ for (const TrackPort* port : mStream->mOwnedTracks) {
+ if (port->GetTrack()->mInputTrackID == aInputTrackID) {
+ return do_AddRef(&port->GetTrack()->GetSource());
+ }
+ }
+
+ return nullptr;
+ }
+
+ protected:
+ virtual ~ClonedStreamSourceGetter() {}
+
+ WeakPtr<DOMMediaStream> mStream;
+ };
+
+ RefPtr<DOMMediaStream> newStream =
+ new DOMMediaStream(GetParentObject(), new ClonedStreamSourceGetter(this));
+
+ LOG(LogLevel::Info, ("DOMMediaStream %p created clone %p",
+ this, newStream.get()));
+
+ MOZ_RELEASE_ASSERT(mPlaybackStream);
+ MOZ_RELEASE_ASSERT(mPlaybackStream->Graph());
+ MediaStreamGraph* graph = mPlaybackStream->Graph();
+
+ // We initiate the owned and playback streams first, since we need to create
+ // all existing DOM tracks before we add the generic input port from
+ // mInputStream to mOwnedStream (see AllocateInputPort wrt. destination
+ // TrackID as to why).
+ newStream->InitOwnedStreamCommon(graph);
+ newStream->InitPlaybackStreamCommon(graph);
+
+ // We set up track-locked input ports for all existing DOM tracks, so
+ // we need to block those in the generic input port set up at the end.
+ nsTArray<TrackID> tracksToBlock;
+ for (const RefPtr<TrackPort>& info : mOwnedTracks) {
+ tracksToBlock.AppendElement(info->GetTrack()->mTrackID);
+ }
+
+ // Set up existing DOM tracks.
+ TrackID allocatedTrackID = 1;
+ for (const RefPtr<TrackPort>& info : mTracks) {
+ MediaStreamTrack& track = *info->GetTrack();
+
+ LOG(LogLevel::Debug, ("DOMMediaStream %p forwarding external track %p to clone %p",
+ this, &track, newStream.get()));
+ RefPtr<MediaStreamTrack> trackClone =
+ newStream->CreateClonedDOMTrack(track, allocatedTrackID++);
+ }
+
+ // Set up an input port from our input stream to the new DOM stream's owned
+ // stream, to allow for dynamically added tracks at the source to appear in
+ // the clone. The clone may treat mInputStream as its own mInputStream but
+ // ownership remains with us.
+ newStream->mInputStream = mInputStream;
+ if (mInputStream) {
+ newStream->mInputStream->RegisterUser();
+ newStream->mOwnedPort =
+ newStream->mOwnedStream->AllocateInputPort(mInputStream,
+ TRACK_ANY, TRACK_ANY, 0, 0,
+ &tracksToBlock);
+ }
+
+ return newStream.forget();
+}
+
bool
DOMMediaStream::HasTrack(const MediaStreamTrack& aTrack) const
{
return !!FindPlaybackTrackPort(aTrack);
}
bool
DOMMediaStream::OwnsTrack(const MediaStreamTrack& aTrack) const
@@ -626,41 +704,44 @@ DOMMediaStream::InitAudioCaptureStream(M
void
DOMMediaStream::InitInputStreamCommon(MediaStream* aStream,
MediaStreamGraph* aGraph)
{
MOZ_ASSERT(!mOwnedStream, "Input stream must be initialized before owned stream");
mInputStream = aStream;
+ mInputStream->RegisterUser();
}
void
DOMMediaStream::InitOwnedStreamCommon(MediaStreamGraph* aGraph)
{
MOZ_ASSERT(!mPlaybackStream, "Owned stream must be initialized before playback stream");
// We pass null as the wrapper since it is only used to signal finished
// streams. This is only needed for the playback stream.
mOwnedStream = aGraph->CreateTrackUnionStream(nullptr);
mOwnedStream->SetAutofinish(true);
+ mOwnedStream->RegisterUser();
if (mInputStream) {
mOwnedPort = mOwnedStream->AllocateInputPort(mInputStream);
}
// Setup track listeners
mOwnedListener = new OwnedStreamListener(this);
mOwnedStream->AddListener(mOwnedListener);
}
void
DOMMediaStream::InitPlaybackStreamCommon(MediaStreamGraph* aGraph)
{
mPlaybackStream = aGraph->CreateTrackUnionStream(this);
mPlaybackStream->SetAutofinish(true);
+ mPlaybackStream->RegisterUser();
if (mOwnedStream) {
mPlaybackPort = mPlaybackStream->AllocateInputPort(mOwnedStream);
}
mPlaybackListener = new PlaybackStreamListener(this);
mPlaybackStream->AddListener(mPlaybackListener);
LOG(LogLevel::Debug, ("DOMMediaStream %p Initiated with mInputStream=%p, mOwnedStream=%p, mPlaybackStream=%p",
--- a/dom/media/DOMMediaStream.h
+++ b/dom/media/DOMMediaStream.h
@@ -358,16 +358,17 @@ public:
void GetId(nsAString& aID) const;
void GetAudioTracks(nsTArray<RefPtr<AudioStreamTrack> >& aTracks) const;
void GetVideoTracks(nsTArray<RefPtr<VideoStreamTrack> >& aTracks) const;
void GetTracks(nsTArray<RefPtr<MediaStreamTrack> >& aTracks) const;
void AddTrack(MediaStreamTrack& aTrack);
void RemoveTrack(MediaStreamTrack& aTrack);
+ already_AddRefed<DOMMediaStream> Clone();
// NON-WebIDL
/**
* Returns true if this DOMMediaStream has aTrack in its mPlaybackStream.
*/
bool HasTrack(const MediaStreamTrack& aTrack) const;
--- a/dom/webidl/MediaStream.webidl
+++ b/dom/webidl/MediaStream.webidl
@@ -34,16 +34,16 @@ dictionary MediaStreamConstraints {
interface MediaStream : EventTarget {
readonly attribute DOMString id;
sequence<AudioStreamTrack> getAudioTracks ();
sequence<VideoStreamTrack> getVideoTracks ();
sequence<MediaStreamTrack> getTracks ();
// MediaStreamTrack? getTrackById (DOMString trackId);
void addTrack (MediaStreamTrack track);
void removeTrack (MediaStreamTrack track);
- // MediaStream clone ();
+ MediaStream clone ();
// readonly attribute boolean active;
// attribute EventHandler onactive;
// attribute EventHandler oninactive;
// attribute EventHandler onaddtrack;
// attribute EventHandler onremovetrack;
readonly attribute double currentTime;
};