blob: 8e3672994dff1e694050a6e0f7b42973c381332e [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellanderb24317b2016-02-10 07:54:43 -08002 * Copyright 2012 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellanderb24317b2016-02-10 07:54:43 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "pc/peerconnection.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
deadbeefeb459812015-12-15 19:24:43 -080013#include <algorithm>
Steve Anton75737c02017-11-06 10:37:17 -080014#include <set>
kwiberg0eb15ed2015-12-17 03:04:15 -080015#include <utility>
16#include <vector>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "api/jsepicecandidate.h"
19#include "api/jsepsessiondescription.h"
20#include "api/mediaconstraintsinterface.h"
21#include "api/mediastreamproxy.h"
22#include "api/mediastreamtrackproxy.h"
23#include "call/call.h"
Elad Alon83ccca12017-10-04 13:18:26 +020024#include "logging/rtc_event_log/output/rtc_event_log_output_file.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "logging/rtc_event_log/rtc_event_log.h"
26#include "media/sctp/sctptransport.h"
27#include "pc/audiotrack.h"
Steve Anton75737c02017-11-06 10:37:17 -080028#include "pc/channel.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "pc/channelmanager.h"
30#include "pc/dtmfsender.h"
31#include "pc/mediastream.h"
32#include "pc/mediastreamobserver.h"
33#include "pc/remoteaudiosource.h"
34#include "pc/rtpreceiver.h"
35#include "pc/rtpsender.h"
Steve Anton75737c02017-11-06 10:37:17 -080036#include "pc/sctputils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020037#include "pc/streamcollection.h"
38#include "pc/videocapturertracksource.h"
39#include "pc/videotrack.h"
40#include "rtc_base/bind.h"
41#include "rtc_base/checks.h"
42#include "rtc_base/logging.h"
Elad Alon83ccca12017-10-04 13:18:26 +020043#include "rtc_base/ptr_util.h"
44#include "rtc_base/safe_conversions.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020045#include "rtc_base/stringencode.h"
46#include "rtc_base/stringutils.h"
47#include "rtc_base/trace_event.h"
48#include "system_wrappers/include/clock.h"
49#include "system_wrappers/include/field_trial.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000050
Steve Anton75737c02017-11-06 10:37:17 -080051using cricket::ContentInfo;
52using cricket::ContentInfos;
53using cricket::MediaContentDescription;
54using cricket::SessionDescription;
55using cricket::TransportInfo;
56
57using cricket::LOCAL_PORT_TYPE;
58using cricket::STUN_PORT_TYPE;
59using cricket::RELAY_PORT_TYPE;
60using cricket::PRFLX_PORT_TYPE;
61
Steve Antonba818672017-11-06 10:21:57 -080062namespace webrtc {
63
Steve Anton75737c02017-11-06 10:37:17 -080064// Error messages
65const char kBundleWithoutRtcpMux[] =
66 "rtcp-mux must be enabled when BUNDLE "
67 "is enabled.";
68const char kCreateChannelFailed[] = "Failed to create channels.";
69const char kInvalidCandidates[] = "Description contains invalid candidates.";
70const char kInvalidSdp[] = "Invalid session description.";
71const char kMlineMismatchInAnswer[] =
72 "The order of m-lines in answer doesn't match order in offer. Rejecting "
73 "answer.";
74const char kMlineMismatchInSubsequentOffer[] =
75 "The order of m-lines in subsequent offer doesn't match order from "
76 "previous offer/answer.";
77const char kPushDownTDFailed[] = "Failed to push down transport description:";
78const char kSdpWithoutDtlsFingerprint[] =
79 "Called with SDP without DTLS fingerprint.";
80const char kSdpWithoutSdesCrypto[] = "Called with SDP without SDES crypto.";
81const char kSdpWithoutIceUfragPwd[] =
82 "Called with SDP without ice-ufrag and ice-pwd.";
83const char kSessionError[] = "Session error code: ";
84const char kSessionErrorDesc[] = "Session error description: ";
85const char kDtlsSrtpSetupFailureRtp[] =
86 "Couldn't set up DTLS-SRTP on RTP channel.";
87const char kDtlsSrtpSetupFailureRtcp[] =
88 "Couldn't set up DTLS-SRTP on RTCP channel.";
89const char kEnableBundleFailed[] = "Failed to enable BUNDLE.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000090
Steve Anton75737c02017-11-06 10:37:17 -080091namespace {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000092
deadbeefab9b2d12015-10-14 11:33:11 -070093static const char kDefaultStreamLabel[] = "default";
94static const char kDefaultAudioTrackLabel[] = "defaulta0";
95static const char kDefaultVideoTrackLabel[] = "defaultv0";
96
zhihuang8f65cdf2016-05-06 18:40:30 -070097// The length of RTCP CNAMEs.
98static const int kRtcpCnameLength = 16;
99
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000101 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000102 MSG_SET_SESSIONDESCRIPTION_FAILED,
deadbeefab9b2d12015-10-14 11:33:11 -0700103 MSG_CREATE_SESSIONDESCRIPTION_FAILED,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000104 MSG_GETSTATS,
deadbeefbd292462015-12-14 18:15:29 -0800105 MSG_FREE_DATACHANNELS,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106};
107
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000108struct SetSessionDescriptionMsg : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109 explicit SetSessionDescriptionMsg(
110 webrtc::SetSessionDescriptionObserver* observer)
111 : observer(observer) {
112 }
113
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000114 rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115 std::string error;
116};
117
deadbeefab9b2d12015-10-14 11:33:11 -0700118struct CreateSessionDescriptionMsg : public rtc::MessageData {
119 explicit CreateSessionDescriptionMsg(
120 webrtc::CreateSessionDescriptionObserver* observer)
121 : observer(observer) {}
122
123 rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserver> observer;
124 std::string error;
125};
126
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000127struct GetStatsMsg : public rtc::MessageData {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000128 GetStatsMsg(webrtc::StatsObserver* observer,
129 webrtc::MediaStreamTrackInterface* track)
130 : observer(observer), track(track) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000132 rtc::scoped_refptr<webrtc::StatsObserver> observer;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000133 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134};
135
deadbeefab9b2d12015-10-14 11:33:11 -0700136// Check if we can send |new_stream| on a PeerConnection.
137bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
138 webrtc::MediaStreamInterface* new_stream) {
139 if (!new_stream || !current_streams) {
140 return false;
141 }
142 if (current_streams->find(new_stream->label()) != nullptr) {
143 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
144 << " is already added.";
145 return false;
146 }
147 return true;
148}
149
150bool MediaContentDirectionHasSend(cricket::MediaContentDirection dir) {
151 return dir == cricket::MD_SENDONLY || dir == cricket::MD_SENDRECV;
152}
153
deadbeef5e97fb52015-10-15 12:49:08 -0700154// If the direction is "recvonly" or "inactive", treat the description
155// as containing no streams.
156// See: https://code.google.com/p/webrtc/issues/detail?id=5054
157std::vector<cricket::StreamParams> GetActiveStreams(
158 const cricket::MediaContentDescription* desc) {
159 return MediaContentDirectionHasSend(desc->direction())
160 ? desc->streams()
161 : std::vector<cricket::StreamParams>();
162}
163
deadbeefab9b2d12015-10-14 11:33:11 -0700164bool IsValidOfferToReceiveMedia(int value) {
165 typedef PeerConnectionInterface::RTCOfferAnswerOptions Options;
166 return (value >= Options::kUndefined) &&
167 (value <= Options::kMaxOfferToReceiveMedia);
168}
169
zhihuang1c378ed2017-08-17 14:10:50 -0700170// Add options to |[audio/video]_media_description_options| from |senders|.
171void AddRtpSenderOptions(
deadbeefa601f5c2016-06-06 14:27:39 -0700172 const std::vector<rtc::scoped_refptr<
173 RtpSenderProxyWithInternal<RtpSenderInternal>>>& senders,
zhihuang1c378ed2017-08-17 14:10:50 -0700174 cricket::MediaDescriptionOptions* audio_media_description_options,
175 cricket::MediaDescriptionOptions* video_media_description_options) {
olka3c747662017-08-17 06:50:32 -0700176 for (const auto& sender : senders) {
zhihuang1c378ed2017-08-17 14:10:50 -0700177 if (sender->media_type() == cricket::MEDIA_TYPE_AUDIO) {
178 if (audio_media_description_options) {
179 audio_media_description_options->AddAudioSender(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700180 sender->id(), sender->internal()->stream_ids());
zhihuang1c378ed2017-08-17 14:10:50 -0700181 }
182 } else {
183 RTC_DCHECK(sender->media_type() == cricket::MEDIA_TYPE_VIDEO);
184 if (video_media_description_options) {
185 video_media_description_options->AddVideoSender(
Steve Anton8ffb9c32017-08-31 15:45:38 -0700186 sender->id(), sender->internal()->stream_ids(), 1);
zhihuang1c378ed2017-08-17 14:10:50 -0700187 }
188 }
zhihuanga77e6bb2017-08-14 18:17:48 -0700189 }
zhihuang1c378ed2017-08-17 14:10:50 -0700190}
olka3c747662017-08-17 06:50:32 -0700191
zhihuang1c378ed2017-08-17 14:10:50 -0700192// Add options to |session_options| from |rtp_data_channels|.
193void AddRtpDataChannelOptions(
194 const std::map<std::string, rtc::scoped_refptr<DataChannel>>&
195 rtp_data_channels,
196 cricket::MediaDescriptionOptions* data_media_description_options) {
197 if (!data_media_description_options) {
198 return;
199 }
deadbeefab9b2d12015-10-14 11:33:11 -0700200 // Check for data channels.
201 for (const auto& kv : rtp_data_channels) {
202 const DataChannel* channel = kv.second;
203 if (channel->state() == DataChannel::kConnecting ||
204 channel->state() == DataChannel::kOpen) {
zhihuang1c378ed2017-08-17 14:10:50 -0700205 // Legacy RTP data channels are signaled with the track/stream ID set to
206 // the data channel's label.
207 data_media_description_options->AddRtpDataChannel(channel->label(),
208 channel->label());
deadbeefab9b2d12015-10-14 11:33:11 -0700209 }
210 }
211}
212
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700213uint32_t ConvertIceTransportTypeToCandidateFilter(
214 PeerConnectionInterface::IceTransportsType type) {
215 switch (type) {
216 case PeerConnectionInterface::kNone:
217 return cricket::CF_NONE;
218 case PeerConnectionInterface::kRelay:
219 return cricket::CF_RELAY;
220 case PeerConnectionInterface::kNoHost:
221 return (cricket::CF_ALL & ~cricket::CF_HOST);
222 case PeerConnectionInterface::kAll:
223 return cricket::CF_ALL;
224 default:
nissec80e7412017-01-11 05:56:46 -0800225 RTC_NOTREACHED();
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700226 }
227 return cricket::CF_NONE;
228}
229
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700230// Helper method to set a voice/video channel on all applicable senders
Steve Anton75737c02017-11-06 10:37:17 -0800231// and receivers when one is created/destroyed by PeerConnection.
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700232//
233// Used by On(Voice|Video)Channel(Created|Destroyed)
234template <class SENDER,
235 class RECEIVER,
236 class CHANNEL,
237 class SENDERS,
238 class RECEIVERS>
239void SetChannelOnSendersAndReceivers(CHANNEL* channel,
Steve Anton36b29d12017-10-30 09:57:42 -0700240 const SENDERS& senders,
241 const RECEIVERS& receivers,
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -0700242 cricket::MediaType media_type) {
243 for (auto& sender : senders) {
244 if (sender->media_type() == media_type) {
245 static_cast<SENDER*>(sender->internal())->SetChannel(channel);
246 }
247 }
248 for (auto& receiver : receivers) {
249 if (receiver->media_type() == media_type) {
250 if (!channel) {
251 receiver->internal()->Stop();
252 }
253 static_cast<RECEIVER*>(receiver->internal())->SetChannel(channel);
254 }
255 }
256}
257
deadbeef293e9262017-01-11 12:28:30 -0800258// Helper to set an error and return from a method.
259bool SafeSetError(webrtc::RTCErrorType type, webrtc::RTCError* error) {
260 if (error) {
261 error->set_type(type);
262 }
263 return type == webrtc::RTCErrorType::NONE;
264}
265
Steve Anton038834f2017-07-14 15:59:59 -0700266bool SafeSetError(webrtc::RTCError error, webrtc::RTCError* error_out) {
267 if (error_out) {
268 *error_out = std::move(error);
269 }
270 return error.ok();
271}
272
Steve Antonba818672017-11-06 10:21:57 -0800273std::string GetSignalingStateString(
274 PeerConnectionInterface::SignalingState state) {
275 switch (state) {
276 case PeerConnectionInterface::kStable:
277 return "kStable";
278 case PeerConnectionInterface::kHaveLocalOffer:
279 return "kHaveLocalOffer";
280 case PeerConnectionInterface::kHaveLocalPrAnswer:
281 return "kHavePrAnswer";
282 case PeerConnectionInterface::kHaveRemoteOffer:
283 return "kHaveRemoteOffer";
284 case PeerConnectionInterface::kHaveRemotePrAnswer:
285 return "kHaveRemotePrAnswer";
286 case PeerConnectionInterface::kClosed:
287 return "kClosed";
288 }
289 RTC_NOTREACHED();
290 return "";
291}
deadbeef0a6c4ca2015-10-06 11:38:28 -0700292
Steve Anton75737c02017-11-06 10:37:17 -0800293IceCandidatePairType GetIceCandidatePairCounter(
294 const cricket::Candidate& local,
295 const cricket::Candidate& remote) {
296 const auto& l = local.type();
297 const auto& r = remote.type();
298 const auto& host = LOCAL_PORT_TYPE;
299 const auto& srflx = STUN_PORT_TYPE;
300 const auto& relay = RELAY_PORT_TYPE;
301 const auto& prflx = PRFLX_PORT_TYPE;
302 if (l == host && r == host) {
303 bool local_private = IPIsPrivate(local.address().ipaddr());
304 bool remote_private = IPIsPrivate(remote.address().ipaddr());
305 if (local_private) {
306 if (remote_private) {
307 return kIceCandidatePairHostPrivateHostPrivate;
308 } else {
309 return kIceCandidatePairHostPrivateHostPublic;
310 }
311 } else {
312 if (remote_private) {
313 return kIceCandidatePairHostPublicHostPrivate;
314 } else {
315 return kIceCandidatePairHostPublicHostPublic;
316 }
317 }
318 }
319 if (l == host && r == srflx)
320 return kIceCandidatePairHostSrflx;
321 if (l == host && r == relay)
322 return kIceCandidatePairHostRelay;
323 if (l == host && r == prflx)
324 return kIceCandidatePairHostPrflx;
325 if (l == srflx && r == host)
326 return kIceCandidatePairSrflxHost;
327 if (l == srflx && r == srflx)
328 return kIceCandidatePairSrflxSrflx;
329 if (l == srflx && r == relay)
330 return kIceCandidatePairSrflxRelay;
331 if (l == srflx && r == prflx)
332 return kIceCandidatePairSrflxPrflx;
333 if (l == relay && r == host)
334 return kIceCandidatePairRelayHost;
335 if (l == relay && r == srflx)
336 return kIceCandidatePairRelaySrflx;
337 if (l == relay && r == relay)
338 return kIceCandidatePairRelayRelay;
339 if (l == relay && r == prflx)
340 return kIceCandidatePairRelayPrflx;
341 if (l == prflx && r == host)
342 return kIceCandidatePairPrflxHost;
343 if (l == prflx && r == srflx)
344 return kIceCandidatePairPrflxSrflx;
345 if (l == prflx && r == relay)
346 return kIceCandidatePairPrflxRelay;
347 return kIceCandidatePairMax;
348}
349
350// Verify that the order of media sections in |new_desc| matches
351// |existing_desc|. The number of m= sections in |new_desc| should be no less
352// than |existing_desc|.
353bool MediaSectionsInSameOrder(const SessionDescription* existing_desc,
354 const SessionDescription* new_desc) {
355 if (!existing_desc || !new_desc) {
356 return false;
357 }
358
359 if (existing_desc->contents().size() > new_desc->contents().size()) {
360 return false;
361 }
362
363 for (size_t i = 0; i < existing_desc->contents().size(); ++i) {
364 if (new_desc->contents()[i].name != existing_desc->contents()[i].name) {
365 return false;
366 }
367 const MediaContentDescription* new_desc_mdesc =
368 static_cast<const MediaContentDescription*>(
369 new_desc->contents()[i].description);
370 const MediaContentDescription* existing_desc_mdesc =
371 static_cast<const MediaContentDescription*>(
372 existing_desc->contents()[i].description);
373 if (new_desc_mdesc->type() != existing_desc_mdesc->type()) {
374 return false;
375 }
376 }
377 return true;
378}
379
380bool MediaSectionsHaveSameCount(const SessionDescription* desc1,
381 const SessionDescription* desc2) {
382 if (!desc1 || !desc2) {
383 return false;
384 }
385 return desc1->contents().size() == desc2->contents().size();
386}
387
388// Checks that each non-rejected content has SDES crypto keys or a DTLS
389// fingerprint, unless it's in a BUNDLE group, in which case only the
390// BUNDLE-tag section (first media section/description in the BUNDLE group)
391// needs a ufrag and pwd. Mismatches, such as replying with a DTLS fingerprint
392// to SDES keys, will be caught in JsepTransport negotiation, and backstopped
393// by Channel's |srtp_required| check.
394bool VerifyCrypto(const SessionDescription* desc,
395 bool dtls_enabled,
396 std::string* error) {
397 const cricket::ContentGroup* bundle =
398 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
399 const ContentInfos& contents = desc->contents();
400 for (size_t index = 0; index < contents.size(); ++index) {
401 const ContentInfo* cinfo = &contents[index];
402 if (cinfo->rejected) {
403 continue;
404 }
405 if (bundle && bundle->HasContentName(cinfo->name) &&
406 cinfo->name != *(bundle->FirstContentName())) {
407 // This isn't the first media section in the BUNDLE group, so it's not
408 // required to have crypto attributes, since only the crypto attributes
409 // from the first section actually get used.
410 continue;
411 }
412
413 // If the content isn't rejected or bundled into another m= section, crypto
414 // must be present.
415 const MediaContentDescription* media =
416 static_cast<const MediaContentDescription*>(cinfo->description);
417 const TransportInfo* tinfo = desc->GetTransportInfoByName(cinfo->name);
418 if (!media || !tinfo) {
419 // Something is not right.
420 LOG(LS_ERROR) << kInvalidSdp;
421 *error = kInvalidSdp;
422 return false;
423 }
424 if (dtls_enabled) {
425 if (!tinfo->description.identity_fingerprint) {
426 LOG(LS_WARNING) << "Session description must have DTLS fingerprint if "
427 "DTLS enabled.";
428 *error = kSdpWithoutDtlsFingerprint;
429 return false;
430 }
431 } else {
432 if (media->cryptos().empty()) {
433 LOG(LS_WARNING)
434 << "Session description must have SDES when DTLS disabled.";
435 *error = kSdpWithoutSdesCrypto;
436 return false;
437 }
438 }
439 }
440
441 return true;
442}
443
444// Checks that each non-rejected content has ice-ufrag and ice-pwd set, unless
445// it's in a BUNDLE group, in which case only the BUNDLE-tag section (first
446// media section/description in the BUNDLE group) needs a ufrag and pwd.
447bool VerifyIceUfragPwdPresent(const SessionDescription* desc) {
448 const cricket::ContentGroup* bundle =
449 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
450 const ContentInfos& contents = desc->contents();
451 for (size_t index = 0; index < contents.size(); ++index) {
452 const ContentInfo* cinfo = &contents[index];
453 if (cinfo->rejected) {
454 continue;
455 }
456 if (bundle && bundle->HasContentName(cinfo->name) &&
457 cinfo->name != *(bundle->FirstContentName())) {
458 // This isn't the first media section in the BUNDLE group, so it's not
459 // required to have ufrag/password, since only the ufrag/password from
460 // the first section actually get used.
461 continue;
462 }
463
464 // If the content isn't rejected or bundled into another m= section,
465 // ice-ufrag and ice-pwd must be present.
466 const TransportInfo* tinfo = desc->GetTransportInfoByName(cinfo->name);
467 if (!tinfo) {
468 // Something is not right.
469 LOG(LS_ERROR) << kInvalidSdp;
470 return false;
471 }
472 if (tinfo->description.ice_ufrag.empty() ||
473 tinfo->description.ice_pwd.empty()) {
474 LOG(LS_ERROR) << "Session description must have ice ufrag and pwd.";
475 return false;
476 }
477 }
478 return true;
479}
480
481bool GetTrackIdBySsrc(const SessionDescription* session_description,
482 uint32_t ssrc,
483 std::string* track_id) {
484 RTC_DCHECK(track_id != NULL);
485
486 const cricket::ContentInfo* audio_info =
487 cricket::GetFirstAudioContent(session_description);
488 if (audio_info) {
489 const cricket::MediaContentDescription* audio_content =
490 static_cast<const cricket::MediaContentDescription*>(
491 audio_info->description);
492
493 const auto* found =
494 cricket::GetStreamBySsrc(audio_content->streams(), ssrc);
495 if (found) {
496 *track_id = found->id;
497 return true;
498 }
499 }
500
501 const cricket::ContentInfo* video_info =
502 cricket::GetFirstVideoContent(session_description);
503 if (video_info) {
504 const cricket::MediaContentDescription* video_content =
505 static_cast<const cricket::MediaContentDescription*>(
506 video_info->description);
507
508 const auto* found =
509 cricket::GetStreamBySsrc(video_content->streams(), ssrc);
510 if (found) {
511 *track_id = found->id;
512 return true;
513 }
514 }
515 return false;
516}
517
518// Get the SCTP port out of a SessionDescription.
519// Return -1 if not found.
520int GetSctpPort(const SessionDescription* session_description) {
521 const ContentInfo* content_info = GetFirstDataContent(session_description);
522 RTC_DCHECK(content_info);
523 if (!content_info) {
524 return -1;
525 }
526 const cricket::DataContentDescription* data =
527 static_cast<const cricket::DataContentDescription*>(
528 (content_info->description));
529 std::string value;
530 cricket::DataCodec match_pattern(cricket::kGoogleSctpDataCodecPlType,
531 cricket::kGoogleSctpDataCodecName);
532 for (const cricket::DataCodec& codec : data->codecs()) {
533 if (!codec.Matches(match_pattern)) {
534 continue;
535 }
536 if (codec.GetParam(cricket::kCodecParamPort, &value)) {
537 return rtc::FromString<int>(value);
538 }
539 }
540 return -1;
541}
542
543bool BadSdp(const std::string& source,
544 const std::string& type,
545 const std::string& reason,
546 std::string* err_desc) {
547 std::ostringstream desc;
548 desc << "Failed to set " << source;
549 if (!type.empty()) {
550 desc << " " << type;
551 }
552 desc << " sdp: " << reason;
553
554 if (err_desc) {
555 *err_desc = desc.str();
556 }
557 LOG(LS_ERROR) << desc.str();
558 return false;
559}
560
561bool BadSdp(cricket::ContentSource source,
562 const std::string& type,
563 const std::string& reason,
564 std::string* err_desc) {
565 if (source == cricket::CS_LOCAL) {
566 return BadSdp("local", type, reason, err_desc);
567 } else {
568 return BadSdp("remote", type, reason, err_desc);
569 }
570}
571
572bool BadLocalSdp(const std::string& type,
573 const std::string& reason,
574 std::string* err_desc) {
575 return BadSdp(cricket::CS_LOCAL, type, reason, err_desc);
576}
577
578bool BadRemoteSdp(const std::string& type,
579 const std::string& reason,
580 std::string* err_desc) {
581 return BadSdp(cricket::CS_REMOTE, type, reason, err_desc);
582}
583
584bool BadOfferSdp(cricket::ContentSource source,
585 const std::string& reason,
586 std::string* err_desc) {
587 return BadSdp(source, SessionDescriptionInterface::kOffer, reason, err_desc);
588}
589
590bool BadPranswerSdp(cricket::ContentSource source,
591 const std::string& reason,
592 std::string* err_desc) {
593 return BadSdp(source, SessionDescriptionInterface::kPrAnswer, reason,
594 err_desc);
595}
596
597bool BadAnswerSdp(cricket::ContentSource source,
598 const std::string& reason,
599 std::string* err_desc) {
600 return BadSdp(source, SessionDescriptionInterface::kAnswer, reason, err_desc);
601}
602
603std::string BadStateErrMsg(PeerConnectionInterface::SignalingState state) {
604 std::ostringstream desc;
605 desc << "Called in wrong state: " << GetSignalingStateString(state);
606 return desc.str();
607}
608
609#define GET_STRING_OF_ERROR_CODE(err) \
610 case webrtc::PeerConnection::err: \
611 result = #err; \
612 break;
613
614std::string GetErrorCodeString(webrtc::PeerConnection::Error err) {
615 std::string result;
616 switch (err) {
617 GET_STRING_OF_ERROR_CODE(ERROR_NONE)
618 GET_STRING_OF_ERROR_CODE(ERROR_CONTENT)
619 GET_STRING_OF_ERROR_CODE(ERROR_TRANSPORT)
620 default:
621 RTC_NOTREACHED();
622 break;
623 }
624 return result;
625}
626
627std::string MakeErrorString(const std::string& error, const std::string& desc) {
628 std::ostringstream ret;
629 ret << error << " " << desc;
630 return ret.str();
631}
632
633std::string MakeTdErrorString(const std::string& desc) {
634 return MakeErrorString(kPushDownTDFailed, desc);
635}
636
637// Returns true if |new_desc| requests an ICE restart (i.e., new ufrag/pwd).
638bool CheckForRemoteIceRestart(const SessionDescriptionInterface* old_desc,
639 const SessionDescriptionInterface* new_desc,
640 const std::string& content_name) {
641 if (!old_desc) {
642 return false;
643 }
644 const SessionDescription* new_sd = new_desc->description();
645 const SessionDescription* old_sd = old_desc->description();
646 const ContentInfo* cinfo = new_sd->GetContentByName(content_name);
647 if (!cinfo || cinfo->rejected) {
648 return false;
649 }
650 // If the content isn't rejected, check if ufrag and password has changed.
651 const cricket::TransportDescription* new_transport_desc =
652 new_sd->GetTransportDescriptionByName(content_name);
653 const cricket::TransportDescription* old_transport_desc =
654 old_sd->GetTransportDescriptionByName(content_name);
655 if (!new_transport_desc || !old_transport_desc) {
656 // No transport description exists. This is not an ICE restart.
657 return false;
658 }
659 if (cricket::IceCredentialsChanged(
660 old_transport_desc->ice_ufrag, old_transport_desc->ice_pwd,
661 new_transport_desc->ice_ufrag, new_transport_desc->ice_pwd)) {
662 LOG(LS_INFO) << "Remote peer requests ICE restart for " << content_name
663 << ".";
664 return true;
665 }
666 return false;
667}
668
669} // namespace
670
deadbeef293e9262017-01-11 12:28:30 -0800671bool PeerConnectionInterface::RTCConfiguration::operator==(
672 const PeerConnectionInterface::RTCConfiguration& o) const {
673 // This static_assert prevents us from accidentally breaking operator==.
Steve Anton300bf8e2017-07-14 10:13:10 -0700674 // Note: Order matters! Fields must be ordered the same as RTCConfiguration.
deadbeef293e9262017-01-11 12:28:30 -0800675 struct stuff_being_tested_for_equality {
Magnus Jedvert3beb2072017-07-14 14:23:56 +0000676 IceServers servers;
Steve Anton300bf8e2017-07-14 10:13:10 -0700677 IceTransportsType type;
deadbeef293e9262017-01-11 12:28:30 -0800678 BundlePolicy bundle_policy;
679 RtcpMuxPolicy rtcp_mux_policy;
Steve Anton300bf8e2017-07-14 10:13:10 -0700680 std::vector<rtc::scoped_refptr<rtc::RTCCertificate>> certificates;
681 int ice_candidate_pool_size;
682 bool disable_ipv6;
683 bool disable_ipv6_on_wifi;
deadbeefd21eab32017-07-26 16:50:11 -0700684 int max_ipv6_networks;
Steve Anton300bf8e2017-07-14 10:13:10 -0700685 bool enable_rtp_data_channel;
686 rtc::Optional<int> screencast_min_bitrate;
687 rtc::Optional<bool> combined_audio_video_bwe;
688 rtc::Optional<bool> enable_dtls_srtp;
deadbeef293e9262017-01-11 12:28:30 -0800689 TcpCandidatePolicy tcp_candidate_policy;
690 CandidateNetworkPolicy candidate_network_policy;
691 int audio_jitter_buffer_max_packets;
692 bool audio_jitter_buffer_fast_accelerate;
693 int ice_connection_receiving_timeout;
694 int ice_backup_candidate_pair_ping_interval;
695 ContinualGatheringPolicy continual_gathering_policy;
deadbeef293e9262017-01-11 12:28:30 -0800696 bool prioritize_most_likely_ice_candidate_pairs;
697 struct cricket::MediaConfig media_config;
deadbeef293e9262017-01-11 12:28:30 -0800698 bool prune_turn_ports;
699 bool presume_writable_when_fully_relayed;
700 bool enable_ice_renomination;
701 bool redetermine_role_on_ice_restart;
skvlad51072462017-02-02 11:50:14 -0800702 rtc::Optional<int> ice_check_min_interval;
Steve Anton300bf8e2017-07-14 10:13:10 -0700703 rtc::Optional<rtc::IntervalRange> ice_regather_interval_range;
Jonas Orelandbdcee282017-10-10 14:01:40 +0200704 webrtc::TurnCustomizer* turn_customizer;
deadbeef293e9262017-01-11 12:28:30 -0800705 };
706 static_assert(sizeof(stuff_being_tested_for_equality) == sizeof(*this),
707 "Did you add something to RTCConfiguration and forget to "
708 "update operator==?");
709 return type == o.type && servers == o.servers &&
710 bundle_policy == o.bundle_policy &&
711 rtcp_mux_policy == o.rtcp_mux_policy &&
712 tcp_candidate_policy == o.tcp_candidate_policy &&
713 candidate_network_policy == o.candidate_network_policy &&
714 audio_jitter_buffer_max_packets == o.audio_jitter_buffer_max_packets &&
715 audio_jitter_buffer_fast_accelerate ==
716 o.audio_jitter_buffer_fast_accelerate &&
717 ice_connection_receiving_timeout ==
718 o.ice_connection_receiving_timeout &&
719 ice_backup_candidate_pair_ping_interval ==
720 o.ice_backup_candidate_pair_ping_interval &&
721 continual_gathering_policy == o.continual_gathering_policy &&
722 certificates == o.certificates &&
723 prioritize_most_likely_ice_candidate_pairs ==
724 o.prioritize_most_likely_ice_candidate_pairs &&
725 media_config == o.media_config && disable_ipv6 == o.disable_ipv6 &&
zhihuangb09b3f92017-03-07 14:40:51 -0800726 disable_ipv6_on_wifi == o.disable_ipv6_on_wifi &&
deadbeefd21eab32017-07-26 16:50:11 -0700727 max_ipv6_networks == o.max_ipv6_networks &&
deadbeef293e9262017-01-11 12:28:30 -0800728 enable_rtp_data_channel == o.enable_rtp_data_channel &&
deadbeef293e9262017-01-11 12:28:30 -0800729 screencast_min_bitrate == o.screencast_min_bitrate &&
730 combined_audio_video_bwe == o.combined_audio_video_bwe &&
731 enable_dtls_srtp == o.enable_dtls_srtp &&
732 ice_candidate_pool_size == o.ice_candidate_pool_size &&
733 prune_turn_ports == o.prune_turn_ports &&
734 presume_writable_when_fully_relayed ==
735 o.presume_writable_when_fully_relayed &&
736 enable_ice_renomination == o.enable_ice_renomination &&
skvlad51072462017-02-02 11:50:14 -0800737 redetermine_role_on_ice_restart == o.redetermine_role_on_ice_restart &&
Steve Anton300bf8e2017-07-14 10:13:10 -0700738 ice_check_min_interval == o.ice_check_min_interval &&
Jonas Orelandbdcee282017-10-10 14:01:40 +0200739 ice_regather_interval_range == o.ice_regather_interval_range &&
740 turn_customizer == o.turn_customizer;
deadbeef293e9262017-01-11 12:28:30 -0800741}
742
743bool PeerConnectionInterface::RTCConfiguration::operator!=(
744 const PeerConnectionInterface::RTCConfiguration& o) const {
745 return !(*this == o);
deadbeef3edec7c2016-12-10 11:44:26 -0800746}
747
zhihuang8f65cdf2016-05-06 18:40:30 -0700748// Generate a RTCP CNAME when a PeerConnection is created.
749std::string GenerateRtcpCname() {
750 std::string cname;
751 if (!rtc::CreateRandomString(kRtcpCnameLength, &cname)) {
752 LOG(LS_ERROR) << "Failed to generate CNAME.";
nisseeb4ca4e2017-01-12 02:24:27 -0800753 RTC_NOTREACHED();
zhihuang8f65cdf2016-05-06 18:40:30 -0700754 }
755 return cname;
756}
757
zhihuang1c378ed2017-08-17 14:10:50 -0700758bool ValidateOfferAnswerOptions(
759 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options) {
760 return IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_audio) &&
761 IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_video);
olka3c747662017-08-17 06:50:32 -0700762}
763
zhihuang1c378ed2017-08-17 14:10:50 -0700764// From |rtc_options|, fill parts of |session_options| shared by all generated
765// m= sections (in other words, nothing that involves a map/array).
766void ExtractSharedMediaSessionOptions(
767 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
768 cricket::MediaSessionOptions* session_options) {
769 session_options->vad_enabled = rtc_options.voice_activity_detection;
770 session_options->bundle_enabled = rtc_options.use_rtp_mux;
771}
zhihuanga77e6bb2017-08-14 18:17:48 -0700772
zhihuang1c378ed2017-08-17 14:10:50 -0700773bool ConvertConstraintsToOfferAnswerOptions(
774 const MediaConstraintsInterface* constraints,
775 PeerConnectionInterface::RTCOfferAnswerOptions* offer_answer_options) {
olka3c747662017-08-17 06:50:32 -0700776 if (!constraints) {
777 return true;
778 }
zhihuang1c378ed2017-08-17 14:10:50 -0700779
780 bool value = false;
781 size_t mandatory_constraints_satisfied = 0;
782
783 if (FindConstraint(constraints,
784 MediaConstraintsInterface::kOfferToReceiveAudio, &value,
785 &mandatory_constraints_satisfied)) {
786 offer_answer_options->offer_to_receive_audio =
787 value ? PeerConnectionInterface::RTCOfferAnswerOptions::
788 kOfferToReceiveMediaTrue
789 : 0;
790 }
791
792 if (FindConstraint(constraints,
793 MediaConstraintsInterface::kOfferToReceiveVideo, &value,
794 &mandatory_constraints_satisfied)) {
795 offer_answer_options->offer_to_receive_video =
796 value ? PeerConnectionInterface::RTCOfferAnswerOptions::
797 kOfferToReceiveMediaTrue
798 : 0;
799 }
800 if (FindConstraint(constraints,
801 MediaConstraintsInterface::kVoiceActivityDetection, &value,
802 &mandatory_constraints_satisfied)) {
803 offer_answer_options->voice_activity_detection = value;
804 }
805 if (FindConstraint(constraints, MediaConstraintsInterface::kUseRtpMux, &value,
806 &mandatory_constraints_satisfied)) {
807 offer_answer_options->use_rtp_mux = value;
808 }
809 if (FindConstraint(constraints, MediaConstraintsInterface::kIceRestart,
810 &value, &mandatory_constraints_satisfied)) {
811 offer_answer_options->ice_restart = value;
812 }
813
deadbeefab9b2d12015-10-14 11:33:11 -0700814 return mandatory_constraints_satisfied == constraints->GetMandatory().size();
815}
816
zhihuang38ede132017-06-15 12:52:32 -0700817PeerConnection::PeerConnection(PeerConnectionFactory* factory,
818 std::unique_ptr<RtcEventLog> event_log,
819 std::unique_ptr<Call> call)
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000820 : factory_(factory),
zhihuang38ede132017-06-15 12:52:32 -0700821 event_log_(std::move(event_log)),
zhihuang8f65cdf2016-05-06 18:40:30 -0700822 rtcp_cname_(GenerateRtcpCname()),
deadbeefab9b2d12015-10-14 11:33:11 -0700823 local_streams_(StreamCollection::Create()),
zhihuang38ede132017-06-15 12:52:32 -0700824 remote_streams_(StreamCollection::Create()),
825 call_(std::move(call)) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000826
827PeerConnection::~PeerConnection() {
Peter Boström1a9d6152015-12-08 22:15:17 +0100828 TRACE_EVENT0("webrtc", "PeerConnection::~PeerConnection");
deadbeef0a6c4ca2015-10-06 11:38:28 -0700829 RTC_DCHECK(signaling_thread()->IsCurrent());
Steve Anton75737c02017-11-06 10:37:17 -0800830 // Need to detach RTP senders/receivers from PeerConnection,
deadbeef70ab1a12015-09-28 16:53:55 -0700831 // since it's about to be destroyed.
832 for (const auto& sender : senders_) {
deadbeefa601f5c2016-06-06 14:27:39 -0700833 sender->internal()->Stop();
deadbeef70ab1a12015-09-28 16:53:55 -0700834 }
835 for (const auto& receiver : receivers_) {
deadbeefa601f5c2016-06-06 14:27:39 -0700836 receiver->internal()->Stop();
deadbeef70ab1a12015-09-28 16:53:55 -0700837 }
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700838 // Destroy stats_ because it depends on session_.
839 stats_.reset(nullptr);
hbosb78306a2016-12-19 05:06:57 -0800840 if (stats_collector_) {
841 stats_collector_->WaitForPendingRequest();
842 stats_collector_ = nullptr;
843 }
Steve Anton75737c02017-11-06 10:37:17 -0800844
845 // Destroy video channels first since they may have a pointer to a voice
846 // channel.
847 for (auto* channel : video_channels_) {
848 DestroyVideoChannel(channel);
849 }
850 for (auto* channel : voice_channels_) {
851 DestroyVoiceChannel(channel);
852 }
853 if (rtp_data_channel_) {
854 DestroyDataChannel();
855 }
856
857 // Note: Cannot use rtc::Bind to create a functor to invoke because it will
858 // grab a reference to this PeerConnection. The RefCountedObject vtable will
859 // have already been destroyed (since it is a subclass of PeerConnection) and
860 // using rtc::Bind will cause "Pure virtual function called" error to appear.
861
862 if (sctp_transport_) {
863 OnDataChannelDestroyed();
864 network_thread()->Invoke<void>(RTC_FROM_HERE,
865 [this] { DestroySctpTransport_n(); });
866 }
867
868 LOG(LS_INFO) << "Session: " << session_id() << " is destroyed.";
869
870 webrtc_session_desc_factory_.reset();
871 sctp_invoker_.reset();
872 sctp_factory_.reset();
873 transport_controller_.reset();
874
deadbeef91dd5672016-05-18 16:55:30 -0700875 // port_allocator_ lives on the network thread and should be destroyed there.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700876 network_thread()->Invoke<void>(RTC_FROM_HERE,
nisseeaabdf62017-05-05 02:23:02 -0700877 [this] { port_allocator_.reset(); });
eladalon248fd4f2017-09-06 05:18:15 -0700878 // call_ and event_log_ must be destroyed on the worker thread.
Steve Anton978b8762017-09-29 12:15:02 -0700879 worker_thread()->Invoke<void>(RTC_FROM_HERE, [this] {
eladalon248fd4f2017-09-06 05:18:15 -0700880 call_.reset();
881 event_log_.reset();
882 });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000883}
884
885bool PeerConnection::Initialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000886 const PeerConnectionInterface::RTCConfiguration& configuration,
kwibergd1fe2812016-04-27 06:47:29 -0700887 std::unique_ptr<cricket::PortAllocator> allocator,
Henrik Boströmd03c23b2016-06-01 11:44:18 +0200888 std::unique_ptr<rtc::RTCCertificateGeneratorInterface> cert_generator,
deadbeef653b8e02015-11-11 12:55:10 -0800889 PeerConnectionObserver* observer) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100890 TRACE_EVENT0("webrtc", "PeerConnection::Initialize");
Steve Anton038834f2017-07-14 15:59:59 -0700891
892 RTCError config_error = ValidateConfiguration(configuration);
893 if (!config_error.ok()) {
894 LOG(LS_ERROR) << "Invalid configuration: " << config_error.message();
895 return false;
896 }
897
deadbeef293e9262017-01-11 12:28:30 -0800898 if (!allocator) {
899 LOG(LS_ERROR) << "PeerConnection initialized without a PortAllocator? "
900 << "This shouldn't happen if using PeerConnectionFactory.";
901 return false;
902 }
Jonas Orelandbdcee282017-10-10 14:01:40 +0200903
deadbeef653b8e02015-11-11 12:55:10 -0800904 if (!observer) {
deadbeef293e9262017-01-11 12:28:30 -0800905 // TODO(deadbeef): Why do we do this?
906 LOG(LS_ERROR) << "PeerConnection initialized without a "
907 << "PeerConnectionObserver";
deadbeef653b8e02015-11-11 12:55:10 -0800908 return false;
909 }
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000910 observer_ = observer;
kwiberg0eb15ed2015-12-17 03:04:15 -0800911 port_allocator_ = std::move(allocator);
deadbeef653b8e02015-11-11 12:55:10 -0800912
deadbeef91dd5672016-05-18 16:55:30 -0700913 // The port allocator lives on the network thread and should be initialized
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700914 // there.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700915 if (!network_thread()->Invoke<bool>(
916 RTC_FROM_HERE, rtc::Bind(&PeerConnection::InitializePortAllocator_n,
917 this, configuration))) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000918 return false;
919 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000920
Steve Anton75737c02017-11-06 10:37:17 -0800921 // RFC 3264: The numeric value of the session id and version in the
922 // o line MUST be representable with a "64 bit signed integer".
923 // Due to this constraint session id |session_id_| is max limited to
924 // LLONG_MAX.
925 session_id_ = rtc::ToString(rtc::CreateRandomId64() & LLONG_MAX);
926 transport_controller_.reset(factory_->CreateTransportController(
927 port_allocator_.get(), configuration.redetermine_role_on_ice_restart));
928 transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLED);
929 transport_controller_->SignalConnectionState.connect(
930 this, &PeerConnection::OnTransportControllerConnectionState);
931 transport_controller_->SignalGatheringState.connect(
932 this, &PeerConnection::OnTransportControllerGatheringState);
933 transport_controller_->SignalCandidatesGathered.connect(
934 this, &PeerConnection::OnTransportControllerCandidatesGathered);
935 transport_controller_->SignalCandidatesRemoved.connect(
936 this, &PeerConnection::OnTransportControllerCandidatesRemoved);
937 transport_controller_->SignalDtlsHandshakeError.connect(
938 this, &PeerConnection::OnTransportControllerDtlsHandshakeError);
939
940 sctp_factory_ = factory_->CreateSctpTransportInternalFactory();
zhihuang29ff8442016-07-27 11:07:25 -0700941
deadbeefab9b2d12015-10-14 11:33:11 -0700942 stats_.reset(new StatsCollector(this));
hbos74e1a4f2016-09-15 23:33:01 -0700943 stats_collector_ = RTCStatsCollector::Create(this);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000944
Steve Antonba818672017-11-06 10:21:57 -0800945 configuration_ = configuration;
946
Steve Anton75737c02017-11-06 10:37:17 -0800947 const PeerConnectionFactoryInterface::Options& options = factory_->options();
948
949 transport_controller_->SetSslMaxProtocolVersion(options.ssl_max_version);
950
951 // Obtain a certificate from RTCConfiguration if any were provided (optional).
952 rtc::scoped_refptr<rtc::RTCCertificate> certificate;
953 if (!configuration.certificates.empty()) {
954 // TODO(hbos,torbjorng): Decide on certificate-selection strategy instead of
955 // just picking the first one. The decision should be made based on the DTLS
956 // handshake. The DTLS negotiations need to know about all certificates.
957 certificate = configuration.certificates[0];
958 }
959
960 SetIceConfig(ParseIceConfig(configuration));
961
962 if (options.disable_encryption) {
963 dtls_enabled_ = false;
964 } else {
965 // Enable DTLS by default if we have an identity store or a certificate.
966 dtls_enabled_ = (cert_generator || certificate);
967 // |configuration| can override the default |dtls_enabled_| value.
968 if (configuration.enable_dtls_srtp) {
969 dtls_enabled_ = *(configuration.enable_dtls_srtp);
970 }
971 }
972
973 // Enable creation of RTP data channels if the kEnableRtpDataChannels is set.
974 // It takes precendence over the disable_sctp_data_channels
975 // PeerConnectionFactoryInterface::Options.
976 if (configuration.enable_rtp_data_channel) {
977 data_channel_type_ = cricket::DCT_RTP;
978 } else {
979 // DTLS has to be enabled to use SCTP.
980 if (!options.disable_sctp_data_channels && dtls_enabled_) {
981 data_channel_type_ = cricket::DCT_SCTP;
982 }
983 }
984
985 video_options_.screencast_min_bitrate_kbps =
986 configuration.screencast_min_bitrate;
987 audio_options_.combined_audio_video_bwe =
988 configuration.combined_audio_video_bwe;
989
990 audio_options_.audio_jitter_buffer_max_packets =
991 rtc::Optional<int>(configuration.audio_jitter_buffer_max_packets);
992
993 audio_options_.audio_jitter_buffer_fast_accelerate =
994 rtc::Optional<bool>(configuration.audio_jitter_buffer_fast_accelerate);
995
996 // Whether the certificate generator/certificate is null or not determines
997 // what PeerConnectionDescriptionFactory will do, so make sure that we give it
998 // the right instructions by clearing the variables if needed.
999 if (!dtls_enabled_) {
1000 cert_generator.reset();
1001 certificate = nullptr;
1002 } else if (certificate) {
1003 // Favor generated certificate over the certificate generator.
1004 cert_generator.reset();
1005 }
1006
1007 webrtc_session_desc_factory_.reset(new WebRtcSessionDescriptionFactory(
1008 signaling_thread(), channel_manager(), this, session_id(),
1009 std::move(cert_generator), certificate));
1010 webrtc_session_desc_factory_->SignalCertificateReady.connect(
1011 this, &PeerConnection::OnCertificateReady);
1012
1013 if (options.disable_encryption) {
1014 webrtc_session_desc_factory_->SetSdesPolicy(cricket::SEC_DISABLED);
1015 }
1016
1017 webrtc_session_desc_factory_->set_enable_encrypted_rtp_header_extensions(
1018 options.crypto_options.enable_encrypted_rtp_header_extensions);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001019
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001020 return true;
1021}
1022
Steve Anton038834f2017-07-14 15:59:59 -07001023RTCError PeerConnection::ValidateConfiguration(
1024 const RTCConfiguration& config) const {
1025 if (config.ice_regather_interval_range &&
1026 config.continual_gathering_policy == GATHER_ONCE) {
1027 return RTCError(RTCErrorType::INVALID_PARAMETER,
1028 "ice_regather_interval_range specified but continual "
1029 "gathering policy is GATHER_ONCE");
1030 }
1031 return RTCError::OK();
1032}
1033
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001034rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001035PeerConnection::local_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -07001036 return local_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001037}
1038
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001039rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001040PeerConnection::remote_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -07001041 return remote_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001042}
1043
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +00001044bool PeerConnection::AddStream(MediaStreamInterface* local_stream) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001045 TRACE_EVENT0("webrtc", "PeerConnection::AddStream");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001046 if (IsClosed()) {
1047 return false;
1048 }
deadbeefab9b2d12015-10-14 11:33:11 -07001049 if (!CanAddLocalMediaStream(local_streams_, local_stream)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001050 return false;
1051 }
deadbeefab9b2d12015-10-14 11:33:11 -07001052
1053 local_streams_->AddStream(local_stream);
deadbeefeb459812015-12-15 19:24:43 -08001054 MediaStreamObserver* observer = new MediaStreamObserver(local_stream);
1055 observer->SignalAudioTrackAdded.connect(this,
1056 &PeerConnection::OnAudioTrackAdded);
1057 observer->SignalAudioTrackRemoved.connect(
1058 this, &PeerConnection::OnAudioTrackRemoved);
1059 observer->SignalVideoTrackAdded.connect(this,
1060 &PeerConnection::OnVideoTrackAdded);
1061 observer->SignalVideoTrackRemoved.connect(
1062 this, &PeerConnection::OnVideoTrackRemoved);
kwibergd1fe2812016-04-27 06:47:29 -07001063 stream_observers_.push_back(std::unique_ptr<MediaStreamObserver>(observer));
deadbeefab9b2d12015-10-14 11:33:11 -07001064
deadbeefab9b2d12015-10-14 11:33:11 -07001065 for (const auto& track : local_stream->GetAudioTracks()) {
korniltsev.anatolyec390b52017-07-24 17:00:25 -07001066 AddAudioTrack(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -07001067 }
1068 for (const auto& track : local_stream->GetVideoTracks()) {
korniltsev.anatolyec390b52017-07-24 17:00:25 -07001069 AddVideoTrack(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -07001070 }
1071
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001072 stats_->AddStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001073 observer_->OnRenegotiationNeeded();
1074 return true;
1075}
1076
1077void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001078 TRACE_EVENT0("webrtc", "PeerConnection::RemoveStream");
korniltsev.anatolyec390b52017-07-24 17:00:25 -07001079 if (!IsClosed()) {
1080 for (const auto& track : local_stream->GetAudioTracks()) {
1081 RemoveAudioTrack(track.get(), local_stream);
1082 }
1083 for (const auto& track : local_stream->GetVideoTracks()) {
1084 RemoveVideoTrack(track.get(), local_stream);
1085 }
deadbeefab9b2d12015-10-14 11:33:11 -07001086 }
deadbeefab9b2d12015-10-14 11:33:11 -07001087 local_streams_->RemoveStream(local_stream);
deadbeefeb459812015-12-15 19:24:43 -08001088 stream_observers_.erase(
1089 std::remove_if(
1090 stream_observers_.begin(), stream_observers_.end(),
kwibergd1fe2812016-04-27 06:47:29 -07001091 [local_stream](const std::unique_ptr<MediaStreamObserver>& observer) {
deadbeefeb459812015-12-15 19:24:43 -08001092 return observer->stream()->label().compare(local_stream->label()) ==
1093 0;
1094 }),
1095 stream_observers_.end());
deadbeefab9b2d12015-10-14 11:33:11 -07001096
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001097 if (IsClosed()) {
1098 return;
1099 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001100 observer_->OnRenegotiationNeeded();
1101}
1102
deadbeefe1f9d832016-01-14 15:35:42 -08001103rtc::scoped_refptr<RtpSenderInterface> PeerConnection::AddTrack(
1104 MediaStreamTrackInterface* track,
1105 std::vector<MediaStreamInterface*> streams) {
1106 TRACE_EVENT0("webrtc", "PeerConnection::AddTrack");
1107 if (IsClosed()) {
1108 return nullptr;
1109 }
1110 if (streams.size() >= 2) {
1111 LOG(LS_ERROR)
1112 << "Adding a track with two streams is not currently supported.";
1113 return nullptr;
1114 }
1115 // TODO(deadbeef): Support adding a track to two different senders.
1116 if (FindSenderForTrack(track) != senders_.end()) {
1117 LOG(LS_ERROR) << "Sender for track " << track->id() << " already exists.";
1118 return nullptr;
1119 }
1120
1121 // TODO(deadbeef): Support adding a track to multiple streams.
deadbeefa601f5c2016-06-06 14:27:39 -07001122 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> new_sender;
deadbeefe1f9d832016-01-14 15:35:42 -08001123 if (track->kind() == MediaStreamTrackInterface::kAudioKind) {
deadbeefa601f5c2016-06-06 14:27:39 -07001124 new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
deadbeefe1f9d832016-01-14 15:35:42 -08001125 signaling_thread(),
1126 new AudioRtpSender(static_cast<AudioTrackInterface*>(track),
Steve Anton75737c02017-11-06 10:37:17 -08001127 voice_channel(), stats_.get()));
deadbeefe1f9d832016-01-14 15:35:42 -08001128 if (!streams.empty()) {
deadbeefa601f5c2016-06-06 14:27:39 -07001129 new_sender->internal()->set_stream_id(streams[0]->label());
deadbeefe1f9d832016-01-14 15:35:42 -08001130 }
1131 const TrackInfo* track_info = FindTrackInfo(
deadbeefa601f5c2016-06-06 14:27:39 -07001132 local_audio_tracks_, new_sender->internal()->stream_id(), track->id());
deadbeefe1f9d832016-01-14 15:35:42 -08001133 if (track_info) {
deadbeefa601f5c2016-06-06 14:27:39 -07001134 new_sender->internal()->SetSsrc(track_info->ssrc);
deadbeefe1f9d832016-01-14 15:35:42 -08001135 }
1136 } else if (track->kind() == MediaStreamTrackInterface::kVideoKind) {
deadbeefa601f5c2016-06-06 14:27:39 -07001137 new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
deadbeefe1f9d832016-01-14 15:35:42 -08001138 signaling_thread(),
1139 new VideoRtpSender(static_cast<VideoTrackInterface*>(track),
Steve Anton75737c02017-11-06 10:37:17 -08001140 video_channel()));
deadbeefe1f9d832016-01-14 15:35:42 -08001141 if (!streams.empty()) {
deadbeefa601f5c2016-06-06 14:27:39 -07001142 new_sender->internal()->set_stream_id(streams[0]->label());
deadbeefe1f9d832016-01-14 15:35:42 -08001143 }
1144 const TrackInfo* track_info = FindTrackInfo(
deadbeefa601f5c2016-06-06 14:27:39 -07001145 local_video_tracks_, new_sender->internal()->stream_id(), track->id());
deadbeefe1f9d832016-01-14 15:35:42 -08001146 if (track_info) {
deadbeefa601f5c2016-06-06 14:27:39 -07001147 new_sender->internal()->SetSsrc(track_info->ssrc);
deadbeefe1f9d832016-01-14 15:35:42 -08001148 }
1149 } else {
1150 LOG(LS_ERROR) << "CreateSender called with invalid kind: " << track->kind();
1151 return rtc::scoped_refptr<RtpSenderInterface>();
1152 }
1153
1154 senders_.push_back(new_sender);
1155 observer_->OnRenegotiationNeeded();
1156 return new_sender;
1157}
1158
1159bool PeerConnection::RemoveTrack(RtpSenderInterface* sender) {
1160 TRACE_EVENT0("webrtc", "PeerConnection::RemoveTrack");
1161 if (IsClosed()) {
1162 return false;
1163 }
1164
1165 auto it = std::find(senders_.begin(), senders_.end(), sender);
1166 if (it == senders_.end()) {
1167 LOG(LS_ERROR) << "Couldn't find sender " << sender->id() << " to remove.";
1168 return false;
1169 }
deadbeefa601f5c2016-06-06 14:27:39 -07001170 (*it)->internal()->Stop();
deadbeefe1f9d832016-01-14 15:35:42 -08001171 senders_.erase(it);
1172
1173 observer_->OnRenegotiationNeeded();
1174 return true;
1175}
1176
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001177rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001178 AudioTrackInterface* track) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001179 TRACE_EVENT0("webrtc", "PeerConnection::CreateDtmfSender");
zhihuang29ff8442016-07-27 11:07:25 -07001180 if (IsClosed()) {
1181 return nullptr;
1182 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001183 if (!track) {
1184 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
deadbeef20cb0c12017-02-01 20:27:00 -08001185 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001186 }
deadbeef20cb0c12017-02-01 20:27:00 -08001187 auto it = FindSenderForTrack(track);
1188 if (it == senders_.end()) {
1189 LOG(LS_ERROR) << "CreateDtmfSender called with a non-added track.";
1190 return nullptr;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001191 }
1192
deadbeef20cb0c12017-02-01 20:27:00 -08001193 return (*it)->GetDtmfSender();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001194}
1195
deadbeeffac06552015-11-25 11:26:01 -08001196rtc::scoped_refptr<RtpSenderInterface> PeerConnection::CreateSender(
deadbeefbd7d8f72015-12-18 16:58:44 -08001197 const std::string& kind,
1198 const std::string& stream_id) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001199 TRACE_EVENT0("webrtc", "PeerConnection::CreateSender");
zhihuang29ff8442016-07-27 11:07:25 -07001200 if (IsClosed()) {
1201 return nullptr;
1202 }
deadbeefa601f5c2016-06-06 14:27:39 -07001203 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> new_sender;
deadbeeffac06552015-11-25 11:26:01 -08001204 if (kind == MediaStreamTrackInterface::kAudioKind) {
deadbeefa601f5c2016-06-06 14:27:39 -07001205 new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
Steve Anton75737c02017-11-06 10:37:17 -08001206 signaling_thread(), new AudioRtpSender(voice_channel(), stats_.get()));
deadbeeffac06552015-11-25 11:26:01 -08001207 } else if (kind == MediaStreamTrackInterface::kVideoKind) {
deadbeefa601f5c2016-06-06 14:27:39 -07001208 new_sender = RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
Steve Anton75737c02017-11-06 10:37:17 -08001209 signaling_thread(), new VideoRtpSender(video_channel()));
deadbeeffac06552015-11-25 11:26:01 -08001210 } else {
1211 LOG(LS_ERROR) << "CreateSender called with invalid kind: " << kind;
deadbeefe1f9d832016-01-14 15:35:42 -08001212 return new_sender;
deadbeeffac06552015-11-25 11:26:01 -08001213 }
deadbeefbd7d8f72015-12-18 16:58:44 -08001214 if (!stream_id.empty()) {
deadbeefa601f5c2016-06-06 14:27:39 -07001215 new_sender->internal()->set_stream_id(stream_id);
deadbeefbd7d8f72015-12-18 16:58:44 -08001216 }
deadbeeffac06552015-11-25 11:26:01 -08001217 senders_.push_back(new_sender);
deadbeefe1f9d832016-01-14 15:35:42 -08001218 return new_sender;
deadbeeffac06552015-11-25 11:26:01 -08001219}
1220
deadbeef70ab1a12015-09-28 16:53:55 -07001221std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders()
1222 const {
deadbeefa601f5c2016-06-06 14:27:39 -07001223 std::vector<rtc::scoped_refptr<RtpSenderInterface>> ret;
1224 for (const auto& sender : senders_) {
1225 ret.push_back(sender.get());
1226 }
1227 return ret;
deadbeef70ab1a12015-09-28 16:53:55 -07001228}
1229
1230std::vector<rtc::scoped_refptr<RtpReceiverInterface>>
1231PeerConnection::GetReceivers() const {
deadbeefa601f5c2016-06-06 14:27:39 -07001232 std::vector<rtc::scoped_refptr<RtpReceiverInterface>> ret;
1233 for (const auto& receiver : receivers_) {
1234 ret.push_back(receiver.get());
1235 }
1236 return ret;
deadbeef70ab1a12015-09-28 16:53:55 -07001237}
1238
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001239bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +00001240 MediaStreamTrackInterface* track,
1241 StatsOutputLevel level) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001242 TRACE_EVENT0("webrtc", "PeerConnection::GetStats");
deadbeef0a6c4ca2015-10-06 11:38:28 -07001243 RTC_DCHECK(signaling_thread()->IsCurrent());
nisse7ce109a2017-01-31 00:57:56 -08001244 if (!observer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001245 LOG(LS_ERROR) << "GetStats - observer is NULL.";
1246 return false;
1247 }
1248
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001249 stats_->UpdateStats(level);
zhihuange9e94c32016-11-04 11:38:15 -07001250 // The StatsCollector is used to tell if a track is valid because it may
1251 // remember tracks that the PeerConnection previously removed.
1252 if (track && !stats_->IsValidTrack(track->id())) {
1253 LOG(LS_WARNING) << "GetStats is called with an invalid track: "
1254 << track->id();
1255 return false;
1256 }
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001257 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_GETSTATS,
tommi@webrtc.org5b06b062014-08-15 08:38:30 +00001258 new GetStatsMsg(observer, track));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001259 return true;
1260}
1261
hbos74e1a4f2016-09-15 23:33:01 -07001262void PeerConnection::GetStats(RTCStatsCollectorCallback* callback) {
1263 RTC_DCHECK(stats_collector_);
1264 stats_collector_->GetStatsReport(callback);
1265}
1266
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001267PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
1268 return signaling_state_;
1269}
1270
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001271PeerConnectionInterface::IceConnectionState
1272PeerConnection::ice_connection_state() {
1273 return ice_connection_state_;
1274}
1275
1276PeerConnectionInterface::IceGatheringState
1277PeerConnection::ice_gathering_state() {
1278 return ice_gathering_state_;
1279}
1280
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001281rtc::scoped_refptr<DataChannelInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001282PeerConnection::CreateDataChannel(
1283 const std::string& label,
1284 const DataChannelInit* config) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001285 TRACE_EVENT0("webrtc", "PeerConnection::CreateDataChannel");
zhihuang9763d562016-08-05 11:14:50 -07001286
deadbeefab9b2d12015-10-14 11:33:11 -07001287 bool first_datachannel = !HasDataChannels();
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +00001288
kwibergd1fe2812016-04-27 06:47:29 -07001289 std::unique_ptr<InternalDataChannelInit> internal_config;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +00001290 if (config) {
1291 internal_config.reset(new InternalDataChannelInit(*config));
1292 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001293 rtc::scoped_refptr<DataChannelInterface> channel(
deadbeefab9b2d12015-10-14 11:33:11 -07001294 InternalCreateDataChannel(label, internal_config.get()));
1295 if (!channel.get()) {
1296 return nullptr;
1297 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001298
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +00001299 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
1300 // the first SCTP DataChannel.
Steve Anton75737c02017-11-06 10:37:17 -08001301 if (data_channel_type() == cricket::DCT_RTP || first_datachannel) {
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +00001302 observer_->OnRenegotiationNeeded();
1303 }
wu@webrtc.org91053e72013-08-10 07:18:04 +00001304
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001305 return DataChannelProxy::Create(signaling_thread(), channel.get());
1306}
1307
1308void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
1309 const MediaConstraintsInterface* constraints) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001310 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer");
Steve Anton8d3444d2017-10-20 15:30:51 -07001311
zhihuang1c378ed2017-08-17 14:10:50 -07001312 PeerConnectionInterface::RTCOfferAnswerOptions offer_answer_options;
1313 // Always create an offer even if |ConvertConstraintsToOfferAnswerOptions|
1314 // returns false for now. Because |ConvertConstraintsToOfferAnswerOptions|
1315 // compares the mandatory fields parsed with the mandatory fields added in the
1316 // |constraints| and some downstream applications might create offers with
1317 // mandatory fields which would not be parsed in the helper method. For
1318 // example, in Chromium/remoting, |kEnableDtlsSrtp| is added to the
1319 // |constraints| as a mandatory field but it is not parsed.
1320 ConvertConstraintsToOfferAnswerOptions(constraints, &offer_answer_options);
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +00001321
zhihuang1c378ed2017-08-17 14:10:50 -07001322 CreateOffer(observer, offer_answer_options);
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +00001323}
1324
1325void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
1326 const RTCOfferAnswerOptions& options) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001327 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer");
Steve Anton8d3444d2017-10-20 15:30:51 -07001328
nisse7ce109a2017-01-31 00:57:56 -08001329 if (!observer) {
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +00001330 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
1331 return;
1332 }
deadbeefab9b2d12015-10-14 11:33:11 -07001333
Steve Anton8d3444d2017-10-20 15:30:51 -07001334 if (IsClosed()) {
1335 std::string error = "CreateOffer called when PeerConnection is closed.";
1336 LOG(LS_ERROR) << error;
1337 PostCreateSessionDescriptionFailure(observer, error);
1338 return;
1339 }
1340
zhihuang1c378ed2017-08-17 14:10:50 -07001341 if (!ValidateOfferAnswerOptions(options)) {
deadbeefab9b2d12015-10-14 11:33:11 -07001342 std::string error = "CreateOffer called with invalid options.";
1343 LOG(LS_ERROR) << error;
1344 PostCreateSessionDescriptionFailure(observer, error);
1345 return;
1346 }
1347
zhihuang1c378ed2017-08-17 14:10:50 -07001348 cricket::MediaSessionOptions session_options;
1349 GetOptionsForOffer(options, &session_options);
Steve Anton75737c02017-11-06 10:37:17 -08001350 CreateOffer(observer, options, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001351}
1352
1353void PeerConnection::CreateAnswer(
1354 CreateSessionDescriptionObserver* observer,
1355 const MediaConstraintsInterface* constraints) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001356 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer");
Steve Anton8d3444d2017-10-20 15:30:51 -07001357
nisse7ce109a2017-01-31 00:57:56 -08001358 if (!observer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001359 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
1360 return;
1361 }
deadbeefab9b2d12015-10-14 11:33:11 -07001362
zhihuang1c378ed2017-08-17 14:10:50 -07001363 PeerConnectionInterface::RTCOfferAnswerOptions offer_answer_options;
1364 if (!ConvertConstraintsToOfferAnswerOptions(constraints,
1365 &offer_answer_options)) {
deadbeefab9b2d12015-10-14 11:33:11 -07001366 std::string error = "CreateAnswer called with invalid constraints.";
1367 LOG(LS_ERROR) << error;
1368 PostCreateSessionDescriptionFailure(observer, error);
1369 return;
1370 }
1371
Steve Anton8d3444d2017-10-20 15:30:51 -07001372 CreateAnswer(observer, offer_answer_options);
htaa2a49d92016-03-04 02:51:39 -08001373}
1374
1375void PeerConnection::CreateAnswer(CreateSessionDescriptionObserver* observer,
1376 const RTCOfferAnswerOptions& options) {
1377 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer");
nisse7ce109a2017-01-31 00:57:56 -08001378 if (!observer) {
htaa2a49d92016-03-04 02:51:39 -08001379 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
1380 return;
1381 }
1382
Steve Anton8d3444d2017-10-20 15:30:51 -07001383 if (IsClosed()) {
1384 std::string error = "CreateAnswer called when PeerConnection is closed.";
1385 LOG(LS_ERROR) << error;
1386 PostCreateSessionDescriptionFailure(observer, error);
1387 return;
1388 }
1389
Steve Anton75737c02017-11-06 10:37:17 -08001390 if (remote_description() &&
1391 remote_description()->type() != SessionDescriptionInterface::kOffer) {
Steve Anton8d3444d2017-10-20 15:30:51 -07001392 std::string error = "CreateAnswer called without remote offer.";
1393 LOG(LS_ERROR) << error;
1394 PostCreateSessionDescriptionFailure(observer, error);
1395 return;
1396 }
1397
htaa2a49d92016-03-04 02:51:39 -08001398 cricket::MediaSessionOptions session_options;
zhihuang1c378ed2017-08-17 14:10:50 -07001399 GetOptionsForAnswer(options, &session_options);
htaa2a49d92016-03-04 02:51:39 -08001400
Steve Anton75737c02017-11-06 10:37:17 -08001401 CreateAnswer(observer, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001402}
1403
1404void PeerConnection::SetLocalDescription(
1405 SetSessionDescriptionObserver* observer,
1406 SessionDescriptionInterface* desc) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001407 TRACE_EVENT0("webrtc", "PeerConnection::SetLocalDescription");
nisse7ce109a2017-01-31 00:57:56 -08001408 if (!observer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001409 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
1410 return;
1411 }
1412 if (!desc) {
1413 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
1414 return;
1415 }
Steve Anton8d3444d2017-10-20 15:30:51 -07001416
1417 // Takes the ownership of |desc| regardless of the result.
1418 std::unique_ptr<SessionDescriptionInterface> desc_temp(desc);
1419
1420 if (IsClosed()) {
1421 std::string error = "Failed to set local " + desc->type() +
1422 " sdp: Called in wrong state: STATE_CLOSED";
1423 LOG(LS_ERROR) << error;
1424 PostSetSessionDescriptionFailure(observer, error);
1425 return;
1426 }
1427
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001428 // Update stats here so that we have the most recent stats for tracks and
1429 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001430 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001431 std::string error;
Steve Anton75737c02017-11-06 10:37:17 -08001432 if (!SetLocalDescription(std::move(desc_temp), &error)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001433 PostSetSessionDescriptionFailure(observer, error);
1434 return;
1435 }
deadbeefab9b2d12015-10-14 11:33:11 -07001436
1437 // If setting the description decided our SSL role, allocate any necessary
1438 // SCTP sids.
1439 rtc::SSLRole role;
Steve Anton75737c02017-11-06 10:37:17 -08001440 if (data_channel_type() == cricket::DCT_SCTP && GetSctpSslRole(&role)) {
deadbeefab9b2d12015-10-14 11:33:11 -07001441 AllocateSctpSids(role);
1442 }
1443
1444 // Update state and SSRC of local MediaStreams and DataChannels based on the
1445 // local session description.
1446 const cricket::ContentInfo* audio_content =
1447 GetFirstAudioContent(desc->description());
1448 if (audio_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001449 if (audio_content->rejected) {
1450 RemoveTracks(cricket::MEDIA_TYPE_AUDIO);
1451 } else {
1452 const cricket::AudioContentDescription* audio_desc =
1453 static_cast<const cricket::AudioContentDescription*>(
1454 audio_content->description);
1455 UpdateLocalTracks(audio_desc->streams(), audio_desc->type());
1456 }
deadbeefab9b2d12015-10-14 11:33:11 -07001457 }
1458
1459 const cricket::ContentInfo* video_content =
1460 GetFirstVideoContent(desc->description());
1461 if (video_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001462 if (video_content->rejected) {
1463 RemoveTracks(cricket::MEDIA_TYPE_VIDEO);
1464 } else {
1465 const cricket::VideoContentDescription* video_desc =
1466 static_cast<const cricket::VideoContentDescription*>(
1467 video_content->description);
1468 UpdateLocalTracks(video_desc->streams(), video_desc->type());
1469 }
deadbeefab9b2d12015-10-14 11:33:11 -07001470 }
1471
1472 const cricket::ContentInfo* data_content =
1473 GetFirstDataContent(desc->description());
1474 if (data_content) {
1475 const cricket::DataContentDescription* data_desc =
1476 static_cast<const cricket::DataContentDescription*>(
1477 data_content->description);
1478 if (rtc::starts_with(data_desc->protocol().data(),
1479 cricket::kMediaProtocolRtpPrefix)) {
1480 UpdateLocalRtpDataChannels(data_desc->streams());
1481 }
1482 }
1483
1484 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001485 signaling_thread()->Post(RTC_FROM_HERE, this,
1486 MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeefab9b2d12015-10-14 11:33:11 -07001487
deadbeef42a42632017-03-10 15:18:00 -08001488 // According to JSEP, after setLocalDescription, changing the candidate pool
1489 // size is not allowed, and changing the set of ICE servers will not result
1490 // in new candidates being gathered.
1491 port_allocator_->FreezeCandidatePool();
1492
deadbeefcbecd352015-09-23 11:50:27 -07001493 // MaybeStartGathering needs to be called after posting
1494 // MSG_SET_SESSIONDESCRIPTION_SUCCESS, so that we don't signal any candidates
1495 // before signaling that SetLocalDescription completed.
Steve Anton75737c02017-11-06 10:37:17 -08001496 MaybeStartGathering();
deadbeef42a42632017-03-10 15:18:00 -08001497
1498 if (desc->type() == SessionDescriptionInterface::kAnswer) {
1499 // TODO(deadbeef): We already had to hop to the network thread for
1500 // MaybeStartGathering...
1501 network_thread()->Invoke<void>(
1502 RTC_FROM_HERE,
1503 rtc::Bind(&cricket::PortAllocator::DiscardCandidatePool,
1504 port_allocator_.get()));
1505 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001506}
1507
1508void PeerConnection::SetRemoteDescription(
1509 SetSessionDescriptionObserver* observer,
1510 SessionDescriptionInterface* desc) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001511 TRACE_EVENT0("webrtc", "PeerConnection::SetRemoteDescription");
nisse7ce109a2017-01-31 00:57:56 -08001512 if (!observer) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001513 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
1514 return;
1515 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001516 if (!desc) {
1517 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
1518 return;
1519 }
Steve Anton8d3444d2017-10-20 15:30:51 -07001520
1521 // Takes the ownership of |desc| regardless of the result.
1522 std::unique_ptr<SessionDescriptionInterface> desc_temp(desc);
1523
1524 if (IsClosed()) {
1525 std::string error = "Failed to set remote " + desc->type() +
1526 " sdp: Called in wrong state: STATE_CLOSED";
1527 LOG(LS_ERROR) << error;
1528 PostSetSessionDescriptionFailure(observer, error);
1529 return;
1530 }
1531
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001532 // Update stats here so that we have the most recent stats for tracks and
1533 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001534 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001535 std::string error;
Steve Anton75737c02017-11-06 10:37:17 -08001536 if (!SetRemoteDescription(std::move(desc_temp), &error)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001537 PostSetSessionDescriptionFailure(observer, error);
1538 return;
1539 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001540
deadbeefab9b2d12015-10-14 11:33:11 -07001541 // If setting the description decided our SSL role, allocate any necessary
1542 // SCTP sids.
1543 rtc::SSLRole role;
Steve Anton75737c02017-11-06 10:37:17 -08001544 if (data_channel_type() == cricket::DCT_SCTP && GetSctpSslRole(&role)) {
deadbeefab9b2d12015-10-14 11:33:11 -07001545 AllocateSctpSids(role);
1546 }
1547
1548 const cricket::SessionDescription* remote_desc = desc->description();
deadbeefbda7e0b2015-12-08 17:13:40 -08001549 const cricket::ContentInfo* audio_content = GetFirstAudioContent(remote_desc);
1550 const cricket::ContentInfo* video_content = GetFirstVideoContent(remote_desc);
1551 const cricket::AudioContentDescription* audio_desc =
1552 GetFirstAudioContentDescription(remote_desc);
1553 const cricket::VideoContentDescription* video_desc =
1554 GetFirstVideoContentDescription(remote_desc);
1555 const cricket::DataContentDescription* data_desc =
1556 GetFirstDataContentDescription(remote_desc);
1557
1558 // Check if the descriptions include streams, just in case the peer supports
1559 // MSID, but doesn't indicate so with "a=msid-semantic".
1560 if (remote_desc->msid_supported() ||
1561 (audio_desc && !audio_desc->streams().empty()) ||
1562 (video_desc && !video_desc->streams().empty())) {
1563 remote_peer_supports_msid_ = true;
1564 }
deadbeefab9b2d12015-10-14 11:33:11 -07001565
1566 // We wait to signal new streams until we finish processing the description,
1567 // since only at that point will new streams have all their tracks.
1568 rtc::scoped_refptr<StreamCollection> new_streams(StreamCollection::Create());
1569
Steve Anton8d3444d2017-10-20 15:30:51 -07001570 // TODO(steveanton): When removing RTP senders/receivers in response to a
1571 // rejected media section, there is some cleanup logic that expects the voice/
1572 // video channel to still be set. But in this method the voice/video channel
Steve Anton75737c02017-11-06 10:37:17 -08001573 // would have been destroyed by the SetRemoteDescription caller above so the
1574 // cleanup that relies on them fails to run. The RemoveTracks calls should be
1575 // moved to right before the DestroyChannel calls to fix this.
Steve Anton8d3444d2017-10-20 15:30:51 -07001576
deadbeefab9b2d12015-10-14 11:33:11 -07001577 // Find all audio rtp streams and create corresponding remote AudioTracks
1578 // and MediaStreams.
deadbeefab9b2d12015-10-14 11:33:11 -07001579 if (audio_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001580 if (audio_content->rejected) {
1581 RemoveTracks(cricket::MEDIA_TYPE_AUDIO);
1582 } else {
deadbeefbda7e0b2015-12-08 17:13:40 -08001583 bool default_audio_track_needed =
1584 !remote_peer_supports_msid_ &&
1585 MediaContentDirectionHasSend(audio_desc->direction());
1586 UpdateRemoteStreamsList(GetActiveStreams(audio_desc),
1587 default_audio_track_needed, audio_desc->type(),
deadbeeffaac4972015-11-12 15:33:07 -08001588 new_streams);
deadbeeffaac4972015-11-12 15:33:07 -08001589 }
deadbeefab9b2d12015-10-14 11:33:11 -07001590 }
1591
1592 // Find all video rtp streams and create corresponding remote VideoTracks
1593 // and MediaStreams.
deadbeefab9b2d12015-10-14 11:33:11 -07001594 if (video_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001595 if (video_content->rejected) {
1596 RemoveTracks(cricket::MEDIA_TYPE_VIDEO);
1597 } else {
deadbeefbda7e0b2015-12-08 17:13:40 -08001598 bool default_video_track_needed =
1599 !remote_peer_supports_msid_ &&
1600 MediaContentDirectionHasSend(video_desc->direction());
1601 UpdateRemoteStreamsList(GetActiveStreams(video_desc),
1602 default_video_track_needed, video_desc->type(),
deadbeeffaac4972015-11-12 15:33:07 -08001603 new_streams);
deadbeeffaac4972015-11-12 15:33:07 -08001604 }
deadbeefab9b2d12015-10-14 11:33:11 -07001605 }
1606
1607 // Update the DataChannels with the information from the remote peer.
deadbeefbda7e0b2015-12-08 17:13:40 -08001608 if (data_desc) {
1609 if (rtc::starts_with(data_desc->protocol().data(),
deadbeefab9b2d12015-10-14 11:33:11 -07001610 cricket::kMediaProtocolRtpPrefix)) {
deadbeefbda7e0b2015-12-08 17:13:40 -08001611 UpdateRemoteRtpDataChannels(GetActiveStreams(data_desc));
deadbeefab9b2d12015-10-14 11:33:11 -07001612 }
1613 }
1614
1615 // Iterate new_streams and notify the observer about new MediaStreams.
1616 for (size_t i = 0; i < new_streams->count(); ++i) {
1617 MediaStreamInterface* new_stream = new_streams->at(i);
1618 stats_->AddStream(new_stream);
Taylor Brandstetter98cde262016-05-31 13:02:21 -07001619 observer_->OnAddStream(
1620 rtc::scoped_refptr<MediaStreamInterface>(new_stream));
deadbeefab9b2d12015-10-14 11:33:11 -07001621 }
1622
deadbeefbda7e0b2015-12-08 17:13:40 -08001623 UpdateEndedRemoteMediaStreams();
deadbeefab9b2d12015-10-14 11:33:11 -07001624
1625 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07001626 signaling_thread()->Post(RTC_FROM_HERE, this,
1627 MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeef42a42632017-03-10 15:18:00 -08001628
1629 if (desc->type() == SessionDescriptionInterface::kAnswer) {
1630 // TODO(deadbeef): We already had to hop to the network thread for
1631 // MaybeStartGathering...
1632 network_thread()->Invoke<void>(
1633 RTC_FROM_HERE,
1634 rtc::Bind(&cricket::PortAllocator::DiscardCandidatePool,
1635 port_allocator_.get()));
1636 }
deadbeeffc648b62015-10-13 16:42:33 -07001637}
1638
deadbeef46c73892016-11-16 19:42:04 -08001639PeerConnectionInterface::RTCConfiguration PeerConnection::GetConfiguration() {
1640 return configuration_;
1641}
1642
deadbeef293e9262017-01-11 12:28:30 -08001643bool PeerConnection::SetConfiguration(const RTCConfiguration& configuration,
1644 RTCError* error) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001645 TRACE_EVENT0("webrtc", "PeerConnection::SetConfiguration");
deadbeef6de92f92016-12-12 18:49:32 -08001646
Steve Anton75737c02017-11-06 10:37:17 -08001647 if (local_description() && configuration.ice_candidate_pool_size !=
1648 configuration_.ice_candidate_pool_size) {
deadbeef6de92f92016-12-12 18:49:32 -08001649 LOG(LS_ERROR) << "Can't change candidate pool size after calling "
1650 "SetLocalDescription.";
deadbeef293e9262017-01-11 12:28:30 -08001651 return SafeSetError(RTCErrorType::INVALID_MODIFICATION, error);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001652 }
Taylor Brandstettera1c30352016-05-13 08:15:11 -07001653
deadbeef293e9262017-01-11 12:28:30 -08001654 // The simplest (and most future-compatible) way to tell if the config was
1655 // modified in an invalid way is to copy each property we do support
1656 // modifying, then use operator==. There are far more properties we don't
1657 // support modifying than those we do, and more could be added.
1658 RTCConfiguration modified_config = configuration_;
1659 modified_config.servers = configuration.servers;
1660 modified_config.type = configuration.type;
1661 modified_config.ice_candidate_pool_size =
1662 configuration.ice_candidate_pool_size;
1663 modified_config.prune_turn_ports = configuration.prune_turn_ports;
skvladd1f5fda2017-02-03 16:54:05 -08001664 modified_config.ice_check_min_interval = configuration.ice_check_min_interval;
Jonas Orelandbdcee282017-10-10 14:01:40 +02001665 modified_config.turn_customizer = configuration.turn_customizer;
deadbeef293e9262017-01-11 12:28:30 -08001666 if (configuration != modified_config) {
1667 LOG(LS_ERROR) << "Modifying the configuration in an unsupported way.";
1668 return SafeSetError(RTCErrorType::INVALID_MODIFICATION, error);
1669 }
1670
Steve Anton038834f2017-07-14 15:59:59 -07001671 // Validate the modified configuration.
1672 RTCError validate_error = ValidateConfiguration(modified_config);
1673 if (!validate_error.ok()) {
1674 return SafeSetError(std::move(validate_error), error);
1675 }
1676
deadbeef293e9262017-01-11 12:28:30 -08001677 // Note that this isn't possible through chromium, since it's an unsigned
1678 // short in WebIDL.
1679 if (configuration.ice_candidate_pool_size < 0 ||
1680 configuration.ice_candidate_pool_size > UINT16_MAX) {
1681 return SafeSetError(RTCErrorType::INVALID_RANGE, error);
1682 }
1683
1684 // Parse ICE servers before hopping to network thread.
1685 cricket::ServerAddresses stun_servers;
1686 std::vector<cricket::RelayServerConfig> turn_servers;
1687 RTCErrorType parse_error =
1688 ParseIceServers(configuration.servers, &stun_servers, &turn_servers);
1689 if (parse_error != RTCErrorType::NONE) {
1690 return SafeSetError(parse_error, error);
1691 }
1692
1693 // In theory this shouldn't fail.
1694 if (!network_thread()->Invoke<bool>(
1695 RTC_FROM_HERE,
1696 rtc::Bind(&PeerConnection::ReconfigurePortAllocator_n, this,
1697 stun_servers, turn_servers, modified_config.type,
1698 modified_config.ice_candidate_pool_size,
Jonas Orelandbdcee282017-10-10 14:01:40 +02001699 modified_config.prune_turn_ports,
1700 modified_config.turn_customizer))) {
deadbeef293e9262017-01-11 12:28:30 -08001701 LOG(LS_ERROR) << "Failed to apply configuration to PortAllocator.";
1702 return SafeSetError(RTCErrorType::INTERNAL_ERROR, error);
1703 }
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07001704
deadbeefd1a38b52016-12-10 13:15:33 -08001705 // As described in JSEP, calling setConfiguration with new ICE servers or
1706 // candidate policy must set a "needs-ice-restart" bit so that the next offer
1707 // triggers an ICE restart which will pick up the changes.
deadbeef293e9262017-01-11 12:28:30 -08001708 if (modified_config.servers != configuration_.servers ||
1709 modified_config.type != configuration_.type ||
1710 modified_config.prune_turn_ports != configuration_.prune_turn_ports) {
Steve Anton75737c02017-11-06 10:37:17 -08001711 SetNeedsIceRestartFlag();
deadbeefd1a38b52016-12-10 13:15:33 -08001712 }
skvladd1f5fda2017-02-03 16:54:05 -08001713
1714 if (modified_config.ice_check_min_interval !=
1715 configuration_.ice_check_min_interval) {
Steve Anton75737c02017-11-06 10:37:17 -08001716 SetIceConfig(ParseIceConfig(modified_config));
skvladd1f5fda2017-02-03 16:54:05 -08001717 }
1718
deadbeef293e9262017-01-11 12:28:30 -08001719 configuration_ = modified_config;
1720 return SafeSetError(RTCErrorType::NONE, error);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001721}
1722
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001723bool PeerConnection::AddIceCandidate(
1724 const IceCandidateInterface* ice_candidate) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001725 TRACE_EVENT0("webrtc", "PeerConnection::AddIceCandidate");
zhihuang29ff8442016-07-27 11:07:25 -07001726 if (IsClosed()) {
1727 return false;
1728 }
Steve Anton75737c02017-11-06 10:37:17 -08001729 return ProcessIceMessage(ice_candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001730}
1731
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001732bool PeerConnection::RemoveIceCandidates(
1733 const std::vector<cricket::Candidate>& candidates) {
1734 TRACE_EVENT0("webrtc", "PeerConnection::RemoveIceCandidates");
Steve Anton75737c02017-11-06 10:37:17 -08001735 return RemoveRemoteIceCandidates(candidates);
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001736}
1737
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001738void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001739 TRACE_EVENT0("webrtc", "PeerConnection::RegisterUmaObserver");
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001740 uma_observer_ = observer;
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +00001741
Steve Anton75737c02017-11-06 10:37:17 -08001742 if (transport_controller()) {
1743 transport_controller()->SetMetricsObserver(uma_observer_);
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +00001744 }
1745
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001746 // Send information about IPv4/IPv6 status.
deadbeef293e9262017-01-11 12:28:30 -08001747 if (uma_observer_) {
Honghai Zhangd93f50c2016-10-05 11:47:22 -07001748 port_allocator_->SetMetricsObserver(uma_observer_);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001749 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001750 uma_observer_->IncrementEnumCounter(
1751 kEnumCounterAddressFamily, kPeerConnection_IPv6,
1752 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgb445f262014-05-23 22:19:37 +00001753 } else {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001754 uma_observer_->IncrementEnumCounter(
1755 kEnumCounterAddressFamily, kPeerConnection_IPv4,
1756 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001757 }
1758 }
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001759}
1760
zstein4b979802017-06-02 14:37:37 -07001761RTCError PeerConnection::SetBitrate(const BitrateParameters& bitrate) {
Steve Anton978b8762017-09-29 12:15:02 -07001762 if (!worker_thread()->IsCurrent()) {
1763 return worker_thread()->Invoke<RTCError>(
zstein4b979802017-06-02 14:37:37 -07001764 RTC_FROM_HERE, rtc::Bind(&PeerConnection::SetBitrate, this, bitrate));
1765 }
1766
1767 const bool has_min = static_cast<bool>(bitrate.min_bitrate_bps);
1768 const bool has_current = static_cast<bool>(bitrate.current_bitrate_bps);
1769 const bool has_max = static_cast<bool>(bitrate.max_bitrate_bps);
1770 if (has_min && *bitrate.min_bitrate_bps < 0) {
1771 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
1772 "min_bitrate_bps <= 0");
1773 }
1774 if (has_current) {
1775 if (has_min && *bitrate.current_bitrate_bps < *bitrate.min_bitrate_bps) {
1776 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
1777 "current_bitrate_bps < min_bitrate_bps");
1778 } else if (*bitrate.current_bitrate_bps < 0) {
1779 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
1780 "curent_bitrate_bps < 0");
1781 }
1782 }
1783 if (has_max) {
1784 if (has_current &&
1785 *bitrate.max_bitrate_bps < *bitrate.current_bitrate_bps) {
1786 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
1787 "max_bitrate_bps < current_bitrate_bps");
1788 } else if (has_min && *bitrate.max_bitrate_bps < *bitrate.min_bitrate_bps) {
1789 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
1790 "max_bitrate_bps < min_bitrate_bps");
1791 } else if (*bitrate.max_bitrate_bps < 0) {
1792 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
1793 "max_bitrate_bps < 0");
1794 }
1795 }
1796
1797 Call::Config::BitrateConfigMask mask;
1798 mask.min_bitrate_bps = bitrate.min_bitrate_bps;
1799 mask.start_bitrate_bps = bitrate.current_bitrate_bps;
1800 mask.max_bitrate_bps = bitrate.max_bitrate_bps;
1801
1802 RTC_DCHECK(call_.get());
1803 call_->SetBitrateConfigMask(mask);
1804
1805 return RTCError::OK();
1806}
1807
Alex Narest78609d52017-10-20 10:37:47 +02001808void PeerConnection::SetBitrateAllocationStrategy(
1809 std::unique_ptr<rtc::BitrateAllocationStrategy>
1810 bitrate_allocation_strategy) {
1811 rtc::Thread* worker_thread = factory_->worker_thread();
1812 if (!worker_thread->IsCurrent()) {
1813 rtc::BitrateAllocationStrategy* strategy_raw =
1814 bitrate_allocation_strategy.release();
1815 auto functor = [this, strategy_raw]() {
1816 call_->SetBitrateAllocationStrategy(
1817 rtc::WrapUnique<rtc::BitrateAllocationStrategy>(strategy_raw));
1818 };
1819 worker_thread->Invoke<void>(RTC_FROM_HERE, functor);
1820 return;
1821 }
1822 RTC_DCHECK(call_.get());
1823 call_->SetBitrateAllocationStrategy(std::move(bitrate_allocation_strategy));
1824}
1825
henrika5f6bf242017-11-01 11:06:56 +01001826void PeerConnection::SetAudioPlayout(bool playout) {
1827 if (!worker_thread()->IsCurrent()) {
1828 worker_thread()->Invoke<void>(
1829 RTC_FROM_HERE,
1830 rtc::Bind(&PeerConnection::SetAudioPlayout, this, playout));
1831 return;
1832 }
1833 auto audio_state =
1834 factory_->channel_manager()->media_engine()->GetAudioState();
1835 audio_state->SetPlayout(playout);
1836}
1837
1838void PeerConnection::SetAudioRecording(bool recording) {
1839 if (!worker_thread()->IsCurrent()) {
1840 worker_thread()->Invoke<void>(
1841 RTC_FROM_HERE,
1842 rtc::Bind(&PeerConnection::SetAudioRecording, this, recording));
1843 return;
1844 }
1845 auto audio_state =
1846 factory_->channel_manager()->media_engine()->GetAudioState();
1847 audio_state->SetRecording(recording);
1848}
1849
Steve Anton8c0f7a72017-10-03 10:03:10 -07001850std::unique_ptr<rtc::SSLCertificate>
1851PeerConnection::GetRemoteAudioSSLCertificate() {
Steve Anton75737c02017-11-06 10:37:17 -08001852 if (!voice_channel()) {
Steve Anton8c0f7a72017-10-03 10:03:10 -07001853 return nullptr;
1854 }
Steve Anton75737c02017-11-06 10:37:17 -08001855 return GetRemoteSSLCertificate(voice_channel()->transport_name());
Steve Anton8c0f7a72017-10-03 10:03:10 -07001856}
1857
ivoc14d5dbe2016-07-04 07:06:55 -07001858bool PeerConnection::StartRtcEventLog(rtc::PlatformFile file,
1859 int64_t max_size_bytes) {
Elad Alon99c3fe52017-10-13 16:29:40 +02001860 // TODO(eladalon): It would be better to not allow negative values into PC.
1861 const size_t max_size = (max_size_bytes < 0)
1862 ? RtcEventLog::kUnlimitedOutput
1863 : rtc::saturated_cast<size_t>(max_size_bytes);
1864 return StartRtcEventLog(
1865 rtc::MakeUnique<RtcEventLogOutputFile>(file, max_size));
1866}
1867
1868bool PeerConnection::StartRtcEventLog(
1869 std::unique_ptr<RtcEventLogOutput> output) {
Karl Wibergd6b48192017-10-16 23:01:06 +02001870 // TODO(eladalon): In C++14, this can be done with a lambda.
1871 struct Functor {
1872 bool operator()() { return pc->StartRtcEventLog_w(std::move(output)); }
1873 PeerConnection* const pc;
1874 std::unique_ptr<RtcEventLogOutput> output;
Elad Alon99c3fe52017-10-13 16:29:40 +02001875 };
Karl Wibergd6b48192017-10-16 23:01:06 +02001876 return worker_thread()->Invoke<bool>(RTC_FROM_HERE,
1877 Functor{this, std::move(output)});
ivoc14d5dbe2016-07-04 07:06:55 -07001878}
1879
1880void PeerConnection::StopRtcEventLog() {
Steve Anton978b8762017-09-29 12:15:02 -07001881 worker_thread()->Invoke<void>(
ivoc14d5dbe2016-07-04 07:06:55 -07001882 RTC_FROM_HERE, rtc::Bind(&PeerConnection::StopRtcEventLog_w, this));
1883}
1884
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001885const SessionDescriptionInterface* PeerConnection::local_description() const {
Steve Anton75737c02017-11-06 10:37:17 -08001886 return pending_local_description_ ? pending_local_description_.get()
1887 : current_local_description_.get();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001888}
1889
1890const SessionDescriptionInterface* PeerConnection::remote_description() const {
Steve Anton75737c02017-11-06 10:37:17 -08001891 return pending_remote_description_ ? pending_remote_description_.get()
1892 : current_remote_description_.get();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001893}
1894
deadbeeffe4a8a42016-12-20 17:56:17 -08001895const SessionDescriptionInterface* PeerConnection::current_local_description()
1896 const {
Steve Anton75737c02017-11-06 10:37:17 -08001897 return current_local_description_.get();
deadbeeffe4a8a42016-12-20 17:56:17 -08001898}
1899
1900const SessionDescriptionInterface* PeerConnection::current_remote_description()
1901 const {
Steve Anton75737c02017-11-06 10:37:17 -08001902 return current_remote_description_.get();
deadbeeffe4a8a42016-12-20 17:56:17 -08001903}
1904
1905const SessionDescriptionInterface* PeerConnection::pending_local_description()
1906 const {
Steve Anton75737c02017-11-06 10:37:17 -08001907 return pending_local_description_.get();
deadbeeffe4a8a42016-12-20 17:56:17 -08001908}
1909
1910const SessionDescriptionInterface* PeerConnection::pending_remote_description()
1911 const {
Steve Anton75737c02017-11-06 10:37:17 -08001912 return pending_remote_description_.get();
deadbeeffe4a8a42016-12-20 17:56:17 -08001913}
1914
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001915void PeerConnection::Close() {
Peter Boström1a9d6152015-12-08 22:15:17 +01001916 TRACE_EVENT0("webrtc", "PeerConnection::Close");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001917 // Update stats here so that we have the most recent stats for tracks and
1918 // streams before the channels are closed.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001919 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001920
Steve Anton75737c02017-11-06 10:37:17 -08001921 ChangeSignalingState(PeerConnectionInterface::kClosed);
1922 RemoveUnusedChannels(nullptr);
1923 RTC_DCHECK(voice_channels_.empty());
1924 RTC_DCHECK(video_channels_.empty());
1925 RTC_DCHECK(!rtp_data_channel_);
1926 RTC_DCHECK(!sctp_transport_);
1927
deadbeef42a42632017-03-10 15:18:00 -08001928 network_thread()->Invoke<void>(
1929 RTC_FROM_HERE,
1930 rtc::Bind(&cricket::PortAllocator::DiscardCandidatePool,
1931 port_allocator_.get()));
nisseeaabdf62017-05-05 02:23:02 -07001932
Steve Anton978b8762017-09-29 12:15:02 -07001933 worker_thread()->Invoke<void>(RTC_FROM_HERE, [this] {
eladalon248fd4f2017-09-06 05:18:15 -07001934 call_.reset();
1935 // The event log must outlive call (and any other object that uses it).
1936 event_log_.reset();
1937 });
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001938}
1939
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001940void PeerConnection::OnMessage(rtc::Message* msg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001941 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001942 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
1943 SetSessionDescriptionMsg* param =
1944 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1945 param->observer->OnSuccess();
1946 delete param;
1947 break;
1948 }
1949 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
1950 SetSessionDescriptionMsg* param =
1951 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1952 param->observer->OnFailure(param->error);
1953 delete param;
1954 break;
1955 }
deadbeefab9b2d12015-10-14 11:33:11 -07001956 case MSG_CREATE_SESSIONDESCRIPTION_FAILED: {
1957 CreateSessionDescriptionMsg* param =
1958 static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
1959 param->observer->OnFailure(param->error);
1960 delete param;
1961 break;
1962 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001963 case MSG_GETSTATS: {
1964 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
nissee8abe3e2017-01-18 05:00:34 -08001965 StatsReports reports;
1966 stats_->GetStats(param->track, &reports);
1967 param->observer->OnComplete(reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001968 delete param;
1969 break;
1970 }
deadbeefbd292462015-12-14 18:15:29 -08001971 case MSG_FREE_DATACHANNELS: {
1972 sctp_data_channels_to_free_.clear();
1973 break;
1974 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001975 default:
nisseeb4ca4e2017-01-12 02:24:27 -08001976 RTC_NOTREACHED() << "Not implemented";
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001977 break;
1978 }
1979}
1980
deadbeefab9b2d12015-10-14 11:33:11 -07001981void PeerConnection::CreateAudioReceiver(MediaStreamInterface* stream,
perkjd61bf802016-03-24 03:16:19 -07001982 const std::string& track_id,
deadbeefab9b2d12015-10-14 11:33:11 -07001983 uint32_t ssrc) {
zhihuang81c3a032016-11-17 12:06:24 -08001984 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
1985 receiver = RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
deadbeefe814a0d2017-02-25 18:15:09 -08001986 signaling_thread(),
Steve Anton75737c02017-11-06 10:37:17 -08001987 new AudioRtpReceiver(track_id, ssrc, voice_channel()));
deadbeefe814a0d2017-02-25 18:15:09 -08001988 stream->AddTrack(
1989 static_cast<AudioTrackInterface*>(receiver->internal()->track().get()));
zhihuang81c3a032016-11-17 12:06:24 -08001990 receivers_.push_back(receiver);
1991 std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams;
1992 streams.push_back(rtc::scoped_refptr<MediaStreamInterface>(stream));
1993 observer_->OnAddTrack(receiver, streams);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001994}
1995
deadbeefab9b2d12015-10-14 11:33:11 -07001996void PeerConnection::CreateVideoReceiver(MediaStreamInterface* stream,
perkjf0dcfe22016-03-10 18:32:00 +01001997 const std::string& track_id,
deadbeefab9b2d12015-10-14 11:33:11 -07001998 uint32_t ssrc) {
zhihuang81c3a032016-11-17 12:06:24 -08001999 rtc::scoped_refptr<RtpReceiverProxyWithInternal<RtpReceiverInternal>>
2000 receiver = RtpReceiverProxyWithInternal<RtpReceiverInternal>::Create(
Steve Anton75737c02017-11-06 10:37:17 -08002001 signaling_thread(), new VideoRtpReceiver(track_id, worker_thread(),
2002 ssrc, video_channel()));
deadbeefe814a0d2017-02-25 18:15:09 -08002003 stream->AddTrack(
2004 static_cast<VideoTrackInterface*>(receiver->internal()->track().get()));
zhihuang81c3a032016-11-17 12:06:24 -08002005 receivers_.push_back(receiver);
2006 std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams;
2007 streams.push_back(rtc::scoped_refptr<MediaStreamInterface>(stream));
2008 observer_->OnAddTrack(receiver, streams);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002009}
2010
deadbeef70ab1a12015-09-28 16:53:55 -07002011// TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote
2012// description.
Henrik Boström933d8b02017-10-10 10:05:16 -07002013rtc::scoped_refptr<RtpReceiverInterface> PeerConnection::RemoveAndStopReceiver(
2014 const std::string& track_id) {
perkjd61bf802016-03-24 03:16:19 -07002015 auto it = FindReceiverForTrack(track_id);
deadbeef70ab1a12015-09-28 16:53:55 -07002016 if (it == receivers_.end()) {
perkjd61bf802016-03-24 03:16:19 -07002017 LOG(LS_WARNING) << "RtpReceiver for track with id " << track_id
deadbeef70ab1a12015-09-28 16:53:55 -07002018 << " doesn't exist.";
Henrik Boström933d8b02017-10-10 10:05:16 -07002019 return nullptr;
deadbeef70ab1a12015-09-28 16:53:55 -07002020 }
Henrik Boström933d8b02017-10-10 10:05:16 -07002021 (*it)->internal()->Stop();
2022 rtc::scoped_refptr<RtpReceiverInterface> receiver = *it;
2023 receivers_.erase(it);
2024 return receiver;
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002025}
2026
korniltsev.anatolyec390b52017-07-24 17:00:25 -07002027void PeerConnection::AddAudioTrack(AudioTrackInterface* track,
2028 MediaStreamInterface* stream) {
2029 RTC_DCHECK(!IsClosed());
2030 auto sender = FindSenderForTrack(track);
2031 if (sender != senders_.end()) {
2032 // We already have a sender for this track, so just change the stream_id
2033 // so that it's correct in the next call to CreateOffer.
2034 (*sender)->internal()->set_stream_id(stream->label());
2035 return;
2036 }
2037
2038 // Normal case; we've never seen this track before.
2039 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> new_sender =
2040 RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
2041 signaling_thread(),
Steve Anton75737c02017-11-06 10:37:17 -08002042 new AudioRtpSender(track, {stream->label()}, voice_channel(),
2043 stats_.get()));
korniltsev.anatolyec390b52017-07-24 17:00:25 -07002044 senders_.push_back(new_sender);
2045 // If the sender has already been configured in SDP, we call SetSsrc,
2046 // which will connect the sender to the underlying transport. This can
2047 // occur if a local session description that contains the ID of the sender
2048 // is set before AddStream is called. It can also occur if the local
2049 // session description is not changed and RemoveStream is called, and
2050 // later AddStream is called again with the same stream.
2051 const TrackInfo* track_info =
2052 FindTrackInfo(local_audio_tracks_, stream->label(), track->id());
2053 if (track_info) {
2054 new_sender->internal()->SetSsrc(track_info->ssrc);
2055 }
2056}
2057
2058// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around
2059// indefinitely, when we have unified plan SDP.
2060void PeerConnection::RemoveAudioTrack(AudioTrackInterface* track,
2061 MediaStreamInterface* stream) {
2062 RTC_DCHECK(!IsClosed());
2063 auto sender = FindSenderForTrack(track);
2064 if (sender == senders_.end()) {
2065 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
2066 << " doesn't exist.";
2067 return;
2068 }
2069 (*sender)->internal()->Stop();
2070 senders_.erase(sender);
2071}
2072
2073void PeerConnection::AddVideoTrack(VideoTrackInterface* track,
2074 MediaStreamInterface* stream) {
2075 RTC_DCHECK(!IsClosed());
2076 auto sender = FindSenderForTrack(track);
2077 if (sender != senders_.end()) {
2078 // We already have a sender for this track, so just change the stream_id
2079 // so that it's correct in the next call to CreateOffer.
2080 (*sender)->internal()->set_stream_id(stream->label());
2081 return;
2082 }
2083
2084 // Normal case; we've never seen this track before.
2085 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>> new_sender =
2086 RtpSenderProxyWithInternal<RtpSenderInternal>::Create(
Steve Anton75737c02017-11-06 10:37:17 -08002087 signaling_thread(),
2088 new VideoRtpSender(track, {stream->label()}, video_channel()));
korniltsev.anatolyec390b52017-07-24 17:00:25 -07002089 senders_.push_back(new_sender);
2090 const TrackInfo* track_info =
2091 FindTrackInfo(local_video_tracks_, stream->label(), track->id());
2092 if (track_info) {
2093 new_sender->internal()->SetSsrc(track_info->ssrc);
2094 }
2095}
2096
2097void PeerConnection::RemoveVideoTrack(VideoTrackInterface* track,
2098 MediaStreamInterface* stream) {
2099 RTC_DCHECK(!IsClosed());
2100 auto sender = FindSenderForTrack(track);
2101 if (sender == senders_.end()) {
2102 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
2103 << " doesn't exist.";
2104 return;
2105 }
2106 (*sender)->internal()->Stop();
2107 senders_.erase(sender);
2108}
2109
Steve Antonba818672017-11-06 10:21:57 -08002110void PeerConnection::SetIceConnectionState(IceConnectionState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07002111 RTC_DCHECK(signaling_thread()->IsCurrent());
Steve Antonba818672017-11-06 10:21:57 -08002112 if (ice_connection_state_ == new_state) {
2113 return;
2114 }
2115
deadbeefcbecd352015-09-23 11:50:27 -07002116 // After transitioning to "closed", ignore any additional states from
Steve Antonba818672017-11-06 10:21:57 -08002117 // TransportController (such as "disconnected").
deadbeefab9b2d12015-10-14 11:33:11 -07002118 if (IsClosed()) {
deadbeefcbecd352015-09-23 11:50:27 -07002119 return;
2120 }
Steve Antonba818672017-11-06 10:21:57 -08002121
2122 LOG(LS_INFO) << "Changing IceConnectionState " << ice_connection_state_
2123 << " => " << new_state;
2124 RTC_DCHECK(ice_connection_state_ !=
2125 PeerConnectionInterface::kIceConnectionClosed);
2126
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002127 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00002128 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002129}
2130
2131void PeerConnection::OnIceGatheringChange(
2132 PeerConnectionInterface::IceGatheringState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07002133 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002134 if (IsClosed()) {
2135 return;
2136 }
2137 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00002138 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002139}
2140
jbauch81bf7b02017-03-25 08:31:12 -07002141void PeerConnection::OnIceCandidate(
2142 std::unique_ptr<IceCandidateInterface> candidate) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07002143 RTC_DCHECK(signaling_thread()->IsCurrent());
zhihuang29ff8442016-07-27 11:07:25 -07002144 if (IsClosed()) {
2145 return;
2146 }
jbauch81bf7b02017-03-25 08:31:12 -07002147 observer_->OnIceCandidate(candidate.get());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002148}
2149
Honghai Zhang7fb69db2016-03-14 11:59:18 -07002150void PeerConnection::OnIceCandidatesRemoved(
2151 const std::vector<cricket::Candidate>& candidates) {
2152 RTC_DCHECK(signaling_thread()->IsCurrent());
zhihuang29ff8442016-07-27 11:07:25 -07002153 if (IsClosed()) {
2154 return;
2155 }
Honghai Zhang7fb69db2016-03-14 11:59:18 -07002156 observer_->OnIceCandidatesRemoved(candidates);
2157}
2158
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002159void PeerConnection::ChangeSignalingState(
2160 PeerConnectionInterface::SignalingState signaling_state) {
Steve Antonba818672017-11-06 10:21:57 -08002161 RTC_DCHECK(signaling_thread()->IsCurrent());
2162 if (signaling_state_ == signaling_state) {
2163 return;
2164 }
2165 LOG(LS_INFO) << "Session: " << session_id()
2166 << " Old state: " << GetSignalingStateString(signaling_state_)
2167 << " New state: " << GetSignalingStateString(signaling_state);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002168 signaling_state_ = signaling_state;
2169 if (signaling_state == kClosed) {
2170 ice_connection_state_ = kIceConnectionClosed;
2171 observer_->OnIceConnectionChange(ice_connection_state_);
2172 if (ice_gathering_state_ != kIceGatheringComplete) {
2173 ice_gathering_state_ = kIceGatheringComplete;
2174 observer_->OnIceGatheringChange(ice_gathering_state_);
2175 }
2176 }
2177 observer_->OnSignalingChange(signaling_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002178}
2179
deadbeefeb459812015-12-15 19:24:43 -08002180void PeerConnection::OnAudioTrackAdded(AudioTrackInterface* track,
2181 MediaStreamInterface* stream) {
zhihuang29ff8442016-07-27 11:07:25 -07002182 if (IsClosed()) {
2183 return;
2184 }
korniltsev.anatolyec390b52017-07-24 17:00:25 -07002185 AddAudioTrack(track, stream);
2186 observer_->OnRenegotiationNeeded();
deadbeefeb459812015-12-15 19:24:43 -08002187}
2188
deadbeefeb459812015-12-15 19:24:43 -08002189void PeerConnection::OnAudioTrackRemoved(AudioTrackInterface* track,
2190 MediaStreamInterface* stream) {
zhihuang29ff8442016-07-27 11:07:25 -07002191 if (IsClosed()) {
2192 return;
2193 }
korniltsev.anatolyec390b52017-07-24 17:00:25 -07002194 RemoveAudioTrack(track, stream);
2195 observer_->OnRenegotiationNeeded();
deadbeefeb459812015-12-15 19:24:43 -08002196}
2197
2198void PeerConnection::OnVideoTrackAdded(VideoTrackInterface* track,
2199 MediaStreamInterface* stream) {
zhihuang29ff8442016-07-27 11:07:25 -07002200 if (IsClosed()) {
2201 return;
2202 }
korniltsev.anatolyec390b52017-07-24 17:00:25 -07002203 AddVideoTrack(track, stream);
2204 observer_->OnRenegotiationNeeded();
deadbeefeb459812015-12-15 19:24:43 -08002205}
2206
2207void PeerConnection::OnVideoTrackRemoved(VideoTrackInterface* track,
2208 MediaStreamInterface* stream) {
zhihuang29ff8442016-07-27 11:07:25 -07002209 if (IsClosed()) {
2210 return;
2211 }
korniltsev.anatolyec390b52017-07-24 17:00:25 -07002212 RemoveVideoTrack(track, stream);
2213 observer_->OnRenegotiationNeeded();
deadbeefeb459812015-12-15 19:24:43 -08002214}
2215
deadbeefab9b2d12015-10-14 11:33:11 -07002216void PeerConnection::PostSetSessionDescriptionFailure(
2217 SetSessionDescriptionObserver* observer,
2218 const std::string& error) {
2219 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
2220 msg->error = error;
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07002221 signaling_thread()->Post(RTC_FROM_HERE, this,
2222 MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
deadbeefab9b2d12015-10-14 11:33:11 -07002223}
2224
2225void PeerConnection::PostCreateSessionDescriptionFailure(
2226 CreateSessionDescriptionObserver* observer,
2227 const std::string& error) {
2228 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
2229 msg->error = error;
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07002230 signaling_thread()->Post(RTC_FROM_HERE, this,
2231 MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
deadbeefab9b2d12015-10-14 11:33:11 -07002232}
2233
zhihuang1c378ed2017-08-17 14:10:50 -07002234void PeerConnection::GetOptionsForOffer(
deadbeefab9b2d12015-10-14 11:33:11 -07002235 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
2236 cricket::MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -07002237 ExtractSharedMediaSessionOptions(rtc_options, session_options);
2238
2239 // Figure out transceiver directional preferences.
2240 bool send_audio = HasRtpSender(cricket::MEDIA_TYPE_AUDIO);
2241 bool send_video = HasRtpSender(cricket::MEDIA_TYPE_VIDEO);
2242
2243 // By default, generate sendrecv/recvonly m= sections.
2244 bool recv_audio = true;
2245 bool recv_video = true;
2246
2247 // By default, only offer a new m= section if we have media to send with it.
2248 bool offer_new_audio_description = send_audio;
2249 bool offer_new_video_description = send_video;
2250 bool offer_new_data_description = HasDataChannels();
2251
2252 // The "offer_to_receive_X" options allow those defaults to be overridden.
2253 if (rtc_options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) {
2254 recv_audio = (rtc_options.offer_to_receive_audio > 0);
2255 offer_new_audio_description =
2256 offer_new_audio_description || (rtc_options.offer_to_receive_audio > 0);
2257 }
2258 if (rtc_options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) {
2259 recv_video = (rtc_options.offer_to_receive_video > 0);
2260 offer_new_video_description =
2261 offer_new_video_description || (rtc_options.offer_to_receive_video > 0);
2262 }
2263
2264 rtc::Optional<size_t> audio_index;
2265 rtc::Optional<size_t> video_index;
2266 rtc::Optional<size_t> data_index;
2267 // If a current description exists, generate m= sections in the same order,
2268 // using the first audio/video/data section that appears and rejecting
2269 // extraneous ones.
Steve Anton75737c02017-11-06 10:37:17 -08002270 if (local_description()) {
zhihuang1c378ed2017-08-17 14:10:50 -07002271 GenerateMediaDescriptionOptions(
Steve Anton75737c02017-11-06 10:37:17 -08002272 local_description(),
zhihuang1c378ed2017-08-17 14:10:50 -07002273 cricket::RtpTransceiverDirection(send_audio, recv_audio),
2274 cricket::RtpTransceiverDirection(send_video, recv_video), &audio_index,
2275 &video_index, &data_index, session_options);
deadbeefab9b2d12015-10-14 11:33:11 -07002276 }
2277
zhihuang1c378ed2017-08-17 14:10:50 -07002278 // Add audio/video/data m= sections to the end if needed.
2279 if (!audio_index && offer_new_audio_description) {
2280 session_options->media_description_options.push_back(
2281 cricket::MediaDescriptionOptions(
2282 cricket::MEDIA_TYPE_AUDIO, cricket::CN_AUDIO,
2283 cricket::RtpTransceiverDirection(send_audio, recv_audio), false));
2284 audio_index = rtc::Optional<size_t>(
2285 session_options->media_description_options.size() - 1);
deadbeefc80741f2015-10-22 13:14:45 -07002286 }
zhihuang1c378ed2017-08-17 14:10:50 -07002287 if (!video_index && offer_new_video_description) {
2288 session_options->media_description_options.push_back(
2289 cricket::MediaDescriptionOptions(
2290 cricket::MEDIA_TYPE_VIDEO, cricket::CN_VIDEO,
2291 cricket::RtpTransceiverDirection(send_video, recv_video), false));
2292 video_index = rtc::Optional<size_t>(
2293 session_options->media_description_options.size() - 1);
deadbeefc80741f2015-10-22 13:14:45 -07002294 }
zhihuang1c378ed2017-08-17 14:10:50 -07002295 if (!data_index && offer_new_data_description) {
2296 session_options->media_description_options.push_back(
2297 cricket::MediaDescriptionOptions(
2298 cricket::MEDIA_TYPE_DATA, cricket::CN_DATA,
2299 cricket::RtpTransceiverDirection(true, true), false));
2300 data_index = rtc::Optional<size_t>(
2301 session_options->media_description_options.size() - 1);
2302 }
2303
2304 cricket::MediaDescriptionOptions* audio_media_description_options =
2305 !audio_index ? nullptr
2306 : &session_options->media_description_options[*audio_index];
2307 cricket::MediaDescriptionOptions* video_media_description_options =
2308 !video_index ? nullptr
2309 : &session_options->media_description_options[*video_index];
2310 cricket::MediaDescriptionOptions* data_media_description_options =
2311 !data_index ? nullptr
2312 : &session_options->media_description_options[*data_index];
2313
2314 // Apply ICE restart flag and renomination flag.
2315 for (auto& options : session_options->media_description_options) {
2316 options.transport_options.ice_restart = rtc_options.ice_restart;
2317 options.transport_options.enable_ice_renomination =
2318 configuration_.enable_ice_renomination;
2319 }
2320
2321 AddRtpSenderOptions(senders_, audio_media_description_options,
2322 video_media_description_options);
2323 AddRtpDataChannelOptions(rtp_data_channels_, data_media_description_options);
deadbeefc80741f2015-10-22 13:14:45 -07002324
zhihuang9763d562016-08-05 11:14:50 -07002325 // Intentionally unset the data channel type for RTP data channel with the
2326 // second condition. Otherwise the RTP data channels would be successfully
2327 // negotiated by default and the unit tests in WebRtcDataBrowserTest will fail
2328 // when building with chromium. We want to leave RTP data channels broken, so
2329 // people won't try to use them.
Steve Anton75737c02017-11-06 10:37:17 -08002330 if (!rtp_data_channels_.empty() || data_channel_type() != cricket::DCT_RTP) {
2331 session_options->data_channel_type = data_channel_type();
deadbeefab9b2d12015-10-14 11:33:11 -07002332 }
zhihuang8f65cdf2016-05-06 18:40:30 -07002333
2334 session_options->rtcp_cname = rtcp_cname_;
jbauchcb560652016-08-04 05:20:32 -07002335 session_options->crypto_options = factory_->options().crypto_options;
deadbeefab9b2d12015-10-14 11:33:11 -07002336}
2337
zhihuang1c378ed2017-08-17 14:10:50 -07002338void PeerConnection::GetOptionsForAnswer(
2339 const RTCOfferAnswerOptions& rtc_options,
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002340 cricket::MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -07002341 ExtractSharedMediaSessionOptions(rtc_options, session_options);
Honghai Zhang4cedf2b2016-08-31 08:18:11 -07002342
zhihuang1c378ed2017-08-17 14:10:50 -07002343 // Figure out transceiver directional preferences.
2344 bool send_audio = HasRtpSender(cricket::MEDIA_TYPE_AUDIO);
2345 bool send_video = HasRtpSender(cricket::MEDIA_TYPE_VIDEO);
2346
2347 // By default, generate sendrecv/recvonly m= sections. The direction is also
2348 // restricted by the direction in the offer.
2349 bool recv_audio = true;
2350 bool recv_video = true;
2351
2352 // The "offer_to_receive_X" options allow those defaults to be overridden.
2353 if (rtc_options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) {
2354 recv_audio = (rtc_options.offer_to_receive_audio > 0);
deadbeef0ed85b22016-02-23 17:24:52 -08002355 }
zhihuang1c378ed2017-08-17 14:10:50 -07002356 if (rtc_options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) {
2357 recv_video = (rtc_options.offer_to_receive_video > 0);
2358 }
2359
2360 rtc::Optional<size_t> audio_index;
2361 rtc::Optional<size_t> video_index;
2362 rtc::Optional<size_t> data_index;
Steve Anton75737c02017-11-06 10:37:17 -08002363 if (remote_description()) {
zhihuang141aacb2017-08-29 13:23:53 -07002364 // The pending remote description should be an offer.
Steve Anton75737c02017-11-06 10:37:17 -08002365 RTC_DCHECK(remote_description()->type() ==
zhihuang141aacb2017-08-29 13:23:53 -07002366 SessionDescriptionInterface::kOffer);
2367 // Generate m= sections that match those in the offer.
2368 // Note that mediasession.cc will handle intersection our preferred
2369 // direction with the offered direction.
2370 GenerateMediaDescriptionOptions(
Steve Anton75737c02017-11-06 10:37:17 -08002371 remote_description(),
zhihuang141aacb2017-08-29 13:23:53 -07002372 cricket::RtpTransceiverDirection(send_audio, recv_audio),
2373 cricket::RtpTransceiverDirection(send_video, recv_video), &audio_index,
2374 &video_index, &data_index, session_options);
2375 }
zhihuang1c378ed2017-08-17 14:10:50 -07002376
2377 cricket::MediaDescriptionOptions* audio_media_description_options =
2378 !audio_index ? nullptr
2379 : &session_options->media_description_options[*audio_index];
2380 cricket::MediaDescriptionOptions* video_media_description_options =
2381 !video_index ? nullptr
2382 : &session_options->media_description_options[*video_index];
2383 cricket::MediaDescriptionOptions* data_media_description_options =
2384 !data_index ? nullptr
2385 : &session_options->media_description_options[*data_index];
2386
2387 // Apply ICE renomination flag.
2388 for (auto& options : session_options->media_description_options) {
2389 options.transport_options.enable_ice_renomination =
2390 configuration_.enable_ice_renomination;
2391 }
2392
2393 AddRtpSenderOptions(senders_, audio_media_description_options,
2394 video_media_description_options);
2395 AddRtpDataChannelOptions(rtp_data_channels_, data_media_description_options);
2396
zhihuang9763d562016-08-05 11:14:50 -07002397 // Intentionally unset the data channel type for RTP data channel. Otherwise
2398 // the RTP data channels would be successfully negotiated by default and the
2399 // unit tests in WebRtcDataBrowserTest will fail when building with chromium.
2400 // We want to leave RTP data channels broken, so people won't try to use them.
Steve Anton75737c02017-11-06 10:37:17 -08002401 if (!rtp_data_channels_.empty() || data_channel_type() != cricket::DCT_RTP) {
2402 session_options->data_channel_type = data_channel_type();
deadbeef907abe42016-08-04 12:22:18 -07002403 }
zhihuangaf388472016-11-02 16:49:48 -07002404
zhihuang1c378ed2017-08-17 14:10:50 -07002405 session_options->rtcp_cname = rtcp_cname_;
jbauchcb560652016-08-04 05:20:32 -07002406 session_options->crypto_options = factory_->options().crypto_options;
htaa2a49d92016-03-04 02:51:39 -08002407}
2408
zhihuang1c378ed2017-08-17 14:10:50 -07002409void PeerConnection::GenerateMediaDescriptionOptions(
2410 const SessionDescriptionInterface* session_desc,
2411 cricket::RtpTransceiverDirection audio_direction,
2412 cricket::RtpTransceiverDirection video_direction,
2413 rtc::Optional<size_t>* audio_index,
2414 rtc::Optional<size_t>* video_index,
2415 rtc::Optional<size_t>* data_index,
htaa2a49d92016-03-04 02:51:39 -08002416 cricket::MediaSessionOptions* session_options) {
zhihuang1c378ed2017-08-17 14:10:50 -07002417 for (const cricket::ContentInfo& content :
2418 session_desc->description()->contents()) {
2419 if (IsAudioContent(&content)) {
2420 // If we already have an audio m= section, reject this extra one.
2421 if (*audio_index) {
2422 session_options->media_description_options.push_back(
2423 cricket::MediaDescriptionOptions(
2424 cricket::MEDIA_TYPE_AUDIO, content.name,
2425 cricket::RtpTransceiverDirection(false, false), true));
2426 } else {
2427 session_options->media_description_options.push_back(
2428 cricket::MediaDescriptionOptions(
2429 cricket::MEDIA_TYPE_AUDIO, content.name, audio_direction,
2430 !audio_direction.send && !audio_direction.recv));
2431 *audio_index = rtc::Optional<size_t>(
2432 session_options->media_description_options.size() - 1);
2433 }
2434 } else if (IsVideoContent(&content)) {
2435 // If we already have an video m= section, reject this extra one.
2436 if (*video_index) {
2437 session_options->media_description_options.push_back(
2438 cricket::MediaDescriptionOptions(
2439 cricket::MEDIA_TYPE_VIDEO, content.name,
2440 cricket::RtpTransceiverDirection(false, false), true));
2441 } else {
2442 session_options->media_description_options.push_back(
2443 cricket::MediaDescriptionOptions(
2444 cricket::MEDIA_TYPE_VIDEO, content.name, video_direction,
2445 !video_direction.send && !video_direction.recv));
2446 *video_index = rtc::Optional<size_t>(
2447 session_options->media_description_options.size() - 1);
2448 }
2449 } else {
2450 RTC_DCHECK(IsDataContent(&content));
2451 // If we already have an data m= section, reject this extra one.
2452 if (*data_index) {
2453 session_options->media_description_options.push_back(
2454 cricket::MediaDescriptionOptions(
2455 cricket::MEDIA_TYPE_DATA, content.name,
2456 cricket::RtpTransceiverDirection(false, false), true));
2457 } else {
2458 session_options->media_description_options.push_back(
2459 cricket::MediaDescriptionOptions(
2460 cricket::MEDIA_TYPE_DATA, content.name,
2461 // Direction for data sections is meaningless, but legacy
2462 // endpoints might expect sendrecv.
2463 cricket::RtpTransceiverDirection(true, true), false));
2464 *data_index = rtc::Optional<size_t>(
2465 session_options->media_description_options.size() - 1);
2466 }
2467 }
htaa2a49d92016-03-04 02:51:39 -08002468 }
deadbeefab9b2d12015-10-14 11:33:11 -07002469}
2470
deadbeeffaac4972015-11-12 15:33:07 -08002471void PeerConnection::RemoveTracks(cricket::MediaType media_type) {
2472 UpdateLocalTracks(std::vector<cricket::StreamParams>(), media_type);
deadbeefbda7e0b2015-12-08 17:13:40 -08002473 UpdateRemoteStreamsList(std::vector<cricket::StreamParams>(), false,
2474 media_type, nullptr);
deadbeeffaac4972015-11-12 15:33:07 -08002475}
2476
deadbeefab9b2d12015-10-14 11:33:11 -07002477void PeerConnection::UpdateRemoteStreamsList(
2478 const cricket::StreamParamsVec& streams,
deadbeefbda7e0b2015-12-08 17:13:40 -08002479 bool default_track_needed,
deadbeefab9b2d12015-10-14 11:33:11 -07002480 cricket::MediaType media_type,
2481 StreamCollection* new_streams) {
2482 TrackInfos* current_tracks = GetRemoteTracks(media_type);
2483
2484 // Find removed tracks. I.e., tracks where the track id or ssrc don't match
deadbeeffac06552015-11-25 11:26:01 -08002485 // the new StreamParam.
deadbeefab9b2d12015-10-14 11:33:11 -07002486 auto track_it = current_tracks->begin();
2487 while (track_it != current_tracks->end()) {
2488 const TrackInfo& info = *track_it;
2489 const cricket::StreamParams* params =
2490 cricket::GetStreamBySsrc(streams, info.ssrc);
deadbeefbda7e0b2015-12-08 17:13:40 -08002491 bool track_exists = params && params->id == info.track_id;
2492 // If this is a default track, and we still need it, don't remove it.
2493 if ((info.stream_label == kDefaultStreamLabel && default_track_needed) ||
2494 track_exists) {
2495 ++track_it;
2496 } else {
deadbeefab9b2d12015-10-14 11:33:11 -07002497 OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
2498 track_it = current_tracks->erase(track_it);
deadbeefab9b2d12015-10-14 11:33:11 -07002499 }
2500 }
2501
2502 // Find new and active tracks.
2503 for (const cricket::StreamParams& params : streams) {
2504 // The sync_label is the MediaStream label and the |stream.id| is the
2505 // track id.
2506 const std::string& stream_label = params.sync_label;
2507 const std::string& track_id = params.id;
2508 uint32_t ssrc = params.first_ssrc();
2509
2510 rtc::scoped_refptr<MediaStreamInterface> stream =
2511 remote_streams_->find(stream_label);
2512 if (!stream) {
2513 // This is a new MediaStream. Create a new remote MediaStream.
perkjd61bf802016-03-24 03:16:19 -07002514 stream = MediaStreamProxy::Create(rtc::Thread::Current(),
2515 MediaStream::Create(stream_label));
deadbeefab9b2d12015-10-14 11:33:11 -07002516 remote_streams_->AddStream(stream);
2517 new_streams->AddStream(stream);
2518 }
2519
2520 const TrackInfo* track_info =
2521 FindTrackInfo(*current_tracks, stream_label, track_id);
2522 if (!track_info) {
2523 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
2524 OnRemoteTrackSeen(stream_label, track_id, ssrc, media_type);
2525 }
2526 }
deadbeefbda7e0b2015-12-08 17:13:40 -08002527
2528 // Add default track if necessary.
2529 if (default_track_needed) {
2530 rtc::scoped_refptr<MediaStreamInterface> default_stream =
2531 remote_streams_->find(kDefaultStreamLabel);
2532 if (!default_stream) {
2533 // Create the new default MediaStream.
perkjd61bf802016-03-24 03:16:19 -07002534 default_stream = MediaStreamProxy::Create(
2535 rtc::Thread::Current(), MediaStream::Create(kDefaultStreamLabel));
deadbeefbda7e0b2015-12-08 17:13:40 -08002536 remote_streams_->AddStream(default_stream);
2537 new_streams->AddStream(default_stream);
2538 }
2539 std::string default_track_id = (media_type == cricket::MEDIA_TYPE_AUDIO)
2540 ? kDefaultAudioTrackLabel
2541 : kDefaultVideoTrackLabel;
2542 const TrackInfo* default_track_info =
2543 FindTrackInfo(*current_tracks, kDefaultStreamLabel, default_track_id);
2544 if (!default_track_info) {
2545 current_tracks->push_back(
2546 TrackInfo(kDefaultStreamLabel, default_track_id, 0));
2547 OnRemoteTrackSeen(kDefaultStreamLabel, default_track_id, 0, media_type);
2548 }
2549 }
deadbeefab9b2d12015-10-14 11:33:11 -07002550}
2551
2552void PeerConnection::OnRemoteTrackSeen(const std::string& stream_label,
2553 const std::string& track_id,
2554 uint32_t ssrc,
2555 cricket::MediaType media_type) {
2556 MediaStreamInterface* stream = remote_streams_->find(stream_label);
2557
2558 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
perkjd61bf802016-03-24 03:16:19 -07002559 CreateAudioReceiver(stream, track_id, ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -07002560 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
perkjf0dcfe22016-03-10 18:32:00 +01002561 CreateVideoReceiver(stream, track_id, ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -07002562 } else {
nisseeb4ca4e2017-01-12 02:24:27 -08002563 RTC_NOTREACHED() << "Invalid media type";
deadbeefab9b2d12015-10-14 11:33:11 -07002564 }
2565}
2566
2567void PeerConnection::OnRemoteTrackRemoved(const std::string& stream_label,
2568 const std::string& track_id,
2569 cricket::MediaType media_type) {
2570 MediaStreamInterface* stream = remote_streams_->find(stream_label);
2571
Henrik Boström933d8b02017-10-10 10:05:16 -07002572 rtc::scoped_refptr<RtpReceiverInterface> receiver;
deadbeefab9b2d12015-10-14 11:33:11 -07002573 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
perkjd61bf802016-03-24 03:16:19 -07002574 // When the MediaEngine audio channel is destroyed, the RemoteAudioSource
2575 // will be notified which will end the AudioRtpReceiver::track().
Henrik Boström933d8b02017-10-10 10:05:16 -07002576 receiver = RemoveAndStopReceiver(track_id);
deadbeefab9b2d12015-10-14 11:33:11 -07002577 rtc::scoped_refptr<AudioTrackInterface> audio_track =
2578 stream->FindAudioTrack(track_id);
2579 if (audio_track) {
deadbeefab9b2d12015-10-14 11:33:11 -07002580 stream->RemoveTrack(audio_track);
deadbeefab9b2d12015-10-14 11:33:11 -07002581 }
2582 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
perkjd61bf802016-03-24 03:16:19 -07002583 // Stopping or destroying a VideoRtpReceiver will end the
2584 // VideoRtpReceiver::track().
Henrik Boström933d8b02017-10-10 10:05:16 -07002585 receiver = RemoveAndStopReceiver(track_id);
deadbeefab9b2d12015-10-14 11:33:11 -07002586 rtc::scoped_refptr<VideoTrackInterface> video_track =
2587 stream->FindVideoTrack(track_id);
2588 if (video_track) {
perkjd61bf802016-03-24 03:16:19 -07002589 // There's no guarantee the track is still available, e.g. the track may
2590 // have been removed from the stream by an application.
deadbeefab9b2d12015-10-14 11:33:11 -07002591 stream->RemoveTrack(video_track);
deadbeefab9b2d12015-10-14 11:33:11 -07002592 }
2593 } else {
nisseede5da42017-01-12 05:15:36 -08002594 RTC_NOTREACHED() << "Invalid media type";
deadbeefab9b2d12015-10-14 11:33:11 -07002595 }
Henrik Boström933d8b02017-10-10 10:05:16 -07002596 if (receiver) {
2597 observer_->OnRemoveTrack(receiver);
2598 }
deadbeefab9b2d12015-10-14 11:33:11 -07002599}
2600
2601void PeerConnection::UpdateEndedRemoteMediaStreams() {
2602 std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams_to_remove;
2603 for (size_t i = 0; i < remote_streams_->count(); ++i) {
2604 MediaStreamInterface* stream = remote_streams_->at(i);
2605 if (stream->GetAudioTracks().empty() && stream->GetVideoTracks().empty()) {
2606 streams_to_remove.push_back(stream);
2607 }
2608 }
2609
Taylor Brandstetter98cde262016-05-31 13:02:21 -07002610 for (auto& stream : streams_to_remove) {
deadbeefab9b2d12015-10-14 11:33:11 -07002611 remote_streams_->RemoveStream(stream);
Taylor Brandstetter98cde262016-05-31 13:02:21 -07002612 observer_->OnRemoveStream(std::move(stream));
deadbeefab9b2d12015-10-14 11:33:11 -07002613 }
2614}
2615
deadbeefab9b2d12015-10-14 11:33:11 -07002616void PeerConnection::UpdateLocalTracks(
2617 const std::vector<cricket::StreamParams>& streams,
2618 cricket::MediaType media_type) {
2619 TrackInfos* current_tracks = GetLocalTracks(media_type);
2620
2621 // Find removed tracks. I.e., tracks where the track id, stream label or ssrc
2622 // don't match the new StreamParam.
2623 TrackInfos::iterator track_it = current_tracks->begin();
2624 while (track_it != current_tracks->end()) {
2625 const TrackInfo& info = *track_it;
2626 const cricket::StreamParams* params =
2627 cricket::GetStreamBySsrc(streams, info.ssrc);
2628 if (!params || params->id != info.track_id ||
2629 params->sync_label != info.stream_label) {
2630 OnLocalTrackRemoved(info.stream_label, info.track_id, info.ssrc,
2631 media_type);
2632 track_it = current_tracks->erase(track_it);
2633 } else {
2634 ++track_it;
2635 }
2636 }
2637
2638 // Find new and active tracks.
2639 for (const cricket::StreamParams& params : streams) {
2640 // The sync_label is the MediaStream label and the |stream.id| is the
2641 // track id.
2642 const std::string& stream_label = params.sync_label;
2643 const std::string& track_id = params.id;
2644 uint32_t ssrc = params.first_ssrc();
2645 const TrackInfo* track_info =
2646 FindTrackInfo(*current_tracks, stream_label, track_id);
2647 if (!track_info) {
2648 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
2649 OnLocalTrackSeen(stream_label, track_id, params.first_ssrc(), media_type);
2650 }
2651 }
2652}
2653
2654void PeerConnection::OnLocalTrackSeen(const std::string& stream_label,
2655 const std::string& track_id,
2656 uint32_t ssrc,
2657 cricket::MediaType media_type) {
deadbeefa601f5c2016-06-06 14:27:39 -07002658 RtpSenderInternal* sender = FindSenderById(track_id);
deadbeeffac06552015-11-25 11:26:01 -08002659 if (!sender) {
2660 LOG(LS_WARNING) << "An unknown RtpSender with id " << track_id
2661 << " has been configured in the local description.";
deadbeefab9b2d12015-10-14 11:33:11 -07002662 return;
2663 }
2664
deadbeeffac06552015-11-25 11:26:01 -08002665 if (sender->media_type() != media_type) {
2666 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
2667 << " description with an unexpected media type.";
2668 return;
deadbeefab9b2d12015-10-14 11:33:11 -07002669 }
deadbeeffac06552015-11-25 11:26:01 -08002670
2671 sender->set_stream_id(stream_label);
2672 sender->SetSsrc(ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -07002673}
2674
2675void PeerConnection::OnLocalTrackRemoved(const std::string& stream_label,
2676 const std::string& track_id,
2677 uint32_t ssrc,
2678 cricket::MediaType media_type) {
deadbeefa601f5c2016-06-06 14:27:39 -07002679 RtpSenderInternal* sender = FindSenderById(track_id);
deadbeeffac06552015-11-25 11:26:01 -08002680 if (!sender) {
2681 // This is the normal case. I.e., RemoveStream has been called and the
deadbeefab9b2d12015-10-14 11:33:11 -07002682 // SessionDescriptions has been renegotiated.
2683 return;
2684 }
deadbeeffac06552015-11-25 11:26:01 -08002685
2686 // A sender has been removed from the SessionDescription but it's still
2687 // associated with the PeerConnection. This only occurs if the SDP doesn't
2688 // match with the calls to CreateSender, AddStream and RemoveStream.
2689 if (sender->media_type() != media_type) {
2690 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
2691 << " description with an unexpected media type.";
2692 return;
deadbeefab9b2d12015-10-14 11:33:11 -07002693 }
deadbeeffac06552015-11-25 11:26:01 -08002694
2695 sender->SetSsrc(0);
deadbeefab9b2d12015-10-14 11:33:11 -07002696}
2697
2698void PeerConnection::UpdateLocalRtpDataChannels(
2699 const cricket::StreamParamsVec& streams) {
2700 std::vector<std::string> existing_channels;
2701
2702 // Find new and active data channels.
2703 for (const cricket::StreamParams& params : streams) {
2704 // |it->sync_label| is actually the data channel label. The reason is that
2705 // we use the same naming of data channels as we do for
2706 // MediaStreams and Tracks.
2707 // For MediaStreams, the sync_label is the MediaStream label and the
2708 // track label is the same as |streamid|.
2709 const std::string& channel_label = params.sync_label;
2710 auto data_channel_it = rtp_data_channels_.find(channel_label);
nisse7ce109a2017-01-31 00:57:56 -08002711 if (data_channel_it == rtp_data_channels_.end()) {
2712 LOG(LS_ERROR) << "channel label not found";
deadbeefab9b2d12015-10-14 11:33:11 -07002713 continue;
2714 }
2715 // Set the SSRC the data channel should use for sending.
2716 data_channel_it->second->SetSendSsrc(params.first_ssrc());
2717 existing_channels.push_back(data_channel_it->first);
2718 }
2719
2720 UpdateClosingRtpDataChannels(existing_channels, true);
2721}
2722
2723void PeerConnection::UpdateRemoteRtpDataChannels(
2724 const cricket::StreamParamsVec& streams) {
2725 std::vector<std::string> existing_channels;
2726
2727 // Find new and active data channels.
2728 for (const cricket::StreamParams& params : streams) {
2729 // The data channel label is either the mslabel or the SSRC if the mslabel
2730 // does not exist. Ex a=ssrc:444330170 mslabel:test1.
2731 std::string label = params.sync_label.empty()
2732 ? rtc::ToString(params.first_ssrc())
2733 : params.sync_label;
2734 auto data_channel_it = rtp_data_channels_.find(label);
2735 if (data_channel_it == rtp_data_channels_.end()) {
2736 // This is a new data channel.
2737 CreateRemoteRtpDataChannel(label, params.first_ssrc());
2738 } else {
2739 data_channel_it->second->SetReceiveSsrc(params.first_ssrc());
2740 }
2741 existing_channels.push_back(label);
2742 }
2743
2744 UpdateClosingRtpDataChannels(existing_channels, false);
2745}
2746
2747void PeerConnection::UpdateClosingRtpDataChannels(
2748 const std::vector<std::string>& active_channels,
2749 bool is_local_update) {
2750 auto it = rtp_data_channels_.begin();
2751 while (it != rtp_data_channels_.end()) {
2752 DataChannel* data_channel = it->second;
2753 if (std::find(active_channels.begin(), active_channels.end(),
2754 data_channel->label()) != active_channels.end()) {
2755 ++it;
2756 continue;
2757 }
2758
2759 if (is_local_update) {
2760 data_channel->SetSendSsrc(0);
2761 } else {
2762 data_channel->RemotePeerRequestClose();
2763 }
2764
2765 if (data_channel->state() == DataChannel::kClosed) {
2766 rtp_data_channels_.erase(it);
2767 it = rtp_data_channels_.begin();
2768 } else {
2769 ++it;
2770 }
2771 }
2772}
2773
2774void PeerConnection::CreateRemoteRtpDataChannel(const std::string& label,
2775 uint32_t remote_ssrc) {
2776 rtc::scoped_refptr<DataChannel> channel(
2777 InternalCreateDataChannel(label, nullptr));
2778 if (!channel.get()) {
2779 LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
2780 << "CreateDataChannel failed.";
2781 return;
2782 }
2783 channel->SetReceiveSsrc(remote_ssrc);
deadbeefa601f5c2016-06-06 14:27:39 -07002784 rtc::scoped_refptr<DataChannelInterface> proxy_channel =
2785 DataChannelProxy::Create(signaling_thread(), channel);
Taylor Brandstetter98cde262016-05-31 13:02:21 -07002786 observer_->OnDataChannel(std::move(proxy_channel));
deadbeefab9b2d12015-10-14 11:33:11 -07002787}
2788
2789rtc::scoped_refptr<DataChannel> PeerConnection::InternalCreateDataChannel(
2790 const std::string& label,
2791 const InternalDataChannelInit* config) {
2792 if (IsClosed()) {
2793 return nullptr;
2794 }
Steve Anton75737c02017-11-06 10:37:17 -08002795 if (data_channel_type() == cricket::DCT_NONE) {
deadbeefab9b2d12015-10-14 11:33:11 -07002796 LOG(LS_ERROR)
2797 << "InternalCreateDataChannel: Data is not supported in this call.";
2798 return nullptr;
2799 }
2800 InternalDataChannelInit new_config =
2801 config ? (*config) : InternalDataChannelInit();
Steve Anton75737c02017-11-06 10:37:17 -08002802 if (data_channel_type() == cricket::DCT_SCTP) {
deadbeefab9b2d12015-10-14 11:33:11 -07002803 if (new_config.id < 0) {
2804 rtc::SSLRole role;
Steve Anton75737c02017-11-06 10:37:17 -08002805 if ((GetSctpSslRole(&role)) &&
deadbeefab9b2d12015-10-14 11:33:11 -07002806 !sid_allocator_.AllocateSid(role, &new_config.id)) {
2807 LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel.";
2808 return nullptr;
2809 }
2810 } else if (!sid_allocator_.ReserveSid(new_config.id)) {
2811 LOG(LS_ERROR) << "Failed to create a SCTP data channel "
2812 << "because the id is already in use or out of range.";
2813 return nullptr;
2814 }
2815 }
2816
Steve Anton75737c02017-11-06 10:37:17 -08002817 rtc::scoped_refptr<DataChannel> channel(
2818 DataChannel::Create(this, data_channel_type(), label, new_config));
deadbeefab9b2d12015-10-14 11:33:11 -07002819 if (!channel) {
2820 sid_allocator_.ReleaseSid(new_config.id);
2821 return nullptr;
2822 }
2823
2824 if (channel->data_channel_type() == cricket::DCT_RTP) {
2825 if (rtp_data_channels_.find(channel->label()) != rtp_data_channels_.end()) {
2826 LOG(LS_ERROR) << "DataChannel with label " << channel->label()
2827 << " already exists.";
2828 return nullptr;
2829 }
2830 rtp_data_channels_[channel->label()] = channel;
2831 } else {
2832 RTC_DCHECK(channel->data_channel_type() == cricket::DCT_SCTP);
2833 sctp_data_channels_.push_back(channel);
2834 channel->SignalClosed.connect(this,
2835 &PeerConnection::OnSctpDataChannelClosed);
2836 }
2837
hbos82ebe022016-11-14 01:41:09 -08002838 SignalDataChannelCreated(channel.get());
deadbeefab9b2d12015-10-14 11:33:11 -07002839 return channel;
2840}
2841
2842bool PeerConnection::HasDataChannels() const {
2843 return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
2844}
2845
2846void PeerConnection::AllocateSctpSids(rtc::SSLRole role) {
2847 for (const auto& channel : sctp_data_channels_) {
2848 if (channel->id() < 0) {
2849 int sid;
2850 if (!sid_allocator_.AllocateSid(role, &sid)) {
2851 LOG(LS_ERROR) << "Failed to allocate SCTP sid.";
2852 continue;
2853 }
2854 channel->SetSctpSid(sid);
2855 }
2856 }
2857}
2858
2859void PeerConnection::OnSctpDataChannelClosed(DataChannel* channel) {
deadbeefbd292462015-12-14 18:15:29 -08002860 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefab9b2d12015-10-14 11:33:11 -07002861 for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end();
2862 ++it) {
2863 if (it->get() == channel) {
2864 if (channel->id() >= 0) {
2865 sid_allocator_.ReleaseSid(channel->id());
2866 }
deadbeefbd292462015-12-14 18:15:29 -08002867 // Since this method is triggered by a signal from the DataChannel,
2868 // we can't free it directly here; we need to free it asynchronously.
2869 sctp_data_channels_to_free_.push_back(*it);
deadbeefab9b2d12015-10-14 11:33:11 -07002870 sctp_data_channels_.erase(it);
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -07002871 signaling_thread()->Post(RTC_FROM_HERE, this, MSG_FREE_DATACHANNELS,
2872 nullptr);
deadbeefab9b2d12015-10-14 11:33:11 -07002873 return;
2874 }
2875 }
2876}
2877
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -07002878void PeerConnection::OnVoiceChannelCreated() {
2879 SetChannelOnSendersAndReceivers<AudioRtpSender, AudioRtpReceiver>(
Steve Anton75737c02017-11-06 10:37:17 -08002880 voice_channel(), senders_, receivers_, cricket::MEDIA_TYPE_AUDIO);
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -07002881}
2882
deadbeefab9b2d12015-10-14 11:33:11 -07002883void PeerConnection::OnVoiceChannelDestroyed() {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -07002884 SetChannelOnSendersAndReceivers<AudioRtpSender, AudioRtpReceiver,
2885 cricket::VoiceChannel>(
2886 nullptr, senders_, receivers_, cricket::MEDIA_TYPE_AUDIO);
2887}
2888
2889void PeerConnection::OnVideoChannelCreated() {
2890 SetChannelOnSendersAndReceivers<VideoRtpSender, VideoRtpReceiver>(
Steve Anton75737c02017-11-06 10:37:17 -08002891 video_channel(), senders_, receivers_, cricket::MEDIA_TYPE_VIDEO);
deadbeefab9b2d12015-10-14 11:33:11 -07002892}
2893
2894void PeerConnection::OnVideoChannelDestroyed() {
Taylor Brandstetterba29c6a2016-06-27 16:30:35 -07002895 SetChannelOnSendersAndReceivers<VideoRtpSender, VideoRtpReceiver,
2896 cricket::VideoChannel>(
2897 nullptr, senders_, receivers_, cricket::MEDIA_TYPE_VIDEO);
deadbeefab9b2d12015-10-14 11:33:11 -07002898}
2899
2900void PeerConnection::OnDataChannelCreated() {
2901 for (const auto& channel : sctp_data_channels_) {
2902 channel->OnTransportChannelCreated();
2903 }
2904}
2905
2906void PeerConnection::OnDataChannelDestroyed() {
2907 // Use a temporary copy of the RTP/SCTP DataChannel list because the
2908 // DataChannel may callback to us and try to modify the list.
2909 std::map<std::string, rtc::scoped_refptr<DataChannel>> temp_rtp_dcs;
2910 temp_rtp_dcs.swap(rtp_data_channels_);
2911 for (const auto& kv : temp_rtp_dcs) {
2912 kv.second->OnTransportChannelDestroyed();
2913 }
2914
2915 std::vector<rtc::scoped_refptr<DataChannel>> temp_sctp_dcs;
2916 temp_sctp_dcs.swap(sctp_data_channels_);
2917 for (const auto& channel : temp_sctp_dcs) {
2918 channel->OnTransportChannelDestroyed();
2919 }
2920}
2921
2922void PeerConnection::OnDataChannelOpenMessage(
2923 const std::string& label,
2924 const InternalDataChannelInit& config) {
2925 rtc::scoped_refptr<DataChannel> channel(
2926 InternalCreateDataChannel(label, &config));
2927 if (!channel.get()) {
2928 LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
2929 return;
2930 }
2931
deadbeefa601f5c2016-06-06 14:27:39 -07002932 rtc::scoped_refptr<DataChannelInterface> proxy_channel =
2933 DataChannelProxy::Create(signaling_thread(), channel);
Taylor Brandstetter98cde262016-05-31 13:02:21 -07002934 observer_->OnDataChannel(std::move(proxy_channel));
deadbeefab9b2d12015-10-14 11:33:11 -07002935}
2936
zhihuang1c378ed2017-08-17 14:10:50 -07002937bool PeerConnection::HasRtpSender(cricket::MediaType type) const {
2938 return std::find_if(
2939 senders_.begin(), senders_.end(),
2940 [type](const rtc::scoped_refptr<
2941 RtpSenderProxyWithInternal<RtpSenderInternal>>& sender) {
2942 return sender->media_type() == type;
2943 }) != senders_.end();
2944}
2945
deadbeefa601f5c2016-06-06 14:27:39 -07002946RtpSenderInternal* PeerConnection::FindSenderById(const std::string& id) {
2947 auto it = std::find_if(
2948 senders_.begin(), senders_.end(),
2949 [id](const rtc::scoped_refptr<
2950 RtpSenderProxyWithInternal<RtpSenderInternal>>& sender) {
2951 return sender->id() == id;
2952 });
2953 return it != senders_.end() ? (*it)->internal() : nullptr;
deadbeeffac06552015-11-25 11:26:01 -08002954}
2955
deadbeefa601f5c2016-06-06 14:27:39 -07002956std::vector<
2957 rtc::scoped_refptr<RtpSenderProxyWithInternal<RtpSenderInternal>>>::iterator
deadbeef70ab1a12015-09-28 16:53:55 -07002958PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) {
2959 return std::find_if(
2960 senders_.begin(), senders_.end(),
deadbeefa601f5c2016-06-06 14:27:39 -07002961 [track](const rtc::scoped_refptr<
2962 RtpSenderProxyWithInternal<RtpSenderInternal>>& sender) {
deadbeef70ab1a12015-09-28 16:53:55 -07002963 return sender->track() == track;
2964 });
2965}
2966
deadbeefa601f5c2016-06-06 14:27:39 -07002967std::vector<rtc::scoped_refptr<
2968 RtpReceiverProxyWithInternal<RtpReceiverInternal>>>::iterator
perkjd61bf802016-03-24 03:16:19 -07002969PeerConnection::FindReceiverForTrack(const std::string& track_id) {
deadbeef70ab1a12015-09-28 16:53:55 -07002970 return std::find_if(
2971 receivers_.begin(), receivers_.end(),
deadbeefa601f5c2016-06-06 14:27:39 -07002972 [track_id](const rtc::scoped_refptr<
2973 RtpReceiverProxyWithInternal<RtpReceiverInternal>>& receiver) {
perkjd61bf802016-03-24 03:16:19 -07002974 return receiver->id() == track_id;
deadbeef70ab1a12015-09-28 16:53:55 -07002975 });
2976}
2977
deadbeefab9b2d12015-10-14 11:33:11 -07002978PeerConnection::TrackInfos* PeerConnection::GetRemoteTracks(
2979 cricket::MediaType media_type) {
2980 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
2981 media_type == cricket::MEDIA_TYPE_VIDEO);
2982 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &remote_audio_tracks_
2983 : &remote_video_tracks_;
2984}
2985
2986PeerConnection::TrackInfos* PeerConnection::GetLocalTracks(
2987 cricket::MediaType media_type) {
2988 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
2989 media_type == cricket::MEDIA_TYPE_VIDEO);
2990 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &local_audio_tracks_
2991 : &local_video_tracks_;
2992}
2993
2994const PeerConnection::TrackInfo* PeerConnection::FindTrackInfo(
2995 const PeerConnection::TrackInfos& infos,
2996 const std::string& stream_label,
2997 const std::string track_id) const {
2998 for (const TrackInfo& track_info : infos) {
2999 if (track_info.stream_label == stream_label &&
3000 track_info.track_id == track_id) {
3001 return &track_info;
3002 }
3003 }
3004 return nullptr;
3005}
3006
3007DataChannel* PeerConnection::FindDataChannelBySid(int sid) const {
3008 for (const auto& channel : sctp_data_channels_) {
3009 if (channel->id() == sid) {
3010 return channel;
3011 }
3012 }
3013 return nullptr;
3014}
3015
deadbeef91dd5672016-05-18 16:55:30 -07003016bool PeerConnection::InitializePortAllocator_n(
Taylor Brandstettera1c30352016-05-13 08:15:11 -07003017 const RTCConfiguration& configuration) {
3018 cricket::ServerAddresses stun_servers;
3019 std::vector<cricket::RelayServerConfig> turn_servers;
deadbeef293e9262017-01-11 12:28:30 -08003020 if (ParseIceServers(configuration.servers, &stun_servers, &turn_servers) !=
3021 RTCErrorType::NONE) {
Taylor Brandstettera1c30352016-05-13 08:15:11 -07003022 return false;
3023 }
3024
Taylor Brandstetterf8e65772016-06-27 17:20:15 -07003025 port_allocator_->Initialize();
3026
Taylor Brandstettera1c30352016-05-13 08:15:11 -07003027 // To handle both internal and externally created port allocator, we will
3028 // enable BUNDLE here.
3029 int portallocator_flags = port_allocator_->flags();
3030 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
zhihuangb09b3f92017-03-07 14:40:51 -08003031 cricket::PORTALLOCATOR_ENABLE_IPV6 |
3032 cricket::PORTALLOCATOR_ENABLE_IPV6_ON_WIFI;
Taylor Brandstettera1c30352016-05-13 08:15:11 -07003033 // If the disable-IPv6 flag was specified, we'll not override it
3034 // by experiment.
3035 if (configuration.disable_ipv6) {
3036 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
sprangc1b57a12017-02-28 08:50:47 -08003037 } else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default")
3038 .find("Disabled") == 0) {
Taylor Brandstettera1c30352016-05-13 08:15:11 -07003039 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
3040 }
3041
zhihuangb09b3f92017-03-07 14:40:51 -08003042 if (configuration.disable_ipv6_on_wifi) {
3043 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6_ON_WIFI);
3044 LOG(LS_INFO) << "IPv6 candidates on Wi-Fi are disabled.";
3045 }
3046
Taylor Brandstettera1c30352016-05-13 08:15:11 -07003047 if (configuration.tcp_candidate_policy == kTcpCandidatePolicyDisabled) {
3048 portallocator_flags |= cricket::PORTALLOCATOR_DISABLE_TCP;
3049 LOG(LS_INFO) << "TCP candidates are disabled.";
3050 }
3051
honghaiz60347052016-05-31 18:29:12 -07003052 if (configuration.candidate_network_policy ==
3053 kCandidateNetworkPolicyLowCost) {
3054 portallocator_flags |= cricket::PORTALLOCATOR_DISABLE_COSTLY_NETWORKS;
3055 LOG(LS_INFO) << "Do not gather candidates on high-cost networks";
3056 }
3057
Taylor Brandstettera1c30352016-05-13 08:15:11 -07003058 port_allocator_->set_flags(portallocator_flags);
3059 // No step delay is used while allocating ports.
3060 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
3061 port_allocator_->set_candidate_filter(
3062 ConvertIceTransportTypeToCandidateFilter(configuration.type));
deadbeefd21eab32017-07-26 16:50:11 -07003063 port_allocator_->set_max_ipv6_networks(configuration.max_ipv6_networks);
Taylor Brandstettera1c30352016-05-13 08:15:11 -07003064
3065 // Call this last since it may create pooled allocator sessions using the
3066 // properties set above.
3067 port_allocator_->SetConfiguration(stun_servers, turn_servers,
Honghai Zhangb9e7b4a2016-06-30 20:52:02 -07003068 configuration.ice_candidate_pool_size,
Jonas Orelandbdcee282017-10-10 14:01:40 +02003069 configuration.prune_turn_ports,
3070 configuration.turn_customizer);
Taylor Brandstettera1c30352016-05-13 08:15:11 -07003071 return true;
3072}
3073
deadbeef91dd5672016-05-18 16:55:30 -07003074bool PeerConnection::ReconfigurePortAllocator_n(
deadbeef293e9262017-01-11 12:28:30 -08003075 const cricket::ServerAddresses& stun_servers,
3076 const std::vector<cricket::RelayServerConfig>& turn_servers,
3077 IceTransportsType type,
3078 int candidate_pool_size,
Jonas Orelandbdcee282017-10-10 14:01:40 +02003079 bool prune_turn_ports,
3080 webrtc::TurnCustomizer* turn_customizer) {
Taylor Brandstettera1c30352016-05-13 08:15:11 -07003081 port_allocator_->set_candidate_filter(
deadbeef293e9262017-01-11 12:28:30 -08003082 ConvertIceTransportTypeToCandidateFilter(type));
Taylor Brandstettera1c30352016-05-13 08:15:11 -07003083 // Call this last since it may create pooled allocator sessions using the
3084 // candidate filter set above.
deadbeef6de92f92016-12-12 18:49:32 -08003085 return port_allocator_->SetConfiguration(
Jonas Orelandbdcee282017-10-10 14:01:40 +02003086 stun_servers, turn_servers, candidate_pool_size, prune_turn_ports,
3087 turn_customizer);
Taylor Brandstettera1c30352016-05-13 08:15:11 -07003088}
3089
Steve Antonba818672017-11-06 10:21:57 -08003090cricket::ChannelManager* PeerConnection::channel_manager() const {
3091 return factory_->channel_manager();
3092}
3093
3094MetricsObserverInterface* PeerConnection::metrics_observer() const {
3095 return uma_observer_;
3096}
3097
Elad Alon99c3fe52017-10-13 16:29:40 +02003098bool PeerConnection::StartRtcEventLog_w(
3099 std::unique_ptr<RtcEventLogOutput> output) {
zhihuang77985012017-02-07 15:45:16 -08003100 if (!event_log_) {
3101 return false;
3102 }
Elad Alon99c3fe52017-10-13 16:29:40 +02003103 return event_log_->StartLogging(std::move(output));
ivoc14d5dbe2016-07-04 07:06:55 -07003104}
3105
3106void PeerConnection::StopRtcEventLog_w() {
zhihuang77985012017-02-07 15:45:16 -08003107 if (event_log_) {
3108 event_log_->StopLogging();
3109 }
ivoc14d5dbe2016-07-04 07:06:55 -07003110}
nisseeaabdf62017-05-05 02:23:02 -07003111
Steve Anton75737c02017-11-06 10:37:17 -08003112cricket::BaseChannel* PeerConnection::GetChannel(
3113 const std::string& content_name) {
3114 if (voice_channel() && voice_channel()->content_name() == content_name) {
3115 return voice_channel();
3116 }
3117 if (video_channel() && video_channel()->content_name() == content_name) {
3118 return video_channel();
3119 }
3120 if (rtp_data_channel() &&
3121 rtp_data_channel()->content_name() == content_name) {
3122 return rtp_data_channel();
3123 }
3124 return nullptr;
3125}
3126
3127bool PeerConnection::GetSctpSslRole(rtc::SSLRole* role) {
3128 if (!local_description() || !remote_description()) {
3129 LOG(LS_INFO) << "Local and Remote descriptions must be applied to get the "
3130 << "SSL Role of the SCTP transport.";
3131 return false;
3132 }
3133 if (!sctp_transport_) {
3134 LOG(LS_INFO) << "Non-rejected SCTP m= section is needed to get the "
3135 << "SSL Role of the SCTP transport.";
3136 return false;
3137 }
3138
3139 return transport_controller_->GetSslRole(*sctp_transport_name_, role);
3140}
3141
3142bool PeerConnection::GetSslRole(const std::string& content_name,
3143 rtc::SSLRole* role) {
3144 if (!local_description() || !remote_description()) {
3145 LOG(LS_INFO) << "Local and Remote descriptions must be applied to get the "
3146 << "SSL Role of the session.";
3147 return false;
3148 }
3149
3150 return transport_controller_->GetSslRole(GetTransportName(content_name),
3151 role);
3152}
3153
3154void PeerConnection::CreateOffer(
3155 CreateSessionDescriptionObserver* observer,
3156 const PeerConnectionInterface::RTCOfferAnswerOptions& options,
3157 const cricket::MediaSessionOptions& session_options) {
3158 webrtc_session_desc_factory_->CreateOffer(observer, options, session_options);
3159}
3160
3161void PeerConnection::CreateAnswer(
3162 CreateSessionDescriptionObserver* observer,
3163 const cricket::MediaSessionOptions& session_options) {
3164 webrtc_session_desc_factory_->CreateAnswer(observer, session_options);
3165}
3166
3167bool PeerConnection::SetLocalDescription(
3168 std::unique_ptr<SessionDescriptionInterface> desc,
3169 std::string* err_desc) {
3170 RTC_DCHECK(signaling_thread()->IsCurrent());
3171
3172 // Validate SDP.
3173 if (!ValidateSessionDescription(desc.get(), cricket::CS_LOCAL, err_desc)) {
3174 return false;
3175 }
3176
3177 // Update the initial_offerer flag if this session is the initial_offerer.
3178 Action action = GetAction(desc->type());
3179 if (!initial_offerer_.has_value()) {
3180 initial_offerer_.emplace(action == kOffer);
3181 if (*initial_offerer_) {
3182 transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLING);
3183 } else {
3184 transport_controller_->SetIceRole(cricket::ICEROLE_CONTROLLED);
3185 }
3186 }
3187
3188 if (action == kAnswer) {
3189 current_local_description_ = std::move(desc);
3190 pending_local_description_ = nullptr;
3191 current_remote_description_ = std::move(pending_remote_description_);
3192 } else {
3193 pending_local_description_ = std::move(desc);
3194 }
3195
3196 // Transport and Media channels will be created only when offer is set.
3197 if (action == kOffer && !CreateChannels(local_description()->description())) {
3198 // TODO(mallinath) - Handle CreateChannel failure, as new local description
3199 // is applied. Restore back to old description.
3200 return BadLocalSdp(local_description()->type(), kCreateChannelFailed,
3201 err_desc);
3202 }
3203
3204 // Remove unused channels if MediaContentDescription is rejected.
3205 RemoveUnusedChannels(local_description()->description());
3206
3207 if (!UpdateSessionState(action, cricket::CS_LOCAL, err_desc)) {
3208 return false;
3209 }
3210 if (remote_description()) {
3211 // Now that we have a local description, we can push down remote candidates.
3212 UseCandidatesInSessionDescription(remote_description());
3213 }
3214
3215 pending_ice_restarts_.clear();
3216 if (error() != ERROR_NONE) {
3217 return BadLocalSdp(local_description()->type(), GetSessionErrorMsg(),
3218 err_desc);
3219 }
3220 return true;
3221}
3222
3223bool PeerConnection::SetRemoteDescription(
3224 std::unique_ptr<SessionDescriptionInterface> desc,
3225 std::string* err_desc) {
3226 RTC_DCHECK(signaling_thread()->IsCurrent());
3227
3228 // Validate SDP.
3229 if (!ValidateSessionDescription(desc.get(), cricket::CS_REMOTE, err_desc)) {
3230 return false;
3231 }
3232
3233 // Hold this pointer so candidates can be copied to it later in the method.
3234 SessionDescriptionInterface* desc_ptr = desc.get();
3235
3236 const SessionDescriptionInterface* old_remote_description =
3237 remote_description();
3238 // Grab ownership of the description being replaced for the remainder of this
3239 // method, since it's used below as |old_remote_description|.
3240 std::unique_ptr<SessionDescriptionInterface> replaced_remote_description;
3241 Action action = GetAction(desc->type());
3242 if (action == kAnswer) {
3243 replaced_remote_description = pending_remote_description_
3244 ? std::move(pending_remote_description_)
3245 : std::move(current_remote_description_);
3246 current_remote_description_ = std::move(desc);
3247 pending_remote_description_ = nullptr;
3248 current_local_description_ = std::move(pending_local_description_);
3249 } else {
3250 replaced_remote_description = std::move(pending_remote_description_);
3251 pending_remote_description_ = std::move(desc);
3252 }
3253
3254 // Transport and Media channels will be created only when offer is set.
3255 if (action == kOffer &&
3256 !CreateChannels(remote_description()->description())) {
3257 // TODO(mallinath) - Handle CreateChannel failure, as new local description
3258 // is applied. Restore back to old description.
3259 return BadRemoteSdp(remote_description()->type(), kCreateChannelFailed,
3260 err_desc);
3261 }
3262
3263 // Remove unused channels if MediaContentDescription is rejected.
3264 RemoveUnusedChannels(remote_description()->description());
3265
3266 // NOTE: Candidates allocation will be initiated only when SetLocalDescription
3267 // is called.
3268 if (!UpdateSessionState(action, cricket::CS_REMOTE, err_desc)) {
3269 return false;
3270 }
3271
3272 if (local_description() &&
3273 !UseCandidatesInSessionDescription(remote_description())) {
3274 return BadRemoteSdp(remote_description()->type(), kInvalidCandidates,
3275 err_desc);
3276 }
3277
3278 if (old_remote_description) {
3279 for (const cricket::ContentInfo& content :
3280 old_remote_description->description()->contents()) {
3281 // Check if this new SessionDescription contains new ICE ufrag and
3282 // password that indicates the remote peer requests an ICE restart.
3283 // TODO(deadbeef): When we start storing both the current and pending
3284 // remote description, this should reset pending_ice_restarts and compare
3285 // against the current description.
3286 if (CheckForRemoteIceRestart(old_remote_description, remote_description(),
3287 content.name)) {
3288 if (action == kOffer) {
3289 pending_ice_restarts_.insert(content.name);
3290 }
3291 } else {
3292 // We retain all received candidates only if ICE is not restarted.
3293 // When ICE is restarted, all previous candidates belong to an old
3294 // generation and should not be kept.
3295 // TODO(deadbeef): This goes against the W3C spec which says the remote
3296 // description should only contain candidates from the last set remote
3297 // description plus any candidates added since then. We should remove
3298 // this once we're sure it won't break anything.
3299 WebRtcSessionDescriptionFactory::CopyCandidatesFromSessionDescription(
3300 old_remote_description, content.name, desc_ptr);
3301 }
3302 }
3303 }
3304
3305 if (error() != ERROR_NONE) {
3306 return BadRemoteSdp(remote_description()->type(), GetSessionErrorMsg(),
3307 err_desc);
3308 }
3309
3310 // Set the the ICE connection state to connecting since the connection may
3311 // become writable with peer reflexive candidates before any remote candidate
3312 // is signaled.
3313 // TODO(pthatcher): This is a short-term solution for crbug/446908. A real fix
3314 // is to have a new signal the indicates a change in checking state from the
3315 // transport and expose a new checking() member from transport that can be
3316 // read to determine the current checking state. The existing SignalConnecting
3317 // actually means "gathering candidates", so cannot be be used here.
3318 if (remote_description()->type() != SessionDescriptionInterface::kOffer &&
3319 ice_connection_state() == PeerConnectionInterface::kIceConnectionNew) {
3320 SetIceConnectionState(PeerConnectionInterface::kIceConnectionChecking);
3321 }
3322 return true;
3323}
3324
3325// TODO(steveanton): Eventually it'd be nice to store the channels as a single
3326// vector of BaseChannel pointers instead of separate voice and video channel
3327// vectors. At that point, this will become a simple getter.
3328std::vector<cricket::BaseChannel*> PeerConnection::Channels() const {
3329 std::vector<cricket::BaseChannel*> channels;
3330 channels.insert(channels.end(), voice_channels_.begin(),
3331 voice_channels_.end());
3332 channels.insert(channels.end(), video_channels_.begin(),
3333 video_channels_.end());
3334 if (rtp_data_channel_) {
3335 channels.push_back(rtp_data_channel_);
3336 }
3337 return channels;
3338}
3339
3340void PeerConnection::SetError(Error error, const std::string& error_desc) {
3341 RTC_DCHECK(signaling_thread()->IsCurrent());
3342 if (error != error_) {
3343 error_ = error;
3344 error_desc_ = error_desc;
3345 }
3346}
3347
3348bool PeerConnection::UpdateSessionState(Action action,
3349 cricket::ContentSource source,
3350 std::string* err_desc) {
3351 RTC_DCHECK(signaling_thread()->IsCurrent());
3352
3353 // If there's already a pending error then no state transition should happen.
3354 // But all call-sites should be verifying this before calling us!
3355 RTC_DCHECK(error() == ERROR_NONE);
3356 std::string td_err;
3357 if (action == kOffer) {
3358 if (!PushdownTransportDescription(source, cricket::CA_OFFER, &td_err)) {
3359 return BadOfferSdp(source, MakeTdErrorString(td_err), err_desc);
3360 }
3361 ChangeSignalingState(source == cricket::CS_LOCAL
3362 ? PeerConnectionInterface::kHaveLocalOffer
3363 : PeerConnectionInterface::kHaveRemoteOffer);
3364 if (!PushdownMediaDescription(cricket::CA_OFFER, source, err_desc)) {
3365 SetError(ERROR_CONTENT, *err_desc);
3366 }
3367 if (error() != ERROR_NONE) {
3368 return BadOfferSdp(source, GetSessionErrorMsg(), err_desc);
3369 }
3370 } else if (action == kPrAnswer) {
3371 if (!PushdownTransportDescription(source, cricket::CA_PRANSWER, &td_err)) {
3372 return BadPranswerSdp(source, MakeTdErrorString(td_err), err_desc);
3373 }
3374 EnableChannels();
3375 ChangeSignalingState(source == cricket::CS_LOCAL
3376 ? PeerConnectionInterface::kHaveLocalPrAnswer
3377 : PeerConnectionInterface::kHaveRemotePrAnswer);
3378 if (!PushdownMediaDescription(cricket::CA_PRANSWER, source, err_desc)) {
3379 SetError(ERROR_CONTENT, *err_desc);
3380 }
3381 if (error() != ERROR_NONE) {
3382 return BadPranswerSdp(source, GetSessionErrorMsg(), err_desc);
3383 }
3384 } else if (action == kAnswer) {
3385 const cricket::ContentGroup* local_bundle =
3386 local_description()->description()->GetGroupByName(
3387 cricket::GROUP_TYPE_BUNDLE);
3388 const cricket::ContentGroup* remote_bundle =
3389 remote_description()->description()->GetGroupByName(
3390 cricket::GROUP_TYPE_BUNDLE);
3391 if (local_bundle && remote_bundle) {
3392 // The answerer decides the transport to bundle on.
3393 const cricket::ContentGroup* answer_bundle =
3394 (source == cricket::CS_LOCAL ? local_bundle : remote_bundle);
3395 if (!EnableBundle(*answer_bundle)) {
3396 LOG(LS_WARNING) << "Failed to enable BUNDLE.";
3397 return BadAnswerSdp(source, kEnableBundleFailed, err_desc);
3398 }
3399 }
3400 // Only push down the transport description after enabling BUNDLE; we don't
3401 // want to push down a description on a transport about to be destroyed.
3402 if (!PushdownTransportDescription(source, cricket::CA_ANSWER, &td_err)) {
3403 return BadAnswerSdp(source, MakeTdErrorString(td_err), err_desc);
3404 }
3405 EnableChannels();
3406 ChangeSignalingState(PeerConnectionInterface::kStable);
3407 if (!PushdownMediaDescription(cricket::CA_ANSWER, source, err_desc)) {
3408 SetError(ERROR_CONTENT, *err_desc);
3409 }
3410 if (error() != ERROR_NONE) {
3411 return BadAnswerSdp(source, GetSessionErrorMsg(), err_desc);
3412 }
3413 }
3414 return true;
3415}
3416
3417PeerConnection::Action PeerConnection::GetAction(const std::string& type) {
3418 if (type == SessionDescriptionInterface::kOffer) {
3419 return PeerConnection::kOffer;
3420 } else if (type == SessionDescriptionInterface::kPrAnswer) {
3421 return PeerConnection::kPrAnswer;
3422 } else if (type == SessionDescriptionInterface::kAnswer) {
3423 return PeerConnection::kAnswer;
3424 }
3425 RTC_NOTREACHED() << "unknown action type";
3426 return PeerConnection::kOffer;
3427}
3428
3429bool PeerConnection::PushdownMediaDescription(cricket::ContentAction action,
3430 cricket::ContentSource source,
3431 std::string* err) {
3432 const SessionDescription* sdesc =
3433 (source == cricket::CS_LOCAL ? local_description() : remote_description())
3434 ->description();
3435 RTC_DCHECK(sdesc);
3436 bool all_success = true;
3437 for (auto* channel : Channels()) {
3438 // TODO(steveanton): Add support for multiple channels of the same type.
3439 const ContentInfo* content_info =
3440 cricket::GetFirstMediaContent(sdesc->contents(), channel->media_type());
3441 if (!content_info) {
3442 continue;
3443 }
3444 const MediaContentDescription* content_desc =
3445 static_cast<const MediaContentDescription*>(content_info->description);
3446 if (content_desc && !content_info->rejected) {
3447 bool success = (source == cricket::CS_LOCAL)
3448 ? channel->SetLocalContent(content_desc, action, err)
3449 : channel->SetRemoteContent(content_desc, action, err);
3450 if (!success) {
3451 all_success = false;
3452 break;
3453 }
3454 }
3455 }
3456 // Need complete offer/answer with an SCTP m= section before starting SCTP,
3457 // according to https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-19
3458 if (sctp_transport_ && local_description() && remote_description() &&
3459 cricket::GetFirstDataContent(local_description()->description()) &&
3460 cricket::GetFirstDataContent(remote_description()->description())) {
3461 all_success &= network_thread()->Invoke<bool>(
3462 RTC_FROM_HERE,
3463 rtc::Bind(&PeerConnection::PushdownSctpParameters_n, this, source));
3464 }
3465 return all_success;
3466}
3467
3468bool PeerConnection::PushdownSctpParameters_n(cricket::ContentSource source) {
3469 RTC_DCHECK(network_thread()->IsCurrent());
3470 RTC_DCHECK(local_description());
3471 RTC_DCHECK(remote_description());
3472 // Apply the SCTP port (which is hidden inside a DataCodec structure...)
3473 // When we support "max-message-size", that would also be pushed down here.
3474 return sctp_transport_->Start(
3475 GetSctpPort(local_description()->description()),
3476 GetSctpPort(remote_description()->description()));
3477}
3478
3479bool PeerConnection::PushdownTransportDescription(cricket::ContentSource source,
3480 cricket::ContentAction action,
3481 std::string* error_desc) {
3482 RTC_DCHECK(signaling_thread()->IsCurrent());
3483
3484 if (source == cricket::CS_LOCAL) {
3485 return PushdownLocalTransportDescription(local_description()->description(),
3486 action, error_desc);
3487 }
3488 return PushdownRemoteTransportDescription(remote_description()->description(),
3489 action, error_desc);
3490}
3491
3492bool PeerConnection::PushdownLocalTransportDescription(
3493 const SessionDescription* sdesc,
3494 cricket::ContentAction action,
3495 std::string* err) {
3496 RTC_DCHECK(signaling_thread()->IsCurrent());
3497
3498 if (!sdesc) {
3499 return false;
3500 }
3501
3502 for (const TransportInfo& tinfo : sdesc->transport_infos()) {
3503 if (!transport_controller_->SetLocalTransportDescription(
3504 tinfo.content_name, tinfo.description, action, err)) {
3505 return false;
3506 }
3507 }
3508
3509 return true;
3510}
3511
3512bool PeerConnection::PushdownRemoteTransportDescription(
3513 const SessionDescription* sdesc,
3514 cricket::ContentAction action,
3515 std::string* err) {
3516 RTC_DCHECK(signaling_thread()->IsCurrent());
3517
3518 if (!sdesc) {
3519 return false;
3520 }
3521
3522 for (const TransportInfo& tinfo : sdesc->transport_infos()) {
3523 if (!transport_controller_->SetRemoteTransportDescription(
3524 tinfo.content_name, tinfo.description, action, err)) {
3525 return false;
3526 }
3527 }
3528
3529 return true;
3530}
3531
3532bool PeerConnection::GetTransportDescription(
3533 const SessionDescription* description,
3534 const std::string& content_name,
3535 cricket::TransportDescription* tdesc) {
3536 if (!description || !tdesc) {
3537 return false;
3538 }
3539 const TransportInfo* transport_info =
3540 description->GetTransportInfoByName(content_name);
3541 if (!transport_info) {
3542 return false;
3543 }
3544 *tdesc = transport_info->description;
3545 return true;
3546}
3547
3548bool PeerConnection::EnableBundle(const cricket::ContentGroup& bundle) {
3549 const std::string* first_content_name = bundle.FirstContentName();
3550 if (!first_content_name) {
3551 LOG(LS_WARNING) << "Tried to BUNDLE with no contents.";
3552 return false;
3553 }
3554 const std::string& transport_name = *first_content_name;
3555
3556 auto maybe_set_transport = [this, bundle,
3557 transport_name](cricket::BaseChannel* ch) {
3558 if (!ch || !bundle.HasContentName(ch->content_name())) {
3559 return true;
3560 }
3561
3562 std::string old_transport_name = ch->transport_name();
3563 if (old_transport_name == transport_name) {
3564 LOG(LS_INFO) << "BUNDLE already enabled for " << ch->content_name()
3565 << " on " << transport_name << ".";
3566 return true;
3567 }
3568
3569 cricket::DtlsTransportInternal* rtp_dtls_transport =
3570 transport_controller_->CreateDtlsTransport(
3571 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
3572 bool need_rtcp = (ch->rtcp_dtls_transport() != nullptr);
3573 cricket::DtlsTransportInternal* rtcp_dtls_transport = nullptr;
3574 if (need_rtcp) {
3575 rtcp_dtls_transport = transport_controller_->CreateDtlsTransport(
3576 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
3577 }
3578
3579 ch->SetTransports(rtp_dtls_transport, rtcp_dtls_transport);
3580 LOG(LS_INFO) << "Enabled BUNDLE for " << ch->content_name() << " on "
3581 << transport_name << ".";
3582 transport_controller_->DestroyDtlsTransport(
3583 old_transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
3584 // If the channel needs rtcp, it means that the channel used to have a
3585 // rtcp transport which needs to be deleted now.
3586 if (need_rtcp) {
3587 transport_controller_->DestroyDtlsTransport(
3588 old_transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
3589 }
3590 return true;
3591 };
3592
3593 if (!maybe_set_transport(voice_channel()) ||
3594 !maybe_set_transport(video_channel()) ||
3595 !maybe_set_transport(rtp_data_channel())) {
3596 return false;
3597 }
3598 // For SCTP, transport creation/deletion happens here instead of in the
3599 // object itself.
3600 if (sctp_transport_) {
3601 RTC_DCHECK(sctp_transport_name_);
3602 RTC_DCHECK(sctp_content_name_);
3603 if (transport_name != *sctp_transport_name_ &&
3604 bundle.HasContentName(*sctp_content_name_)) {
3605 network_thread()->Invoke<void>(
3606 RTC_FROM_HERE, rtc::Bind(&PeerConnection::ChangeSctpTransport_n, this,
3607 transport_name));
3608 }
3609 }
3610
3611 return true;
3612}
3613
3614bool PeerConnection::ProcessIceMessage(const IceCandidateInterface* candidate) {
3615 if (!remote_description()) {
3616 LOG(LS_ERROR) << "ProcessIceMessage: ICE candidates can't be added "
3617 << "without any remote session description.";
3618 return false;
3619 }
3620
3621 if (!candidate) {
3622 LOG(LS_ERROR) << "ProcessIceMessage: Candidate is NULL.";
3623 return false;
3624 }
3625
3626 bool valid = false;
3627 bool ready = ReadyToUseRemoteCandidate(candidate, NULL, &valid);
3628 if (!valid) {
3629 return false;
3630 }
3631
3632 // Add this candidate to the remote session description.
3633 if (!mutable_remote_description()->AddCandidate(candidate)) {
3634 LOG(LS_ERROR) << "ProcessIceMessage: Candidate cannot be used.";
3635 return false;
3636 }
3637
3638 if (ready) {
3639 return UseCandidate(candidate);
3640 } else {
3641 LOG(LS_INFO) << "ProcessIceMessage: Not ready to use candidate.";
3642 return true;
3643 }
3644}
3645
3646bool PeerConnection::RemoveRemoteIceCandidates(
3647 const std::vector<cricket::Candidate>& candidates) {
3648 if (!remote_description()) {
3649 LOG(LS_ERROR) << "RemoveRemoteIceCandidates: ICE candidates can't be "
3650 << "removed without any remote session description.";
3651 return false;
3652 }
3653
3654 if (candidates.empty()) {
3655 LOG(LS_ERROR) << "RemoveRemoteIceCandidates: candidates are empty.";
3656 return false;
3657 }
3658
3659 size_t number_removed =
3660 mutable_remote_description()->RemoveCandidates(candidates);
3661 if (number_removed != candidates.size()) {
3662 LOG(LS_ERROR) << "RemoveRemoteIceCandidates: Failed to remove candidates. "
3663 << "Requested " << candidates.size() << " but only "
3664 << number_removed << " are removed.";
3665 }
3666
3667 // Remove the candidates from the transport controller.
3668 std::string error;
3669 bool res = transport_controller_->RemoveRemoteCandidates(candidates, &error);
3670 if (!res && !error.empty()) {
3671 LOG(LS_ERROR) << "Error when removing remote candidates: " << error;
3672 }
3673 return true;
3674}
3675
3676cricket::IceConfig PeerConnection::ParseIceConfig(
3677 const PeerConnectionInterface::RTCConfiguration& config) const {
3678 cricket::ContinualGatheringPolicy gathering_policy;
3679 // TODO(honghaiz): Add the third continual gathering policy in
3680 // PeerConnectionInterface and map it to GATHER_CONTINUALLY_AND_RECOVER.
3681 switch (config.continual_gathering_policy) {
3682 case PeerConnectionInterface::GATHER_ONCE:
3683 gathering_policy = cricket::GATHER_ONCE;
3684 break;
3685 case PeerConnectionInterface::GATHER_CONTINUALLY:
3686 gathering_policy = cricket::GATHER_CONTINUALLY;
3687 break;
3688 default:
3689 RTC_NOTREACHED();
3690 gathering_policy = cricket::GATHER_ONCE;
3691 }
3692 cricket::IceConfig ice_config;
3693 ice_config.receiving_timeout = config.ice_connection_receiving_timeout;
3694 ice_config.prioritize_most_likely_candidate_pairs =
3695 config.prioritize_most_likely_ice_candidate_pairs;
3696 ice_config.backup_connection_ping_interval =
3697 config.ice_backup_candidate_pair_ping_interval;
3698 ice_config.continual_gathering_policy = gathering_policy;
3699 ice_config.presume_writable_when_fully_relayed =
3700 config.presume_writable_when_fully_relayed;
3701 ice_config.ice_check_min_interval = config.ice_check_min_interval;
3702 ice_config.regather_all_networks_interval_range =
3703 config.ice_regather_interval_range;
3704 return ice_config;
3705}
3706
3707void PeerConnection::SetIceConfig(const cricket::IceConfig& config) {
3708 transport_controller_->SetIceConfig(config);
3709}
3710
3711void PeerConnection::MaybeStartGathering() {
3712 transport_controller_->MaybeStartGathering();
3713}
3714
3715bool PeerConnection::GetLocalTrackIdBySsrc(uint32_t ssrc,
3716 std::string* track_id) {
3717 if (!local_description()) {
3718 return false;
3719 }
3720 return webrtc::GetTrackIdBySsrc(local_description()->description(), ssrc,
3721 track_id);
3722}
3723
3724bool PeerConnection::GetRemoteTrackIdBySsrc(uint32_t ssrc,
3725 std::string* track_id) {
3726 if (!remote_description()) {
3727 return false;
3728 }
3729 return webrtc::GetTrackIdBySsrc(remote_description()->description(), ssrc,
3730 track_id);
3731}
3732
3733bool PeerConnection::SendData(const cricket::SendDataParams& params,
3734 const rtc::CopyOnWriteBuffer& payload,
3735 cricket::SendDataResult* result) {
3736 if (!rtp_data_channel_ && !sctp_transport_) {
3737 LOG(LS_ERROR) << "SendData called when rtp_data_channel_ "
3738 << "and sctp_transport_ are NULL.";
3739 return false;
3740 }
3741 return rtp_data_channel_
3742 ? rtp_data_channel_->SendData(params, payload, result)
3743 : network_thread()->Invoke<bool>(
3744 RTC_FROM_HERE,
3745 Bind(&cricket::SctpTransportInternal::SendData,
3746 sctp_transport_.get(), params, payload, result));
3747}
3748
3749bool PeerConnection::ConnectDataChannel(DataChannel* webrtc_data_channel) {
3750 if (!rtp_data_channel_ && !sctp_transport_) {
3751 // Don't log an error here, because DataChannels are expected to call
3752 // ConnectDataChannel in this state. It's the only way to initially tell
3753 // whether or not the underlying transport is ready.
3754 return false;
3755 }
3756 if (rtp_data_channel_) {
3757 rtp_data_channel_->SignalReadyToSendData.connect(
3758 webrtc_data_channel, &DataChannel::OnChannelReady);
3759 rtp_data_channel_->SignalDataReceived.connect(webrtc_data_channel,
3760 &DataChannel::OnDataReceived);
3761 } else {
3762 SignalSctpReadyToSendData.connect(webrtc_data_channel,
3763 &DataChannel::OnChannelReady);
3764 SignalSctpDataReceived.connect(webrtc_data_channel,
3765 &DataChannel::OnDataReceived);
3766 SignalSctpStreamClosedRemotely.connect(
3767 webrtc_data_channel, &DataChannel::OnStreamClosedRemotely);
3768 }
3769 return true;
3770}
3771
3772void PeerConnection::DisconnectDataChannel(DataChannel* webrtc_data_channel) {
3773 if (!rtp_data_channel_ && !sctp_transport_) {
3774 LOG(LS_ERROR) << "DisconnectDataChannel called when rtp_data_channel_ and "
3775 "sctp_transport_ are NULL.";
3776 return;
3777 }
3778 if (rtp_data_channel_) {
3779 rtp_data_channel_->SignalReadyToSendData.disconnect(webrtc_data_channel);
3780 rtp_data_channel_->SignalDataReceived.disconnect(webrtc_data_channel);
3781 } else {
3782 SignalSctpReadyToSendData.disconnect(webrtc_data_channel);
3783 SignalSctpDataReceived.disconnect(webrtc_data_channel);
3784 SignalSctpStreamClosedRemotely.disconnect(webrtc_data_channel);
3785 }
3786}
3787
3788void PeerConnection::AddSctpDataStream(int sid) {
3789 if (!sctp_transport_) {
3790 LOG(LS_ERROR) << "AddSctpDataStream called when sctp_transport_ is NULL.";
3791 return;
3792 }
3793 network_thread()->Invoke<void>(
3794 RTC_FROM_HERE, rtc::Bind(&cricket::SctpTransportInternal::OpenStream,
3795 sctp_transport_.get(), sid));
3796}
3797
3798void PeerConnection::RemoveSctpDataStream(int sid) {
3799 if (!sctp_transport_) {
3800 LOG(LS_ERROR) << "RemoveSctpDataStream called when sctp_transport_ is "
3801 << "NULL.";
3802 return;
3803 }
3804 network_thread()->Invoke<void>(
3805 RTC_FROM_HERE, rtc::Bind(&cricket::SctpTransportInternal::ResetStream,
3806 sctp_transport_.get(), sid));
3807}
3808
3809bool PeerConnection::ReadyToSendData() const {
3810 return (rtp_data_channel_ && rtp_data_channel_->ready_to_send_data()) ||
3811 sctp_ready_to_send_data_;
3812}
3813
3814std::unique_ptr<SessionStats> PeerConnection::GetSessionStats_s() {
3815 RTC_DCHECK(signaling_thread()->IsCurrent());
3816 ChannelNamePairs channel_name_pairs;
3817 if (voice_channel()) {
3818 channel_name_pairs.voice = rtc::Optional<ChannelNamePair>(ChannelNamePair(
3819 voice_channel()->content_name(), voice_channel()->transport_name()));
3820 }
3821 if (video_channel()) {
3822 channel_name_pairs.video = rtc::Optional<ChannelNamePair>(ChannelNamePair(
3823 video_channel()->content_name(), video_channel()->transport_name()));
3824 }
3825 if (rtp_data_channel()) {
3826 channel_name_pairs.data = rtc::Optional<ChannelNamePair>(
3827 ChannelNamePair(rtp_data_channel()->content_name(),
3828 rtp_data_channel()->transport_name()));
3829 }
3830 if (sctp_transport_) {
3831 RTC_DCHECK(sctp_content_name_);
3832 RTC_DCHECK(sctp_transport_name_);
3833 channel_name_pairs.data = rtc::Optional<ChannelNamePair>(
3834 ChannelNamePair(*sctp_content_name_, *sctp_transport_name_));
3835 }
3836 return GetSessionStats(channel_name_pairs);
3837}
3838
3839std::unique_ptr<SessionStats> PeerConnection::GetSessionStats(
3840 const ChannelNamePairs& channel_name_pairs) {
3841 if (network_thread()->IsCurrent()) {
3842 return GetSessionStats_n(channel_name_pairs);
3843 }
3844 return network_thread()->Invoke<std::unique_ptr<SessionStats>>(
3845 RTC_FROM_HERE,
3846 rtc::Bind(&PeerConnection::GetSessionStats_n, this, channel_name_pairs));
3847}
3848
3849bool PeerConnection::GetLocalCertificate(
3850 const std::string& transport_name,
3851 rtc::scoped_refptr<rtc::RTCCertificate>* certificate) {
3852 return transport_controller_->GetLocalCertificate(transport_name,
3853 certificate);
3854}
3855
3856std::unique_ptr<rtc::SSLCertificate> PeerConnection::GetRemoteSSLCertificate(
3857 const std::string& transport_name) {
3858 return transport_controller_->GetRemoteSSLCertificate(transport_name);
3859}
3860
3861cricket::DataChannelType PeerConnection::data_channel_type() const {
3862 return data_channel_type_;
3863}
3864
3865bool PeerConnection::IceRestartPending(const std::string& content_name) const {
3866 return pending_ice_restarts_.find(content_name) !=
3867 pending_ice_restarts_.end();
3868}
3869
3870void PeerConnection::SetNeedsIceRestartFlag() {
3871 transport_controller_->SetNeedsIceRestartFlag();
3872}
3873
3874bool PeerConnection::NeedsIceRestart(const std::string& content_name) const {
3875 return transport_controller_->NeedsIceRestart(content_name);
3876}
3877
3878void PeerConnection::OnCertificateReady(
3879 const rtc::scoped_refptr<rtc::RTCCertificate>& certificate) {
3880 transport_controller_->SetLocalCertificate(certificate);
3881}
3882
3883void PeerConnection::OnDtlsSrtpSetupFailure(cricket::BaseChannel*, bool rtcp) {
3884 SetError(ERROR_TRANSPORT,
3885 rtcp ? kDtlsSrtpSetupFailureRtcp : kDtlsSrtpSetupFailureRtp);
3886}
3887
3888void PeerConnection::OnTransportControllerConnectionState(
3889 cricket::IceConnectionState state) {
3890 switch (state) {
3891 case cricket::kIceConnectionConnecting:
3892 // If the current state is Connected or Completed, then there were
3893 // writable channels but now there are not, so the next state must
3894 // be Disconnected.
3895 // kIceConnectionConnecting is currently used as the default,
3896 // un-connected state by the TransportController, so its only use is
3897 // detecting disconnections.
3898 if (ice_connection_state_ ==
3899 PeerConnectionInterface::kIceConnectionConnected ||
3900 ice_connection_state_ ==
3901 PeerConnectionInterface::kIceConnectionCompleted) {
3902 SetIceConnectionState(
3903 PeerConnectionInterface::kIceConnectionDisconnected);
3904 }
3905 break;
3906 case cricket::kIceConnectionFailed:
3907 SetIceConnectionState(PeerConnectionInterface::kIceConnectionFailed);
3908 break;
3909 case cricket::kIceConnectionConnected:
3910 LOG(LS_INFO) << "Changing to ICE connected state because "
3911 << "all transports are writable.";
3912 SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected);
3913 break;
3914 case cricket::kIceConnectionCompleted:
3915 LOG(LS_INFO) << "Changing to ICE completed state because "
3916 << "all transports are complete.";
3917 if (ice_connection_state_ !=
3918 PeerConnectionInterface::kIceConnectionConnected) {
3919 // If jumping directly from "checking" to "connected",
3920 // signal "connected" first.
3921 SetIceConnectionState(PeerConnectionInterface::kIceConnectionConnected);
3922 }
3923 SetIceConnectionState(PeerConnectionInterface::kIceConnectionCompleted);
3924 if (metrics_observer()) {
3925 ReportTransportStats();
3926 }
3927 break;
3928 default:
3929 RTC_NOTREACHED();
3930 }
3931}
3932
3933void PeerConnection::OnTransportControllerCandidatesGathered(
3934 const std::string& transport_name,
3935 const cricket::Candidates& candidates) {
3936 RTC_DCHECK(signaling_thread()->IsCurrent());
3937 int sdp_mline_index;
3938 if (!GetLocalCandidateMediaIndex(transport_name, &sdp_mline_index)) {
3939 LOG(LS_ERROR) << "OnTransportControllerCandidatesGathered: content name "
3940 << transport_name << " not found";
3941 return;
3942 }
3943
3944 for (cricket::Candidates::const_iterator citer = candidates.begin();
3945 citer != candidates.end(); ++citer) {
3946 // Use transport_name as the candidate media id.
3947 std::unique_ptr<JsepIceCandidate> candidate(
3948 new JsepIceCandidate(transport_name, sdp_mline_index, *citer));
3949 if (local_description()) {
3950 mutable_local_description()->AddCandidate(candidate.get());
3951 }
3952 OnIceCandidate(std::move(candidate));
3953 }
3954}
3955
3956void PeerConnection::OnTransportControllerCandidatesRemoved(
3957 const std::vector<cricket::Candidate>& candidates) {
3958 RTC_DCHECK(signaling_thread()->IsCurrent());
3959 // Sanity check.
3960 for (const cricket::Candidate& candidate : candidates) {
3961 if (candidate.transport_name().empty()) {
3962 LOG(LS_ERROR) << "OnTransportControllerCandidatesRemoved: "
3963 << "empty content name in candidate "
3964 << candidate.ToString();
3965 return;
3966 }
3967 }
3968
3969 if (local_description()) {
3970 mutable_local_description()->RemoveCandidates(candidates);
3971 }
3972 OnIceCandidatesRemoved(candidates);
3973}
3974
3975void PeerConnection::OnTransportControllerDtlsHandshakeError(
3976 rtc::SSLHandshakeError error) {
3977 if (metrics_observer()) {
3978 metrics_observer()->IncrementEnumCounter(
3979 webrtc::kEnumCounterDtlsHandshakeError, static_cast<int>(error),
3980 static_cast<int>(rtc::SSLHandshakeError::MAX_VALUE));
3981 }
3982}
3983
3984// Enabling voice and video (and RTP data) channels.
3985void PeerConnection::EnableChannels() {
3986 for (cricket::VoiceChannel* voice_channel : voice_channels_) {
3987 if (!voice_channel->enabled()) {
3988 voice_channel->Enable(true);
3989 }
3990 }
3991
3992 for (cricket::VideoChannel* video_channel : video_channels_) {
3993 if (!video_channel->enabled()) {
3994 video_channel->Enable(true);
3995 }
3996 }
3997
3998 if (rtp_data_channel_ && !rtp_data_channel_->enabled())
3999 rtp_data_channel_->Enable(true);
4000}
4001
4002// Returns the media index for a local ice candidate given the content name.
4003bool PeerConnection::GetLocalCandidateMediaIndex(
4004 const std::string& content_name,
4005 int* sdp_mline_index) {
4006 if (!local_description() || !sdp_mline_index) {
4007 return false;
4008 }
4009
4010 bool content_found = false;
4011 const ContentInfos& contents = local_description()->description()->contents();
4012 for (size_t index = 0; index < contents.size(); ++index) {
4013 if (contents[index].name == content_name) {
4014 *sdp_mline_index = static_cast<int>(index);
4015 content_found = true;
4016 break;
4017 }
4018 }
4019 return content_found;
4020}
4021
4022bool PeerConnection::UseCandidatesInSessionDescription(
4023 const SessionDescriptionInterface* remote_desc) {
4024 if (!remote_desc) {
4025 return true;
4026 }
4027 bool ret = true;
4028
4029 for (size_t m = 0; m < remote_desc->number_of_mediasections(); ++m) {
4030 const IceCandidateCollection* candidates = remote_desc->candidates(m);
4031 for (size_t n = 0; n < candidates->count(); ++n) {
4032 const IceCandidateInterface* candidate = candidates->at(n);
4033 bool valid = false;
4034 if (!ReadyToUseRemoteCandidate(candidate, remote_desc, &valid)) {
4035 if (valid) {
4036 LOG(LS_INFO) << "UseCandidatesInSessionDescription: Not ready to use "
4037 << "candidate.";
4038 }
4039 continue;
4040 }
4041 ret = UseCandidate(candidate);
4042 if (!ret) {
4043 break;
4044 }
4045 }
4046 }
4047 return ret;
4048}
4049
4050bool PeerConnection::UseCandidate(const IceCandidateInterface* candidate) {
4051 size_t mediacontent_index = static_cast<size_t>(candidate->sdp_mline_index());
4052 size_t remote_content_size =
4053 remote_description()->description()->contents().size();
4054 if (mediacontent_index >= remote_content_size) {
4055 LOG(LS_ERROR) << "UseCandidate: Invalid candidate media index.";
4056 return false;
4057 }
4058
4059 cricket::ContentInfo content =
4060 remote_description()->description()->contents()[mediacontent_index];
4061 std::vector<cricket::Candidate> candidates;
4062 candidates.push_back(candidate->candidate());
4063 // Invoking BaseSession method to handle remote candidates.
4064 std::string error;
4065 if (transport_controller_->AddRemoteCandidates(content.name, candidates,
4066 &error)) {
4067 // Candidates successfully submitted for checking.
4068 if (ice_connection_state_ == PeerConnectionInterface::kIceConnectionNew ||
4069 ice_connection_state_ ==
4070 PeerConnectionInterface::kIceConnectionDisconnected) {
4071 // If state is New, then the session has just gotten its first remote ICE
4072 // candidates, so go to Checking.
4073 // If state is Disconnected, the session is re-using old candidates or
4074 // receiving additional ones, so go to Checking.
4075 // If state is Connected, stay Connected.
4076 // TODO(bemasc): If state is Connected, and the new candidates are for a
4077 // newly added transport, then the state actually _should_ move to
4078 // checking. Add a way to distinguish that case.
4079 SetIceConnectionState(PeerConnectionInterface::kIceConnectionChecking);
4080 }
4081 // TODO(bemasc): If state is Completed, go back to Connected.
4082 } else {
4083 if (!error.empty()) {
4084 LOG(LS_WARNING) << error;
4085 }
4086 }
4087 return true;
4088}
4089
4090void PeerConnection::RemoveUnusedChannels(const SessionDescription* desc) {
4091 // TODO(steveanton): Add support for multiple audio/video channels.
4092 // Destroy video channel first since it may have a pointer to the
4093 // voice channel.
4094 const cricket::ContentInfo* video_info = cricket::GetFirstVideoContent(desc);
4095 if ((!video_info || video_info->rejected) && video_channel()) {
4096 RemoveAndDestroyVideoChannel(video_channel());
4097 }
4098
4099 const cricket::ContentInfo* voice_info = cricket::GetFirstAudioContent(desc);
4100 if ((!voice_info || voice_info->rejected) && voice_channel()) {
4101 RemoveAndDestroyVoiceChannel(voice_channel());
4102 }
4103
4104 const cricket::ContentInfo* data_info = cricket::GetFirstDataContent(desc);
4105 if (!data_info || data_info->rejected) {
4106 if (rtp_data_channel_) {
4107 DestroyDataChannel();
4108 }
4109 if (sctp_transport_) {
4110 OnDataChannelDestroyed();
4111 network_thread()->Invoke<void>(
4112 RTC_FROM_HERE,
4113 rtc::Bind(&PeerConnection::DestroySctpTransport_n, this));
4114 }
4115 }
4116}
4117
4118// Returns the name of the transport channel when BUNDLE is enabled, or nullptr
4119// if the channel is not part of any bundle.
4120const std::string* PeerConnection::GetBundleTransportName(
4121 const cricket::ContentInfo* content,
4122 const cricket::ContentGroup* bundle) {
4123 if (!bundle) {
4124 return nullptr;
4125 }
4126 const std::string* first_content_name = bundle->FirstContentName();
4127 if (!first_content_name) {
4128 LOG(LS_WARNING) << "Tried to BUNDLE with no contents.";
4129 return nullptr;
4130 }
4131 if (!bundle->HasContentName(content->name)) {
4132 LOG(LS_WARNING) << content->name << " is not part of any bundle group";
4133 return nullptr;
4134 }
4135 LOG(LS_INFO) << "Bundling " << content->name << " on " << *first_content_name;
4136 return first_content_name;
4137}
4138
4139bool PeerConnection::CreateChannels(const SessionDescription* desc) {
4140 // TODO(steveanton): Add support for multiple audio/video channels.
4141 const cricket::ContentGroup* bundle_group = nullptr;
4142 if (configuration_.bundle_policy ==
4143 PeerConnectionInterface::kBundlePolicyMaxBundle) {
4144 bundle_group = desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
4145 if (!bundle_group) {
4146 LOG(LS_WARNING) << "max-bundle specified without BUNDLE specified";
4147 return false;
4148 }
4149 }
4150 // Creating the media channels and transport proxies.
4151 const cricket::ContentInfo* voice = cricket::GetFirstAudioContent(desc);
4152 if (voice && !voice->rejected && !voice_channel()) {
4153 if (!CreateVoiceChannel(voice,
4154 GetBundleTransportName(voice, bundle_group))) {
4155 LOG(LS_ERROR) << "Failed to create voice channel.";
4156 return false;
4157 }
4158 }
4159
4160 const cricket::ContentInfo* video = cricket::GetFirstVideoContent(desc);
4161 if (video && !video->rejected && !video_channel()) {
4162 if (!CreateVideoChannel(video,
4163 GetBundleTransportName(video, bundle_group))) {
4164 LOG(LS_ERROR) << "Failed to create video channel.";
4165 return false;
4166 }
4167 }
4168
4169 const cricket::ContentInfo* data = cricket::GetFirstDataContent(desc);
4170 if (data_channel_type_ != cricket::DCT_NONE && data && !data->rejected &&
4171 !rtp_data_channel_ && !sctp_transport_) {
4172 if (!CreateDataChannel(data, GetBundleTransportName(data, bundle_group))) {
4173 LOG(LS_ERROR) << "Failed to create data channel.";
4174 return false;
4175 }
4176 }
4177
4178 return true;
4179}
4180
4181bool PeerConnection::CreateVoiceChannel(const cricket::ContentInfo* content,
4182 const std::string* bundle_transport) {
4183 // TODO(steveanton): Check to see if it's safe to create multiple voice
4184 // channels.
4185 RTC_DCHECK(voice_channels_.empty());
4186
4187 std::string transport_name =
4188 bundle_transport ? *bundle_transport : content->name;
4189
4190 cricket::DtlsTransportInternal* rtp_dtls_transport =
4191 transport_controller_->CreateDtlsTransport(
4192 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
4193 cricket::DtlsTransportInternal* rtcp_dtls_transport = nullptr;
4194 if (configuration_.rtcp_mux_policy !=
4195 PeerConnectionInterface::kRtcpMuxPolicyRequire) {
4196 rtcp_dtls_transport = transport_controller_->CreateDtlsTransport(
4197 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
4198 }
4199
4200 cricket::VoiceChannel* voice_channel = channel_manager()->CreateVoiceChannel(
4201 call_.get(), configuration_.media_config, rtp_dtls_transport,
4202 rtcp_dtls_transport, transport_controller_->signaling_thread(),
4203 content->name, SrtpRequired(), audio_options_);
4204 if (!voice_channel) {
4205 transport_controller_->DestroyDtlsTransport(
4206 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
4207 if (rtcp_dtls_transport) {
4208 transport_controller_->DestroyDtlsTransport(
4209 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
4210 }
4211 return false;
4212 }
4213
4214 voice_channels_.push_back(voice_channel);
4215
4216 voice_channel->SignalRtcpMuxFullyActive.connect(
4217 this, &PeerConnection::DestroyRtcpTransport_n);
4218 voice_channel->SignalDtlsSrtpSetupFailure.connect(
4219 this, &PeerConnection::OnDtlsSrtpSetupFailure);
4220
4221 // TODO(steveanton): This should signal which voice channel was created since
4222 // we can have multiple.
4223 OnVoiceChannelCreated();
4224 voice_channel->SignalSentPacket.connect(this,
4225 &PeerConnection::OnSentPacket_w);
4226 return true;
4227}
4228
4229bool PeerConnection::CreateVideoChannel(const cricket::ContentInfo* content,
4230 const std::string* bundle_transport) {
4231 // TODO(steveanton): Check to see if it's safe to create multiple video
4232 // channels.
4233 RTC_DCHECK(video_channels_.empty());
4234
4235 std::string transport_name =
4236 bundle_transport ? *bundle_transport : content->name;
4237
4238 cricket::DtlsTransportInternal* rtp_dtls_transport =
4239 transport_controller_->CreateDtlsTransport(
4240 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
4241 cricket::DtlsTransportInternal* rtcp_dtls_transport = nullptr;
4242 if (configuration_.rtcp_mux_policy !=
4243 PeerConnectionInterface::kRtcpMuxPolicyRequire) {
4244 rtcp_dtls_transport = transport_controller_->CreateDtlsTransport(
4245 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
4246 }
4247
4248 cricket::VideoChannel* video_channel = channel_manager()->CreateVideoChannel(
4249 call_.get(), configuration_.media_config, rtp_dtls_transport,
4250 rtcp_dtls_transport, transport_controller_->signaling_thread(),
4251 content->name, SrtpRequired(), video_options_);
4252
4253 if (!video_channel) {
4254 transport_controller_->DestroyDtlsTransport(
4255 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
4256 if (rtcp_dtls_transport) {
4257 transport_controller_->DestroyDtlsTransport(
4258 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
4259 }
4260 return false;
4261 }
4262
4263 video_channels_.push_back(video_channel);
4264
4265 video_channel->SignalRtcpMuxFullyActive.connect(
4266 this, &PeerConnection::DestroyRtcpTransport_n);
4267 video_channel->SignalDtlsSrtpSetupFailure.connect(
4268 this, &PeerConnection::OnDtlsSrtpSetupFailure);
4269
4270 // TODO(steveanton): This should signal which video channel was created since
4271 // we can have multiple.
4272 OnVideoChannelCreated();
4273 video_channel->SignalSentPacket.connect(this,
4274 &PeerConnection::OnSentPacket_w);
4275 return true;
4276}
4277
4278bool PeerConnection::CreateDataChannel(const cricket::ContentInfo* content,
4279 const std::string* bundle_transport) {
4280 const std::string transport_name =
4281 bundle_transport ? *bundle_transport : content->name;
4282 bool sctp = (data_channel_type_ == cricket::DCT_SCTP);
4283 if (sctp) {
4284 if (!sctp_factory_) {
4285 LOG(LS_ERROR)
4286 << "Trying to create SCTP transport, but didn't compile with "
4287 "SCTP support (HAVE_SCTP)";
4288 return false;
4289 }
4290 if (!network_thread()->Invoke<bool>(
4291 RTC_FROM_HERE, rtc::Bind(&PeerConnection::CreateSctpTransport_n,
4292 this, content->name, transport_name))) {
4293 return false;
4294 }
4295 } else {
4296 std::string transport_name =
4297 bundle_transport ? *bundle_transport : content->name;
4298 cricket::DtlsTransportInternal* rtp_dtls_transport =
4299 transport_controller_->CreateDtlsTransport(
4300 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
4301 cricket::DtlsTransportInternal* rtcp_dtls_transport = nullptr;
4302 if (configuration_.rtcp_mux_policy !=
4303 PeerConnectionInterface::kRtcpMuxPolicyRequire) {
4304 rtcp_dtls_transport = transport_controller_->CreateDtlsTransport(
4305 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
4306 }
4307
4308 rtp_data_channel_ = channel_manager()->CreateRtpDataChannel(
4309 configuration_.media_config, rtp_dtls_transport, rtcp_dtls_transport,
4310 transport_controller_->signaling_thread(), content->name,
4311 SrtpRequired());
4312
4313 if (!rtp_data_channel_) {
4314 transport_controller_->DestroyDtlsTransport(
4315 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
4316 if (rtcp_dtls_transport) {
4317 transport_controller_->DestroyDtlsTransport(
4318 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
4319 }
4320 return false;
4321 }
4322
4323 rtp_data_channel_->SignalRtcpMuxFullyActive.connect(
4324 this, &PeerConnection::DestroyRtcpTransport_n);
4325 rtp_data_channel_->SignalDtlsSrtpSetupFailure.connect(
4326 this, &PeerConnection::OnDtlsSrtpSetupFailure);
4327 rtp_data_channel_->SignalSentPacket.connect(
4328 this, &PeerConnection::OnSentPacket_w);
4329 }
4330
4331 OnDataChannelCreated();
4332
4333 return true;
4334}
4335
4336Call::Stats PeerConnection::GetCallStats() {
4337 if (!worker_thread()->IsCurrent()) {
4338 return worker_thread()->Invoke<Call::Stats>(
4339 RTC_FROM_HERE, rtc::Bind(&PeerConnection::GetCallStats, this));
4340 }
4341 if (call_) {
4342 return call_->GetStats();
4343 } else {
4344 return Call::Stats();
4345 }
4346}
4347
4348std::unique_ptr<SessionStats> PeerConnection::GetSessionStats_n(
4349 const ChannelNamePairs& channel_name_pairs) {
4350 RTC_DCHECK(network_thread()->IsCurrent());
4351 std::unique_ptr<SessionStats> session_stats(new SessionStats());
4352 for (const auto channel_name_pair :
4353 {&channel_name_pairs.voice, &channel_name_pairs.video,
4354 &channel_name_pairs.data}) {
4355 if (*channel_name_pair) {
4356 cricket::TransportStats transport_stats;
4357 if (!transport_controller_->GetStats((*channel_name_pair)->transport_name,
4358 &transport_stats)) {
4359 return nullptr;
4360 }
4361 session_stats->proxy_to_transport[(*channel_name_pair)->content_name] =
4362 (*channel_name_pair)->transport_name;
4363 session_stats->transport_stats[(*channel_name_pair)->transport_name] =
4364 std::move(transport_stats);
4365 }
4366 }
4367 return session_stats;
4368}
4369
4370bool PeerConnection::CreateSctpTransport_n(const std::string& content_name,
4371 const std::string& transport_name) {
4372 RTC_DCHECK(network_thread()->IsCurrent());
4373 RTC_DCHECK(sctp_factory_);
4374 cricket::DtlsTransportInternal* tc =
4375 transport_controller_->CreateDtlsTransport_n(
4376 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
4377 sctp_transport_ = sctp_factory_->CreateSctpTransport(tc);
4378 RTC_DCHECK(sctp_transport_);
4379 sctp_invoker_.reset(new rtc::AsyncInvoker());
4380 sctp_transport_->SignalReadyToSendData.connect(
4381 this, &PeerConnection::OnSctpTransportReadyToSendData_n);
4382 sctp_transport_->SignalDataReceived.connect(
4383 this, &PeerConnection::OnSctpTransportDataReceived_n);
4384 sctp_transport_->SignalStreamClosedRemotely.connect(
4385 this, &PeerConnection::OnSctpStreamClosedRemotely_n);
4386 sctp_transport_name_ = rtc::Optional<std::string>(transport_name);
4387 sctp_content_name_ = rtc::Optional<std::string>(content_name);
4388 return true;
4389}
4390
4391void PeerConnection::ChangeSctpTransport_n(const std::string& transport_name) {
4392 RTC_DCHECK(network_thread()->IsCurrent());
4393 RTC_DCHECK(sctp_transport_);
4394 RTC_DCHECK(sctp_transport_name_);
4395 std::string old_sctp_transport_name = *sctp_transport_name_;
4396 sctp_transport_name_ = rtc::Optional<std::string>(transport_name);
4397 cricket::DtlsTransportInternal* tc =
4398 transport_controller_->CreateDtlsTransport_n(
4399 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
4400 sctp_transport_->SetTransportChannel(tc);
4401 transport_controller_->DestroyDtlsTransport_n(
4402 old_sctp_transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
4403}
4404
4405void PeerConnection::DestroySctpTransport_n() {
4406 RTC_DCHECK(network_thread()->IsCurrent());
4407 sctp_transport_.reset(nullptr);
4408 sctp_content_name_.reset();
4409 sctp_transport_name_.reset();
4410 sctp_invoker_.reset(nullptr);
4411 sctp_ready_to_send_data_ = false;
4412}
4413
4414void PeerConnection::OnSctpTransportReadyToSendData_n() {
4415 RTC_DCHECK(data_channel_type_ == cricket::DCT_SCTP);
4416 RTC_DCHECK(network_thread()->IsCurrent());
4417 // Note: Cannot use rtc::Bind here because it will grab a reference to
4418 // PeerConnection and potentially cause PeerConnection to live longer than
4419 // expected. It is safe not to grab a reference since the sctp_invoker_ will
4420 // be destroyed before PeerConnection is destroyed, and at that point all
4421 // pending tasks will be cleared.
4422 sctp_invoker_->AsyncInvoke<void>(RTC_FROM_HERE, signaling_thread(), [this] {
4423 OnSctpTransportReadyToSendData_s(true);
4424 });
4425}
4426
4427void PeerConnection::OnSctpTransportReadyToSendData_s(bool ready) {
4428 RTC_DCHECK(signaling_thread()->IsCurrent());
4429 sctp_ready_to_send_data_ = ready;
4430 SignalSctpReadyToSendData(ready);
4431}
4432
4433void PeerConnection::OnSctpTransportDataReceived_n(
4434 const cricket::ReceiveDataParams& params,
4435 const rtc::CopyOnWriteBuffer& payload) {
4436 RTC_DCHECK(data_channel_type_ == cricket::DCT_SCTP);
4437 RTC_DCHECK(network_thread()->IsCurrent());
4438 // Note: Cannot use rtc::Bind here because it will grab a reference to
4439 // PeerConnection and potentially cause PeerConnection to live longer than
4440 // expected. It is safe not to grab a reference since the sctp_invoker_ will
4441 // be destroyed before PeerConnection is destroyed, and at that point all
4442 // pending tasks will be cleared.
4443 sctp_invoker_->AsyncInvoke<void>(
4444 RTC_FROM_HERE, signaling_thread(), [this, params, payload] {
4445 OnSctpTransportDataReceived_s(params, payload);
4446 });
4447}
4448
4449void PeerConnection::OnSctpTransportDataReceived_s(
4450 const cricket::ReceiveDataParams& params,
4451 const rtc::CopyOnWriteBuffer& payload) {
4452 RTC_DCHECK(signaling_thread()->IsCurrent());
4453 if (params.type == cricket::DMT_CONTROL && IsOpenMessage(payload)) {
4454 // Received OPEN message; parse and signal that a new data channel should
4455 // be created.
4456 std::string label;
4457 InternalDataChannelInit config;
4458 config.id = params.ssrc;
4459 if (!ParseDataChannelOpenMessage(payload, &label, &config)) {
4460 LOG(LS_WARNING) << "Failed to parse the OPEN message for sid "
4461 << params.ssrc;
4462 return;
4463 }
4464 config.open_handshake_role = InternalDataChannelInit::kAcker;
4465 OnDataChannelOpenMessage(label, config);
4466 } else {
4467 // Otherwise just forward the signal.
4468 SignalSctpDataReceived(params, payload);
4469 }
4470}
4471
4472void PeerConnection::OnSctpStreamClosedRemotely_n(int sid) {
4473 RTC_DCHECK(data_channel_type_ == cricket::DCT_SCTP);
4474 RTC_DCHECK(network_thread()->IsCurrent());
4475 sctp_invoker_->AsyncInvoke<void>(
4476 RTC_FROM_HERE, signaling_thread(),
4477 rtc::Bind(&sigslot::signal1<int>::operator(),
4478 &SignalSctpStreamClosedRemotely, sid));
4479}
4480
4481// Returns false if bundle is enabled and rtcp_mux is disabled.
4482bool PeerConnection::ValidateBundleSettings(const SessionDescription* desc) {
4483 bool bundle_enabled = desc->HasGroup(cricket::GROUP_TYPE_BUNDLE);
4484 if (!bundle_enabled)
4485 return true;
4486
4487 const cricket::ContentGroup* bundle_group =
4488 desc->GetGroupByName(cricket::GROUP_TYPE_BUNDLE);
4489 RTC_DCHECK(bundle_group != NULL);
4490
4491 const cricket::ContentInfos& contents = desc->contents();
4492 for (cricket::ContentInfos::const_iterator citer = contents.begin();
4493 citer != contents.end(); ++citer) {
4494 const cricket::ContentInfo* content = (&*citer);
4495 RTC_DCHECK(content != NULL);
4496 if (bundle_group->HasContentName(content->name) && !content->rejected &&
4497 content->type == cricket::NS_JINGLE_RTP) {
4498 if (!HasRtcpMuxEnabled(content))
4499 return false;
4500 }
4501 }
4502 // RTCP-MUX is enabled in all the contents.
4503 return true;
4504}
4505
4506bool PeerConnection::HasRtcpMuxEnabled(const cricket::ContentInfo* content) {
4507 const cricket::MediaContentDescription* description =
4508 static_cast<cricket::MediaContentDescription*>(content->description);
4509 return description->rtcp_mux();
4510}
4511
4512bool PeerConnection::ValidateSessionDescription(
4513 const SessionDescriptionInterface* sdesc,
4514 cricket::ContentSource source,
4515 std::string* err_desc) {
4516 std::string type;
4517 if (error() != ERROR_NONE) {
4518 return BadSdp(source, type, GetSessionErrorMsg(), err_desc);
4519 }
4520
4521 if (!sdesc || !sdesc->description()) {
4522 return BadSdp(source, type, kInvalidSdp, err_desc);
4523 }
4524
4525 type = sdesc->type();
4526 Action action = GetAction(sdesc->type());
4527 if (source == cricket::CS_LOCAL) {
4528 if (!ExpectSetLocalDescription(action))
4529 return BadLocalSdp(type, BadStateErrMsg(signaling_state()), err_desc);
4530 } else {
4531 if (!ExpectSetRemoteDescription(action))
4532 return BadRemoteSdp(type, BadStateErrMsg(signaling_state()), err_desc);
4533 }
4534
4535 // Verify crypto settings.
4536 std::string crypto_error;
4537 if ((webrtc_session_desc_factory_->SdesPolicy() == cricket::SEC_REQUIRED ||
4538 dtls_enabled_) &&
4539 !VerifyCrypto(sdesc->description(), dtls_enabled_, &crypto_error)) {
4540 return BadSdp(source, type, crypto_error, err_desc);
4541 }
4542
4543 // Verify ice-ufrag and ice-pwd.
4544 if (!VerifyIceUfragPwdPresent(sdesc->description())) {
4545 return BadSdp(source, type, kSdpWithoutIceUfragPwd, err_desc);
4546 }
4547
4548 if (!ValidateBundleSettings(sdesc->description())) {
4549 return BadSdp(source, type, kBundleWithoutRtcpMux, err_desc);
4550 }
4551
4552 // TODO(skvlad): When the local rtcp-mux policy is Require, reject any
4553 // m-lines that do not rtcp-mux enabled.
4554
4555 // Verify m-lines in Answer when compared against Offer.
4556 if (action == kAnswer || action == kPrAnswer) {
4557 const cricket::SessionDescription* offer_desc =
4558 (source == cricket::CS_LOCAL) ? remote_description()->description()
4559 : local_description()->description();
4560 if (!MediaSectionsHaveSameCount(offer_desc, sdesc->description()) ||
4561 !MediaSectionsInSameOrder(offer_desc, sdesc->description())) {
4562 return BadAnswerSdp(source, kMlineMismatchInAnswer, err_desc);
4563 }
4564 } else {
4565 const cricket::SessionDescription* current_desc = nullptr;
4566 if (source == cricket::CS_LOCAL && local_description()) {
4567 current_desc = local_description()->description();
4568 } else if (source == cricket::CS_REMOTE && remote_description()) {
4569 current_desc = remote_description()->description();
4570 }
4571 // The re-offers should respect the order of m= sections in current
4572 // description. See RFC3264 Section 8 paragraph 4 for more details.
4573 if (current_desc &&
4574 !MediaSectionsInSameOrder(current_desc, sdesc->description())) {
4575 return BadOfferSdp(source, kMlineMismatchInSubsequentOffer, err_desc);
4576 }
4577 }
4578
4579 return true;
4580}
4581
4582bool PeerConnection::ExpectSetLocalDescription(Action action) {
4583 PeerConnectionInterface::SignalingState state = signaling_state();
4584 if (action == kOffer) {
4585 return (state == PeerConnectionInterface::kStable) ||
4586 (state == PeerConnectionInterface::kHaveLocalOffer);
4587 } else { // Answer or PrAnswer
4588 return (state == PeerConnectionInterface::kHaveRemoteOffer) ||
4589 (state == PeerConnectionInterface::kHaveLocalPrAnswer);
4590 }
4591}
4592
4593bool PeerConnection::ExpectSetRemoteDescription(Action action) {
4594 PeerConnectionInterface::SignalingState state = signaling_state();
4595 if (action == kOffer) {
4596 return (state == PeerConnectionInterface::kStable) ||
4597 (state == PeerConnectionInterface::kHaveRemoteOffer);
4598 } else { // Answer or PrAnswer.
4599 return (state == PeerConnectionInterface::kHaveLocalOffer) ||
4600 (state == PeerConnectionInterface::kHaveRemotePrAnswer);
4601 }
4602}
4603
4604std::string PeerConnection::GetSessionErrorMsg() {
4605 std::ostringstream desc;
4606 desc << kSessionError << GetErrorCodeString(error()) << ". ";
4607 desc << kSessionErrorDesc << error_desc() << ".";
4608 return desc.str();
4609}
4610
4611// We need to check the local/remote description for the Transport instead of
4612// the session, because a new Transport added during renegotiation may have
4613// them unset while the session has them set from the previous negotiation.
4614// Not doing so may trigger the auto generation of transport description and
4615// mess up DTLS identity information, ICE credential, etc.
4616bool PeerConnection::ReadyToUseRemoteCandidate(
4617 const IceCandidateInterface* candidate,
4618 const SessionDescriptionInterface* remote_desc,
4619 bool* valid) {
4620 *valid = true;
4621
4622 const SessionDescriptionInterface* current_remote_desc =
4623 remote_desc ? remote_desc : remote_description();
4624
4625 if (!current_remote_desc) {
4626 return false;
4627 }
4628
4629 size_t mediacontent_index = static_cast<size_t>(candidate->sdp_mline_index());
4630 size_t remote_content_size =
4631 current_remote_desc->description()->contents().size();
4632 if (mediacontent_index >= remote_content_size) {
4633 LOG(LS_ERROR) << "ReadyToUseRemoteCandidate: Invalid candidate media index "
4634 << mediacontent_index;
4635
4636 *valid = false;
4637 return false;
4638 }
4639
4640 cricket::ContentInfo content =
4641 current_remote_desc->description()->contents()[mediacontent_index];
4642
4643 const std::string transport_name = GetTransportName(content.name);
4644 if (transport_name.empty()) {
4645 return false;
4646 }
4647 return transport_controller_->ReadyForRemoteCandidates(transport_name);
4648}
4649
4650bool PeerConnection::SrtpRequired() const {
4651 return dtls_enabled_ ||
4652 webrtc_session_desc_factory_->SdesPolicy() == cricket::SEC_REQUIRED;
4653}
4654
4655void PeerConnection::OnTransportControllerGatheringState(
4656 cricket::IceGatheringState state) {
4657 RTC_DCHECK(signaling_thread()->IsCurrent());
4658 if (state == cricket::kIceGatheringGathering) {
4659 OnIceGatheringChange(PeerConnectionInterface::kIceGatheringGathering);
4660 } else if (state == cricket::kIceGatheringComplete) {
4661 OnIceGatheringChange(PeerConnectionInterface::kIceGatheringComplete);
4662 }
4663}
4664
4665void PeerConnection::ReportTransportStats() {
4666 // Use a set so we don't report the same stats twice if two channels share
4667 // a transport.
4668 std::set<std::string> transport_names;
4669 if (voice_channel()) {
4670 transport_names.insert(voice_channel()->transport_name());
4671 }
4672 if (video_channel()) {
4673 transport_names.insert(video_channel()->transport_name());
4674 }
4675 if (rtp_data_channel()) {
4676 transport_names.insert(rtp_data_channel()->transport_name());
4677 }
4678 if (sctp_transport_name_) {
4679 transport_names.insert(*sctp_transport_name_);
4680 }
4681 for (const auto& name : transport_names) {
4682 cricket::TransportStats stats;
4683 if (transport_controller_->GetStats(name, &stats)) {
4684 ReportBestConnectionState(stats);
4685 ReportNegotiatedCiphers(stats);
4686 }
4687 }
4688}
4689// Walk through the ConnectionInfos to gather best connection usage
4690// for IPv4 and IPv6.
4691void PeerConnection::ReportBestConnectionState(
4692 const cricket::TransportStats& stats) {
4693 RTC_DCHECK(metrics_observer());
4694 for (cricket::TransportChannelStatsList::const_iterator it =
4695 stats.channel_stats.begin();
4696 it != stats.channel_stats.end(); ++it) {
4697 for (cricket::ConnectionInfos::const_iterator it_info =
4698 it->connection_infos.begin();
4699 it_info != it->connection_infos.end(); ++it_info) {
4700 if (!it_info->best_connection) {
4701 continue;
4702 }
4703
4704 PeerConnectionEnumCounterType type = kPeerConnectionEnumCounterMax;
4705 const cricket::Candidate& local = it_info->local_candidate;
4706 const cricket::Candidate& remote = it_info->remote_candidate;
4707
4708 // Increment the counter for IceCandidatePairType.
4709 if (local.protocol() == cricket::TCP_PROTOCOL_NAME ||
4710 (local.type() == RELAY_PORT_TYPE &&
4711 local.relay_protocol() == cricket::TCP_PROTOCOL_NAME)) {
4712 type = kEnumCounterIceCandidatePairTypeTcp;
4713 } else if (local.protocol() == cricket::UDP_PROTOCOL_NAME) {
4714 type = kEnumCounterIceCandidatePairTypeUdp;
4715 } else {
4716 RTC_CHECK(0);
4717 }
4718 metrics_observer()->IncrementEnumCounter(
4719 type, GetIceCandidatePairCounter(local, remote),
4720 kIceCandidatePairMax);
4721
4722 // Increment the counter for IP type.
4723 if (local.address().family() == AF_INET) {
4724 metrics_observer()->IncrementEnumCounter(
4725 kEnumCounterAddressFamily, kBestConnections_IPv4,
4726 kPeerConnectionAddressFamilyCounter_Max);
4727
4728 } else if (local.address().family() == AF_INET6) {
4729 metrics_observer()->IncrementEnumCounter(
4730 kEnumCounterAddressFamily, kBestConnections_IPv6,
4731 kPeerConnectionAddressFamilyCounter_Max);
4732 } else {
4733 RTC_CHECK(0);
4734 }
4735
4736 return;
4737 }
4738 }
4739}
4740
4741void PeerConnection::ReportNegotiatedCiphers(
4742 const cricket::TransportStats& stats) {
4743 RTC_DCHECK(metrics_observer());
4744 if (!dtls_enabled_ || stats.channel_stats.empty()) {
4745 return;
4746 }
4747
4748 int srtp_crypto_suite = stats.channel_stats[0].srtp_crypto_suite;
4749 int ssl_cipher_suite = stats.channel_stats[0].ssl_cipher_suite;
4750 if (srtp_crypto_suite == rtc::SRTP_INVALID_CRYPTO_SUITE &&
4751 ssl_cipher_suite == rtc::TLS_NULL_WITH_NULL_NULL) {
4752 return;
4753 }
4754
4755 PeerConnectionEnumCounterType srtp_counter_type;
4756 PeerConnectionEnumCounterType ssl_counter_type;
4757 if (stats.transport_name == cricket::CN_AUDIO) {
4758 srtp_counter_type = kEnumCounterAudioSrtpCipher;
4759 ssl_counter_type = kEnumCounterAudioSslCipher;
4760 } else if (stats.transport_name == cricket::CN_VIDEO) {
4761 srtp_counter_type = kEnumCounterVideoSrtpCipher;
4762 ssl_counter_type = kEnumCounterVideoSslCipher;
4763 } else if (stats.transport_name == cricket::CN_DATA) {
4764 srtp_counter_type = kEnumCounterDataSrtpCipher;
4765 ssl_counter_type = kEnumCounterDataSslCipher;
4766 } else {
4767 RTC_NOTREACHED();
4768 return;
4769 }
4770
4771 if (srtp_crypto_suite != rtc::SRTP_INVALID_CRYPTO_SUITE) {
4772 metrics_observer()->IncrementSparseEnumCounter(srtp_counter_type,
4773 srtp_crypto_suite);
4774 }
4775 if (ssl_cipher_suite != rtc::TLS_NULL_WITH_NULL_NULL) {
4776 metrics_observer()->IncrementSparseEnumCounter(ssl_counter_type,
4777 ssl_cipher_suite);
4778 }
4779}
4780
4781void PeerConnection::OnSentPacket_w(const rtc::SentPacket& sent_packet) {
4782 RTC_DCHECK(worker_thread()->IsCurrent());
4783 RTC_DCHECK(call_);
4784 call_->OnSentPacket(sent_packet);
4785}
4786
4787const std::string PeerConnection::GetTransportName(
4788 const std::string& content_name) {
4789 cricket::BaseChannel* channel = GetChannel(content_name);
4790 if (!channel) {
4791 if (sctp_transport_) {
4792 RTC_DCHECK(sctp_content_name_);
4793 RTC_DCHECK(sctp_transport_name_);
4794 if (content_name == *sctp_content_name_) {
4795 return *sctp_transport_name_;
4796 }
4797 }
4798 // Return an empty string if failed to retrieve the transport name.
4799 return "";
4800 }
4801 return channel->transport_name();
4802}
4803
4804void PeerConnection::DestroyRtcpTransport_n(const std::string& transport_name) {
4805 RTC_DCHECK(network_thread()->IsCurrent());
4806 transport_controller_->DestroyDtlsTransport_n(
4807 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
4808}
4809
4810void PeerConnection::RemoveAndDestroyVideoChannel(
4811 cricket::VideoChannel* video_channel) {
4812 auto it =
4813 std::find(video_channels_.begin(), video_channels_.end(), video_channel);
4814 RTC_DCHECK(it != video_channels_.end());
4815 if (it == video_channels_.end()) {
4816 return;
4817 }
4818 video_channels_.erase(it);
4819 DestroyVideoChannel(video_channel);
4820}
4821
4822void PeerConnection::DestroyVideoChannel(cricket::VideoChannel* video_channel) {
4823 // TODO(steveanton): This should take an identifier for the video channel
4824 // since we now support more than one.
4825 OnVideoChannelDestroyed();
4826 RTC_DCHECK(video_channel->rtp_dtls_transport());
4827 const std::string transport_name =
4828 video_channel->rtp_dtls_transport()->transport_name();
4829 const bool need_to_delete_rtcp =
4830 (video_channel->rtcp_dtls_transport() != nullptr);
4831 // The above need to be cached before destroying the video channel so that we
4832 // do not access uninitialized memory.
4833 channel_manager()->DestroyVideoChannel(video_channel);
4834 transport_controller_->DestroyDtlsTransport(
4835 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
4836 if (need_to_delete_rtcp) {
4837 transport_controller_->DestroyDtlsTransport(
4838 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
4839 }
4840}
4841
4842void PeerConnection::RemoveAndDestroyVoiceChannel(
4843 cricket::VoiceChannel* voice_channel) {
4844 auto it =
4845 std::find(voice_channels_.begin(), voice_channels_.end(), voice_channel);
4846 RTC_DCHECK(it != voice_channels_.end());
4847 if (it == voice_channels_.end()) {
4848 return;
4849 }
4850 voice_channels_.erase(it);
4851 DestroyVoiceChannel(voice_channel);
4852}
4853
4854void PeerConnection::DestroyVoiceChannel(cricket::VoiceChannel* voice_channel) {
4855 // TODO(steveanton): This should take an identifier for the voice channel
4856 // since we now support more than one.
4857 OnVoiceChannelDestroyed();
4858 RTC_DCHECK(voice_channel->rtp_dtls_transport());
4859 const std::string transport_name =
4860 voice_channel->rtp_dtls_transport()->transport_name();
4861 const bool need_to_delete_rtcp =
4862 (voice_channel->rtcp_dtls_transport() != nullptr);
4863 // The above need to be cached before destroying the video channel so that we
4864 // do not access uninitialized memory.
4865 channel_manager()->DestroyVoiceChannel(voice_channel);
4866 transport_controller_->DestroyDtlsTransport(
4867 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
4868 if (need_to_delete_rtcp) {
4869 transport_controller_->DestroyDtlsTransport(
4870 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
4871 }
4872}
4873
4874void PeerConnection::DestroyDataChannel() {
4875 OnDataChannelDestroyed();
4876 RTC_DCHECK(rtp_data_channel_->rtp_dtls_transport());
4877 std::string transport_name;
4878 transport_name = rtp_data_channel_->rtp_dtls_transport()->transport_name();
4879 bool need_to_delete_rtcp =
4880 (rtp_data_channel_->rtcp_dtls_transport() != nullptr);
4881 channel_manager()->DestroyRtpDataChannel(rtp_data_channel_);
4882 rtp_data_channel_ = nullptr;
4883 transport_controller_->DestroyDtlsTransport(
4884 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
4885 if (need_to_delete_rtcp) {
4886 transport_controller_->DestroyDtlsTransport(
4887 transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTCP);
4888 }
4889}
4890
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004891} // namespace webrtc