blob: 617eb15518a18bb77730245db63b310ed591cb48 [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(
deadbeefbd7d8f72015-12-18 16:58:44 -0800816 const std::string& kind,
817 const std::string& stream_id) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100818 TRACE_EVENT0("webrtc", "PeerConnection::CreateSender");
deadbeeffac06552015-11-25 11:26:01 -0800819 RtpSenderInterface* new_sender;
820 if (kind == MediaStreamTrackInterface::kAudioKind) {
821 new_sender = new AudioRtpSender(session_.get(), stats_.get());
822 } else if (kind == MediaStreamTrackInterface::kVideoKind) {
823 new_sender = new VideoRtpSender(session_.get());
824 } else {
825 LOG(LS_ERROR) << "CreateSender called with invalid kind: " << kind;
826 return rtc::scoped_refptr<RtpSenderInterface>();
827 }
deadbeefbd7d8f72015-12-18 16:58:44 -0800828 if (!stream_id.empty()) {
829 new_sender->set_stream_id(stream_id);
830 }
deadbeeffac06552015-11-25 11:26:01 -0800831 senders_.push_back(new_sender);
832 return RtpSenderProxy::Create(signaling_thread(), new_sender);
833}
834
deadbeef70ab1a12015-09-28 16:53:55 -0700835std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders()
836 const {
837 std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders;
838 for (const auto& sender : senders_) {
839 senders.push_back(RtpSenderProxy::Create(signaling_thread(), sender.get()));
840 }
841 return senders;
842}
843
844std::vector<rtc::scoped_refptr<RtpReceiverInterface>>
845PeerConnection::GetReceivers() const {
846 std::vector<rtc::scoped_refptr<RtpReceiverInterface>> receivers;
847 for (const auto& receiver : receivers_) {
848 receivers.push_back(
849 RtpReceiverProxy::Create(signaling_thread(), receiver.get()));
850 }
851 return receivers;
852}
853
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000854bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000855 MediaStreamTrackInterface* track,
856 StatsOutputLevel level) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100857 TRACE_EVENT0("webrtc", "PeerConnection::GetStats");
deadbeef0a6c4ca2015-10-06 11:38:28 -0700858 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000859 if (!VERIFY(observer != NULL)) {
860 LOG(LS_ERROR) << "GetStats - observer is NULL.";
861 return false;
862 }
863
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000864 stats_->UpdateStats(level);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000865 signaling_thread()->Post(this, MSG_GETSTATS,
866 new GetStatsMsg(observer, track));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000867 return true;
868}
869
870PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
871 return signaling_state_;
872}
873
874PeerConnectionInterface::IceState PeerConnection::ice_state() {
875 return ice_state_;
876}
877
878PeerConnectionInterface::IceConnectionState
879PeerConnection::ice_connection_state() {
880 return ice_connection_state_;
881}
882
883PeerConnectionInterface::IceGatheringState
884PeerConnection::ice_gathering_state() {
885 return ice_gathering_state_;
886}
887
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000888rtc::scoped_refptr<DataChannelInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000889PeerConnection::CreateDataChannel(
890 const std::string& label,
891 const DataChannelInit* config) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100892 TRACE_EVENT0("webrtc", "PeerConnection::CreateDataChannel");
deadbeefab9b2d12015-10-14 11:33:11 -0700893 bool first_datachannel = !HasDataChannels();
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000894
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000895 rtc::scoped_ptr<InternalDataChannelInit> internal_config;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000896 if (config) {
897 internal_config.reset(new InternalDataChannelInit(*config));
898 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000899 rtc::scoped_refptr<DataChannelInterface> channel(
deadbeefab9b2d12015-10-14 11:33:11 -0700900 InternalCreateDataChannel(label, internal_config.get()));
901 if (!channel.get()) {
902 return nullptr;
903 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000904
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000905 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
906 // the first SCTP DataChannel.
907 if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
908 observer_->OnRenegotiationNeeded();
909 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000910
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000911 return DataChannelProxy::Create(signaling_thread(), channel.get());
912}
913
914void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
915 const MediaConstraintsInterface* constraints) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100916 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer");
deadbeefab9b2d12015-10-14 11:33:11 -0700917 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000918 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
919 return;
920 }
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000921 RTCOfferAnswerOptions options;
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000922
923 bool value;
924 size_t mandatory_constraints = 0;
925
926 if (FindConstraint(constraints,
927 MediaConstraintsInterface::kOfferToReceiveAudio,
928 &value,
929 &mandatory_constraints)) {
930 options.offer_to_receive_audio =
931 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
932 }
933
934 if (FindConstraint(constraints,
935 MediaConstraintsInterface::kOfferToReceiveVideo,
936 &value,
937 &mandatory_constraints)) {
938 options.offer_to_receive_video =
939 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
940 }
941
942 if (FindConstraint(constraints,
943 MediaConstraintsInterface::kVoiceActivityDetection,
944 &value,
945 &mandatory_constraints)) {
946 options.voice_activity_detection = value;
947 }
948
949 if (FindConstraint(constraints,
950 MediaConstraintsInterface::kIceRestart,
951 &value,
952 &mandatory_constraints)) {
953 options.ice_restart = value;
954 }
955
956 if (FindConstraint(constraints,
957 MediaConstraintsInterface::kUseRtpMux,
958 &value,
959 &mandatory_constraints)) {
960 options.use_rtp_mux = value;
961 }
962
963 CreateOffer(observer, options);
964}
965
966void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
967 const RTCOfferAnswerOptions& options) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100968 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer");
deadbeefab9b2d12015-10-14 11:33:11 -0700969 if (!VERIFY(observer != nullptr)) {
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000970 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
971 return;
972 }
deadbeefab9b2d12015-10-14 11:33:11 -0700973
974 cricket::MediaSessionOptions session_options;
975 if (!GetOptionsForOffer(options, &session_options)) {
976 std::string error = "CreateOffer called with invalid options.";
977 LOG(LS_ERROR) << error;
978 PostCreateSessionDescriptionFailure(observer, error);
979 return;
980 }
981
982 session_->CreateOffer(observer, options, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000983}
984
985void PeerConnection::CreateAnswer(
986 CreateSessionDescriptionObserver* observer,
987 const MediaConstraintsInterface* constraints) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100988 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer");
deadbeefab9b2d12015-10-14 11:33:11 -0700989 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000990 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
991 return;
992 }
deadbeefab9b2d12015-10-14 11:33:11 -0700993
994 cricket::MediaSessionOptions session_options;
995 if (!GetOptionsForAnswer(constraints, &session_options)) {
996 std::string error = "CreateAnswer called with invalid constraints.";
997 LOG(LS_ERROR) << error;
998 PostCreateSessionDescriptionFailure(observer, error);
999 return;
1000 }
1001
1002 session_->CreateAnswer(observer, constraints, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001003}
1004
1005void PeerConnection::SetLocalDescription(
1006 SetSessionDescriptionObserver* observer,
1007 SessionDescriptionInterface* desc) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001008 TRACE_EVENT0("webrtc", "PeerConnection::SetLocalDescription");
deadbeefab9b2d12015-10-14 11:33:11 -07001009 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001010 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
1011 return;
1012 }
1013 if (!desc) {
1014 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
1015 return;
1016 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001017 // Update stats here so that we have the most recent stats for tracks and
1018 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001019 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001020 std::string error;
1021 if (!session_->SetLocalDescription(desc, &error)) {
1022 PostSetSessionDescriptionFailure(observer, error);
1023 return;
1024 }
deadbeefab9b2d12015-10-14 11:33:11 -07001025
1026 // If setting the description decided our SSL role, allocate any necessary
1027 // SCTP sids.
1028 rtc::SSLRole role;
1029 if (session_->data_channel_type() == cricket::DCT_SCTP &&
1030 session_->GetSslRole(&role)) {
1031 AllocateSctpSids(role);
1032 }
1033
1034 // Update state and SSRC of local MediaStreams and DataChannels based on the
1035 // local session description.
1036 const cricket::ContentInfo* audio_content =
1037 GetFirstAudioContent(desc->description());
1038 if (audio_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001039 if (audio_content->rejected) {
1040 RemoveTracks(cricket::MEDIA_TYPE_AUDIO);
1041 } else {
1042 const cricket::AudioContentDescription* audio_desc =
1043 static_cast<const cricket::AudioContentDescription*>(
1044 audio_content->description);
1045 UpdateLocalTracks(audio_desc->streams(), audio_desc->type());
1046 }
deadbeefab9b2d12015-10-14 11:33:11 -07001047 }
1048
1049 const cricket::ContentInfo* video_content =
1050 GetFirstVideoContent(desc->description());
1051 if (video_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001052 if (video_content->rejected) {
1053 RemoveTracks(cricket::MEDIA_TYPE_VIDEO);
1054 } else {
1055 const cricket::VideoContentDescription* video_desc =
1056 static_cast<const cricket::VideoContentDescription*>(
1057 video_content->description);
1058 UpdateLocalTracks(video_desc->streams(), video_desc->type());
1059 }
deadbeefab9b2d12015-10-14 11:33:11 -07001060 }
1061
1062 const cricket::ContentInfo* data_content =
1063 GetFirstDataContent(desc->description());
1064 if (data_content) {
1065 const cricket::DataContentDescription* data_desc =
1066 static_cast<const cricket::DataContentDescription*>(
1067 data_content->description);
1068 if (rtc::starts_with(data_desc->protocol().data(),
1069 cricket::kMediaProtocolRtpPrefix)) {
1070 UpdateLocalRtpDataChannels(data_desc->streams());
1071 }
1072 }
1073
1074 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001075 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeefab9b2d12015-10-14 11:33:11 -07001076
deadbeefcbecd352015-09-23 11:50:27 -07001077 // MaybeStartGathering needs to be called after posting
1078 // MSG_SET_SESSIONDESCRIPTION_SUCCESS, so that we don't signal any candidates
1079 // before signaling that SetLocalDescription completed.
1080 session_->MaybeStartGathering();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001081}
1082
1083void PeerConnection::SetRemoteDescription(
1084 SetSessionDescriptionObserver* observer,
1085 SessionDescriptionInterface* desc) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001086 TRACE_EVENT0("webrtc", "PeerConnection::SetRemoteDescription");
deadbeefab9b2d12015-10-14 11:33:11 -07001087 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001088 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
1089 return;
1090 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001091 if (!desc) {
1092 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
1093 return;
1094 }
1095 // Update stats here so that we have the most recent stats for tracks and
1096 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001097 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001098 std::string error;
1099 if (!session_->SetRemoteDescription(desc, &error)) {
1100 PostSetSessionDescriptionFailure(observer, error);
1101 return;
1102 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001103
deadbeefab9b2d12015-10-14 11:33:11 -07001104 // If setting the description decided our SSL role, allocate any necessary
1105 // SCTP sids.
1106 rtc::SSLRole role;
1107 if (session_->data_channel_type() == cricket::DCT_SCTP &&
1108 session_->GetSslRole(&role)) {
1109 AllocateSctpSids(role);
1110 }
1111
1112 const cricket::SessionDescription* remote_desc = desc->description();
deadbeefbda7e0b2015-12-08 17:13:40 -08001113 const cricket::ContentInfo* audio_content = GetFirstAudioContent(remote_desc);
1114 const cricket::ContentInfo* video_content = GetFirstVideoContent(remote_desc);
1115 const cricket::AudioContentDescription* audio_desc =
1116 GetFirstAudioContentDescription(remote_desc);
1117 const cricket::VideoContentDescription* video_desc =
1118 GetFirstVideoContentDescription(remote_desc);
1119 const cricket::DataContentDescription* data_desc =
1120 GetFirstDataContentDescription(remote_desc);
1121
1122 // Check if the descriptions include streams, just in case the peer supports
1123 // MSID, but doesn't indicate so with "a=msid-semantic".
1124 if (remote_desc->msid_supported() ||
1125 (audio_desc && !audio_desc->streams().empty()) ||
1126 (video_desc && !video_desc->streams().empty())) {
1127 remote_peer_supports_msid_ = true;
1128 }
deadbeefab9b2d12015-10-14 11:33:11 -07001129
1130 // We wait to signal new streams until we finish processing the description,
1131 // since only at that point will new streams have all their tracks.
1132 rtc::scoped_refptr<StreamCollection> new_streams(StreamCollection::Create());
1133
1134 // Find all audio rtp streams and create corresponding remote AudioTracks
1135 // and MediaStreams.
deadbeefab9b2d12015-10-14 11:33:11 -07001136 if (audio_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001137 if (audio_content->rejected) {
1138 RemoveTracks(cricket::MEDIA_TYPE_AUDIO);
1139 } else {
deadbeefbda7e0b2015-12-08 17:13:40 -08001140 bool default_audio_track_needed =
1141 !remote_peer_supports_msid_ &&
1142 MediaContentDirectionHasSend(audio_desc->direction());
1143 UpdateRemoteStreamsList(GetActiveStreams(audio_desc),
1144 default_audio_track_needed, audio_desc->type(),
deadbeeffaac4972015-11-12 15:33:07 -08001145 new_streams);
deadbeeffaac4972015-11-12 15:33:07 -08001146 }
deadbeefab9b2d12015-10-14 11:33:11 -07001147 }
1148
1149 // Find all video rtp streams and create corresponding remote VideoTracks
1150 // and MediaStreams.
deadbeefab9b2d12015-10-14 11:33:11 -07001151 if (video_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001152 if (video_content->rejected) {
1153 RemoveTracks(cricket::MEDIA_TYPE_VIDEO);
1154 } else {
deadbeefbda7e0b2015-12-08 17:13:40 -08001155 bool default_video_track_needed =
1156 !remote_peer_supports_msid_ &&
1157 MediaContentDirectionHasSend(video_desc->direction());
1158 UpdateRemoteStreamsList(GetActiveStreams(video_desc),
1159 default_video_track_needed, video_desc->type(),
deadbeeffaac4972015-11-12 15:33:07 -08001160 new_streams);
deadbeeffaac4972015-11-12 15:33:07 -08001161 }
deadbeefab9b2d12015-10-14 11:33:11 -07001162 }
1163
1164 // Update the DataChannels with the information from the remote peer.
deadbeefbda7e0b2015-12-08 17:13:40 -08001165 if (data_desc) {
1166 if (rtc::starts_with(data_desc->protocol().data(),
deadbeefab9b2d12015-10-14 11:33:11 -07001167 cricket::kMediaProtocolRtpPrefix)) {
deadbeefbda7e0b2015-12-08 17:13:40 -08001168 UpdateRemoteRtpDataChannels(GetActiveStreams(data_desc));
deadbeefab9b2d12015-10-14 11:33:11 -07001169 }
1170 }
1171
1172 // Iterate new_streams and notify the observer about new MediaStreams.
1173 for (size_t i = 0; i < new_streams->count(); ++i) {
1174 MediaStreamInterface* new_stream = new_streams->at(i);
1175 stats_->AddStream(new_stream);
1176 observer_->OnAddStream(new_stream);
1177 }
1178
deadbeefbda7e0b2015-12-08 17:13:40 -08001179 UpdateEndedRemoteMediaStreams();
deadbeefab9b2d12015-10-14 11:33:11 -07001180
1181 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1182 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeeffc648b62015-10-13 16:42:33 -07001183}
1184
deadbeefa67696b2015-09-29 11:56:26 -07001185bool PeerConnection::SetConfiguration(const RTCConfiguration& config) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001186 TRACE_EVENT0("webrtc", "PeerConnection::SetConfiguration");
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001187 if (port_allocator_) {
1188 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
1189 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
1190 if (!ParseIceServers(config.servers, &stuns, &turns)) {
1191 return false;
1192 }
1193
deadbeef653b8e02015-11-11 12:55:10 -08001194 cricket::ServerAddresses cricket_stuns;
1195 std::vector<cricket::RelayServerConfig> cricket_turns;
1196 ConvertToCricketIceServers(stuns, turns, &cricket_stuns, &cricket_turns);
1197 port_allocator_->SetIceServers(cricket_stuns, cricket_turns);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001198 }
honghaiz1f429e32015-09-28 07:57:34 -07001199 session_->SetIceConfig(session_->ParseIceConfig(config));
mallinath@webrtc.org3d81b1b2014-09-09 14:38:10 +00001200 return session_->SetIceTransports(config.type);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001201}
1202
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001203bool PeerConnection::AddIceCandidate(
1204 const IceCandidateInterface* ice_candidate) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001205 TRACE_EVENT0("webrtc", "PeerConnection::AddIceCandidate");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001206 return session_->ProcessIceMessage(ice_candidate);
1207}
1208
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001209void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001210 TRACE_EVENT0("webrtc", "PeerConnection::RegisterUmaObserver");
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001211 uma_observer_ = observer;
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +00001212
1213 if (session_) {
1214 session_->set_metrics_observer(uma_observer_);
1215 }
1216
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001217 // Send information about IPv4/IPv6 status.
1218 if (uma_observer_ && port_allocator_) {
1219 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001220 uma_observer_->IncrementEnumCounter(
1221 kEnumCounterAddressFamily, kPeerConnection_IPv6,
1222 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgb445f262014-05-23 22:19:37 +00001223 } else {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001224 uma_observer_->IncrementEnumCounter(
1225 kEnumCounterAddressFamily, kPeerConnection_IPv4,
1226 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001227 }
1228 }
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001229}
1230
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001231const SessionDescriptionInterface* PeerConnection::local_description() const {
1232 return session_->local_description();
1233}
1234
1235const SessionDescriptionInterface* PeerConnection::remote_description() const {
1236 return session_->remote_description();
1237}
1238
1239void PeerConnection::Close() {
Peter Boström1a9d6152015-12-08 22:15:17 +01001240 TRACE_EVENT0("webrtc", "PeerConnection::Close");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001241 // Update stats here so that we have the most recent stats for tracks and
1242 // streams before the channels are closed.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001243 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001244
deadbeefd59daf82015-10-14 15:02:44 -07001245 session_->Close();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001246}
1247
deadbeefd59daf82015-10-14 15:02:44 -07001248void PeerConnection::OnSessionStateChange(WebRtcSession* /*session*/,
1249 WebRtcSession::State state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001250 switch (state) {
deadbeefd59daf82015-10-14 15:02:44 -07001251 case WebRtcSession::STATE_INIT:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001252 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001253 break;
deadbeefd59daf82015-10-14 15:02:44 -07001254 case WebRtcSession::STATE_SENTOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001255 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
1256 break;
deadbeefd59daf82015-10-14 15:02:44 -07001257 case WebRtcSession::STATE_SENTPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001258 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
1259 break;
deadbeefd59daf82015-10-14 15:02:44 -07001260 case WebRtcSession::STATE_RECEIVEDOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001261 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
1262 break;
deadbeefd59daf82015-10-14 15:02:44 -07001263 case WebRtcSession::STATE_RECEIVEDPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001264 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
1265 break;
deadbeefd59daf82015-10-14 15:02:44 -07001266 case WebRtcSession::STATE_INPROGRESS:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001267 ChangeSignalingState(PeerConnectionInterface::kStable);
1268 break;
deadbeefd59daf82015-10-14 15:02:44 -07001269 case WebRtcSession::STATE_CLOSED:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001270 ChangeSignalingState(PeerConnectionInterface::kClosed);
1271 break;
1272 default:
1273 break;
1274 }
1275}
1276
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001277void PeerConnection::OnMessage(rtc::Message* msg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001278 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001279 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
1280 SetSessionDescriptionMsg* param =
1281 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1282 param->observer->OnSuccess();
1283 delete param;
1284 break;
1285 }
1286 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
1287 SetSessionDescriptionMsg* param =
1288 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1289 param->observer->OnFailure(param->error);
1290 delete param;
1291 break;
1292 }
deadbeefab9b2d12015-10-14 11:33:11 -07001293 case MSG_CREATE_SESSIONDESCRIPTION_FAILED: {
1294 CreateSessionDescriptionMsg* param =
1295 static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
1296 param->observer->OnFailure(param->error);
1297 delete param;
1298 break;
1299 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001300 case MSG_GETSTATS: {
1301 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +00001302 StatsReports reports;
1303 stats_->GetStats(param->track, &reports);
1304 param->observer->OnComplete(reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001305 delete param;
1306 break;
1307 }
deadbeefbd292462015-12-14 18:15:29 -08001308 case MSG_FREE_DATACHANNELS: {
1309 sctp_data_channels_to_free_.clear();
1310 break;
1311 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001312 default:
deadbeef0a6c4ca2015-10-06 11:38:28 -07001313 RTC_DCHECK(false && "Not implemented");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001314 break;
1315 }
1316}
1317
deadbeefab9b2d12015-10-14 11:33:11 -07001318void PeerConnection::CreateAudioReceiver(MediaStreamInterface* stream,
1319 AudioTrackInterface* audio_track,
1320 uint32_t ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -07001321 receivers_.push_back(new AudioRtpReceiver(audio_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001322}
1323
deadbeefab9b2d12015-10-14 11:33:11 -07001324void PeerConnection::CreateVideoReceiver(MediaStreamInterface* stream,
1325 VideoTrackInterface* video_track,
1326 uint32_t ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -07001327 receivers_.push_back(new VideoRtpReceiver(video_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001328}
1329
deadbeef70ab1a12015-09-28 16:53:55 -07001330// TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote
1331// description.
deadbeefab9b2d12015-10-14 11:33:11 -07001332void PeerConnection::DestroyAudioReceiver(MediaStreamInterface* stream,
1333 AudioTrackInterface* audio_track) {
deadbeef70ab1a12015-09-28 16:53:55 -07001334 auto it = FindReceiverForTrack(audio_track);
1335 if (it == receivers_.end()) {
1336 LOG(LS_WARNING) << "RtpReceiver for track with id " << audio_track->id()
1337 << " doesn't exist.";
1338 } else {
1339 (*it)->Stop();
1340 receivers_.erase(it);
1341 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001342}
1343
deadbeefab9b2d12015-10-14 11:33:11 -07001344void PeerConnection::DestroyVideoReceiver(MediaStreamInterface* stream,
1345 VideoTrackInterface* video_track) {
deadbeef70ab1a12015-09-28 16:53:55 -07001346 auto it = FindReceiverForTrack(video_track);
1347 if (it == receivers_.end()) {
1348 LOG(LS_WARNING) << "RtpReceiver for track with id " << video_track->id()
1349 << " doesn't exist.";
1350 } else {
1351 (*it)->Stop();
1352 receivers_.erase(it);
1353 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001354}
deadbeef70ab1a12015-09-28 16:53:55 -07001355
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001356void PeerConnection::OnIceConnectionChange(
1357 PeerConnectionInterface::IceConnectionState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001358 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefcbecd352015-09-23 11:50:27 -07001359 // After transitioning to "closed", ignore any additional states from
1360 // WebRtcSession (such as "disconnected").
deadbeefab9b2d12015-10-14 11:33:11 -07001361 if (IsClosed()) {
deadbeefcbecd352015-09-23 11:50:27 -07001362 return;
1363 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001364 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001365 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001366}
1367
1368void PeerConnection::OnIceGatheringChange(
1369 PeerConnectionInterface::IceGatheringState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001370 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001371 if (IsClosed()) {
1372 return;
1373 }
1374 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001375 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001376}
1377
1378void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001379 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001380 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001381}
1382
1383void PeerConnection::OnIceComplete() {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001384 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001385 observer_->OnIceComplete();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001386}
1387
Peter Thatcher54360512015-07-08 11:08:35 -07001388void PeerConnection::OnIceConnectionReceivingChange(bool receiving) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001389 RTC_DCHECK(signaling_thread()->IsCurrent());
Peter Thatcher54360512015-07-08 11:08:35 -07001390 observer_->OnIceConnectionReceivingChange(receiving);
1391}
1392
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001393void PeerConnection::ChangeSignalingState(
1394 PeerConnectionInterface::SignalingState signaling_state) {
1395 signaling_state_ = signaling_state;
1396 if (signaling_state == kClosed) {
1397 ice_connection_state_ = kIceConnectionClosed;
1398 observer_->OnIceConnectionChange(ice_connection_state_);
1399 if (ice_gathering_state_ != kIceGatheringComplete) {
1400 ice_gathering_state_ = kIceGatheringComplete;
1401 observer_->OnIceGatheringChange(ice_gathering_state_);
1402 }
1403 }
1404 observer_->OnSignalingChange(signaling_state_);
1405 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
1406}
1407
deadbeefeb459812015-12-15 19:24:43 -08001408void PeerConnection::OnAudioTrackAdded(AudioTrackInterface* track,
1409 MediaStreamInterface* stream) {
1410 auto sender = FindSenderForTrack(track);
1411 if (sender != senders_.end()) {
1412 // We already have a sender for this track, so just change the stream_id
1413 // so that it's correct in the next call to CreateOffer.
1414 (*sender)->set_stream_id(stream->label());
1415 return;
1416 }
1417
1418 // Normal case; we've never seen this track before.
1419 AudioRtpSender* new_sender =
1420 new AudioRtpSender(track, stream->label(), session_.get(), stats_.get());
1421 senders_.push_back(new_sender);
1422 // If the sender has already been configured in SDP, we call SetSsrc,
1423 // which will connect the sender to the underlying transport. This can
1424 // occur if a local session description that contains the ID of the sender
1425 // is set before AddStream is called. It can also occur if the local
1426 // session description is not changed and RemoveStream is called, and
1427 // later AddStream is called again with the same stream.
1428 const TrackInfo* track_info =
1429 FindTrackInfo(local_audio_tracks_, stream->label(), track->id());
1430 if (track_info) {
1431 new_sender->SetSsrc(track_info->ssrc);
1432 }
1433}
1434
1435// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around
1436// indefinitely, when we have unified plan SDP.
1437void PeerConnection::OnAudioTrackRemoved(AudioTrackInterface* track,
1438 MediaStreamInterface* stream) {
1439 auto sender = FindSenderForTrack(track);
1440 if (sender == senders_.end()) {
1441 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
1442 << " doesn't exist.";
1443 return;
1444 }
1445 (*sender)->Stop();
1446 senders_.erase(sender);
1447}
1448
1449void PeerConnection::OnVideoTrackAdded(VideoTrackInterface* track,
1450 MediaStreamInterface* stream) {
1451 auto sender = FindSenderForTrack(track);
1452 if (sender != senders_.end()) {
1453 // We already have a sender for this track, so just change the stream_id
1454 // so that it's correct in the next call to CreateOffer.
1455 (*sender)->set_stream_id(stream->label());
1456 return;
1457 }
1458
1459 // Normal case; we've never seen this track before.
1460 VideoRtpSender* new_sender =
1461 new VideoRtpSender(track, stream->label(), session_.get());
1462 senders_.push_back(new_sender);
1463 const TrackInfo* track_info =
1464 FindTrackInfo(local_video_tracks_, stream->label(), track->id());
1465 if (track_info) {
1466 new_sender->SetSsrc(track_info->ssrc);
1467 }
1468}
1469
1470void PeerConnection::OnVideoTrackRemoved(VideoTrackInterface* track,
1471 MediaStreamInterface* stream) {
1472 auto sender = FindSenderForTrack(track);
1473 if (sender == senders_.end()) {
1474 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
1475 << " doesn't exist.";
1476 return;
1477 }
1478 (*sender)->Stop();
1479 senders_.erase(sender);
1480}
1481
deadbeefab9b2d12015-10-14 11:33:11 -07001482void PeerConnection::PostSetSessionDescriptionFailure(
1483 SetSessionDescriptionObserver* observer,
1484 const std::string& error) {
1485 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1486 msg->error = error;
1487 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
1488}
1489
1490void PeerConnection::PostCreateSessionDescriptionFailure(
1491 CreateSessionDescriptionObserver* observer,
1492 const std::string& error) {
1493 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
1494 msg->error = error;
1495 signaling_thread()->Post(this, MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
1496}
1497
1498bool PeerConnection::GetOptionsForOffer(
1499 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
1500 cricket::MediaSessionOptions* session_options) {
deadbeefab9b2d12015-10-14 11:33:11 -07001501 if (!ConvertRtcOptionsForOffer(rtc_options, session_options)) {
1502 return false;
1503 }
1504
deadbeeffac06552015-11-25 11:26:01 -08001505 AddSendStreams(session_options, senders_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001506 // Offer to receive audio/video if the constraint is not set and there are
1507 // send streams, or we're currently receiving.
1508 if (rtc_options.offer_to_receive_audio == RTCOfferAnswerOptions::kUndefined) {
1509 session_options->recv_audio =
1510 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_AUDIO) ||
1511 !remote_audio_tracks_.empty();
1512 }
1513 if (rtc_options.offer_to_receive_video == RTCOfferAnswerOptions::kUndefined) {
1514 session_options->recv_video =
1515 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_VIDEO) ||
1516 !remote_video_tracks_.empty();
1517 }
1518 session_options->bundle_enabled =
1519 session_options->bundle_enabled &&
1520 (session_options->has_audio() || session_options->has_video() ||
1521 session_options->has_data());
1522
deadbeefab9b2d12015-10-14 11:33:11 -07001523 if (session_->data_channel_type() == cricket::DCT_SCTP && HasDataChannels()) {
1524 session_options->data_channel_type = cricket::DCT_SCTP;
1525 }
1526 return true;
1527}
1528
1529bool PeerConnection::GetOptionsForAnswer(
1530 const MediaConstraintsInterface* constraints,
1531 cricket::MediaSessionOptions* session_options) {
deadbeefab9b2d12015-10-14 11:33:11 -07001532 session_options->recv_audio = false;
1533 session_options->recv_video = false;
deadbeefab9b2d12015-10-14 11:33:11 -07001534 if (!ParseConstraintsForAnswer(constraints, session_options)) {
1535 return false;
1536 }
1537
deadbeeffac06552015-11-25 11:26:01 -08001538 AddSendStreams(session_options, senders_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001539 session_options->bundle_enabled =
1540 session_options->bundle_enabled &&
1541 (session_options->has_audio() || session_options->has_video() ||
1542 session_options->has_data());
1543
deadbeefab9b2d12015-10-14 11:33:11 -07001544 // RTP data channel is handled in MediaSessionOptions::AddStream. SCTP streams
1545 // are not signaled in the SDP so does not go through that path and must be
1546 // handled here.
1547 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1548 session_options->data_channel_type = cricket::DCT_SCTP;
1549 }
1550 return true;
1551}
1552
deadbeeffaac4972015-11-12 15:33:07 -08001553void PeerConnection::RemoveTracks(cricket::MediaType media_type) {
1554 UpdateLocalTracks(std::vector<cricket::StreamParams>(), media_type);
deadbeefbda7e0b2015-12-08 17:13:40 -08001555 UpdateRemoteStreamsList(std::vector<cricket::StreamParams>(), false,
1556 media_type, nullptr);
deadbeeffaac4972015-11-12 15:33:07 -08001557}
1558
deadbeefab9b2d12015-10-14 11:33:11 -07001559void PeerConnection::UpdateRemoteStreamsList(
1560 const cricket::StreamParamsVec& streams,
deadbeefbda7e0b2015-12-08 17:13:40 -08001561 bool default_track_needed,
deadbeefab9b2d12015-10-14 11:33:11 -07001562 cricket::MediaType media_type,
1563 StreamCollection* new_streams) {
1564 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1565
1566 // Find removed tracks. I.e., tracks where the track id or ssrc don't match
deadbeeffac06552015-11-25 11:26:01 -08001567 // the new StreamParam.
deadbeefab9b2d12015-10-14 11:33:11 -07001568 auto track_it = current_tracks->begin();
1569 while (track_it != current_tracks->end()) {
1570 const TrackInfo& info = *track_it;
1571 const cricket::StreamParams* params =
1572 cricket::GetStreamBySsrc(streams, info.ssrc);
deadbeefbda7e0b2015-12-08 17:13:40 -08001573 bool track_exists = params && params->id == info.track_id;
1574 // If this is a default track, and we still need it, don't remove it.
1575 if ((info.stream_label == kDefaultStreamLabel && default_track_needed) ||
1576 track_exists) {
1577 ++track_it;
1578 } else {
deadbeefab9b2d12015-10-14 11:33:11 -07001579 OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
1580 track_it = current_tracks->erase(track_it);
deadbeefab9b2d12015-10-14 11:33:11 -07001581 }
1582 }
1583
1584 // Find new and active tracks.
1585 for (const cricket::StreamParams& params : streams) {
1586 // The sync_label is the MediaStream label and the |stream.id| is the
1587 // track id.
1588 const std::string& stream_label = params.sync_label;
1589 const std::string& track_id = params.id;
1590 uint32_t ssrc = params.first_ssrc();
1591
1592 rtc::scoped_refptr<MediaStreamInterface> stream =
1593 remote_streams_->find(stream_label);
1594 if (!stream) {
1595 // This is a new MediaStream. Create a new remote MediaStream.
1596 stream = remote_stream_factory_->CreateMediaStream(stream_label);
1597 remote_streams_->AddStream(stream);
1598 new_streams->AddStream(stream);
1599 }
1600
1601 const TrackInfo* track_info =
1602 FindTrackInfo(*current_tracks, stream_label, track_id);
1603 if (!track_info) {
1604 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1605 OnRemoteTrackSeen(stream_label, track_id, ssrc, media_type);
1606 }
1607 }
deadbeefbda7e0b2015-12-08 17:13:40 -08001608
1609 // Add default track if necessary.
1610 if (default_track_needed) {
1611 rtc::scoped_refptr<MediaStreamInterface> default_stream =
1612 remote_streams_->find(kDefaultStreamLabel);
1613 if (!default_stream) {
1614 // Create the new default MediaStream.
1615 default_stream =
1616 remote_stream_factory_->CreateMediaStream(kDefaultStreamLabel);
1617 remote_streams_->AddStream(default_stream);
1618 new_streams->AddStream(default_stream);
1619 }
1620 std::string default_track_id = (media_type == cricket::MEDIA_TYPE_AUDIO)
1621 ? kDefaultAudioTrackLabel
1622 : kDefaultVideoTrackLabel;
1623 const TrackInfo* default_track_info =
1624 FindTrackInfo(*current_tracks, kDefaultStreamLabel, default_track_id);
1625 if (!default_track_info) {
1626 current_tracks->push_back(
1627 TrackInfo(kDefaultStreamLabel, default_track_id, 0));
1628 OnRemoteTrackSeen(kDefaultStreamLabel, default_track_id, 0, media_type);
1629 }
1630 }
deadbeefab9b2d12015-10-14 11:33:11 -07001631}
1632
1633void PeerConnection::OnRemoteTrackSeen(const std::string& stream_label,
1634 const std::string& track_id,
1635 uint32_t ssrc,
1636 cricket::MediaType media_type) {
1637 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1638
1639 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
Tommif888bb52015-12-12 01:37:01 +01001640 AudioTrackInterface* audio_track = remote_stream_factory_->AddAudioTrack(
1641 ssrc, session_.get(), stream, track_id);
deadbeefab9b2d12015-10-14 11:33:11 -07001642 CreateAudioReceiver(stream, audio_track, ssrc);
1643 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1644 VideoTrackInterface* video_track =
1645 remote_stream_factory_->AddVideoTrack(stream, track_id);
1646 CreateVideoReceiver(stream, video_track, ssrc);
1647 } else {
1648 RTC_DCHECK(false && "Invalid media type");
1649 }
1650}
1651
1652void PeerConnection::OnRemoteTrackRemoved(const std::string& stream_label,
1653 const std::string& track_id,
1654 cricket::MediaType media_type) {
1655 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1656
1657 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1658 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1659 stream->FindAudioTrack(track_id);
1660 if (audio_track) {
1661 audio_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1662 stream->RemoveTrack(audio_track);
1663 DestroyAudioReceiver(stream, audio_track);
1664 }
1665 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1666 rtc::scoped_refptr<VideoTrackInterface> video_track =
1667 stream->FindVideoTrack(track_id);
1668 if (video_track) {
1669 video_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1670 stream->RemoveTrack(video_track);
1671 DestroyVideoReceiver(stream, video_track);
1672 }
1673 } else {
1674 ASSERT(false && "Invalid media type");
1675 }
1676}
1677
1678void PeerConnection::UpdateEndedRemoteMediaStreams() {
1679 std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams_to_remove;
1680 for (size_t i = 0; i < remote_streams_->count(); ++i) {
1681 MediaStreamInterface* stream = remote_streams_->at(i);
1682 if (stream->GetAudioTracks().empty() && stream->GetVideoTracks().empty()) {
1683 streams_to_remove.push_back(stream);
1684 }
1685 }
1686
1687 for (const auto& stream : streams_to_remove) {
1688 remote_streams_->RemoveStream(stream);
1689 observer_->OnRemoveStream(stream);
1690 }
1691}
1692
deadbeefab9b2d12015-10-14 11:33:11 -07001693void PeerConnection::EndRemoteTracks(cricket::MediaType media_type) {
1694 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1695 for (TrackInfos::iterator track_it = current_tracks->begin();
1696 track_it != current_tracks->end(); ++track_it) {
1697 const TrackInfo& info = *track_it;
1698 MediaStreamInterface* stream = remote_streams_->find(info.stream_label);
1699 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1700 AudioTrackInterface* track = stream->FindAudioTrack(info.track_id);
1701 // There's no guarantee the track is still available, e.g. the track may
1702 // have been removed from the stream by javascript.
1703 if (track) {
1704 track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1705 }
1706 }
1707 if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1708 VideoTrackInterface* track = stream->FindVideoTrack(info.track_id);
1709 // There's no guarantee the track is still available, e.g. the track may
1710 // have been removed from the stream by javascript.
1711 if (track) {
1712 track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1713 }
1714 }
1715 }
1716}
1717
1718void PeerConnection::UpdateLocalTracks(
1719 const std::vector<cricket::StreamParams>& streams,
1720 cricket::MediaType media_type) {
1721 TrackInfos* current_tracks = GetLocalTracks(media_type);
1722
1723 // Find removed tracks. I.e., tracks where the track id, stream label or ssrc
1724 // don't match the new StreamParam.
1725 TrackInfos::iterator track_it = current_tracks->begin();
1726 while (track_it != current_tracks->end()) {
1727 const TrackInfo& info = *track_it;
1728 const cricket::StreamParams* params =
1729 cricket::GetStreamBySsrc(streams, info.ssrc);
1730 if (!params || params->id != info.track_id ||
1731 params->sync_label != info.stream_label) {
1732 OnLocalTrackRemoved(info.stream_label, info.track_id, info.ssrc,
1733 media_type);
1734 track_it = current_tracks->erase(track_it);
1735 } else {
1736 ++track_it;
1737 }
1738 }
1739
1740 // Find new and active tracks.
1741 for (const cricket::StreamParams& params : streams) {
1742 // The sync_label is the MediaStream label and the |stream.id| is the
1743 // track id.
1744 const std::string& stream_label = params.sync_label;
1745 const std::string& track_id = params.id;
1746 uint32_t ssrc = params.first_ssrc();
1747 const TrackInfo* track_info =
1748 FindTrackInfo(*current_tracks, stream_label, track_id);
1749 if (!track_info) {
1750 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1751 OnLocalTrackSeen(stream_label, track_id, params.first_ssrc(), media_type);
1752 }
1753 }
1754}
1755
1756void PeerConnection::OnLocalTrackSeen(const std::string& stream_label,
1757 const std::string& track_id,
1758 uint32_t ssrc,
1759 cricket::MediaType media_type) {
deadbeeffac06552015-11-25 11:26:01 -08001760 RtpSenderInterface* sender = FindSenderById(track_id);
1761 if (!sender) {
1762 LOG(LS_WARNING) << "An unknown RtpSender with id " << track_id
1763 << " has been configured in the local description.";
deadbeefab9b2d12015-10-14 11:33:11 -07001764 return;
1765 }
1766
deadbeeffac06552015-11-25 11:26:01 -08001767 if (sender->media_type() != media_type) {
1768 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
1769 << " description with an unexpected media type.";
1770 return;
deadbeefab9b2d12015-10-14 11:33:11 -07001771 }
deadbeeffac06552015-11-25 11:26:01 -08001772
1773 sender->set_stream_id(stream_label);
1774 sender->SetSsrc(ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -07001775}
1776
1777void PeerConnection::OnLocalTrackRemoved(const std::string& stream_label,
1778 const std::string& track_id,
1779 uint32_t ssrc,
1780 cricket::MediaType media_type) {
deadbeeffac06552015-11-25 11:26:01 -08001781 RtpSenderInterface* sender = FindSenderById(track_id);
1782 if (!sender) {
1783 // This is the normal case. I.e., RemoveStream has been called and the
deadbeefab9b2d12015-10-14 11:33:11 -07001784 // SessionDescriptions has been renegotiated.
1785 return;
1786 }
deadbeeffac06552015-11-25 11:26:01 -08001787
1788 // A sender has been removed from the SessionDescription but it's still
1789 // associated with the PeerConnection. This only occurs if the SDP doesn't
1790 // match with the calls to CreateSender, AddStream and RemoveStream.
1791 if (sender->media_type() != media_type) {
1792 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
1793 << " description with an unexpected media type.";
1794 return;
deadbeefab9b2d12015-10-14 11:33:11 -07001795 }
deadbeeffac06552015-11-25 11:26:01 -08001796
1797 sender->SetSsrc(0);
deadbeefab9b2d12015-10-14 11:33:11 -07001798}
1799
1800void PeerConnection::UpdateLocalRtpDataChannels(
1801 const cricket::StreamParamsVec& streams) {
1802 std::vector<std::string> existing_channels;
1803
1804 // Find new and active data channels.
1805 for (const cricket::StreamParams& params : streams) {
1806 // |it->sync_label| is actually the data channel label. The reason is that
1807 // we use the same naming of data channels as we do for
1808 // MediaStreams and Tracks.
1809 // For MediaStreams, the sync_label is the MediaStream label and the
1810 // track label is the same as |streamid|.
1811 const std::string& channel_label = params.sync_label;
1812 auto data_channel_it = rtp_data_channels_.find(channel_label);
1813 if (!VERIFY(data_channel_it != rtp_data_channels_.end())) {
1814 continue;
1815 }
1816 // Set the SSRC the data channel should use for sending.
1817 data_channel_it->second->SetSendSsrc(params.first_ssrc());
1818 existing_channels.push_back(data_channel_it->first);
1819 }
1820
1821 UpdateClosingRtpDataChannels(existing_channels, true);
1822}
1823
1824void PeerConnection::UpdateRemoteRtpDataChannels(
1825 const cricket::StreamParamsVec& streams) {
1826 std::vector<std::string> existing_channels;
1827
1828 // Find new and active data channels.
1829 for (const cricket::StreamParams& params : streams) {
1830 // The data channel label is either the mslabel or the SSRC if the mslabel
1831 // does not exist. Ex a=ssrc:444330170 mslabel:test1.
1832 std::string label = params.sync_label.empty()
1833 ? rtc::ToString(params.first_ssrc())
1834 : params.sync_label;
1835 auto data_channel_it = rtp_data_channels_.find(label);
1836 if (data_channel_it == rtp_data_channels_.end()) {
1837 // This is a new data channel.
1838 CreateRemoteRtpDataChannel(label, params.first_ssrc());
1839 } else {
1840 data_channel_it->second->SetReceiveSsrc(params.first_ssrc());
1841 }
1842 existing_channels.push_back(label);
1843 }
1844
1845 UpdateClosingRtpDataChannels(existing_channels, false);
1846}
1847
1848void PeerConnection::UpdateClosingRtpDataChannels(
1849 const std::vector<std::string>& active_channels,
1850 bool is_local_update) {
1851 auto it = rtp_data_channels_.begin();
1852 while (it != rtp_data_channels_.end()) {
1853 DataChannel* data_channel = it->second;
1854 if (std::find(active_channels.begin(), active_channels.end(),
1855 data_channel->label()) != active_channels.end()) {
1856 ++it;
1857 continue;
1858 }
1859
1860 if (is_local_update) {
1861 data_channel->SetSendSsrc(0);
1862 } else {
1863 data_channel->RemotePeerRequestClose();
1864 }
1865
1866 if (data_channel->state() == DataChannel::kClosed) {
1867 rtp_data_channels_.erase(it);
1868 it = rtp_data_channels_.begin();
1869 } else {
1870 ++it;
1871 }
1872 }
1873}
1874
1875void PeerConnection::CreateRemoteRtpDataChannel(const std::string& label,
1876 uint32_t remote_ssrc) {
1877 rtc::scoped_refptr<DataChannel> channel(
1878 InternalCreateDataChannel(label, nullptr));
1879 if (!channel.get()) {
1880 LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
1881 << "CreateDataChannel failed.";
1882 return;
1883 }
1884 channel->SetReceiveSsrc(remote_ssrc);
1885 observer_->OnDataChannel(
1886 DataChannelProxy::Create(signaling_thread(), channel));
1887}
1888
1889rtc::scoped_refptr<DataChannel> PeerConnection::InternalCreateDataChannel(
1890 const std::string& label,
1891 const InternalDataChannelInit* config) {
1892 if (IsClosed()) {
1893 return nullptr;
1894 }
1895 if (session_->data_channel_type() == cricket::DCT_NONE) {
1896 LOG(LS_ERROR)
1897 << "InternalCreateDataChannel: Data is not supported in this call.";
1898 return nullptr;
1899 }
1900 InternalDataChannelInit new_config =
1901 config ? (*config) : InternalDataChannelInit();
1902 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1903 if (new_config.id < 0) {
1904 rtc::SSLRole role;
1905 if (session_->GetSslRole(&role) &&
1906 !sid_allocator_.AllocateSid(role, &new_config.id)) {
1907 LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel.";
1908 return nullptr;
1909 }
1910 } else if (!sid_allocator_.ReserveSid(new_config.id)) {
1911 LOG(LS_ERROR) << "Failed to create a SCTP data channel "
1912 << "because the id is already in use or out of range.";
1913 return nullptr;
1914 }
1915 }
1916
1917 rtc::scoped_refptr<DataChannel> channel(DataChannel::Create(
1918 session_.get(), session_->data_channel_type(), label, new_config));
1919 if (!channel) {
1920 sid_allocator_.ReleaseSid(new_config.id);
1921 return nullptr;
1922 }
1923
1924 if (channel->data_channel_type() == cricket::DCT_RTP) {
1925 if (rtp_data_channels_.find(channel->label()) != rtp_data_channels_.end()) {
1926 LOG(LS_ERROR) << "DataChannel with label " << channel->label()
1927 << " already exists.";
1928 return nullptr;
1929 }
1930 rtp_data_channels_[channel->label()] = channel;
1931 } else {
1932 RTC_DCHECK(channel->data_channel_type() == cricket::DCT_SCTP);
1933 sctp_data_channels_.push_back(channel);
1934 channel->SignalClosed.connect(this,
1935 &PeerConnection::OnSctpDataChannelClosed);
1936 }
1937
1938 return channel;
1939}
1940
1941bool PeerConnection::HasDataChannels() const {
1942 return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
1943}
1944
1945void PeerConnection::AllocateSctpSids(rtc::SSLRole role) {
1946 for (const auto& channel : sctp_data_channels_) {
1947 if (channel->id() < 0) {
1948 int sid;
1949 if (!sid_allocator_.AllocateSid(role, &sid)) {
1950 LOG(LS_ERROR) << "Failed to allocate SCTP sid.";
1951 continue;
1952 }
1953 channel->SetSctpSid(sid);
1954 }
1955 }
1956}
1957
1958void PeerConnection::OnSctpDataChannelClosed(DataChannel* channel) {
deadbeefbd292462015-12-14 18:15:29 -08001959 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefab9b2d12015-10-14 11:33:11 -07001960 for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end();
1961 ++it) {
1962 if (it->get() == channel) {
1963 if (channel->id() >= 0) {
1964 sid_allocator_.ReleaseSid(channel->id());
1965 }
deadbeefbd292462015-12-14 18:15:29 -08001966 // Since this method is triggered by a signal from the DataChannel,
1967 // we can't free it directly here; we need to free it asynchronously.
1968 sctp_data_channels_to_free_.push_back(*it);
deadbeefab9b2d12015-10-14 11:33:11 -07001969 sctp_data_channels_.erase(it);
deadbeefbd292462015-12-14 18:15:29 -08001970 signaling_thread()->Post(this, MSG_FREE_DATACHANNELS, nullptr);
deadbeefab9b2d12015-10-14 11:33:11 -07001971 return;
1972 }
1973 }
1974}
1975
1976void PeerConnection::OnVoiceChannelDestroyed() {
1977 EndRemoteTracks(cricket::MEDIA_TYPE_AUDIO);
1978}
1979
1980void PeerConnection::OnVideoChannelDestroyed() {
1981 EndRemoteTracks(cricket::MEDIA_TYPE_VIDEO);
1982}
1983
1984void PeerConnection::OnDataChannelCreated() {
1985 for (const auto& channel : sctp_data_channels_) {
1986 channel->OnTransportChannelCreated();
1987 }
1988}
1989
1990void PeerConnection::OnDataChannelDestroyed() {
1991 // Use a temporary copy of the RTP/SCTP DataChannel list because the
1992 // DataChannel may callback to us and try to modify the list.
1993 std::map<std::string, rtc::scoped_refptr<DataChannel>> temp_rtp_dcs;
1994 temp_rtp_dcs.swap(rtp_data_channels_);
1995 for (const auto& kv : temp_rtp_dcs) {
1996 kv.second->OnTransportChannelDestroyed();
1997 }
1998
1999 std::vector<rtc::scoped_refptr<DataChannel>> temp_sctp_dcs;
2000 temp_sctp_dcs.swap(sctp_data_channels_);
2001 for (const auto& channel : temp_sctp_dcs) {
2002 channel->OnTransportChannelDestroyed();
2003 }
2004}
2005
2006void PeerConnection::OnDataChannelOpenMessage(
2007 const std::string& label,
2008 const InternalDataChannelInit& config) {
2009 rtc::scoped_refptr<DataChannel> channel(
2010 InternalCreateDataChannel(label, &config));
2011 if (!channel.get()) {
2012 LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
2013 return;
2014 }
2015
2016 observer_->OnDataChannel(
2017 DataChannelProxy::Create(signaling_thread(), channel));
2018}
2019
deadbeeffac06552015-11-25 11:26:01 -08002020RtpSenderInterface* PeerConnection::FindSenderById(const std::string& id) {
2021 auto it =
2022 std::find_if(senders_.begin(), senders_.end(),
2023 [id](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
2024 return sender->id() == id;
2025 });
2026 return it != senders_.end() ? it->get() : nullptr;
2027}
2028
deadbeef70ab1a12015-09-28 16:53:55 -07002029std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator
2030PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) {
2031 return std::find_if(
2032 senders_.begin(), senders_.end(),
2033 [track](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
2034 return sender->track() == track;
2035 });
2036}
2037
2038std::vector<rtc::scoped_refptr<RtpReceiverInterface>>::iterator
2039PeerConnection::FindReceiverForTrack(MediaStreamTrackInterface* track) {
2040 return std::find_if(
2041 receivers_.begin(), receivers_.end(),
2042 [track](const rtc::scoped_refptr<RtpReceiverInterface>& receiver) {
2043 return receiver->track() == track;
2044 });
2045}
2046
deadbeefab9b2d12015-10-14 11:33:11 -07002047PeerConnection::TrackInfos* PeerConnection::GetRemoteTracks(
2048 cricket::MediaType media_type) {
2049 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
2050 media_type == cricket::MEDIA_TYPE_VIDEO);
2051 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &remote_audio_tracks_
2052 : &remote_video_tracks_;
2053}
2054
2055PeerConnection::TrackInfos* PeerConnection::GetLocalTracks(
2056 cricket::MediaType media_type) {
2057 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
2058 media_type == cricket::MEDIA_TYPE_VIDEO);
2059 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &local_audio_tracks_
2060 : &local_video_tracks_;
2061}
2062
2063const PeerConnection::TrackInfo* PeerConnection::FindTrackInfo(
2064 const PeerConnection::TrackInfos& infos,
2065 const std::string& stream_label,
2066 const std::string track_id) const {
2067 for (const TrackInfo& track_info : infos) {
2068 if (track_info.stream_label == stream_label &&
2069 track_info.track_id == track_id) {
2070 return &track_info;
2071 }
2072 }
2073 return nullptr;
2074}
2075
2076DataChannel* PeerConnection::FindDataChannelBySid(int sid) const {
2077 for (const auto& channel : sctp_data_channels_) {
2078 if (channel->id() == sid) {
2079 return channel;
2080 }
2081 }
2082 return nullptr;
2083}
2084
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002085} // namespace webrtc