diff --git a/content/media/DOMMediaStream.cpp b/content/media/DOMMediaStream.cpp index 7aa4f47bc93..8f86edcec65 100644 --- a/content/media/DOMMediaStream.cpp +++ b/content/media/DOMMediaStream.cpp @@ -196,6 +196,18 @@ DOMMediaStream::GetVideoTracks(nsTArray >& aTracks) } } +void +DOMMediaStream::GetTracks(nsTArray >& aTracks) +{ + aTracks.AppendElements(mTracks); +} + +bool +DOMMediaStream::HasTrack(const MediaStreamTrack& aTrack) const +{ + return mTracks.Contains(&aTrack); +} + bool DOMMediaStream::IsFinished() { diff --git a/content/media/DOMMediaStream.h b/content/media/DOMMediaStream.h index c58bff7cac1..18b85b9c8bb 100644 --- a/content/media/DOMMediaStream.h +++ b/content/media/DOMMediaStream.h @@ -81,6 +81,8 @@ public: void GetAudioTracks(nsTArray >& aTracks); void GetVideoTracks(nsTArray >& aTracks); + void GetTracks(nsTArray >& aTracks); + bool HasTrack(const MediaStreamTrack& aTrack) const; MediaStream* GetStream() const { return mStream; } diff --git a/dom/media/PeerConnection.js b/dom/media/PeerConnection.js index fcb56e888a2..a35ed4ccdbb 100644 --- a/dom/media/PeerConnection.js +++ b/dom/media/PeerConnection.js @@ -210,12 +210,6 @@ RTCSessionDescription.prototype = { }; function RTCStatsReport(win, dict) { - function appendStats(stats, report) { - stats.forEach(function(stat) { - report[stat.id] = stat; - }); - } - this._win = win; this._pcid = dict.pcid; this._report = convertToRTCStatsReport(dict); @@ -287,6 +281,8 @@ RTCIdentityAssertion.prototype = { function RTCPeerConnection() { this._queue = []; + this._senders = []; + this._receivers = []; this._pc = null; this._observer = null; @@ -341,6 +337,7 @@ RTCPeerConnection.prototype = { } this.makeGetterSetterEH("onaddstream"); + this.makeGetterSetterEH("onaddtrack"); this.makeGetterSetterEH("onicecandidate"); this.makeGetterSetterEH("onnegotiationneeded"); this.makeGetterSetterEH("onsignalingstatechange"); @@ -805,6 +802,26 @@ RTCPeerConnection.prototype = { throw new this._win.DOMError("", "getStreamById not yet implemented"); }, + addTrack: function(track, stream) { + if (stream.currentTime === undefined) { + throw new this._win.DOMError("", "invalid stream."); + } + if (stream.getTracks().indexOf(track) == -1) { + throw new this._win.DOMError("", "track is not in stream."); + } + this._checkClosed(); + this._impl.addTrack(track, stream); + let sender = this._win.RTCRtpSender._create(this._win, + new RTCRtpSender(this, track)); + this._senders.push({ sender: sender, stream: stream }); + return sender; + }, + + removeTrack: function(sender) { + // Bug 844295: Not implementing this functionality. + throw new this._win.DOMError("", "removeTrack not yet implemented"); + }, + close: function() { if (this._closed) { return; @@ -830,6 +847,36 @@ RTCPeerConnection.prototype = { return this._impl.getRemoteStreams(); }, + getSenders: function() { + this._checkClosed(); + let streams = this._impl.getLocalStreams(); + let senders = []; + // prune senders in case any streams have disappeared down below + for (let i = this._senders.length - 1; i >= 0; i--) { + if (streams.indexOf(this._senders[i].stream) != -1) { + senders.push(this._senders[i].sender); + } else { + this._senders.splice(i,1); + } + } + return senders; + }, + + getReceivers: function() { + this._checkClosed(); + let streams = this._impl.getRemoteStreams(); + let receivers = []; + // prune receivers in case any streams have disappeared down below + for (let i = this._receivers.length - 1; i >= 0; i--) { + if (streams.indexOf(this._receivers[i].stream) != -1) { + receivers.push(this._receivers[i].receiver); + } else { + this._receivers.splice(i,1); + } + } + return receivers; + }, + get localDescription() { this._checkClosed(); let sdp = this._impl.localDescription; @@ -1248,6 +1295,17 @@ PeerConnectionObserver.prototype = { { stream: stream })); }, + onAddTrack: function(track) { + let ev = new this._dompc._win.MediaStreamTrackEvent("addtrack", + { track: track }); + this._dompc.dispatchEvent(ev); + }, + + onRemoveTrack: function(track, type) { + this.dispatchEvent(new this._dompc._win.MediaStreamTrackEvent("removetrack", + { track: track })); + }, + foundIceCandidate: function(cand) { this.dispatchEvent(new this._dompc._win.RTCPeerConnectionIceEvent("icecandidate", { candidate: cand } )); @@ -1279,34 +1337,26 @@ RTCPeerConnectionStatic.prototype = { }, }; -function RTCRtpSender() {} +function RTCRtpSender(pc, track) { + this.pc = pc; + this.track = track; +} RTCRtpSender.prototype = { classDescription: "RTCRtpSender", classID: PC_SENDER_CID, contractID: PC_SENDER_CONTRACT, - QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, - Ci.nsIDOMGlobalPropertyInitializer]), - - init: function(win) { this._win = win; }, - - __init: function(track) { - this.track = track; - } + QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]), }; -function RTCRtpReceiver() {} +function RTCRtpReceiver(pc, track) { + this.pc = pc; + this.track = track; +} RTCRtpReceiver.prototype = { classDescription: "RTCRtpReceiver", classID: PC_RECEIVER_CID, contractID: PC_RECEIVER_CONTRACT, - QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, - Ci.nsIDOMGlobalPropertyInitializer]), - - init: function(win) { this._win = win; }, - - __init: function(track) { - this.track = track; - } + QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]), }; this.NSGetFactory = XPCOMUtils.generateNSGetFactory( diff --git a/dom/media/tests/mochitest/pc.js b/dom/media/tests/mochitest/pc.js index 7cd0d025cf3..7f48d679bef 100644 --- a/dom/media/tests/mochitest/pc.js +++ b/dom/media/tests/mochitest/pc.js @@ -1543,7 +1543,9 @@ PeerConnectionWrapper.prototype = { this.streams.push(stream); if (side === 'local') { - this._pc.addStream(stream); + stream.getTracks().forEach(function(track) { + this._pc.addTrack(track, stream); + }.bind(this)); } var element = createMediaElement(type, this.label + '_' + side); diff --git a/dom/webidl/MediaStream.webidl b/dom/webidl/MediaStream.webidl index 988545cf1cd..1db6b176602 100644 --- a/dom/webidl/MediaStream.webidl +++ b/dom/webidl/MediaStream.webidl @@ -23,8 +23,9 @@ dictionary MediaStreamConstraints { interface MediaStream { // readonly attribute DOMString id; - sequence getAudioTracks (); - sequence getVideoTracks (); + sequence getAudioTracks(); + sequence getVideoTracks(); + sequence getTracks(); // MediaStreamTrack getTrackById (DOMString trackId); // void addTrack (MediaStreamTrack track); // void removeTrack (MediaStreamTrack track); diff --git a/dom/webidl/PeerConnectionImpl.webidl b/dom/webidl/PeerConnectionImpl.webidl index 659ac21de64..46ffe022b36 100644 --- a/dom/webidl/PeerConnectionImpl.webidl +++ b/dom/webidl/PeerConnectionImpl.webidl @@ -38,7 +38,11 @@ interface PeerConnectionImpl { [Throws] void getStats(MediaStreamTrack? selector); - /* Adds the stream created by GetUserMedia */ + /* Adds the tracks created by GetUserMedia */ + [Throws] + void addTrack(MediaStreamTrack track, MediaStream... streams); + [Throws] + void removeTrack(MediaStreamTrack track); [Throws] void addStream(MediaStream stream); [Throws] diff --git a/dom/webidl/PeerConnectionObserver.webidl b/dom/webidl/PeerConnectionObserver.webidl index a68ba9d9c58..45b24ae92b7 100644 --- a/dom/webidl/PeerConnectionObserver.webidl +++ b/dom/webidl/PeerConnectionObserver.webidl @@ -34,9 +34,9 @@ interface PeerConnectionObserver /* Notification of one of several types of state changed */ void onStateChange(PCObserverStateType state); - /* Changes to MediaStreams */ + /* Changes to MediaStreamTracks */ void onAddStream(MediaStream stream); void onRemoveStream(); - void onAddTrack(); + void onAddTrack(MediaStreamTrack track); void onRemoveTrack(); }; diff --git a/dom/webidl/RTCPeerConnection.webidl b/dom/webidl/RTCPeerConnection.webidl index 1f09106c0bd..3b56e6de8af 100644 --- a/dom/webidl/RTCPeerConnection.webidl +++ b/dom/webidl/RTCPeerConnection.webidl @@ -107,10 +107,12 @@ interface mozRTCPeerConnection : EventTarget { void removeStream (MediaStream stream); // replaces addStream; fails if already added - // because a track can be part of multiple streams, the id parameter - // indicates which particular stream should be referenced in signaling + // because a track can be part of multiple streams, stream parameters + // indicate which particular streams should be referenced in signaling - RTCRtpSender addTrack(MediaStreamTrack track, DOMString streamId); + RTCRtpSender addTrack(MediaStreamTrack track, + MediaStream stream, + MediaStream... moreStreams); void removeTrack(RTCRtpSender sender); sequence getSenders(); diff --git a/dom/webidl/RTCRtpReceiver.webidl b/dom/webidl/RTCRtpReceiver.webidl index 6c526ca5eeb..94343ea03c3 100644 --- a/dom/webidl/RTCRtpReceiver.webidl +++ b/dom/webidl/RTCRtpReceiver.webidl @@ -8,8 +8,7 @@ */ [Pref="media.peerconnection.enabled", - JSImplementation="@mozilla.org/dom/rtpreceiver;1", - Constructor (MediaStreamTrack track)] + JSImplementation="@mozilla.org/dom/rtpreceiver;1"] interface RTCRtpReceiver { readonly attribute MediaStreamTrack track; }; diff --git a/dom/webidl/RTCRtpSender.webidl b/dom/webidl/RTCRtpSender.webidl index f028f3010ca..f7ffb292ff1 100644 --- a/dom/webidl/RTCRtpSender.webidl +++ b/dom/webidl/RTCRtpSender.webidl @@ -8,8 +8,7 @@ */ [Pref="media.peerconnection.enabled", - JSImplementation="@mozilla.org/dom/rtpsender;1", - Constructor (MediaStreamTrack track)] + JSImplementation="@mozilla.org/dom/rtpsender;1"] interface RTCRtpSender { readonly attribute MediaStreamTrack track; }; diff --git a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp index 42daafede6a..d063ed9a605 100644 --- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp +++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp @@ -2535,6 +2535,10 @@ static int vcmTxStartICE_m(cc_mcapid_t mcap_id, ENSURE_PC(pc, VCM_ERROR); nsRefPtr stream = pc.impl()->media()->GetLocalStream(pc_stream_id); + if (!stream) { + CSFLogError(logTag, "Stream not found"); + return VCM_ERROR; + } // Create the transport flows mozilla::RefPtr rtp_flow = diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp index c025c412a29..8c601434289 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp @@ -285,6 +285,17 @@ public: CSFLogInfo(logTag, "Returning success for OnAddStream()"); // We are running on main thread here so we shouldn't have a race // on this callback + + nsTArray> tracks; + aStream->GetTracks(tracks); + for (uint32_t i = 0; i < tracks.Length(); i++) { + JSErrorResult rv; + mObserver->OnAddTrack(*tracks[i], rv); + if (rv.Failed()) { + CSFLogError(logTag, ": OnAddTrack(%d) failed! Error: %d", i, + rv.ErrorCode()); + } + } JSErrorResult rv; mObserver->OnAddStream(*aStream, rv); if (rv.Failed()) { @@ -1465,7 +1476,7 @@ PeerConnectionImpl::AddStream(DOMMediaStream &aMediaStream) } uint32_t stream_id; - nsresult res = mMedia->AddStream(&aMediaStream, &stream_id); + nsresult res = mMedia->AddStream(&aMediaStream, hints, &stream_id); if (NS_FAILED(res)) { return res; } @@ -1490,15 +1501,141 @@ NS_IMETHODIMP PeerConnectionImpl::RemoveStream(DOMMediaStream& aMediaStream) { PC_AUTO_ENTER_API_CALL(true); + uint32_t hints = aMediaStream.GetHintContents(); + uint32_t stream_id; - nsresult res = mMedia->RemoveStream(&aMediaStream, &stream_id); + nsresult res = mMedia->RemoveStream(&aMediaStream, hints, &stream_id); if (NS_FAILED(res)) return res; aMediaStream.RemovePrincipalChangeObserver(this); + if (hints & DOMMediaStream::HINT_CONTENTS_AUDIO) { + mInternal->mCall->removeStream(stream_id, 0, AUDIO); + MOZ_ASSERT(mNumAudioStreams > 0); + mNumAudioStreams--; + } + + if (hints & DOMMediaStream::HINT_CONTENTS_VIDEO) { + mInternal->mCall->removeStream(stream_id, 1, VIDEO); + MOZ_ASSERT(mNumVideoStreams > 0); + mNumVideoStreams--; + } + + return NS_OK; +} + +nsresult +PeerConnectionImpl::AddTrack(MediaStreamTrack& aTrack, + const Sequence>& aStreams) +{ + PC_AUTO_ENTER_API_CALL(true); + + if (!aStreams.Length()) { + CSFLogError(logTag, "%s: At least one stream arg required", __FUNCTION__); + return NS_ERROR_FAILURE; + } + DOMMediaStream& aMediaStream = aStreams[0]; +#ifdef MOZILLA_INTERNAL_API + if (!aMediaStream.HasTrack(aTrack)) { + CSFLogError(logTag, "%s: Track is not in stream", __FUNCTION__); + return NS_ERROR_FAILURE; + } + uint32_t hints = aMediaStream.GetHintContents() & + ((aTrack.AsAudioStreamTrack()? DOMMediaStream::HINT_CONTENTS_AUDIO : 0) | + (aTrack.AsVideoStreamTrack()? DOMMediaStream::HINT_CONTENTS_VIDEO : 0)); +#else uint32_t hints = aMediaStream.GetHintContents(); +#endif + + // XXX Remove this check once addStream has an error callback + // available and/or we have plumbing to handle multiple + // local audio streams. + if ((hints & DOMMediaStream::HINT_CONTENTS_AUDIO) && + mNumAudioStreams > 0) { + CSFLogError(logTag, "%s: Only one local audio stream is supported for now", + __FUNCTION__); + return NS_ERROR_FAILURE; + } + + // XXX Remove this check once addStream has an error callback + // available and/or we have plumbing to handle multiple + // local video streams. + if ((hints & DOMMediaStream::HINT_CONTENTS_VIDEO) && + mNumVideoStreams > 0) { + CSFLogError(logTag, "%s: Only one local video stream is supported for now", + __FUNCTION__); + return NS_ERROR_FAILURE; + } + + uint32_t num = mMedia->LocalStreamsLength(); + + uint32_t stream_id; + nsresult res = mMedia->AddStream(&aMediaStream, hints, &stream_id); + if (NS_FAILED(res)) { + return res; + } + + if (num != mMedia->LocalStreamsLength()) { + aMediaStream.AddPrincipalChangeObserver(this); + } + + // TODO(ekr@rtfm.com): these integers should be the track IDs + if (hints & DOMMediaStream::HINT_CONTENTS_AUDIO) { + mInternal->mCall->addStream(stream_id, 0, AUDIO); + mNumAudioStreams++; + } + + if (hints & DOMMediaStream::HINT_CONTENTS_VIDEO) { + mInternal->mCall->addStream(stream_id, 1, VIDEO); + mNumVideoStreams++; + } + + return NS_OK; +} + +NS_IMETHODIMP +PeerConnectionImpl::RemoveTrack(MediaStreamTrack& aTrack) { + PC_AUTO_ENTER_API_CALL(true); + + DOMMediaStream *stream = nullptr; +#ifdef MOZILLA_INTERNAL_API + for (uint32_t i = 0; i < mMedia->LocalStreamsLength(); ++i) { + auto* candidate = mMedia->GetLocalStream(i)->GetMediaStream(); + if (candidate->HasTrack(aTrack)) { + stream = candidate; + break; + } + } +#endif + if (!stream) { + CSFLogError(logTag, "%s: Track not found", __FUNCTION__); + return NS_OK; + } + + DOMMediaStream& aMediaStream = *stream; + +#ifdef MOZILLA_INTERNAL_API + uint32_t hints = aMediaStream.GetHintContents() & + ((aTrack.AsAudioStreamTrack()? DOMMediaStream::HINT_CONTENTS_AUDIO : 0) | + (aTrack.AsVideoStreamTrack()? DOMMediaStream::HINT_CONTENTS_VIDEO : 0)); +#else + uint32_t hints = aMediaStream.GetHintContents(); +#endif + + uint32_t num = mMedia->LocalStreamsLength(); + + uint32_t stream_id; + nsresult res = mMedia->RemoveStream(&aMediaStream, hints, &stream_id); + + if (NS_FAILED(res)) { + return res; + } + + if (num != mMedia->LocalStreamsLength()) { + aMediaStream.RemovePrincipalChangeObserver(this); + } if (hints & DOMMediaStream::HINT_CONTENTS_AUDIO) { mInternal->mCall->removeStream(stream_id, 0, AUDIO); diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h index 05e1f0384e3..67299d00705 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h @@ -375,6 +375,18 @@ public: rv = RemoveStream(aMediaStream); } + NS_IMETHODIMP_TO_ERRORRESULT(AddTrack, ErrorResult &rv, + mozilla::dom::MediaStreamTrack& aTrack, + const mozilla::dom::Sequence>& aStreams) + { + rv = AddTrack(aTrack, aStreams); + } + + NS_IMETHODIMP_TO_ERRORRESULT(RemoveTrack, ErrorResult &rv, + mozilla::dom::MediaStreamTrack& aTrack) + { + rv = RemoveTrack(aTrack); + } nsresult GetPeerIdentity(nsAString& peerIdentity) { diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp index 347ff6c35d8..46e9ea928b7 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp @@ -43,6 +43,12 @@ LocalSourceStreamInfo::ExpectAudio(const mozilla::TrackID aID) mAudioTracks.AppendElement(aID); } +void +LocalSourceStreamInfo::RemoveAudio(const mozilla::TrackID aID) +{ + mAudioTracks.RemoveElement(aID); +} + // If the ExpectVideo hint is on we will add a track at the default first // video track ID (1). void @@ -51,6 +57,12 @@ LocalSourceStreamInfo::ExpectVideo(const mozilla::TrackID aID) mVideoTracks.AppendElement(aID); } +void +LocalSourceStreamInfo::RemoveVideo(const mozilla::TrackID aID) +{ + mVideoTracks.RemoveElement(aID); +} + unsigned LocalSourceStreamInfo::AudioTrackCount() { @@ -234,7 +246,9 @@ nsresult PeerConnectionMedia::Init(const std::vector& stun_serv } nsresult -PeerConnectionMedia::AddStream(nsIDOMMediaStream* aMediaStream, uint32_t *stream_id) +PeerConnectionMedia::AddStream(nsIDOMMediaStream* aMediaStream, + uint32_t hints, + uint32_t *stream_id) { ASSERT_ON_THREAD(mMainThread); @@ -245,11 +259,9 @@ PeerConnectionMedia::AddStream(nsIDOMMediaStream* aMediaStream, uint32_t *stream DOMMediaStream* stream = static_cast(aMediaStream); - CSFLogDebug(logTag, "%s: MediaStream: %p", - __FUNCTION__, aMediaStream); + CSFLogDebug(logTag, "%s: MediaStream: %p", __FUNCTION__, aMediaStream); // Adding tracks here based on nsDOMMediaStream expectation settings - uint32_t hints = stream->GetHintContents(); #ifdef MOZILLA_INTERNAL_API if (!Preferences::GetBool("media.peerconnection.video.enabled", true)) { hints &= ~(DOMMediaStream::HINT_CONTENTS_VIDEO); @@ -262,23 +274,30 @@ PeerConnectionMedia::AddStream(nsIDOMMediaStream* aMediaStream, uint32_t *stream return NS_OK; } - // Now see if we already have a stream of this type, since we only - // allow one of each. + // Now see if we already have this stream or another stream with + // tracks of the same type, since we only allow one track of each type. // TODO(ekr@rtfm.com): remove this when multiple of each stream // is allowed - for (uint32_t u = 0; u < mLocalSourceStreams.Length(); u++) { - nsRefPtr localSourceStream = mLocalSourceStreams[u]; + nsRefPtr localSourceStream = nullptr; - if (localSourceStream->GetMediaStream()->GetHintContents() & hints) { + for (uint32_t u = 0; u < mLocalSourceStreams.Length(); u++) { + auto& lss = mLocalSourceStreams[u]; + if (((hints & DOMMediaStream::HINT_CONTENTS_AUDIO) && lss->AudioTrackCount()) || + ((hints & DOMMediaStream::HINT_CONTENTS_VIDEO) && lss->VideoTrackCount())) { CSFLogError(logTag, "Only one stream of any given type allowed"); return NS_ERROR_FAILURE; } + if (stream == lss->GetMediaStream()) { + localSourceStream = lss; + *stream_id = u; + break; + } + } + if (!localSourceStream) { + localSourceStream = new LocalSourceStreamInfo(stream, this); + mLocalSourceStreams.AppendElement(localSourceStream); + *stream_id = mLocalSourceStreams.Length() - 1; } - - // OK, we're good to add - nsRefPtr localSourceStream = - new LocalSourceStreamInfo(stream, this); - *stream_id = mLocalSourceStreams.Length(); if (hints & DOMMediaStream::HINT_CONTENTS_AUDIO) { localSourceStream->ExpectAudio(TRACK_AUDIO); @@ -287,14 +306,13 @@ PeerConnectionMedia::AddStream(nsIDOMMediaStream* aMediaStream, uint32_t *stream if (hints & DOMMediaStream::HINT_CONTENTS_VIDEO) { localSourceStream->ExpectVideo(TRACK_VIDEO); } - - mLocalSourceStreams.AppendElement(localSourceStream); - return NS_OK; } nsresult -PeerConnectionMedia::RemoveStream(nsIDOMMediaStream* aMediaStream, uint32_t *stream_id) +PeerConnectionMedia::RemoveStream(nsIDOMMediaStream* aMediaStream, + uint32_t hints, + uint32_t *stream_id) { MOZ_ASSERT(aMediaStream); ASSERT_ON_THREAD(mMainThread); @@ -308,6 +326,17 @@ PeerConnectionMedia::RemoveStream(nsIDOMMediaStream* aMediaStream, uint32_t *str nsRefPtr localSourceStream = mLocalSourceStreams[u]; if (localSourceStream->GetMediaStream() == stream) { *stream_id = u; + + if (hints & DOMMediaStream::HINT_CONTENTS_AUDIO) { + localSourceStream->RemoveAudio(TRACK_AUDIO); + } + if (hints & DOMMediaStream::HINT_CONTENTS_VIDEO) { + localSourceStream->RemoveAudio(TRACK_VIDEO); + } + if (!(localSourceStream->AudioTrackCount() + + localSourceStream->VideoTrackCount())) { + mLocalSourceStreams.RemoveElementAt(u); + } return NS_OK; } } diff --git a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h index 0ab20580036..4d34dafb735 100644 --- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h +++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h @@ -226,6 +226,8 @@ public: void ExpectAudio(const mozilla::TrackID); void ExpectVideo(const mozilla::TrackID); + void RemoveAudio(const mozilla::TrackID); + void RemoveVideo(const mozilla::TrackID); unsigned AudioTrackCount(); unsigned VideoTrackCount(); void DetachTransport_s(); @@ -301,10 +303,13 @@ class PeerConnectionMedia : public sigslot::has_slots<> { } // Add a stream (main thread only) - nsresult AddStream(nsIDOMMediaStream* aMediaStream, uint32_t *stream_id); + nsresult AddStream(nsIDOMMediaStream* aMediaStream, uint32_t hints, + uint32_t *stream_id); // Remove a stream (main thread only) - nsresult RemoveStream(nsIDOMMediaStream* aMediaStream, uint32_t *stream_id); + nsresult RemoveStream(nsIDOMMediaStream* aMediaStream, + uint32_t hints, + uint32_t *stream_id); // Get a specific local stream uint32_t LocalStreamsLength()