blob: 5284db37fd7675bb65c01af4417f8a20b66783e3 [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
Henrik Kjellander15583c12016-02-10 10:53:12 +010011#include "webrtc/api/peerconnection.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
deadbeefeb459812015-12-15 19:24:43 -080013#include <algorithm>
deadbeef0a6c4ca2015-10-06 11:38:28 -070014#include <cctype> // for isdigit
kwiberg0eb15ed2015-12-17 03:04:15 -080015#include <utility>
16#include <vector>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017
Henrik Kjellander15583c12016-02-10 10:53:12 +010018#include "webrtc/api/audiotrack.h"
19#include "webrtc/api/dtmfsender.h"
20#include "webrtc/api/jsepicecandidate.h"
21#include "webrtc/api/jsepsessiondescription.h"
22#include "webrtc/api/mediaconstraintsinterface.h"
23#include "webrtc/api/mediastream.h"
24#include "webrtc/api/mediastreamobserver.h"
25#include "webrtc/api/mediastreamproxy.h"
26#include "webrtc/api/mediastreamtrackproxy.h"
27#include "webrtc/api/remoteaudiosource.h"
Henrik Kjellander15583c12016-02-10 10:53:12 +010028#include "webrtc/api/rtpreceiver.h"
29#include "webrtc/api/rtpsender.h"
30#include "webrtc/api/streamcollection.h"
perkja3ede6c2016-03-08 01:27:48 +010031#include "webrtc/api/videocapturertracksource.h"
Henrik Kjellander15583c12016-02-10 10:53:12 +010032#include "webrtc/api/videotrack.h"
tfarina5237aaf2015-11-10 23:44:30 -080033#include "webrtc/base/arraysize.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000034#include "webrtc/base/logging.h"
35#include "webrtc/base/stringencode.h"
deadbeefab9b2d12015-10-14 11:33:11 -070036#include "webrtc/base/stringutils.h"
Peter Boström1a9d6152015-12-08 22:15:17 +010037#include "webrtc/base/trace_event.h"
kjellandera96e2d72016-02-04 23:52:28 -080038#include "webrtc/media/sctp/sctpdataengine.h"
tfarina5237aaf2015-11-10 23:44:30 -080039#include "webrtc/p2p/client/basicportallocator.h"
kjellander@webrtc.org9b8df252016-02-12 06:47:59 +010040#include "webrtc/pc/channelmanager.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010041#include "webrtc/system_wrappers/include/field_trial.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000042
43namespace {
44
deadbeefab9b2d12015-10-14 11:33:11 -070045using webrtc::DataChannel;
46using webrtc::MediaConstraintsInterface;
47using webrtc::MediaStreamInterface;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000048using webrtc::PeerConnectionInterface;
deadbeeffac06552015-11-25 11:26:01 -080049using webrtc::RtpSenderInterface;
deadbeefab9b2d12015-10-14 11:33:11 -070050using webrtc::StreamCollection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000051
deadbeefab9b2d12015-10-14 11:33:11 -070052static const char kDefaultStreamLabel[] = "default";
53static const char kDefaultAudioTrackLabel[] = "defaulta0";
54static const char kDefaultVideoTrackLabel[] = "defaultv0";
55
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056// The min number of tokens must present in Turn host uri.
57// e.g. user@turn.example.org
58static const size_t kTurnHostTokensNum = 2;
59// Number of tokens must be preset when TURN uri has transport param.
60static const size_t kTurnTransportTokensNum = 2;
61// The default stun port.
wu@webrtc.org91053e72013-08-10 07:18:04 +000062static const int kDefaultStunPort = 3478;
63static const int kDefaultStunTlsPort = 5349;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000064static const char kTransport[] = "transport";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000065
66// NOTE: Must be in the same order as the ServiceType enum.
deadbeef0a6c4ca2015-10-06 11:38:28 -070067static const char* kValidIceServiceTypes[] = {"stun", "stuns", "turn", "turns"};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000068
zhihuang8f65cdf2016-05-06 18:40:30 -070069// The length of RTCP CNAMEs.
70static const int kRtcpCnameLength = 16;
71
deadbeef0a6c4ca2015-10-06 11:38:28 -070072// NOTE: A loop below assumes that the first value of this enum is 0 and all
73// other values are incremental.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000074enum ServiceType {
deadbeef0a6c4ca2015-10-06 11:38:28 -070075 STUN = 0, // Indicates a STUN server.
76 STUNS, // Indicates a STUN server used with a TLS session.
77 TURN, // Indicates a TURN server
78 TURNS, // Indicates a TURN server used with a TLS session.
79 INVALID, // Unknown.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000080};
tfarina5237aaf2015-11-10 23:44:30 -080081static_assert(INVALID == arraysize(kValidIceServiceTypes),
deadbeef0a6c4ca2015-10-06 11:38:28 -070082 "kValidIceServiceTypes must have as many strings as ServiceType "
83 "has values.");
henrike@webrtc.org28e20752013-07-10 00:45:36 +000084
85enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +000086 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000087 MSG_SET_SESSIONDESCRIPTION_FAILED,
deadbeefab9b2d12015-10-14 11:33:11 -070088 MSG_CREATE_SESSIONDESCRIPTION_FAILED,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000089 MSG_GETSTATS,
deadbeefbd292462015-12-14 18:15:29 -080090 MSG_FREE_DATACHANNELS,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000091};
92
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000093struct SetSessionDescriptionMsg : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000094 explicit SetSessionDescriptionMsg(
95 webrtc::SetSessionDescriptionObserver* observer)
96 : observer(observer) {
97 }
98
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000099 rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000100 std::string error;
101};
102
deadbeefab9b2d12015-10-14 11:33:11 -0700103struct CreateSessionDescriptionMsg : public rtc::MessageData {
104 explicit CreateSessionDescriptionMsg(
105 webrtc::CreateSessionDescriptionObserver* observer)
106 : observer(observer) {}
107
108 rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserver> observer;
109 std::string error;
110};
111
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000112struct GetStatsMsg : public rtc::MessageData {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000113 GetStatsMsg(webrtc::StatsObserver* observer,
114 webrtc::MediaStreamTrackInterface* track)
115 : observer(observer), track(track) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000116 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000117 rtc::scoped_refptr<webrtc::StatsObserver> observer;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000118 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000119};
120
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000121// |in_str| should be of format
122// stunURI = scheme ":" stun-host [ ":" stun-port ]
123// scheme = "stun" / "stuns"
124// stun-host = IP-literal / IPv4address / reg-name
125// stun-port = *DIGIT
deadbeef0a6c4ca2015-10-06 11:38:28 -0700126//
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000127// draft-petithuguenin-behave-turn-uris-01
128// turnURI = scheme ":" turn-host [ ":" turn-port ]
129// turn-host = username@IP-literal / IPv4address / reg-name
130bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
131 ServiceType* service_type,
132 std::string* hostname) {
Tommi77d444a2015-04-24 15:38:38 +0200133 const std::string::size_type colonpos = in_str.find(':');
deadbeef0a6c4ca2015-10-06 11:38:28 -0700134 if (colonpos == std::string::npos) {
135 LOG(LS_WARNING) << "Missing ':' in ICE URI: " << in_str;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000136 return false;
137 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700138 if ((colonpos + 1) == in_str.length()) {
139 LOG(LS_WARNING) << "Empty hostname in ICE URI: " << in_str;
140 return false;
141 }
142 *service_type = INVALID;
tfarina5237aaf2015-11-10 23:44:30 -0800143 for (size_t i = 0; i < arraysize(kValidIceServiceTypes); ++i) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700144 if (in_str.compare(0, colonpos, kValidIceServiceTypes[i]) == 0) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000145 *service_type = static_cast<ServiceType>(i);
146 break;
147 }
148 }
149 if (*service_type == INVALID) {
150 return false;
151 }
152 *hostname = in_str.substr(colonpos + 1, std::string::npos);
153 return true;
154}
155
deadbeef0a6c4ca2015-10-06 11:38:28 -0700156bool ParsePort(const std::string& in_str, int* port) {
157 // Make sure port only contains digits. FromString doesn't check this.
158 for (const char& c : in_str) {
159 if (!std::isdigit(c)) {
160 return false;
161 }
162 }
163 return rtc::FromString(in_str, port);
164}
165
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000166// This method parses IPv6 and IPv4 literal strings, along with hostnames in
167// standard hostname:port format.
168// Consider following formats as correct.
169// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700170// |hostname|, |[IPv6 address]|, |IPv4 address|.
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000171bool ParseHostnameAndPortFromString(const std::string& in_str,
172 std::string* host,
173 int* port) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700174 RTC_DCHECK(host->empty());
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000175 if (in_str.at(0) == '[') {
176 std::string::size_type closebracket = in_str.rfind(']');
177 if (closebracket != std::string::npos) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000178 std::string::size_type colonpos = in_str.find(':', closebracket);
179 if (std::string::npos != colonpos) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700180 if (!ParsePort(in_str.substr(closebracket + 2, std::string::npos),
181 port)) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000182 return false;
183 }
184 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700185 *host = in_str.substr(1, closebracket - 1);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000186 } else {
187 return false;
188 }
189 } else {
190 std::string::size_type colonpos = in_str.find(':');
191 if (std::string::npos != colonpos) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700192 if (!ParsePort(in_str.substr(colonpos + 1, std::string::npos), port)) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000193 return false;
194 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700195 *host = in_str.substr(0, colonpos);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000196 } else {
197 *host = in_str;
198 }
199 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700200 return !host->empty();
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000201}
202
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800203// Adds a STUN or TURN server to the appropriate list,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700204// by parsing |url| and using the username/password in |server|.
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200205bool ParseIceServerUrl(const PeerConnectionInterface::IceServer& server,
206 const std::string& url,
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800207 cricket::ServerAddresses* stun_servers,
208 std::vector<cricket::RelayServerConfig>* turn_servers) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000209 // draft-nandakumar-rtcweb-stun-uri-01
210 // stunURI = scheme ":" stun-host [ ":" stun-port ]
211 // scheme = "stun" / "stuns"
212 // stun-host = IP-literal / IPv4address / reg-name
213 // stun-port = *DIGIT
214
215 // draft-petithuguenin-behave-turn-uris-01
216 // turnURI = scheme ":" turn-host [ ":" turn-port ]
217 // [ "?transport=" transport ]
218 // scheme = "turn" / "turns"
219 // transport = "udp" / "tcp" / transport-ext
220 // transport-ext = 1*unreserved
221 // turn-host = IP-literal / IPv4address / reg-name
222 // turn-port = *DIGIT
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800223 RTC_DCHECK(stun_servers != nullptr);
224 RTC_DCHECK(turn_servers != nullptr);
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200225 std::vector<std::string> tokens;
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800226 cricket::ProtocolType turn_transport_type = cricket::PROTO_UDP;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700227 RTC_DCHECK(!url.empty());
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200228 rtc::tokenize(url, '?', &tokens);
229 std::string uri_without_transport = tokens[0];
230 // Let's look into transport= param, if it exists.
231 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
232 std::string uri_transport_param = tokens[1];
233 rtc::tokenize(uri_transport_param, '=', &tokens);
234 if (tokens[0] == kTransport) {
235 // As per above grammar transport param will be consist of lower case
236 // letters.
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800237 if (!cricket::StringToProto(tokens[1].c_str(), &turn_transport_type) ||
238 (turn_transport_type != cricket::PROTO_UDP &&
239 turn_transport_type != cricket::PROTO_TCP)) {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200240 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
deadbeef0a6c4ca2015-10-06 11:38:28 -0700241 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000242 }
243 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200244 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000245
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200246 std::string hoststring;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700247 ServiceType service_type;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200248 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
249 &service_type,
250 &hoststring)) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700251 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: " << url;
252 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200253 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000254
deadbeef0a6c4ca2015-10-06 11:38:28 -0700255 // GetServiceTypeAndHostnameFromUri should never give an empty hoststring
256 RTC_DCHECK(!hoststring.empty());
Tommi77d444a2015-04-24 15:38:38 +0200257
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200258 // Let's break hostname.
259 tokens.clear();
deadbeef0a6c4ca2015-10-06 11:38:28 -0700260 rtc::tokenize_with_empty_tokens(hoststring, '@', &tokens);
261
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200262 std::string username(server.username);
deadbeef0a6c4ca2015-10-06 11:38:28 -0700263 if (tokens.size() > kTurnHostTokensNum) {
264 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring;
265 return false;
266 }
267 if (tokens.size() == kTurnHostTokensNum) {
268 if (tokens[0].empty() || tokens[1].empty()) {
269 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring;
270 return false;
271 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200272 username.assign(rtc::s_url_decode(tokens[0]));
273 hoststring = tokens[1];
274 } else {
275 hoststring = tokens[0];
276 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000277
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200278 int port = kDefaultStunPort;
279 if (service_type == TURNS) {
280 port = kDefaultStunTlsPort;
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800281 turn_transport_type = cricket::PROTO_TCP;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200282 }
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000283
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200284 std::string address;
285 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700286 LOG(WARNING) << "Invalid hostname format: " << uri_without_transport;
287 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200288 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000289
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200290 if (port <= 0 || port > 0xffff) {
291 LOG(WARNING) << "Invalid port: " << port;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700292 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200293 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000294
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200295 switch (service_type) {
296 case STUN:
297 case STUNS:
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800298 stun_servers->insert(rtc::SocketAddress(address, port));
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200299 break;
300 case TURN:
301 case TURNS: {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200302 bool secure = (service_type == TURNS);
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800303 turn_servers->push_back(
304 cricket::RelayServerConfig(address, port, username, server.password,
305 turn_transport_type, secure));
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200306 break;
307 }
308 case INVALID:
309 default:
310 LOG(WARNING) << "Configuration not supported: " << url;
311 return false;
312 }
313 return true;
314}
315
deadbeefab9b2d12015-10-14 11:33:11 -0700316// Check if we can send |new_stream| on a PeerConnection.
317bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
318 webrtc::MediaStreamInterface* new_stream) {
319 if (!new_stream || !current_streams) {
320 return false;
321 }
322 if (current_streams->find(new_stream->label()) != nullptr) {
323 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
324 << " is already added.";
325 return false;
326 }
327 return true;
328}
329
330bool MediaContentDirectionHasSend(cricket::MediaContentDirection dir) {
331 return dir == cricket::MD_SENDONLY || dir == cricket::MD_SENDRECV;
332}
333
deadbeef5e97fb52015-10-15 12:49:08 -0700334// If the direction is "recvonly" or "inactive", treat the description
335// as containing no streams.
336// See: https://code.google.com/p/webrtc/issues/detail?id=5054
337std::vector<cricket::StreamParams> GetActiveStreams(
338 const cricket::MediaContentDescription* desc) {
339 return MediaContentDirectionHasSend(desc->direction())
340 ? desc->streams()
341 : std::vector<cricket::StreamParams>();
342}
343
deadbeefab9b2d12015-10-14 11:33:11 -0700344bool IsValidOfferToReceiveMedia(int value) {
345 typedef PeerConnectionInterface::RTCOfferAnswerOptions Options;
346 return (value >= Options::kUndefined) &&
347 (value <= Options::kMaxOfferToReceiveMedia);
348}
349
350// Add the stream and RTP data channel info to |session_options|.
deadbeeffac06552015-11-25 11:26:01 -0800351void AddSendStreams(
352 cricket::MediaSessionOptions* session_options,
353 const std::vector<rtc::scoped_refptr<RtpSenderInterface>>& senders,
354 const std::map<std::string, rtc::scoped_refptr<DataChannel>>&
355 rtp_data_channels) {
deadbeefab9b2d12015-10-14 11:33:11 -0700356 session_options->streams.clear();
deadbeeffac06552015-11-25 11:26:01 -0800357 for (const auto& sender : senders) {
358 session_options->AddSendStream(sender->media_type(), sender->id(),
359 sender->stream_id());
deadbeefab9b2d12015-10-14 11:33:11 -0700360 }
361
362 // Check for data channels.
363 for (const auto& kv : rtp_data_channels) {
364 const DataChannel* channel = kv.second;
365 if (channel->state() == DataChannel::kConnecting ||
366 channel->state() == DataChannel::kOpen) {
367 // |streamid| and |sync_label| are both set to the DataChannel label
368 // here so they can be signaled the same way as MediaStreams and Tracks.
369 // For MediaStreams, the sync_label is the MediaStream label and the
370 // track label is the same as |streamid|.
371 const std::string& streamid = channel->label();
372 const std::string& sync_label = channel->label();
373 session_options->AddSendStream(cricket::MEDIA_TYPE_DATA, streamid,
374 sync_label);
375 }
376 }
377}
378
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700379uint32_t ConvertIceTransportTypeToCandidateFilter(
380 PeerConnectionInterface::IceTransportsType type) {
381 switch (type) {
382 case PeerConnectionInterface::kNone:
383 return cricket::CF_NONE;
384 case PeerConnectionInterface::kRelay:
385 return cricket::CF_RELAY;
386 case PeerConnectionInterface::kNoHost:
387 return (cricket::CF_ALL & ~cricket::CF_HOST);
388 case PeerConnectionInterface::kAll:
389 return cricket::CF_ALL;
390 default:
391 ASSERT(false);
392 }
393 return cricket::CF_NONE;
394}
395
deadbeef0a6c4ca2015-10-06 11:38:28 -0700396} // namespace
397
398namespace webrtc {
399
zhihuang8f65cdf2016-05-06 18:40:30 -0700400// Generate a RTCP CNAME when a PeerConnection is created.
401std::string GenerateRtcpCname() {
402 std::string cname;
403 if (!rtc::CreateRandomString(kRtcpCnameLength, &cname)) {
404 LOG(LS_ERROR) << "Failed to generate CNAME.";
405 RTC_DCHECK(false);
406 }
407 return cname;
408}
409
htaa2a49d92016-03-04 02:51:39 -0800410bool ExtractMediaSessionOptions(
deadbeefab9b2d12015-10-14 11:33:11 -0700411 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
htaaac2dea2016-03-10 13:35:55 -0800412 bool is_offer,
deadbeefab9b2d12015-10-14 11:33:11 -0700413 cricket::MediaSessionOptions* session_options) {
414 typedef PeerConnectionInterface::RTCOfferAnswerOptions RTCOfferAnswerOptions;
415 if (!IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_audio) ||
416 !IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_video)) {
417 return false;
418 }
419
htaaac2dea2016-03-10 13:35:55 -0800420 // If constraints don't prevent us, we always accept video.
deadbeefc80741f2015-10-22 13:14:45 -0700421 if (rtc_options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) {
deadbeefab9b2d12015-10-14 11:33:11 -0700422 session_options->recv_audio = (rtc_options.offer_to_receive_audio > 0);
htaaac2dea2016-03-10 13:35:55 -0800423 } else {
424 session_options->recv_audio = true;
deadbeefab9b2d12015-10-14 11:33:11 -0700425 }
htaaac2dea2016-03-10 13:35:55 -0800426 // For offers, we only offer video if we have it or it's forced by options.
427 // For answers, we will always accept video (if offered).
deadbeefc80741f2015-10-22 13:14:45 -0700428 if (rtc_options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) {
deadbeefab9b2d12015-10-14 11:33:11 -0700429 session_options->recv_video = (rtc_options.offer_to_receive_video > 0);
htaaac2dea2016-03-10 13:35:55 -0800430 } else if (is_offer) {
431 session_options->recv_video = false;
432 } else {
433 session_options->recv_video = true;
deadbeefab9b2d12015-10-14 11:33:11 -0700434 }
435
436 session_options->vad_enabled = rtc_options.voice_activity_detection;
deadbeefc80741f2015-10-22 13:14:45 -0700437 session_options->bundle_enabled = rtc_options.use_rtp_mux;
deadbeef0ed85b22016-02-23 17:24:52 -0800438 for (auto& kv : session_options->transport_options) {
439 kv.second.ice_restart = rtc_options.ice_restart;
440 }
deadbeefab9b2d12015-10-14 11:33:11 -0700441
442 return true;
443}
444
445bool ParseConstraintsForAnswer(const MediaConstraintsInterface* constraints,
446 cricket::MediaSessionOptions* session_options) {
447 bool value = false;
448 size_t mandatory_constraints_satisfied = 0;
449
450 // kOfferToReceiveAudio defaults to true according to spec.
451 if (!FindConstraint(constraints,
452 MediaConstraintsInterface::kOfferToReceiveAudio, &value,
453 &mandatory_constraints_satisfied) ||
454 value) {
455 session_options->recv_audio = true;
456 }
457
458 // kOfferToReceiveVideo defaults to false according to spec. But
459 // if it is an answer and video is offered, we should still accept video
460 // per default.
461 value = false;
462 if (!FindConstraint(constraints,
463 MediaConstraintsInterface::kOfferToReceiveVideo, &value,
464 &mandatory_constraints_satisfied) ||
465 value) {
466 session_options->recv_video = true;
467 }
468
469 if (FindConstraint(constraints,
470 MediaConstraintsInterface::kVoiceActivityDetection, &value,
471 &mandatory_constraints_satisfied)) {
472 session_options->vad_enabled = value;
473 }
474
475 if (FindConstraint(constraints, MediaConstraintsInterface::kUseRtpMux, &value,
476 &mandatory_constraints_satisfied)) {
477 session_options->bundle_enabled = value;
478 } else {
479 // kUseRtpMux defaults to true according to spec.
480 session_options->bundle_enabled = true;
481 }
deadbeefab9b2d12015-10-14 11:33:11 -0700482
deadbeef0ed85b22016-02-23 17:24:52 -0800483 bool ice_restart = false;
deadbeefab9b2d12015-10-14 11:33:11 -0700484 if (FindConstraint(constraints, MediaConstraintsInterface::kIceRestart,
485 &value, &mandatory_constraints_satisfied)) {
deadbeefab9b2d12015-10-14 11:33:11 -0700486 // kIceRestart defaults to false according to spec.
deadbeef0ed85b22016-02-23 17:24:52 -0800487 ice_restart = true;
488 }
489 for (auto& kv : session_options->transport_options) {
490 kv.second.ice_restart = ice_restart;
deadbeefab9b2d12015-10-14 11:33:11 -0700491 }
492
493 if (!constraints) {
494 return true;
495 }
496 return mandatory_constraints_satisfied == constraints->GetMandatory().size();
497}
498
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200499bool ParseIceServers(const PeerConnectionInterface::IceServers& servers,
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800500 cricket::ServerAddresses* stun_servers,
501 std::vector<cricket::RelayServerConfig>* turn_servers) {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200502 for (const webrtc::PeerConnectionInterface::IceServer& server : servers) {
503 if (!server.urls.empty()) {
504 for (const std::string& url : server.urls) {
Joachim Bauchd935f912015-05-29 22:14:21 +0200505 if (url.empty()) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700506 LOG(LS_ERROR) << "Empty uri.";
507 return false;
Joachim Bauchd935f912015-05-29 22:14:21 +0200508 }
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800509 if (!ParseIceServerUrl(server, url, stun_servers, turn_servers)) {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200510 return false;
511 }
512 }
513 } else if (!server.uri.empty()) {
514 // Fallback to old .uri if new .urls isn't present.
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800515 if (!ParseIceServerUrl(server, server.uri, stun_servers, turn_servers)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000516 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200517 }
518 } else {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700519 LOG(LS_ERROR) << "Empty uri.";
520 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000521 }
522 }
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800523 // Candidates must have unique priorities, so that connectivity checks
524 // are performed in a well-defined order.
525 int priority = static_cast<int>(turn_servers->size() - 1);
526 for (cricket::RelayServerConfig& turn_server : *turn_servers) {
527 // First in the list gets highest priority.
528 turn_server.priority = priority--;
529 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000530 return true;
531}
532
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000533PeerConnection::PeerConnection(PeerConnectionFactory* factory)
534 : factory_(factory),
535 observer_(NULL),
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000536 uma_observer_(NULL),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000537 signaling_state_(kStable),
538 ice_state_(kIceNew),
539 ice_connection_state_(kIceConnectionNew),
deadbeefab9b2d12015-10-14 11:33:11 -0700540 ice_gathering_state_(kIceGatheringNew),
zhihuang8f65cdf2016-05-06 18:40:30 -0700541 rtcp_cname_(GenerateRtcpCname()),
deadbeefab9b2d12015-10-14 11:33:11 -0700542 local_streams_(StreamCollection::Create()),
543 remote_streams_(StreamCollection::Create()) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000544
545PeerConnection::~PeerConnection() {
Peter Boström1a9d6152015-12-08 22:15:17 +0100546 TRACE_EVENT0("webrtc", "PeerConnection::~PeerConnection");
deadbeef0a6c4ca2015-10-06 11:38:28 -0700547 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeef70ab1a12015-09-28 16:53:55 -0700548 // Need to detach RTP senders/receivers from WebRtcSession,
549 // since it's about to be destroyed.
550 for (const auto& sender : senders_) {
551 sender->Stop();
552 }
553 for (const auto& receiver : receivers_) {
554 receiver->Stop();
555 }
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700556 // Destroy stats_ because it depends on session_.
557 stats_.reset(nullptr);
558 // Now destroy session_ before destroying other members,
559 // because its destruction fires signals (such as VoiceChannelDestroyed)
560 // which will trigger some final actions in PeerConnection...
561 session_.reset(nullptr);
562 // port_allocator_ lives on the worker thread and should be destroyed there.
563 worker_thread()->Invoke<void>([this] { port_allocator_.reset(nullptr); });
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000564}
565
566bool PeerConnection::Initialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000567 const PeerConnectionInterface::RTCConfiguration& configuration,
kwibergd1fe2812016-04-27 06:47:29 -0700568 std::unique_ptr<cricket::PortAllocator> allocator,
569 std::unique_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
deadbeef653b8e02015-11-11 12:55:10 -0800570 PeerConnectionObserver* observer) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100571 TRACE_EVENT0("webrtc", "PeerConnection::Initialize");
deadbeef653b8e02015-11-11 12:55:10 -0800572 RTC_DCHECK(observer != nullptr);
573 if (!observer) {
574 return false;
575 }
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000576 observer_ = observer;
577
kwiberg0eb15ed2015-12-17 03:04:15 -0800578 port_allocator_ = std::move(allocator);
deadbeef653b8e02015-11-11 12:55:10 -0800579
Taylor Brandstettera1c30352016-05-13 08:15:11 -0700580 // The port allocator lives on the worker thread and should be initialized
581 // there.
582 if (!worker_thread()->Invoke<bool>(rtc::Bind(
583 &PeerConnection::InitializePortAllocator_w, this, configuration))) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000584 return false;
585 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586
nissec36b31b2016-04-11 23:25:29 -0700587 media_controller_.reset(
588 factory_->CreateMediaController(configuration.media_config));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000589
stefanc1aeaf02015-10-15 07:26:07 -0700590 session_.reset(
591 new WebRtcSession(media_controller_.get(), factory_->signaling_thread(),
592 factory_->worker_thread(), port_allocator_.get()));
deadbeefab9b2d12015-10-14 11:33:11 -0700593 stats_.reset(new StatsCollector(this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000594
595 // Initialize the WebRtcSession. It creates transport channels etc.
htaa2a49d92016-03-04 02:51:39 -0800596 if (!session_->Initialize(factory_->options(), std::move(dtls_identity_store),
597 configuration)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 return false;
deadbeefab9b2d12015-10-14 11:33:11 -0700599 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000600
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000601 // Register PeerConnection as receiver of local ice candidates.
602 // All the callbacks will be posted to the application from PeerConnection.
603 session_->RegisterIceObserver(this);
604 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
deadbeefab9b2d12015-10-14 11:33:11 -0700605 session_->SignalVoiceChannelDestroyed.connect(
606 this, &PeerConnection::OnVoiceChannelDestroyed);
607 session_->SignalVideoChannelDestroyed.connect(
608 this, &PeerConnection::OnVideoChannelDestroyed);
609 session_->SignalDataChannelCreated.connect(
610 this, &PeerConnection::OnDataChannelCreated);
611 session_->SignalDataChannelDestroyed.connect(
612 this, &PeerConnection::OnDataChannelDestroyed);
613 session_->SignalDataChannelOpenMessage.connect(
614 this, &PeerConnection::OnDataChannelOpenMessage);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000615 return true;
616}
617
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000618rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619PeerConnection::local_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -0700620 return local_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000621}
622
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000623rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000624PeerConnection::remote_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -0700625 return remote_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000626}
627
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +0000628bool PeerConnection::AddStream(MediaStreamInterface* local_stream) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100629 TRACE_EVENT0("webrtc", "PeerConnection::AddStream");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000630 if (IsClosed()) {
631 return false;
632 }
deadbeefab9b2d12015-10-14 11:33:11 -0700633 if (!CanAddLocalMediaStream(local_streams_, local_stream)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000634 return false;
635 }
deadbeefab9b2d12015-10-14 11:33:11 -0700636
637 local_streams_->AddStream(local_stream);
deadbeefeb459812015-12-15 19:24:43 -0800638 MediaStreamObserver* observer = new MediaStreamObserver(local_stream);
639 observer->SignalAudioTrackAdded.connect(this,
640 &PeerConnection::OnAudioTrackAdded);
641 observer->SignalAudioTrackRemoved.connect(
642 this, &PeerConnection::OnAudioTrackRemoved);
643 observer->SignalVideoTrackAdded.connect(this,
644 &PeerConnection::OnVideoTrackAdded);
645 observer->SignalVideoTrackRemoved.connect(
646 this, &PeerConnection::OnVideoTrackRemoved);
kwibergd1fe2812016-04-27 06:47:29 -0700647 stream_observers_.push_back(std::unique_ptr<MediaStreamObserver>(observer));
deadbeefab9b2d12015-10-14 11:33:11 -0700648
deadbeefab9b2d12015-10-14 11:33:11 -0700649 for (const auto& track : local_stream->GetAudioTracks()) {
deadbeefeb459812015-12-15 19:24:43 -0800650 OnAudioTrackAdded(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -0700651 }
652 for (const auto& track : local_stream->GetVideoTracks()) {
deadbeefeb459812015-12-15 19:24:43 -0800653 OnVideoTrackAdded(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -0700654 }
655
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000656 stats_->AddStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000657 observer_->OnRenegotiationNeeded();
658 return true;
659}
660
661void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100662 TRACE_EVENT0("webrtc", "PeerConnection::RemoveStream");
deadbeefab9b2d12015-10-14 11:33:11 -0700663 for (const auto& track : local_stream->GetAudioTracks()) {
deadbeefeb459812015-12-15 19:24:43 -0800664 OnAudioTrackRemoved(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -0700665 }
666 for (const auto& track : local_stream->GetVideoTracks()) {
deadbeefeb459812015-12-15 19:24:43 -0800667 OnVideoTrackRemoved(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -0700668 }
669
670 local_streams_->RemoveStream(local_stream);
deadbeefeb459812015-12-15 19:24:43 -0800671 stream_observers_.erase(
672 std::remove_if(
673 stream_observers_.begin(), stream_observers_.end(),
kwibergd1fe2812016-04-27 06:47:29 -0700674 [local_stream](const std::unique_ptr<MediaStreamObserver>& observer) {
deadbeefeb459812015-12-15 19:24:43 -0800675 return observer->stream()->label().compare(local_stream->label()) ==
676 0;
677 }),
678 stream_observers_.end());
deadbeefab9b2d12015-10-14 11:33:11 -0700679
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000680 if (IsClosed()) {
681 return;
682 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000683 observer_->OnRenegotiationNeeded();
684}
685
deadbeefe1f9d832016-01-14 15:35:42 -0800686rtc::scoped_refptr<RtpSenderInterface> PeerConnection::AddTrack(
687 MediaStreamTrackInterface* track,
688 std::vector<MediaStreamInterface*> streams) {
689 TRACE_EVENT0("webrtc", "PeerConnection::AddTrack");
690 if (IsClosed()) {
691 return nullptr;
692 }
693 if (streams.size() >= 2) {
694 LOG(LS_ERROR)
695 << "Adding a track with two streams is not currently supported.";
696 return nullptr;
697 }
698 // TODO(deadbeef): Support adding a track to two different senders.
699 if (FindSenderForTrack(track) != senders_.end()) {
700 LOG(LS_ERROR) << "Sender for track " << track->id() << " already exists.";
701 return nullptr;
702 }
703
704 // TODO(deadbeef): Support adding a track to multiple streams.
705 rtc::scoped_refptr<RtpSenderInterface> new_sender;
706 if (track->kind() == MediaStreamTrackInterface::kAudioKind) {
707 new_sender = RtpSenderProxy::Create(
708 signaling_thread(),
709 new AudioRtpSender(static_cast<AudioTrackInterface*>(track),
710 session_.get(), stats_.get()));
711 if (!streams.empty()) {
712 new_sender->set_stream_id(streams[0]->label());
713 }
714 const TrackInfo* track_info = FindTrackInfo(
715 local_audio_tracks_, new_sender->stream_id(), track->id());
716 if (track_info) {
717 new_sender->SetSsrc(track_info->ssrc);
718 }
719 } else if (track->kind() == MediaStreamTrackInterface::kVideoKind) {
720 new_sender = RtpSenderProxy::Create(
721 signaling_thread(),
722 new VideoRtpSender(static_cast<VideoTrackInterface*>(track),
723 session_.get()));
724 if (!streams.empty()) {
725 new_sender->set_stream_id(streams[0]->label());
726 }
727 const TrackInfo* track_info = FindTrackInfo(
728 local_video_tracks_, new_sender->stream_id(), track->id());
729 if (track_info) {
730 new_sender->SetSsrc(track_info->ssrc);
731 }
732 } else {
733 LOG(LS_ERROR) << "CreateSender called with invalid kind: " << track->kind();
734 return rtc::scoped_refptr<RtpSenderInterface>();
735 }
736
737 senders_.push_back(new_sender);
738 observer_->OnRenegotiationNeeded();
739 return new_sender;
740}
741
742bool PeerConnection::RemoveTrack(RtpSenderInterface* sender) {
743 TRACE_EVENT0("webrtc", "PeerConnection::RemoveTrack");
744 if (IsClosed()) {
745 return false;
746 }
747
748 auto it = std::find(senders_.begin(), senders_.end(), sender);
749 if (it == senders_.end()) {
750 LOG(LS_ERROR) << "Couldn't find sender " << sender->id() << " to remove.";
751 return false;
752 }
753 (*it)->Stop();
754 senders_.erase(it);
755
756 observer_->OnRenegotiationNeeded();
757 return true;
758}
759
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000760rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000761 AudioTrackInterface* track) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100762 TRACE_EVENT0("webrtc", "PeerConnection::CreateDtmfSender");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000763 if (!track) {
764 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
765 return NULL;
766 }
deadbeefab9b2d12015-10-14 11:33:11 -0700767 if (!local_streams_->FindAudioTrack(track->id())) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
769 return NULL;
770 }
771
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000772 rtc::scoped_refptr<DtmfSenderInterface> sender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000773 DtmfSender::Create(track, signaling_thread(), session_.get()));
774 if (!sender.get()) {
775 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
776 return NULL;
777 }
778 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
779}
780
deadbeeffac06552015-11-25 11:26:01 -0800781rtc::scoped_refptr<RtpSenderInterface> PeerConnection::CreateSender(
deadbeefbd7d8f72015-12-18 16:58:44 -0800782 const std::string& kind,
783 const std::string& stream_id) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100784 TRACE_EVENT0("webrtc", "PeerConnection::CreateSender");
deadbeefe1f9d832016-01-14 15:35:42 -0800785 rtc::scoped_refptr<RtpSenderInterface> new_sender;
deadbeeffac06552015-11-25 11:26:01 -0800786 if (kind == MediaStreamTrackInterface::kAudioKind) {
deadbeefe1f9d832016-01-14 15:35:42 -0800787 new_sender = RtpSenderProxy::Create(
788 signaling_thread(), new AudioRtpSender(session_.get(), stats_.get()));
deadbeeffac06552015-11-25 11:26:01 -0800789 } else if (kind == MediaStreamTrackInterface::kVideoKind) {
deadbeefe1f9d832016-01-14 15:35:42 -0800790 new_sender = RtpSenderProxy::Create(signaling_thread(),
791 new VideoRtpSender(session_.get()));
deadbeeffac06552015-11-25 11:26:01 -0800792 } else {
793 LOG(LS_ERROR) << "CreateSender called with invalid kind: " << kind;
deadbeefe1f9d832016-01-14 15:35:42 -0800794 return new_sender;
deadbeeffac06552015-11-25 11:26:01 -0800795 }
deadbeefbd7d8f72015-12-18 16:58:44 -0800796 if (!stream_id.empty()) {
797 new_sender->set_stream_id(stream_id);
798 }
deadbeeffac06552015-11-25 11:26:01 -0800799 senders_.push_back(new_sender);
deadbeefe1f9d832016-01-14 15:35:42 -0800800 return new_sender;
deadbeeffac06552015-11-25 11:26:01 -0800801}
802
deadbeef70ab1a12015-09-28 16:53:55 -0700803std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders()
804 const {
deadbeefe1f9d832016-01-14 15:35:42 -0800805 return senders_;
deadbeef70ab1a12015-09-28 16:53:55 -0700806}
807
808std::vector<rtc::scoped_refptr<RtpReceiverInterface>>
809PeerConnection::GetReceivers() const {
deadbeefe1f9d832016-01-14 15:35:42 -0800810 return receivers_;
deadbeef70ab1a12015-09-28 16:53:55 -0700811}
812
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000813bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000814 MediaStreamTrackInterface* track,
815 StatsOutputLevel level) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100816 TRACE_EVENT0("webrtc", "PeerConnection::GetStats");
deadbeef0a6c4ca2015-10-06 11:38:28 -0700817 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000818 if (!VERIFY(observer != NULL)) {
819 LOG(LS_ERROR) << "GetStats - observer is NULL.";
820 return false;
821 }
822
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000823 stats_->UpdateStats(level);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000824 signaling_thread()->Post(this, MSG_GETSTATS,
825 new GetStatsMsg(observer, track));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000826 return true;
827}
828
829PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
830 return signaling_state_;
831}
832
833PeerConnectionInterface::IceState PeerConnection::ice_state() {
834 return ice_state_;
835}
836
837PeerConnectionInterface::IceConnectionState
838PeerConnection::ice_connection_state() {
839 return ice_connection_state_;
840}
841
842PeerConnectionInterface::IceGatheringState
843PeerConnection::ice_gathering_state() {
844 return ice_gathering_state_;
845}
846
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000847rtc::scoped_refptr<DataChannelInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000848PeerConnection::CreateDataChannel(
849 const std::string& label,
850 const DataChannelInit* config) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100851 TRACE_EVENT0("webrtc", "PeerConnection::CreateDataChannel");
deadbeefab9b2d12015-10-14 11:33:11 -0700852 bool first_datachannel = !HasDataChannels();
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000853
kwibergd1fe2812016-04-27 06:47:29 -0700854 std::unique_ptr<InternalDataChannelInit> internal_config;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000855 if (config) {
856 internal_config.reset(new InternalDataChannelInit(*config));
857 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000858 rtc::scoped_refptr<DataChannelInterface> channel(
deadbeefab9b2d12015-10-14 11:33:11 -0700859 InternalCreateDataChannel(label, internal_config.get()));
860 if (!channel.get()) {
861 return nullptr;
862 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000863
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000864 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
865 // the first SCTP DataChannel.
866 if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
867 observer_->OnRenegotiationNeeded();
868 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000869
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000870 return DataChannelProxy::Create(signaling_thread(), channel.get());
871}
872
873void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
874 const MediaConstraintsInterface* constraints) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100875 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer");
deadbeefab9b2d12015-10-14 11:33:11 -0700876 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000877 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
878 return;
879 }
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000880 RTCOfferAnswerOptions options;
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000881
882 bool value;
883 size_t mandatory_constraints = 0;
884
885 if (FindConstraint(constraints,
886 MediaConstraintsInterface::kOfferToReceiveAudio,
887 &value,
888 &mandatory_constraints)) {
889 options.offer_to_receive_audio =
890 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
891 }
892
893 if (FindConstraint(constraints,
894 MediaConstraintsInterface::kOfferToReceiveVideo,
895 &value,
896 &mandatory_constraints)) {
897 options.offer_to_receive_video =
898 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
899 }
900
901 if (FindConstraint(constraints,
902 MediaConstraintsInterface::kVoiceActivityDetection,
903 &value,
904 &mandatory_constraints)) {
905 options.voice_activity_detection = value;
906 }
907
908 if (FindConstraint(constraints,
909 MediaConstraintsInterface::kIceRestart,
910 &value,
911 &mandatory_constraints)) {
912 options.ice_restart = value;
913 }
914
915 if (FindConstraint(constraints,
916 MediaConstraintsInterface::kUseRtpMux,
917 &value,
918 &mandatory_constraints)) {
919 options.use_rtp_mux = value;
920 }
921
922 CreateOffer(observer, options);
923}
924
925void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
926 const RTCOfferAnswerOptions& options) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100927 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer");
deadbeefab9b2d12015-10-14 11:33:11 -0700928 if (!VERIFY(observer != nullptr)) {
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000929 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
930 return;
931 }
deadbeefab9b2d12015-10-14 11:33:11 -0700932
933 cricket::MediaSessionOptions session_options;
934 if (!GetOptionsForOffer(options, &session_options)) {
935 std::string error = "CreateOffer called with invalid options.";
936 LOG(LS_ERROR) << error;
937 PostCreateSessionDescriptionFailure(observer, error);
938 return;
939 }
940
941 session_->CreateOffer(observer, options, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000942}
943
944void PeerConnection::CreateAnswer(
945 CreateSessionDescriptionObserver* observer,
946 const MediaConstraintsInterface* constraints) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100947 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer");
deadbeefab9b2d12015-10-14 11:33:11 -0700948 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000949 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
950 return;
951 }
deadbeefab9b2d12015-10-14 11:33:11 -0700952
953 cricket::MediaSessionOptions session_options;
954 if (!GetOptionsForAnswer(constraints, &session_options)) {
955 std::string error = "CreateAnswer called with invalid constraints.";
956 LOG(LS_ERROR) << error;
957 PostCreateSessionDescriptionFailure(observer, error);
958 return;
959 }
960
htaa2a49d92016-03-04 02:51:39 -0800961 session_->CreateAnswer(observer, session_options);
962}
963
964void PeerConnection::CreateAnswer(CreateSessionDescriptionObserver* observer,
965 const RTCOfferAnswerOptions& options) {
966 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer");
967 if (!VERIFY(observer != nullptr)) {
968 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
969 return;
970 }
971
972 cricket::MediaSessionOptions session_options;
973 if (!GetOptionsForAnswer(options, &session_options)) {
974 std::string error = "CreateAnswer called with invalid options.";
975 LOG(LS_ERROR) << error;
976 PostCreateSessionDescriptionFailure(observer, error);
977 return;
978 }
979
980 session_->CreateAnswer(observer, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000981}
982
983void PeerConnection::SetLocalDescription(
984 SetSessionDescriptionObserver* observer,
985 SessionDescriptionInterface* desc) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100986 TRACE_EVENT0("webrtc", "PeerConnection::SetLocalDescription");
deadbeefab9b2d12015-10-14 11:33:11 -0700987 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000988 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
989 return;
990 }
991 if (!desc) {
992 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
993 return;
994 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000995 // Update stats here so that we have the most recent stats for tracks and
996 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000997 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000998 std::string error;
999 if (!session_->SetLocalDescription(desc, &error)) {
1000 PostSetSessionDescriptionFailure(observer, error);
1001 return;
1002 }
deadbeefab9b2d12015-10-14 11:33:11 -07001003
1004 // If setting the description decided our SSL role, allocate any necessary
1005 // SCTP sids.
1006 rtc::SSLRole role;
1007 if (session_->data_channel_type() == cricket::DCT_SCTP &&
Taylor Brandstetterf475d362016-01-08 15:35:57 -08001008 session_->GetSslRole(session_->data_channel(), &role)) {
deadbeefab9b2d12015-10-14 11:33:11 -07001009 AllocateSctpSids(role);
1010 }
1011
1012 // Update state and SSRC of local MediaStreams and DataChannels based on the
1013 // local session description.
1014 const cricket::ContentInfo* audio_content =
1015 GetFirstAudioContent(desc->description());
1016 if (audio_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001017 if (audio_content->rejected) {
1018 RemoveTracks(cricket::MEDIA_TYPE_AUDIO);
1019 } else {
1020 const cricket::AudioContentDescription* audio_desc =
1021 static_cast<const cricket::AudioContentDescription*>(
1022 audio_content->description);
1023 UpdateLocalTracks(audio_desc->streams(), audio_desc->type());
1024 }
deadbeefab9b2d12015-10-14 11:33:11 -07001025 }
1026
1027 const cricket::ContentInfo* video_content =
1028 GetFirstVideoContent(desc->description());
1029 if (video_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001030 if (video_content->rejected) {
1031 RemoveTracks(cricket::MEDIA_TYPE_VIDEO);
1032 } else {
1033 const cricket::VideoContentDescription* video_desc =
1034 static_cast<const cricket::VideoContentDescription*>(
1035 video_content->description);
1036 UpdateLocalTracks(video_desc->streams(), video_desc->type());
1037 }
deadbeefab9b2d12015-10-14 11:33:11 -07001038 }
1039
1040 const cricket::ContentInfo* data_content =
1041 GetFirstDataContent(desc->description());
1042 if (data_content) {
1043 const cricket::DataContentDescription* data_desc =
1044 static_cast<const cricket::DataContentDescription*>(
1045 data_content->description);
1046 if (rtc::starts_with(data_desc->protocol().data(),
1047 cricket::kMediaProtocolRtpPrefix)) {
1048 UpdateLocalRtpDataChannels(data_desc->streams());
1049 }
1050 }
1051
1052 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001053 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeefab9b2d12015-10-14 11:33:11 -07001054
deadbeefcbecd352015-09-23 11:50:27 -07001055 // MaybeStartGathering needs to be called after posting
1056 // MSG_SET_SESSIONDESCRIPTION_SUCCESS, so that we don't signal any candidates
1057 // before signaling that SetLocalDescription completed.
1058 session_->MaybeStartGathering();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001059}
1060
1061void PeerConnection::SetRemoteDescription(
1062 SetSessionDescriptionObserver* observer,
1063 SessionDescriptionInterface* desc) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001064 TRACE_EVENT0("webrtc", "PeerConnection::SetRemoteDescription");
deadbeefab9b2d12015-10-14 11:33:11 -07001065 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001066 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
1067 return;
1068 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001069 if (!desc) {
1070 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
1071 return;
1072 }
1073 // Update stats here so that we have the most recent stats for tracks and
1074 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001075 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001076 std::string error;
1077 if (!session_->SetRemoteDescription(desc, &error)) {
1078 PostSetSessionDescriptionFailure(observer, error);
1079 return;
1080 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001081
deadbeefab9b2d12015-10-14 11:33:11 -07001082 // If setting the description decided our SSL role, allocate any necessary
1083 // SCTP sids.
1084 rtc::SSLRole role;
1085 if (session_->data_channel_type() == cricket::DCT_SCTP &&
Taylor Brandstetterf475d362016-01-08 15:35:57 -08001086 session_->GetSslRole(session_->data_channel(), &role)) {
deadbeefab9b2d12015-10-14 11:33:11 -07001087 AllocateSctpSids(role);
1088 }
1089
1090 const cricket::SessionDescription* remote_desc = desc->description();
deadbeefbda7e0b2015-12-08 17:13:40 -08001091 const cricket::ContentInfo* audio_content = GetFirstAudioContent(remote_desc);
1092 const cricket::ContentInfo* video_content = GetFirstVideoContent(remote_desc);
1093 const cricket::AudioContentDescription* audio_desc =
1094 GetFirstAudioContentDescription(remote_desc);
1095 const cricket::VideoContentDescription* video_desc =
1096 GetFirstVideoContentDescription(remote_desc);
1097 const cricket::DataContentDescription* data_desc =
1098 GetFirstDataContentDescription(remote_desc);
1099
1100 // Check if the descriptions include streams, just in case the peer supports
1101 // MSID, but doesn't indicate so with "a=msid-semantic".
1102 if (remote_desc->msid_supported() ||
1103 (audio_desc && !audio_desc->streams().empty()) ||
1104 (video_desc && !video_desc->streams().empty())) {
1105 remote_peer_supports_msid_ = true;
1106 }
deadbeefab9b2d12015-10-14 11:33:11 -07001107
1108 // We wait to signal new streams until we finish processing the description,
1109 // since only at that point will new streams have all their tracks.
1110 rtc::scoped_refptr<StreamCollection> new_streams(StreamCollection::Create());
1111
1112 // Find all audio rtp streams and create corresponding remote AudioTracks
1113 // and MediaStreams.
deadbeefab9b2d12015-10-14 11:33:11 -07001114 if (audio_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001115 if (audio_content->rejected) {
1116 RemoveTracks(cricket::MEDIA_TYPE_AUDIO);
1117 } else {
deadbeefbda7e0b2015-12-08 17:13:40 -08001118 bool default_audio_track_needed =
1119 !remote_peer_supports_msid_ &&
1120 MediaContentDirectionHasSend(audio_desc->direction());
1121 UpdateRemoteStreamsList(GetActiveStreams(audio_desc),
1122 default_audio_track_needed, audio_desc->type(),
deadbeeffaac4972015-11-12 15:33:07 -08001123 new_streams);
deadbeeffaac4972015-11-12 15:33:07 -08001124 }
deadbeefab9b2d12015-10-14 11:33:11 -07001125 }
1126
1127 // Find all video rtp streams and create corresponding remote VideoTracks
1128 // and MediaStreams.
deadbeefab9b2d12015-10-14 11:33:11 -07001129 if (video_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001130 if (video_content->rejected) {
1131 RemoveTracks(cricket::MEDIA_TYPE_VIDEO);
1132 } else {
deadbeefbda7e0b2015-12-08 17:13:40 -08001133 bool default_video_track_needed =
1134 !remote_peer_supports_msid_ &&
1135 MediaContentDirectionHasSend(video_desc->direction());
1136 UpdateRemoteStreamsList(GetActiveStreams(video_desc),
1137 default_video_track_needed, video_desc->type(),
deadbeeffaac4972015-11-12 15:33:07 -08001138 new_streams);
deadbeeffaac4972015-11-12 15:33:07 -08001139 }
deadbeefab9b2d12015-10-14 11:33:11 -07001140 }
1141
1142 // Update the DataChannels with the information from the remote peer.
deadbeefbda7e0b2015-12-08 17:13:40 -08001143 if (data_desc) {
1144 if (rtc::starts_with(data_desc->protocol().data(),
deadbeefab9b2d12015-10-14 11:33:11 -07001145 cricket::kMediaProtocolRtpPrefix)) {
deadbeefbda7e0b2015-12-08 17:13:40 -08001146 UpdateRemoteRtpDataChannels(GetActiveStreams(data_desc));
deadbeefab9b2d12015-10-14 11:33:11 -07001147 }
1148 }
1149
1150 // Iterate new_streams and notify the observer about new MediaStreams.
1151 for (size_t i = 0; i < new_streams->count(); ++i) {
1152 MediaStreamInterface* new_stream = new_streams->at(i);
1153 stats_->AddStream(new_stream);
1154 observer_->OnAddStream(new_stream);
1155 }
1156
deadbeefbda7e0b2015-12-08 17:13:40 -08001157 UpdateEndedRemoteMediaStreams();
deadbeefab9b2d12015-10-14 11:33:11 -07001158
1159 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1160 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeeffc648b62015-10-13 16:42:33 -07001161}
1162
Taylor Brandstettera1c30352016-05-13 08:15:11 -07001163bool PeerConnection::SetConfiguration(const RTCConfiguration& configuration) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001164 TRACE_EVENT0("webrtc", "PeerConnection::SetConfiguration");
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001165 if (port_allocator_) {
Taylor Brandstettera1c30352016-05-13 08:15:11 -07001166 if (!worker_thread()->Invoke<bool>(
1167 rtc::Bind(&PeerConnection::ReconfigurePortAllocator_w, this,
1168 configuration))) {
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001169 return false;
1170 }
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001171 }
Taylor Brandstettera1c30352016-05-13 08:15:11 -07001172
1173 // TODO(deadbeef): Shouldn't have to hop to the worker thread twice...
1174 session_->SetIceConfig(session_->ParseIceConfig(configuration));
1175 return true;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001176}
1177
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001178bool PeerConnection::AddIceCandidate(
1179 const IceCandidateInterface* ice_candidate) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001180 TRACE_EVENT0("webrtc", "PeerConnection::AddIceCandidate");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001181 return session_->ProcessIceMessage(ice_candidate);
1182}
1183
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001184bool PeerConnection::RemoveIceCandidates(
1185 const std::vector<cricket::Candidate>& candidates) {
1186 TRACE_EVENT0("webrtc", "PeerConnection::RemoveIceCandidates");
1187 return session_->RemoveRemoteIceCandidates(candidates);
1188}
1189
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001190void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001191 TRACE_EVENT0("webrtc", "PeerConnection::RegisterUmaObserver");
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001192 uma_observer_ = observer;
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +00001193
1194 if (session_) {
1195 session_->set_metrics_observer(uma_observer_);
1196 }
1197
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001198 // Send information about IPv4/IPv6 status.
1199 if (uma_observer_ && port_allocator_) {
1200 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001201 uma_observer_->IncrementEnumCounter(
1202 kEnumCounterAddressFamily, kPeerConnection_IPv6,
1203 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgb445f262014-05-23 22:19:37 +00001204 } else {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001205 uma_observer_->IncrementEnumCounter(
1206 kEnumCounterAddressFamily, kPeerConnection_IPv4,
1207 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001208 }
1209 }
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001210}
1211
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001212const SessionDescriptionInterface* PeerConnection::local_description() const {
1213 return session_->local_description();
1214}
1215
1216const SessionDescriptionInterface* PeerConnection::remote_description() const {
1217 return session_->remote_description();
1218}
1219
1220void PeerConnection::Close() {
Peter Boström1a9d6152015-12-08 22:15:17 +01001221 TRACE_EVENT0("webrtc", "PeerConnection::Close");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001222 // Update stats here so that we have the most recent stats for tracks and
1223 // streams before the channels are closed.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001224 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001225
deadbeefd59daf82015-10-14 15:02:44 -07001226 session_->Close();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001227}
1228
deadbeefd59daf82015-10-14 15:02:44 -07001229void PeerConnection::OnSessionStateChange(WebRtcSession* /*session*/,
1230 WebRtcSession::State state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001231 switch (state) {
deadbeefd59daf82015-10-14 15:02:44 -07001232 case WebRtcSession::STATE_INIT:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001233 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001234 break;
deadbeefd59daf82015-10-14 15:02:44 -07001235 case WebRtcSession::STATE_SENTOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001236 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
1237 break;
deadbeefd59daf82015-10-14 15:02:44 -07001238 case WebRtcSession::STATE_SENTPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001239 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
1240 break;
deadbeefd59daf82015-10-14 15:02:44 -07001241 case WebRtcSession::STATE_RECEIVEDOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001242 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
1243 break;
deadbeefd59daf82015-10-14 15:02:44 -07001244 case WebRtcSession::STATE_RECEIVEDPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001245 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
1246 break;
deadbeefd59daf82015-10-14 15:02:44 -07001247 case WebRtcSession::STATE_INPROGRESS:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001248 ChangeSignalingState(PeerConnectionInterface::kStable);
1249 break;
deadbeefd59daf82015-10-14 15:02:44 -07001250 case WebRtcSession::STATE_CLOSED:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001251 ChangeSignalingState(PeerConnectionInterface::kClosed);
1252 break;
1253 default:
1254 break;
1255 }
1256}
1257
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001258void PeerConnection::OnMessage(rtc::Message* msg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001259 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001260 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
1261 SetSessionDescriptionMsg* param =
1262 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1263 param->observer->OnSuccess();
1264 delete param;
1265 break;
1266 }
1267 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
1268 SetSessionDescriptionMsg* param =
1269 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1270 param->observer->OnFailure(param->error);
1271 delete param;
1272 break;
1273 }
deadbeefab9b2d12015-10-14 11:33:11 -07001274 case MSG_CREATE_SESSIONDESCRIPTION_FAILED: {
1275 CreateSessionDescriptionMsg* param =
1276 static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
1277 param->observer->OnFailure(param->error);
1278 delete param;
1279 break;
1280 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001281 case MSG_GETSTATS: {
1282 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +00001283 StatsReports reports;
1284 stats_->GetStats(param->track, &reports);
1285 param->observer->OnComplete(reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001286 delete param;
1287 break;
1288 }
deadbeefbd292462015-12-14 18:15:29 -08001289 case MSG_FREE_DATACHANNELS: {
1290 sctp_data_channels_to_free_.clear();
1291 break;
1292 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001293 default:
deadbeef0a6c4ca2015-10-06 11:38:28 -07001294 RTC_DCHECK(false && "Not implemented");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001295 break;
1296 }
1297}
1298
deadbeefab9b2d12015-10-14 11:33:11 -07001299void PeerConnection::CreateAudioReceiver(MediaStreamInterface* stream,
perkjd61bf802016-03-24 03:16:19 -07001300 const std::string& track_id,
deadbeefab9b2d12015-10-14 11:33:11 -07001301 uint32_t ssrc) {
deadbeefe1f9d832016-01-14 15:35:42 -08001302 receivers_.push_back(RtpReceiverProxy::Create(
1303 signaling_thread(),
perkjd61bf802016-03-24 03:16:19 -07001304 new AudioRtpReceiver(stream, track_id, ssrc, session_.get())));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001305}
1306
deadbeefab9b2d12015-10-14 11:33:11 -07001307void PeerConnection::CreateVideoReceiver(MediaStreamInterface* stream,
perkjf0dcfe22016-03-10 18:32:00 +01001308 const std::string& track_id,
deadbeefab9b2d12015-10-14 11:33:11 -07001309 uint32_t ssrc) {
perkjd61bf802016-03-24 03:16:19 -07001310 receivers_.push_back(RtpReceiverProxy::Create(
1311 signaling_thread(),
1312 new VideoRtpReceiver(stream, track_id, factory_->worker_thread(), ssrc,
1313 session_.get())));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001314}
1315
deadbeef70ab1a12015-09-28 16:53:55 -07001316// TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote
1317// description.
perkjd61bf802016-03-24 03:16:19 -07001318void PeerConnection::DestroyReceiver(const std::string& track_id) {
1319 auto it = FindReceiverForTrack(track_id);
deadbeef70ab1a12015-09-28 16:53:55 -07001320 if (it == receivers_.end()) {
perkjd61bf802016-03-24 03:16:19 -07001321 LOG(LS_WARNING) << "RtpReceiver for track with id " << track_id
deadbeef70ab1a12015-09-28 16:53:55 -07001322 << " doesn't exist.";
1323 } else {
1324 (*it)->Stop();
1325 receivers_.erase(it);
1326 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001327}
1328
perkjd61bf802016-03-24 03:16:19 -07001329void PeerConnection::StopReceivers(cricket::MediaType media_type) {
1330 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1331 for (const auto& track_info : *current_tracks) {
1332 auto it = FindReceiverForTrack(track_info.track_id);
1333 if (it == receivers_.end()) {
1334 LOG(LS_WARNING) << "RtpReceiver for track with id " << track_info.track_id
1335 << " doesn't exist.";
1336 } else {
1337 (*it)->Stop();
1338 }
deadbeef70ab1a12015-09-28 16:53:55 -07001339 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001340}
deadbeef70ab1a12015-09-28 16:53:55 -07001341
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001342void PeerConnection::OnIceConnectionChange(
1343 PeerConnectionInterface::IceConnectionState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001344 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefcbecd352015-09-23 11:50:27 -07001345 // After transitioning to "closed", ignore any additional states from
1346 // WebRtcSession (such as "disconnected").
deadbeefab9b2d12015-10-14 11:33:11 -07001347 if (IsClosed()) {
deadbeefcbecd352015-09-23 11:50:27 -07001348 return;
1349 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001350 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001351 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001352}
1353
1354void PeerConnection::OnIceGatheringChange(
1355 PeerConnectionInterface::IceGatheringState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001356 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001357 if (IsClosed()) {
1358 return;
1359 }
1360 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001361 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001362}
1363
1364void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001365 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001366 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001367}
1368
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001369void PeerConnection::OnIceCandidatesRemoved(
1370 const std::vector<cricket::Candidate>& candidates) {
1371 RTC_DCHECK(signaling_thread()->IsCurrent());
1372 observer_->OnIceCandidatesRemoved(candidates);
1373}
1374
Peter Thatcher54360512015-07-08 11:08:35 -07001375void PeerConnection::OnIceConnectionReceivingChange(bool receiving) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001376 RTC_DCHECK(signaling_thread()->IsCurrent());
Peter Thatcher54360512015-07-08 11:08:35 -07001377 observer_->OnIceConnectionReceivingChange(receiving);
1378}
1379
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001380void PeerConnection::ChangeSignalingState(
1381 PeerConnectionInterface::SignalingState signaling_state) {
1382 signaling_state_ = signaling_state;
1383 if (signaling_state == kClosed) {
1384 ice_connection_state_ = kIceConnectionClosed;
1385 observer_->OnIceConnectionChange(ice_connection_state_);
1386 if (ice_gathering_state_ != kIceGatheringComplete) {
1387 ice_gathering_state_ = kIceGatheringComplete;
1388 observer_->OnIceGatheringChange(ice_gathering_state_);
1389 }
1390 }
1391 observer_->OnSignalingChange(signaling_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001392}
1393
deadbeefeb459812015-12-15 19:24:43 -08001394void PeerConnection::OnAudioTrackAdded(AudioTrackInterface* track,
1395 MediaStreamInterface* stream) {
1396 auto sender = FindSenderForTrack(track);
1397 if (sender != senders_.end()) {
1398 // We already have a sender for this track, so just change the stream_id
1399 // so that it's correct in the next call to CreateOffer.
1400 (*sender)->set_stream_id(stream->label());
1401 return;
1402 }
1403
1404 // Normal case; we've never seen this track before.
deadbeefe1f9d832016-01-14 15:35:42 -08001405 rtc::scoped_refptr<RtpSenderInterface> new_sender = RtpSenderProxy::Create(
1406 signaling_thread(),
1407 new AudioRtpSender(track, stream->label(), session_.get(), stats_.get()));
deadbeefeb459812015-12-15 19:24:43 -08001408 senders_.push_back(new_sender);
1409 // If the sender has already been configured in SDP, we call SetSsrc,
1410 // which will connect the sender to the underlying transport. This can
1411 // occur if a local session description that contains the ID of the sender
1412 // is set before AddStream is called. It can also occur if the local
1413 // session description is not changed and RemoveStream is called, and
1414 // later AddStream is called again with the same stream.
1415 const TrackInfo* track_info =
1416 FindTrackInfo(local_audio_tracks_, stream->label(), track->id());
1417 if (track_info) {
1418 new_sender->SetSsrc(track_info->ssrc);
1419 }
1420}
1421
1422// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around
1423// indefinitely, when we have unified plan SDP.
1424void PeerConnection::OnAudioTrackRemoved(AudioTrackInterface* track,
1425 MediaStreamInterface* stream) {
1426 auto sender = FindSenderForTrack(track);
1427 if (sender == senders_.end()) {
1428 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
1429 << " doesn't exist.";
1430 return;
1431 }
1432 (*sender)->Stop();
1433 senders_.erase(sender);
1434}
1435
1436void PeerConnection::OnVideoTrackAdded(VideoTrackInterface* track,
1437 MediaStreamInterface* stream) {
1438 auto sender = FindSenderForTrack(track);
1439 if (sender != senders_.end()) {
1440 // We already have a sender for this track, so just change the stream_id
1441 // so that it's correct in the next call to CreateOffer.
1442 (*sender)->set_stream_id(stream->label());
1443 return;
1444 }
1445
1446 // Normal case; we've never seen this track before.
deadbeefe1f9d832016-01-14 15:35:42 -08001447 rtc::scoped_refptr<RtpSenderInterface> new_sender = RtpSenderProxy::Create(
1448 signaling_thread(),
1449 new VideoRtpSender(track, stream->label(), session_.get()));
deadbeefeb459812015-12-15 19:24:43 -08001450 senders_.push_back(new_sender);
1451 const TrackInfo* track_info =
1452 FindTrackInfo(local_video_tracks_, stream->label(), track->id());
1453 if (track_info) {
1454 new_sender->SetSsrc(track_info->ssrc);
1455 }
1456}
1457
1458void PeerConnection::OnVideoTrackRemoved(VideoTrackInterface* track,
1459 MediaStreamInterface* stream) {
1460 auto sender = FindSenderForTrack(track);
1461 if (sender == senders_.end()) {
1462 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
1463 << " doesn't exist.";
1464 return;
1465 }
1466 (*sender)->Stop();
1467 senders_.erase(sender);
1468}
1469
deadbeefab9b2d12015-10-14 11:33:11 -07001470void PeerConnection::PostSetSessionDescriptionFailure(
1471 SetSessionDescriptionObserver* observer,
1472 const std::string& error) {
1473 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1474 msg->error = error;
1475 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
1476}
1477
1478void PeerConnection::PostCreateSessionDescriptionFailure(
1479 CreateSessionDescriptionObserver* observer,
1480 const std::string& error) {
1481 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
1482 msg->error = error;
1483 signaling_thread()->Post(this, MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
1484}
1485
1486bool PeerConnection::GetOptionsForOffer(
1487 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
1488 cricket::MediaSessionOptions* session_options) {
deadbeef0ed85b22016-02-23 17:24:52 -08001489 // TODO(deadbeef): Once we have transceivers, enumerate them here instead of
1490 // ContentInfos.
1491 if (session_->local_description()) {
1492 for (const cricket::ContentInfo& content :
1493 session_->local_description()->description()->contents()) {
1494 session_options->transport_options[content.name] =
1495 cricket::TransportOptions();
1496 }
1497 }
htaaac2dea2016-03-10 13:35:55 -08001498 if (!ExtractMediaSessionOptions(rtc_options, true, session_options)) {
deadbeefab9b2d12015-10-14 11:33:11 -07001499 return false;
1500 }
1501
deadbeeffac06552015-11-25 11:26:01 -08001502 AddSendStreams(session_options, senders_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001503 // Offer to receive audio/video if the constraint is not set and there are
1504 // send streams, or we're currently receiving.
1505 if (rtc_options.offer_to_receive_audio == RTCOfferAnswerOptions::kUndefined) {
1506 session_options->recv_audio =
1507 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_AUDIO) ||
1508 !remote_audio_tracks_.empty();
1509 }
1510 if (rtc_options.offer_to_receive_video == RTCOfferAnswerOptions::kUndefined) {
1511 session_options->recv_video =
1512 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_VIDEO) ||
1513 !remote_video_tracks_.empty();
1514 }
1515 session_options->bundle_enabled =
1516 session_options->bundle_enabled &&
1517 (session_options->has_audio() || session_options->has_video() ||
1518 session_options->has_data());
1519
deadbeefab9b2d12015-10-14 11:33:11 -07001520 if (session_->data_channel_type() == cricket::DCT_SCTP && HasDataChannels()) {
1521 session_options->data_channel_type = cricket::DCT_SCTP;
1522 }
zhihuang8f65cdf2016-05-06 18:40:30 -07001523
1524 session_options->rtcp_cname = rtcp_cname_;
deadbeefab9b2d12015-10-14 11:33:11 -07001525 return true;
1526}
1527
htaa2a49d92016-03-04 02:51:39 -08001528void PeerConnection::FinishOptionsForAnswer(
deadbeefab9b2d12015-10-14 11:33:11 -07001529 cricket::MediaSessionOptions* session_options) {
deadbeef0ed85b22016-02-23 17:24:52 -08001530 // TODO(deadbeef): Once we have transceivers, enumerate them here instead of
1531 // ContentInfos.
1532 if (session_->remote_description()) {
1533 // Initialize the transport_options map.
1534 for (const cricket::ContentInfo& content :
1535 session_->remote_description()->description()->contents()) {
1536 session_options->transport_options[content.name] =
1537 cricket::TransportOptions();
1538 }
1539 }
deadbeeffac06552015-11-25 11:26:01 -08001540 AddSendStreams(session_options, senders_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001541 session_options->bundle_enabled =
1542 session_options->bundle_enabled &&
1543 (session_options->has_audio() || session_options->has_video() ||
1544 session_options->has_data());
1545
deadbeefab9b2d12015-10-14 11:33:11 -07001546 // RTP data channel is handled in MediaSessionOptions::AddStream. SCTP streams
1547 // are not signaled in the SDP so does not go through that path and must be
1548 // handled here.
1549 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1550 session_options->data_channel_type = cricket::DCT_SCTP;
1551 }
htaa2a49d92016-03-04 02:51:39 -08001552}
1553
1554bool PeerConnection::GetOptionsForAnswer(
1555 const MediaConstraintsInterface* constraints,
1556 cricket::MediaSessionOptions* session_options) {
1557 session_options->recv_audio = false;
1558 session_options->recv_video = false;
1559 if (!ParseConstraintsForAnswer(constraints, session_options)) {
1560 return false;
1561 }
zhihuang8f65cdf2016-05-06 18:40:30 -07001562 session_options->rtcp_cname = rtcp_cname_;
1563
htaa2a49d92016-03-04 02:51:39 -08001564 FinishOptionsForAnswer(session_options);
1565 return true;
1566}
1567
1568bool PeerConnection::GetOptionsForAnswer(
1569 const RTCOfferAnswerOptions& options,
1570 cricket::MediaSessionOptions* session_options) {
1571 session_options->recv_audio = false;
1572 session_options->recv_video = false;
htaaac2dea2016-03-10 13:35:55 -08001573 if (!ExtractMediaSessionOptions(options, false, session_options)) {
htaa2a49d92016-03-04 02:51:39 -08001574 return false;
1575 }
zhihuang8f65cdf2016-05-06 18:40:30 -07001576 session_options->rtcp_cname = rtcp_cname_;
1577
htaa2a49d92016-03-04 02:51:39 -08001578 FinishOptionsForAnswer(session_options);
deadbeefab9b2d12015-10-14 11:33:11 -07001579 return true;
1580}
1581
deadbeeffaac4972015-11-12 15:33:07 -08001582void PeerConnection::RemoveTracks(cricket::MediaType media_type) {
1583 UpdateLocalTracks(std::vector<cricket::StreamParams>(), media_type);
deadbeefbda7e0b2015-12-08 17:13:40 -08001584 UpdateRemoteStreamsList(std::vector<cricket::StreamParams>(), false,
1585 media_type, nullptr);
deadbeeffaac4972015-11-12 15:33:07 -08001586}
1587
deadbeefab9b2d12015-10-14 11:33:11 -07001588void PeerConnection::UpdateRemoteStreamsList(
1589 const cricket::StreamParamsVec& streams,
deadbeefbda7e0b2015-12-08 17:13:40 -08001590 bool default_track_needed,
deadbeefab9b2d12015-10-14 11:33:11 -07001591 cricket::MediaType media_type,
1592 StreamCollection* new_streams) {
1593 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1594
1595 // Find removed tracks. I.e., tracks where the track id or ssrc don't match
deadbeeffac06552015-11-25 11:26:01 -08001596 // the new StreamParam.
deadbeefab9b2d12015-10-14 11:33:11 -07001597 auto track_it = current_tracks->begin();
1598 while (track_it != current_tracks->end()) {
1599 const TrackInfo& info = *track_it;
1600 const cricket::StreamParams* params =
1601 cricket::GetStreamBySsrc(streams, info.ssrc);
deadbeefbda7e0b2015-12-08 17:13:40 -08001602 bool track_exists = params && params->id == info.track_id;
1603 // If this is a default track, and we still need it, don't remove it.
1604 if ((info.stream_label == kDefaultStreamLabel && default_track_needed) ||
1605 track_exists) {
1606 ++track_it;
1607 } else {
deadbeefab9b2d12015-10-14 11:33:11 -07001608 OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
1609 track_it = current_tracks->erase(track_it);
deadbeefab9b2d12015-10-14 11:33:11 -07001610 }
1611 }
1612
1613 // Find new and active tracks.
1614 for (const cricket::StreamParams& params : streams) {
1615 // The sync_label is the MediaStream label and the |stream.id| is the
1616 // track id.
1617 const std::string& stream_label = params.sync_label;
1618 const std::string& track_id = params.id;
1619 uint32_t ssrc = params.first_ssrc();
1620
1621 rtc::scoped_refptr<MediaStreamInterface> stream =
1622 remote_streams_->find(stream_label);
1623 if (!stream) {
1624 // This is a new MediaStream. Create a new remote MediaStream.
perkjd61bf802016-03-24 03:16:19 -07001625 stream = MediaStreamProxy::Create(rtc::Thread::Current(),
1626 MediaStream::Create(stream_label));
deadbeefab9b2d12015-10-14 11:33:11 -07001627 remote_streams_->AddStream(stream);
1628 new_streams->AddStream(stream);
1629 }
1630
1631 const TrackInfo* track_info =
1632 FindTrackInfo(*current_tracks, stream_label, track_id);
1633 if (!track_info) {
1634 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1635 OnRemoteTrackSeen(stream_label, track_id, ssrc, media_type);
1636 }
1637 }
deadbeefbda7e0b2015-12-08 17:13:40 -08001638
1639 // Add default track if necessary.
1640 if (default_track_needed) {
1641 rtc::scoped_refptr<MediaStreamInterface> default_stream =
1642 remote_streams_->find(kDefaultStreamLabel);
1643 if (!default_stream) {
1644 // Create the new default MediaStream.
perkjd61bf802016-03-24 03:16:19 -07001645 default_stream = MediaStreamProxy::Create(
1646 rtc::Thread::Current(), MediaStream::Create(kDefaultStreamLabel));
deadbeefbda7e0b2015-12-08 17:13:40 -08001647 remote_streams_->AddStream(default_stream);
1648 new_streams->AddStream(default_stream);
1649 }
1650 std::string default_track_id = (media_type == cricket::MEDIA_TYPE_AUDIO)
1651 ? kDefaultAudioTrackLabel
1652 : kDefaultVideoTrackLabel;
1653 const TrackInfo* default_track_info =
1654 FindTrackInfo(*current_tracks, kDefaultStreamLabel, default_track_id);
1655 if (!default_track_info) {
1656 current_tracks->push_back(
1657 TrackInfo(kDefaultStreamLabel, default_track_id, 0));
1658 OnRemoteTrackSeen(kDefaultStreamLabel, default_track_id, 0, media_type);
1659 }
1660 }
deadbeefab9b2d12015-10-14 11:33:11 -07001661}
1662
1663void PeerConnection::OnRemoteTrackSeen(const std::string& stream_label,
1664 const std::string& track_id,
1665 uint32_t ssrc,
1666 cricket::MediaType media_type) {
1667 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1668
1669 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
perkjd61bf802016-03-24 03:16:19 -07001670 CreateAudioReceiver(stream, track_id, ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -07001671 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
perkjf0dcfe22016-03-10 18:32:00 +01001672 CreateVideoReceiver(stream, track_id, ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -07001673 } else {
1674 RTC_DCHECK(false && "Invalid media type");
1675 }
1676}
1677
1678void PeerConnection::OnRemoteTrackRemoved(const std::string& stream_label,
1679 const std::string& track_id,
1680 cricket::MediaType media_type) {
1681 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1682
1683 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
perkjd61bf802016-03-24 03:16:19 -07001684 // When the MediaEngine audio channel is destroyed, the RemoteAudioSource
1685 // will be notified which will end the AudioRtpReceiver::track().
1686 DestroyReceiver(track_id);
deadbeefab9b2d12015-10-14 11:33:11 -07001687 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1688 stream->FindAudioTrack(track_id);
1689 if (audio_track) {
deadbeefab9b2d12015-10-14 11:33:11 -07001690 stream->RemoveTrack(audio_track);
deadbeefab9b2d12015-10-14 11:33:11 -07001691 }
1692 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
perkjd61bf802016-03-24 03:16:19 -07001693 // Stopping or destroying a VideoRtpReceiver will end the
1694 // VideoRtpReceiver::track().
1695 DestroyReceiver(track_id);
deadbeefab9b2d12015-10-14 11:33:11 -07001696 rtc::scoped_refptr<VideoTrackInterface> video_track =
1697 stream->FindVideoTrack(track_id);
1698 if (video_track) {
perkjd61bf802016-03-24 03:16:19 -07001699 // There's no guarantee the track is still available, e.g. the track may
1700 // have been removed from the stream by an application.
deadbeefab9b2d12015-10-14 11:33:11 -07001701 stream->RemoveTrack(video_track);
deadbeefab9b2d12015-10-14 11:33:11 -07001702 }
1703 } else {
1704 ASSERT(false && "Invalid media type");
1705 }
1706}
1707
1708void PeerConnection::UpdateEndedRemoteMediaStreams() {
1709 std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams_to_remove;
1710 for (size_t i = 0; i < remote_streams_->count(); ++i) {
1711 MediaStreamInterface* stream = remote_streams_->at(i);
1712 if (stream->GetAudioTracks().empty() && stream->GetVideoTracks().empty()) {
1713 streams_to_remove.push_back(stream);
1714 }
1715 }
1716
1717 for (const auto& stream : streams_to_remove) {
1718 remote_streams_->RemoveStream(stream);
1719 observer_->OnRemoveStream(stream);
1720 }
1721}
1722
deadbeefab9b2d12015-10-14 11:33:11 -07001723void PeerConnection::UpdateLocalTracks(
1724 const std::vector<cricket::StreamParams>& streams,
1725 cricket::MediaType media_type) {
1726 TrackInfos* current_tracks = GetLocalTracks(media_type);
1727
1728 // Find removed tracks. I.e., tracks where the track id, stream label or ssrc
1729 // don't match the new StreamParam.
1730 TrackInfos::iterator track_it = current_tracks->begin();
1731 while (track_it != current_tracks->end()) {
1732 const TrackInfo& info = *track_it;
1733 const cricket::StreamParams* params =
1734 cricket::GetStreamBySsrc(streams, info.ssrc);
1735 if (!params || params->id != info.track_id ||
1736 params->sync_label != info.stream_label) {
1737 OnLocalTrackRemoved(info.stream_label, info.track_id, info.ssrc,
1738 media_type);
1739 track_it = current_tracks->erase(track_it);
1740 } else {
1741 ++track_it;
1742 }
1743 }
1744
1745 // Find new and active tracks.
1746 for (const cricket::StreamParams& params : streams) {
1747 // The sync_label is the MediaStream label and the |stream.id| is the
1748 // track id.
1749 const std::string& stream_label = params.sync_label;
1750 const std::string& track_id = params.id;
1751 uint32_t ssrc = params.first_ssrc();
1752 const TrackInfo* track_info =
1753 FindTrackInfo(*current_tracks, stream_label, track_id);
1754 if (!track_info) {
1755 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1756 OnLocalTrackSeen(stream_label, track_id, params.first_ssrc(), media_type);
1757 }
1758 }
1759}
1760
1761void PeerConnection::OnLocalTrackSeen(const std::string& stream_label,
1762 const std::string& track_id,
1763 uint32_t ssrc,
1764 cricket::MediaType media_type) {
deadbeeffac06552015-11-25 11:26:01 -08001765 RtpSenderInterface* sender = FindSenderById(track_id);
1766 if (!sender) {
1767 LOG(LS_WARNING) << "An unknown RtpSender with id " << track_id
1768 << " has been configured in the local description.";
deadbeefab9b2d12015-10-14 11:33:11 -07001769 return;
1770 }
1771
deadbeeffac06552015-11-25 11:26:01 -08001772 if (sender->media_type() != media_type) {
1773 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
1774 << " description with an unexpected media type.";
1775 return;
deadbeefab9b2d12015-10-14 11:33:11 -07001776 }
deadbeeffac06552015-11-25 11:26:01 -08001777
1778 sender->set_stream_id(stream_label);
1779 sender->SetSsrc(ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -07001780}
1781
1782void PeerConnection::OnLocalTrackRemoved(const std::string& stream_label,
1783 const std::string& track_id,
1784 uint32_t ssrc,
1785 cricket::MediaType media_type) {
deadbeeffac06552015-11-25 11:26:01 -08001786 RtpSenderInterface* sender = FindSenderById(track_id);
1787 if (!sender) {
1788 // This is the normal case. I.e., RemoveStream has been called and the
deadbeefab9b2d12015-10-14 11:33:11 -07001789 // SessionDescriptions has been renegotiated.
1790 return;
1791 }
deadbeeffac06552015-11-25 11:26:01 -08001792
1793 // A sender has been removed from the SessionDescription but it's still
1794 // associated with the PeerConnection. This only occurs if the SDP doesn't
1795 // match with the calls to CreateSender, AddStream and RemoveStream.
1796 if (sender->media_type() != media_type) {
1797 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
1798 << " description with an unexpected media type.";
1799 return;
deadbeefab9b2d12015-10-14 11:33:11 -07001800 }
deadbeeffac06552015-11-25 11:26:01 -08001801
1802 sender->SetSsrc(0);
deadbeefab9b2d12015-10-14 11:33:11 -07001803}
1804
1805void PeerConnection::UpdateLocalRtpDataChannels(
1806 const cricket::StreamParamsVec& streams) {
1807 std::vector<std::string> existing_channels;
1808
1809 // Find new and active data channels.
1810 for (const cricket::StreamParams& params : streams) {
1811 // |it->sync_label| is actually the data channel label. The reason is that
1812 // we use the same naming of data channels as we do for
1813 // MediaStreams and Tracks.
1814 // For MediaStreams, the sync_label is the MediaStream label and the
1815 // track label is the same as |streamid|.
1816 const std::string& channel_label = params.sync_label;
1817 auto data_channel_it = rtp_data_channels_.find(channel_label);
1818 if (!VERIFY(data_channel_it != rtp_data_channels_.end())) {
1819 continue;
1820 }
1821 // Set the SSRC the data channel should use for sending.
1822 data_channel_it->second->SetSendSsrc(params.first_ssrc());
1823 existing_channels.push_back(data_channel_it->first);
1824 }
1825
1826 UpdateClosingRtpDataChannels(existing_channels, true);
1827}
1828
1829void PeerConnection::UpdateRemoteRtpDataChannels(
1830 const cricket::StreamParamsVec& streams) {
1831 std::vector<std::string> existing_channels;
1832
1833 // Find new and active data channels.
1834 for (const cricket::StreamParams& params : streams) {
1835 // The data channel label is either the mslabel or the SSRC if the mslabel
1836 // does not exist. Ex a=ssrc:444330170 mslabel:test1.
1837 std::string label = params.sync_label.empty()
1838 ? rtc::ToString(params.first_ssrc())
1839 : params.sync_label;
1840 auto data_channel_it = rtp_data_channels_.find(label);
1841 if (data_channel_it == rtp_data_channels_.end()) {
1842 // This is a new data channel.
1843 CreateRemoteRtpDataChannel(label, params.first_ssrc());
1844 } else {
1845 data_channel_it->second->SetReceiveSsrc(params.first_ssrc());
1846 }
1847 existing_channels.push_back(label);
1848 }
1849
1850 UpdateClosingRtpDataChannels(existing_channels, false);
1851}
1852
1853void PeerConnection::UpdateClosingRtpDataChannels(
1854 const std::vector<std::string>& active_channels,
1855 bool is_local_update) {
1856 auto it = rtp_data_channels_.begin();
1857 while (it != rtp_data_channels_.end()) {
1858 DataChannel* data_channel = it->second;
1859 if (std::find(active_channels.begin(), active_channels.end(),
1860 data_channel->label()) != active_channels.end()) {
1861 ++it;
1862 continue;
1863 }
1864
1865 if (is_local_update) {
1866 data_channel->SetSendSsrc(0);
1867 } else {
1868 data_channel->RemotePeerRequestClose();
1869 }
1870
1871 if (data_channel->state() == DataChannel::kClosed) {
1872 rtp_data_channels_.erase(it);
1873 it = rtp_data_channels_.begin();
1874 } else {
1875 ++it;
1876 }
1877 }
1878}
1879
1880void PeerConnection::CreateRemoteRtpDataChannel(const std::string& label,
1881 uint32_t remote_ssrc) {
1882 rtc::scoped_refptr<DataChannel> channel(
1883 InternalCreateDataChannel(label, nullptr));
1884 if (!channel.get()) {
1885 LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
1886 << "CreateDataChannel failed.";
1887 return;
1888 }
1889 channel->SetReceiveSsrc(remote_ssrc);
1890 observer_->OnDataChannel(
1891 DataChannelProxy::Create(signaling_thread(), channel));
1892}
1893
1894rtc::scoped_refptr<DataChannel> PeerConnection::InternalCreateDataChannel(
1895 const std::string& label,
1896 const InternalDataChannelInit* config) {
1897 if (IsClosed()) {
1898 return nullptr;
1899 }
1900 if (session_->data_channel_type() == cricket::DCT_NONE) {
1901 LOG(LS_ERROR)
1902 << "InternalCreateDataChannel: Data is not supported in this call.";
1903 return nullptr;
1904 }
1905 InternalDataChannelInit new_config =
1906 config ? (*config) : InternalDataChannelInit();
1907 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1908 if (new_config.id < 0) {
1909 rtc::SSLRole role;
Taylor Brandstetterf475d362016-01-08 15:35:57 -08001910 if ((session_->GetSslRole(session_->data_channel(), &role)) &&
deadbeefab9b2d12015-10-14 11:33:11 -07001911 !sid_allocator_.AllocateSid(role, &new_config.id)) {
1912 LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel.";
1913 return nullptr;
1914 }
1915 } else if (!sid_allocator_.ReserveSid(new_config.id)) {
1916 LOG(LS_ERROR) << "Failed to create a SCTP data channel "
1917 << "because the id is already in use or out of range.";
1918 return nullptr;
1919 }
1920 }
1921
1922 rtc::scoped_refptr<DataChannel> channel(DataChannel::Create(
1923 session_.get(), session_->data_channel_type(), label, new_config));
1924 if (!channel) {
1925 sid_allocator_.ReleaseSid(new_config.id);
1926 return nullptr;
1927 }
1928
1929 if (channel->data_channel_type() == cricket::DCT_RTP) {
1930 if (rtp_data_channels_.find(channel->label()) != rtp_data_channels_.end()) {
1931 LOG(LS_ERROR) << "DataChannel with label " << channel->label()
1932 << " already exists.";
1933 return nullptr;
1934 }
1935 rtp_data_channels_[channel->label()] = channel;
1936 } else {
1937 RTC_DCHECK(channel->data_channel_type() == cricket::DCT_SCTP);
1938 sctp_data_channels_.push_back(channel);
1939 channel->SignalClosed.connect(this,
1940 &PeerConnection::OnSctpDataChannelClosed);
1941 }
1942
1943 return channel;
1944}
1945
1946bool PeerConnection::HasDataChannels() const {
1947 return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
1948}
1949
1950void PeerConnection::AllocateSctpSids(rtc::SSLRole role) {
1951 for (const auto& channel : sctp_data_channels_) {
1952 if (channel->id() < 0) {
1953 int sid;
1954 if (!sid_allocator_.AllocateSid(role, &sid)) {
1955 LOG(LS_ERROR) << "Failed to allocate SCTP sid.";
1956 continue;
1957 }
1958 channel->SetSctpSid(sid);
1959 }
1960 }
1961}
1962
1963void PeerConnection::OnSctpDataChannelClosed(DataChannel* channel) {
deadbeefbd292462015-12-14 18:15:29 -08001964 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefab9b2d12015-10-14 11:33:11 -07001965 for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end();
1966 ++it) {
1967 if (it->get() == channel) {
1968 if (channel->id() >= 0) {
1969 sid_allocator_.ReleaseSid(channel->id());
1970 }
deadbeefbd292462015-12-14 18:15:29 -08001971 // Since this method is triggered by a signal from the DataChannel,
1972 // we can't free it directly here; we need to free it asynchronously.
1973 sctp_data_channels_to_free_.push_back(*it);
deadbeefab9b2d12015-10-14 11:33:11 -07001974 sctp_data_channels_.erase(it);
deadbeefbd292462015-12-14 18:15:29 -08001975 signaling_thread()->Post(this, MSG_FREE_DATACHANNELS, nullptr);
deadbeefab9b2d12015-10-14 11:33:11 -07001976 return;
1977 }
1978 }
1979}
1980
1981void PeerConnection::OnVoiceChannelDestroyed() {
perkjd61bf802016-03-24 03:16:19 -07001982 StopReceivers(cricket::MEDIA_TYPE_AUDIO);
deadbeefab9b2d12015-10-14 11:33:11 -07001983}
1984
1985void PeerConnection::OnVideoChannelDestroyed() {
perkjd61bf802016-03-24 03:16:19 -07001986 StopReceivers(cricket::MEDIA_TYPE_VIDEO);
deadbeefab9b2d12015-10-14 11:33:11 -07001987}
1988
1989void PeerConnection::OnDataChannelCreated() {
1990 for (const auto& channel : sctp_data_channels_) {
1991 channel->OnTransportChannelCreated();
1992 }
1993}
1994
1995void PeerConnection::OnDataChannelDestroyed() {
1996 // Use a temporary copy of the RTP/SCTP DataChannel list because the
1997 // DataChannel may callback to us and try to modify the list.
1998 std::map<std::string, rtc::scoped_refptr<DataChannel>> temp_rtp_dcs;
1999 temp_rtp_dcs.swap(rtp_data_channels_);
2000 for (const auto& kv : temp_rtp_dcs) {
2001 kv.second->OnTransportChannelDestroyed();
2002 }
2003
2004 std::vector<rtc::scoped_refptr<DataChannel>> temp_sctp_dcs;
2005 temp_sctp_dcs.swap(sctp_data_channels_);
2006 for (const auto& channel : temp_sctp_dcs) {
2007 channel->OnTransportChannelDestroyed();
2008 }
2009}
2010
2011void PeerConnection::OnDataChannelOpenMessage(
2012 const std::string& label,
2013 const InternalDataChannelInit& config) {
2014 rtc::scoped_refptr<DataChannel> channel(
2015 InternalCreateDataChannel(label, &config));
2016 if (!channel.get()) {
2017 LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
2018 return;
2019 }
2020
2021 observer_->OnDataChannel(
2022 DataChannelProxy::Create(signaling_thread(), channel));
2023}
2024
deadbeeffac06552015-11-25 11:26:01 -08002025RtpSenderInterface* PeerConnection::FindSenderById(const std::string& id) {
2026 auto it =
2027 std::find_if(senders_.begin(), senders_.end(),
2028 [id](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
2029 return sender->id() == id;
2030 });
2031 return it != senders_.end() ? it->get() : nullptr;
2032}
2033
deadbeef70ab1a12015-09-28 16:53:55 -07002034std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator
2035PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) {
2036 return std::find_if(
2037 senders_.begin(), senders_.end(),
2038 [track](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
2039 return sender->track() == track;
2040 });
2041}
2042
2043std::vector<rtc::scoped_refptr<RtpReceiverInterface>>::iterator
perkjd61bf802016-03-24 03:16:19 -07002044PeerConnection::FindReceiverForTrack(const std::string& track_id) {
deadbeef70ab1a12015-09-28 16:53:55 -07002045 return std::find_if(
2046 receivers_.begin(), receivers_.end(),
perkjd61bf802016-03-24 03:16:19 -07002047 [track_id](const rtc::scoped_refptr<RtpReceiverInterface>& receiver) {
2048 return receiver->id() == track_id;
deadbeef70ab1a12015-09-28 16:53:55 -07002049 });
2050}
2051
deadbeefab9b2d12015-10-14 11:33:11 -07002052PeerConnection::TrackInfos* PeerConnection::GetRemoteTracks(
2053 cricket::MediaType media_type) {
2054 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
2055 media_type == cricket::MEDIA_TYPE_VIDEO);
2056 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &remote_audio_tracks_
2057 : &remote_video_tracks_;
2058}
2059
2060PeerConnection::TrackInfos* PeerConnection::GetLocalTracks(
2061 cricket::MediaType media_type) {
2062 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
2063 media_type == cricket::MEDIA_TYPE_VIDEO);
2064 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &local_audio_tracks_
2065 : &local_video_tracks_;
2066}
2067
2068const PeerConnection::TrackInfo* PeerConnection::FindTrackInfo(
2069 const PeerConnection::TrackInfos& infos,
2070 const std::string& stream_label,
2071 const std::string track_id) const {
2072 for (const TrackInfo& track_info : infos) {
2073 if (track_info.stream_label == stream_label &&
2074 track_info.track_id == track_id) {
2075 return &track_info;
2076 }
2077 }
2078 return nullptr;
2079}
2080
2081DataChannel* PeerConnection::FindDataChannelBySid(int sid) const {
2082 for (const auto& channel : sctp_data_channels_) {
2083 if (channel->id() == sid) {
2084 return channel;
2085 }
2086 }
2087 return nullptr;
2088}
2089
Taylor Brandstettera1c30352016-05-13 08:15:11 -07002090bool PeerConnection::InitializePortAllocator_w(
2091 const RTCConfiguration& configuration) {
2092 cricket::ServerAddresses stun_servers;
2093 std::vector<cricket::RelayServerConfig> turn_servers;
2094 if (!ParseIceServers(configuration.servers, &stun_servers, &turn_servers)) {
2095 return false;
2096 }
2097
2098 // To handle both internal and externally created port allocator, we will
2099 // enable BUNDLE here.
2100 int portallocator_flags = port_allocator_->flags();
2101 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
2102 cricket::PORTALLOCATOR_ENABLE_IPV6;
2103 // If the disable-IPv6 flag was specified, we'll not override it
2104 // by experiment.
2105 if (configuration.disable_ipv6) {
2106 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
2107 } else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default") ==
2108 "Disabled") {
2109 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
2110 }
2111
2112 if (configuration.tcp_candidate_policy == kTcpCandidatePolicyDisabled) {
2113 portallocator_flags |= cricket::PORTALLOCATOR_DISABLE_TCP;
2114 LOG(LS_INFO) << "TCP candidates are disabled.";
2115 }
2116
2117 port_allocator_->set_flags(portallocator_flags);
2118 // No step delay is used while allocating ports.
2119 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
2120 port_allocator_->set_candidate_filter(
2121 ConvertIceTransportTypeToCandidateFilter(configuration.type));
2122
2123 // Call this last since it may create pooled allocator sessions using the
2124 // properties set above.
2125 port_allocator_->SetConfiguration(stun_servers, turn_servers,
2126 configuration.ice_candidate_pool_size);
2127 return true;
2128}
2129
2130bool PeerConnection::ReconfigurePortAllocator_w(
2131 const RTCConfiguration& configuration) {
2132 cricket::ServerAddresses stun_servers;
2133 std::vector<cricket::RelayServerConfig> turn_servers;
2134 if (!ParseIceServers(configuration.servers, &stun_servers, &turn_servers)) {
2135 return false;
2136 }
2137 port_allocator_->set_candidate_filter(
2138 ConvertIceTransportTypeToCandidateFilter(configuration.type));
2139 // Call this last since it may create pooled allocator sessions using the
2140 // candidate filter set above.
2141 port_allocator_->SetConfiguration(stun_servers, turn_servers,
2142 configuration.ice_candidate_pool_size);
2143 return true;
2144}
2145
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002146} // namespace webrtc