diff --git a/webrtc/media/base/streamparams.h b/webrtc/media/base/streamparams.h index 75d82809cf..5d7feafbe3 100644 --- a/webrtc/media/base/streamparams.h +++ b/webrtc/media/base/streamparams.h @@ -252,6 +252,13 @@ const StreamParams* GetStream(const StreamParamsVec& streams, return found == streams.end() ? nullptr : &(*found); } +template +StreamParams* GetStream(StreamParamsVec& streams, Condition condition) { + StreamParamsVec::iterator found = + std::find_if(streams.begin(), streams.end(), condition); + return found == streams.end() ? nullptr : &(*found); +} + inline const StreamParams* GetStreamBySsrc(const StreamParamsVec& streams, uint32_t ssrc) { return GetStream(streams, @@ -261,6 +268,14 @@ inline const StreamParams* GetStreamBySsrc(const StreamParamsVec& streams, inline const StreamParams* GetStreamByIds(const StreamParamsVec& streams, const std::string& groupid, const std::string& id) { + return GetStream(streams, [&groupid, &id](const StreamParams& sp) { + return sp.groupid == groupid && sp.id == id; + }); +} + +inline StreamParams* GetStreamByIds(StreamParamsVec& streams, + const std::string& groupid, + const std::string& id) { return GetStream(streams, [&groupid, &id](const StreamParams& sp) { return sp.groupid == groupid && sp.id == id; diff --git a/webrtc/pc/mediasession.cc b/webrtc/pc/mediasession.cc index dbd32566d5..0df65297db 100644 --- a/webrtc/pc/mediasession.cc +++ b/webrtc/pc/mediasession.cc @@ -448,8 +448,7 @@ static bool AddStreamParams(MediaType media_type, if (stream_it->type != media_type) continue; // Wrong media type. - const StreamParams* param = - GetStreamByIds(*current_streams, "", stream_it->id); + StreamParams* param = GetStreamByIds(*current_streams, "", stream_it->id); // groupid is empty for StreamParams generated using // MediaSessionDescriptionFactory. if (!param) { @@ -500,6 +499,10 @@ static bool AddStreamParams(MediaType media_type, // This is necessary so that we can use the CNAME for other media types. current_streams->push_back(stream_param); } else { + // Use existing generated SSRCs/groups, but update the sync_label if + // necessary. This may be needed if a MediaStreamTrack was moved from one + // MediaStream to another. + param->sync_label = stream_it->sync_label; content_description->AddStream(*param); } } diff --git a/webrtc/pc/peerconnection_integrationtest.cc b/webrtc/pc/peerconnection_integrationtest.cc index d818300c23..49771f60a4 100644 --- a/webrtc/pc/peerconnection_integrationtest.cc +++ b/webrtc/pc/peerconnection_integrationtest.cc @@ -217,6 +217,10 @@ class PeerConnectionWrapper : public webrtc::PeerConnectionObserver, return client; } + webrtc::PeerConnectionFactoryInterface* pc_factory() const { + return peer_connection_factory_.get(); + } + webrtc::PeerConnectionInterface* pc() const { return peer_connection_.get(); } // If a signaling message receiver is set (via ConnectFakeSignaling), this @@ -2773,6 +2777,38 @@ TEST_F(PeerConnectionIntegrationTest, GetSources) { contributing_sources[0].source_id()); } +// Test that if a track is removed and added again with a different stream ID, +// the new stream ID is successfully communicated in SDP and media continues to +// flow end-to-end. +TEST_F(PeerConnectionIntegrationTest, RemoveAndAddTrackWithNewStreamId) { + ASSERT_TRUE(CreatePeerConnectionWrappers()); + ConnectFakeSignaling(); + + rtc::scoped_refptr stream_1 = + caller()->pc_factory()->CreateLocalMediaStream("stream_1"); + rtc::scoped_refptr stream_2 = + caller()->pc_factory()->CreateLocalMediaStream("stream_2"); + + // Add track using stream 1, do offer/answer. + rtc::scoped_refptr track = + caller()->CreateLocalAudioTrack(); + rtc::scoped_refptr sender = + caller()->pc()->AddTrack(track, {stream_1.get()}); + caller()->CreateAndSetAndSignalOffer(); + ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout); + // Wait for one audio frame to be received by the callee. + ExpectNewFramesReceivedWithWait(0, 0, 1, 0, kMaxWaitForFramesMs); + + // Remove the sender, and create a new one with the new stream. + caller()->pc()->RemoveTrack(sender); + sender = caller()->pc()->AddTrack(track, {stream_2.get()}); + caller()->CreateAndSetAndSignalOffer(); + ASSERT_TRUE_WAIT(SignalingStateStable(), kDefaultTimeout); + // Wait for additional audio frames to be received by the callee. + ExpectNewFramesReceivedWithWait(0, 0, kDefaultExpectedAudioFrameCount, 0, + kMaxWaitForFramesMs); +} + } // namespace #endif // if !defined(THREAD_SANITIZER)