blob: 85e03f99b8434691f40fbe4bea09163112d34e6d [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
deadbeefeb459812015-12-15 19:24:43 -080030#include <algorithm>
deadbeef0a6c4ca2015-10-06 11:38:28 -070031#include <cctype> // for isdigit
kwiberg0eb15ed2015-12-17 03:04:15 -080032#include <utility>
33#include <vector>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000034
deadbeefab9b2d12015-10-14 11:33:11 -070035#include "talk/app/webrtc/audiotrack.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000036#include "talk/app/webrtc/dtmfsender.h"
37#include "talk/app/webrtc/jsepicecandidate.h"
38#include "talk/app/webrtc/jsepsessiondescription.h"
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +000039#include "talk/app/webrtc/mediaconstraintsinterface.h"
deadbeefab9b2d12015-10-14 11:33:11 -070040#include "talk/app/webrtc/mediastream.h"
deadbeefeb459812015-12-15 19:24:43 -080041#include "talk/app/webrtc/mediastreamobserver.h"
deadbeefab9b2d12015-10-14 11:33:11 -070042#include "talk/app/webrtc/mediastreamproxy.h"
43#include "talk/app/webrtc/mediastreamtrackproxy.h"
44#include "talk/app/webrtc/remoteaudiosource.h"
45#include "talk/app/webrtc/remotevideocapturer.h"
deadbeef70ab1a12015-09-28 16:53:55 -070046#include "talk/app/webrtc/rtpreceiver.h"
47#include "talk/app/webrtc/rtpsender.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000048#include "talk/app/webrtc/streamcollection.h"
deadbeefab9b2d12015-10-14 11:33:11 -070049#include "talk/app/webrtc/videosource.h"
50#include "talk/app/webrtc/videotrack.h"
51#include "talk/media/sctp/sctpdataengine.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000052#include "talk/session/media/channelmanager.h"
tfarina5237aaf2015-11-10 23:44:30 -080053#include "webrtc/base/arraysize.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000054#include "webrtc/base/logging.h"
55#include "webrtc/base/stringencode.h"
deadbeefab9b2d12015-10-14 11:33:11 -070056#include "webrtc/base/stringutils.h"
Peter Boström1a9d6152015-12-08 22:15:17 +010057#include "webrtc/base/trace_event.h"
tfarina5237aaf2015-11-10 23:44:30 -080058#include "webrtc/p2p/client/basicportallocator.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010059#include "webrtc/system_wrappers/include/field_trial.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060
61namespace {
62
deadbeefab9b2d12015-10-14 11:33:11 -070063using webrtc::DataChannel;
64using webrtc::MediaConstraintsInterface;
65using webrtc::MediaStreamInterface;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000066using webrtc::PeerConnectionInterface;
deadbeeffac06552015-11-25 11:26:01 -080067using webrtc::RtpSenderInterface;
deadbeefab9b2d12015-10-14 11:33:11 -070068using webrtc::StreamCollection;
deadbeef0a6c4ca2015-10-06 11:38:28 -070069using webrtc::StunConfigurations;
70using webrtc::TurnConfigurations;
71typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
72 StunConfiguration;
73typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
74 TurnConfiguration;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000075
deadbeefab9b2d12015-10-14 11:33:11 -070076static const char kDefaultStreamLabel[] = "default";
77static const char kDefaultAudioTrackLabel[] = "defaulta0";
78static const char kDefaultVideoTrackLabel[] = "defaultv0";
79
henrike@webrtc.org28e20752013-07-10 00:45:36 +000080// The min number of tokens must present in Turn host uri.
81// e.g. user@turn.example.org
82static const size_t kTurnHostTokensNum = 2;
83// Number of tokens must be preset when TURN uri has transport param.
84static const size_t kTurnTransportTokensNum = 2;
85// The default stun port.
wu@webrtc.org91053e72013-08-10 07:18:04 +000086static const int kDefaultStunPort = 3478;
87static const int kDefaultStunTlsPort = 5349;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088static const char kTransport[] = "transport";
wu@webrtc.org91053e72013-08-10 07:18:04 +000089static const char kUdpTransportType[] = "udp";
90static const char kTcpTransportType[] = "tcp";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000091
92// NOTE: Must be in the same order as the ServiceType enum.
deadbeef0a6c4ca2015-10-06 11:38:28 -070093static const char* kValidIceServiceTypes[] = {"stun", "stuns", "turn", "turns"};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000094
deadbeef0a6c4ca2015-10-06 11:38:28 -070095// NOTE: A loop below assumes that the first value of this enum is 0 and all
96// other values are incremental.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000097enum ServiceType {
deadbeef0a6c4ca2015-10-06 11:38:28 -070098 STUN = 0, // Indicates a STUN server.
99 STUNS, // Indicates a STUN server used with a TLS session.
100 TURN, // Indicates a TURN server
101 TURNS, // Indicates a TURN server used with a TLS session.
102 INVALID, // Unknown.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103};
tfarina5237aaf2015-11-10 23:44:30 -0800104static_assert(INVALID == arraysize(kValidIceServiceTypes),
deadbeef0a6c4ca2015-10-06 11:38:28 -0700105 "kValidIceServiceTypes must have as many strings as ServiceType "
106 "has values.");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000107
108enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000109 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000110 MSG_SET_SESSIONDESCRIPTION_FAILED,
deadbeefab9b2d12015-10-14 11:33:11 -0700111 MSG_CREATE_SESSIONDESCRIPTION_FAILED,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112 MSG_GETSTATS,
deadbeefbd292462015-12-14 18:15:29 -0800113 MSG_FREE_DATACHANNELS,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000114};
115
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000116struct SetSessionDescriptionMsg : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000117 explicit SetSessionDescriptionMsg(
118 webrtc::SetSessionDescriptionObserver* observer)
119 : observer(observer) {
120 }
121
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000122 rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000123 std::string error;
124};
125
deadbeefab9b2d12015-10-14 11:33:11 -0700126struct CreateSessionDescriptionMsg : public rtc::MessageData {
127 explicit CreateSessionDescriptionMsg(
128 webrtc::CreateSessionDescriptionObserver* observer)
129 : observer(observer) {}
130
131 rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserver> observer;
132 std::string error;
133};
134
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000135struct GetStatsMsg : public rtc::MessageData {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000136 GetStatsMsg(webrtc::StatsObserver* observer,
137 webrtc::MediaStreamTrackInterface* track)
138 : observer(observer), track(track) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000140 rtc::scoped_refptr<webrtc::StatsObserver> observer;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000141 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000142};
143
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000144// |in_str| should be of format
145// stunURI = scheme ":" stun-host [ ":" stun-port ]
146// scheme = "stun" / "stuns"
147// stun-host = IP-literal / IPv4address / reg-name
148// stun-port = *DIGIT
deadbeef0a6c4ca2015-10-06 11:38:28 -0700149//
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000150// draft-petithuguenin-behave-turn-uris-01
151// turnURI = scheme ":" turn-host [ ":" turn-port ]
152// turn-host = username@IP-literal / IPv4address / reg-name
153bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
154 ServiceType* service_type,
155 std::string* hostname) {
Tommi77d444a2015-04-24 15:38:38 +0200156 const std::string::size_type colonpos = in_str.find(':');
deadbeef0a6c4ca2015-10-06 11:38:28 -0700157 if (colonpos == std::string::npos) {
158 LOG(LS_WARNING) << "Missing ':' in ICE URI: " << in_str;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000159 return false;
160 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700161 if ((colonpos + 1) == in_str.length()) {
162 LOG(LS_WARNING) << "Empty hostname in ICE URI: " << in_str;
163 return false;
164 }
165 *service_type = INVALID;
tfarina5237aaf2015-11-10 23:44:30 -0800166 for (size_t i = 0; i < arraysize(kValidIceServiceTypes); ++i) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700167 if (in_str.compare(0, colonpos, kValidIceServiceTypes[i]) == 0) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000168 *service_type = static_cast<ServiceType>(i);
169 break;
170 }
171 }
172 if (*service_type == INVALID) {
173 return false;
174 }
175 *hostname = in_str.substr(colonpos + 1, std::string::npos);
176 return true;
177}
178
deadbeef0a6c4ca2015-10-06 11:38:28 -0700179bool ParsePort(const std::string& in_str, int* port) {
180 // Make sure port only contains digits. FromString doesn't check this.
181 for (const char& c : in_str) {
182 if (!std::isdigit(c)) {
183 return false;
184 }
185 }
186 return rtc::FromString(in_str, port);
187}
188
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000189// This method parses IPv6 and IPv4 literal strings, along with hostnames in
190// standard hostname:port format.
191// Consider following formats as correct.
192// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700193// |hostname|, |[IPv6 address]|, |IPv4 address|.
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000194bool ParseHostnameAndPortFromString(const std::string& in_str,
195 std::string* host,
196 int* port) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700197 RTC_DCHECK(host->empty());
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000198 if (in_str.at(0) == '[') {
199 std::string::size_type closebracket = in_str.rfind(']');
200 if (closebracket != std::string::npos) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000201 std::string::size_type colonpos = in_str.find(':', closebracket);
202 if (std::string::npos != colonpos) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700203 if (!ParsePort(in_str.substr(closebracket + 2, std::string::npos),
204 port)) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000205 return false;
206 }
207 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700208 *host = in_str.substr(1, closebracket - 1);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000209 } else {
210 return false;
211 }
212 } else {
213 std::string::size_type colonpos = in_str.find(':');
214 if (std::string::npos != colonpos) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700215 if (!ParsePort(in_str.substr(colonpos + 1, std::string::npos), port)) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000216 return false;
217 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700218 *host = in_str.substr(0, colonpos);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000219 } else {
220 *host = in_str;
221 }
222 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700223 return !host->empty();
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000224}
225
deadbeef0a6c4ca2015-10-06 11:38:28 -0700226// Adds a StunConfiguration or TurnConfiguration to the appropriate list,
227// by parsing |url| and using the username/password in |server|.
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200228bool ParseIceServerUrl(const PeerConnectionInterface::IceServer& server,
229 const std::string& url,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700230 StunConfigurations* stun_config,
231 TurnConfigurations* turn_config) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000232 // draft-nandakumar-rtcweb-stun-uri-01
233 // stunURI = scheme ":" stun-host [ ":" stun-port ]
234 // scheme = "stun" / "stuns"
235 // stun-host = IP-literal / IPv4address / reg-name
236 // stun-port = *DIGIT
237
238 // draft-petithuguenin-behave-turn-uris-01
239 // turnURI = scheme ":" turn-host [ ":" turn-port ]
240 // [ "?transport=" transport ]
241 // scheme = "turn" / "turns"
242 // transport = "udp" / "tcp" / transport-ext
243 // transport-ext = 1*unreserved
244 // turn-host = IP-literal / IPv4address / reg-name
245 // turn-port = *DIGIT
deadbeef0a6c4ca2015-10-06 11:38:28 -0700246 RTC_DCHECK(stun_config != nullptr);
247 RTC_DCHECK(turn_config != nullptr);
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200248 std::vector<std::string> tokens;
249 std::string turn_transport_type = kUdpTransportType;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700250 RTC_DCHECK(!url.empty());
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200251 rtc::tokenize(url, '?', &tokens);
252 std::string uri_without_transport = tokens[0];
253 // Let's look into transport= param, if it exists.
254 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
255 std::string uri_transport_param = tokens[1];
256 rtc::tokenize(uri_transport_param, '=', &tokens);
257 if (tokens[0] == kTransport) {
258 // As per above grammar transport param will be consist of lower case
259 // letters.
260 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
261 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
deadbeef0a6c4ca2015-10-06 11:38:28 -0700262 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000263 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200264 turn_transport_type = tokens[1];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000265 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200266 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000267
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200268 std::string hoststring;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700269 ServiceType service_type;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200270 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
271 &service_type,
272 &hoststring)) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700273 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: " << url;
274 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200275 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000276
deadbeef0a6c4ca2015-10-06 11:38:28 -0700277 // GetServiceTypeAndHostnameFromUri should never give an empty hoststring
278 RTC_DCHECK(!hoststring.empty());
Tommi77d444a2015-04-24 15:38:38 +0200279
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200280 // Let's break hostname.
281 tokens.clear();
deadbeef0a6c4ca2015-10-06 11:38:28 -0700282 rtc::tokenize_with_empty_tokens(hoststring, '@', &tokens);
283
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200284 std::string username(server.username);
deadbeef0a6c4ca2015-10-06 11:38:28 -0700285 if (tokens.size() > kTurnHostTokensNum) {
286 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring;
287 return false;
288 }
289 if (tokens.size() == kTurnHostTokensNum) {
290 if (tokens[0].empty() || tokens[1].empty()) {
291 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring;
292 return false;
293 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200294 username.assign(rtc::s_url_decode(tokens[0]));
295 hoststring = tokens[1];
296 } else {
297 hoststring = tokens[0];
298 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000299
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200300 int port = kDefaultStunPort;
301 if (service_type == TURNS) {
302 port = kDefaultStunTlsPort;
303 turn_transport_type = kTcpTransportType;
304 }
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000305
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200306 std::string address;
307 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700308 LOG(WARNING) << "Invalid hostname format: " << uri_without_transport;
309 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200310 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000311
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200312 if (port <= 0 || port > 0xffff) {
313 LOG(WARNING) << "Invalid port: " << port;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700314 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200315 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000316
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200317 switch (service_type) {
318 case STUN:
319 case STUNS:
320 stun_config->push_back(StunConfiguration(address, port));
321 break;
322 case TURN:
323 case TURNS: {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200324 bool secure = (service_type == TURNS);
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200325 turn_config->push_back(TurnConfiguration(address, port,
326 username,
327 server.password,
328 turn_transport_type,
329 secure));
330 break;
331 }
332 case INVALID:
333 default:
334 LOG(WARNING) << "Configuration not supported: " << url;
335 return false;
336 }
337 return true;
338}
339
deadbeef653b8e02015-11-11 12:55:10 -0800340void ConvertToCricketIceServers(
341 const std::vector<StunConfiguration>& stuns,
342 const std::vector<TurnConfiguration>& turns,
343 cricket::ServerAddresses* cricket_stuns,
344 std::vector<cricket::RelayServerConfig>* cricket_turns) {
345 RTC_DCHECK(cricket_stuns && cricket_turns);
346 for (const StunConfiguration& stun : stuns) {
347 cricket_stuns->insert(stun.server);
348 }
349
350 int priority = static_cast<int>(turns.size() - 1);
351 for (const TurnConfiguration& turn : turns) {
352 cricket::RelayCredentials credentials(turn.username, turn.password);
353 cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
354 cricket::ProtocolType protocol;
355 // Using VERIFY because ParseIceServers should have already caught an
356 // invalid transport type.
357 if (!VERIFY(
358 cricket::StringToProto(turn.transport_type.c_str(), &protocol))) {
359 LOG(LS_WARNING) << "Ignoring TURN server " << turn.server << ". "
360 << "Reason= Incorrect " << turn.transport_type
361 << " transport parameter.";
362 } else {
363 relay_server.ports.push_back(
364 cricket::ProtocolAddress(turn.server, protocol, turn.secure));
365 relay_server.credentials = credentials;
366 relay_server.priority = priority;
367 cricket_turns->push_back(relay_server);
368 }
369 // First in the list gets highest priority.
370 --priority;
371 }
372}
373
deadbeefab9b2d12015-10-14 11:33:11 -0700374// Check if we can send |new_stream| on a PeerConnection.
375bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
376 webrtc::MediaStreamInterface* new_stream) {
377 if (!new_stream || !current_streams) {
378 return false;
379 }
380 if (current_streams->find(new_stream->label()) != nullptr) {
381 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
382 << " is already added.";
383 return false;
384 }
385 return true;
386}
387
388bool MediaContentDirectionHasSend(cricket::MediaContentDirection dir) {
389 return dir == cricket::MD_SENDONLY || dir == cricket::MD_SENDRECV;
390}
391
deadbeef5e97fb52015-10-15 12:49:08 -0700392// If the direction is "recvonly" or "inactive", treat the description
393// as containing no streams.
394// See: https://code.google.com/p/webrtc/issues/detail?id=5054
395std::vector<cricket::StreamParams> GetActiveStreams(
396 const cricket::MediaContentDescription* desc) {
397 return MediaContentDirectionHasSend(desc->direction())
398 ? desc->streams()
399 : std::vector<cricket::StreamParams>();
400}
401
deadbeefab9b2d12015-10-14 11:33:11 -0700402bool IsValidOfferToReceiveMedia(int value) {
403 typedef PeerConnectionInterface::RTCOfferAnswerOptions Options;
404 return (value >= Options::kUndefined) &&
405 (value <= Options::kMaxOfferToReceiveMedia);
406}
407
408// Add the stream and RTP data channel info to |session_options|.
deadbeeffac06552015-11-25 11:26:01 -0800409void AddSendStreams(
410 cricket::MediaSessionOptions* session_options,
411 const std::vector<rtc::scoped_refptr<RtpSenderInterface>>& senders,
412 const std::map<std::string, rtc::scoped_refptr<DataChannel>>&
413 rtp_data_channels) {
deadbeefab9b2d12015-10-14 11:33:11 -0700414 session_options->streams.clear();
deadbeeffac06552015-11-25 11:26:01 -0800415 for (const auto& sender : senders) {
416 session_options->AddSendStream(sender->media_type(), sender->id(),
417 sender->stream_id());
deadbeefab9b2d12015-10-14 11:33:11 -0700418 }
419
420 // Check for data channels.
421 for (const auto& kv : rtp_data_channels) {
422 const DataChannel* channel = kv.second;
423 if (channel->state() == DataChannel::kConnecting ||
424 channel->state() == DataChannel::kOpen) {
425 // |streamid| and |sync_label| are both set to the DataChannel label
426 // here so they can be signaled the same way as MediaStreams and Tracks.
427 // For MediaStreams, the sync_label is the MediaStream label and the
428 // track label is the same as |streamid|.
429 const std::string& streamid = channel->label();
430 const std::string& sync_label = channel->label();
431 session_options->AddSendStream(cricket::MEDIA_TYPE_DATA, streamid,
432 sync_label);
433 }
434 }
435}
436
deadbeef0a6c4ca2015-10-06 11:38:28 -0700437} // namespace
438
439namespace webrtc {
440
deadbeefab9b2d12015-10-14 11:33:11 -0700441// Factory class for creating remote MediaStreams and MediaStreamTracks.
442class RemoteMediaStreamFactory {
443 public:
444 explicit RemoteMediaStreamFactory(rtc::Thread* signaling_thread,
445 cricket::ChannelManager* channel_manager)
446 : signaling_thread_(signaling_thread),
447 channel_manager_(channel_manager) {}
448
449 rtc::scoped_refptr<MediaStreamInterface> CreateMediaStream(
450 const std::string& stream_label) {
451 return MediaStreamProxy::Create(signaling_thread_,
452 MediaStream::Create(stream_label));
453 }
454
Tommif888bb52015-12-12 01:37:01 +0100455 AudioTrackInterface* AddAudioTrack(uint32_t ssrc,
456 AudioProviderInterface* provider,
457 webrtc::MediaStreamInterface* stream,
deadbeefab9b2d12015-10-14 11:33:11 -0700458 const std::string& track_id) {
tommi6eca7e32015-12-15 04:27:11 -0800459 return AddTrack<AudioTrackInterface, AudioTrack, AudioTrackProxy>(
Tommif888bb52015-12-12 01:37:01 +0100460 stream, track_id, RemoteAudioSource::Create(ssrc, provider));
deadbeefab9b2d12015-10-14 11:33:11 -0700461 }
462
463 VideoTrackInterface* AddVideoTrack(webrtc::MediaStreamInterface* stream,
464 const std::string& track_id) {
465 return AddTrack<VideoTrackInterface, VideoTrack, VideoTrackProxy>(
466 stream, track_id,
467 VideoSource::Create(channel_manager_, new RemoteVideoCapturer(),
tommi6eca7e32015-12-15 04:27:11 -0800468 nullptr, true)
deadbeefab9b2d12015-10-14 11:33:11 -0700469 .get());
470 }
471
472 private:
473 template <typename TI, typename T, typename TP, typename S>
474 TI* AddTrack(MediaStreamInterface* stream,
475 const std::string& track_id,
Tommif888bb52015-12-12 01:37:01 +0100476 const S& source) {
deadbeefab9b2d12015-10-14 11:33:11 -0700477 rtc::scoped_refptr<TI> track(
478 TP::Create(signaling_thread_, T::Create(track_id, source)));
479 track->set_state(webrtc::MediaStreamTrackInterface::kLive);
480 if (stream->AddTrack(track)) {
481 return track;
482 }
483 return nullptr;
484 }
485
486 rtc::Thread* signaling_thread_;
487 cricket::ChannelManager* channel_manager_;
488};
489
490bool ConvertRtcOptionsForOffer(
491 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
492 cricket::MediaSessionOptions* session_options) {
493 typedef PeerConnectionInterface::RTCOfferAnswerOptions RTCOfferAnswerOptions;
494 if (!IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_audio) ||
495 !IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_video)) {
496 return false;
497 }
498
deadbeefc80741f2015-10-22 13:14:45 -0700499 if (rtc_options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) {
deadbeefab9b2d12015-10-14 11:33:11 -0700500 session_options->recv_audio = (rtc_options.offer_to_receive_audio > 0);
501 }
deadbeefc80741f2015-10-22 13:14:45 -0700502 if (rtc_options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) {
deadbeefab9b2d12015-10-14 11:33:11 -0700503 session_options->recv_video = (rtc_options.offer_to_receive_video > 0);
504 }
505
506 session_options->vad_enabled = rtc_options.voice_activity_detection;
507 session_options->transport_options.ice_restart = rtc_options.ice_restart;
deadbeefc80741f2015-10-22 13:14:45 -0700508 session_options->bundle_enabled = rtc_options.use_rtp_mux;
deadbeefab9b2d12015-10-14 11:33:11 -0700509
510 return true;
511}
512
513bool ParseConstraintsForAnswer(const MediaConstraintsInterface* constraints,
514 cricket::MediaSessionOptions* session_options) {
515 bool value = false;
516 size_t mandatory_constraints_satisfied = 0;
517
518 // kOfferToReceiveAudio defaults to true according to spec.
519 if (!FindConstraint(constraints,
520 MediaConstraintsInterface::kOfferToReceiveAudio, &value,
521 &mandatory_constraints_satisfied) ||
522 value) {
523 session_options->recv_audio = true;
524 }
525
526 // kOfferToReceiveVideo defaults to false according to spec. But
527 // if it is an answer and video is offered, we should still accept video
528 // per default.
529 value = false;
530 if (!FindConstraint(constraints,
531 MediaConstraintsInterface::kOfferToReceiveVideo, &value,
532 &mandatory_constraints_satisfied) ||
533 value) {
534 session_options->recv_video = true;
535 }
536
537 if (FindConstraint(constraints,
538 MediaConstraintsInterface::kVoiceActivityDetection, &value,
539 &mandatory_constraints_satisfied)) {
540 session_options->vad_enabled = value;
541 }
542
543 if (FindConstraint(constraints, MediaConstraintsInterface::kUseRtpMux, &value,
544 &mandatory_constraints_satisfied)) {
545 session_options->bundle_enabled = value;
546 } else {
547 // kUseRtpMux defaults to true according to spec.
548 session_options->bundle_enabled = true;
549 }
deadbeefab9b2d12015-10-14 11:33:11 -0700550
551 if (FindConstraint(constraints, MediaConstraintsInterface::kIceRestart,
552 &value, &mandatory_constraints_satisfied)) {
553 session_options->transport_options.ice_restart = value;
554 } else {
555 // kIceRestart defaults to false according to spec.
556 session_options->transport_options.ice_restart = false;
557 }
558
559 if (!constraints) {
560 return true;
561 }
562 return mandatory_constraints_satisfied == constraints->GetMandatory().size();
563}
564
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200565bool ParseIceServers(const PeerConnectionInterface::IceServers& servers,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700566 StunConfigurations* stun_config,
567 TurnConfigurations* turn_config) {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200568 for (const webrtc::PeerConnectionInterface::IceServer& server : servers) {
569 if (!server.urls.empty()) {
570 for (const std::string& url : server.urls) {
Joachim Bauchd935f912015-05-29 22:14:21 +0200571 if (url.empty()) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700572 LOG(LS_ERROR) << "Empty uri.";
573 return false;
Joachim Bauchd935f912015-05-29 22:14:21 +0200574 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200575 if (!ParseIceServerUrl(server, url, stun_config, turn_config)) {
576 return false;
577 }
578 }
579 } else if (!server.uri.empty()) {
580 // Fallback to old .uri if new .urls isn't present.
581 if (!ParseIceServerUrl(server, server.uri, stun_config, turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200583 }
584 } else {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700585 LOG(LS_ERROR) << "Empty uri.";
586 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000587 }
588 }
589 return true;
590}
591
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000592PeerConnection::PeerConnection(PeerConnectionFactory* factory)
593 : factory_(factory),
594 observer_(NULL),
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000595 uma_observer_(NULL),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000596 signaling_state_(kStable),
597 ice_state_(kIceNew),
598 ice_connection_state_(kIceConnectionNew),
deadbeefab9b2d12015-10-14 11:33:11 -0700599 ice_gathering_state_(kIceGatheringNew),
600 local_streams_(StreamCollection::Create()),
601 remote_streams_(StreamCollection::Create()) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000602
603PeerConnection::~PeerConnection() {
Peter Boström1a9d6152015-12-08 22:15:17 +0100604 TRACE_EVENT0("webrtc", "PeerConnection::~PeerConnection");
deadbeef0a6c4ca2015-10-06 11:38:28 -0700605 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeef70ab1a12015-09-28 16:53:55 -0700606 // Need to detach RTP senders/receivers from WebRtcSession,
607 // since it's about to be destroyed.
608 for (const auto& sender : senders_) {
609 sender->Stop();
610 }
611 for (const auto& receiver : receivers_) {
612 receiver->Stop();
613 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614}
615
616bool PeerConnection::Initialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000617 const PeerConnectionInterface::RTCConfiguration& configuration,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000618 const MediaConstraintsInterface* constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000619 PortAllocatorFactoryInterface* allocator_factory,
Henrik Boström5e56c592015-08-11 10:33:13 +0200620 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000621 PeerConnectionObserver* observer) {
deadbeefab9b2d12015-10-14 11:33:11 -0700622 RTC_DCHECK(observer != nullptr);
623 if (!observer) {
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000624 return false;
deadbeefab9b2d12015-10-14 11:33:11 -0700625 }
deadbeef653b8e02015-11-11 12:55:10 -0800626
627 // This Initialize function parses ICE servers an extra time, but it will
628 // be removed once all PortAllocaotrs support SetIceServers.
629 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
630 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
631 if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
632 return false;
633 }
634 rtc::scoped_ptr<cricket::PortAllocator> allocator(
635 allocator_factory->CreatePortAllocator(stun_config, turn_config));
kwiberg0eb15ed2015-12-17 03:04:15 -0800636 return Initialize(configuration, constraints, std::move(allocator),
637 std::move(dtls_identity_store), observer);
deadbeef653b8e02015-11-11 12:55:10 -0800638}
639
640bool PeerConnection::Initialize(
641 const PeerConnectionInterface::RTCConfiguration& configuration,
642 const MediaConstraintsInterface* constraints,
643 rtc::scoped_ptr<cricket::PortAllocator> allocator,
644 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
645 PeerConnectionObserver* observer) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100646 TRACE_EVENT0("webrtc", "PeerConnection::Initialize");
deadbeef653b8e02015-11-11 12:55:10 -0800647 RTC_DCHECK(observer != nullptr);
648 if (!observer) {
649 return false;
650 }
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000651 observer_ = observer;
652
kwiberg0eb15ed2015-12-17 03:04:15 -0800653 port_allocator_ = std::move(allocator);
deadbeef653b8e02015-11-11 12:55:10 -0800654
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000655 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
656 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000657 if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658 return false;
659 }
deadbeef653b8e02015-11-11 12:55:10 -0800660
661 cricket::ServerAddresses cricket_stuns;
662 std::vector<cricket::RelayServerConfig> cricket_turns;
663 ConvertToCricketIceServers(stun_config, turn_config, &cricket_stuns,
664 &cricket_turns);
665 port_allocator_->SetIceServers(cricket_stuns, cricket_turns);
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000666
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000667 // To handle both internal and externally created port allocator, we will
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000668 // enable BUNDLE here.
braveyao@webrtc.org1732df62014-10-27 03:01:37 +0000669 int portallocator_flags = port_allocator_->flags();
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700670 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000671 cricket::PORTALLOCATOR_ENABLE_IPV6;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000672 bool value;
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000673 // If IPv6 flag was specified, we'll not override it by experiment.
deadbeefab9b2d12015-10-14 11:33:11 -0700674 if (FindConstraint(constraints, MediaConstraintsInterface::kEnableIPv6,
675 &value, nullptr)) {
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000676 if (!value) {
677 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000678 }
guoweis@webrtc.org2c1bcea2014-09-23 16:23:02 +0000679 } else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default") ==
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000680 "Disabled") {
681 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000682 }
683
Jiayang Liucac1b382015-04-30 12:35:24 -0700684 if (configuration.tcp_candidate_policy == kTcpCandidatePolicyDisabled) {
685 portallocator_flags |= cricket::PORTALLOCATOR_DISABLE_TCP;
686 LOG(LS_INFO) << "TCP candidates are disabled.";
687 }
688
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000689 port_allocator_->set_flags(portallocator_flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000690 // No step delay is used while allocating ports.
691 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
692
stefanc1aeaf02015-10-15 07:26:07 -0700693 media_controller_.reset(factory_->CreateMediaController());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000694
stefanc1aeaf02015-10-15 07:26:07 -0700695 remote_stream_factory_.reset(new RemoteMediaStreamFactory(
696 factory_->signaling_thread(), media_controller_->channel_manager()));
697
698 session_.reset(
699 new WebRtcSession(media_controller_.get(), factory_->signaling_thread(),
700 factory_->worker_thread(), port_allocator_.get()));
deadbeefab9b2d12015-10-14 11:33:11 -0700701 stats_.reset(new StatsCollector(this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000702
703 // Initialize the WebRtcSession. It creates transport channels etc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000704 if (!session_->Initialize(factory_->options(), constraints,
kwiberg0eb15ed2015-12-17 03:04:15 -0800705 std::move(dtls_identity_store), configuration)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000706 return false;
deadbeefab9b2d12015-10-14 11:33:11 -0700707 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000708
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000709 // Register PeerConnection as receiver of local ice candidates.
710 // All the callbacks will be posted to the application from PeerConnection.
711 session_->RegisterIceObserver(this);
712 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
deadbeefab9b2d12015-10-14 11:33:11 -0700713 session_->SignalVoiceChannelDestroyed.connect(
714 this, &PeerConnection::OnVoiceChannelDestroyed);
715 session_->SignalVideoChannelDestroyed.connect(
716 this, &PeerConnection::OnVideoChannelDestroyed);
717 session_->SignalDataChannelCreated.connect(
718 this, &PeerConnection::OnDataChannelCreated);
719 session_->SignalDataChannelDestroyed.connect(
720 this, &PeerConnection::OnDataChannelDestroyed);
721 session_->SignalDataChannelOpenMessage.connect(
722 this, &PeerConnection::OnDataChannelOpenMessage);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000723 return true;
724}
725
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000726rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000727PeerConnection::local_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -0700728 return local_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729}
730
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000731rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000732PeerConnection::remote_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -0700733 return remote_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000734}
735
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +0000736bool PeerConnection::AddStream(MediaStreamInterface* local_stream) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100737 TRACE_EVENT0("webrtc", "PeerConnection::AddStream");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000738 if (IsClosed()) {
739 return false;
740 }
deadbeefab9b2d12015-10-14 11:33:11 -0700741 if (!CanAddLocalMediaStream(local_streams_, local_stream)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000742 return false;
743 }
deadbeefab9b2d12015-10-14 11:33:11 -0700744
745 local_streams_->AddStream(local_stream);
deadbeefeb459812015-12-15 19:24:43 -0800746 MediaStreamObserver* observer = new MediaStreamObserver(local_stream);
747 observer->SignalAudioTrackAdded.connect(this,
748 &PeerConnection::OnAudioTrackAdded);
749 observer->SignalAudioTrackRemoved.connect(
750 this, &PeerConnection::OnAudioTrackRemoved);
751 observer->SignalVideoTrackAdded.connect(this,
752 &PeerConnection::OnVideoTrackAdded);
753 observer->SignalVideoTrackRemoved.connect(
754 this, &PeerConnection::OnVideoTrackRemoved);
755 stream_observers_.push_back(rtc::scoped_ptr<MediaStreamObserver>(observer));
deadbeefab9b2d12015-10-14 11:33:11 -0700756
deadbeefab9b2d12015-10-14 11:33:11 -0700757 for (const auto& track : local_stream->GetAudioTracks()) {
deadbeefeb459812015-12-15 19:24:43 -0800758 OnAudioTrackAdded(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -0700759 }
760 for (const auto& track : local_stream->GetVideoTracks()) {
deadbeefeb459812015-12-15 19:24:43 -0800761 OnVideoTrackAdded(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -0700762 }
763
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000764 stats_->AddStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000765 observer_->OnRenegotiationNeeded();
766 return true;
767}
768
769void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100770 TRACE_EVENT0("webrtc", "PeerConnection::RemoveStream");
deadbeefab9b2d12015-10-14 11:33:11 -0700771 for (const auto& track : local_stream->GetAudioTracks()) {
deadbeefeb459812015-12-15 19:24:43 -0800772 OnAudioTrackRemoved(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -0700773 }
774 for (const auto& track : local_stream->GetVideoTracks()) {
deadbeefeb459812015-12-15 19:24:43 -0800775 OnVideoTrackRemoved(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -0700776 }
777
778 local_streams_->RemoveStream(local_stream);
deadbeefeb459812015-12-15 19:24:43 -0800779 stream_observers_.erase(
780 std::remove_if(
781 stream_observers_.begin(), stream_observers_.end(),
782 [local_stream](const rtc::scoped_ptr<MediaStreamObserver>& observer) {
783 return observer->stream()->label().compare(local_stream->label()) ==
784 0;
785 }),
786 stream_observers_.end());
deadbeefab9b2d12015-10-14 11:33:11 -0700787
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000788 if (IsClosed()) {
789 return;
790 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000791 observer_->OnRenegotiationNeeded();
792}
793
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000794rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000795 AudioTrackInterface* track) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100796 TRACE_EVENT0("webrtc", "PeerConnection::CreateDtmfSender");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000797 if (!track) {
798 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
799 return NULL;
800 }
deadbeefab9b2d12015-10-14 11:33:11 -0700801 if (!local_streams_->FindAudioTrack(track->id())) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000802 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
803 return NULL;
804 }
805
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000806 rtc::scoped_refptr<DtmfSenderInterface> sender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000807 DtmfSender::Create(track, signaling_thread(), session_.get()));
808 if (!sender.get()) {
809 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
810 return NULL;
811 }
812 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
813}
814
deadbeeffac06552015-11-25 11:26:01 -0800815rtc::scoped_refptr<RtpSenderInterface> PeerConnection::CreateSender(
816 const std::string& kind) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100817 TRACE_EVENT0("webrtc", "PeerConnection::CreateSender");
deadbeeffac06552015-11-25 11:26:01 -0800818 RtpSenderInterface* new_sender;
819 if (kind == MediaStreamTrackInterface::kAudioKind) {
820 new_sender = new AudioRtpSender(session_.get(), stats_.get());
821 } else if (kind == MediaStreamTrackInterface::kVideoKind) {
822 new_sender = new VideoRtpSender(session_.get());
823 } else {
824 LOG(LS_ERROR) << "CreateSender called with invalid kind: " << kind;
825 return rtc::scoped_refptr<RtpSenderInterface>();
826 }
827 senders_.push_back(new_sender);
828 return RtpSenderProxy::Create(signaling_thread(), new_sender);
829}
830
deadbeef70ab1a12015-09-28 16:53:55 -0700831std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders()
832 const {
833 std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders;
834 for (const auto& sender : senders_) {
835 senders.push_back(RtpSenderProxy::Create(signaling_thread(), sender.get()));
836 }
837 return senders;
838}
839
840std::vector<rtc::scoped_refptr<RtpReceiverInterface>>
841PeerConnection::GetReceivers() const {
842 std::vector<rtc::scoped_refptr<RtpReceiverInterface>> receivers;
843 for (const auto& receiver : receivers_) {
844 receivers.push_back(
845 RtpReceiverProxy::Create(signaling_thread(), receiver.get()));
846 }
847 return receivers;
848}
849
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000851 MediaStreamTrackInterface* track,
852 StatsOutputLevel level) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100853 TRACE_EVENT0("webrtc", "PeerConnection::GetStats");
deadbeef0a6c4ca2015-10-06 11:38:28 -0700854 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000855 if (!VERIFY(observer != NULL)) {
856 LOG(LS_ERROR) << "GetStats - observer is NULL.";
857 return false;
858 }
859
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000860 stats_->UpdateStats(level);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000861 signaling_thread()->Post(this, MSG_GETSTATS,
862 new GetStatsMsg(observer, track));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000863 return true;
864}
865
866PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
867 return signaling_state_;
868}
869
870PeerConnectionInterface::IceState PeerConnection::ice_state() {
871 return ice_state_;
872}
873
874PeerConnectionInterface::IceConnectionState
875PeerConnection::ice_connection_state() {
876 return ice_connection_state_;
877}
878
879PeerConnectionInterface::IceGatheringState
880PeerConnection::ice_gathering_state() {
881 return ice_gathering_state_;
882}
883
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000884rtc::scoped_refptr<DataChannelInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000885PeerConnection::CreateDataChannel(
886 const std::string& label,
887 const DataChannelInit* config) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100888 TRACE_EVENT0("webrtc", "PeerConnection::CreateDataChannel");
deadbeefab9b2d12015-10-14 11:33:11 -0700889 bool first_datachannel = !HasDataChannels();
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000890
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000891 rtc::scoped_ptr<InternalDataChannelInit> internal_config;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000892 if (config) {
893 internal_config.reset(new InternalDataChannelInit(*config));
894 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000895 rtc::scoped_refptr<DataChannelInterface> channel(
deadbeefab9b2d12015-10-14 11:33:11 -0700896 InternalCreateDataChannel(label, internal_config.get()));
897 if (!channel.get()) {
898 return nullptr;
899 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000900
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000901 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
902 // the first SCTP DataChannel.
903 if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
904 observer_->OnRenegotiationNeeded();
905 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000906
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000907 return DataChannelProxy::Create(signaling_thread(), channel.get());
908}
909
910void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
911 const MediaConstraintsInterface* constraints) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100912 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer");
deadbeefab9b2d12015-10-14 11:33:11 -0700913 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000914 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
915 return;
916 }
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000917 RTCOfferAnswerOptions options;
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000918
919 bool value;
920 size_t mandatory_constraints = 0;
921
922 if (FindConstraint(constraints,
923 MediaConstraintsInterface::kOfferToReceiveAudio,
924 &value,
925 &mandatory_constraints)) {
926 options.offer_to_receive_audio =
927 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
928 }
929
930 if (FindConstraint(constraints,
931 MediaConstraintsInterface::kOfferToReceiveVideo,
932 &value,
933 &mandatory_constraints)) {
934 options.offer_to_receive_video =
935 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
936 }
937
938 if (FindConstraint(constraints,
939 MediaConstraintsInterface::kVoiceActivityDetection,
940 &value,
941 &mandatory_constraints)) {
942 options.voice_activity_detection = value;
943 }
944
945 if (FindConstraint(constraints,
946 MediaConstraintsInterface::kIceRestart,
947 &value,
948 &mandatory_constraints)) {
949 options.ice_restart = value;
950 }
951
952 if (FindConstraint(constraints,
953 MediaConstraintsInterface::kUseRtpMux,
954 &value,
955 &mandatory_constraints)) {
956 options.use_rtp_mux = value;
957 }
958
959 CreateOffer(observer, options);
960}
961
962void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
963 const RTCOfferAnswerOptions& options) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100964 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer");
deadbeefab9b2d12015-10-14 11:33:11 -0700965 if (!VERIFY(observer != nullptr)) {
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000966 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
967 return;
968 }
deadbeefab9b2d12015-10-14 11:33:11 -0700969
970 cricket::MediaSessionOptions session_options;
971 if (!GetOptionsForOffer(options, &session_options)) {
972 std::string error = "CreateOffer called with invalid options.";
973 LOG(LS_ERROR) << error;
974 PostCreateSessionDescriptionFailure(observer, error);
975 return;
976 }
977
978 session_->CreateOffer(observer, options, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000979}
980
981void PeerConnection::CreateAnswer(
982 CreateSessionDescriptionObserver* observer,
983 const MediaConstraintsInterface* constraints) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100984 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer");
deadbeefab9b2d12015-10-14 11:33:11 -0700985 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000986 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
987 return;
988 }
deadbeefab9b2d12015-10-14 11:33:11 -0700989
990 cricket::MediaSessionOptions session_options;
991 if (!GetOptionsForAnswer(constraints, &session_options)) {
992 std::string error = "CreateAnswer called with invalid constraints.";
993 LOG(LS_ERROR) << error;
994 PostCreateSessionDescriptionFailure(observer, error);
995 return;
996 }
997
998 session_->CreateAnswer(observer, constraints, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000999}
1000
1001void PeerConnection::SetLocalDescription(
1002 SetSessionDescriptionObserver* observer,
1003 SessionDescriptionInterface* desc) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001004 TRACE_EVENT0("webrtc", "PeerConnection::SetLocalDescription");
deadbeefab9b2d12015-10-14 11:33:11 -07001005 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001006 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
1007 return;
1008 }
1009 if (!desc) {
1010 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
1011 return;
1012 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001013 // Update stats here so that we have the most recent stats for tracks and
1014 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001015 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001016 std::string error;
1017 if (!session_->SetLocalDescription(desc, &error)) {
1018 PostSetSessionDescriptionFailure(observer, error);
1019 return;
1020 }
deadbeefab9b2d12015-10-14 11:33:11 -07001021
1022 // If setting the description decided our SSL role, allocate any necessary
1023 // SCTP sids.
1024 rtc::SSLRole role;
1025 if (session_->data_channel_type() == cricket::DCT_SCTP &&
1026 session_->GetSslRole(&role)) {
1027 AllocateSctpSids(role);
1028 }
1029
1030 // Update state and SSRC of local MediaStreams and DataChannels based on the
1031 // local session description.
1032 const cricket::ContentInfo* audio_content =
1033 GetFirstAudioContent(desc->description());
1034 if (audio_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001035 if (audio_content->rejected) {
1036 RemoveTracks(cricket::MEDIA_TYPE_AUDIO);
1037 } else {
1038 const cricket::AudioContentDescription* audio_desc =
1039 static_cast<const cricket::AudioContentDescription*>(
1040 audio_content->description);
1041 UpdateLocalTracks(audio_desc->streams(), audio_desc->type());
1042 }
deadbeefab9b2d12015-10-14 11:33:11 -07001043 }
1044
1045 const cricket::ContentInfo* video_content =
1046 GetFirstVideoContent(desc->description());
1047 if (video_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001048 if (video_content->rejected) {
1049 RemoveTracks(cricket::MEDIA_TYPE_VIDEO);
1050 } else {
1051 const cricket::VideoContentDescription* video_desc =
1052 static_cast<const cricket::VideoContentDescription*>(
1053 video_content->description);
1054 UpdateLocalTracks(video_desc->streams(), video_desc->type());
1055 }
deadbeefab9b2d12015-10-14 11:33:11 -07001056 }
1057
1058 const cricket::ContentInfo* data_content =
1059 GetFirstDataContent(desc->description());
1060 if (data_content) {
1061 const cricket::DataContentDescription* data_desc =
1062 static_cast<const cricket::DataContentDescription*>(
1063 data_content->description);
1064 if (rtc::starts_with(data_desc->protocol().data(),
1065 cricket::kMediaProtocolRtpPrefix)) {
1066 UpdateLocalRtpDataChannels(data_desc->streams());
1067 }
1068 }
1069
1070 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001071 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeefab9b2d12015-10-14 11:33:11 -07001072
deadbeefcbecd352015-09-23 11:50:27 -07001073 // MaybeStartGathering needs to be called after posting
1074 // MSG_SET_SESSIONDESCRIPTION_SUCCESS, so that we don't signal any candidates
1075 // before signaling that SetLocalDescription completed.
1076 session_->MaybeStartGathering();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001077}
1078
1079void PeerConnection::SetRemoteDescription(
1080 SetSessionDescriptionObserver* observer,
1081 SessionDescriptionInterface* desc) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001082 TRACE_EVENT0("webrtc", "PeerConnection::SetRemoteDescription");
deadbeefab9b2d12015-10-14 11:33:11 -07001083 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001084 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
1085 return;
1086 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001087 if (!desc) {
1088 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
1089 return;
1090 }
1091 // Update stats here so that we have the most recent stats for tracks and
1092 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001093 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001094 std::string error;
1095 if (!session_->SetRemoteDescription(desc, &error)) {
1096 PostSetSessionDescriptionFailure(observer, error);
1097 return;
1098 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001099
deadbeefab9b2d12015-10-14 11:33:11 -07001100 // If setting the description decided our SSL role, allocate any necessary
1101 // SCTP sids.
1102 rtc::SSLRole role;
1103 if (session_->data_channel_type() == cricket::DCT_SCTP &&
1104 session_->GetSslRole(&role)) {
1105 AllocateSctpSids(role);
1106 }
1107
1108 const cricket::SessionDescription* remote_desc = desc->description();
deadbeefbda7e0b2015-12-08 17:13:40 -08001109 const cricket::ContentInfo* audio_content = GetFirstAudioContent(remote_desc);
1110 const cricket::ContentInfo* video_content = GetFirstVideoContent(remote_desc);
1111 const cricket::AudioContentDescription* audio_desc =
1112 GetFirstAudioContentDescription(remote_desc);
1113 const cricket::VideoContentDescription* video_desc =
1114 GetFirstVideoContentDescription(remote_desc);
1115 const cricket::DataContentDescription* data_desc =
1116 GetFirstDataContentDescription(remote_desc);
1117
1118 // Check if the descriptions include streams, just in case the peer supports
1119 // MSID, but doesn't indicate so with "a=msid-semantic".
1120 if (remote_desc->msid_supported() ||
1121 (audio_desc && !audio_desc->streams().empty()) ||
1122 (video_desc && !video_desc->streams().empty())) {
1123 remote_peer_supports_msid_ = true;
1124 }
deadbeefab9b2d12015-10-14 11:33:11 -07001125
1126 // We wait to signal new streams until we finish processing the description,
1127 // since only at that point will new streams have all their tracks.
1128 rtc::scoped_refptr<StreamCollection> new_streams(StreamCollection::Create());
1129
1130 // Find all audio rtp streams and create corresponding remote AudioTracks
1131 // and MediaStreams.
deadbeefab9b2d12015-10-14 11:33:11 -07001132 if (audio_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001133 if (audio_content->rejected) {
1134 RemoveTracks(cricket::MEDIA_TYPE_AUDIO);
1135 } else {
deadbeefbda7e0b2015-12-08 17:13:40 -08001136 bool default_audio_track_needed =
1137 !remote_peer_supports_msid_ &&
1138 MediaContentDirectionHasSend(audio_desc->direction());
1139 UpdateRemoteStreamsList(GetActiveStreams(audio_desc),
1140 default_audio_track_needed, audio_desc->type(),
deadbeeffaac4972015-11-12 15:33:07 -08001141 new_streams);
deadbeeffaac4972015-11-12 15:33:07 -08001142 }
deadbeefab9b2d12015-10-14 11:33:11 -07001143 }
1144
1145 // Find all video rtp streams and create corresponding remote VideoTracks
1146 // and MediaStreams.
deadbeefab9b2d12015-10-14 11:33:11 -07001147 if (video_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001148 if (video_content->rejected) {
1149 RemoveTracks(cricket::MEDIA_TYPE_VIDEO);
1150 } else {
deadbeefbda7e0b2015-12-08 17:13:40 -08001151 bool default_video_track_needed =
1152 !remote_peer_supports_msid_ &&
1153 MediaContentDirectionHasSend(video_desc->direction());
1154 UpdateRemoteStreamsList(GetActiveStreams(video_desc),
1155 default_video_track_needed, video_desc->type(),
deadbeeffaac4972015-11-12 15:33:07 -08001156 new_streams);
deadbeeffaac4972015-11-12 15:33:07 -08001157 }
deadbeefab9b2d12015-10-14 11:33:11 -07001158 }
1159
1160 // Update the DataChannels with the information from the remote peer.
deadbeefbda7e0b2015-12-08 17:13:40 -08001161 if (data_desc) {
1162 if (rtc::starts_with(data_desc->protocol().data(),
deadbeefab9b2d12015-10-14 11:33:11 -07001163 cricket::kMediaProtocolRtpPrefix)) {
deadbeefbda7e0b2015-12-08 17:13:40 -08001164 UpdateRemoteRtpDataChannels(GetActiveStreams(data_desc));
deadbeefab9b2d12015-10-14 11:33:11 -07001165 }
1166 }
1167
1168 // Iterate new_streams and notify the observer about new MediaStreams.
1169 for (size_t i = 0; i < new_streams->count(); ++i) {
1170 MediaStreamInterface* new_stream = new_streams->at(i);
1171 stats_->AddStream(new_stream);
1172 observer_->OnAddStream(new_stream);
1173 }
1174
deadbeefbda7e0b2015-12-08 17:13:40 -08001175 UpdateEndedRemoteMediaStreams();
deadbeefab9b2d12015-10-14 11:33:11 -07001176
1177 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1178 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeeffc648b62015-10-13 16:42:33 -07001179}
1180
deadbeefa67696b2015-09-29 11:56:26 -07001181bool PeerConnection::SetConfiguration(const RTCConfiguration& config) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001182 TRACE_EVENT0("webrtc", "PeerConnection::SetConfiguration");
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001183 if (port_allocator_) {
1184 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
1185 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
1186 if (!ParseIceServers(config.servers, &stuns, &turns)) {
1187 return false;
1188 }
1189
deadbeef653b8e02015-11-11 12:55:10 -08001190 cricket::ServerAddresses cricket_stuns;
1191 std::vector<cricket::RelayServerConfig> cricket_turns;
1192 ConvertToCricketIceServers(stuns, turns, &cricket_stuns, &cricket_turns);
1193 port_allocator_->SetIceServers(cricket_stuns, cricket_turns);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001194 }
honghaiz1f429e32015-09-28 07:57:34 -07001195 session_->SetIceConfig(session_->ParseIceConfig(config));
mallinath@webrtc.org3d81b1b2014-09-09 14:38:10 +00001196 return session_->SetIceTransports(config.type);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001197}
1198
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001199bool PeerConnection::AddIceCandidate(
1200 const IceCandidateInterface* ice_candidate) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001201 TRACE_EVENT0("webrtc", "PeerConnection::AddIceCandidate");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001202 return session_->ProcessIceMessage(ice_candidate);
1203}
1204
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001205void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001206 TRACE_EVENT0("webrtc", "PeerConnection::RegisterUmaObserver");
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001207 uma_observer_ = observer;
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +00001208
1209 if (session_) {
1210 session_->set_metrics_observer(uma_observer_);
1211 }
1212
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001213 // Send information about IPv4/IPv6 status.
1214 if (uma_observer_ && port_allocator_) {
1215 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001216 uma_observer_->IncrementEnumCounter(
1217 kEnumCounterAddressFamily, kPeerConnection_IPv6,
1218 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgb445f262014-05-23 22:19:37 +00001219 } else {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001220 uma_observer_->IncrementEnumCounter(
1221 kEnumCounterAddressFamily, kPeerConnection_IPv4,
1222 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001223 }
1224 }
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001225}
1226
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001227const SessionDescriptionInterface* PeerConnection::local_description() const {
1228 return session_->local_description();
1229}
1230
1231const SessionDescriptionInterface* PeerConnection::remote_description() const {
1232 return session_->remote_description();
1233}
1234
1235void PeerConnection::Close() {
Peter Boström1a9d6152015-12-08 22:15:17 +01001236 TRACE_EVENT0("webrtc", "PeerConnection::Close");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001237 // Update stats here so that we have the most recent stats for tracks and
1238 // streams before the channels are closed.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001239 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001240
deadbeefd59daf82015-10-14 15:02:44 -07001241 session_->Close();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001242}
1243
deadbeefd59daf82015-10-14 15:02:44 -07001244void PeerConnection::OnSessionStateChange(WebRtcSession* /*session*/,
1245 WebRtcSession::State state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001246 switch (state) {
deadbeefd59daf82015-10-14 15:02:44 -07001247 case WebRtcSession::STATE_INIT:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001248 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001249 break;
deadbeefd59daf82015-10-14 15:02:44 -07001250 case WebRtcSession::STATE_SENTOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001251 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
1252 break;
deadbeefd59daf82015-10-14 15:02:44 -07001253 case WebRtcSession::STATE_SENTPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001254 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
1255 break;
deadbeefd59daf82015-10-14 15:02:44 -07001256 case WebRtcSession::STATE_RECEIVEDOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001257 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
1258 break;
deadbeefd59daf82015-10-14 15:02:44 -07001259 case WebRtcSession::STATE_RECEIVEDPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001260 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
1261 break;
deadbeefd59daf82015-10-14 15:02:44 -07001262 case WebRtcSession::STATE_INPROGRESS:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001263 ChangeSignalingState(PeerConnectionInterface::kStable);
1264 break;
deadbeefd59daf82015-10-14 15:02:44 -07001265 case WebRtcSession::STATE_CLOSED:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001266 ChangeSignalingState(PeerConnectionInterface::kClosed);
1267 break;
1268 default:
1269 break;
1270 }
1271}
1272
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001273void PeerConnection::OnMessage(rtc::Message* msg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001274 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001275 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
1276 SetSessionDescriptionMsg* param =
1277 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1278 param->observer->OnSuccess();
1279 delete param;
1280 break;
1281 }
1282 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
1283 SetSessionDescriptionMsg* param =
1284 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1285 param->observer->OnFailure(param->error);
1286 delete param;
1287 break;
1288 }
deadbeefab9b2d12015-10-14 11:33:11 -07001289 case MSG_CREATE_SESSIONDESCRIPTION_FAILED: {
1290 CreateSessionDescriptionMsg* param =
1291 static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
1292 param->observer->OnFailure(param->error);
1293 delete param;
1294 break;
1295 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001296 case MSG_GETSTATS: {
1297 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +00001298 StatsReports reports;
1299 stats_->GetStats(param->track, &reports);
1300 param->observer->OnComplete(reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001301 delete param;
1302 break;
1303 }
deadbeefbd292462015-12-14 18:15:29 -08001304 case MSG_FREE_DATACHANNELS: {
1305 sctp_data_channels_to_free_.clear();
1306 break;
1307 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001308 default:
deadbeef0a6c4ca2015-10-06 11:38:28 -07001309 RTC_DCHECK(false && "Not implemented");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001310 break;
1311 }
1312}
1313
deadbeefab9b2d12015-10-14 11:33:11 -07001314void PeerConnection::CreateAudioReceiver(MediaStreamInterface* stream,
1315 AudioTrackInterface* audio_track,
1316 uint32_t ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -07001317 receivers_.push_back(new AudioRtpReceiver(audio_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001318}
1319
deadbeefab9b2d12015-10-14 11:33:11 -07001320void PeerConnection::CreateVideoReceiver(MediaStreamInterface* stream,
1321 VideoTrackInterface* video_track,
1322 uint32_t ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -07001323 receivers_.push_back(new VideoRtpReceiver(video_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001324}
1325
deadbeef70ab1a12015-09-28 16:53:55 -07001326// TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote
1327// description.
deadbeefab9b2d12015-10-14 11:33:11 -07001328void PeerConnection::DestroyAudioReceiver(MediaStreamInterface* stream,
1329 AudioTrackInterface* audio_track) {
deadbeef70ab1a12015-09-28 16:53:55 -07001330 auto it = FindReceiverForTrack(audio_track);
1331 if (it == receivers_.end()) {
1332 LOG(LS_WARNING) << "RtpReceiver for track with id " << audio_track->id()
1333 << " doesn't exist.";
1334 } else {
1335 (*it)->Stop();
1336 receivers_.erase(it);
1337 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001338}
1339
deadbeefab9b2d12015-10-14 11:33:11 -07001340void PeerConnection::DestroyVideoReceiver(MediaStreamInterface* stream,
1341 VideoTrackInterface* video_track) {
deadbeef70ab1a12015-09-28 16:53:55 -07001342 auto it = FindReceiverForTrack(video_track);
1343 if (it == receivers_.end()) {
1344 LOG(LS_WARNING) << "RtpReceiver for track with id " << video_track->id()
1345 << " doesn't exist.";
1346 } else {
1347 (*it)->Stop();
1348 receivers_.erase(it);
1349 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001350}
deadbeef70ab1a12015-09-28 16:53:55 -07001351
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001352void PeerConnection::OnIceConnectionChange(
1353 PeerConnectionInterface::IceConnectionState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001354 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefcbecd352015-09-23 11:50:27 -07001355 // After transitioning to "closed", ignore any additional states from
1356 // WebRtcSession (such as "disconnected").
deadbeefab9b2d12015-10-14 11:33:11 -07001357 if (IsClosed()) {
deadbeefcbecd352015-09-23 11:50:27 -07001358 return;
1359 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001360 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001361 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001362}
1363
1364void PeerConnection::OnIceGatheringChange(
1365 PeerConnectionInterface::IceGatheringState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001366 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001367 if (IsClosed()) {
1368 return;
1369 }
1370 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001371 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001372}
1373
1374void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001375 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001376 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001377}
1378
1379void PeerConnection::OnIceComplete() {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001380 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001381 observer_->OnIceComplete();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001382}
1383
Peter Thatcher54360512015-07-08 11:08:35 -07001384void PeerConnection::OnIceConnectionReceivingChange(bool receiving) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001385 RTC_DCHECK(signaling_thread()->IsCurrent());
Peter Thatcher54360512015-07-08 11:08:35 -07001386 observer_->OnIceConnectionReceivingChange(receiving);
1387}
1388
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001389void PeerConnection::ChangeSignalingState(
1390 PeerConnectionInterface::SignalingState signaling_state) {
1391 signaling_state_ = signaling_state;
1392 if (signaling_state == kClosed) {
1393 ice_connection_state_ = kIceConnectionClosed;
1394 observer_->OnIceConnectionChange(ice_connection_state_);
1395 if (ice_gathering_state_ != kIceGatheringComplete) {
1396 ice_gathering_state_ = kIceGatheringComplete;
1397 observer_->OnIceGatheringChange(ice_gathering_state_);
1398 }
1399 }
1400 observer_->OnSignalingChange(signaling_state_);
1401 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
1402}
1403
deadbeefeb459812015-12-15 19:24:43 -08001404void PeerConnection::OnAudioTrackAdded(AudioTrackInterface* track,
1405 MediaStreamInterface* stream) {
1406 auto sender = FindSenderForTrack(track);
1407 if (sender != senders_.end()) {
1408 // We already have a sender for this track, so just change the stream_id
1409 // so that it's correct in the next call to CreateOffer.
1410 (*sender)->set_stream_id(stream->label());
1411 return;
1412 }
1413
1414 // Normal case; we've never seen this track before.
1415 AudioRtpSender* new_sender =
1416 new AudioRtpSender(track, stream->label(), session_.get(), stats_.get());
1417 senders_.push_back(new_sender);
1418 // If the sender has already been configured in SDP, we call SetSsrc,
1419 // which will connect the sender to the underlying transport. This can
1420 // occur if a local session description that contains the ID of the sender
1421 // is set before AddStream is called. It can also occur if the local
1422 // session description is not changed and RemoveStream is called, and
1423 // later AddStream is called again with the same stream.
1424 const TrackInfo* track_info =
1425 FindTrackInfo(local_audio_tracks_, stream->label(), track->id());
1426 if (track_info) {
1427 new_sender->SetSsrc(track_info->ssrc);
1428 }
1429}
1430
1431// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around
1432// indefinitely, when we have unified plan SDP.
1433void PeerConnection::OnAudioTrackRemoved(AudioTrackInterface* track,
1434 MediaStreamInterface* stream) {
1435 auto sender = FindSenderForTrack(track);
1436 if (sender == senders_.end()) {
1437 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
1438 << " doesn't exist.";
1439 return;
1440 }
1441 (*sender)->Stop();
1442 senders_.erase(sender);
1443}
1444
1445void PeerConnection::OnVideoTrackAdded(VideoTrackInterface* track,
1446 MediaStreamInterface* stream) {
1447 auto sender = FindSenderForTrack(track);
1448 if (sender != senders_.end()) {
1449 // We already have a sender for this track, so just change the stream_id
1450 // so that it's correct in the next call to CreateOffer.
1451 (*sender)->set_stream_id(stream->label());
1452 return;
1453 }
1454
1455 // Normal case; we've never seen this track before.
1456 VideoRtpSender* new_sender =
1457 new VideoRtpSender(track, stream->label(), session_.get());
1458 senders_.push_back(new_sender);
1459 const TrackInfo* track_info =
1460 FindTrackInfo(local_video_tracks_, stream->label(), track->id());
1461 if (track_info) {
1462 new_sender->SetSsrc(track_info->ssrc);
1463 }
1464}
1465
1466void PeerConnection::OnVideoTrackRemoved(VideoTrackInterface* track,
1467 MediaStreamInterface* stream) {
1468 auto sender = FindSenderForTrack(track);
1469 if (sender == senders_.end()) {
1470 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
1471 << " doesn't exist.";
1472 return;
1473 }
1474 (*sender)->Stop();
1475 senders_.erase(sender);
1476}
1477
deadbeefab9b2d12015-10-14 11:33:11 -07001478void PeerConnection::PostSetSessionDescriptionFailure(
1479 SetSessionDescriptionObserver* observer,
1480 const std::string& error) {
1481 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1482 msg->error = error;
1483 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
1484}
1485
1486void PeerConnection::PostCreateSessionDescriptionFailure(
1487 CreateSessionDescriptionObserver* observer,
1488 const std::string& error) {
1489 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
1490 msg->error = error;
1491 signaling_thread()->Post(this, MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
1492}
1493
1494bool PeerConnection::GetOptionsForOffer(
1495 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
1496 cricket::MediaSessionOptions* session_options) {
deadbeefab9b2d12015-10-14 11:33:11 -07001497 if (!ConvertRtcOptionsForOffer(rtc_options, session_options)) {
1498 return false;
1499 }
1500
deadbeeffac06552015-11-25 11:26:01 -08001501 AddSendStreams(session_options, senders_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001502 // Offer to receive audio/video if the constraint is not set and there are
1503 // send streams, or we're currently receiving.
1504 if (rtc_options.offer_to_receive_audio == RTCOfferAnswerOptions::kUndefined) {
1505 session_options->recv_audio =
1506 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_AUDIO) ||
1507 !remote_audio_tracks_.empty();
1508 }
1509 if (rtc_options.offer_to_receive_video == RTCOfferAnswerOptions::kUndefined) {
1510 session_options->recv_video =
1511 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_VIDEO) ||
1512 !remote_video_tracks_.empty();
1513 }
1514 session_options->bundle_enabled =
1515 session_options->bundle_enabled &&
1516 (session_options->has_audio() || session_options->has_video() ||
1517 session_options->has_data());
1518
deadbeefab9b2d12015-10-14 11:33:11 -07001519 if (session_->data_channel_type() == cricket::DCT_SCTP && HasDataChannels()) {
1520 session_options->data_channel_type = cricket::DCT_SCTP;
1521 }
1522 return true;
1523}
1524
1525bool PeerConnection::GetOptionsForAnswer(
1526 const MediaConstraintsInterface* constraints,
1527 cricket::MediaSessionOptions* session_options) {
deadbeefab9b2d12015-10-14 11:33:11 -07001528 session_options->recv_audio = false;
1529 session_options->recv_video = false;
deadbeefab9b2d12015-10-14 11:33:11 -07001530 if (!ParseConstraintsForAnswer(constraints, session_options)) {
1531 return false;
1532 }
1533
deadbeeffac06552015-11-25 11:26:01 -08001534 AddSendStreams(session_options, senders_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001535 session_options->bundle_enabled =
1536 session_options->bundle_enabled &&
1537 (session_options->has_audio() || session_options->has_video() ||
1538 session_options->has_data());
1539
deadbeefab9b2d12015-10-14 11:33:11 -07001540 // RTP data channel is handled in MediaSessionOptions::AddStream. SCTP streams
1541 // are not signaled in the SDP so does not go through that path and must be
1542 // handled here.
1543 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1544 session_options->data_channel_type = cricket::DCT_SCTP;
1545 }
1546 return true;
1547}
1548
deadbeeffaac4972015-11-12 15:33:07 -08001549void PeerConnection::RemoveTracks(cricket::MediaType media_type) {
1550 UpdateLocalTracks(std::vector<cricket::StreamParams>(), media_type);
deadbeefbda7e0b2015-12-08 17:13:40 -08001551 UpdateRemoteStreamsList(std::vector<cricket::StreamParams>(), false,
1552 media_type, nullptr);
deadbeeffaac4972015-11-12 15:33:07 -08001553}
1554
deadbeefab9b2d12015-10-14 11:33:11 -07001555void PeerConnection::UpdateRemoteStreamsList(
1556 const cricket::StreamParamsVec& streams,
deadbeefbda7e0b2015-12-08 17:13:40 -08001557 bool default_track_needed,
deadbeefab9b2d12015-10-14 11:33:11 -07001558 cricket::MediaType media_type,
1559 StreamCollection* new_streams) {
1560 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1561
1562 // Find removed tracks. I.e., tracks where the track id or ssrc don't match
deadbeeffac06552015-11-25 11:26:01 -08001563 // the new StreamParam.
deadbeefab9b2d12015-10-14 11:33:11 -07001564 auto track_it = current_tracks->begin();
1565 while (track_it != current_tracks->end()) {
1566 const TrackInfo& info = *track_it;
1567 const cricket::StreamParams* params =
1568 cricket::GetStreamBySsrc(streams, info.ssrc);
deadbeefbda7e0b2015-12-08 17:13:40 -08001569 bool track_exists = params && params->id == info.track_id;
1570 // If this is a default track, and we still need it, don't remove it.
1571 if ((info.stream_label == kDefaultStreamLabel && default_track_needed) ||
1572 track_exists) {
1573 ++track_it;
1574 } else {
deadbeefab9b2d12015-10-14 11:33:11 -07001575 OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
1576 track_it = current_tracks->erase(track_it);
deadbeefab9b2d12015-10-14 11:33:11 -07001577 }
1578 }
1579
1580 // Find new and active tracks.
1581 for (const cricket::StreamParams& params : streams) {
1582 // The sync_label is the MediaStream label and the |stream.id| is the
1583 // track id.
1584 const std::string& stream_label = params.sync_label;
1585 const std::string& track_id = params.id;
1586 uint32_t ssrc = params.first_ssrc();
1587
1588 rtc::scoped_refptr<MediaStreamInterface> stream =
1589 remote_streams_->find(stream_label);
1590 if (!stream) {
1591 // This is a new MediaStream. Create a new remote MediaStream.
1592 stream = remote_stream_factory_->CreateMediaStream(stream_label);
1593 remote_streams_->AddStream(stream);
1594 new_streams->AddStream(stream);
1595 }
1596
1597 const TrackInfo* track_info =
1598 FindTrackInfo(*current_tracks, stream_label, track_id);
1599 if (!track_info) {
1600 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1601 OnRemoteTrackSeen(stream_label, track_id, ssrc, media_type);
1602 }
1603 }
deadbeefbda7e0b2015-12-08 17:13:40 -08001604
1605 // Add default track if necessary.
1606 if (default_track_needed) {
1607 rtc::scoped_refptr<MediaStreamInterface> default_stream =
1608 remote_streams_->find(kDefaultStreamLabel);
1609 if (!default_stream) {
1610 // Create the new default MediaStream.
1611 default_stream =
1612 remote_stream_factory_->CreateMediaStream(kDefaultStreamLabel);
1613 remote_streams_->AddStream(default_stream);
1614 new_streams->AddStream(default_stream);
1615 }
1616 std::string default_track_id = (media_type == cricket::MEDIA_TYPE_AUDIO)
1617 ? kDefaultAudioTrackLabel
1618 : kDefaultVideoTrackLabel;
1619 const TrackInfo* default_track_info =
1620 FindTrackInfo(*current_tracks, kDefaultStreamLabel, default_track_id);
1621 if (!default_track_info) {
1622 current_tracks->push_back(
1623 TrackInfo(kDefaultStreamLabel, default_track_id, 0));
1624 OnRemoteTrackSeen(kDefaultStreamLabel, default_track_id, 0, media_type);
1625 }
1626 }
deadbeefab9b2d12015-10-14 11:33:11 -07001627}
1628
1629void PeerConnection::OnRemoteTrackSeen(const std::string& stream_label,
1630 const std::string& track_id,
1631 uint32_t ssrc,
1632 cricket::MediaType media_type) {
1633 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1634
1635 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
Tommif888bb52015-12-12 01:37:01 +01001636 AudioTrackInterface* audio_track = remote_stream_factory_->AddAudioTrack(
1637 ssrc, session_.get(), stream, track_id);
deadbeefab9b2d12015-10-14 11:33:11 -07001638 CreateAudioReceiver(stream, audio_track, ssrc);
1639 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1640 VideoTrackInterface* video_track =
1641 remote_stream_factory_->AddVideoTrack(stream, track_id);
1642 CreateVideoReceiver(stream, video_track, ssrc);
1643 } else {
1644 RTC_DCHECK(false && "Invalid media type");
1645 }
1646}
1647
1648void PeerConnection::OnRemoteTrackRemoved(const std::string& stream_label,
1649 const std::string& track_id,
1650 cricket::MediaType media_type) {
1651 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1652
1653 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1654 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1655 stream->FindAudioTrack(track_id);
1656 if (audio_track) {
1657 audio_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1658 stream->RemoveTrack(audio_track);
1659 DestroyAudioReceiver(stream, audio_track);
1660 }
1661 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1662 rtc::scoped_refptr<VideoTrackInterface> video_track =
1663 stream->FindVideoTrack(track_id);
1664 if (video_track) {
1665 video_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1666 stream->RemoveTrack(video_track);
1667 DestroyVideoReceiver(stream, video_track);
1668 }
1669 } else {
1670 ASSERT(false && "Invalid media type");
1671 }
1672}
1673
1674void PeerConnection::UpdateEndedRemoteMediaStreams() {
1675 std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams_to_remove;
1676 for (size_t i = 0; i < remote_streams_->count(); ++i) {
1677 MediaStreamInterface* stream = remote_streams_->at(i);
1678 if (stream->GetAudioTracks().empty() && stream->GetVideoTracks().empty()) {
1679 streams_to_remove.push_back(stream);
1680 }
1681 }
1682
1683 for (const auto& stream : streams_to_remove) {
1684 remote_streams_->RemoveStream(stream);
1685 observer_->OnRemoveStream(stream);
1686 }
1687}
1688
deadbeefab9b2d12015-10-14 11:33:11 -07001689void PeerConnection::EndRemoteTracks(cricket::MediaType media_type) {
1690 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1691 for (TrackInfos::iterator track_it = current_tracks->begin();
1692 track_it != current_tracks->end(); ++track_it) {
1693 const TrackInfo& info = *track_it;
1694 MediaStreamInterface* stream = remote_streams_->find(info.stream_label);
1695 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1696 AudioTrackInterface* track = stream->FindAudioTrack(info.track_id);
1697 // There's no guarantee the track is still available, e.g. the track may
1698 // have been removed from the stream by javascript.
1699 if (track) {
1700 track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1701 }
1702 }
1703 if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1704 VideoTrackInterface* track = stream->FindVideoTrack(info.track_id);
1705 // There's no guarantee the track is still available, e.g. the track may
1706 // have been removed from the stream by javascript.
1707 if (track) {
1708 track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1709 }
1710 }
1711 }
1712}
1713
1714void PeerConnection::UpdateLocalTracks(
1715 const std::vector<cricket::StreamParams>& streams,
1716 cricket::MediaType media_type) {
1717 TrackInfos* current_tracks = GetLocalTracks(media_type);
1718
1719 // Find removed tracks. I.e., tracks where the track id, stream label or ssrc
1720 // don't match the new StreamParam.
1721 TrackInfos::iterator track_it = current_tracks->begin();
1722 while (track_it != current_tracks->end()) {
1723 const TrackInfo& info = *track_it;
1724 const cricket::StreamParams* params =
1725 cricket::GetStreamBySsrc(streams, info.ssrc);
1726 if (!params || params->id != info.track_id ||
1727 params->sync_label != info.stream_label) {
1728 OnLocalTrackRemoved(info.stream_label, info.track_id, info.ssrc,
1729 media_type);
1730 track_it = current_tracks->erase(track_it);
1731 } else {
1732 ++track_it;
1733 }
1734 }
1735
1736 // Find new and active tracks.
1737 for (const cricket::StreamParams& params : streams) {
1738 // The sync_label is the MediaStream label and the |stream.id| is the
1739 // track id.
1740 const std::string& stream_label = params.sync_label;
1741 const std::string& track_id = params.id;
1742 uint32_t ssrc = params.first_ssrc();
1743 const TrackInfo* track_info =
1744 FindTrackInfo(*current_tracks, stream_label, track_id);
1745 if (!track_info) {
1746 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1747 OnLocalTrackSeen(stream_label, track_id, params.first_ssrc(), media_type);
1748 }
1749 }
1750}
1751
1752void PeerConnection::OnLocalTrackSeen(const std::string& stream_label,
1753 const std::string& track_id,
1754 uint32_t ssrc,
1755 cricket::MediaType media_type) {
deadbeeffac06552015-11-25 11:26:01 -08001756 RtpSenderInterface* sender = FindSenderById(track_id);
1757 if (!sender) {
1758 LOG(LS_WARNING) << "An unknown RtpSender with id " << track_id
1759 << " has been configured in the local description.";
deadbeefab9b2d12015-10-14 11:33:11 -07001760 return;
1761 }
1762
deadbeeffac06552015-11-25 11:26:01 -08001763 if (sender->media_type() != media_type) {
1764 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
1765 << " description with an unexpected media type.";
1766 return;
deadbeefab9b2d12015-10-14 11:33:11 -07001767 }
deadbeeffac06552015-11-25 11:26:01 -08001768
1769 sender->set_stream_id(stream_label);
1770 sender->SetSsrc(ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -07001771}
1772
1773void PeerConnection::OnLocalTrackRemoved(const std::string& stream_label,
1774 const std::string& track_id,
1775 uint32_t ssrc,
1776 cricket::MediaType media_type) {
deadbeeffac06552015-11-25 11:26:01 -08001777 RtpSenderInterface* sender = FindSenderById(track_id);
1778 if (!sender) {
1779 // This is the normal case. I.e., RemoveStream has been called and the
deadbeefab9b2d12015-10-14 11:33:11 -07001780 // SessionDescriptions has been renegotiated.
1781 return;
1782 }
deadbeeffac06552015-11-25 11:26:01 -08001783
1784 // A sender has been removed from the SessionDescription but it's still
1785 // associated with the PeerConnection. This only occurs if the SDP doesn't
1786 // match with the calls to CreateSender, AddStream and RemoveStream.
1787 if (sender->media_type() != media_type) {
1788 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
1789 << " description with an unexpected media type.";
1790 return;
deadbeefab9b2d12015-10-14 11:33:11 -07001791 }
deadbeeffac06552015-11-25 11:26:01 -08001792
1793 sender->SetSsrc(0);
deadbeefab9b2d12015-10-14 11:33:11 -07001794}
1795
1796void PeerConnection::UpdateLocalRtpDataChannels(
1797 const cricket::StreamParamsVec& streams) {
1798 std::vector<std::string> existing_channels;
1799
1800 // Find new and active data channels.
1801 for (const cricket::StreamParams& params : streams) {
1802 // |it->sync_label| is actually the data channel label. The reason is that
1803 // we use the same naming of data channels as we do for
1804 // MediaStreams and Tracks.
1805 // For MediaStreams, the sync_label is the MediaStream label and the
1806 // track label is the same as |streamid|.
1807 const std::string& channel_label = params.sync_label;
1808 auto data_channel_it = rtp_data_channels_.find(channel_label);
1809 if (!VERIFY(data_channel_it != rtp_data_channels_.end())) {
1810 continue;
1811 }
1812 // Set the SSRC the data channel should use for sending.
1813 data_channel_it->second->SetSendSsrc(params.first_ssrc());
1814 existing_channels.push_back(data_channel_it->first);
1815 }
1816
1817 UpdateClosingRtpDataChannels(existing_channels, true);
1818}
1819
1820void PeerConnection::UpdateRemoteRtpDataChannels(
1821 const cricket::StreamParamsVec& streams) {
1822 std::vector<std::string> existing_channels;
1823
1824 // Find new and active data channels.
1825 for (const cricket::StreamParams& params : streams) {
1826 // The data channel label is either the mslabel or the SSRC if the mslabel
1827 // does not exist. Ex a=ssrc:444330170 mslabel:test1.
1828 std::string label = params.sync_label.empty()
1829 ? rtc::ToString(params.first_ssrc())
1830 : params.sync_label;
1831 auto data_channel_it = rtp_data_channels_.find(label);
1832 if (data_channel_it == rtp_data_channels_.end()) {
1833 // This is a new data channel.
1834 CreateRemoteRtpDataChannel(label, params.first_ssrc());
1835 } else {
1836 data_channel_it->second->SetReceiveSsrc(params.first_ssrc());
1837 }
1838 existing_channels.push_back(label);
1839 }
1840
1841 UpdateClosingRtpDataChannels(existing_channels, false);
1842}
1843
1844void PeerConnection::UpdateClosingRtpDataChannels(
1845 const std::vector<std::string>& active_channels,
1846 bool is_local_update) {
1847 auto it = rtp_data_channels_.begin();
1848 while (it != rtp_data_channels_.end()) {
1849 DataChannel* data_channel = it->second;
1850 if (std::find(active_channels.begin(), active_channels.end(),
1851 data_channel->label()) != active_channels.end()) {
1852 ++it;
1853 continue;
1854 }
1855
1856 if (is_local_update) {
1857 data_channel->SetSendSsrc(0);
1858 } else {
1859 data_channel->RemotePeerRequestClose();
1860 }
1861
1862 if (data_channel->state() == DataChannel::kClosed) {
1863 rtp_data_channels_.erase(it);
1864 it = rtp_data_channels_.begin();
1865 } else {
1866 ++it;
1867 }
1868 }
1869}
1870
1871void PeerConnection::CreateRemoteRtpDataChannel(const std::string& label,
1872 uint32_t remote_ssrc) {
1873 rtc::scoped_refptr<DataChannel> channel(
1874 InternalCreateDataChannel(label, nullptr));
1875 if (!channel.get()) {
1876 LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
1877 << "CreateDataChannel failed.";
1878 return;
1879 }
1880 channel->SetReceiveSsrc(remote_ssrc);
1881 observer_->OnDataChannel(
1882 DataChannelProxy::Create(signaling_thread(), channel));
1883}
1884
1885rtc::scoped_refptr<DataChannel> PeerConnection::InternalCreateDataChannel(
1886 const std::string& label,
1887 const InternalDataChannelInit* config) {
1888 if (IsClosed()) {
1889 return nullptr;
1890 }
1891 if (session_->data_channel_type() == cricket::DCT_NONE) {
1892 LOG(LS_ERROR)
1893 << "InternalCreateDataChannel: Data is not supported in this call.";
1894 return nullptr;
1895 }
1896 InternalDataChannelInit new_config =
1897 config ? (*config) : InternalDataChannelInit();
1898 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1899 if (new_config.id < 0) {
1900 rtc::SSLRole role;
1901 if (session_->GetSslRole(&role) &&
1902 !sid_allocator_.AllocateSid(role, &new_config.id)) {
1903 LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel.";
1904 return nullptr;
1905 }
1906 } else if (!sid_allocator_.ReserveSid(new_config.id)) {
1907 LOG(LS_ERROR) << "Failed to create a SCTP data channel "
1908 << "because the id is already in use or out of range.";
1909 return nullptr;
1910 }
1911 }
1912
1913 rtc::scoped_refptr<DataChannel> channel(DataChannel::Create(
1914 session_.get(), session_->data_channel_type(), label, new_config));
1915 if (!channel) {
1916 sid_allocator_.ReleaseSid(new_config.id);
1917 return nullptr;
1918 }
1919
1920 if (channel->data_channel_type() == cricket::DCT_RTP) {
1921 if (rtp_data_channels_.find(channel->label()) != rtp_data_channels_.end()) {
1922 LOG(LS_ERROR) << "DataChannel with label " << channel->label()
1923 << " already exists.";
1924 return nullptr;
1925 }
1926 rtp_data_channels_[channel->label()] = channel;
1927 } else {
1928 RTC_DCHECK(channel->data_channel_type() == cricket::DCT_SCTP);
1929 sctp_data_channels_.push_back(channel);
1930 channel->SignalClosed.connect(this,
1931 &PeerConnection::OnSctpDataChannelClosed);
1932 }
1933
1934 return channel;
1935}
1936
1937bool PeerConnection::HasDataChannels() const {
1938 return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
1939}
1940
1941void PeerConnection::AllocateSctpSids(rtc::SSLRole role) {
1942 for (const auto& channel : sctp_data_channels_) {
1943 if (channel->id() < 0) {
1944 int sid;
1945 if (!sid_allocator_.AllocateSid(role, &sid)) {
1946 LOG(LS_ERROR) << "Failed to allocate SCTP sid.";
1947 continue;
1948 }
1949 channel->SetSctpSid(sid);
1950 }
1951 }
1952}
1953
1954void PeerConnection::OnSctpDataChannelClosed(DataChannel* channel) {
deadbeefbd292462015-12-14 18:15:29 -08001955 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefab9b2d12015-10-14 11:33:11 -07001956 for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end();
1957 ++it) {
1958 if (it->get() == channel) {
1959 if (channel->id() >= 0) {
1960 sid_allocator_.ReleaseSid(channel->id());
1961 }
deadbeefbd292462015-12-14 18:15:29 -08001962 // Since this method is triggered by a signal from the DataChannel,
1963 // we can't free it directly here; we need to free it asynchronously.
1964 sctp_data_channels_to_free_.push_back(*it);
deadbeefab9b2d12015-10-14 11:33:11 -07001965 sctp_data_channels_.erase(it);
deadbeefbd292462015-12-14 18:15:29 -08001966 signaling_thread()->Post(this, MSG_FREE_DATACHANNELS, nullptr);
deadbeefab9b2d12015-10-14 11:33:11 -07001967 return;
1968 }
1969 }
1970}
1971
1972void PeerConnection::OnVoiceChannelDestroyed() {
1973 EndRemoteTracks(cricket::MEDIA_TYPE_AUDIO);
1974}
1975
1976void PeerConnection::OnVideoChannelDestroyed() {
1977 EndRemoteTracks(cricket::MEDIA_TYPE_VIDEO);
1978}
1979
1980void PeerConnection::OnDataChannelCreated() {
1981 for (const auto& channel : sctp_data_channels_) {
1982 channel->OnTransportChannelCreated();
1983 }
1984}
1985
1986void PeerConnection::OnDataChannelDestroyed() {
1987 // Use a temporary copy of the RTP/SCTP DataChannel list because the
1988 // DataChannel may callback to us and try to modify the list.
1989 std::map<std::string, rtc::scoped_refptr<DataChannel>> temp_rtp_dcs;
1990 temp_rtp_dcs.swap(rtp_data_channels_);
1991 for (const auto& kv : temp_rtp_dcs) {
1992 kv.second->OnTransportChannelDestroyed();
1993 }
1994
1995 std::vector<rtc::scoped_refptr<DataChannel>> temp_sctp_dcs;
1996 temp_sctp_dcs.swap(sctp_data_channels_);
1997 for (const auto& channel : temp_sctp_dcs) {
1998 channel->OnTransportChannelDestroyed();
1999 }
2000}
2001
2002void PeerConnection::OnDataChannelOpenMessage(
2003 const std::string& label,
2004 const InternalDataChannelInit& config) {
2005 rtc::scoped_refptr<DataChannel> channel(
2006 InternalCreateDataChannel(label, &config));
2007 if (!channel.get()) {
2008 LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
2009 return;
2010 }
2011
2012 observer_->OnDataChannel(
2013 DataChannelProxy::Create(signaling_thread(), channel));
2014}
2015
deadbeeffac06552015-11-25 11:26:01 -08002016RtpSenderInterface* PeerConnection::FindSenderById(const std::string& id) {
2017 auto it =
2018 std::find_if(senders_.begin(), senders_.end(),
2019 [id](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
2020 return sender->id() == id;
2021 });
2022 return it != senders_.end() ? it->get() : nullptr;
2023}
2024
deadbeef70ab1a12015-09-28 16:53:55 -07002025std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator
2026PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) {
2027 return std::find_if(
2028 senders_.begin(), senders_.end(),
2029 [track](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
2030 return sender->track() == track;
2031 });
2032}
2033
2034std::vector<rtc::scoped_refptr<RtpReceiverInterface>>::iterator
2035PeerConnection::FindReceiverForTrack(MediaStreamTrackInterface* track) {
2036 return std::find_if(
2037 receivers_.begin(), receivers_.end(),
2038 [track](const rtc::scoped_refptr<RtpReceiverInterface>& receiver) {
2039 return receiver->track() == track;
2040 });
2041}
2042
deadbeefab9b2d12015-10-14 11:33:11 -07002043PeerConnection::TrackInfos* PeerConnection::GetRemoteTracks(
2044 cricket::MediaType media_type) {
2045 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
2046 media_type == cricket::MEDIA_TYPE_VIDEO);
2047 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &remote_audio_tracks_
2048 : &remote_video_tracks_;
2049}
2050
2051PeerConnection::TrackInfos* PeerConnection::GetLocalTracks(
2052 cricket::MediaType media_type) {
2053 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
2054 media_type == cricket::MEDIA_TYPE_VIDEO);
2055 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &local_audio_tracks_
2056 : &local_video_tracks_;
2057}
2058
2059const PeerConnection::TrackInfo* PeerConnection::FindTrackInfo(
2060 const PeerConnection::TrackInfos& infos,
2061 const std::string& stream_label,
2062 const std::string track_id) const {
2063 for (const TrackInfo& track_info : infos) {
2064 if (track_info.stream_label == stream_label &&
2065 track_info.track_id == track_id) {
2066 return &track_info;
2067 }
2068 }
2069 return nullptr;
2070}
2071
2072DataChannel* PeerConnection::FindDataChannelBySid(int sid) const {
2073 for (const auto& channel : sctp_data_channels_) {
2074 if (channel->id() == sid) {
2075 return channel;
2076 }
2077 }
2078 return nullptr;
2079}
2080
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002081} // namespace webrtc