blob: 121565593d718c83e2f884268a59c3e090691a1a [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>
31
32#include "talk/app/webrtc/dtmfsender.h"
33#include "talk/app/webrtc/jsepicecandidate.h"
34#include "talk/app/webrtc/jsepsessiondescription.h"
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +000035#include "talk/app/webrtc/mediaconstraintsinterface.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000036#include "talk/app/webrtc/mediastreamhandler.h"
37#include "talk/app/webrtc/streamcollection.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000038#include "webrtc/p2p/client/basicportallocator.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000039#include "talk/session/media/channelmanager.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000040#include "webrtc/base/logging.h"
41#include "webrtc/base/stringencode.h"
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +000042#include "webrtc/system_wrappers/interface/field_trial.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000043
44namespace {
45
46using webrtc::PeerConnectionInterface;
47
henrike@webrtc.org28e20752013-07-10 00:45:36 +000048// The min number of tokens must present in Turn host uri.
49// e.g. user@turn.example.org
50static const size_t kTurnHostTokensNum = 2;
51// Number of tokens must be preset when TURN uri has transport param.
52static const size_t kTurnTransportTokensNum = 2;
53// The default stun port.
wu@webrtc.org91053e72013-08-10 07:18:04 +000054static const int kDefaultStunPort = 3478;
55static const int kDefaultStunTlsPort = 5349;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056static const char kTransport[] = "transport";
wu@webrtc.org91053e72013-08-10 07:18:04 +000057static const char kUdpTransportType[] = "udp";
58static const char kTcpTransportType[] = "tcp";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059
60// NOTE: Must be in the same order as the ServiceType enum.
61static const char* kValidIceServiceTypes[] = {
62 "stun", "stuns", "turn", "turns", "invalid" };
63
64enum ServiceType {
65 STUN, // Indicates a STUN server.
66 STUNS, // Indicates a STUN server used with a TLS session.
67 TURN, // Indicates a TURN server
68 TURNS, // Indicates a TURN server used with a TLS session.
69 INVALID, // Unknown.
70};
71
72enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +000073 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000074 MSG_SET_SESSIONDESCRIPTION_FAILED,
75 MSG_GETSTATS,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076};
77
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000078struct SetSessionDescriptionMsg : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000079 explicit SetSessionDescriptionMsg(
80 webrtc::SetSessionDescriptionObserver* observer)
81 : observer(observer) {
82 }
83
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000084 rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000085 std::string error;
86};
87
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000088struct GetStatsMsg : public rtc::MessageData {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +000089 GetStatsMsg(webrtc::StatsObserver* observer,
90 webrtc::MediaStreamTrackInterface* track)
91 : observer(observer), track(track) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000092 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000093 rtc::scoped_refptr<webrtc::StatsObserver> observer;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +000094 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000095};
96
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +000097// |in_str| should be of format
98// stunURI = scheme ":" stun-host [ ":" stun-port ]
99// scheme = "stun" / "stuns"
100// stun-host = IP-literal / IPv4address / reg-name
101// stun-port = *DIGIT
102
103// draft-petithuguenin-behave-turn-uris-01
104// turnURI = scheme ":" turn-host [ ":" turn-port ]
105// turn-host = username@IP-literal / IPv4address / reg-name
106bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
107 ServiceType* service_type,
108 std::string* hostname) {
Tommi77d444a2015-04-24 15:38:38 +0200109 const std::string::size_type colonpos = in_str.find(':');
110 if (colonpos == std::string::npos || (colonpos + 1) == in_str.length()) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000111 return false;
112 }
113 std::string type = in_str.substr(0, colonpos);
114 for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
115 if (type.compare(kValidIceServiceTypes[i]) == 0) {
116 *service_type = static_cast<ServiceType>(i);
117 break;
118 }
119 }
120 if (*service_type == INVALID) {
121 return false;
122 }
123 *hostname = in_str.substr(colonpos + 1, std::string::npos);
124 return true;
125}
126
127// This method parses IPv6 and IPv4 literal strings, along with hostnames in
128// standard hostname:port format.
129// Consider following formats as correct.
130// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
131// |hostname|, |[IPv6 address]|, |IPv4 address|
132bool ParseHostnameAndPortFromString(const std::string& in_str,
133 std::string* host,
134 int* port) {
135 if (in_str.at(0) == '[') {
136 std::string::size_type closebracket = in_str.rfind(']');
137 if (closebracket != std::string::npos) {
138 *host = in_str.substr(1, closebracket - 1);
139 std::string::size_type colonpos = in_str.find(':', closebracket);
140 if (std::string::npos != colonpos) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000141 if (!rtc::FromString(
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000142 in_str.substr(closebracket + 2, std::string::npos), port)) {
143 return false;
144 }
145 }
146 } else {
147 return false;
148 }
149 } else {
150 std::string::size_type colonpos = in_str.find(':');
151 if (std::string::npos != colonpos) {
152 *host = in_str.substr(0, colonpos);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000153 if (!rtc::FromString(
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000154 in_str.substr(colonpos + 1, std::string::npos), port)) {
155 return false;
156 }
157 } else {
158 *host = in_str;
159 }
160 }
161 return true;
162}
163
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000164typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
165 StunConfiguration;
166typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
167 TurnConfiguration;
168
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200169bool ParseIceServerUrl(const PeerConnectionInterface::IceServer& server,
170 const std::string& url,
171 std::vector<StunConfiguration>* stun_config,
172 std::vector<TurnConfiguration>* turn_config) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000173 // draft-nandakumar-rtcweb-stun-uri-01
174 // stunURI = scheme ":" stun-host [ ":" stun-port ]
175 // scheme = "stun" / "stuns"
176 // stun-host = IP-literal / IPv4address / reg-name
177 // stun-port = *DIGIT
178
179 // draft-petithuguenin-behave-turn-uris-01
180 // turnURI = scheme ":" turn-host [ ":" turn-port ]
181 // [ "?transport=" transport ]
182 // scheme = "turn" / "turns"
183 // transport = "udp" / "tcp" / transport-ext
184 // transport-ext = 1*unreserved
185 // turn-host = IP-literal / IPv4address / reg-name
186 // turn-port = *DIGIT
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200187 std::vector<std::string> tokens;
188 std::string turn_transport_type = kUdpTransportType;
Joachim Bauchd935f912015-05-29 22:14:21 +0200189 ASSERT(!url.empty());
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200190 rtc::tokenize(url, '?', &tokens);
191 std::string uri_without_transport = tokens[0];
192 // Let's look into transport= param, if it exists.
193 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
194 std::string uri_transport_param = tokens[1];
195 rtc::tokenize(uri_transport_param, '=', &tokens);
196 if (tokens[0] == kTransport) {
197 // As per above grammar transport param will be consist of lower case
198 // letters.
199 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
200 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
201 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000202 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200203 turn_transport_type = tokens[1];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000204 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200205 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000206
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200207 std::string hoststring;
208 ServiceType service_type = INVALID;
209 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
210 &service_type,
211 &hoststring)) {
212 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: "
213 << uri_without_transport;
214 return true;
215 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000216
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200217 ASSERT(!hoststring.empty());
Tommi77d444a2015-04-24 15:38:38 +0200218
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200219 // Let's break hostname.
220 tokens.clear();
221 rtc::tokenize(hoststring, '@', &tokens);
222 ASSERT(!tokens.empty());
223 std::string username(server.username);
224 // TODO(pthatcher): What's the right thing to do if tokens.size() is >2?
225 // E.g. a string like "foo@bar@bat".
226 if (tokens.size() >= kTurnHostTokensNum) {
227 username.assign(rtc::s_url_decode(tokens[0]));
228 hoststring = tokens[1];
229 } else {
230 hoststring = tokens[0];
231 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000232
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200233 int port = kDefaultStunPort;
234 if (service_type == TURNS) {
235 port = kDefaultStunTlsPort;
236 turn_transport_type = kTcpTransportType;
237 }
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000238
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200239 std::string address;
240 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
241 LOG(WARNING) << "Invalid Hostname format: " << uri_without_transport;
242 return true;
243 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000244
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200245 if (port <= 0 || port > 0xffff) {
246 LOG(WARNING) << "Invalid port: " << port;
247 return true;
248 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000249
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200250 switch (service_type) {
251 case STUN:
252 case STUNS:
253 stun_config->push_back(StunConfiguration(address, port));
254 break;
255 case TURN:
256 case TURNS: {
257 if (username.empty()) {
258 // Turn url example from the spec |url:"turn:user@turn.example.org"|.
259 std::vector<std::string> turn_tokens;
260 rtc::tokenize(address, '@', &turn_tokens);
261 if (turn_tokens.size() == kTurnHostTokensNum) {
262 username.assign(rtc::s_url_decode(turn_tokens[0]));
263 address = turn_tokens[1];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000264 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000265 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200266
267 bool secure = (service_type == TURNS);
268
269 turn_config->push_back(TurnConfiguration(address, port,
270 username,
271 server.password,
272 turn_transport_type,
273 secure));
274 break;
275 }
276 case INVALID:
277 default:
278 LOG(WARNING) << "Configuration not supported: " << url;
279 return false;
280 }
281 return true;
282}
283
284bool ParseIceServers(const PeerConnectionInterface::IceServers& servers,
285 std::vector<StunConfiguration>* stun_config,
286 std::vector<TurnConfiguration>* turn_config) {
287 for (const webrtc::PeerConnectionInterface::IceServer& server : servers) {
288 if (!server.urls.empty()) {
289 for (const std::string& url : server.urls) {
Joachim Bauchd935f912015-05-29 22:14:21 +0200290 if (url.empty()) {
291 LOG(WARNING) << "Empty uri.";
292 continue;
293 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200294 if (!ParseIceServerUrl(server, url, stun_config, turn_config)) {
295 return false;
296 }
297 }
298 } else if (!server.uri.empty()) {
299 // Fallback to old .uri if new .urls isn't present.
300 if (!ParseIceServerUrl(server, server.uri, stun_config, turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000301 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200302 }
303 } else {
304 LOG(WARNING) << "Empty uri.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000305 }
306 }
307 return true;
308}
309
310// Check if we can send |new_stream| on a PeerConnection.
311// Currently only one audio but multiple video track is supported per
312// PeerConnection.
313bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
314 webrtc::MediaStreamInterface* new_stream) {
315 if (!new_stream || !current_streams)
316 return false;
317 if (current_streams->find(new_stream->label()) != NULL) {
318 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
319 << " is already added.";
320 return false;
321 }
322
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000323 return true;
324}
325
326} // namespace
327
328namespace webrtc {
329
330PeerConnection::PeerConnection(PeerConnectionFactory* factory)
331 : factory_(factory),
332 observer_(NULL),
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000333 uma_observer_(NULL),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000334 signaling_state_(kStable),
335 ice_state_(kIceNew),
336 ice_connection_state_(kIceConnectionNew),
337 ice_gathering_state_(kIceGatheringNew) {
338}
339
340PeerConnection::~PeerConnection() {
tommi0f620f42015-07-09 03:25:02 -0700341 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000342 if (mediastream_signaling_)
343 mediastream_signaling_->TearDown();
344 if (stream_handler_container_)
345 stream_handler_container_->TearDown();
346}
347
348bool PeerConnection::Initialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000349 const PeerConnectionInterface::RTCConfiguration& configuration,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000350 const MediaConstraintsInterface* constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000351 PortAllocatorFactoryInterface* allocator_factory,
Henrik Boström5e56c592015-08-11 10:33:13 +0200352 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000353 PeerConnectionObserver* observer) {
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000354 ASSERT(observer != NULL);
355 if (!observer)
356 return false;
357 observer_ = observer;
358
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000359 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
360 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000361 if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000362 return false;
363 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000364 port_allocator_.reset(
365 allocator_factory->CreatePortAllocator(stun_config, turn_config));
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000366
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000367 // To handle both internal and externally created port allocator, we will
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000368 // enable BUNDLE here.
braveyao@webrtc.org1732df62014-10-27 03:01:37 +0000369 int portallocator_flags = port_allocator_->flags();
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700370 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000371 cricket::PORTALLOCATOR_ENABLE_IPV6;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000372 bool value;
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000373 // If IPv6 flag was specified, we'll not override it by experiment.
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000374 if (FindConstraint(
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000375 constraints, MediaConstraintsInterface::kEnableIPv6, &value, NULL)) {
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000376 if (!value) {
377 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000378 }
guoweis@webrtc.org2c1bcea2014-09-23 16:23:02 +0000379 } else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default") ==
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000380 "Disabled") {
381 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000382 }
383
Jiayang Liucac1b382015-04-30 12:35:24 -0700384 if (configuration.tcp_candidate_policy == kTcpCandidatePolicyDisabled) {
385 portallocator_flags |= cricket::PORTALLOCATOR_DISABLE_TCP;
386 LOG(LS_INFO) << "TCP candidates are disabled.";
387 }
388
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000389 port_allocator_->set_flags(portallocator_flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000390 // No step delay is used while allocating ports.
391 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
392
393 mediastream_signaling_.reset(new MediaStreamSignaling(
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000394 factory_->signaling_thread(), this, factory_->channel_manager()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000395
396 session_.reset(new WebRtcSession(factory_->channel_manager(),
397 factory_->signaling_thread(),
398 factory_->worker_thread(),
399 port_allocator_.get(),
400 mediastream_signaling_.get()));
401 stream_handler_container_.reset(new MediaStreamHandlerContainer(
402 session_.get(), session_.get()));
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000403 stats_.reset(new StatsCollector(session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000404
405 // Initialize the WebRtcSession. It creates transport channels etc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000406 if (!session_->Initialize(factory_->options(), constraints,
Henrik Boström5e56c592015-08-11 10:33:13 +0200407 dtls_identity_store.Pass(), configuration))
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000408 return false;
409
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000410 // Register PeerConnection as receiver of local ice candidates.
411 // All the callbacks will be posted to the application from PeerConnection.
412 session_->RegisterIceObserver(this);
413 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
414 return true;
415}
416
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000417rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000418PeerConnection::local_streams() {
419 return mediastream_signaling_->local_streams();
420}
421
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000422rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000423PeerConnection::remote_streams() {
424 return mediastream_signaling_->remote_streams();
425}
426
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +0000427bool PeerConnection::AddStream(MediaStreamInterface* local_stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000428 if (IsClosed()) {
429 return false;
430 }
431 if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(),
432 local_stream))
433 return false;
434
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000435 if (!mediastream_signaling_->AddLocalStream(local_stream)) {
436 return false;
437 }
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000438 stats_->AddStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000439 observer_->OnRenegotiationNeeded();
440 return true;
441}
442
443void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000444 mediastream_signaling_->RemoveLocalStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000445 if (IsClosed()) {
446 return;
447 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000448 observer_->OnRenegotiationNeeded();
449}
450
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000451rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000452 AudioTrackInterface* track) {
453 if (!track) {
454 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
455 return NULL;
456 }
457 if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) {
458 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
459 return NULL;
460 }
461
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000462 rtc::scoped_refptr<DtmfSenderInterface> sender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000463 DtmfSender::Create(track, signaling_thread(), session_.get()));
464 if (!sender.get()) {
465 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
466 return NULL;
467 }
468 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
469}
470
471bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000472 MediaStreamTrackInterface* track,
473 StatsOutputLevel level) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000474 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000475 if (!VERIFY(observer != NULL)) {
476 LOG(LS_ERROR) << "GetStats - observer is NULL.";
477 return false;
478 }
479
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000480 stats_->UpdateStats(level);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000481 signaling_thread()->Post(this, MSG_GETSTATS,
482 new GetStatsMsg(observer, track));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000483 return true;
484}
485
486PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
487 return signaling_state_;
488}
489
490PeerConnectionInterface::IceState PeerConnection::ice_state() {
491 return ice_state_;
492}
493
494PeerConnectionInterface::IceConnectionState
495PeerConnection::ice_connection_state() {
496 return ice_connection_state_;
497}
498
499PeerConnectionInterface::IceGatheringState
500PeerConnection::ice_gathering_state() {
501 return ice_gathering_state_;
502}
503
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000504rtc::scoped_refptr<DataChannelInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505PeerConnection::CreateDataChannel(
506 const std::string& label,
507 const DataChannelInit* config) {
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000508 bool first_datachannel = !mediastream_signaling_->HasDataChannels();
509
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000510 rtc::scoped_ptr<InternalDataChannelInit> internal_config;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000511 if (config) {
512 internal_config.reset(new InternalDataChannelInit(*config));
513 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000514 rtc::scoped_refptr<DataChannelInterface> channel(
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000515 session_->CreateDataChannel(label, internal_config.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000516 if (!channel.get())
517 return NULL;
518
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000519 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
520 // the first SCTP DataChannel.
521 if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
522 observer_->OnRenegotiationNeeded();
523 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000524
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000525 return DataChannelProxy::Create(signaling_thread(), channel.get());
526}
527
528void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
529 const MediaConstraintsInterface* constraints) {
530 if (!VERIFY(observer != NULL)) {
531 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
532 return;
533 }
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000534 RTCOfferAnswerOptions options;
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000535
536 bool value;
537 size_t mandatory_constraints = 0;
538
539 if (FindConstraint(constraints,
540 MediaConstraintsInterface::kOfferToReceiveAudio,
541 &value,
542 &mandatory_constraints)) {
543 options.offer_to_receive_audio =
544 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
545 }
546
547 if (FindConstraint(constraints,
548 MediaConstraintsInterface::kOfferToReceiveVideo,
549 &value,
550 &mandatory_constraints)) {
551 options.offer_to_receive_video =
552 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
553 }
554
555 if (FindConstraint(constraints,
556 MediaConstraintsInterface::kVoiceActivityDetection,
557 &value,
558 &mandatory_constraints)) {
559 options.voice_activity_detection = value;
560 }
561
562 if (FindConstraint(constraints,
563 MediaConstraintsInterface::kIceRestart,
564 &value,
565 &mandatory_constraints)) {
566 options.ice_restart = value;
567 }
568
569 if (FindConstraint(constraints,
570 MediaConstraintsInterface::kUseRtpMux,
571 &value,
572 &mandatory_constraints)) {
573 options.use_rtp_mux = value;
574 }
575
576 CreateOffer(observer, options);
577}
578
579void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
580 const RTCOfferAnswerOptions& options) {
581 if (!VERIFY(observer != NULL)) {
582 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
583 return;
584 }
585 session_->CreateOffer(observer, options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586}
587
588void PeerConnection::CreateAnswer(
589 CreateSessionDescriptionObserver* observer,
590 const MediaConstraintsInterface* constraints) {
591 if (!VERIFY(observer != NULL)) {
592 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
593 return;
594 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000595 session_->CreateAnswer(observer, constraints);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000596}
597
598void PeerConnection::SetLocalDescription(
599 SetSessionDescriptionObserver* observer,
600 SessionDescriptionInterface* desc) {
601 if (!VERIFY(observer != NULL)) {
602 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
603 return;
604 }
605 if (!desc) {
606 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
607 return;
608 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000609 // Update stats here so that we have the most recent stats for tracks and
610 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000611 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612 std::string error;
613 if (!session_->SetLocalDescription(desc, &error)) {
614 PostSetSessionDescriptionFailure(observer, error);
615 return;
616 }
617 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
618 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeefcbecd352015-09-23 11:50:27 -0700619 // MaybeStartGathering needs to be called after posting
620 // MSG_SET_SESSIONDESCRIPTION_SUCCESS, so that we don't signal any candidates
621 // before signaling that SetLocalDescription completed.
622 session_->MaybeStartGathering();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000623}
624
625void PeerConnection::SetRemoteDescription(
626 SetSessionDescriptionObserver* observer,
627 SessionDescriptionInterface* desc) {
628 if (!VERIFY(observer != NULL)) {
629 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
630 return;
631 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632 if (!desc) {
633 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
634 return;
635 }
636 // Update stats here so that we have the most recent stats for tracks and
637 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000638 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000639 std::string error;
640 if (!session_->SetRemoteDescription(desc, &error)) {
641 PostSetSessionDescriptionFailure(observer, error);
642 return;
643 }
644 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
645 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
646}
647
648void PeerConnection::PostSetSessionDescriptionFailure(
649 SetSessionDescriptionObserver* observer,
650 const std::string& error) {
651 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
652 msg->error = error;
653 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
654}
655
656bool PeerConnection::UpdateIce(const IceServers& configuration,
657 const MediaConstraintsInterface* constraints) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658 return false;
659}
660
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000661bool PeerConnection::UpdateIce(const RTCConfiguration& config) {
662 if (port_allocator_) {
663 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
664 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
665 if (!ParseIceServers(config.servers, &stuns, &turns)) {
666 return false;
667 }
668
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000669 std::vector<rtc::SocketAddress> stun_hosts;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000670 typedef std::vector<StunConfiguration>::const_iterator StunIt;
671 for (StunIt stun_it = stuns.begin(); stun_it != stuns.end(); ++stun_it) {
672 stun_hosts.push_back(stun_it->server);
673 }
674
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000675 rtc::SocketAddress stun_addr;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000676 if (!stun_hosts.empty()) {
677 stun_addr = stun_hosts.front();
678 LOG(LS_INFO) << "UpdateIce: StunServer Address: " << stun_addr.ToString();
679 }
680
681 for (size_t i = 0; i < turns.size(); ++i) {
682 cricket::RelayCredentials credentials(turns[i].username,
683 turns[i].password);
684 cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
685 cricket::ProtocolType protocol;
686 if (cricket::StringToProto(turns[i].transport_type.c_str(), &protocol)) {
687 relay_server.ports.push_back(cricket::ProtocolAddress(
688 turns[i].server, protocol, turns[i].secure));
689 relay_server.credentials = credentials;
690 LOG(LS_INFO) << "UpdateIce: TurnServer Address: "
691 << turns[i].server.ToString();
692 } else {
693 LOG(LS_WARNING) << "Ignoring TURN server " << turns[i].server << ". "
694 << "Reason= Incorrect " << turns[i].transport_type
695 << " transport parameter.";
696 }
697 }
698 }
honghaiz4edc39c2015-09-01 09:53:56 -0700699 session_->SetIceConnectionReceivingTimeout(
700 config.ice_connection_receiving_timeout);
mallinath@webrtc.org3d81b1b2014-09-09 14:38:10 +0000701 return session_->SetIceTransports(config.type);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000702}
703
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000704bool PeerConnection::AddIceCandidate(
705 const IceCandidateInterface* ice_candidate) {
706 return session_->ProcessIceMessage(ice_candidate);
707}
708
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000709void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
710 uma_observer_ = observer;
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +0000711
712 if (session_) {
713 session_->set_metrics_observer(uma_observer_);
714 }
715
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +0000716 // Send information about IPv4/IPv6 status.
717 if (uma_observer_ && port_allocator_) {
718 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -0700719 uma_observer_->IncrementEnumCounter(
720 kEnumCounterAddressFamily, kPeerConnection_IPv6,
721 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgb445f262014-05-23 22:19:37 +0000722 } else {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -0700723 uma_observer_->IncrementEnumCounter(
724 kEnumCounterAddressFamily, kPeerConnection_IPv4,
725 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +0000726 }
727 }
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000728}
729
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000730const SessionDescriptionInterface* PeerConnection::local_description() const {
731 return session_->local_description();
732}
733
734const SessionDescriptionInterface* PeerConnection::remote_description() const {
735 return session_->remote_description();
736}
737
738void PeerConnection::Close() {
739 // Update stats here so that we have the most recent stats for tracks and
740 // streams before the channels are closed.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000741 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000742
743 session_->Terminate();
744}
745
746void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
747 cricket::BaseSession::State state) {
748 switch (state) {
749 case cricket::BaseSession::STATE_INIT:
750 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000751 break;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000752 case cricket::BaseSession::STATE_SENTINITIATE:
753 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
754 break;
755 case cricket::BaseSession::STATE_SENTPRACCEPT:
756 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
757 break;
758 case cricket::BaseSession::STATE_RECEIVEDINITIATE:
759 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
760 break;
761 case cricket::BaseSession::STATE_RECEIVEDPRACCEPT:
762 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
763 break;
764 case cricket::BaseSession::STATE_SENTACCEPT:
765 case cricket::BaseSession::STATE_RECEIVEDACCEPT:
766 ChangeSignalingState(PeerConnectionInterface::kStable);
767 break;
768 case cricket::BaseSession::STATE_RECEIVEDTERMINATE:
769 ChangeSignalingState(PeerConnectionInterface::kClosed);
770 break;
771 default:
772 break;
773 }
774}
775
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000776void PeerConnection::OnMessage(rtc::Message* msg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000777 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000778 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
779 SetSessionDescriptionMsg* param =
780 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
781 param->observer->OnSuccess();
782 delete param;
783 break;
784 }
785 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
786 SetSessionDescriptionMsg* param =
787 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
788 param->observer->OnFailure(param->error);
789 delete param;
790 break;
791 }
792 case MSG_GETSTATS: {
793 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000794 StatsReports reports;
795 stats_->GetStats(param->track, &reports);
796 param->observer->OnComplete(reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000797 delete param;
798 break;
799 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000800 default:
801 ASSERT(false && "Not implemented");
802 break;
803 }
804}
805
806void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000807 stats_->AddStream(stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000808 observer_->OnAddStream(stream);
809}
810
811void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
812 stream_handler_container_->RemoveRemoteStream(stream);
813 observer_->OnRemoveStream(stream);
814}
815
816void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
817 observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
818 data_channel));
819}
820
821void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
822 AudioTrackInterface* audio_track,
823 uint32 ssrc) {
824 stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc);
825}
826
827void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
828 VideoTrackInterface* video_track,
829 uint32 ssrc) {
830 stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc);
831}
832
833void PeerConnection::OnRemoveRemoteAudioTrack(
834 MediaStreamInterface* stream,
835 AudioTrackInterface* audio_track) {
836 stream_handler_container_->RemoveRemoteTrack(stream, audio_track);
837}
838
839void PeerConnection::OnRemoveRemoteVideoTrack(
840 MediaStreamInterface* stream,
841 VideoTrackInterface* video_track) {
842 stream_handler_container_->RemoveRemoteTrack(stream, video_track);
843}
844void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
845 AudioTrackInterface* audio_track,
846 uint32 ssrc) {
847 stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc);
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000848 stats_->AddLocalAudioTrack(audio_track, ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849}
850void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
851 VideoTrackInterface* video_track,
852 uint32 ssrc) {
853 stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc);
854}
855
856void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000857 AudioTrackInterface* audio_track,
858 uint32 ssrc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000859 stream_handler_container_->RemoveLocalTrack(stream, audio_track);
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000860 stats_->RemoveLocalAudioTrack(audio_track, ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000861}
862
863void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
864 VideoTrackInterface* video_track) {
865 stream_handler_container_->RemoveLocalTrack(stream, video_track);
866}
867
868void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
869 stream_handler_container_->RemoveLocalStream(stream);
870}
871
872void PeerConnection::OnIceConnectionChange(
873 PeerConnectionInterface::IceConnectionState new_state) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000874 ASSERT(signaling_thread()->IsCurrent());
deadbeefcbecd352015-09-23 11:50:27 -0700875 // After transitioning to "closed", ignore any additional states from
876 // WebRtcSession (such as "disconnected").
877 if (ice_connection_state_ == kIceConnectionClosed) {
878 return;
879 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000880 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000881 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000882}
883
884void PeerConnection::OnIceGatheringChange(
885 PeerConnectionInterface::IceGatheringState new_state) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000886 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000887 if (IsClosed()) {
888 return;
889 }
890 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000891 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000892}
893
894void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000895 ASSERT(signaling_thread()->IsCurrent());
896 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000897}
898
899void PeerConnection::OnIceComplete() {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000900 ASSERT(signaling_thread()->IsCurrent());
901 observer_->OnIceComplete();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000902}
903
Peter Thatcher54360512015-07-08 11:08:35 -0700904void PeerConnection::OnIceConnectionReceivingChange(bool receiving) {
905 ASSERT(signaling_thread()->IsCurrent());
906 observer_->OnIceConnectionReceivingChange(receiving);
907}
908
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000909void PeerConnection::ChangeSignalingState(
910 PeerConnectionInterface::SignalingState signaling_state) {
911 signaling_state_ = signaling_state;
912 if (signaling_state == kClosed) {
913 ice_connection_state_ = kIceConnectionClosed;
914 observer_->OnIceConnectionChange(ice_connection_state_);
915 if (ice_gathering_state_ != kIceGatheringComplete) {
916 ice_gathering_state_ = kIceGatheringComplete;
917 observer_->OnIceGatheringChange(ice_gathering_state_);
918 }
919 }
920 observer_->OnSignalingChange(signaling_state_);
921 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
922}
923
924} // namespace webrtc