blob: 83380e17b52dfe7e64b8d028ecbde7fe4b43a518 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
jlmiller@webrtc.org5f93d0a2015-01-20 21:36:13 +00003 * Copyright 2012 Google Inc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "talk/app/webrtc/peerconnection.h"
29
30#include <vector>
deadbeef0a6c4ca2015-10-06 11:38:28 -070031#include <cctype> // for isdigit
henrike@webrtc.org28e20752013-07-10 00:45:36 +000032
deadbeefab9b2d12015-10-14 11:33:11 -070033#include "talk/app/webrtc/audiotrack.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000034#include "talk/app/webrtc/dtmfsender.h"
35#include "talk/app/webrtc/jsepicecandidate.h"
36#include "talk/app/webrtc/jsepsessiondescription.h"
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +000037#include "talk/app/webrtc/mediaconstraintsinterface.h"
deadbeefab9b2d12015-10-14 11:33:11 -070038#include "talk/app/webrtc/mediastream.h"
39#include "talk/app/webrtc/mediastreamproxy.h"
40#include "talk/app/webrtc/mediastreamtrackproxy.h"
41#include "talk/app/webrtc/remoteaudiosource.h"
Tommif888bb52015-12-12 01:37:01 +010042#include "talk/app/webrtc/remoteaudiotrack.h"
deadbeefab9b2d12015-10-14 11:33:11 -070043#include "talk/app/webrtc/remotevideocapturer.h"
deadbeef70ab1a12015-09-28 16:53:55 -070044#include "talk/app/webrtc/rtpreceiver.h"
45#include "talk/app/webrtc/rtpsender.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000046#include "talk/app/webrtc/streamcollection.h"
deadbeefab9b2d12015-10-14 11:33:11 -070047#include "talk/app/webrtc/videosource.h"
48#include "talk/app/webrtc/videotrack.h"
49#include "talk/media/sctp/sctpdataengine.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000050#include "talk/session/media/channelmanager.h"
tfarina5237aaf2015-11-10 23:44:30 -080051#include "webrtc/base/arraysize.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000052#include "webrtc/base/logging.h"
53#include "webrtc/base/stringencode.h"
deadbeefab9b2d12015-10-14 11:33:11 -070054#include "webrtc/base/stringutils.h"
Peter Boström1a9d6152015-12-08 22:15:17 +010055#include "webrtc/base/trace_event.h"
tfarina5237aaf2015-11-10 23:44:30 -080056#include "webrtc/p2p/client/basicportallocator.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010057#include "webrtc/system_wrappers/include/field_trial.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000058
59namespace {
60
deadbeefab9b2d12015-10-14 11:33:11 -070061using webrtc::DataChannel;
62using webrtc::MediaConstraintsInterface;
63using webrtc::MediaStreamInterface;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000064using webrtc::PeerConnectionInterface;
deadbeeffac06552015-11-25 11:26:01 -080065using webrtc::RtpSenderInterface;
deadbeefab9b2d12015-10-14 11:33:11 -070066using webrtc::StreamCollection;
deadbeef0a6c4ca2015-10-06 11:38:28 -070067using webrtc::StunConfigurations;
68using webrtc::TurnConfigurations;
69typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
70 StunConfiguration;
71typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
72 TurnConfiguration;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073
deadbeefab9b2d12015-10-14 11:33:11 -070074static const char kDefaultStreamLabel[] = "default";
75static const char kDefaultAudioTrackLabel[] = "defaulta0";
76static const char kDefaultVideoTrackLabel[] = "defaultv0";
77
henrike@webrtc.org28e20752013-07-10 00:45:36 +000078// The min number of tokens must present in Turn host uri.
79// e.g. user@turn.example.org
80static const size_t kTurnHostTokensNum = 2;
81// Number of tokens must be preset when TURN uri has transport param.
82static const size_t kTurnTransportTokensNum = 2;
83// The default stun port.
wu@webrtc.org91053e72013-08-10 07:18:04 +000084static const int kDefaultStunPort = 3478;
85static const int kDefaultStunTlsPort = 5349;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000086static const char kTransport[] = "transport";
wu@webrtc.org91053e72013-08-10 07:18:04 +000087static const char kUdpTransportType[] = "udp";
88static const char kTcpTransportType[] = "tcp";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000089
90// NOTE: Must be in the same order as the ServiceType enum.
deadbeef0a6c4ca2015-10-06 11:38:28 -070091static const char* kValidIceServiceTypes[] = {"stun", "stuns", "turn", "turns"};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000092
deadbeef0a6c4ca2015-10-06 11:38:28 -070093// NOTE: A loop below assumes that the first value of this enum is 0 and all
94// other values are incremental.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000095enum ServiceType {
deadbeef0a6c4ca2015-10-06 11:38:28 -070096 STUN = 0, // Indicates a STUN server.
97 STUNS, // Indicates a STUN server used with a TLS session.
98 TURN, // Indicates a TURN server
99 TURNS, // Indicates a TURN server used with a TLS session.
100 INVALID, // Unknown.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000101};
tfarina5237aaf2015-11-10 23:44:30 -0800102static_assert(INVALID == arraysize(kValidIceServiceTypes),
deadbeef0a6c4ca2015-10-06 11:38:28 -0700103 "kValidIceServiceTypes must have as many strings as ServiceType "
104 "has values.");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000105
106enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000107 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108 MSG_SET_SESSIONDESCRIPTION_FAILED,
deadbeefab9b2d12015-10-14 11:33:11 -0700109 MSG_CREATE_SESSIONDESCRIPTION_FAILED,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000110 MSG_GETSTATS,
deadbeefbd292462015-12-14 18:15:29 -0800111 MSG_FREE_DATACHANNELS,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000112};
113
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000114struct SetSessionDescriptionMsg : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115 explicit SetSessionDescriptionMsg(
116 webrtc::SetSessionDescriptionObserver* observer)
117 : observer(observer) {
118 }
119
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000120 rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121 std::string error;
122};
123
deadbeefab9b2d12015-10-14 11:33:11 -0700124struct CreateSessionDescriptionMsg : public rtc::MessageData {
125 explicit CreateSessionDescriptionMsg(
126 webrtc::CreateSessionDescriptionObserver* observer)
127 : observer(observer) {}
128
129 rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserver> observer;
130 std::string error;
131};
132
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000133struct GetStatsMsg : public rtc::MessageData {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000134 GetStatsMsg(webrtc::StatsObserver* observer,
135 webrtc::MediaStreamTrackInterface* track)
136 : observer(observer), track(track) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000137 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000138 rtc::scoped_refptr<webrtc::StatsObserver> observer;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000139 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000140};
141
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000142// |in_str| should be of format
143// stunURI = scheme ":" stun-host [ ":" stun-port ]
144// scheme = "stun" / "stuns"
145// stun-host = IP-literal / IPv4address / reg-name
146// stun-port = *DIGIT
deadbeef0a6c4ca2015-10-06 11:38:28 -0700147//
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000148// draft-petithuguenin-behave-turn-uris-01
149// turnURI = scheme ":" turn-host [ ":" turn-port ]
150// turn-host = username@IP-literal / IPv4address / reg-name
151bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
152 ServiceType* service_type,
153 std::string* hostname) {
Tommi77d444a2015-04-24 15:38:38 +0200154 const std::string::size_type colonpos = in_str.find(':');
deadbeef0a6c4ca2015-10-06 11:38:28 -0700155 if (colonpos == std::string::npos) {
156 LOG(LS_WARNING) << "Missing ':' in ICE URI: " << in_str;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000157 return false;
158 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700159 if ((colonpos + 1) == in_str.length()) {
160 LOG(LS_WARNING) << "Empty hostname in ICE URI: " << in_str;
161 return false;
162 }
163 *service_type = INVALID;
tfarina5237aaf2015-11-10 23:44:30 -0800164 for (size_t i = 0; i < arraysize(kValidIceServiceTypes); ++i) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700165 if (in_str.compare(0, colonpos, kValidIceServiceTypes[i]) == 0) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000166 *service_type = static_cast<ServiceType>(i);
167 break;
168 }
169 }
170 if (*service_type == INVALID) {
171 return false;
172 }
173 *hostname = in_str.substr(colonpos + 1, std::string::npos);
174 return true;
175}
176
deadbeef0a6c4ca2015-10-06 11:38:28 -0700177bool ParsePort(const std::string& in_str, int* port) {
178 // Make sure port only contains digits. FromString doesn't check this.
179 for (const char& c : in_str) {
180 if (!std::isdigit(c)) {
181 return false;
182 }
183 }
184 return rtc::FromString(in_str, port);
185}
186
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000187// This method parses IPv6 and IPv4 literal strings, along with hostnames in
188// standard hostname:port format.
189// Consider following formats as correct.
190// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700191// |hostname|, |[IPv6 address]|, |IPv4 address|.
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000192bool ParseHostnameAndPortFromString(const std::string& in_str,
193 std::string* host,
194 int* port) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700195 RTC_DCHECK(host->empty());
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000196 if (in_str.at(0) == '[') {
197 std::string::size_type closebracket = in_str.rfind(']');
198 if (closebracket != std::string::npos) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000199 std::string::size_type colonpos = in_str.find(':', closebracket);
200 if (std::string::npos != colonpos) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700201 if (!ParsePort(in_str.substr(closebracket + 2, std::string::npos),
202 port)) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000203 return false;
204 }
205 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700206 *host = in_str.substr(1, closebracket - 1);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000207 } else {
208 return false;
209 }
210 } else {
211 std::string::size_type colonpos = in_str.find(':');
212 if (std::string::npos != colonpos) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700213 if (!ParsePort(in_str.substr(colonpos + 1, std::string::npos), port)) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000214 return false;
215 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700216 *host = in_str.substr(0, colonpos);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000217 } else {
218 *host = in_str;
219 }
220 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700221 return !host->empty();
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000222}
223
deadbeef0a6c4ca2015-10-06 11:38:28 -0700224// Adds a StunConfiguration or TurnConfiguration to the appropriate list,
225// by parsing |url| and using the username/password in |server|.
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200226bool ParseIceServerUrl(const PeerConnectionInterface::IceServer& server,
227 const std::string& url,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700228 StunConfigurations* stun_config,
229 TurnConfigurations* turn_config) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000230 // draft-nandakumar-rtcweb-stun-uri-01
231 // stunURI = scheme ":" stun-host [ ":" stun-port ]
232 // scheme = "stun" / "stuns"
233 // stun-host = IP-literal / IPv4address / reg-name
234 // stun-port = *DIGIT
235
236 // draft-petithuguenin-behave-turn-uris-01
237 // turnURI = scheme ":" turn-host [ ":" turn-port ]
238 // [ "?transport=" transport ]
239 // scheme = "turn" / "turns"
240 // transport = "udp" / "tcp" / transport-ext
241 // transport-ext = 1*unreserved
242 // turn-host = IP-literal / IPv4address / reg-name
243 // turn-port = *DIGIT
deadbeef0a6c4ca2015-10-06 11:38:28 -0700244 RTC_DCHECK(stun_config != nullptr);
245 RTC_DCHECK(turn_config != nullptr);
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200246 std::vector<std::string> tokens;
247 std::string turn_transport_type = kUdpTransportType;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700248 RTC_DCHECK(!url.empty());
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200249 rtc::tokenize(url, '?', &tokens);
250 std::string uri_without_transport = tokens[0];
251 // Let's look into transport= param, if it exists.
252 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
253 std::string uri_transport_param = tokens[1];
254 rtc::tokenize(uri_transport_param, '=', &tokens);
255 if (tokens[0] == kTransport) {
256 // As per above grammar transport param will be consist of lower case
257 // letters.
258 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
259 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
deadbeef0a6c4ca2015-10-06 11:38:28 -0700260 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000261 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200262 turn_transport_type = tokens[1];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000263 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200264 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000265
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200266 std::string hoststring;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700267 ServiceType service_type;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200268 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
269 &service_type,
270 &hoststring)) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700271 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: " << url;
272 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200273 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000274
deadbeef0a6c4ca2015-10-06 11:38:28 -0700275 // GetServiceTypeAndHostnameFromUri should never give an empty hoststring
276 RTC_DCHECK(!hoststring.empty());
Tommi77d444a2015-04-24 15:38:38 +0200277
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200278 // Let's break hostname.
279 tokens.clear();
deadbeef0a6c4ca2015-10-06 11:38:28 -0700280 rtc::tokenize_with_empty_tokens(hoststring, '@', &tokens);
281
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200282 std::string username(server.username);
deadbeef0a6c4ca2015-10-06 11:38:28 -0700283 if (tokens.size() > kTurnHostTokensNum) {
284 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring;
285 return false;
286 }
287 if (tokens.size() == kTurnHostTokensNum) {
288 if (tokens[0].empty() || tokens[1].empty()) {
289 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring;
290 return false;
291 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200292 username.assign(rtc::s_url_decode(tokens[0]));
293 hoststring = tokens[1];
294 } else {
295 hoststring = tokens[0];
296 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000297
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200298 int port = kDefaultStunPort;
299 if (service_type == TURNS) {
300 port = kDefaultStunTlsPort;
301 turn_transport_type = kTcpTransportType;
302 }
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000303
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200304 std::string address;
305 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700306 LOG(WARNING) << "Invalid hostname format: " << uri_without_transport;
307 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200308 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000309
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200310 if (port <= 0 || port > 0xffff) {
311 LOG(WARNING) << "Invalid port: " << port;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700312 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200313 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000314
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200315 switch (service_type) {
316 case STUN:
317 case STUNS:
318 stun_config->push_back(StunConfiguration(address, port));
319 break;
320 case TURN:
321 case TURNS: {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200322 bool secure = (service_type == TURNS);
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200323 turn_config->push_back(TurnConfiguration(address, port,
324 username,
325 server.password,
326 turn_transport_type,
327 secure));
328 break;
329 }
330 case INVALID:
331 default:
332 LOG(WARNING) << "Configuration not supported: " << url;
333 return false;
334 }
335 return true;
336}
337
deadbeef653b8e02015-11-11 12:55:10 -0800338void ConvertToCricketIceServers(
339 const std::vector<StunConfiguration>& stuns,
340 const std::vector<TurnConfiguration>& turns,
341 cricket::ServerAddresses* cricket_stuns,
342 std::vector<cricket::RelayServerConfig>* cricket_turns) {
343 RTC_DCHECK(cricket_stuns && cricket_turns);
344 for (const StunConfiguration& stun : stuns) {
345 cricket_stuns->insert(stun.server);
346 }
347
348 int priority = static_cast<int>(turns.size() - 1);
349 for (const TurnConfiguration& turn : turns) {
350 cricket::RelayCredentials credentials(turn.username, turn.password);
351 cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
352 cricket::ProtocolType protocol;
353 // Using VERIFY because ParseIceServers should have already caught an
354 // invalid transport type.
355 if (!VERIFY(
356 cricket::StringToProto(turn.transport_type.c_str(), &protocol))) {
357 LOG(LS_WARNING) << "Ignoring TURN server " << turn.server << ". "
358 << "Reason= Incorrect " << turn.transport_type
359 << " transport parameter.";
360 } else {
361 relay_server.ports.push_back(
362 cricket::ProtocolAddress(turn.server, protocol, turn.secure));
363 relay_server.credentials = credentials;
364 relay_server.priority = priority;
365 cricket_turns->push_back(relay_server);
366 }
367 // First in the list gets highest priority.
368 --priority;
369 }
370}
371
deadbeefab9b2d12015-10-14 11:33:11 -0700372// Check if we can send |new_stream| on a PeerConnection.
373bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
374 webrtc::MediaStreamInterface* new_stream) {
375 if (!new_stream || !current_streams) {
376 return false;
377 }
378 if (current_streams->find(new_stream->label()) != nullptr) {
379 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
380 << " is already added.";
381 return false;
382 }
383 return true;
384}
385
386bool MediaContentDirectionHasSend(cricket::MediaContentDirection dir) {
387 return dir == cricket::MD_SENDONLY || dir == cricket::MD_SENDRECV;
388}
389
deadbeef5e97fb52015-10-15 12:49:08 -0700390// If the direction is "recvonly" or "inactive", treat the description
391// as containing no streams.
392// See: https://code.google.com/p/webrtc/issues/detail?id=5054
393std::vector<cricket::StreamParams> GetActiveStreams(
394 const cricket::MediaContentDescription* desc) {
395 return MediaContentDirectionHasSend(desc->direction())
396 ? desc->streams()
397 : std::vector<cricket::StreamParams>();
398}
399
deadbeefab9b2d12015-10-14 11:33:11 -0700400bool IsValidOfferToReceiveMedia(int value) {
401 typedef PeerConnectionInterface::RTCOfferAnswerOptions Options;
402 return (value >= Options::kUndefined) &&
403 (value <= Options::kMaxOfferToReceiveMedia);
404}
405
406// Add the stream and RTP data channel info to |session_options|.
deadbeeffac06552015-11-25 11:26:01 -0800407void AddSendStreams(
408 cricket::MediaSessionOptions* session_options,
409 const std::vector<rtc::scoped_refptr<RtpSenderInterface>>& senders,
410 const std::map<std::string, rtc::scoped_refptr<DataChannel>>&
411 rtp_data_channels) {
deadbeefab9b2d12015-10-14 11:33:11 -0700412 session_options->streams.clear();
deadbeeffac06552015-11-25 11:26:01 -0800413 for (const auto& sender : senders) {
414 session_options->AddSendStream(sender->media_type(), sender->id(),
415 sender->stream_id());
deadbeefab9b2d12015-10-14 11:33:11 -0700416 }
417
418 // Check for data channels.
419 for (const auto& kv : rtp_data_channels) {
420 const DataChannel* channel = kv.second;
421 if (channel->state() == DataChannel::kConnecting ||
422 channel->state() == DataChannel::kOpen) {
423 // |streamid| and |sync_label| are both set to the DataChannel label
424 // here so they can be signaled the same way as MediaStreams and Tracks.
425 // For MediaStreams, the sync_label is the MediaStream label and the
426 // track label is the same as |streamid|.
427 const std::string& streamid = channel->label();
428 const std::string& sync_label = channel->label();
429 session_options->AddSendStream(cricket::MEDIA_TYPE_DATA, streamid,
430 sync_label);
431 }
432 }
433}
434
deadbeef0a6c4ca2015-10-06 11:38:28 -0700435} // namespace
436
437namespace webrtc {
438
deadbeefab9b2d12015-10-14 11:33:11 -0700439// Factory class for creating remote MediaStreams and MediaStreamTracks.
440class RemoteMediaStreamFactory {
441 public:
442 explicit RemoteMediaStreamFactory(rtc::Thread* signaling_thread,
443 cricket::ChannelManager* channel_manager)
444 : signaling_thread_(signaling_thread),
445 channel_manager_(channel_manager) {}
446
447 rtc::scoped_refptr<MediaStreamInterface> CreateMediaStream(
448 const std::string& stream_label) {
449 return MediaStreamProxy::Create(signaling_thread_,
450 MediaStream::Create(stream_label));
451 }
452
Tommif888bb52015-12-12 01:37:01 +0100453 AudioTrackInterface* AddAudioTrack(uint32_t ssrc,
454 AudioProviderInterface* provider,
455 webrtc::MediaStreamInterface* stream,
deadbeefab9b2d12015-10-14 11:33:11 -0700456 const std::string& track_id) {
Tommif888bb52015-12-12 01:37:01 +0100457 return AddTrack<AudioTrackInterface, RemoteAudioTrack, AudioTrackProxy>(
458 stream, track_id, RemoteAudioSource::Create(ssrc, provider));
deadbeefab9b2d12015-10-14 11:33:11 -0700459 }
460
461 VideoTrackInterface* AddVideoTrack(webrtc::MediaStreamInterface* stream,
462 const std::string& track_id) {
463 return AddTrack<VideoTrackInterface, VideoTrack, VideoTrackProxy>(
464 stream, track_id,
465 VideoSource::Create(channel_manager_, new RemoteVideoCapturer(),
466 nullptr)
467 .get());
468 }
469
470 private:
471 template <typename TI, typename T, typename TP, typename S>
472 TI* AddTrack(MediaStreamInterface* stream,
473 const std::string& track_id,
Tommif888bb52015-12-12 01:37:01 +0100474 const S& source) {
deadbeefab9b2d12015-10-14 11:33:11 -0700475 rtc::scoped_refptr<TI> track(
476 TP::Create(signaling_thread_, T::Create(track_id, source)));
477 track->set_state(webrtc::MediaStreamTrackInterface::kLive);
478 if (stream->AddTrack(track)) {
479 return track;
480 }
481 return nullptr;
482 }
483
484 rtc::Thread* signaling_thread_;
485 cricket::ChannelManager* channel_manager_;
486};
487
488bool ConvertRtcOptionsForOffer(
489 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
490 cricket::MediaSessionOptions* session_options) {
491 typedef PeerConnectionInterface::RTCOfferAnswerOptions RTCOfferAnswerOptions;
492 if (!IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_audio) ||
493 !IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_video)) {
494 return false;
495 }
496
deadbeefc80741f2015-10-22 13:14:45 -0700497 if (rtc_options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) {
deadbeefab9b2d12015-10-14 11:33:11 -0700498 session_options->recv_audio = (rtc_options.offer_to_receive_audio > 0);
499 }
deadbeefc80741f2015-10-22 13:14:45 -0700500 if (rtc_options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) {
deadbeefab9b2d12015-10-14 11:33:11 -0700501 session_options->recv_video = (rtc_options.offer_to_receive_video > 0);
502 }
503
504 session_options->vad_enabled = rtc_options.voice_activity_detection;
505 session_options->transport_options.ice_restart = rtc_options.ice_restart;
deadbeefc80741f2015-10-22 13:14:45 -0700506 session_options->bundle_enabled = rtc_options.use_rtp_mux;
deadbeefab9b2d12015-10-14 11:33:11 -0700507
508 return true;
509}
510
511bool ParseConstraintsForAnswer(const MediaConstraintsInterface* constraints,
512 cricket::MediaSessionOptions* session_options) {
513 bool value = false;
514 size_t mandatory_constraints_satisfied = 0;
515
516 // kOfferToReceiveAudio defaults to true according to spec.
517 if (!FindConstraint(constraints,
518 MediaConstraintsInterface::kOfferToReceiveAudio, &value,
519 &mandatory_constraints_satisfied) ||
520 value) {
521 session_options->recv_audio = true;
522 }
523
524 // kOfferToReceiveVideo defaults to false according to spec. But
525 // if it is an answer and video is offered, we should still accept video
526 // per default.
527 value = false;
528 if (!FindConstraint(constraints,
529 MediaConstraintsInterface::kOfferToReceiveVideo, &value,
530 &mandatory_constraints_satisfied) ||
531 value) {
532 session_options->recv_video = true;
533 }
534
535 if (FindConstraint(constraints,
536 MediaConstraintsInterface::kVoiceActivityDetection, &value,
537 &mandatory_constraints_satisfied)) {
538 session_options->vad_enabled = value;
539 }
540
541 if (FindConstraint(constraints, MediaConstraintsInterface::kUseRtpMux, &value,
542 &mandatory_constraints_satisfied)) {
543 session_options->bundle_enabled = value;
544 } else {
545 // kUseRtpMux defaults to true according to spec.
546 session_options->bundle_enabled = true;
547 }
deadbeefab9b2d12015-10-14 11:33:11 -0700548
549 if (FindConstraint(constraints, MediaConstraintsInterface::kIceRestart,
550 &value, &mandatory_constraints_satisfied)) {
551 session_options->transport_options.ice_restart = value;
552 } else {
553 // kIceRestart defaults to false according to spec.
554 session_options->transport_options.ice_restart = false;
555 }
556
557 if (!constraints) {
558 return true;
559 }
560 return mandatory_constraints_satisfied == constraints->GetMandatory().size();
561}
562
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200563bool ParseIceServers(const PeerConnectionInterface::IceServers& servers,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700564 StunConfigurations* stun_config,
565 TurnConfigurations* turn_config) {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200566 for (const webrtc::PeerConnectionInterface::IceServer& server : servers) {
567 if (!server.urls.empty()) {
568 for (const std::string& url : server.urls) {
Joachim Bauchd935f912015-05-29 22:14:21 +0200569 if (url.empty()) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700570 LOG(LS_ERROR) << "Empty uri.";
571 return false;
Joachim Bauchd935f912015-05-29 22:14:21 +0200572 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200573 if (!ParseIceServerUrl(server, url, stun_config, turn_config)) {
574 return false;
575 }
576 }
577 } else if (!server.uri.empty()) {
578 // Fallback to old .uri if new .urls isn't present.
579 if (!ParseIceServerUrl(server, server.uri, stun_config, turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000580 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200581 }
582 } else {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700583 LOG(LS_ERROR) << "Empty uri.";
584 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000585 }
586 }
587 return true;
588}
589
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590PeerConnection::PeerConnection(PeerConnectionFactory* factory)
591 : factory_(factory),
592 observer_(NULL),
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000593 uma_observer_(NULL),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000594 signaling_state_(kStable),
595 ice_state_(kIceNew),
596 ice_connection_state_(kIceConnectionNew),
deadbeefab9b2d12015-10-14 11:33:11 -0700597 ice_gathering_state_(kIceGatheringNew),
598 local_streams_(StreamCollection::Create()),
599 remote_streams_(StreamCollection::Create()) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000600
601PeerConnection::~PeerConnection() {
Peter Boström1a9d6152015-12-08 22:15:17 +0100602 TRACE_EVENT0("webrtc", "PeerConnection::~PeerConnection");
deadbeef0a6c4ca2015-10-06 11:38:28 -0700603 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeef70ab1a12015-09-28 16:53:55 -0700604 // Need to detach RTP senders/receivers from WebRtcSession,
605 // since it's about to be destroyed.
606 for (const auto& sender : senders_) {
607 sender->Stop();
608 }
609 for (const auto& receiver : receivers_) {
610 receiver->Stop();
611 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000612}
613
614bool PeerConnection::Initialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000615 const PeerConnectionInterface::RTCConfiguration& configuration,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000616 const MediaConstraintsInterface* constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000617 PortAllocatorFactoryInterface* allocator_factory,
Henrik Boström5e56c592015-08-11 10:33:13 +0200618 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000619 PeerConnectionObserver* observer) {
deadbeefab9b2d12015-10-14 11:33:11 -0700620 RTC_DCHECK(observer != nullptr);
621 if (!observer) {
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000622 return false;
deadbeefab9b2d12015-10-14 11:33:11 -0700623 }
deadbeef653b8e02015-11-11 12:55:10 -0800624
625 // This Initialize function parses ICE servers an extra time, but it will
626 // be removed once all PortAllocaotrs support SetIceServers.
627 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
628 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
629 if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
630 return false;
631 }
632 rtc::scoped_ptr<cricket::PortAllocator> allocator(
633 allocator_factory->CreatePortAllocator(stun_config, turn_config));
634 return Initialize(configuration, constraints, allocator.Pass(),
635 dtls_identity_store.Pass(), observer);
636}
637
638bool PeerConnection::Initialize(
639 const PeerConnectionInterface::RTCConfiguration& configuration,
640 const MediaConstraintsInterface* constraints,
641 rtc::scoped_ptr<cricket::PortAllocator> allocator,
642 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
643 PeerConnectionObserver* observer) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100644 TRACE_EVENT0("webrtc", "PeerConnection::Initialize");
deadbeef653b8e02015-11-11 12:55:10 -0800645 RTC_DCHECK(observer != nullptr);
646 if (!observer) {
647 return false;
648 }
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000649 observer_ = observer;
650
deadbeef653b8e02015-11-11 12:55:10 -0800651 port_allocator_ = allocator.Pass();
652
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000653 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
654 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000655 if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000656 return false;
657 }
deadbeef653b8e02015-11-11 12:55:10 -0800658
659 cricket::ServerAddresses cricket_stuns;
660 std::vector<cricket::RelayServerConfig> cricket_turns;
661 ConvertToCricketIceServers(stun_config, turn_config, &cricket_stuns,
662 &cricket_turns);
663 port_allocator_->SetIceServers(cricket_stuns, cricket_turns);
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000664
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665 // To handle both internal and externally created port allocator, we will
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000666 // enable BUNDLE here.
braveyao@webrtc.org1732df62014-10-27 03:01:37 +0000667 int portallocator_flags = port_allocator_->flags();
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700668 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000669 cricket::PORTALLOCATOR_ENABLE_IPV6;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000670 bool value;
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000671 // If IPv6 flag was specified, we'll not override it by experiment.
deadbeefab9b2d12015-10-14 11:33:11 -0700672 if (FindConstraint(constraints, MediaConstraintsInterface::kEnableIPv6,
673 &value, nullptr)) {
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000674 if (!value) {
675 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000676 }
guoweis@webrtc.org2c1bcea2014-09-23 16:23:02 +0000677 } else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default") ==
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000678 "Disabled") {
679 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000680 }
681
Jiayang Liucac1b382015-04-30 12:35:24 -0700682 if (configuration.tcp_candidate_policy == kTcpCandidatePolicyDisabled) {
683 portallocator_flags |= cricket::PORTALLOCATOR_DISABLE_TCP;
684 LOG(LS_INFO) << "TCP candidates are disabled.";
685 }
686
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000687 port_allocator_->set_flags(portallocator_flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000688 // No step delay is used while allocating ports.
689 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
690
stefanc1aeaf02015-10-15 07:26:07 -0700691 media_controller_.reset(factory_->CreateMediaController());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000692
stefanc1aeaf02015-10-15 07:26:07 -0700693 remote_stream_factory_.reset(new RemoteMediaStreamFactory(
694 factory_->signaling_thread(), media_controller_->channel_manager()));
695
696 session_.reset(
697 new WebRtcSession(media_controller_.get(), factory_->signaling_thread(),
698 factory_->worker_thread(), port_allocator_.get()));
deadbeefab9b2d12015-10-14 11:33:11 -0700699 stats_.reset(new StatsCollector(this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000700
701 // Initialize the WebRtcSession. It creates transport channels etc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000702 if (!session_->Initialize(factory_->options(), constraints,
deadbeefab9b2d12015-10-14 11:33:11 -0700703 dtls_identity_store.Pass(), configuration)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000704 return false;
deadbeefab9b2d12015-10-14 11:33:11 -0700705 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000706
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000707 // Register PeerConnection as receiver of local ice candidates.
708 // All the callbacks will be posted to the application from PeerConnection.
709 session_->RegisterIceObserver(this);
710 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
deadbeefab9b2d12015-10-14 11:33:11 -0700711 session_->SignalVoiceChannelDestroyed.connect(
712 this, &PeerConnection::OnVoiceChannelDestroyed);
713 session_->SignalVideoChannelDestroyed.connect(
714 this, &PeerConnection::OnVideoChannelDestroyed);
715 session_->SignalDataChannelCreated.connect(
716 this, &PeerConnection::OnDataChannelCreated);
717 session_->SignalDataChannelDestroyed.connect(
718 this, &PeerConnection::OnDataChannelDestroyed);
719 session_->SignalDataChannelOpenMessage.connect(
720 this, &PeerConnection::OnDataChannelOpenMessage);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000721 return true;
722}
723
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000724rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000725PeerConnection::local_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -0700726 return local_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000727}
728
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000729rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000730PeerConnection::remote_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -0700731 return remote_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000732}
733
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +0000734bool PeerConnection::AddStream(MediaStreamInterface* local_stream) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100735 TRACE_EVENT0("webrtc", "PeerConnection::AddStream");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000736 if (IsClosed()) {
737 return false;
738 }
deadbeefab9b2d12015-10-14 11:33:11 -0700739 if (!CanAddLocalMediaStream(local_streams_, local_stream)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000740 return false;
741 }
deadbeefab9b2d12015-10-14 11:33:11 -0700742
743 local_streams_->AddStream(local_stream);
744
deadbeefab9b2d12015-10-14 11:33:11 -0700745 for (const auto& track : local_stream->GetAudioTracks()) {
deadbeeffac06552015-11-25 11:26:01 -0800746 auto sender = FindSenderForTrack(track.get());
747 if (sender == senders_.end()) {
748 // Normal case; we've never seen this track before.
749 AudioRtpSender* new_sender = new AudioRtpSender(
750 track.get(), local_stream->label(), session_.get(), stats_.get());
751 senders_.push_back(new_sender);
752 // If the sender has already been configured in SDP, we call SetSsrc,
753 // which will connect the sender to the underlying transport. This can
754 // occur if a local session description that contains the ID of the sender
755 // is set before AddStream is called. It can also occur if the local
756 // session description is not changed and RemoveStream is called, and
757 // later AddStream is called again with the same stream.
758 const TrackInfo* track_info = FindTrackInfo(
759 local_audio_tracks_, local_stream->label(), track->id());
760 if (track_info) {
761 new_sender->SetSsrc(track_info->ssrc);
762 }
763 } else {
764 // We already have a sender for this track, so just change the stream_id
765 // so that it's correct in the next call to CreateOffer.
766 (*sender)->set_stream_id(local_stream->label());
deadbeefab9b2d12015-10-14 11:33:11 -0700767 }
768 }
769 for (const auto& track : local_stream->GetVideoTracks()) {
deadbeeffac06552015-11-25 11:26:01 -0800770 auto sender = FindSenderForTrack(track.get());
771 if (sender == senders_.end()) {
772 // Normal case; we've never seen this track before.
773 VideoRtpSender* new_sender = new VideoRtpSender(
774 track.get(), local_stream->label(), session_.get());
775 senders_.push_back(new_sender);
776 const TrackInfo* track_info = FindTrackInfo(
777 local_video_tracks_, local_stream->label(), track->id());
778 if (track_info) {
779 new_sender->SetSsrc(track_info->ssrc);
780 }
781 } else {
782 // We already have a sender for this track, so just change the stream_id
783 // so that it's correct in the next call to CreateOffer.
784 (*sender)->set_stream_id(local_stream->label());
deadbeefab9b2d12015-10-14 11:33:11 -0700785 }
786 }
787
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000788 stats_->AddStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000789 observer_->OnRenegotiationNeeded();
790 return true;
791}
792
deadbeefab9b2d12015-10-14 11:33:11 -0700793// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around
deadbeeffac06552015-11-25 11:26:01 -0800794// indefinitely, when we have unified plan SDP.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000795void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100796 TRACE_EVENT0("webrtc", "PeerConnection::RemoveStream");
deadbeefab9b2d12015-10-14 11:33:11 -0700797 for (const auto& track : local_stream->GetAudioTracks()) {
deadbeeffac06552015-11-25 11:26:01 -0800798 auto sender = FindSenderForTrack(track.get());
799 if (sender == senders_.end()) {
800 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
801 << " doesn't exist.";
802 continue;
deadbeefab9b2d12015-10-14 11:33:11 -0700803 }
deadbeeffac06552015-11-25 11:26:01 -0800804 (*sender)->Stop();
805 senders_.erase(sender);
deadbeefab9b2d12015-10-14 11:33:11 -0700806 }
807 for (const auto& track : local_stream->GetVideoTracks()) {
deadbeeffac06552015-11-25 11:26:01 -0800808 auto sender = FindSenderForTrack(track.get());
809 if (sender == senders_.end()) {
810 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
811 << " doesn't exist.";
812 continue;
deadbeefab9b2d12015-10-14 11:33:11 -0700813 }
deadbeeffac06552015-11-25 11:26:01 -0800814 (*sender)->Stop();
815 senders_.erase(sender);
deadbeefab9b2d12015-10-14 11:33:11 -0700816 }
817
818 local_streams_->RemoveStream(local_stream);
819
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000820 if (IsClosed()) {
821 return;
822 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000823 observer_->OnRenegotiationNeeded();
824}
825
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000826rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000827 AudioTrackInterface* track) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100828 TRACE_EVENT0("webrtc", "PeerConnection::CreateDtmfSender");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000829 if (!track) {
830 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
831 return NULL;
832 }
deadbeefab9b2d12015-10-14 11:33:11 -0700833 if (!local_streams_->FindAudioTrack(track->id())) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000834 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
835 return NULL;
836 }
837
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000838 rtc::scoped_refptr<DtmfSenderInterface> sender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000839 DtmfSender::Create(track, signaling_thread(), session_.get()));
840 if (!sender.get()) {
841 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
842 return NULL;
843 }
844 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
845}
846
deadbeeffac06552015-11-25 11:26:01 -0800847rtc::scoped_refptr<RtpSenderInterface> PeerConnection::CreateSender(
848 const std::string& kind) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100849 TRACE_EVENT0("webrtc", "PeerConnection::CreateSender");
deadbeeffac06552015-11-25 11:26:01 -0800850 RtpSenderInterface* new_sender;
851 if (kind == MediaStreamTrackInterface::kAudioKind) {
852 new_sender = new AudioRtpSender(session_.get(), stats_.get());
853 } else if (kind == MediaStreamTrackInterface::kVideoKind) {
854 new_sender = new VideoRtpSender(session_.get());
855 } else {
856 LOG(LS_ERROR) << "CreateSender called with invalid kind: " << kind;
857 return rtc::scoped_refptr<RtpSenderInterface>();
858 }
859 senders_.push_back(new_sender);
860 return RtpSenderProxy::Create(signaling_thread(), new_sender);
861}
862
deadbeef70ab1a12015-09-28 16:53:55 -0700863std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders()
864 const {
865 std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders;
866 for (const auto& sender : senders_) {
867 senders.push_back(RtpSenderProxy::Create(signaling_thread(), sender.get()));
868 }
869 return senders;
870}
871
872std::vector<rtc::scoped_refptr<RtpReceiverInterface>>
873PeerConnection::GetReceivers() const {
874 std::vector<rtc::scoped_refptr<RtpReceiverInterface>> receivers;
875 for (const auto& receiver : receivers_) {
876 receivers.push_back(
877 RtpReceiverProxy::Create(signaling_thread(), receiver.get()));
878 }
879 return receivers;
880}
881
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000882bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000883 MediaStreamTrackInterface* track,
884 StatsOutputLevel level) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100885 TRACE_EVENT0("webrtc", "PeerConnection::GetStats");
deadbeef0a6c4ca2015-10-06 11:38:28 -0700886 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000887 if (!VERIFY(observer != NULL)) {
888 LOG(LS_ERROR) << "GetStats - observer is NULL.";
889 return false;
890 }
891
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000892 stats_->UpdateStats(level);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000893 signaling_thread()->Post(this, MSG_GETSTATS,
894 new GetStatsMsg(observer, track));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000895 return true;
896}
897
898PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
899 return signaling_state_;
900}
901
902PeerConnectionInterface::IceState PeerConnection::ice_state() {
903 return ice_state_;
904}
905
906PeerConnectionInterface::IceConnectionState
907PeerConnection::ice_connection_state() {
908 return ice_connection_state_;
909}
910
911PeerConnectionInterface::IceGatheringState
912PeerConnection::ice_gathering_state() {
913 return ice_gathering_state_;
914}
915
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000916rtc::scoped_refptr<DataChannelInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000917PeerConnection::CreateDataChannel(
918 const std::string& label,
919 const DataChannelInit* config) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100920 TRACE_EVENT0("webrtc", "PeerConnection::CreateDataChannel");
deadbeefab9b2d12015-10-14 11:33:11 -0700921 bool first_datachannel = !HasDataChannels();
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000922
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000923 rtc::scoped_ptr<InternalDataChannelInit> internal_config;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000924 if (config) {
925 internal_config.reset(new InternalDataChannelInit(*config));
926 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000927 rtc::scoped_refptr<DataChannelInterface> channel(
deadbeefab9b2d12015-10-14 11:33:11 -0700928 InternalCreateDataChannel(label, internal_config.get()));
929 if (!channel.get()) {
930 return nullptr;
931 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000932
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000933 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
934 // the first SCTP DataChannel.
935 if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
936 observer_->OnRenegotiationNeeded();
937 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000938
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000939 return DataChannelProxy::Create(signaling_thread(), channel.get());
940}
941
942void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
943 const MediaConstraintsInterface* constraints) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100944 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer");
deadbeefab9b2d12015-10-14 11:33:11 -0700945 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000946 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
947 return;
948 }
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000949 RTCOfferAnswerOptions options;
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000950
951 bool value;
952 size_t mandatory_constraints = 0;
953
954 if (FindConstraint(constraints,
955 MediaConstraintsInterface::kOfferToReceiveAudio,
956 &value,
957 &mandatory_constraints)) {
958 options.offer_to_receive_audio =
959 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
960 }
961
962 if (FindConstraint(constraints,
963 MediaConstraintsInterface::kOfferToReceiveVideo,
964 &value,
965 &mandatory_constraints)) {
966 options.offer_to_receive_video =
967 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
968 }
969
970 if (FindConstraint(constraints,
971 MediaConstraintsInterface::kVoiceActivityDetection,
972 &value,
973 &mandatory_constraints)) {
974 options.voice_activity_detection = value;
975 }
976
977 if (FindConstraint(constraints,
978 MediaConstraintsInterface::kIceRestart,
979 &value,
980 &mandatory_constraints)) {
981 options.ice_restart = value;
982 }
983
984 if (FindConstraint(constraints,
985 MediaConstraintsInterface::kUseRtpMux,
986 &value,
987 &mandatory_constraints)) {
988 options.use_rtp_mux = value;
989 }
990
991 CreateOffer(observer, options);
992}
993
994void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
995 const RTCOfferAnswerOptions& options) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100996 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer");
deadbeefab9b2d12015-10-14 11:33:11 -0700997 if (!VERIFY(observer != nullptr)) {
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000998 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
999 return;
1000 }
deadbeefab9b2d12015-10-14 11:33:11 -07001001
1002 cricket::MediaSessionOptions session_options;
1003 if (!GetOptionsForOffer(options, &session_options)) {
1004 std::string error = "CreateOffer called with invalid options.";
1005 LOG(LS_ERROR) << error;
1006 PostCreateSessionDescriptionFailure(observer, error);
1007 return;
1008 }
1009
1010 session_->CreateOffer(observer, options, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001011}
1012
1013void PeerConnection::CreateAnswer(
1014 CreateSessionDescriptionObserver* observer,
1015 const MediaConstraintsInterface* constraints) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001016 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer");
deadbeefab9b2d12015-10-14 11:33:11 -07001017 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001018 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
1019 return;
1020 }
deadbeefab9b2d12015-10-14 11:33:11 -07001021
1022 cricket::MediaSessionOptions session_options;
1023 if (!GetOptionsForAnswer(constraints, &session_options)) {
1024 std::string error = "CreateAnswer called with invalid constraints.";
1025 LOG(LS_ERROR) << error;
1026 PostCreateSessionDescriptionFailure(observer, error);
1027 return;
1028 }
1029
1030 session_->CreateAnswer(observer, constraints, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001031}
1032
1033void PeerConnection::SetLocalDescription(
1034 SetSessionDescriptionObserver* observer,
1035 SessionDescriptionInterface* desc) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001036 TRACE_EVENT0("webrtc", "PeerConnection::SetLocalDescription");
deadbeefab9b2d12015-10-14 11:33:11 -07001037 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001038 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
1039 return;
1040 }
1041 if (!desc) {
1042 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
1043 return;
1044 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001045 // Update stats here so that we have the most recent stats for tracks and
1046 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001047 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001048 std::string error;
1049 if (!session_->SetLocalDescription(desc, &error)) {
1050 PostSetSessionDescriptionFailure(observer, error);
1051 return;
1052 }
deadbeefab9b2d12015-10-14 11:33:11 -07001053
1054 // If setting the description decided our SSL role, allocate any necessary
1055 // SCTP sids.
1056 rtc::SSLRole role;
1057 if (session_->data_channel_type() == cricket::DCT_SCTP &&
1058 session_->GetSslRole(&role)) {
1059 AllocateSctpSids(role);
1060 }
1061
1062 // Update state and SSRC of local MediaStreams and DataChannels based on the
1063 // local session description.
1064 const cricket::ContentInfo* audio_content =
1065 GetFirstAudioContent(desc->description());
1066 if (audio_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001067 if (audio_content->rejected) {
1068 RemoveTracks(cricket::MEDIA_TYPE_AUDIO);
1069 } else {
1070 const cricket::AudioContentDescription* audio_desc =
1071 static_cast<const cricket::AudioContentDescription*>(
1072 audio_content->description);
1073 UpdateLocalTracks(audio_desc->streams(), audio_desc->type());
1074 }
deadbeefab9b2d12015-10-14 11:33:11 -07001075 }
1076
1077 const cricket::ContentInfo* video_content =
1078 GetFirstVideoContent(desc->description());
1079 if (video_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001080 if (video_content->rejected) {
1081 RemoveTracks(cricket::MEDIA_TYPE_VIDEO);
1082 } else {
1083 const cricket::VideoContentDescription* video_desc =
1084 static_cast<const cricket::VideoContentDescription*>(
1085 video_content->description);
1086 UpdateLocalTracks(video_desc->streams(), video_desc->type());
1087 }
deadbeefab9b2d12015-10-14 11:33:11 -07001088 }
1089
1090 const cricket::ContentInfo* data_content =
1091 GetFirstDataContent(desc->description());
1092 if (data_content) {
1093 const cricket::DataContentDescription* data_desc =
1094 static_cast<const cricket::DataContentDescription*>(
1095 data_content->description);
1096 if (rtc::starts_with(data_desc->protocol().data(),
1097 cricket::kMediaProtocolRtpPrefix)) {
1098 UpdateLocalRtpDataChannels(data_desc->streams());
1099 }
1100 }
1101
1102 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001103 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeefab9b2d12015-10-14 11:33:11 -07001104
deadbeefcbecd352015-09-23 11:50:27 -07001105 // MaybeStartGathering needs to be called after posting
1106 // MSG_SET_SESSIONDESCRIPTION_SUCCESS, so that we don't signal any candidates
1107 // before signaling that SetLocalDescription completed.
1108 session_->MaybeStartGathering();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001109}
1110
1111void PeerConnection::SetRemoteDescription(
1112 SetSessionDescriptionObserver* observer,
1113 SessionDescriptionInterface* desc) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001114 TRACE_EVENT0("webrtc", "PeerConnection::SetRemoteDescription");
deadbeefab9b2d12015-10-14 11:33:11 -07001115 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001116 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
1117 return;
1118 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001119 if (!desc) {
1120 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
1121 return;
1122 }
1123 // Update stats here so that we have the most recent stats for tracks and
1124 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001125 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001126 std::string error;
1127 if (!session_->SetRemoteDescription(desc, &error)) {
1128 PostSetSessionDescriptionFailure(observer, error);
1129 return;
1130 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001131
deadbeefab9b2d12015-10-14 11:33:11 -07001132 // If setting the description decided our SSL role, allocate any necessary
1133 // SCTP sids.
1134 rtc::SSLRole role;
1135 if (session_->data_channel_type() == cricket::DCT_SCTP &&
1136 session_->GetSslRole(&role)) {
1137 AllocateSctpSids(role);
1138 }
1139
1140 const cricket::SessionDescription* remote_desc = desc->description();
deadbeefbda7e0b2015-12-08 17:13:40 -08001141 const cricket::ContentInfo* audio_content = GetFirstAudioContent(remote_desc);
1142 const cricket::ContentInfo* video_content = GetFirstVideoContent(remote_desc);
1143 const cricket::AudioContentDescription* audio_desc =
1144 GetFirstAudioContentDescription(remote_desc);
1145 const cricket::VideoContentDescription* video_desc =
1146 GetFirstVideoContentDescription(remote_desc);
1147 const cricket::DataContentDescription* data_desc =
1148 GetFirstDataContentDescription(remote_desc);
1149
1150 // Check if the descriptions include streams, just in case the peer supports
1151 // MSID, but doesn't indicate so with "a=msid-semantic".
1152 if (remote_desc->msid_supported() ||
1153 (audio_desc && !audio_desc->streams().empty()) ||
1154 (video_desc && !video_desc->streams().empty())) {
1155 remote_peer_supports_msid_ = true;
1156 }
deadbeefab9b2d12015-10-14 11:33:11 -07001157
1158 // We wait to signal new streams until we finish processing the description,
1159 // since only at that point will new streams have all their tracks.
1160 rtc::scoped_refptr<StreamCollection> new_streams(StreamCollection::Create());
1161
1162 // Find all audio rtp streams and create corresponding remote AudioTracks
1163 // and MediaStreams.
deadbeefab9b2d12015-10-14 11:33:11 -07001164 if (audio_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001165 if (audio_content->rejected) {
1166 RemoveTracks(cricket::MEDIA_TYPE_AUDIO);
1167 } else {
deadbeefbda7e0b2015-12-08 17:13:40 -08001168 bool default_audio_track_needed =
1169 !remote_peer_supports_msid_ &&
1170 MediaContentDirectionHasSend(audio_desc->direction());
1171 UpdateRemoteStreamsList(GetActiveStreams(audio_desc),
1172 default_audio_track_needed, audio_desc->type(),
deadbeeffaac4972015-11-12 15:33:07 -08001173 new_streams);
deadbeeffaac4972015-11-12 15:33:07 -08001174 }
deadbeefab9b2d12015-10-14 11:33:11 -07001175 }
1176
1177 // Find all video rtp streams and create corresponding remote VideoTracks
1178 // and MediaStreams.
deadbeefab9b2d12015-10-14 11:33:11 -07001179 if (video_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001180 if (video_content->rejected) {
1181 RemoveTracks(cricket::MEDIA_TYPE_VIDEO);
1182 } else {
deadbeefbda7e0b2015-12-08 17:13:40 -08001183 bool default_video_track_needed =
1184 !remote_peer_supports_msid_ &&
1185 MediaContentDirectionHasSend(video_desc->direction());
1186 UpdateRemoteStreamsList(GetActiveStreams(video_desc),
1187 default_video_track_needed, video_desc->type(),
deadbeeffaac4972015-11-12 15:33:07 -08001188 new_streams);
deadbeeffaac4972015-11-12 15:33:07 -08001189 }
deadbeefab9b2d12015-10-14 11:33:11 -07001190 }
1191
1192 // Update the DataChannels with the information from the remote peer.
deadbeefbda7e0b2015-12-08 17:13:40 -08001193 if (data_desc) {
1194 if (rtc::starts_with(data_desc->protocol().data(),
deadbeefab9b2d12015-10-14 11:33:11 -07001195 cricket::kMediaProtocolRtpPrefix)) {
deadbeefbda7e0b2015-12-08 17:13:40 -08001196 UpdateRemoteRtpDataChannels(GetActiveStreams(data_desc));
deadbeefab9b2d12015-10-14 11:33:11 -07001197 }
1198 }
1199
1200 // Iterate new_streams and notify the observer about new MediaStreams.
1201 for (size_t i = 0; i < new_streams->count(); ++i) {
1202 MediaStreamInterface* new_stream = new_streams->at(i);
1203 stats_->AddStream(new_stream);
1204 observer_->OnAddStream(new_stream);
1205 }
1206
deadbeefbda7e0b2015-12-08 17:13:40 -08001207 UpdateEndedRemoteMediaStreams();
deadbeefab9b2d12015-10-14 11:33:11 -07001208
1209 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1210 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeeffc648b62015-10-13 16:42:33 -07001211}
1212
deadbeefa67696b2015-09-29 11:56:26 -07001213bool PeerConnection::SetConfiguration(const RTCConfiguration& config) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001214 TRACE_EVENT0("webrtc", "PeerConnection::SetConfiguration");
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001215 if (port_allocator_) {
1216 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
1217 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
1218 if (!ParseIceServers(config.servers, &stuns, &turns)) {
1219 return false;
1220 }
1221
deadbeef653b8e02015-11-11 12:55:10 -08001222 cricket::ServerAddresses cricket_stuns;
1223 std::vector<cricket::RelayServerConfig> cricket_turns;
1224 ConvertToCricketIceServers(stuns, turns, &cricket_stuns, &cricket_turns);
1225 port_allocator_->SetIceServers(cricket_stuns, cricket_turns);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001226 }
honghaiz1f429e32015-09-28 07:57:34 -07001227 session_->SetIceConfig(session_->ParseIceConfig(config));
mallinath@webrtc.org3d81b1b2014-09-09 14:38:10 +00001228 return session_->SetIceTransports(config.type);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001229}
1230
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001231bool PeerConnection::AddIceCandidate(
1232 const IceCandidateInterface* ice_candidate) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001233 TRACE_EVENT0("webrtc", "PeerConnection::AddIceCandidate");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001234 return session_->ProcessIceMessage(ice_candidate);
1235}
1236
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001237void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001238 TRACE_EVENT0("webrtc", "PeerConnection::RegisterUmaObserver");
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001239 uma_observer_ = observer;
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +00001240
1241 if (session_) {
1242 session_->set_metrics_observer(uma_observer_);
1243 }
1244
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001245 // Send information about IPv4/IPv6 status.
1246 if (uma_observer_ && port_allocator_) {
1247 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001248 uma_observer_->IncrementEnumCounter(
1249 kEnumCounterAddressFamily, kPeerConnection_IPv6,
1250 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgb445f262014-05-23 22:19:37 +00001251 } else {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001252 uma_observer_->IncrementEnumCounter(
1253 kEnumCounterAddressFamily, kPeerConnection_IPv4,
1254 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001255 }
1256 }
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001257}
1258
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001259const SessionDescriptionInterface* PeerConnection::local_description() const {
1260 return session_->local_description();
1261}
1262
1263const SessionDescriptionInterface* PeerConnection::remote_description() const {
1264 return session_->remote_description();
1265}
1266
1267void PeerConnection::Close() {
Peter Boström1a9d6152015-12-08 22:15:17 +01001268 TRACE_EVENT0("webrtc", "PeerConnection::Close");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001269 // Update stats here so that we have the most recent stats for tracks and
1270 // streams before the channels are closed.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001271 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001272
deadbeefd59daf82015-10-14 15:02:44 -07001273 session_->Close();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001274}
1275
deadbeefd59daf82015-10-14 15:02:44 -07001276void PeerConnection::OnSessionStateChange(WebRtcSession* /*session*/,
1277 WebRtcSession::State state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001278 switch (state) {
deadbeefd59daf82015-10-14 15:02:44 -07001279 case WebRtcSession::STATE_INIT:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001280 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001281 break;
deadbeefd59daf82015-10-14 15:02:44 -07001282 case WebRtcSession::STATE_SENTOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001283 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
1284 break;
deadbeefd59daf82015-10-14 15:02:44 -07001285 case WebRtcSession::STATE_SENTPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001286 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
1287 break;
deadbeefd59daf82015-10-14 15:02:44 -07001288 case WebRtcSession::STATE_RECEIVEDOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001289 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
1290 break;
deadbeefd59daf82015-10-14 15:02:44 -07001291 case WebRtcSession::STATE_RECEIVEDPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001292 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
1293 break;
deadbeefd59daf82015-10-14 15:02:44 -07001294 case WebRtcSession::STATE_INPROGRESS:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001295 ChangeSignalingState(PeerConnectionInterface::kStable);
1296 break;
deadbeefd59daf82015-10-14 15:02:44 -07001297 case WebRtcSession::STATE_CLOSED:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001298 ChangeSignalingState(PeerConnectionInterface::kClosed);
1299 break;
1300 default:
1301 break;
1302 }
1303}
1304
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001305void PeerConnection::OnMessage(rtc::Message* msg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001306 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001307 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
1308 SetSessionDescriptionMsg* param =
1309 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1310 param->observer->OnSuccess();
1311 delete param;
1312 break;
1313 }
1314 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
1315 SetSessionDescriptionMsg* param =
1316 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1317 param->observer->OnFailure(param->error);
1318 delete param;
1319 break;
1320 }
deadbeefab9b2d12015-10-14 11:33:11 -07001321 case MSG_CREATE_SESSIONDESCRIPTION_FAILED: {
1322 CreateSessionDescriptionMsg* param =
1323 static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
1324 param->observer->OnFailure(param->error);
1325 delete param;
1326 break;
1327 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001328 case MSG_GETSTATS: {
1329 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +00001330 StatsReports reports;
1331 stats_->GetStats(param->track, &reports);
1332 param->observer->OnComplete(reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001333 delete param;
1334 break;
1335 }
deadbeefbd292462015-12-14 18:15:29 -08001336 case MSG_FREE_DATACHANNELS: {
1337 sctp_data_channels_to_free_.clear();
1338 break;
1339 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001340 default:
deadbeef0a6c4ca2015-10-06 11:38:28 -07001341 RTC_DCHECK(false && "Not implemented");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001342 break;
1343 }
1344}
1345
deadbeefab9b2d12015-10-14 11:33:11 -07001346void PeerConnection::CreateAudioReceiver(MediaStreamInterface* stream,
1347 AudioTrackInterface* audio_track,
1348 uint32_t ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -07001349 receivers_.push_back(new AudioRtpReceiver(audio_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001350}
1351
deadbeefab9b2d12015-10-14 11:33:11 -07001352void PeerConnection::CreateVideoReceiver(MediaStreamInterface* stream,
1353 VideoTrackInterface* video_track,
1354 uint32_t ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -07001355 receivers_.push_back(new VideoRtpReceiver(video_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001356}
1357
deadbeef70ab1a12015-09-28 16:53:55 -07001358// TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote
1359// description.
deadbeefab9b2d12015-10-14 11:33:11 -07001360void PeerConnection::DestroyAudioReceiver(MediaStreamInterface* stream,
1361 AudioTrackInterface* audio_track) {
deadbeef70ab1a12015-09-28 16:53:55 -07001362 auto it = FindReceiverForTrack(audio_track);
1363 if (it == receivers_.end()) {
1364 LOG(LS_WARNING) << "RtpReceiver for track with id " << audio_track->id()
1365 << " doesn't exist.";
1366 } else {
1367 (*it)->Stop();
1368 receivers_.erase(it);
1369 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001370}
1371
deadbeefab9b2d12015-10-14 11:33:11 -07001372void PeerConnection::DestroyVideoReceiver(MediaStreamInterface* stream,
1373 VideoTrackInterface* video_track) {
deadbeef70ab1a12015-09-28 16:53:55 -07001374 auto it = FindReceiverForTrack(video_track);
1375 if (it == receivers_.end()) {
1376 LOG(LS_WARNING) << "RtpReceiver for track with id " << video_track->id()
1377 << " doesn't exist.";
1378 } else {
1379 (*it)->Stop();
1380 receivers_.erase(it);
1381 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001382}
deadbeef70ab1a12015-09-28 16:53:55 -07001383
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001384void PeerConnection::OnIceConnectionChange(
1385 PeerConnectionInterface::IceConnectionState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001386 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefcbecd352015-09-23 11:50:27 -07001387 // After transitioning to "closed", ignore any additional states from
1388 // WebRtcSession (such as "disconnected").
deadbeefab9b2d12015-10-14 11:33:11 -07001389 if (IsClosed()) {
deadbeefcbecd352015-09-23 11:50:27 -07001390 return;
1391 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001392 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001393 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001394}
1395
1396void PeerConnection::OnIceGatheringChange(
1397 PeerConnectionInterface::IceGatheringState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001398 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001399 if (IsClosed()) {
1400 return;
1401 }
1402 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001403 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001404}
1405
1406void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001407 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001408 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001409}
1410
1411void PeerConnection::OnIceComplete() {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001412 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001413 observer_->OnIceComplete();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001414}
1415
Peter Thatcher54360512015-07-08 11:08:35 -07001416void PeerConnection::OnIceConnectionReceivingChange(bool receiving) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001417 RTC_DCHECK(signaling_thread()->IsCurrent());
Peter Thatcher54360512015-07-08 11:08:35 -07001418 observer_->OnIceConnectionReceivingChange(receiving);
1419}
1420
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001421void PeerConnection::ChangeSignalingState(
1422 PeerConnectionInterface::SignalingState signaling_state) {
1423 signaling_state_ = signaling_state;
1424 if (signaling_state == kClosed) {
1425 ice_connection_state_ = kIceConnectionClosed;
1426 observer_->OnIceConnectionChange(ice_connection_state_);
1427 if (ice_gathering_state_ != kIceGatheringComplete) {
1428 ice_gathering_state_ = kIceGatheringComplete;
1429 observer_->OnIceGatheringChange(ice_gathering_state_);
1430 }
1431 }
1432 observer_->OnSignalingChange(signaling_state_);
1433 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
1434}
1435
deadbeefab9b2d12015-10-14 11:33:11 -07001436void PeerConnection::PostSetSessionDescriptionFailure(
1437 SetSessionDescriptionObserver* observer,
1438 const std::string& error) {
1439 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1440 msg->error = error;
1441 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
1442}
1443
1444void PeerConnection::PostCreateSessionDescriptionFailure(
1445 CreateSessionDescriptionObserver* observer,
1446 const std::string& error) {
1447 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
1448 msg->error = error;
1449 signaling_thread()->Post(this, MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
1450}
1451
1452bool PeerConnection::GetOptionsForOffer(
1453 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
1454 cricket::MediaSessionOptions* session_options) {
deadbeefab9b2d12015-10-14 11:33:11 -07001455 if (!ConvertRtcOptionsForOffer(rtc_options, session_options)) {
1456 return false;
1457 }
1458
deadbeeffac06552015-11-25 11:26:01 -08001459 AddSendStreams(session_options, senders_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001460 // Offer to receive audio/video if the constraint is not set and there are
1461 // send streams, or we're currently receiving.
1462 if (rtc_options.offer_to_receive_audio == RTCOfferAnswerOptions::kUndefined) {
1463 session_options->recv_audio =
1464 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_AUDIO) ||
1465 !remote_audio_tracks_.empty();
1466 }
1467 if (rtc_options.offer_to_receive_video == RTCOfferAnswerOptions::kUndefined) {
1468 session_options->recv_video =
1469 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_VIDEO) ||
1470 !remote_video_tracks_.empty();
1471 }
1472 session_options->bundle_enabled =
1473 session_options->bundle_enabled &&
1474 (session_options->has_audio() || session_options->has_video() ||
1475 session_options->has_data());
1476
deadbeefab9b2d12015-10-14 11:33:11 -07001477 if (session_->data_channel_type() == cricket::DCT_SCTP && HasDataChannels()) {
1478 session_options->data_channel_type = cricket::DCT_SCTP;
1479 }
1480 return true;
1481}
1482
1483bool PeerConnection::GetOptionsForAnswer(
1484 const MediaConstraintsInterface* constraints,
1485 cricket::MediaSessionOptions* session_options) {
deadbeefab9b2d12015-10-14 11:33:11 -07001486 session_options->recv_audio = false;
1487 session_options->recv_video = false;
deadbeefab9b2d12015-10-14 11:33:11 -07001488 if (!ParseConstraintsForAnswer(constraints, session_options)) {
1489 return false;
1490 }
1491
deadbeeffac06552015-11-25 11:26:01 -08001492 AddSendStreams(session_options, senders_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001493 session_options->bundle_enabled =
1494 session_options->bundle_enabled &&
1495 (session_options->has_audio() || session_options->has_video() ||
1496 session_options->has_data());
1497
deadbeefab9b2d12015-10-14 11:33:11 -07001498 // RTP data channel is handled in MediaSessionOptions::AddStream. SCTP streams
1499 // are not signaled in the SDP so does not go through that path and must be
1500 // handled here.
1501 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1502 session_options->data_channel_type = cricket::DCT_SCTP;
1503 }
1504 return true;
1505}
1506
deadbeeffaac4972015-11-12 15:33:07 -08001507void PeerConnection::RemoveTracks(cricket::MediaType media_type) {
1508 UpdateLocalTracks(std::vector<cricket::StreamParams>(), media_type);
deadbeefbda7e0b2015-12-08 17:13:40 -08001509 UpdateRemoteStreamsList(std::vector<cricket::StreamParams>(), false,
1510 media_type, nullptr);
deadbeeffaac4972015-11-12 15:33:07 -08001511}
1512
deadbeefab9b2d12015-10-14 11:33:11 -07001513void PeerConnection::UpdateRemoteStreamsList(
1514 const cricket::StreamParamsVec& streams,
deadbeefbda7e0b2015-12-08 17:13:40 -08001515 bool default_track_needed,
deadbeefab9b2d12015-10-14 11:33:11 -07001516 cricket::MediaType media_type,
1517 StreamCollection* new_streams) {
1518 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1519
1520 // Find removed tracks. I.e., tracks where the track id or ssrc don't match
deadbeeffac06552015-11-25 11:26:01 -08001521 // the new StreamParam.
deadbeefab9b2d12015-10-14 11:33:11 -07001522 auto track_it = current_tracks->begin();
1523 while (track_it != current_tracks->end()) {
1524 const TrackInfo& info = *track_it;
1525 const cricket::StreamParams* params =
1526 cricket::GetStreamBySsrc(streams, info.ssrc);
deadbeefbda7e0b2015-12-08 17:13:40 -08001527 bool track_exists = params && params->id == info.track_id;
1528 // If this is a default track, and we still need it, don't remove it.
1529 if ((info.stream_label == kDefaultStreamLabel && default_track_needed) ||
1530 track_exists) {
1531 ++track_it;
1532 } else {
deadbeefab9b2d12015-10-14 11:33:11 -07001533 OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
1534 track_it = current_tracks->erase(track_it);
deadbeefab9b2d12015-10-14 11:33:11 -07001535 }
1536 }
1537
1538 // Find new and active tracks.
1539 for (const cricket::StreamParams& params : streams) {
1540 // The sync_label is the MediaStream label and the |stream.id| is the
1541 // track id.
1542 const std::string& stream_label = params.sync_label;
1543 const std::string& track_id = params.id;
1544 uint32_t ssrc = params.first_ssrc();
1545
1546 rtc::scoped_refptr<MediaStreamInterface> stream =
1547 remote_streams_->find(stream_label);
1548 if (!stream) {
1549 // This is a new MediaStream. Create a new remote MediaStream.
1550 stream = remote_stream_factory_->CreateMediaStream(stream_label);
1551 remote_streams_->AddStream(stream);
1552 new_streams->AddStream(stream);
1553 }
1554
1555 const TrackInfo* track_info =
1556 FindTrackInfo(*current_tracks, stream_label, track_id);
1557 if (!track_info) {
1558 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1559 OnRemoteTrackSeen(stream_label, track_id, ssrc, media_type);
1560 }
1561 }
deadbeefbda7e0b2015-12-08 17:13:40 -08001562
1563 // Add default track if necessary.
1564 if (default_track_needed) {
1565 rtc::scoped_refptr<MediaStreamInterface> default_stream =
1566 remote_streams_->find(kDefaultStreamLabel);
1567 if (!default_stream) {
1568 // Create the new default MediaStream.
1569 default_stream =
1570 remote_stream_factory_->CreateMediaStream(kDefaultStreamLabel);
1571 remote_streams_->AddStream(default_stream);
1572 new_streams->AddStream(default_stream);
1573 }
1574 std::string default_track_id = (media_type == cricket::MEDIA_TYPE_AUDIO)
1575 ? kDefaultAudioTrackLabel
1576 : kDefaultVideoTrackLabel;
1577 const TrackInfo* default_track_info =
1578 FindTrackInfo(*current_tracks, kDefaultStreamLabel, default_track_id);
1579 if (!default_track_info) {
1580 current_tracks->push_back(
1581 TrackInfo(kDefaultStreamLabel, default_track_id, 0));
1582 OnRemoteTrackSeen(kDefaultStreamLabel, default_track_id, 0, media_type);
1583 }
1584 }
deadbeefab9b2d12015-10-14 11:33:11 -07001585}
1586
1587void PeerConnection::OnRemoteTrackSeen(const std::string& stream_label,
1588 const std::string& track_id,
1589 uint32_t ssrc,
1590 cricket::MediaType media_type) {
1591 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1592
1593 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
Tommif888bb52015-12-12 01:37:01 +01001594 AudioTrackInterface* audio_track = remote_stream_factory_->AddAudioTrack(
1595 ssrc, session_.get(), stream, track_id);
deadbeefab9b2d12015-10-14 11:33:11 -07001596 CreateAudioReceiver(stream, audio_track, ssrc);
1597 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1598 VideoTrackInterface* video_track =
1599 remote_stream_factory_->AddVideoTrack(stream, track_id);
1600 CreateVideoReceiver(stream, video_track, ssrc);
1601 } else {
1602 RTC_DCHECK(false && "Invalid media type");
1603 }
1604}
1605
1606void PeerConnection::OnRemoteTrackRemoved(const std::string& stream_label,
1607 const std::string& track_id,
1608 cricket::MediaType media_type) {
1609 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1610
1611 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1612 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1613 stream->FindAudioTrack(track_id);
1614 if (audio_track) {
1615 audio_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1616 stream->RemoveTrack(audio_track);
1617 DestroyAudioReceiver(stream, audio_track);
1618 }
1619 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1620 rtc::scoped_refptr<VideoTrackInterface> video_track =
1621 stream->FindVideoTrack(track_id);
1622 if (video_track) {
1623 video_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1624 stream->RemoveTrack(video_track);
1625 DestroyVideoReceiver(stream, video_track);
1626 }
1627 } else {
1628 ASSERT(false && "Invalid media type");
1629 }
1630}
1631
1632void PeerConnection::UpdateEndedRemoteMediaStreams() {
1633 std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams_to_remove;
1634 for (size_t i = 0; i < remote_streams_->count(); ++i) {
1635 MediaStreamInterface* stream = remote_streams_->at(i);
1636 if (stream->GetAudioTracks().empty() && stream->GetVideoTracks().empty()) {
1637 streams_to_remove.push_back(stream);
1638 }
1639 }
1640
1641 for (const auto& stream : streams_to_remove) {
1642 remote_streams_->RemoveStream(stream);
1643 observer_->OnRemoveStream(stream);
1644 }
1645}
1646
deadbeefab9b2d12015-10-14 11:33:11 -07001647void PeerConnection::EndRemoteTracks(cricket::MediaType media_type) {
1648 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1649 for (TrackInfos::iterator track_it = current_tracks->begin();
1650 track_it != current_tracks->end(); ++track_it) {
1651 const TrackInfo& info = *track_it;
1652 MediaStreamInterface* stream = remote_streams_->find(info.stream_label);
1653 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1654 AudioTrackInterface* track = stream->FindAudioTrack(info.track_id);
1655 // There's no guarantee the track is still available, e.g. the track may
1656 // have been removed from the stream by javascript.
1657 if (track) {
1658 track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1659 }
1660 }
1661 if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1662 VideoTrackInterface* track = stream->FindVideoTrack(info.track_id);
1663 // There's no guarantee the track is still available, e.g. the track may
1664 // have been removed from the stream by javascript.
1665 if (track) {
1666 track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1667 }
1668 }
1669 }
1670}
1671
1672void PeerConnection::UpdateLocalTracks(
1673 const std::vector<cricket::StreamParams>& streams,
1674 cricket::MediaType media_type) {
1675 TrackInfos* current_tracks = GetLocalTracks(media_type);
1676
1677 // Find removed tracks. I.e., tracks where the track id, stream label or ssrc
1678 // don't match the new StreamParam.
1679 TrackInfos::iterator track_it = current_tracks->begin();
1680 while (track_it != current_tracks->end()) {
1681 const TrackInfo& info = *track_it;
1682 const cricket::StreamParams* params =
1683 cricket::GetStreamBySsrc(streams, info.ssrc);
1684 if (!params || params->id != info.track_id ||
1685 params->sync_label != info.stream_label) {
1686 OnLocalTrackRemoved(info.stream_label, info.track_id, info.ssrc,
1687 media_type);
1688 track_it = current_tracks->erase(track_it);
1689 } else {
1690 ++track_it;
1691 }
1692 }
1693
1694 // Find new and active tracks.
1695 for (const cricket::StreamParams& params : streams) {
1696 // The sync_label is the MediaStream label and the |stream.id| is the
1697 // track id.
1698 const std::string& stream_label = params.sync_label;
1699 const std::string& track_id = params.id;
1700 uint32_t ssrc = params.first_ssrc();
1701 const TrackInfo* track_info =
1702 FindTrackInfo(*current_tracks, stream_label, track_id);
1703 if (!track_info) {
1704 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1705 OnLocalTrackSeen(stream_label, track_id, params.first_ssrc(), media_type);
1706 }
1707 }
1708}
1709
1710void PeerConnection::OnLocalTrackSeen(const std::string& stream_label,
1711 const std::string& track_id,
1712 uint32_t ssrc,
1713 cricket::MediaType media_type) {
deadbeeffac06552015-11-25 11:26:01 -08001714 RtpSenderInterface* sender = FindSenderById(track_id);
1715 if (!sender) {
1716 LOG(LS_WARNING) << "An unknown RtpSender with id " << track_id
1717 << " has been configured in the local description.";
deadbeefab9b2d12015-10-14 11:33:11 -07001718 return;
1719 }
1720
deadbeeffac06552015-11-25 11:26:01 -08001721 if (sender->media_type() != media_type) {
1722 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
1723 << " description with an unexpected media type.";
1724 return;
deadbeefab9b2d12015-10-14 11:33:11 -07001725 }
deadbeeffac06552015-11-25 11:26:01 -08001726
1727 sender->set_stream_id(stream_label);
1728 sender->SetSsrc(ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -07001729}
1730
1731void PeerConnection::OnLocalTrackRemoved(const std::string& stream_label,
1732 const std::string& track_id,
1733 uint32_t ssrc,
1734 cricket::MediaType media_type) {
deadbeeffac06552015-11-25 11:26:01 -08001735 RtpSenderInterface* sender = FindSenderById(track_id);
1736 if (!sender) {
1737 // This is the normal case. I.e., RemoveStream has been called and the
deadbeefab9b2d12015-10-14 11:33:11 -07001738 // SessionDescriptions has been renegotiated.
1739 return;
1740 }
deadbeeffac06552015-11-25 11:26:01 -08001741
1742 // A sender has been removed from the SessionDescription but it's still
1743 // associated with the PeerConnection. This only occurs if the SDP doesn't
1744 // match with the calls to CreateSender, AddStream and RemoveStream.
1745 if (sender->media_type() != media_type) {
1746 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
1747 << " description with an unexpected media type.";
1748 return;
deadbeefab9b2d12015-10-14 11:33:11 -07001749 }
deadbeeffac06552015-11-25 11:26:01 -08001750
1751 sender->SetSsrc(0);
deadbeefab9b2d12015-10-14 11:33:11 -07001752}
1753
1754void PeerConnection::UpdateLocalRtpDataChannels(
1755 const cricket::StreamParamsVec& streams) {
1756 std::vector<std::string> existing_channels;
1757
1758 // Find new and active data channels.
1759 for (const cricket::StreamParams& params : streams) {
1760 // |it->sync_label| is actually the data channel label. The reason is that
1761 // we use the same naming of data channels as we do for
1762 // MediaStreams and Tracks.
1763 // For MediaStreams, the sync_label is the MediaStream label and the
1764 // track label is the same as |streamid|.
1765 const std::string& channel_label = params.sync_label;
1766 auto data_channel_it = rtp_data_channels_.find(channel_label);
1767 if (!VERIFY(data_channel_it != rtp_data_channels_.end())) {
1768 continue;
1769 }
1770 // Set the SSRC the data channel should use for sending.
1771 data_channel_it->second->SetSendSsrc(params.first_ssrc());
1772 existing_channels.push_back(data_channel_it->first);
1773 }
1774
1775 UpdateClosingRtpDataChannels(existing_channels, true);
1776}
1777
1778void PeerConnection::UpdateRemoteRtpDataChannels(
1779 const cricket::StreamParamsVec& streams) {
1780 std::vector<std::string> existing_channels;
1781
1782 // Find new and active data channels.
1783 for (const cricket::StreamParams& params : streams) {
1784 // The data channel label is either the mslabel or the SSRC if the mslabel
1785 // does not exist. Ex a=ssrc:444330170 mslabel:test1.
1786 std::string label = params.sync_label.empty()
1787 ? rtc::ToString(params.first_ssrc())
1788 : params.sync_label;
1789 auto data_channel_it = rtp_data_channels_.find(label);
1790 if (data_channel_it == rtp_data_channels_.end()) {
1791 // This is a new data channel.
1792 CreateRemoteRtpDataChannel(label, params.first_ssrc());
1793 } else {
1794 data_channel_it->second->SetReceiveSsrc(params.first_ssrc());
1795 }
1796 existing_channels.push_back(label);
1797 }
1798
1799 UpdateClosingRtpDataChannels(existing_channels, false);
1800}
1801
1802void PeerConnection::UpdateClosingRtpDataChannels(
1803 const std::vector<std::string>& active_channels,
1804 bool is_local_update) {
1805 auto it = rtp_data_channels_.begin();
1806 while (it != rtp_data_channels_.end()) {
1807 DataChannel* data_channel = it->second;
1808 if (std::find(active_channels.begin(), active_channels.end(),
1809 data_channel->label()) != active_channels.end()) {
1810 ++it;
1811 continue;
1812 }
1813
1814 if (is_local_update) {
1815 data_channel->SetSendSsrc(0);
1816 } else {
1817 data_channel->RemotePeerRequestClose();
1818 }
1819
1820 if (data_channel->state() == DataChannel::kClosed) {
1821 rtp_data_channels_.erase(it);
1822 it = rtp_data_channels_.begin();
1823 } else {
1824 ++it;
1825 }
1826 }
1827}
1828
1829void PeerConnection::CreateRemoteRtpDataChannel(const std::string& label,
1830 uint32_t remote_ssrc) {
1831 rtc::scoped_refptr<DataChannel> channel(
1832 InternalCreateDataChannel(label, nullptr));
1833 if (!channel.get()) {
1834 LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
1835 << "CreateDataChannel failed.";
1836 return;
1837 }
1838 channel->SetReceiveSsrc(remote_ssrc);
1839 observer_->OnDataChannel(
1840 DataChannelProxy::Create(signaling_thread(), channel));
1841}
1842
1843rtc::scoped_refptr<DataChannel> PeerConnection::InternalCreateDataChannel(
1844 const std::string& label,
1845 const InternalDataChannelInit* config) {
1846 if (IsClosed()) {
1847 return nullptr;
1848 }
1849 if (session_->data_channel_type() == cricket::DCT_NONE) {
1850 LOG(LS_ERROR)
1851 << "InternalCreateDataChannel: Data is not supported in this call.";
1852 return nullptr;
1853 }
1854 InternalDataChannelInit new_config =
1855 config ? (*config) : InternalDataChannelInit();
1856 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1857 if (new_config.id < 0) {
1858 rtc::SSLRole role;
1859 if (session_->GetSslRole(&role) &&
1860 !sid_allocator_.AllocateSid(role, &new_config.id)) {
1861 LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel.";
1862 return nullptr;
1863 }
1864 } else if (!sid_allocator_.ReserveSid(new_config.id)) {
1865 LOG(LS_ERROR) << "Failed to create a SCTP data channel "
1866 << "because the id is already in use or out of range.";
1867 return nullptr;
1868 }
1869 }
1870
1871 rtc::scoped_refptr<DataChannel> channel(DataChannel::Create(
1872 session_.get(), session_->data_channel_type(), label, new_config));
1873 if (!channel) {
1874 sid_allocator_.ReleaseSid(new_config.id);
1875 return nullptr;
1876 }
1877
1878 if (channel->data_channel_type() == cricket::DCT_RTP) {
1879 if (rtp_data_channels_.find(channel->label()) != rtp_data_channels_.end()) {
1880 LOG(LS_ERROR) << "DataChannel with label " << channel->label()
1881 << " already exists.";
1882 return nullptr;
1883 }
1884 rtp_data_channels_[channel->label()] = channel;
1885 } else {
1886 RTC_DCHECK(channel->data_channel_type() == cricket::DCT_SCTP);
1887 sctp_data_channels_.push_back(channel);
1888 channel->SignalClosed.connect(this,
1889 &PeerConnection::OnSctpDataChannelClosed);
1890 }
1891
1892 return channel;
1893}
1894
1895bool PeerConnection::HasDataChannels() const {
1896 return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
1897}
1898
1899void PeerConnection::AllocateSctpSids(rtc::SSLRole role) {
1900 for (const auto& channel : sctp_data_channels_) {
1901 if (channel->id() < 0) {
1902 int sid;
1903 if (!sid_allocator_.AllocateSid(role, &sid)) {
1904 LOG(LS_ERROR) << "Failed to allocate SCTP sid.";
1905 continue;
1906 }
1907 channel->SetSctpSid(sid);
1908 }
1909 }
1910}
1911
1912void PeerConnection::OnSctpDataChannelClosed(DataChannel* channel) {
deadbeefbd292462015-12-14 18:15:29 -08001913 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefab9b2d12015-10-14 11:33:11 -07001914 for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end();
1915 ++it) {
1916 if (it->get() == channel) {
1917 if (channel->id() >= 0) {
1918 sid_allocator_.ReleaseSid(channel->id());
1919 }
deadbeefbd292462015-12-14 18:15:29 -08001920 // Since this method is triggered by a signal from the DataChannel,
1921 // we can't free it directly here; we need to free it asynchronously.
1922 sctp_data_channels_to_free_.push_back(*it);
deadbeefab9b2d12015-10-14 11:33:11 -07001923 sctp_data_channels_.erase(it);
deadbeefbd292462015-12-14 18:15:29 -08001924 signaling_thread()->Post(this, MSG_FREE_DATACHANNELS, nullptr);
deadbeefab9b2d12015-10-14 11:33:11 -07001925 return;
1926 }
1927 }
1928}
1929
1930void PeerConnection::OnVoiceChannelDestroyed() {
1931 EndRemoteTracks(cricket::MEDIA_TYPE_AUDIO);
1932}
1933
1934void PeerConnection::OnVideoChannelDestroyed() {
1935 EndRemoteTracks(cricket::MEDIA_TYPE_VIDEO);
1936}
1937
1938void PeerConnection::OnDataChannelCreated() {
1939 for (const auto& channel : sctp_data_channels_) {
1940 channel->OnTransportChannelCreated();
1941 }
1942}
1943
1944void PeerConnection::OnDataChannelDestroyed() {
1945 // Use a temporary copy of the RTP/SCTP DataChannel list because the
1946 // DataChannel may callback to us and try to modify the list.
1947 std::map<std::string, rtc::scoped_refptr<DataChannel>> temp_rtp_dcs;
1948 temp_rtp_dcs.swap(rtp_data_channels_);
1949 for (const auto& kv : temp_rtp_dcs) {
1950 kv.second->OnTransportChannelDestroyed();
1951 }
1952
1953 std::vector<rtc::scoped_refptr<DataChannel>> temp_sctp_dcs;
1954 temp_sctp_dcs.swap(sctp_data_channels_);
1955 for (const auto& channel : temp_sctp_dcs) {
1956 channel->OnTransportChannelDestroyed();
1957 }
1958}
1959
1960void PeerConnection::OnDataChannelOpenMessage(
1961 const std::string& label,
1962 const InternalDataChannelInit& config) {
1963 rtc::scoped_refptr<DataChannel> channel(
1964 InternalCreateDataChannel(label, &config));
1965 if (!channel.get()) {
1966 LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
1967 return;
1968 }
1969
1970 observer_->OnDataChannel(
1971 DataChannelProxy::Create(signaling_thread(), channel));
1972}
1973
deadbeeffac06552015-11-25 11:26:01 -08001974RtpSenderInterface* PeerConnection::FindSenderById(const std::string& id) {
1975 auto it =
1976 std::find_if(senders_.begin(), senders_.end(),
1977 [id](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
1978 return sender->id() == id;
1979 });
1980 return it != senders_.end() ? it->get() : nullptr;
1981}
1982
deadbeef70ab1a12015-09-28 16:53:55 -07001983std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator
1984PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) {
1985 return std::find_if(
1986 senders_.begin(), senders_.end(),
1987 [track](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
1988 return sender->track() == track;
1989 });
1990}
1991
1992std::vector<rtc::scoped_refptr<RtpReceiverInterface>>::iterator
1993PeerConnection::FindReceiverForTrack(MediaStreamTrackInterface* track) {
1994 return std::find_if(
1995 receivers_.begin(), receivers_.end(),
1996 [track](const rtc::scoped_refptr<RtpReceiverInterface>& receiver) {
1997 return receiver->track() == track;
1998 });
1999}
2000
deadbeefab9b2d12015-10-14 11:33:11 -07002001PeerConnection::TrackInfos* PeerConnection::GetRemoteTracks(
2002 cricket::MediaType media_type) {
2003 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
2004 media_type == cricket::MEDIA_TYPE_VIDEO);
2005 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &remote_audio_tracks_
2006 : &remote_video_tracks_;
2007}
2008
2009PeerConnection::TrackInfos* PeerConnection::GetLocalTracks(
2010 cricket::MediaType media_type) {
2011 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
2012 media_type == cricket::MEDIA_TYPE_VIDEO);
2013 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &local_audio_tracks_
2014 : &local_video_tracks_;
2015}
2016
2017const PeerConnection::TrackInfo* PeerConnection::FindTrackInfo(
2018 const PeerConnection::TrackInfos& infos,
2019 const std::string& stream_label,
2020 const std::string track_id) const {
2021 for (const TrackInfo& track_info : infos) {
2022 if (track_info.stream_label == stream_label &&
2023 track_info.track_id == track_id) {
2024 return &track_info;
2025 }
2026 }
2027 return nullptr;
2028}
2029
2030DataChannel* PeerConnection::FindDataChannelBySid(int sid) const {
2031 for (const auto& channel : sctp_data_channels_) {
2032 if (channel->id() == sid) {
2033 return channel;
2034 }
2035 }
2036 return nullptr;
2037}
2038
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002039} // namespace webrtc