blob: bf9a80d9b7199ccab41c5503e0ae26be9d000d65 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
jlmiller@webrtc.org5f93d0a2015-01-20 21:36:13 +00003 * Copyright 2012 Google Inc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "talk/app/webrtc/peerconnection.h"
29
30#include <vector>
deadbeef0a6c4ca2015-10-06 11:38:28 -070031#include <cctype> // for isdigit
henrike@webrtc.org28e20752013-07-10 00:45:36 +000032
33#include "talk/app/webrtc/dtmfsender.h"
34#include "talk/app/webrtc/jsepicecandidate.h"
35#include "talk/app/webrtc/jsepsessiondescription.h"
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +000036#include "talk/app/webrtc/mediaconstraintsinterface.h"
deadbeef70ab1a12015-09-28 16:53:55 -070037#include "talk/app/webrtc/rtpreceiver.h"
38#include "talk/app/webrtc/rtpsender.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000039#include "talk/app/webrtc/streamcollection.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000040#include "webrtc/p2p/client/basicportallocator.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000041#include "talk/session/media/channelmanager.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000042#include "webrtc/base/logging.h"
43#include "webrtc/base/stringencode.h"
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +000044#include "webrtc/system_wrappers/interface/field_trial.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000045
46namespace {
47
48using webrtc::PeerConnectionInterface;
deadbeef0a6c4ca2015-10-06 11:38:28 -070049using webrtc::StunConfigurations;
50using webrtc::TurnConfigurations;
51typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
52 StunConfiguration;
53typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
54 TurnConfiguration;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000055
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";
wu@webrtc.org91053e72013-08-10 07:18:04 +000065static const char kUdpTransportType[] = "udp";
66static const char kTcpTransportType[] = "tcp";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000067
68// NOTE: Must be in the same order as the ServiceType enum.
deadbeef0a6c4ca2015-10-06 11:38:28 -070069static const char* kValidIceServiceTypes[] = {"stun", "stuns", "turn", "turns"};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000070
deadbeef0a6c4ca2015-10-06 11:38:28 -070071// NOTE: A loop below assumes that the first value of this enum is 0 and all
72// other values are incremental.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073enum ServiceType {
deadbeef0a6c4ca2015-10-06 11:38:28 -070074 STUN = 0, // Indicates a STUN server.
75 STUNS, // Indicates a STUN server used with a TLS session.
76 TURN, // Indicates a TURN server
77 TURNS, // Indicates a TURN server used with a TLS session.
78 INVALID, // Unknown.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000079};
deadbeef0a6c4ca2015-10-06 11:38:28 -070080static_assert(INVALID == ARRAY_SIZE(kValidIceServiceTypes),
81 "kValidIceServiceTypes must have as many strings as ServiceType "
82 "has values.");
henrike@webrtc.org28e20752013-07-10 00:45:36 +000083
84enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +000085 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000086 MSG_SET_SESSIONDESCRIPTION_FAILED,
87 MSG_GETSTATS,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088};
89
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000090struct SetSessionDescriptionMsg : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000091 explicit SetSessionDescriptionMsg(
92 webrtc::SetSessionDescriptionObserver* observer)
93 : observer(observer) {
94 }
95
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000096 rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000097 std::string error;
98};
99
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000100struct GetStatsMsg : public rtc::MessageData {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000101 GetStatsMsg(webrtc::StatsObserver* observer,
102 webrtc::MediaStreamTrackInterface* track)
103 : observer(observer), track(track) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000104 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000105 rtc::scoped_refptr<webrtc::StatsObserver> observer;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000106 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000107};
108
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000109// |in_str| should be of format
110// stunURI = scheme ":" stun-host [ ":" stun-port ]
111// scheme = "stun" / "stuns"
112// stun-host = IP-literal / IPv4address / reg-name
113// stun-port = *DIGIT
deadbeef0a6c4ca2015-10-06 11:38:28 -0700114//
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000115// draft-petithuguenin-behave-turn-uris-01
116// turnURI = scheme ":" turn-host [ ":" turn-port ]
117// turn-host = username@IP-literal / IPv4address / reg-name
118bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
119 ServiceType* service_type,
120 std::string* hostname) {
Tommi77d444a2015-04-24 15:38:38 +0200121 const std::string::size_type colonpos = in_str.find(':');
deadbeef0a6c4ca2015-10-06 11:38:28 -0700122 if (colonpos == std::string::npos) {
123 LOG(LS_WARNING) << "Missing ':' in ICE URI: " << in_str;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000124 return false;
125 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700126 if ((colonpos + 1) == in_str.length()) {
127 LOG(LS_WARNING) << "Empty hostname in ICE URI: " << in_str;
128 return false;
129 }
130 *service_type = INVALID;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000131 for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700132 if (in_str.compare(0, colonpos, kValidIceServiceTypes[i]) == 0) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000133 *service_type = static_cast<ServiceType>(i);
134 break;
135 }
136 }
137 if (*service_type == INVALID) {
138 return false;
139 }
140 *hostname = in_str.substr(colonpos + 1, std::string::npos);
141 return true;
142}
143
deadbeef0a6c4ca2015-10-06 11:38:28 -0700144bool ParsePort(const std::string& in_str, int* port) {
145 // Make sure port only contains digits. FromString doesn't check this.
146 for (const char& c : in_str) {
147 if (!std::isdigit(c)) {
148 return false;
149 }
150 }
151 return rtc::FromString(in_str, port);
152}
153
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000154// This method parses IPv6 and IPv4 literal strings, along with hostnames in
155// standard hostname:port format.
156// Consider following formats as correct.
157// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700158// |hostname|, |[IPv6 address]|, |IPv4 address|.
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000159bool ParseHostnameAndPortFromString(const std::string& in_str,
160 std::string* host,
161 int* port) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700162 RTC_DCHECK(host->empty());
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000163 if (in_str.at(0) == '[') {
164 std::string::size_type closebracket = in_str.rfind(']');
165 if (closebracket != std::string::npos) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000166 std::string::size_type colonpos = in_str.find(':', closebracket);
167 if (std::string::npos != colonpos) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700168 if (!ParsePort(in_str.substr(closebracket + 2, std::string::npos),
169 port)) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000170 return false;
171 }
172 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700173 *host = in_str.substr(1, closebracket - 1);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000174 } else {
175 return false;
176 }
177 } else {
178 std::string::size_type colonpos = in_str.find(':');
179 if (std::string::npos != colonpos) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700180 if (!ParsePort(in_str.substr(colonpos + 1, std::string::npos), port)) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000181 return false;
182 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700183 *host = in_str.substr(0, colonpos);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000184 } else {
185 *host = in_str;
186 }
187 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700188 return !host->empty();
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000189}
190
deadbeef0a6c4ca2015-10-06 11:38:28 -0700191// Adds a StunConfiguration or TurnConfiguration to the appropriate list,
192// by parsing |url| and using the username/password in |server|.
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200193bool ParseIceServerUrl(const PeerConnectionInterface::IceServer& server,
194 const std::string& url,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700195 StunConfigurations* stun_config,
196 TurnConfigurations* turn_config) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000197 // draft-nandakumar-rtcweb-stun-uri-01
198 // stunURI = scheme ":" stun-host [ ":" stun-port ]
199 // scheme = "stun" / "stuns"
200 // stun-host = IP-literal / IPv4address / reg-name
201 // stun-port = *DIGIT
202
203 // draft-petithuguenin-behave-turn-uris-01
204 // turnURI = scheme ":" turn-host [ ":" turn-port ]
205 // [ "?transport=" transport ]
206 // scheme = "turn" / "turns"
207 // transport = "udp" / "tcp" / transport-ext
208 // transport-ext = 1*unreserved
209 // turn-host = IP-literal / IPv4address / reg-name
210 // turn-port = *DIGIT
deadbeef0a6c4ca2015-10-06 11:38:28 -0700211 RTC_DCHECK(stun_config != nullptr);
212 RTC_DCHECK(turn_config != nullptr);
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200213 std::vector<std::string> tokens;
214 std::string turn_transport_type = kUdpTransportType;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700215 RTC_DCHECK(!url.empty());
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200216 rtc::tokenize(url, '?', &tokens);
217 std::string uri_without_transport = tokens[0];
218 // Let's look into transport= param, if it exists.
219 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
220 std::string uri_transport_param = tokens[1];
221 rtc::tokenize(uri_transport_param, '=', &tokens);
222 if (tokens[0] == kTransport) {
223 // As per above grammar transport param will be consist of lower case
224 // letters.
225 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
226 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
deadbeef0a6c4ca2015-10-06 11:38:28 -0700227 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000228 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200229 turn_transport_type = tokens[1];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000230 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200231 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000232
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200233 std::string hoststring;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700234 ServiceType service_type;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200235 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
236 &service_type,
237 &hoststring)) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700238 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: " << url;
239 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200240 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000241
deadbeef0a6c4ca2015-10-06 11:38:28 -0700242 // GetServiceTypeAndHostnameFromUri should never give an empty hoststring
243 RTC_DCHECK(!hoststring.empty());
Tommi77d444a2015-04-24 15:38:38 +0200244
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200245 // Let's break hostname.
246 tokens.clear();
deadbeef0a6c4ca2015-10-06 11:38:28 -0700247 rtc::tokenize_with_empty_tokens(hoststring, '@', &tokens);
248
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200249 std::string username(server.username);
deadbeef0a6c4ca2015-10-06 11:38:28 -0700250 if (tokens.size() > kTurnHostTokensNum) {
251 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring;
252 return false;
253 }
254 if (tokens.size() == kTurnHostTokensNum) {
255 if (tokens[0].empty() || tokens[1].empty()) {
256 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring;
257 return false;
258 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200259 username.assign(rtc::s_url_decode(tokens[0]));
260 hoststring = tokens[1];
261 } else {
262 hoststring = tokens[0];
263 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000264
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200265 int port = kDefaultStunPort;
266 if (service_type == TURNS) {
267 port = kDefaultStunTlsPort;
268 turn_transport_type = kTcpTransportType;
269 }
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000270
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200271 std::string address;
272 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700273 LOG(WARNING) << "Invalid hostname format: " << uri_without_transport;
274 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200275 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000276
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200277 if (port <= 0 || port > 0xffff) {
278 LOG(WARNING) << "Invalid port: " << port;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700279 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200280 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000281
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200282 switch (service_type) {
283 case STUN:
284 case STUNS:
285 stun_config->push_back(StunConfiguration(address, port));
286 break;
287 case TURN:
288 case TURNS: {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200289 bool secure = (service_type == TURNS);
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200290 turn_config->push_back(TurnConfiguration(address, port,
291 username,
292 server.password,
293 turn_transport_type,
294 secure));
295 break;
296 }
297 case INVALID:
298 default:
299 LOG(WARNING) << "Configuration not supported: " << url;
300 return false;
301 }
302 return true;
303}
304
deadbeef0a6c4ca2015-10-06 11:38:28 -0700305} // namespace
306
307namespace webrtc {
308
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200309bool ParseIceServers(const PeerConnectionInterface::IceServers& servers,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700310 StunConfigurations* stun_config,
311 TurnConfigurations* turn_config) {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200312 for (const webrtc::PeerConnectionInterface::IceServer& server : servers) {
313 if (!server.urls.empty()) {
314 for (const std::string& url : server.urls) {
Joachim Bauchd935f912015-05-29 22:14:21 +0200315 if (url.empty()) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700316 LOG(LS_ERROR) << "Empty uri.";
317 return false;
Joachim Bauchd935f912015-05-29 22:14:21 +0200318 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200319 if (!ParseIceServerUrl(server, url, stun_config, turn_config)) {
320 return false;
321 }
322 }
323 } else if (!server.uri.empty()) {
324 // Fallback to old .uri if new .urls isn't present.
325 if (!ParseIceServerUrl(server, server.uri, stun_config, turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000326 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200327 }
328 } else {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700329 LOG(LS_ERROR) << "Empty uri.";
330 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000331 }
332 }
333 return true;
334}
335
336// Check if we can send |new_stream| on a PeerConnection.
337// Currently only one audio but multiple video track is supported per
338// PeerConnection.
339bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
340 webrtc::MediaStreamInterface* new_stream) {
341 if (!new_stream || !current_streams)
342 return false;
343 if (current_streams->find(new_stream->label()) != NULL) {
344 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
345 << " is already added.";
346 return false;
347 }
348
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000349 return true;
350}
351
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000352PeerConnection::PeerConnection(PeerConnectionFactory* factory)
353 : factory_(factory),
354 observer_(NULL),
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000355 uma_observer_(NULL),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000356 signaling_state_(kStable),
357 ice_state_(kIceNew),
358 ice_connection_state_(kIceConnectionNew),
359 ice_gathering_state_(kIceGatheringNew) {
360}
361
362PeerConnection::~PeerConnection() {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700363 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeef70ab1a12015-09-28 16:53:55 -0700364 if (mediastream_signaling_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000365 mediastream_signaling_->TearDown();
deadbeef70ab1a12015-09-28 16:53:55 -0700366 }
367 // Need to detach RTP senders/receivers from WebRtcSession,
368 // since it's about to be destroyed.
369 for (const auto& sender : senders_) {
370 sender->Stop();
371 }
372 for (const auto& receiver : receivers_) {
373 receiver->Stop();
374 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000375}
376
377bool PeerConnection::Initialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000378 const PeerConnectionInterface::RTCConfiguration& configuration,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000379 const MediaConstraintsInterface* constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000380 PortAllocatorFactoryInterface* allocator_factory,
Henrik Boström5e56c592015-08-11 10:33:13 +0200381 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000382 PeerConnectionObserver* observer) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700383 RTC_DCHECK(observer != NULL);
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000384 if (!observer)
385 return false;
386 observer_ = observer;
387
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000388 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
389 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000390 if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000391 return false;
392 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000393 port_allocator_.reset(
394 allocator_factory->CreatePortAllocator(stun_config, turn_config));
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000395
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000396 // To handle both internal and externally created port allocator, we will
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000397 // enable BUNDLE here.
braveyao@webrtc.org1732df62014-10-27 03:01:37 +0000398 int portallocator_flags = port_allocator_->flags();
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700399 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000400 cricket::PORTALLOCATOR_ENABLE_IPV6;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000401 bool value;
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000402 // If IPv6 flag was specified, we'll not override it by experiment.
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000403 if (FindConstraint(
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000404 constraints, MediaConstraintsInterface::kEnableIPv6, &value, NULL)) {
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000405 if (!value) {
406 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000407 }
guoweis@webrtc.org2c1bcea2014-09-23 16:23:02 +0000408 } else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default") ==
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000409 "Disabled") {
410 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000411 }
412
Jiayang Liucac1b382015-04-30 12:35:24 -0700413 if (configuration.tcp_candidate_policy == kTcpCandidatePolicyDisabled) {
414 portallocator_flags |= cricket::PORTALLOCATOR_DISABLE_TCP;
415 LOG(LS_INFO) << "TCP candidates are disabled.";
416 }
417
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000418 port_allocator_->set_flags(portallocator_flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000419 // No step delay is used while allocating ports.
420 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
421
422 mediastream_signaling_.reset(new MediaStreamSignaling(
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000423 factory_->signaling_thread(), this, factory_->channel_manager()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000424
425 session_.reset(new WebRtcSession(factory_->channel_manager(),
426 factory_->signaling_thread(),
427 factory_->worker_thread(),
428 port_allocator_.get(),
429 mediastream_signaling_.get()));
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000430 stats_.reset(new StatsCollector(session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000431
432 // Initialize the WebRtcSession. It creates transport channels etc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000433 if (!session_->Initialize(factory_->options(), constraints,
Henrik Boström5e56c592015-08-11 10:33:13 +0200434 dtls_identity_store.Pass(), configuration))
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000435 return false;
436
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000437 // Register PeerConnection as receiver of local ice candidates.
438 // All the callbacks will be posted to the application from PeerConnection.
439 session_->RegisterIceObserver(this);
440 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
441 return true;
442}
443
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000444rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000445PeerConnection::local_streams() {
446 return mediastream_signaling_->local_streams();
447}
448
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000449rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000450PeerConnection::remote_streams() {
451 return mediastream_signaling_->remote_streams();
452}
453
deadbeef70ab1a12015-09-28 16:53:55 -0700454// TODO(deadbeef): Create RtpSenders immediately here, even if local
455// description hasn't yet been set.
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +0000456bool PeerConnection::AddStream(MediaStreamInterface* local_stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000457 if (IsClosed()) {
458 return false;
459 }
460 if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(),
461 local_stream))
462 return false;
463
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464 if (!mediastream_signaling_->AddLocalStream(local_stream)) {
465 return false;
466 }
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000467 stats_->AddStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000468 observer_->OnRenegotiationNeeded();
469 return true;
470}
471
472void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000473 mediastream_signaling_->RemoveLocalStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000474 if (IsClosed()) {
475 return;
476 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000477 observer_->OnRenegotiationNeeded();
478}
479
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000480rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000481 AudioTrackInterface* track) {
482 if (!track) {
483 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
484 return NULL;
485 }
486 if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) {
487 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
488 return NULL;
489 }
490
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000491 rtc::scoped_refptr<DtmfSenderInterface> sender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000492 DtmfSender::Create(track, signaling_thread(), session_.get()));
493 if (!sender.get()) {
494 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
495 return NULL;
496 }
497 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
498}
499
deadbeef70ab1a12015-09-28 16:53:55 -0700500std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders()
501 const {
502 std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders;
503 for (const auto& sender : senders_) {
504 senders.push_back(RtpSenderProxy::Create(signaling_thread(), sender.get()));
505 }
506 return senders;
507}
508
509std::vector<rtc::scoped_refptr<RtpReceiverInterface>>
510PeerConnection::GetReceivers() const {
511 std::vector<rtc::scoped_refptr<RtpReceiverInterface>> receivers;
512 for (const auto& receiver : receivers_) {
513 receivers.push_back(
514 RtpReceiverProxy::Create(signaling_thread(), receiver.get()));
515 }
516 return receivers;
517}
518
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000519bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000520 MediaStreamTrackInterface* track,
521 StatsOutputLevel level) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700522 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000523 if (!VERIFY(observer != NULL)) {
524 LOG(LS_ERROR) << "GetStats - observer is NULL.";
525 return false;
526 }
527
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000528 stats_->UpdateStats(level);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000529 signaling_thread()->Post(this, MSG_GETSTATS,
530 new GetStatsMsg(observer, track));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000531 return true;
532}
533
534PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
535 return signaling_state_;
536}
537
538PeerConnectionInterface::IceState PeerConnection::ice_state() {
539 return ice_state_;
540}
541
542PeerConnectionInterface::IceConnectionState
543PeerConnection::ice_connection_state() {
544 return ice_connection_state_;
545}
546
547PeerConnectionInterface::IceGatheringState
548PeerConnection::ice_gathering_state() {
549 return ice_gathering_state_;
550}
551
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000552rtc::scoped_refptr<DataChannelInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000553PeerConnection::CreateDataChannel(
554 const std::string& label,
555 const DataChannelInit* config) {
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000556 bool first_datachannel = !mediastream_signaling_->HasDataChannels();
557
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000558 rtc::scoped_ptr<InternalDataChannelInit> internal_config;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000559 if (config) {
560 internal_config.reset(new InternalDataChannelInit(*config));
561 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000562 rtc::scoped_refptr<DataChannelInterface> channel(
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000563 session_->CreateDataChannel(label, internal_config.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000564 if (!channel.get())
565 return NULL;
566
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000567 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
568 // the first SCTP DataChannel.
569 if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
570 observer_->OnRenegotiationNeeded();
571 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000572
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000573 return DataChannelProxy::Create(signaling_thread(), channel.get());
574}
575
576void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
577 const MediaConstraintsInterface* constraints) {
578 if (!VERIFY(observer != NULL)) {
579 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
580 return;
581 }
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000582 RTCOfferAnswerOptions options;
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000583
584 bool value;
585 size_t mandatory_constraints = 0;
586
587 if (FindConstraint(constraints,
588 MediaConstraintsInterface::kOfferToReceiveAudio,
589 &value,
590 &mandatory_constraints)) {
591 options.offer_to_receive_audio =
592 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
593 }
594
595 if (FindConstraint(constraints,
596 MediaConstraintsInterface::kOfferToReceiveVideo,
597 &value,
598 &mandatory_constraints)) {
599 options.offer_to_receive_video =
600 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
601 }
602
603 if (FindConstraint(constraints,
604 MediaConstraintsInterface::kVoiceActivityDetection,
605 &value,
606 &mandatory_constraints)) {
607 options.voice_activity_detection = value;
608 }
609
610 if (FindConstraint(constraints,
611 MediaConstraintsInterface::kIceRestart,
612 &value,
613 &mandatory_constraints)) {
614 options.ice_restart = value;
615 }
616
617 if (FindConstraint(constraints,
618 MediaConstraintsInterface::kUseRtpMux,
619 &value,
620 &mandatory_constraints)) {
621 options.use_rtp_mux = value;
622 }
623
624 CreateOffer(observer, options);
625}
626
627void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
628 const RTCOfferAnswerOptions& options) {
629 if (!VERIFY(observer != NULL)) {
630 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
631 return;
632 }
633 session_->CreateOffer(observer, options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000634}
635
636void PeerConnection::CreateAnswer(
637 CreateSessionDescriptionObserver* observer,
638 const MediaConstraintsInterface* constraints) {
639 if (!VERIFY(observer != NULL)) {
640 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
641 return;
642 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000643 session_->CreateAnswer(observer, constraints);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000644}
645
646void PeerConnection::SetLocalDescription(
647 SetSessionDescriptionObserver* observer,
648 SessionDescriptionInterface* desc) {
649 if (!VERIFY(observer != NULL)) {
650 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
651 return;
652 }
653 if (!desc) {
654 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
655 return;
656 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000657 // Update stats here so that we have the most recent stats for tracks and
658 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000659 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000660 std::string error;
661 if (!session_->SetLocalDescription(desc, &error)) {
662 PostSetSessionDescriptionFailure(observer, error);
663 return;
664 }
665 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
666 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeefcbecd352015-09-23 11:50:27 -0700667 // MaybeStartGathering needs to be called after posting
668 // MSG_SET_SESSIONDESCRIPTION_SUCCESS, so that we don't signal any candidates
669 // before signaling that SetLocalDescription completed.
670 session_->MaybeStartGathering();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000671}
672
673void PeerConnection::SetRemoteDescription(
674 SetSessionDescriptionObserver* observer,
675 SessionDescriptionInterface* desc) {
676 if (!VERIFY(observer != NULL)) {
677 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
678 return;
679 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000680 if (!desc) {
681 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
682 return;
683 }
684 // Update stats here so that we have the most recent stats for tracks and
685 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000686 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000687 std::string error;
688 if (!session_->SetRemoteDescription(desc, &error)) {
689 PostSetSessionDescriptionFailure(observer, error);
690 return;
691 }
692 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
693 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
694}
695
696void PeerConnection::PostSetSessionDescriptionFailure(
697 SetSessionDescriptionObserver* observer,
698 const std::string& error) {
699 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
700 msg->error = error;
701 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
702}
703
deadbeefa67696b2015-09-29 11:56:26 -0700704bool PeerConnection::SetConfiguration(const RTCConfiguration& config) {
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000705 if (port_allocator_) {
706 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
707 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
708 if (!ParseIceServers(config.servers, &stuns, &turns)) {
709 return false;
710 }
711
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000712 std::vector<rtc::SocketAddress> stun_hosts;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000713 typedef std::vector<StunConfiguration>::const_iterator StunIt;
714 for (StunIt stun_it = stuns.begin(); stun_it != stuns.end(); ++stun_it) {
715 stun_hosts.push_back(stun_it->server);
716 }
717
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000718 rtc::SocketAddress stun_addr;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000719 if (!stun_hosts.empty()) {
720 stun_addr = stun_hosts.front();
deadbeefa67696b2015-09-29 11:56:26 -0700721 LOG(LS_INFO) << "SetConfiguration: StunServer Address: "
722 << stun_addr.ToString();
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000723 }
724
725 for (size_t i = 0; i < turns.size(); ++i) {
726 cricket::RelayCredentials credentials(turns[i].username,
727 turns[i].password);
728 cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
729 cricket::ProtocolType protocol;
730 if (cricket::StringToProto(turns[i].transport_type.c_str(), &protocol)) {
731 relay_server.ports.push_back(cricket::ProtocolAddress(
732 turns[i].server, protocol, turns[i].secure));
733 relay_server.credentials = credentials;
deadbeefa67696b2015-09-29 11:56:26 -0700734 LOG(LS_INFO) << "SetConfiguration: TurnServer Address: "
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000735 << turns[i].server.ToString();
736 } else {
737 LOG(LS_WARNING) << "Ignoring TURN server " << turns[i].server << ". "
738 << "Reason= Incorrect " << turns[i].transport_type
739 << " transport parameter.";
740 }
741 }
742 }
honghaiz1f429e32015-09-28 07:57:34 -0700743 session_->SetIceConfig(session_->ParseIceConfig(config));
mallinath@webrtc.org3d81b1b2014-09-09 14:38:10 +0000744 return session_->SetIceTransports(config.type);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000745}
746
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000747bool PeerConnection::AddIceCandidate(
748 const IceCandidateInterface* ice_candidate) {
749 return session_->ProcessIceMessage(ice_candidate);
750}
751
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000752void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
753 uma_observer_ = observer;
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +0000754
755 if (session_) {
756 session_->set_metrics_observer(uma_observer_);
757 }
758
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +0000759 // Send information about IPv4/IPv6 status.
760 if (uma_observer_ && port_allocator_) {
761 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -0700762 uma_observer_->IncrementEnumCounter(
763 kEnumCounterAddressFamily, kPeerConnection_IPv6,
764 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgb445f262014-05-23 22:19:37 +0000765 } else {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -0700766 uma_observer_->IncrementEnumCounter(
767 kEnumCounterAddressFamily, kPeerConnection_IPv4,
768 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +0000769 }
770 }
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000771}
772
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000773const SessionDescriptionInterface* PeerConnection::local_description() const {
774 return session_->local_description();
775}
776
777const SessionDescriptionInterface* PeerConnection::remote_description() const {
778 return session_->remote_description();
779}
780
781void PeerConnection::Close() {
782 // Update stats here so that we have the most recent stats for tracks and
783 // streams before the channels are closed.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000784 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000785
786 session_->Terminate();
787}
788
789void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
790 cricket::BaseSession::State state) {
791 switch (state) {
792 case cricket::BaseSession::STATE_INIT:
793 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000794 break;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000795 case cricket::BaseSession::STATE_SENTINITIATE:
796 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
797 break;
798 case cricket::BaseSession::STATE_SENTPRACCEPT:
799 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
800 break;
801 case cricket::BaseSession::STATE_RECEIVEDINITIATE:
802 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
803 break;
804 case cricket::BaseSession::STATE_RECEIVEDPRACCEPT:
805 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
806 break;
807 case cricket::BaseSession::STATE_SENTACCEPT:
808 case cricket::BaseSession::STATE_RECEIVEDACCEPT:
809 ChangeSignalingState(PeerConnectionInterface::kStable);
810 break;
811 case cricket::BaseSession::STATE_RECEIVEDTERMINATE:
812 ChangeSignalingState(PeerConnectionInterface::kClosed);
813 break;
814 default:
815 break;
816 }
817}
818
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000819void PeerConnection::OnMessage(rtc::Message* msg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000820 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
822 SetSessionDescriptionMsg* param =
823 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
824 param->observer->OnSuccess();
825 delete param;
826 break;
827 }
828 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
829 SetSessionDescriptionMsg* param =
830 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
831 param->observer->OnFailure(param->error);
832 delete param;
833 break;
834 }
835 case MSG_GETSTATS: {
836 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000837 StatsReports reports;
838 stats_->GetStats(param->track, &reports);
839 param->observer->OnComplete(reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000840 delete param;
841 break;
842 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000843 default:
deadbeef0a6c4ca2015-10-06 11:38:28 -0700844 RTC_DCHECK(false && "Not implemented");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000845 break;
846 }
847}
848
849void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000850 stats_->AddStream(stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000851 observer_->OnAddStream(stream);
852}
853
854void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000855 observer_->OnRemoveStream(stream);
856}
857
858void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
859 observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
860 data_channel));
861}
862
863void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
864 AudioTrackInterface* audio_track,
865 uint32 ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -0700866 receivers_.push_back(new AudioRtpReceiver(audio_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000867}
868
869void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
870 VideoTrackInterface* video_track,
871 uint32 ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -0700872 receivers_.push_back(new VideoRtpReceiver(video_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000873}
874
deadbeef70ab1a12015-09-28 16:53:55 -0700875// TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote
876// description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000877void PeerConnection::OnRemoveRemoteAudioTrack(
878 MediaStreamInterface* stream,
879 AudioTrackInterface* audio_track) {
deadbeef70ab1a12015-09-28 16:53:55 -0700880 auto it = FindReceiverForTrack(audio_track);
881 if (it == receivers_.end()) {
882 LOG(LS_WARNING) << "RtpReceiver for track with id " << audio_track->id()
883 << " doesn't exist.";
884 } else {
885 (*it)->Stop();
886 receivers_.erase(it);
887 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000888}
889
890void PeerConnection::OnRemoveRemoteVideoTrack(
891 MediaStreamInterface* stream,
892 VideoTrackInterface* video_track) {
deadbeef70ab1a12015-09-28 16:53:55 -0700893 auto it = FindReceiverForTrack(video_track);
894 if (it == receivers_.end()) {
895 LOG(LS_WARNING) << "RtpReceiver for track with id " << video_track->id()
896 << " doesn't exist.";
897 } else {
898 (*it)->Stop();
899 receivers_.erase(it);
900 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000901}
deadbeef70ab1a12015-09-28 16:53:55 -0700902
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000903void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
904 AudioTrackInterface* audio_track,
905 uint32 ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -0700906 senders_.push_back(new AudioRtpSender(audio_track, ssrc, session_.get()));
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000907 stats_->AddLocalAudioTrack(audio_track, ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000908}
deadbeef70ab1a12015-09-28 16:53:55 -0700909
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000910void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
911 VideoTrackInterface* video_track,
912 uint32 ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -0700913 senders_.push_back(new VideoRtpSender(video_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000914}
915
deadbeef70ab1a12015-09-28 16:53:55 -0700916// TODO(deadbeef): Keep RtpSenders around even if track goes away in local
917// description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000918void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000919 AudioTrackInterface* audio_track,
920 uint32 ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -0700921 auto it = FindSenderForTrack(audio_track);
922 if (it == senders_.end()) {
923 LOG(LS_WARNING) << "RtpSender for track with id " << audio_track->id()
924 << " doesn't exist.";
925 return;
926 } else {
927 (*it)->Stop();
928 senders_.erase(it);
929 }
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000930 stats_->RemoveLocalAudioTrack(audio_track, ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000931}
932
933void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
934 VideoTrackInterface* video_track) {
deadbeef70ab1a12015-09-28 16:53:55 -0700935 auto it = FindSenderForTrack(video_track);
936 if (it == senders_.end()) {
937 LOG(LS_WARNING) << "RtpSender for track with id " << video_track->id()
938 << " doesn't exist.";
939 return;
940 } else {
941 (*it)->Stop();
942 senders_.erase(it);
943 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000944}
945
946void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000947}
948
949void PeerConnection::OnIceConnectionChange(
950 PeerConnectionInterface::IceConnectionState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700951 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefcbecd352015-09-23 11:50:27 -0700952 // After transitioning to "closed", ignore any additional states from
953 // WebRtcSession (such as "disconnected").
954 if (ice_connection_state_ == kIceConnectionClosed) {
955 return;
956 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000957 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000958 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000959}
960
961void PeerConnection::OnIceGatheringChange(
962 PeerConnectionInterface::IceGatheringState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700963 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000964 if (IsClosed()) {
965 return;
966 }
967 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000968 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000969}
970
971void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700972 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000973 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000974}
975
976void PeerConnection::OnIceComplete() {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700977 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000978 observer_->OnIceComplete();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000979}
980
Peter Thatcher54360512015-07-08 11:08:35 -0700981void PeerConnection::OnIceConnectionReceivingChange(bool receiving) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700982 RTC_DCHECK(signaling_thread()->IsCurrent());
Peter Thatcher54360512015-07-08 11:08:35 -0700983 observer_->OnIceConnectionReceivingChange(receiving);
984}
985
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000986void PeerConnection::ChangeSignalingState(
987 PeerConnectionInterface::SignalingState signaling_state) {
988 signaling_state_ = signaling_state;
989 if (signaling_state == kClosed) {
990 ice_connection_state_ = kIceConnectionClosed;
991 observer_->OnIceConnectionChange(ice_connection_state_);
992 if (ice_gathering_state_ != kIceGatheringComplete) {
993 ice_gathering_state_ = kIceGatheringComplete;
994 observer_->OnIceGatheringChange(ice_gathering_state_);
995 }
996 }
997 observer_->OnSignalingChange(signaling_state_);
998 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
999}
1000
deadbeef70ab1a12015-09-28 16:53:55 -07001001std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator
1002PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) {
1003 return std::find_if(
1004 senders_.begin(), senders_.end(),
1005 [track](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
1006 return sender->track() == track;
1007 });
1008}
1009
1010std::vector<rtc::scoped_refptr<RtpReceiverInterface>>::iterator
1011PeerConnection::FindReceiverForTrack(MediaStreamTrackInterface* track) {
1012 return std::find_if(
1013 receivers_.begin(), receivers_.end(),
1014 [track](const rtc::scoped_refptr<RtpReceiverInterface>& receiver) {
1015 return receiver->track() == track;
1016 });
1017}
1018
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001019} // namespace webrtc