blob: 961ba261a88b7459412b344e8dd294e37ce99391 [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"
deadbeef70ab1a12015-09-28 16:53:55 -070036#include "talk/app/webrtc/rtpreceiver.h"
37#include "talk/app/webrtc/rtpsender.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000038#include "talk/app/webrtc/streamcollection.h"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000039#include "webrtc/p2p/client/basicportallocator.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000040#include "talk/session/media/channelmanager.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000041#include "webrtc/base/logging.h"
42#include "webrtc/base/stringencode.h"
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +000043#include "webrtc/system_wrappers/interface/field_trial.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000044
45namespace {
46
47using webrtc::PeerConnectionInterface;
48
henrike@webrtc.org28e20752013-07-10 00:45:36 +000049// The min number of tokens must present in Turn host uri.
50// e.g. user@turn.example.org
51static const size_t kTurnHostTokensNum = 2;
52// Number of tokens must be preset when TURN uri has transport param.
53static const size_t kTurnTransportTokensNum = 2;
54// The default stun port.
wu@webrtc.org91053e72013-08-10 07:18:04 +000055static const int kDefaultStunPort = 3478;
56static const int kDefaultStunTlsPort = 5349;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000057static const char kTransport[] = "transport";
wu@webrtc.org91053e72013-08-10 07:18:04 +000058static const char kUdpTransportType[] = "udp";
59static const char kTcpTransportType[] = "tcp";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060
61// NOTE: Must be in the same order as the ServiceType enum.
62static const char* kValidIceServiceTypes[] = {
63 "stun", "stuns", "turn", "turns", "invalid" };
64
65enum ServiceType {
66 STUN, // Indicates a STUN server.
67 STUNS, // Indicates a STUN server used with a TLS session.
68 TURN, // Indicates a TURN server
69 TURNS, // Indicates a TURN server used with a TLS session.
70 INVALID, // Unknown.
71};
72
73enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +000074 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000075 MSG_SET_SESSIONDESCRIPTION_FAILED,
76 MSG_GETSTATS,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000077};
78
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000079struct SetSessionDescriptionMsg : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000080 explicit SetSessionDescriptionMsg(
81 webrtc::SetSessionDescriptionObserver* observer)
82 : observer(observer) {
83 }
84
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000085 rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000086 std::string error;
87};
88
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000089struct GetStatsMsg : public rtc::MessageData {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +000090 GetStatsMsg(webrtc::StatsObserver* observer,
91 webrtc::MediaStreamTrackInterface* track)
92 : observer(observer), track(track) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000093 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000094 rtc::scoped_refptr<webrtc::StatsObserver> observer;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +000095 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000096};
97
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +000098// |in_str| should be of format
99// stunURI = scheme ":" stun-host [ ":" stun-port ]
100// scheme = "stun" / "stuns"
101// stun-host = IP-literal / IPv4address / reg-name
102// stun-port = *DIGIT
103
104// draft-petithuguenin-behave-turn-uris-01
105// turnURI = scheme ":" turn-host [ ":" turn-port ]
106// turn-host = username@IP-literal / IPv4address / reg-name
107bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
108 ServiceType* service_type,
109 std::string* hostname) {
Tommi77d444a2015-04-24 15:38:38 +0200110 const std::string::size_type colonpos = in_str.find(':');
111 if (colonpos == std::string::npos || (colonpos + 1) == in_str.length()) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000112 return false;
113 }
114 std::string type = in_str.substr(0, colonpos);
115 for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
116 if (type.compare(kValidIceServiceTypes[i]) == 0) {
117 *service_type = static_cast<ServiceType>(i);
118 break;
119 }
120 }
121 if (*service_type == INVALID) {
122 return false;
123 }
124 *hostname = in_str.substr(colonpos + 1, std::string::npos);
125 return true;
126}
127
128// This method parses IPv6 and IPv4 literal strings, along with hostnames in
129// standard hostname:port format.
130// Consider following formats as correct.
131// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
132// |hostname|, |[IPv6 address]|, |IPv4 address|
133bool ParseHostnameAndPortFromString(const std::string& in_str,
134 std::string* host,
135 int* port) {
136 if (in_str.at(0) == '[') {
137 std::string::size_type closebracket = in_str.rfind(']');
138 if (closebracket != std::string::npos) {
139 *host = in_str.substr(1, closebracket - 1);
140 std::string::size_type colonpos = in_str.find(':', closebracket);
141 if (std::string::npos != colonpos) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000142 if (!rtc::FromString(
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000143 in_str.substr(closebracket + 2, std::string::npos), port)) {
144 return false;
145 }
146 }
147 } else {
148 return false;
149 }
150 } else {
151 std::string::size_type colonpos = in_str.find(':');
152 if (std::string::npos != colonpos) {
153 *host = in_str.substr(0, colonpos);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000154 if (!rtc::FromString(
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000155 in_str.substr(colonpos + 1, std::string::npos), port)) {
156 return false;
157 }
158 } else {
159 *host = in_str;
160 }
161 }
162 return true;
163}
164
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000165typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
166 StunConfiguration;
167typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
168 TurnConfiguration;
169
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200170bool ParseIceServerUrl(const PeerConnectionInterface::IceServer& server,
171 const std::string& url,
172 std::vector<StunConfiguration>* stun_config,
173 std::vector<TurnConfiguration>* turn_config) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000174 // draft-nandakumar-rtcweb-stun-uri-01
175 // stunURI = scheme ":" stun-host [ ":" stun-port ]
176 // scheme = "stun" / "stuns"
177 // stun-host = IP-literal / IPv4address / reg-name
178 // stun-port = *DIGIT
179
180 // draft-petithuguenin-behave-turn-uris-01
181 // turnURI = scheme ":" turn-host [ ":" turn-port ]
182 // [ "?transport=" transport ]
183 // scheme = "turn" / "turns"
184 // transport = "udp" / "tcp" / transport-ext
185 // transport-ext = 1*unreserved
186 // turn-host = IP-literal / IPv4address / reg-name
187 // turn-port = *DIGIT
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200188 std::vector<std::string> tokens;
189 std::string turn_transport_type = kUdpTransportType;
Joachim Bauchd935f912015-05-29 22:14:21 +0200190 ASSERT(!url.empty());
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200191 rtc::tokenize(url, '?', &tokens);
192 std::string uri_without_transport = tokens[0];
193 // Let's look into transport= param, if it exists.
194 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
195 std::string uri_transport_param = tokens[1];
196 rtc::tokenize(uri_transport_param, '=', &tokens);
197 if (tokens[0] == kTransport) {
198 // As per above grammar transport param will be consist of lower case
199 // letters.
200 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
201 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
202 return true;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000203 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200204 turn_transport_type = tokens[1];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000205 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200206 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000207
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200208 std::string hoststring;
209 ServiceType service_type = INVALID;
210 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
211 &service_type,
212 &hoststring)) {
213 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: "
214 << uri_without_transport;
215 return true;
216 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000217
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200218 ASSERT(!hoststring.empty());
Tommi77d444a2015-04-24 15:38:38 +0200219
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200220 // Let's break hostname.
221 tokens.clear();
222 rtc::tokenize(hoststring, '@', &tokens);
223 ASSERT(!tokens.empty());
224 std::string username(server.username);
225 // TODO(pthatcher): What's the right thing to do if tokens.size() is >2?
226 // E.g. a string like "foo@bar@bat".
227 if (tokens.size() >= kTurnHostTokensNum) {
228 username.assign(rtc::s_url_decode(tokens[0]));
229 hoststring = tokens[1];
230 } else {
231 hoststring = tokens[0];
232 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000233
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200234 int port = kDefaultStunPort;
235 if (service_type == TURNS) {
236 port = kDefaultStunTlsPort;
237 turn_transport_type = kTcpTransportType;
238 }
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000239
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200240 std::string address;
241 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
242 LOG(WARNING) << "Invalid Hostname format: " << uri_without_transport;
243 return true;
244 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000245
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200246 if (port <= 0 || port > 0xffff) {
247 LOG(WARNING) << "Invalid port: " << port;
248 return true;
249 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000250
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200251 switch (service_type) {
252 case STUN:
253 case STUNS:
254 stun_config->push_back(StunConfiguration(address, port));
255 break;
256 case TURN:
257 case TURNS: {
258 if (username.empty()) {
259 // Turn url example from the spec |url:"turn:user@turn.example.org"|.
260 std::vector<std::string> turn_tokens;
261 rtc::tokenize(address, '@', &turn_tokens);
262 if (turn_tokens.size() == kTurnHostTokensNum) {
263 username.assign(rtc::s_url_decode(turn_tokens[0]));
264 address = turn_tokens[1];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000265 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000266 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200267
268 bool secure = (service_type == TURNS);
269
270 turn_config->push_back(TurnConfiguration(address, port,
271 username,
272 server.password,
273 turn_transport_type,
274 secure));
275 break;
276 }
277 case INVALID:
278 default:
279 LOG(WARNING) << "Configuration not supported: " << url;
280 return false;
281 }
282 return true;
283}
284
285bool ParseIceServers(const PeerConnectionInterface::IceServers& servers,
286 std::vector<StunConfiguration>* stun_config,
287 std::vector<TurnConfiguration>* turn_config) {
288 for (const webrtc::PeerConnectionInterface::IceServer& server : servers) {
289 if (!server.urls.empty()) {
290 for (const std::string& url : server.urls) {
Joachim Bauchd935f912015-05-29 22:14:21 +0200291 if (url.empty()) {
292 LOG(WARNING) << "Empty uri.";
293 continue;
294 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200295 if (!ParseIceServerUrl(server, url, stun_config, turn_config)) {
296 return false;
297 }
298 }
299 } else if (!server.uri.empty()) {
300 // Fallback to old .uri if new .urls isn't present.
301 if (!ParseIceServerUrl(server, server.uri, stun_config, turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000302 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200303 }
304 } else {
305 LOG(WARNING) << "Empty uri.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000306 }
307 }
308 return true;
309}
310
311// Check if we can send |new_stream| on a PeerConnection.
312// Currently only one audio but multiple video track is supported per
313// PeerConnection.
314bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
315 webrtc::MediaStreamInterface* new_stream) {
316 if (!new_stream || !current_streams)
317 return false;
318 if (current_streams->find(new_stream->label()) != NULL) {
319 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
320 << " is already added.";
321 return false;
322 }
323
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000324 return true;
325}
326
327} // namespace
328
329namespace webrtc {
330
331PeerConnection::PeerConnection(PeerConnectionFactory* factory)
332 : factory_(factory),
333 observer_(NULL),
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000334 uma_observer_(NULL),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000335 signaling_state_(kStable),
336 ice_state_(kIceNew),
337 ice_connection_state_(kIceConnectionNew),
338 ice_gathering_state_(kIceGatheringNew) {
339}
340
341PeerConnection::~PeerConnection() {
tommi0f620f42015-07-09 03:25:02 -0700342 ASSERT(signaling_thread()->IsCurrent());
deadbeef70ab1a12015-09-28 16:53:55 -0700343 if (mediastream_signaling_) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000344 mediastream_signaling_->TearDown();
deadbeef70ab1a12015-09-28 16:53:55 -0700345 }
346 // Need to detach RTP senders/receivers from WebRtcSession,
347 // since it's about to be destroyed.
348 for (const auto& sender : senders_) {
349 sender->Stop();
350 }
351 for (const auto& receiver : receivers_) {
352 receiver->Stop();
353 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000354}
355
356bool PeerConnection::Initialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000357 const PeerConnectionInterface::RTCConfiguration& configuration,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000358 const MediaConstraintsInterface* constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000359 PortAllocatorFactoryInterface* allocator_factory,
Henrik Boström5e56c592015-08-11 10:33:13 +0200360 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000361 PeerConnectionObserver* observer) {
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000362 ASSERT(observer != NULL);
363 if (!observer)
364 return false;
365 observer_ = observer;
366
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000367 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
368 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000369 if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000370 return false;
371 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000372 port_allocator_.reset(
373 allocator_factory->CreatePortAllocator(stun_config, turn_config));
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000374
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000375 // To handle both internal and externally created port allocator, we will
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000376 // enable BUNDLE here.
braveyao@webrtc.org1732df62014-10-27 03:01:37 +0000377 int portallocator_flags = port_allocator_->flags();
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700378 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000379 cricket::PORTALLOCATOR_ENABLE_IPV6;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000380 bool value;
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000381 // If IPv6 flag was specified, we'll not override it by experiment.
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000382 if (FindConstraint(
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000383 constraints, MediaConstraintsInterface::kEnableIPv6, &value, NULL)) {
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000384 if (!value) {
385 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000386 }
guoweis@webrtc.org2c1bcea2014-09-23 16:23:02 +0000387 } else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default") ==
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000388 "Disabled") {
389 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000390 }
391
Jiayang Liucac1b382015-04-30 12:35:24 -0700392 if (configuration.tcp_candidate_policy == kTcpCandidatePolicyDisabled) {
393 portallocator_flags |= cricket::PORTALLOCATOR_DISABLE_TCP;
394 LOG(LS_INFO) << "TCP candidates are disabled.";
395 }
396
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000397 port_allocator_->set_flags(portallocator_flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000398 // No step delay is used while allocating ports.
399 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
400
401 mediastream_signaling_.reset(new MediaStreamSignaling(
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000402 factory_->signaling_thread(), this, factory_->channel_manager()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000403
404 session_.reset(new WebRtcSession(factory_->channel_manager(),
405 factory_->signaling_thread(),
406 factory_->worker_thread(),
407 port_allocator_.get(),
408 mediastream_signaling_.get()));
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000409 stats_.reset(new StatsCollector(session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000410
411 // Initialize the WebRtcSession. It creates transport channels etc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000412 if (!session_->Initialize(factory_->options(), constraints,
Henrik Boström5e56c592015-08-11 10:33:13 +0200413 dtls_identity_store.Pass(), configuration))
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000414 return false;
415
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000416 // Register PeerConnection as receiver of local ice candidates.
417 // All the callbacks will be posted to the application from PeerConnection.
418 session_->RegisterIceObserver(this);
419 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
420 return true;
421}
422
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000423rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000424PeerConnection::local_streams() {
425 return mediastream_signaling_->local_streams();
426}
427
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000428rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000429PeerConnection::remote_streams() {
430 return mediastream_signaling_->remote_streams();
431}
432
deadbeef70ab1a12015-09-28 16:53:55 -0700433// TODO(deadbeef): Create RtpSenders immediately here, even if local
434// description hasn't yet been set.
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +0000435bool PeerConnection::AddStream(MediaStreamInterface* local_stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000436 if (IsClosed()) {
437 return false;
438 }
439 if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(),
440 local_stream))
441 return false;
442
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000443 if (!mediastream_signaling_->AddLocalStream(local_stream)) {
444 return false;
445 }
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000446 stats_->AddStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000447 observer_->OnRenegotiationNeeded();
448 return true;
449}
450
451void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000452 mediastream_signaling_->RemoveLocalStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000453 if (IsClosed()) {
454 return;
455 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000456 observer_->OnRenegotiationNeeded();
457}
458
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000459rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000460 AudioTrackInterface* track) {
461 if (!track) {
462 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
463 return NULL;
464 }
465 if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) {
466 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
467 return NULL;
468 }
469
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000470 rtc::scoped_refptr<DtmfSenderInterface> sender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000471 DtmfSender::Create(track, signaling_thread(), session_.get()));
472 if (!sender.get()) {
473 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
474 return NULL;
475 }
476 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
477}
478
deadbeef70ab1a12015-09-28 16:53:55 -0700479std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders()
480 const {
481 std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders;
482 for (const auto& sender : senders_) {
483 senders.push_back(RtpSenderProxy::Create(signaling_thread(), sender.get()));
484 }
485 return senders;
486}
487
488std::vector<rtc::scoped_refptr<RtpReceiverInterface>>
489PeerConnection::GetReceivers() const {
490 std::vector<rtc::scoped_refptr<RtpReceiverInterface>> receivers;
491 for (const auto& receiver : receivers_) {
492 receivers.push_back(
493 RtpReceiverProxy::Create(signaling_thread(), receiver.get()));
494 }
495 return receivers;
496}
497
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000498bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000499 MediaStreamTrackInterface* track,
500 StatsOutputLevel level) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000501 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000502 if (!VERIFY(observer != NULL)) {
503 LOG(LS_ERROR) << "GetStats - observer is NULL.";
504 return false;
505 }
506
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000507 stats_->UpdateStats(level);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000508 signaling_thread()->Post(this, MSG_GETSTATS,
509 new GetStatsMsg(observer, track));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000510 return true;
511}
512
513PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
514 return signaling_state_;
515}
516
517PeerConnectionInterface::IceState PeerConnection::ice_state() {
518 return ice_state_;
519}
520
521PeerConnectionInterface::IceConnectionState
522PeerConnection::ice_connection_state() {
523 return ice_connection_state_;
524}
525
526PeerConnectionInterface::IceGatheringState
527PeerConnection::ice_gathering_state() {
528 return ice_gathering_state_;
529}
530
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000531rtc::scoped_refptr<DataChannelInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000532PeerConnection::CreateDataChannel(
533 const std::string& label,
534 const DataChannelInit* config) {
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000535 bool first_datachannel = !mediastream_signaling_->HasDataChannels();
536
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000537 rtc::scoped_ptr<InternalDataChannelInit> internal_config;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000538 if (config) {
539 internal_config.reset(new InternalDataChannelInit(*config));
540 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000541 rtc::scoped_refptr<DataChannelInterface> channel(
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000542 session_->CreateDataChannel(label, internal_config.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000543 if (!channel.get())
544 return NULL;
545
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000546 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
547 // the first SCTP DataChannel.
548 if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
549 observer_->OnRenegotiationNeeded();
550 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000551
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 return DataChannelProxy::Create(signaling_thread(), channel.get());
553}
554
555void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
556 const MediaConstraintsInterface* constraints) {
557 if (!VERIFY(observer != NULL)) {
558 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
559 return;
560 }
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000561 RTCOfferAnswerOptions options;
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000562
563 bool value;
564 size_t mandatory_constraints = 0;
565
566 if (FindConstraint(constraints,
567 MediaConstraintsInterface::kOfferToReceiveAudio,
568 &value,
569 &mandatory_constraints)) {
570 options.offer_to_receive_audio =
571 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
572 }
573
574 if (FindConstraint(constraints,
575 MediaConstraintsInterface::kOfferToReceiveVideo,
576 &value,
577 &mandatory_constraints)) {
578 options.offer_to_receive_video =
579 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
580 }
581
582 if (FindConstraint(constraints,
583 MediaConstraintsInterface::kVoiceActivityDetection,
584 &value,
585 &mandatory_constraints)) {
586 options.voice_activity_detection = value;
587 }
588
589 if (FindConstraint(constraints,
590 MediaConstraintsInterface::kIceRestart,
591 &value,
592 &mandatory_constraints)) {
593 options.ice_restart = value;
594 }
595
596 if (FindConstraint(constraints,
597 MediaConstraintsInterface::kUseRtpMux,
598 &value,
599 &mandatory_constraints)) {
600 options.use_rtp_mux = value;
601 }
602
603 CreateOffer(observer, options);
604}
605
606void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
607 const RTCOfferAnswerOptions& options) {
608 if (!VERIFY(observer != NULL)) {
609 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
610 return;
611 }
612 session_->CreateOffer(observer, options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000613}
614
615void PeerConnection::CreateAnswer(
616 CreateSessionDescriptionObserver* observer,
617 const MediaConstraintsInterface* constraints) {
618 if (!VERIFY(observer != NULL)) {
619 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
620 return;
621 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000622 session_->CreateAnswer(observer, constraints);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000623}
624
625void PeerConnection::SetLocalDescription(
626 SetSessionDescriptionObserver* observer,
627 SessionDescriptionInterface* desc) {
628 if (!VERIFY(observer != NULL)) {
629 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
630 return;
631 }
632 if (!desc) {
633 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
634 return;
635 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000636 // 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_->SetLocalDescription(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);
deadbeefcbecd352015-09-23 11:50:27 -0700646 // MaybeStartGathering needs to be called after posting
647 // MSG_SET_SESSIONDESCRIPTION_SUCCESS, so that we don't signal any candidates
648 // before signaling that SetLocalDescription completed.
649 session_->MaybeStartGathering();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000650}
651
652void PeerConnection::SetRemoteDescription(
653 SetSessionDescriptionObserver* observer,
654 SessionDescriptionInterface* desc) {
655 if (!VERIFY(observer != NULL)) {
656 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
657 return;
658 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000659 if (!desc) {
660 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
661 return;
662 }
663 // Update stats here so that we have the most recent stats for tracks and
664 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000665 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000666 std::string error;
667 if (!session_->SetRemoteDescription(desc, &error)) {
668 PostSetSessionDescriptionFailure(observer, error);
669 return;
670 }
671 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
672 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
673}
674
675void PeerConnection::PostSetSessionDescriptionFailure(
676 SetSessionDescriptionObserver* observer,
677 const std::string& error) {
678 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
679 msg->error = error;
680 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
681}
682
683bool PeerConnection::UpdateIce(const IceServers& configuration,
684 const MediaConstraintsInterface* constraints) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000685 return false;
686}
687
deadbeef7603c762015-09-23 17:37:11 -0700688bool PeerConnection::UpdateIce(const RTCConfiguration& config) {
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000689 if (port_allocator_) {
690 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
691 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
692 if (!ParseIceServers(config.servers, &stuns, &turns)) {
693 return false;
694 }
695
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000696 std::vector<rtc::SocketAddress> stun_hosts;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000697 typedef std::vector<StunConfiguration>::const_iterator StunIt;
698 for (StunIt stun_it = stuns.begin(); stun_it != stuns.end(); ++stun_it) {
699 stun_hosts.push_back(stun_it->server);
700 }
701
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000702 rtc::SocketAddress stun_addr;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000703 if (!stun_hosts.empty()) {
704 stun_addr = stun_hosts.front();
deadbeef7603c762015-09-23 17:37:11 -0700705 LOG(LS_INFO) << "UpdateIce: StunServer Address: " << stun_addr.ToString();
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000706 }
707
708 for (size_t i = 0; i < turns.size(); ++i) {
709 cricket::RelayCredentials credentials(turns[i].username,
710 turns[i].password);
711 cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
712 cricket::ProtocolType protocol;
713 if (cricket::StringToProto(turns[i].transport_type.c_str(), &protocol)) {
714 relay_server.ports.push_back(cricket::ProtocolAddress(
715 turns[i].server, protocol, turns[i].secure));
716 relay_server.credentials = credentials;
deadbeef7603c762015-09-23 17:37:11 -0700717 LOG(LS_INFO) << "UpdateIce: TurnServer Address: "
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000718 << turns[i].server.ToString();
719 } else {
720 LOG(LS_WARNING) << "Ignoring TURN server " << turns[i].server << ". "
721 << "Reason= Incorrect " << turns[i].transport_type
722 << " transport parameter.";
723 }
724 }
725 }
honghaiz1f429e32015-09-28 07:57:34 -0700726 session_->SetIceConfig(session_->ParseIceConfig(config));
mallinath@webrtc.org3d81b1b2014-09-09 14:38:10 +0000727 return session_->SetIceTransports(config.type);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000728}
729
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000730bool PeerConnection::AddIceCandidate(
731 const IceCandidateInterface* ice_candidate) {
732 return session_->ProcessIceMessage(ice_candidate);
733}
734
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000735void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
736 uma_observer_ = observer;
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +0000737
738 if (session_) {
739 session_->set_metrics_observer(uma_observer_);
740 }
741
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +0000742 // Send information about IPv4/IPv6 status.
743 if (uma_observer_ && port_allocator_) {
744 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -0700745 uma_observer_->IncrementEnumCounter(
746 kEnumCounterAddressFamily, kPeerConnection_IPv6,
747 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgb445f262014-05-23 22:19:37 +0000748 } else {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -0700749 uma_observer_->IncrementEnumCounter(
750 kEnumCounterAddressFamily, kPeerConnection_IPv4,
751 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +0000752 }
753 }
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000754}
755
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000756const SessionDescriptionInterface* PeerConnection::local_description() const {
757 return session_->local_description();
758}
759
760const SessionDescriptionInterface* PeerConnection::remote_description() const {
761 return session_->remote_description();
762}
763
764void PeerConnection::Close() {
765 // Update stats here so that we have the most recent stats for tracks and
766 // streams before the channels are closed.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000767 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768
769 session_->Terminate();
770}
771
772void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
773 cricket::BaseSession::State state) {
774 switch (state) {
775 case cricket::BaseSession::STATE_INIT:
776 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000777 break;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000778 case cricket::BaseSession::STATE_SENTINITIATE:
779 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
780 break;
781 case cricket::BaseSession::STATE_SENTPRACCEPT:
782 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
783 break;
784 case cricket::BaseSession::STATE_RECEIVEDINITIATE:
785 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
786 break;
787 case cricket::BaseSession::STATE_RECEIVEDPRACCEPT:
788 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
789 break;
790 case cricket::BaseSession::STATE_SENTACCEPT:
791 case cricket::BaseSession::STATE_RECEIVEDACCEPT:
792 ChangeSignalingState(PeerConnectionInterface::kStable);
793 break;
794 case cricket::BaseSession::STATE_RECEIVEDTERMINATE:
795 ChangeSignalingState(PeerConnectionInterface::kClosed);
796 break;
797 default:
798 break;
799 }
800}
801
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000802void PeerConnection::OnMessage(rtc::Message* msg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000803 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000804 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
805 SetSessionDescriptionMsg* param =
806 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
807 param->observer->OnSuccess();
808 delete param;
809 break;
810 }
811 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
812 SetSessionDescriptionMsg* param =
813 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
814 param->observer->OnFailure(param->error);
815 delete param;
816 break;
817 }
818 case MSG_GETSTATS: {
819 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000820 StatsReports reports;
821 stats_->GetStats(param->track, &reports);
822 param->observer->OnComplete(reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000823 delete param;
824 break;
825 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000826 default:
827 ASSERT(false && "Not implemented");
828 break;
829 }
830}
831
832void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000833 stats_->AddStream(stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000834 observer_->OnAddStream(stream);
835}
836
837void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000838 observer_->OnRemoveStream(stream);
839}
840
841void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
842 observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
843 data_channel));
844}
845
846void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
847 AudioTrackInterface* audio_track,
848 uint32 ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -0700849 receivers_.push_back(new AudioRtpReceiver(audio_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850}
851
852void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
853 VideoTrackInterface* video_track,
854 uint32 ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -0700855 receivers_.push_back(new VideoRtpReceiver(video_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000856}
857
deadbeef70ab1a12015-09-28 16:53:55 -0700858// TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote
859// description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000860void PeerConnection::OnRemoveRemoteAudioTrack(
861 MediaStreamInterface* stream,
862 AudioTrackInterface* audio_track) {
deadbeef70ab1a12015-09-28 16:53:55 -0700863 auto it = FindReceiverForTrack(audio_track);
864 if (it == receivers_.end()) {
865 LOG(LS_WARNING) << "RtpReceiver for track with id " << audio_track->id()
866 << " doesn't exist.";
867 } else {
868 (*it)->Stop();
869 receivers_.erase(it);
870 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000871}
872
873void PeerConnection::OnRemoveRemoteVideoTrack(
874 MediaStreamInterface* stream,
875 VideoTrackInterface* video_track) {
deadbeef70ab1a12015-09-28 16:53:55 -0700876 auto it = FindReceiverForTrack(video_track);
877 if (it == receivers_.end()) {
878 LOG(LS_WARNING) << "RtpReceiver for track with id " << video_track->id()
879 << " doesn't exist.";
880 } else {
881 (*it)->Stop();
882 receivers_.erase(it);
883 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000884}
deadbeef70ab1a12015-09-28 16:53:55 -0700885
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000886void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
887 AudioTrackInterface* audio_track,
888 uint32 ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -0700889 senders_.push_back(new AudioRtpSender(audio_track, ssrc, session_.get()));
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000890 stats_->AddLocalAudioTrack(audio_track, ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000891}
deadbeef70ab1a12015-09-28 16:53:55 -0700892
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000893void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
894 VideoTrackInterface* video_track,
895 uint32 ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -0700896 senders_.push_back(new VideoRtpSender(video_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000897}
898
deadbeef70ab1a12015-09-28 16:53:55 -0700899// TODO(deadbeef): Keep RtpSenders around even if track goes away in local
900// description.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000901void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000902 AudioTrackInterface* audio_track,
903 uint32 ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -0700904 auto it = FindSenderForTrack(audio_track);
905 if (it == senders_.end()) {
906 LOG(LS_WARNING) << "RtpSender for track with id " << audio_track->id()
907 << " doesn't exist.";
908 return;
909 } else {
910 (*it)->Stop();
911 senders_.erase(it);
912 }
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000913 stats_->RemoveLocalAudioTrack(audio_track, ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000914}
915
916void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
917 VideoTrackInterface* video_track) {
deadbeef70ab1a12015-09-28 16:53:55 -0700918 auto it = FindSenderForTrack(video_track);
919 if (it == senders_.end()) {
920 LOG(LS_WARNING) << "RtpSender for track with id " << video_track->id()
921 << " doesn't exist.";
922 return;
923 } else {
924 (*it)->Stop();
925 senders_.erase(it);
926 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000927}
928
929void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000930}
931
932void PeerConnection::OnIceConnectionChange(
933 PeerConnectionInterface::IceConnectionState new_state) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000934 ASSERT(signaling_thread()->IsCurrent());
deadbeefcbecd352015-09-23 11:50:27 -0700935 // After transitioning to "closed", ignore any additional states from
936 // WebRtcSession (such as "disconnected").
937 if (ice_connection_state_ == kIceConnectionClosed) {
938 return;
939 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000940 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000941 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000942}
943
944void PeerConnection::OnIceGatheringChange(
945 PeerConnectionInterface::IceGatheringState new_state) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000946 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000947 if (IsClosed()) {
948 return;
949 }
950 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000951 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000952}
953
954void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000955 ASSERT(signaling_thread()->IsCurrent());
956 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000957}
958
959void PeerConnection::OnIceComplete() {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000960 ASSERT(signaling_thread()->IsCurrent());
961 observer_->OnIceComplete();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000962}
963
Peter Thatcher54360512015-07-08 11:08:35 -0700964void PeerConnection::OnIceConnectionReceivingChange(bool receiving) {
965 ASSERT(signaling_thread()->IsCurrent());
966 observer_->OnIceConnectionReceivingChange(receiving);
967}
968
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000969void PeerConnection::ChangeSignalingState(
970 PeerConnectionInterface::SignalingState signaling_state) {
971 signaling_state_ = signaling_state;
972 if (signaling_state == kClosed) {
973 ice_connection_state_ = kIceConnectionClosed;
974 observer_->OnIceConnectionChange(ice_connection_state_);
975 if (ice_gathering_state_ != kIceGatheringComplete) {
976 ice_gathering_state_ = kIceGatheringComplete;
977 observer_->OnIceGatheringChange(ice_gathering_state_);
978 }
979 }
980 observer_->OnSignalingChange(signaling_state_);
981 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
982}
983
deadbeef70ab1a12015-09-28 16:53:55 -0700984std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator
985PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) {
986 return std::find_if(
987 senders_.begin(), senders_.end(),
988 [track](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
989 return sender->track() == track;
990 });
991}
992
993std::vector<rtc::scoped_refptr<RtpReceiverInterface>>::iterator
994PeerConnection::FindReceiverForTrack(MediaStreamTrackInterface* track) {
995 return std::find_if(
996 receivers_.begin(), receivers_.end(),
997 [track](const rtc::scoped_refptr<RtpReceiverInterface>& receiver) {
998 return receiver->track() == track;
999 });
1000}
1001
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001002} // namespace webrtc