Index: talk/app/webrtc/peerconnection.cc |
diff --git a/talk/app/webrtc/peerconnection.cc b/talk/app/webrtc/peerconnection.cc |
index fecc19ba0ebce95bd9a911eac9ef280fa80302ee..138da5b33a75b98fff5185ce455b06e6b6bf5816 100644 |
--- a/talk/app/webrtc/peerconnection.cc |
+++ b/talk/app/webrtc/peerconnection.cc |
@@ -59,6 +59,7 @@ using webrtc::DataChannel; |
using webrtc::MediaConstraintsInterface; |
using webrtc::MediaStreamInterface; |
using webrtc::PeerConnectionInterface; |
+using webrtc::RtpSenderInterface; |
using webrtc::StreamCollection; |
using webrtc::StunConfigurations; |
using webrtc::TurnConfigurations; |
@@ -365,25 +366,15 @@ bool IsValidOfferToReceiveMedia(int value) { |
} |
// Add the stream and RTP data channel info to |session_options|. |
-void SetStreams(cricket::MediaSessionOptions* session_options, |
- rtc::scoped_refptr<StreamCollection> streams, |
- const std::map<std::string, rtc::scoped_refptr<DataChannel>>& |
- rtp_data_channels) { |
+void AddSendStreams( |
+ cricket::MediaSessionOptions* session_options, |
+ const std::vector<rtc::scoped_refptr<RtpSenderInterface>>& senders, |
+ const std::map<std::string, rtc::scoped_refptr<DataChannel>>& |
+ rtp_data_channels) { |
session_options->streams.clear(); |
- if (streams != nullptr) { |
- for (size_t i = 0; i < streams->count(); ++i) { |
- MediaStreamInterface* stream = streams->at(i); |
- // For each audio track in the stream, add it to the MediaSessionOptions. |
- for (const auto& track : stream->GetAudioTracks()) { |
- session_options->AddSendStream(cricket::MEDIA_TYPE_AUDIO, track->id(), |
- stream->label()); |
- } |
- // For each video track in the stream, add it to the MediaSessionOptions. |
- for (const auto& track : stream->GetVideoTracks()) { |
- session_options->AddSendStream(cricket::MEDIA_TYPE_VIDEO, track->id(), |
- stream->label()); |
- } |
- } |
+ for (const auto& sender : senders) { |
+ session_options->AddSendStream(sender->media_type(), sender->id(), |
+ sender->stream_id()); |
} |
// Check for data channels. |
@@ -668,8 +659,6 @@ PeerConnection::remote_streams() { |
return remote_streams_; |
} |
-// TODO(deadbeef): Create RtpSenders immediately here, even if local |
-// description hasn't yet been set. |
bool PeerConnection::AddStream(MediaStreamInterface* local_stream) { |
if (IsClosed()) { |
return false; |
@@ -680,23 +669,46 @@ bool PeerConnection::AddStream(MediaStreamInterface* local_stream) { |
local_streams_->AddStream(local_stream); |
- // Find tracks that have already been configured in SDP. This can occur if a |
- // local session description that contains the MSID of these tracks is set |
- // before AddLocalStream is called. It can also occur if the local session |
- // description is not changed and RemoveLocalStream is called and later |
- // AddLocalStream is called again with the same stream. |
for (const auto& track : local_stream->GetAudioTracks()) { |
- const TrackInfo* track_info = |
- FindTrackInfo(local_audio_tracks_, local_stream->label(), track->id()); |
- if (track_info) { |
- CreateAudioSender(local_stream, track.get(), track_info->ssrc); |
+ auto sender = FindSenderForTrack(track.get()); |
+ if (sender == senders_.end()) { |
+ // Normal case; we've never seen this track before. |
+ AudioRtpSender* new_sender = new AudioRtpSender( |
+ track.get(), local_stream->label(), session_.get(), stats_.get()); |
+ senders_.push_back(new_sender); |
+ // If the sender has already been configured in SDP, we call SetSsrc, |
+ // which will connect the sender to the underlying transport. This can |
+ // occur if a local session description that contains the ID of the sender |
+ // is set before AddStream is called. It can also occur if the local |
+ // session description is not changed and RemoveStream is called, and |
+ // later AddStream is called again with the same stream. |
+ const TrackInfo* track_info = FindTrackInfo( |
+ local_audio_tracks_, local_stream->label(), track->id()); |
+ if (track_info) { |
+ new_sender->SetSsrc(track_info->ssrc); |
+ } |
+ } else { |
+ // We already have a sender for this track, so just change the stream_id |
+ // so that it's correct in the next call to CreateOffer. |
+ (*sender)->set_stream_id(local_stream->label()); |
} |
} |
for (const auto& track : local_stream->GetVideoTracks()) { |
- const TrackInfo* track_info = |
- FindTrackInfo(local_video_tracks_, local_stream->label(), track->id()); |
- if (track_info) { |
- CreateVideoSender(local_stream, track.get(), track_info->ssrc); |
+ auto sender = FindSenderForTrack(track.get()); |
+ if (sender == senders_.end()) { |
+ // Normal case; we've never seen this track before. |
+ VideoRtpSender* new_sender = new VideoRtpSender( |
+ track.get(), local_stream->label(), session_.get()); |
+ senders_.push_back(new_sender); |
+ const TrackInfo* track_info = FindTrackInfo( |
+ local_video_tracks_, local_stream->label(), track->id()); |
+ if (track_info) { |
+ new_sender->SetSsrc(track_info->ssrc); |
+ } |
+ } else { |
+ // We already have a sender for this track, so just change the stream_id |
+ // so that it's correct in the next call to CreateOffer. |
+ (*sender)->set_stream_id(local_stream->label()); |
} |
} |
@@ -706,21 +718,27 @@ bool PeerConnection::AddStream(MediaStreamInterface* local_stream) { |
} |
// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around |
-// indefinitely. |
+// indefinitely, when we have unified plan SDP. |
void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) { |
for (const auto& track : local_stream->GetAudioTracks()) { |
- const TrackInfo* track_info = |
- FindTrackInfo(local_audio_tracks_, local_stream->label(), track->id()); |
- if (track_info) { |
- DestroyAudioSender(local_stream, track.get(), track_info->ssrc); |
+ auto sender = FindSenderForTrack(track.get()); |
+ if (sender == senders_.end()) { |
+ LOG(LS_WARNING) << "RtpSender for track with id " << track->id() |
+ << " doesn't exist."; |
+ continue; |
} |
+ (*sender)->Stop(); |
+ senders_.erase(sender); |
} |
for (const auto& track : local_stream->GetVideoTracks()) { |
- const TrackInfo* track_info = |
- FindTrackInfo(local_video_tracks_, local_stream->label(), track->id()); |
- if (track_info) { |
- DestroyVideoSender(local_stream, track.get()); |
+ auto sender = FindSenderForTrack(track.get()); |
+ if (sender == senders_.end()) { |
+ LOG(LS_WARNING) << "RtpSender for track with id " << track->id() |
+ << " doesn't exist."; |
+ continue; |
} |
+ (*sender)->Stop(); |
+ senders_.erase(sender); |
} |
local_streams_->RemoveStream(local_stream); |
@@ -751,6 +769,21 @@ rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender( |
return DtmfSenderProxy::Create(signaling_thread(), sender.get()); |
} |
+rtc::scoped_refptr<RtpSenderInterface> PeerConnection::CreateSender( |
+ const std::string& kind) { |
+ RtpSenderInterface* new_sender; |
+ if (kind == MediaStreamTrackInterface::kAudioTrackKind) { |
+ new_sender = new AudioRtpSender(session_.get(), stats_.get()); |
+ } else if (kind == MediaStreamTrackInterface::kVideoTrackKind) { |
+ new_sender = new VideoRtpSender(session_.get()); |
+ } else { |
+ LOG(LS_ERROR) << "CreateSender called with invalid kind: " << kind; |
+ return rtc::scoped_refptr<RtpSenderInterface>(); |
+ } |
+ senders_.push_back(new_sender); |
+ return RtpSenderProxy::Create(signaling_thread(), new_sender); |
+} |
+ |
std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders() |
const { |
std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders; |
@@ -1267,49 +1300,6 @@ void PeerConnection::DestroyVideoReceiver(MediaStreamInterface* stream, |
} |
} |
-void PeerConnection::CreateAudioSender(MediaStreamInterface* stream, |
- AudioTrackInterface* audio_track, |
- uint32_t ssrc) { |
- senders_.push_back(new AudioRtpSender(audio_track, ssrc, session_.get())); |
- stats_->AddLocalAudioTrack(audio_track, ssrc); |
-} |
- |
-void PeerConnection::CreateVideoSender(MediaStreamInterface* stream, |
- VideoTrackInterface* video_track, |
- uint32_t ssrc) { |
- senders_.push_back(new VideoRtpSender(video_track, ssrc, session_.get())); |
-} |
- |
-// TODO(deadbeef): Keep RtpSenders around even if track goes away in local |
-// description. |
-void PeerConnection::DestroyAudioSender(MediaStreamInterface* stream, |
- AudioTrackInterface* audio_track, |
- uint32_t ssrc) { |
- auto it = FindSenderForTrack(audio_track); |
- if (it == senders_.end()) { |
- LOG(LS_WARNING) << "RtpSender for track with id " << audio_track->id() |
- << " doesn't exist."; |
- return; |
- } else { |
- (*it)->Stop(); |
- senders_.erase(it); |
- } |
- stats_->RemoveLocalAudioTrack(audio_track, ssrc); |
-} |
- |
-void PeerConnection::DestroyVideoSender(MediaStreamInterface* stream, |
- VideoTrackInterface* video_track) { |
- auto it = FindSenderForTrack(video_track); |
- if (it == senders_.end()) { |
- LOG(LS_WARNING) << "RtpSender for track with id " << video_track->id() |
- << " doesn't exist."; |
- return; |
- } else { |
- (*it)->Stop(); |
- senders_.erase(it); |
- } |
-} |
- |
void PeerConnection::OnIceConnectionChange( |
PeerConnectionInterface::IceConnectionState new_state) { |
RTC_DCHECK(signaling_thread()->IsCurrent()); |
@@ -1385,7 +1375,7 @@ bool PeerConnection::GetOptionsForOffer( |
return false; |
} |
- SetStreams(session_options, local_streams_, rtp_data_channels_); |
+ AddSendStreams(session_options, senders_, rtp_data_channels_); |
// Offer to receive audio/video if the constraint is not set and there are |
// send streams, or we're currently receiving. |
if (rtc_options.offer_to_receive_audio == RTCOfferAnswerOptions::kUndefined) { |
@@ -1418,7 +1408,7 @@ bool PeerConnection::GetOptionsForAnswer( |
return false; |
} |
- SetStreams(session_options, local_streams_, rtp_data_channels_); |
+ AddSendStreams(session_options, senders_, rtp_data_channels_); |
session_options->bundle_enabled = |
session_options->bundle_enabled && |
(session_options->has_audio() || session_options->has_video() || |
@@ -1440,8 +1430,7 @@ void PeerConnection::UpdateRemoteStreamsList( |
TrackInfos* current_tracks = GetRemoteTracks(media_type); |
// Find removed tracks. I.e., tracks where the track id or ssrc don't match |
- // the |
- // new StreamParam. |
+ // the new StreamParam. |
auto track_it = current_tracks->begin(); |
while (track_it != current_tracks->end()) { |
const TrackInfo& info = *track_it; |
@@ -1643,62 +1632,44 @@ void PeerConnection::OnLocalTrackSeen(const std::string& stream_label, |
const std::string& track_id, |
uint32_t ssrc, |
cricket::MediaType media_type) { |
- MediaStreamInterface* stream = local_streams_->find(stream_label); |
- if (!stream) { |
- LOG(LS_WARNING) << "An unknown local MediaStream with label " |
- << stream_label << " has been configured."; |
+ RtpSenderInterface* sender = FindSenderById(track_id); |
+ if (!sender) { |
+ LOG(LS_WARNING) << "An unknown RtpSender with id " << track_id |
+ << " has been configured in the local description."; |
return; |
} |
- if (media_type == cricket::MEDIA_TYPE_AUDIO) { |
- AudioTrackInterface* audio_track = stream->FindAudioTrack(track_id); |
- if (!audio_track) { |
- LOG(LS_WARNING) << "An unknown local AudioTrack with id , " << track_id |
- << " has been configured."; |
- return; |
- } |
- CreateAudioSender(stream, audio_track, ssrc); |
- } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { |
- VideoTrackInterface* video_track = stream->FindVideoTrack(track_id); |
- if (!video_track) { |
- LOG(LS_WARNING) << "An unknown local VideoTrack with id , " << track_id |
- << " has been configured."; |
- return; |
- } |
- CreateVideoSender(stream, video_track, ssrc); |
- } else { |
- RTC_DCHECK(false && "Invalid media type"); |
+ if (sender->media_type() != media_type) { |
+ LOG(LS_WARNING) << "An RtpSender has been configured in the local" |
+ << " description with an unexpected media type."; |
+ return; |
} |
+ |
+ sender->set_stream_id(stream_label); |
+ sender->SetSsrc(ssrc); |
} |
void PeerConnection::OnLocalTrackRemoved(const std::string& stream_label, |
const std::string& track_id, |
uint32_t ssrc, |
cricket::MediaType media_type) { |
- MediaStreamInterface* stream = local_streams_->find(stream_label); |
- if (!stream) { |
- // This is the normal case. I.e., RemoveLocalStream has been called and the |
+ RtpSenderInterface* sender = FindSenderById(track_id); |
+ if (!sender) { |
+ // This is the normal case. I.e., RemoveStream has been called and the |
// SessionDescriptions has been renegotiated. |
return; |
} |
- // A track has been removed from the SessionDescription but the MediaStream |
- // is still associated with PeerConnection. This only occurs if the SDP |
- // doesn't match with the calls to AddLocalStream and RemoveLocalStream. |
- if (media_type == cricket::MEDIA_TYPE_AUDIO) { |
- AudioTrackInterface* audio_track = stream->FindAudioTrack(track_id); |
- if (!audio_track) { |
- return; |
- } |
- DestroyAudioSender(stream, audio_track, ssrc); |
- } else if (media_type == cricket::MEDIA_TYPE_VIDEO) { |
- VideoTrackInterface* video_track = stream->FindVideoTrack(track_id); |
- if (!video_track) { |
- return; |
- } |
- DestroyVideoSender(stream, video_track); |
- } else { |
- RTC_DCHECK(false && "Invalid media type."); |
+ |
+ // A sender has been removed from the SessionDescription but it's still |
+ // associated with the PeerConnection. This only occurs if the SDP doesn't |
+ // match with the calls to CreateSender, AddStream and RemoveStream. |
+ if (sender->media_type() != media_type) { |
+ LOG(LS_WARNING) << "An RtpSender has been configured in the local" |
+ << " description with an unexpected media type."; |
+ return; |
} |
+ |
+ sender->SetSsrc(0); |
} |
void PeerConnection::UpdateLocalRtpDataChannels( |
@@ -1916,6 +1887,15 @@ void PeerConnection::OnDataChannelOpenMessage( |
DataChannelProxy::Create(signaling_thread(), channel)); |
} |
+RtpSenderInterface* PeerConnection::FindSenderById(const std::string& id) { |
+ auto it = |
+ std::find_if(senders_.begin(), senders_.end(), |
+ [id](const rtc::scoped_refptr<RtpSenderInterface>& sender) { |
+ return sender->id() == id; |
+ }); |
+ return it != senders_.end() ? it->get() : nullptr; |
+} |
+ |
std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator |
PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) { |
return std::find_if( |