blob: 8d04ae629068f367b5daeecfe6c03398f97692aa [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"
42#include "talk/app/webrtc/remotevideocapturer.h"
deadbeef70ab1a12015-09-28 16:53:55 -070043#include "talk/app/webrtc/rtpreceiver.h"
44#include "talk/app/webrtc/rtpsender.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000045#include "talk/app/webrtc/streamcollection.h"
deadbeefab9b2d12015-10-14 11:33:11 -070046#include "talk/app/webrtc/videosource.h"
47#include "talk/app/webrtc/videotrack.h"
48#include "talk/media/sctp/sctpdataengine.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000049#include "talk/session/media/channelmanager.h"
tfarina5237aaf2015-11-10 23:44:30 -080050#include "webrtc/base/arraysize.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000051#include "webrtc/base/logging.h"
52#include "webrtc/base/stringencode.h"
deadbeefab9b2d12015-10-14 11:33:11 -070053#include "webrtc/base/stringutils.h"
tfarina5237aaf2015-11-10 23:44:30 -080054#include "webrtc/p2p/client/basicportallocator.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010055#include "webrtc/system_wrappers/include/field_trial.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056
57namespace {
58
deadbeefab9b2d12015-10-14 11:33:11 -070059using webrtc::DataChannel;
60using webrtc::MediaConstraintsInterface;
61using webrtc::MediaStreamInterface;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000062using webrtc::PeerConnectionInterface;
deadbeeffac06552015-11-25 11:26:01 -080063using webrtc::RtpSenderInterface;
deadbeefab9b2d12015-10-14 11:33:11 -070064using webrtc::StreamCollection;
deadbeef0a6c4ca2015-10-06 11:38:28 -070065using webrtc::StunConfigurations;
66using webrtc::TurnConfigurations;
67typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
68 StunConfiguration;
69typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
70 TurnConfiguration;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071
deadbeefab9b2d12015-10-14 11:33:11 -070072static const char kDefaultStreamLabel[] = "default";
73static const char kDefaultAudioTrackLabel[] = "defaulta0";
74static const char kDefaultVideoTrackLabel[] = "defaultv0";
75
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076// The min number of tokens must present in Turn host uri.
77// e.g. user@turn.example.org
78static const size_t kTurnHostTokensNum = 2;
79// Number of tokens must be preset when TURN uri has transport param.
80static const size_t kTurnTransportTokensNum = 2;
81// The default stun port.
wu@webrtc.org91053e72013-08-10 07:18:04 +000082static const int kDefaultStunPort = 3478;
83static const int kDefaultStunTlsPort = 5349;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000084static const char kTransport[] = "transport";
wu@webrtc.org91053e72013-08-10 07:18:04 +000085static const char kUdpTransportType[] = "udp";
86static const char kTcpTransportType[] = "tcp";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000087
88// NOTE: Must be in the same order as the ServiceType enum.
deadbeef0a6c4ca2015-10-06 11:38:28 -070089static const char* kValidIceServiceTypes[] = {"stun", "stuns", "turn", "turns"};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000090
deadbeef0a6c4ca2015-10-06 11:38:28 -070091// NOTE: A loop below assumes that the first value of this enum is 0 and all
92// other values are incremental.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000093enum ServiceType {
deadbeef0a6c4ca2015-10-06 11:38:28 -070094 STUN = 0, // Indicates a STUN server.
95 STUNS, // Indicates a STUN server used with a TLS session.
96 TURN, // Indicates a TURN server
97 TURNS, // Indicates a TURN server used with a TLS session.
98 INVALID, // Unknown.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000099};
tfarina5237aaf2015-11-10 23:44:30 -0800100static_assert(INVALID == arraysize(kValidIceServiceTypes),
deadbeef0a6c4ca2015-10-06 11:38:28 -0700101 "kValidIceServiceTypes must have as many strings as ServiceType "
102 "has values.");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000103
104enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000105 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106 MSG_SET_SESSIONDESCRIPTION_FAILED,
deadbeefab9b2d12015-10-14 11:33:11 -0700107 MSG_CREATE_SESSIONDESCRIPTION_FAILED,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108 MSG_GETSTATS,
deadbeef38686922015-12-07 15:32:23 -0800109 MSG_DELETE,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000110};
111
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000112struct SetSessionDescriptionMsg : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000113 explicit SetSessionDescriptionMsg(
114 webrtc::SetSessionDescriptionObserver* observer)
115 : observer(observer) {
116 }
117
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000118 rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000119 std::string error;
120};
121
deadbeefab9b2d12015-10-14 11:33:11 -0700122struct CreateSessionDescriptionMsg : public rtc::MessageData {
123 explicit CreateSessionDescriptionMsg(
124 webrtc::CreateSessionDescriptionObserver* observer)
125 : observer(observer) {}
126
127 rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserver> observer;
128 std::string error;
129};
130
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000131struct GetStatsMsg : public rtc::MessageData {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000132 GetStatsMsg(webrtc::StatsObserver* observer,
133 webrtc::MediaStreamTrackInterface* track)
134 : observer(observer), track(track) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000135 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000136 rtc::scoped_refptr<webrtc::StatsObserver> observer;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000137 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000138};
139
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000140// |in_str| should be of format
141// stunURI = scheme ":" stun-host [ ":" stun-port ]
142// scheme = "stun" / "stuns"
143// stun-host = IP-literal / IPv4address / reg-name
144// stun-port = *DIGIT
deadbeef0a6c4ca2015-10-06 11:38:28 -0700145//
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000146// draft-petithuguenin-behave-turn-uris-01
147// turnURI = scheme ":" turn-host [ ":" turn-port ]
148// turn-host = username@IP-literal / IPv4address / reg-name
149bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
150 ServiceType* service_type,
151 std::string* hostname) {
Tommi77d444a2015-04-24 15:38:38 +0200152 const std::string::size_type colonpos = in_str.find(':');
deadbeef0a6c4ca2015-10-06 11:38:28 -0700153 if (colonpos == std::string::npos) {
154 LOG(LS_WARNING) << "Missing ':' in ICE URI: " << in_str;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000155 return false;
156 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700157 if ((colonpos + 1) == in_str.length()) {
158 LOG(LS_WARNING) << "Empty hostname in ICE URI: " << in_str;
159 return false;
160 }
161 *service_type = INVALID;
tfarina5237aaf2015-11-10 23:44:30 -0800162 for (size_t i = 0; i < arraysize(kValidIceServiceTypes); ++i) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700163 if (in_str.compare(0, colonpos, kValidIceServiceTypes[i]) == 0) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000164 *service_type = static_cast<ServiceType>(i);
165 break;
166 }
167 }
168 if (*service_type == INVALID) {
169 return false;
170 }
171 *hostname = in_str.substr(colonpos + 1, std::string::npos);
172 return true;
173}
174
deadbeef0a6c4ca2015-10-06 11:38:28 -0700175bool ParsePort(const std::string& in_str, int* port) {
176 // Make sure port only contains digits. FromString doesn't check this.
177 for (const char& c : in_str) {
178 if (!std::isdigit(c)) {
179 return false;
180 }
181 }
182 return rtc::FromString(in_str, port);
183}
184
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000185// This method parses IPv6 and IPv4 literal strings, along with hostnames in
186// standard hostname:port format.
187// Consider following formats as correct.
188// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700189// |hostname|, |[IPv6 address]|, |IPv4 address|.
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000190bool ParseHostnameAndPortFromString(const std::string& in_str,
191 std::string* host,
192 int* port) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700193 RTC_DCHECK(host->empty());
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000194 if (in_str.at(0) == '[') {
195 std::string::size_type closebracket = in_str.rfind(']');
196 if (closebracket != std::string::npos) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000197 std::string::size_type colonpos = in_str.find(':', closebracket);
198 if (std::string::npos != colonpos) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700199 if (!ParsePort(in_str.substr(closebracket + 2, std::string::npos),
200 port)) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000201 return false;
202 }
203 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700204 *host = in_str.substr(1, closebracket - 1);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000205 } else {
206 return false;
207 }
208 } else {
209 std::string::size_type colonpos = in_str.find(':');
210 if (std::string::npos != colonpos) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700211 if (!ParsePort(in_str.substr(colonpos + 1, std::string::npos), port)) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000212 return false;
213 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700214 *host = in_str.substr(0, colonpos);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000215 } else {
216 *host = in_str;
217 }
218 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700219 return !host->empty();
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000220}
221
deadbeef0a6c4ca2015-10-06 11:38:28 -0700222// Adds a StunConfiguration or TurnConfiguration to the appropriate list,
223// by parsing |url| and using the username/password in |server|.
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200224bool ParseIceServerUrl(const PeerConnectionInterface::IceServer& server,
225 const std::string& url,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700226 StunConfigurations* stun_config,
227 TurnConfigurations* turn_config) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000228 // draft-nandakumar-rtcweb-stun-uri-01
229 // stunURI = scheme ":" stun-host [ ":" stun-port ]
230 // scheme = "stun" / "stuns"
231 // stun-host = IP-literal / IPv4address / reg-name
232 // stun-port = *DIGIT
233
234 // draft-petithuguenin-behave-turn-uris-01
235 // turnURI = scheme ":" turn-host [ ":" turn-port ]
236 // [ "?transport=" transport ]
237 // scheme = "turn" / "turns"
238 // transport = "udp" / "tcp" / transport-ext
239 // transport-ext = 1*unreserved
240 // turn-host = IP-literal / IPv4address / reg-name
241 // turn-port = *DIGIT
deadbeef0a6c4ca2015-10-06 11:38:28 -0700242 RTC_DCHECK(stun_config != nullptr);
243 RTC_DCHECK(turn_config != nullptr);
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200244 std::vector<std::string> tokens;
245 std::string turn_transport_type = kUdpTransportType;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700246 RTC_DCHECK(!url.empty());
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200247 rtc::tokenize(url, '?', &tokens);
248 std::string uri_without_transport = tokens[0];
249 // Let's look into transport= param, if it exists.
250 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
251 std::string uri_transport_param = tokens[1];
252 rtc::tokenize(uri_transport_param, '=', &tokens);
253 if (tokens[0] == kTransport) {
254 // As per above grammar transport param will be consist of lower case
255 // letters.
256 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
257 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
deadbeef0a6c4ca2015-10-06 11:38:28 -0700258 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000259 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200260 turn_transport_type = tokens[1];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000261 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200262 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000263
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200264 std::string hoststring;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700265 ServiceType service_type;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200266 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
267 &service_type,
268 &hoststring)) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700269 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: " << url;
270 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200271 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000272
deadbeef0a6c4ca2015-10-06 11:38:28 -0700273 // GetServiceTypeAndHostnameFromUri should never give an empty hoststring
274 RTC_DCHECK(!hoststring.empty());
Tommi77d444a2015-04-24 15:38:38 +0200275
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200276 // Let's break hostname.
277 tokens.clear();
deadbeef0a6c4ca2015-10-06 11:38:28 -0700278 rtc::tokenize_with_empty_tokens(hoststring, '@', &tokens);
279
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200280 std::string username(server.username);
deadbeef0a6c4ca2015-10-06 11:38:28 -0700281 if (tokens.size() > kTurnHostTokensNum) {
282 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring;
283 return false;
284 }
285 if (tokens.size() == kTurnHostTokensNum) {
286 if (tokens[0].empty() || tokens[1].empty()) {
287 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring;
288 return false;
289 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200290 username.assign(rtc::s_url_decode(tokens[0]));
291 hoststring = tokens[1];
292 } else {
293 hoststring = tokens[0];
294 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000295
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200296 int port = kDefaultStunPort;
297 if (service_type == TURNS) {
298 port = kDefaultStunTlsPort;
299 turn_transport_type = kTcpTransportType;
300 }
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000301
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200302 std::string address;
303 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700304 LOG(WARNING) << "Invalid hostname format: " << uri_without_transport;
305 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200306 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000307
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200308 if (port <= 0 || port > 0xffff) {
309 LOG(WARNING) << "Invalid port: " << port;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700310 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200311 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000312
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200313 switch (service_type) {
314 case STUN:
315 case STUNS:
316 stun_config->push_back(StunConfiguration(address, port));
317 break;
318 case TURN:
319 case TURNS: {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200320 bool secure = (service_type == TURNS);
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200321 turn_config->push_back(TurnConfiguration(address, port,
322 username,
323 server.password,
324 turn_transport_type,
325 secure));
326 break;
327 }
328 case INVALID:
329 default:
330 LOG(WARNING) << "Configuration not supported: " << url;
331 return false;
332 }
333 return true;
334}
335
deadbeef653b8e02015-11-11 12:55:10 -0800336void ConvertToCricketIceServers(
337 const std::vector<StunConfiguration>& stuns,
338 const std::vector<TurnConfiguration>& turns,
339 cricket::ServerAddresses* cricket_stuns,
340 std::vector<cricket::RelayServerConfig>* cricket_turns) {
341 RTC_DCHECK(cricket_stuns && cricket_turns);
342 for (const StunConfiguration& stun : stuns) {
343 cricket_stuns->insert(stun.server);
344 }
345
346 int priority = static_cast<int>(turns.size() - 1);
347 for (const TurnConfiguration& turn : turns) {
348 cricket::RelayCredentials credentials(turn.username, turn.password);
349 cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
350 cricket::ProtocolType protocol;
351 // Using VERIFY because ParseIceServers should have already caught an
352 // invalid transport type.
353 if (!VERIFY(
354 cricket::StringToProto(turn.transport_type.c_str(), &protocol))) {
355 LOG(LS_WARNING) << "Ignoring TURN server " << turn.server << ". "
356 << "Reason= Incorrect " << turn.transport_type
357 << " transport parameter.";
358 } else {
359 relay_server.ports.push_back(
360 cricket::ProtocolAddress(turn.server, protocol, turn.secure));
361 relay_server.credentials = credentials;
362 relay_server.priority = priority;
363 cricket_turns->push_back(relay_server);
364 }
365 // First in the list gets highest priority.
366 --priority;
367 }
368}
369
deadbeefab9b2d12015-10-14 11:33:11 -0700370// Check if we can send |new_stream| on a PeerConnection.
371bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
372 webrtc::MediaStreamInterface* new_stream) {
373 if (!new_stream || !current_streams) {
374 return false;
375 }
376 if (current_streams->find(new_stream->label()) != nullptr) {
377 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
378 << " is already added.";
379 return false;
380 }
381 return true;
382}
383
384bool MediaContentDirectionHasSend(cricket::MediaContentDirection dir) {
385 return dir == cricket::MD_SENDONLY || dir == cricket::MD_SENDRECV;
386}
387
deadbeef5e97fb52015-10-15 12:49:08 -0700388// If the direction is "recvonly" or "inactive", treat the description
389// as containing no streams.
390// See: https://code.google.com/p/webrtc/issues/detail?id=5054
391std::vector<cricket::StreamParams> GetActiveStreams(
392 const cricket::MediaContentDescription* desc) {
393 return MediaContentDirectionHasSend(desc->direction())
394 ? desc->streams()
395 : std::vector<cricket::StreamParams>();
396}
397
deadbeefab9b2d12015-10-14 11:33:11 -0700398bool IsValidOfferToReceiveMedia(int value) {
399 typedef PeerConnectionInterface::RTCOfferAnswerOptions Options;
400 return (value >= Options::kUndefined) &&
401 (value <= Options::kMaxOfferToReceiveMedia);
402}
403
404// Add the stream and RTP data channel info to |session_options|.
deadbeeffac06552015-11-25 11:26:01 -0800405void AddSendStreams(
406 cricket::MediaSessionOptions* session_options,
407 const std::vector<rtc::scoped_refptr<RtpSenderInterface>>& senders,
408 const std::map<std::string, rtc::scoped_refptr<DataChannel>>&
409 rtp_data_channels) {
deadbeefab9b2d12015-10-14 11:33:11 -0700410 session_options->streams.clear();
deadbeeffac06552015-11-25 11:26:01 -0800411 for (const auto& sender : senders) {
412 session_options->AddSendStream(sender->media_type(), sender->id(),
413 sender->stream_id());
deadbeefab9b2d12015-10-14 11:33:11 -0700414 }
415
416 // Check for data channels.
417 for (const auto& kv : rtp_data_channels) {
418 const DataChannel* channel = kv.second;
419 if (channel->state() == DataChannel::kConnecting ||
420 channel->state() == DataChannel::kOpen) {
421 // |streamid| and |sync_label| are both set to the DataChannel label
422 // here so they can be signaled the same way as MediaStreams and Tracks.
423 // For MediaStreams, the sync_label is the MediaStream label and the
424 // track label is the same as |streamid|.
425 const std::string& streamid = channel->label();
426 const std::string& sync_label = channel->label();
427 session_options->AddSendStream(cricket::MEDIA_TYPE_DATA, streamid,
428 sync_label);
429 }
430 }
431}
432
deadbeef0a6c4ca2015-10-06 11:38:28 -0700433} // namespace
434
435namespace webrtc {
436
deadbeefab9b2d12015-10-14 11:33:11 -0700437// Factory class for creating remote MediaStreams and MediaStreamTracks.
438class RemoteMediaStreamFactory {
439 public:
440 explicit RemoteMediaStreamFactory(rtc::Thread* signaling_thread,
441 cricket::ChannelManager* channel_manager)
442 : signaling_thread_(signaling_thread),
443 channel_manager_(channel_manager) {}
444
445 rtc::scoped_refptr<MediaStreamInterface> CreateMediaStream(
446 const std::string& stream_label) {
447 return MediaStreamProxy::Create(signaling_thread_,
448 MediaStream::Create(stream_label));
449 }
450
451 AudioTrackInterface* AddAudioTrack(webrtc::MediaStreamInterface* stream,
452 const std::string& track_id) {
453 return AddTrack<AudioTrackInterface, AudioTrack, AudioTrackProxy>(
454 stream, track_id, RemoteAudioSource::Create().get());
455 }
456
457 VideoTrackInterface* AddVideoTrack(webrtc::MediaStreamInterface* stream,
458 const std::string& track_id) {
459 return AddTrack<VideoTrackInterface, VideoTrack, VideoTrackProxy>(
460 stream, track_id,
461 VideoSource::Create(channel_manager_, new RemoteVideoCapturer(),
462 nullptr)
463 .get());
464 }
465
466 private:
467 template <typename TI, typename T, typename TP, typename S>
468 TI* AddTrack(MediaStreamInterface* stream,
469 const std::string& track_id,
470 S* source) {
471 rtc::scoped_refptr<TI> track(
472 TP::Create(signaling_thread_, T::Create(track_id, source)));
473 track->set_state(webrtc::MediaStreamTrackInterface::kLive);
474 if (stream->AddTrack(track)) {
475 return track;
476 }
477 return nullptr;
478 }
479
480 rtc::Thread* signaling_thread_;
481 cricket::ChannelManager* channel_manager_;
482};
483
484bool ConvertRtcOptionsForOffer(
485 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
486 cricket::MediaSessionOptions* session_options) {
487 typedef PeerConnectionInterface::RTCOfferAnswerOptions RTCOfferAnswerOptions;
488 if (!IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_audio) ||
489 !IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_video)) {
490 return false;
491 }
492
deadbeefc80741f2015-10-22 13:14:45 -0700493 if (rtc_options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) {
deadbeefab9b2d12015-10-14 11:33:11 -0700494 session_options->recv_audio = (rtc_options.offer_to_receive_audio > 0);
495 }
deadbeefc80741f2015-10-22 13:14:45 -0700496 if (rtc_options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) {
deadbeefab9b2d12015-10-14 11:33:11 -0700497 session_options->recv_video = (rtc_options.offer_to_receive_video > 0);
498 }
499
500 session_options->vad_enabled = rtc_options.voice_activity_detection;
501 session_options->transport_options.ice_restart = rtc_options.ice_restart;
deadbeefc80741f2015-10-22 13:14:45 -0700502 session_options->bundle_enabled = rtc_options.use_rtp_mux;
deadbeefab9b2d12015-10-14 11:33:11 -0700503
504 return true;
505}
506
507bool ParseConstraintsForAnswer(const MediaConstraintsInterface* constraints,
508 cricket::MediaSessionOptions* session_options) {
509 bool value = false;
510 size_t mandatory_constraints_satisfied = 0;
511
512 // kOfferToReceiveAudio defaults to true according to spec.
513 if (!FindConstraint(constraints,
514 MediaConstraintsInterface::kOfferToReceiveAudio, &value,
515 &mandatory_constraints_satisfied) ||
516 value) {
517 session_options->recv_audio = true;
518 }
519
520 // kOfferToReceiveVideo defaults to false according to spec. But
521 // if it is an answer and video is offered, we should still accept video
522 // per default.
523 value = false;
524 if (!FindConstraint(constraints,
525 MediaConstraintsInterface::kOfferToReceiveVideo, &value,
526 &mandatory_constraints_satisfied) ||
527 value) {
528 session_options->recv_video = true;
529 }
530
531 if (FindConstraint(constraints,
532 MediaConstraintsInterface::kVoiceActivityDetection, &value,
533 &mandatory_constraints_satisfied)) {
534 session_options->vad_enabled = value;
535 }
536
537 if (FindConstraint(constraints, MediaConstraintsInterface::kUseRtpMux, &value,
538 &mandatory_constraints_satisfied)) {
539 session_options->bundle_enabled = value;
540 } else {
541 // kUseRtpMux defaults to true according to spec.
542 session_options->bundle_enabled = true;
543 }
deadbeefab9b2d12015-10-14 11:33:11 -0700544
545 if (FindConstraint(constraints, MediaConstraintsInterface::kIceRestart,
546 &value, &mandatory_constraints_satisfied)) {
547 session_options->transport_options.ice_restart = value;
548 } else {
549 // kIceRestart defaults to false according to spec.
550 session_options->transport_options.ice_restart = false;
551 }
552
553 if (!constraints) {
554 return true;
555 }
556 return mandatory_constraints_satisfied == constraints->GetMandatory().size();
557}
558
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200559bool ParseIceServers(const PeerConnectionInterface::IceServers& servers,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700560 StunConfigurations* stun_config,
561 TurnConfigurations* turn_config) {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200562 for (const webrtc::PeerConnectionInterface::IceServer& server : servers) {
563 if (!server.urls.empty()) {
564 for (const std::string& url : server.urls) {
Joachim Bauchd935f912015-05-29 22:14:21 +0200565 if (url.empty()) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700566 LOG(LS_ERROR) << "Empty uri.";
567 return false;
Joachim Bauchd935f912015-05-29 22:14:21 +0200568 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200569 if (!ParseIceServerUrl(server, url, stun_config, turn_config)) {
570 return false;
571 }
572 }
573 } else if (!server.uri.empty()) {
574 // Fallback to old .uri if new .urls isn't present.
575 if (!ParseIceServerUrl(server, server.uri, stun_config, turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000576 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200577 }
578 } else {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700579 LOG(LS_ERROR) << "Empty uri.";
580 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000581 }
582 }
583 return true;
584}
585
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586PeerConnection::PeerConnection(PeerConnectionFactory* factory)
587 : factory_(factory),
588 observer_(NULL),
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000589 uma_observer_(NULL),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590 signaling_state_(kStable),
591 ice_state_(kIceNew),
592 ice_connection_state_(kIceConnectionNew),
deadbeefab9b2d12015-10-14 11:33:11 -0700593 ice_gathering_state_(kIceGatheringNew),
594 local_streams_(StreamCollection::Create()),
595 remote_streams_(StreamCollection::Create()) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000596
597PeerConnection::~PeerConnection() {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700598 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeef38686922015-12-07 15:32:23 -0800599 // Finish any pending deletions.
600 signaling_thread()->Clear(this, MSG_DELETE, nullptr);
deadbeef70ab1a12015-09-28 16:53:55 -0700601 // Need to detach RTP senders/receivers from WebRtcSession,
602 // since it's about to be destroyed.
603 for (const auto& sender : senders_) {
604 sender->Stop();
605 }
606 for (const auto& receiver : receivers_) {
607 receiver->Stop();
608 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000609}
610
611bool PeerConnection::Initialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000612 const PeerConnectionInterface::RTCConfiguration& configuration,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000613 const MediaConstraintsInterface* constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000614 PortAllocatorFactoryInterface* allocator_factory,
Henrik Boström5e56c592015-08-11 10:33:13 +0200615 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000616 PeerConnectionObserver* observer) {
deadbeefab9b2d12015-10-14 11:33:11 -0700617 RTC_DCHECK(observer != nullptr);
618 if (!observer) {
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000619 return false;
deadbeefab9b2d12015-10-14 11:33:11 -0700620 }
deadbeef653b8e02015-11-11 12:55:10 -0800621
622 // This Initialize function parses ICE servers an extra time, but it will
623 // be removed once all PortAllocaotrs support SetIceServers.
624 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
625 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
626 if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
627 return false;
628 }
629 rtc::scoped_ptr<cricket::PortAllocator> allocator(
630 allocator_factory->CreatePortAllocator(stun_config, turn_config));
631 return Initialize(configuration, constraints, allocator.Pass(),
632 dtls_identity_store.Pass(), observer);
633}
634
635bool PeerConnection::Initialize(
636 const PeerConnectionInterface::RTCConfiguration& configuration,
637 const MediaConstraintsInterface* constraints,
638 rtc::scoped_ptr<cricket::PortAllocator> allocator,
639 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
640 PeerConnectionObserver* observer) {
641 RTC_DCHECK(observer != nullptr);
642 if (!observer) {
643 return false;
644 }
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000645 observer_ = observer;
646
deadbeef653b8e02015-11-11 12:55:10 -0800647 port_allocator_ = allocator.Pass();
648
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000649 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
650 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000651 if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000652 return false;
653 }
deadbeef653b8e02015-11-11 12:55:10 -0800654
655 cricket::ServerAddresses cricket_stuns;
656 std::vector<cricket::RelayServerConfig> cricket_turns;
657 ConvertToCricketIceServers(stun_config, turn_config, &cricket_stuns,
658 &cricket_turns);
659 port_allocator_->SetIceServers(cricket_stuns, cricket_turns);
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000660
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000661 // To handle both internal and externally created port allocator, we will
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000662 // enable BUNDLE here.
braveyao@webrtc.org1732df62014-10-27 03:01:37 +0000663 int portallocator_flags = port_allocator_->flags();
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700664 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000665 cricket::PORTALLOCATOR_ENABLE_IPV6;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000666 bool value;
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000667 // If IPv6 flag was specified, we'll not override it by experiment.
deadbeefab9b2d12015-10-14 11:33:11 -0700668 if (FindConstraint(constraints, MediaConstraintsInterface::kEnableIPv6,
669 &value, nullptr)) {
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000670 if (!value) {
671 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000672 }
guoweis@webrtc.org2c1bcea2014-09-23 16:23:02 +0000673 } else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default") ==
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000674 "Disabled") {
675 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000676 }
677
Jiayang Liucac1b382015-04-30 12:35:24 -0700678 if (configuration.tcp_candidate_policy == kTcpCandidatePolicyDisabled) {
679 portallocator_flags |= cricket::PORTALLOCATOR_DISABLE_TCP;
680 LOG(LS_INFO) << "TCP candidates are disabled.";
681 }
682
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000683 port_allocator_->set_flags(portallocator_flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000684 // No step delay is used while allocating ports.
685 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
686
stefanc1aeaf02015-10-15 07:26:07 -0700687 media_controller_.reset(factory_->CreateMediaController());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000688
stefanc1aeaf02015-10-15 07:26:07 -0700689 remote_stream_factory_.reset(new RemoteMediaStreamFactory(
690 factory_->signaling_thread(), media_controller_->channel_manager()));
691
692 session_.reset(
693 new WebRtcSession(media_controller_.get(), factory_->signaling_thread(),
694 factory_->worker_thread(), port_allocator_.get()));
deadbeefab9b2d12015-10-14 11:33:11 -0700695 stats_.reset(new StatsCollector(this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000696
697 // Initialize the WebRtcSession. It creates transport channels etc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000698 if (!session_->Initialize(factory_->options(), constraints,
deadbeefab9b2d12015-10-14 11:33:11 -0700699 dtls_identity_store.Pass(), configuration)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000700 return false;
deadbeefab9b2d12015-10-14 11:33:11 -0700701 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000702
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000703 // Register PeerConnection as receiver of local ice candidates.
704 // All the callbacks will be posted to the application from PeerConnection.
705 session_->RegisterIceObserver(this);
706 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
deadbeefab9b2d12015-10-14 11:33:11 -0700707 session_->SignalVoiceChannelDestroyed.connect(
708 this, &PeerConnection::OnVoiceChannelDestroyed);
709 session_->SignalVideoChannelDestroyed.connect(
710 this, &PeerConnection::OnVideoChannelDestroyed);
711 session_->SignalDataChannelCreated.connect(
712 this, &PeerConnection::OnDataChannelCreated);
713 session_->SignalDataChannelDestroyed.connect(
714 this, &PeerConnection::OnDataChannelDestroyed);
715 session_->SignalDataChannelOpenMessage.connect(
716 this, &PeerConnection::OnDataChannelOpenMessage);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000717 return true;
718}
719
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000720rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000721PeerConnection::local_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -0700722 return local_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000723}
724
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000725rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000726PeerConnection::remote_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -0700727 return remote_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000728}
729
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +0000730bool PeerConnection::AddStream(MediaStreamInterface* local_stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000731 if (IsClosed()) {
732 return false;
733 }
deadbeefab9b2d12015-10-14 11:33:11 -0700734 if (!CanAddLocalMediaStream(local_streams_, local_stream)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000735 return false;
736 }
deadbeefab9b2d12015-10-14 11:33:11 -0700737
738 local_streams_->AddStream(local_stream);
739
deadbeefab9b2d12015-10-14 11:33:11 -0700740 for (const auto& track : local_stream->GetAudioTracks()) {
deadbeeffac06552015-11-25 11:26:01 -0800741 auto sender = FindSenderForTrack(track.get());
742 if (sender == senders_.end()) {
743 // Normal case; we've never seen this track before.
744 AudioRtpSender* new_sender = new AudioRtpSender(
745 track.get(), local_stream->label(), session_.get(), stats_.get());
746 senders_.push_back(new_sender);
747 // If the sender has already been configured in SDP, we call SetSsrc,
748 // which will connect the sender to the underlying transport. This can
749 // occur if a local session description that contains the ID of the sender
750 // is set before AddStream is called. It can also occur if the local
751 // session description is not changed and RemoveStream is called, and
752 // later AddStream is called again with the same stream.
753 const TrackInfo* track_info = FindTrackInfo(
754 local_audio_tracks_, local_stream->label(), track->id());
755 if (track_info) {
756 new_sender->SetSsrc(track_info->ssrc);
757 }
758 } else {
759 // We already have a sender for this track, so just change the stream_id
760 // so that it's correct in the next call to CreateOffer.
761 (*sender)->set_stream_id(local_stream->label());
deadbeefab9b2d12015-10-14 11:33:11 -0700762 }
763 }
764 for (const auto& track : local_stream->GetVideoTracks()) {
deadbeeffac06552015-11-25 11:26:01 -0800765 auto sender = FindSenderForTrack(track.get());
766 if (sender == senders_.end()) {
767 // Normal case; we've never seen this track before.
768 VideoRtpSender* new_sender = new VideoRtpSender(
769 track.get(), local_stream->label(), session_.get());
770 senders_.push_back(new_sender);
771 const TrackInfo* track_info = FindTrackInfo(
772 local_video_tracks_, local_stream->label(), track->id());
773 if (track_info) {
774 new_sender->SetSsrc(track_info->ssrc);
775 }
776 } else {
777 // We already have a sender for this track, so just change the stream_id
778 // so that it's correct in the next call to CreateOffer.
779 (*sender)->set_stream_id(local_stream->label());
deadbeefab9b2d12015-10-14 11:33:11 -0700780 }
781 }
782
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000783 stats_->AddStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000784 observer_->OnRenegotiationNeeded();
785 return true;
786}
787
deadbeefab9b2d12015-10-14 11:33:11 -0700788// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around
deadbeeffac06552015-11-25 11:26:01 -0800789// indefinitely, when we have unified plan SDP.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000790void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
deadbeefab9b2d12015-10-14 11:33:11 -0700791 for (const auto& track : local_stream->GetAudioTracks()) {
deadbeeffac06552015-11-25 11:26:01 -0800792 auto sender = FindSenderForTrack(track.get());
793 if (sender == senders_.end()) {
794 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
795 << " doesn't exist.";
796 continue;
deadbeefab9b2d12015-10-14 11:33:11 -0700797 }
deadbeeffac06552015-11-25 11:26:01 -0800798 (*sender)->Stop();
799 senders_.erase(sender);
deadbeefab9b2d12015-10-14 11:33:11 -0700800 }
801 for (const auto& track : local_stream->GetVideoTracks()) {
deadbeeffac06552015-11-25 11:26:01 -0800802 auto sender = FindSenderForTrack(track.get());
803 if (sender == senders_.end()) {
804 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
805 << " doesn't exist.";
806 continue;
deadbeefab9b2d12015-10-14 11:33:11 -0700807 }
deadbeeffac06552015-11-25 11:26:01 -0800808 (*sender)->Stop();
809 senders_.erase(sender);
deadbeefab9b2d12015-10-14 11:33:11 -0700810 }
811
812 local_streams_->RemoveStream(local_stream);
813
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000814 if (IsClosed()) {
815 return;
816 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000817 observer_->OnRenegotiationNeeded();
818}
819
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000820rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000821 AudioTrackInterface* track) {
822 if (!track) {
823 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
824 return NULL;
825 }
deadbeefab9b2d12015-10-14 11:33:11 -0700826 if (!local_streams_->FindAudioTrack(track->id())) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000827 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
828 return NULL;
829 }
830
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000831 rtc::scoped_refptr<DtmfSenderInterface> sender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000832 DtmfSender::Create(track, signaling_thread(), session_.get()));
833 if (!sender.get()) {
834 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
835 return NULL;
836 }
837 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
838}
839
deadbeeffac06552015-11-25 11:26:01 -0800840rtc::scoped_refptr<RtpSenderInterface> PeerConnection::CreateSender(
841 const std::string& kind) {
842 RtpSenderInterface* new_sender;
843 if (kind == MediaStreamTrackInterface::kAudioKind) {
844 new_sender = new AudioRtpSender(session_.get(), stats_.get());
845 } else if (kind == MediaStreamTrackInterface::kVideoKind) {
846 new_sender = new VideoRtpSender(session_.get());
847 } else {
848 LOG(LS_ERROR) << "CreateSender called with invalid kind: " << kind;
849 return rtc::scoped_refptr<RtpSenderInterface>();
850 }
851 senders_.push_back(new_sender);
852 return RtpSenderProxy::Create(signaling_thread(), new_sender);
853}
854
deadbeef70ab1a12015-09-28 16:53:55 -0700855std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders()
856 const {
857 std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders;
858 for (const auto& sender : senders_) {
859 senders.push_back(RtpSenderProxy::Create(signaling_thread(), sender.get()));
860 }
861 return senders;
862}
863
864std::vector<rtc::scoped_refptr<RtpReceiverInterface>>
865PeerConnection::GetReceivers() const {
866 std::vector<rtc::scoped_refptr<RtpReceiverInterface>> receivers;
867 for (const auto& receiver : receivers_) {
868 receivers.push_back(
869 RtpReceiverProxy::Create(signaling_thread(), receiver.get()));
870 }
871 return receivers;
872}
873
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000874bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000875 MediaStreamTrackInterface* track,
876 StatsOutputLevel level) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700877 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000878 if (!VERIFY(observer != NULL)) {
879 LOG(LS_ERROR) << "GetStats - observer is NULL.";
880 return false;
881 }
882
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000883 stats_->UpdateStats(level);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000884 signaling_thread()->Post(this, MSG_GETSTATS,
885 new GetStatsMsg(observer, track));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000886 return true;
887}
888
889PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
890 return signaling_state_;
891}
892
893PeerConnectionInterface::IceState PeerConnection::ice_state() {
894 return ice_state_;
895}
896
897PeerConnectionInterface::IceConnectionState
898PeerConnection::ice_connection_state() {
899 return ice_connection_state_;
900}
901
902PeerConnectionInterface::IceGatheringState
903PeerConnection::ice_gathering_state() {
904 return ice_gathering_state_;
905}
906
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000907rtc::scoped_refptr<DataChannelInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000908PeerConnection::CreateDataChannel(
909 const std::string& label,
910 const DataChannelInit* config) {
deadbeefab9b2d12015-10-14 11:33:11 -0700911 bool first_datachannel = !HasDataChannels();
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000912
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000913 rtc::scoped_ptr<InternalDataChannelInit> internal_config;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000914 if (config) {
915 internal_config.reset(new InternalDataChannelInit(*config));
916 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000917 rtc::scoped_refptr<DataChannelInterface> channel(
deadbeefab9b2d12015-10-14 11:33:11 -0700918 InternalCreateDataChannel(label, internal_config.get()));
919 if (!channel.get()) {
920 return nullptr;
921 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000922
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000923 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
924 // the first SCTP DataChannel.
925 if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
926 observer_->OnRenegotiationNeeded();
927 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000928
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000929 return DataChannelProxy::Create(signaling_thread(), channel.get());
930}
931
932void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
933 const MediaConstraintsInterface* constraints) {
deadbeefab9b2d12015-10-14 11:33:11 -0700934 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000935 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
936 return;
937 }
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000938 RTCOfferAnswerOptions options;
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000939
940 bool value;
941 size_t mandatory_constraints = 0;
942
943 if (FindConstraint(constraints,
944 MediaConstraintsInterface::kOfferToReceiveAudio,
945 &value,
946 &mandatory_constraints)) {
947 options.offer_to_receive_audio =
948 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
949 }
950
951 if (FindConstraint(constraints,
952 MediaConstraintsInterface::kOfferToReceiveVideo,
953 &value,
954 &mandatory_constraints)) {
955 options.offer_to_receive_video =
956 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
957 }
958
959 if (FindConstraint(constraints,
960 MediaConstraintsInterface::kVoiceActivityDetection,
961 &value,
962 &mandatory_constraints)) {
963 options.voice_activity_detection = value;
964 }
965
966 if (FindConstraint(constraints,
967 MediaConstraintsInterface::kIceRestart,
968 &value,
969 &mandatory_constraints)) {
970 options.ice_restart = value;
971 }
972
973 if (FindConstraint(constraints,
974 MediaConstraintsInterface::kUseRtpMux,
975 &value,
976 &mandatory_constraints)) {
977 options.use_rtp_mux = value;
978 }
979
980 CreateOffer(observer, options);
981}
982
983void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
984 const RTCOfferAnswerOptions& options) {
deadbeefab9b2d12015-10-14 11:33:11 -0700985 if (!VERIFY(observer != nullptr)) {
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000986 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
987 return;
988 }
deadbeefab9b2d12015-10-14 11:33:11 -0700989
990 cricket::MediaSessionOptions session_options;
991 if (!GetOptionsForOffer(options, &session_options)) {
992 std::string error = "CreateOffer called with invalid options.";
993 LOG(LS_ERROR) << error;
994 PostCreateSessionDescriptionFailure(observer, error);
995 return;
996 }
997
998 session_->CreateOffer(observer, options, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000999}
1000
1001void PeerConnection::CreateAnswer(
1002 CreateSessionDescriptionObserver* observer,
1003 const MediaConstraintsInterface* constraints) {
deadbeefab9b2d12015-10-14 11:33:11 -07001004 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001005 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
1006 return;
1007 }
deadbeefab9b2d12015-10-14 11:33:11 -07001008
1009 cricket::MediaSessionOptions session_options;
1010 if (!GetOptionsForAnswer(constraints, &session_options)) {
1011 std::string error = "CreateAnswer called with invalid constraints.";
1012 LOG(LS_ERROR) << error;
1013 PostCreateSessionDescriptionFailure(observer, error);
1014 return;
1015 }
1016
1017 session_->CreateAnswer(observer, constraints, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001018}
1019
1020void PeerConnection::SetLocalDescription(
1021 SetSessionDescriptionObserver* observer,
1022 SessionDescriptionInterface* desc) {
deadbeefab9b2d12015-10-14 11:33:11 -07001023 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001024 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
1025 return;
1026 }
1027 if (!desc) {
1028 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
1029 return;
1030 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001031 // Update stats here so that we have the most recent stats for tracks and
1032 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001033 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001034 std::string error;
1035 if (!session_->SetLocalDescription(desc, &error)) {
1036 PostSetSessionDescriptionFailure(observer, error);
1037 return;
1038 }
deadbeefab9b2d12015-10-14 11:33:11 -07001039
1040 // If setting the description decided our SSL role, allocate any necessary
1041 // SCTP sids.
1042 rtc::SSLRole role;
1043 if (session_->data_channel_type() == cricket::DCT_SCTP &&
1044 session_->GetSslRole(&role)) {
1045 AllocateSctpSids(role);
1046 }
1047
1048 // Update state and SSRC of local MediaStreams and DataChannels based on the
1049 // local session description.
1050 const cricket::ContentInfo* audio_content =
1051 GetFirstAudioContent(desc->description());
1052 if (audio_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001053 if (audio_content->rejected) {
1054 RemoveTracks(cricket::MEDIA_TYPE_AUDIO);
1055 } else {
1056 const cricket::AudioContentDescription* audio_desc =
1057 static_cast<const cricket::AudioContentDescription*>(
1058 audio_content->description);
1059 UpdateLocalTracks(audio_desc->streams(), audio_desc->type());
1060 }
deadbeefab9b2d12015-10-14 11:33:11 -07001061 }
1062
1063 const cricket::ContentInfo* video_content =
1064 GetFirstVideoContent(desc->description());
1065 if (video_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001066 if (video_content->rejected) {
1067 RemoveTracks(cricket::MEDIA_TYPE_VIDEO);
1068 } else {
1069 const cricket::VideoContentDescription* video_desc =
1070 static_cast<const cricket::VideoContentDescription*>(
1071 video_content->description);
1072 UpdateLocalTracks(video_desc->streams(), video_desc->type());
1073 }
deadbeefab9b2d12015-10-14 11:33:11 -07001074 }
1075
1076 const cricket::ContentInfo* data_content =
1077 GetFirstDataContent(desc->description());
1078 if (data_content) {
1079 const cricket::DataContentDescription* data_desc =
1080 static_cast<const cricket::DataContentDescription*>(
1081 data_content->description);
1082 if (rtc::starts_with(data_desc->protocol().data(),
1083 cricket::kMediaProtocolRtpPrefix)) {
1084 UpdateLocalRtpDataChannels(data_desc->streams());
1085 }
1086 }
1087
1088 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001089 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeefab9b2d12015-10-14 11:33:11 -07001090
deadbeefcbecd352015-09-23 11:50:27 -07001091 // MaybeStartGathering needs to be called after posting
1092 // MSG_SET_SESSIONDESCRIPTION_SUCCESS, so that we don't signal any candidates
1093 // before signaling that SetLocalDescription completed.
1094 session_->MaybeStartGathering();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001095}
1096
1097void PeerConnection::SetRemoteDescription(
1098 SetSessionDescriptionObserver* observer,
1099 SessionDescriptionInterface* desc) {
deadbeefab9b2d12015-10-14 11:33:11 -07001100 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001101 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
1102 return;
1103 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001104 if (!desc) {
1105 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
1106 return;
1107 }
1108 // Update stats here so that we have the most recent stats for tracks and
1109 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001110 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001111 std::string error;
1112 if (!session_->SetRemoteDescription(desc, &error)) {
1113 PostSetSessionDescriptionFailure(observer, error);
1114 return;
1115 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001116
deadbeefab9b2d12015-10-14 11:33:11 -07001117 // If setting the description decided our SSL role, allocate any necessary
1118 // SCTP sids.
1119 rtc::SSLRole role;
1120 if (session_->data_channel_type() == cricket::DCT_SCTP &&
1121 session_->GetSslRole(&role)) {
1122 AllocateSctpSids(role);
1123 }
1124
1125 const cricket::SessionDescription* remote_desc = desc->description();
1126
1127 // We wait to signal new streams until we finish processing the description,
1128 // since only at that point will new streams have all their tracks.
1129 rtc::scoped_refptr<StreamCollection> new_streams(StreamCollection::Create());
1130
1131 // Find all audio rtp streams and create corresponding remote AudioTracks
1132 // and MediaStreams.
1133 const cricket::ContentInfo* audio_content = GetFirstAudioContent(remote_desc);
1134 if (audio_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001135 if (audio_content->rejected) {
1136 RemoveTracks(cricket::MEDIA_TYPE_AUDIO);
1137 } else {
1138 const cricket::AudioContentDescription* desc =
1139 static_cast<const cricket::AudioContentDescription*>(
1140 audio_content->description);
1141 UpdateRemoteStreamsList(GetActiveStreams(desc), desc->type(),
1142 new_streams);
1143 remote_info_.default_audio_track_needed =
1144 !remote_desc->msid_supported() && desc->streams().empty() &&
1145 MediaContentDirectionHasSend(desc->direction());
1146 }
deadbeefab9b2d12015-10-14 11:33:11 -07001147 }
1148
1149 // Find all video rtp streams and create corresponding remote VideoTracks
1150 // and MediaStreams.
1151 const cricket::ContentInfo* video_content = GetFirstVideoContent(remote_desc);
1152 if (video_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001153 if (video_content->rejected) {
1154 RemoveTracks(cricket::MEDIA_TYPE_VIDEO);
1155 } else {
1156 const cricket::VideoContentDescription* desc =
1157 static_cast<const cricket::VideoContentDescription*>(
1158 video_content->description);
1159 UpdateRemoteStreamsList(GetActiveStreams(desc), desc->type(),
1160 new_streams);
1161 remote_info_.default_video_track_needed =
1162 !remote_desc->msid_supported() && desc->streams().empty() &&
1163 MediaContentDirectionHasSend(desc->direction());
1164 }
deadbeefab9b2d12015-10-14 11:33:11 -07001165 }
1166
1167 // Update the DataChannels with the information from the remote peer.
1168 const cricket::ContentInfo* data_content = GetFirstDataContent(remote_desc);
1169 if (data_content) {
deadbeef5e97fb52015-10-15 12:49:08 -07001170 const cricket::DataContentDescription* desc =
deadbeefab9b2d12015-10-14 11:33:11 -07001171 static_cast<const cricket::DataContentDescription*>(
1172 data_content->description);
deadbeef5e97fb52015-10-15 12:49:08 -07001173 if (rtc::starts_with(desc->protocol().data(),
deadbeefab9b2d12015-10-14 11:33:11 -07001174 cricket::kMediaProtocolRtpPrefix)) {
deadbeef5e97fb52015-10-15 12:49:08 -07001175 UpdateRemoteRtpDataChannels(GetActiveStreams(desc));
deadbeefab9b2d12015-10-14 11:33:11 -07001176 }
1177 }
1178
1179 // Iterate new_streams and notify the observer about new MediaStreams.
1180 for (size_t i = 0; i < new_streams->count(); ++i) {
1181 MediaStreamInterface* new_stream = new_streams->at(i);
1182 stats_->AddStream(new_stream);
1183 observer_->OnAddStream(new_stream);
1184 }
1185
1186 // Find removed MediaStreams.
1187 if (remote_info_.IsDefaultMediaStreamNeeded() &&
1188 remote_streams_->find(kDefaultStreamLabel) != nullptr) {
1189 // The default media stream already exists. No need to do anything.
1190 } else {
1191 UpdateEndedRemoteMediaStreams();
1192 remote_info_.msid_supported |= remote_streams_->count() > 0;
1193 }
1194 MaybeCreateDefaultStream();
1195
1196 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1197 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeeffc648b62015-10-13 16:42:33 -07001198}
1199
deadbeefa67696b2015-09-29 11:56:26 -07001200bool PeerConnection::SetConfiguration(const RTCConfiguration& config) {
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001201 if (port_allocator_) {
1202 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
1203 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
1204 if (!ParseIceServers(config.servers, &stuns, &turns)) {
1205 return false;
1206 }
1207
deadbeef653b8e02015-11-11 12:55:10 -08001208 cricket::ServerAddresses cricket_stuns;
1209 std::vector<cricket::RelayServerConfig> cricket_turns;
1210 ConvertToCricketIceServers(stuns, turns, &cricket_stuns, &cricket_turns);
1211 port_allocator_->SetIceServers(cricket_stuns, cricket_turns);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001212 }
honghaiz1f429e32015-09-28 07:57:34 -07001213 session_->SetIceConfig(session_->ParseIceConfig(config));
mallinath@webrtc.org3d81b1b2014-09-09 14:38:10 +00001214 return session_->SetIceTransports(config.type);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001215}
1216
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001217bool PeerConnection::AddIceCandidate(
1218 const IceCandidateInterface* ice_candidate) {
1219 return session_->ProcessIceMessage(ice_candidate);
1220}
1221
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001222void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
1223 uma_observer_ = observer;
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +00001224
1225 if (session_) {
1226 session_->set_metrics_observer(uma_observer_);
1227 }
1228
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001229 // Send information about IPv4/IPv6 status.
1230 if (uma_observer_ && port_allocator_) {
1231 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001232 uma_observer_->IncrementEnumCounter(
1233 kEnumCounterAddressFamily, kPeerConnection_IPv6,
1234 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgb445f262014-05-23 22:19:37 +00001235 } else {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001236 uma_observer_->IncrementEnumCounter(
1237 kEnumCounterAddressFamily, kPeerConnection_IPv4,
1238 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001239 }
1240 }
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001241}
1242
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001243const SessionDescriptionInterface* PeerConnection::local_description() const {
1244 return session_->local_description();
1245}
1246
1247const SessionDescriptionInterface* PeerConnection::remote_description() const {
1248 return session_->remote_description();
1249}
1250
1251void PeerConnection::Close() {
1252 // Update stats here so that we have the most recent stats for tracks and
1253 // streams before the channels are closed.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001254 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001255
deadbeefd59daf82015-10-14 15:02:44 -07001256 session_->Close();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001257}
1258
deadbeefd59daf82015-10-14 15:02:44 -07001259void PeerConnection::OnSessionStateChange(WebRtcSession* /*session*/,
1260 WebRtcSession::State state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001261 switch (state) {
deadbeefd59daf82015-10-14 15:02:44 -07001262 case WebRtcSession::STATE_INIT:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001263 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001264 break;
deadbeefd59daf82015-10-14 15:02:44 -07001265 case WebRtcSession::STATE_SENTOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001266 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
1267 break;
deadbeefd59daf82015-10-14 15:02:44 -07001268 case WebRtcSession::STATE_SENTPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001269 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
1270 break;
deadbeefd59daf82015-10-14 15:02:44 -07001271 case WebRtcSession::STATE_RECEIVEDOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001272 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
1273 break;
deadbeefd59daf82015-10-14 15:02:44 -07001274 case WebRtcSession::STATE_RECEIVEDPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001275 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
1276 break;
deadbeefd59daf82015-10-14 15:02:44 -07001277 case WebRtcSession::STATE_INPROGRESS:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001278 ChangeSignalingState(PeerConnectionInterface::kStable);
1279 break;
deadbeefd59daf82015-10-14 15:02:44 -07001280 case WebRtcSession::STATE_CLOSED:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001281 ChangeSignalingState(PeerConnectionInterface::kClosed);
1282 break;
1283 default:
1284 break;
1285 }
1286}
1287
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001288void PeerConnection::OnMessage(rtc::Message* msg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001289 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001290 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
1291 SetSessionDescriptionMsg* param =
1292 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1293 param->observer->OnSuccess();
1294 delete param;
1295 break;
1296 }
1297 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
1298 SetSessionDescriptionMsg* param =
1299 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1300 param->observer->OnFailure(param->error);
1301 delete param;
1302 break;
1303 }
deadbeefab9b2d12015-10-14 11:33:11 -07001304 case MSG_CREATE_SESSIONDESCRIPTION_FAILED: {
1305 CreateSessionDescriptionMsg* param =
1306 static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
1307 param->observer->OnFailure(param->error);
1308 delete param;
1309 break;
1310 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001311 case MSG_GETSTATS: {
1312 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +00001313 StatsReports reports;
1314 stats_->GetStats(param->track, &reports);
1315 param->observer->OnComplete(reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001316 delete param;
1317 break;
1318 }
deadbeef38686922015-12-07 15:32:23 -08001319 case MSG_DELETE: {
1320 delete msg->pdata;
1321 break;
1322 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001323 default:
deadbeef0a6c4ca2015-10-06 11:38:28 -07001324 RTC_DCHECK(false && "Not implemented");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001325 break;
1326 }
1327}
1328
deadbeefab9b2d12015-10-14 11:33:11 -07001329void PeerConnection::CreateAudioReceiver(MediaStreamInterface* stream,
1330 AudioTrackInterface* audio_track,
1331 uint32_t ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -07001332 receivers_.push_back(new AudioRtpReceiver(audio_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001333}
1334
deadbeefab9b2d12015-10-14 11:33:11 -07001335void PeerConnection::CreateVideoReceiver(MediaStreamInterface* stream,
1336 VideoTrackInterface* video_track,
1337 uint32_t ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -07001338 receivers_.push_back(new VideoRtpReceiver(video_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001339}
1340
deadbeef70ab1a12015-09-28 16:53:55 -07001341// TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote
1342// description.
deadbeefab9b2d12015-10-14 11:33:11 -07001343void PeerConnection::DestroyAudioReceiver(MediaStreamInterface* stream,
1344 AudioTrackInterface* audio_track) {
deadbeef70ab1a12015-09-28 16:53:55 -07001345 auto it = FindReceiverForTrack(audio_track);
1346 if (it == receivers_.end()) {
1347 LOG(LS_WARNING) << "RtpReceiver for track with id " << audio_track->id()
1348 << " doesn't exist.";
1349 } else {
1350 (*it)->Stop();
1351 receivers_.erase(it);
1352 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001353}
1354
deadbeefab9b2d12015-10-14 11:33:11 -07001355void PeerConnection::DestroyVideoReceiver(MediaStreamInterface* stream,
1356 VideoTrackInterface* video_track) {
deadbeef70ab1a12015-09-28 16:53:55 -07001357 auto it = FindReceiverForTrack(video_track);
1358 if (it == receivers_.end()) {
1359 LOG(LS_WARNING) << "RtpReceiver for track with id " << video_track->id()
1360 << " doesn't exist.";
1361 } else {
1362 (*it)->Stop();
1363 receivers_.erase(it);
1364 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001365}
deadbeef70ab1a12015-09-28 16:53:55 -07001366
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001367void PeerConnection::OnIceConnectionChange(
1368 PeerConnectionInterface::IceConnectionState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001369 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefcbecd352015-09-23 11:50:27 -07001370 // After transitioning to "closed", ignore any additional states from
1371 // WebRtcSession (such as "disconnected").
deadbeefab9b2d12015-10-14 11:33:11 -07001372 if (IsClosed()) {
deadbeefcbecd352015-09-23 11:50:27 -07001373 return;
1374 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001375 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001376 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001377}
1378
1379void PeerConnection::OnIceGatheringChange(
1380 PeerConnectionInterface::IceGatheringState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001381 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001382 if (IsClosed()) {
1383 return;
1384 }
1385 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001386 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001387}
1388
1389void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001390 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001391 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001392}
1393
1394void PeerConnection::OnIceComplete() {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001395 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001396 observer_->OnIceComplete();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001397}
1398
Peter Thatcher54360512015-07-08 11:08:35 -07001399void PeerConnection::OnIceConnectionReceivingChange(bool receiving) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001400 RTC_DCHECK(signaling_thread()->IsCurrent());
Peter Thatcher54360512015-07-08 11:08:35 -07001401 observer_->OnIceConnectionReceivingChange(receiving);
1402}
1403
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001404void PeerConnection::ChangeSignalingState(
1405 PeerConnectionInterface::SignalingState signaling_state) {
1406 signaling_state_ = signaling_state;
1407 if (signaling_state == kClosed) {
1408 ice_connection_state_ = kIceConnectionClosed;
1409 observer_->OnIceConnectionChange(ice_connection_state_);
1410 if (ice_gathering_state_ != kIceGatheringComplete) {
1411 ice_gathering_state_ = kIceGatheringComplete;
1412 observer_->OnIceGatheringChange(ice_gathering_state_);
1413 }
1414 }
1415 observer_->OnSignalingChange(signaling_state_);
1416 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
1417}
1418
deadbeefab9b2d12015-10-14 11:33:11 -07001419void PeerConnection::PostSetSessionDescriptionFailure(
1420 SetSessionDescriptionObserver* observer,
1421 const std::string& error) {
1422 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1423 msg->error = error;
1424 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
1425}
1426
1427void PeerConnection::PostCreateSessionDescriptionFailure(
1428 CreateSessionDescriptionObserver* observer,
1429 const std::string& error) {
1430 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
1431 msg->error = error;
1432 signaling_thread()->Post(this, MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
1433}
1434
1435bool PeerConnection::GetOptionsForOffer(
1436 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
1437 cricket::MediaSessionOptions* session_options) {
deadbeefab9b2d12015-10-14 11:33:11 -07001438 if (!ConvertRtcOptionsForOffer(rtc_options, session_options)) {
1439 return false;
1440 }
1441
deadbeeffac06552015-11-25 11:26:01 -08001442 AddSendStreams(session_options, senders_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001443 // Offer to receive audio/video if the constraint is not set and there are
1444 // send streams, or we're currently receiving.
1445 if (rtc_options.offer_to_receive_audio == RTCOfferAnswerOptions::kUndefined) {
1446 session_options->recv_audio =
1447 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_AUDIO) ||
1448 !remote_audio_tracks_.empty();
1449 }
1450 if (rtc_options.offer_to_receive_video == RTCOfferAnswerOptions::kUndefined) {
1451 session_options->recv_video =
1452 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_VIDEO) ||
1453 !remote_video_tracks_.empty();
1454 }
1455 session_options->bundle_enabled =
1456 session_options->bundle_enabled &&
1457 (session_options->has_audio() || session_options->has_video() ||
1458 session_options->has_data());
1459
deadbeefab9b2d12015-10-14 11:33:11 -07001460 if (session_->data_channel_type() == cricket::DCT_SCTP && HasDataChannels()) {
1461 session_options->data_channel_type = cricket::DCT_SCTP;
1462 }
1463 return true;
1464}
1465
1466bool PeerConnection::GetOptionsForAnswer(
1467 const MediaConstraintsInterface* constraints,
1468 cricket::MediaSessionOptions* session_options) {
deadbeefab9b2d12015-10-14 11:33:11 -07001469 session_options->recv_audio = false;
1470 session_options->recv_video = false;
deadbeefab9b2d12015-10-14 11:33:11 -07001471 if (!ParseConstraintsForAnswer(constraints, session_options)) {
1472 return false;
1473 }
1474
deadbeeffac06552015-11-25 11:26:01 -08001475 AddSendStreams(session_options, senders_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001476 session_options->bundle_enabled =
1477 session_options->bundle_enabled &&
1478 (session_options->has_audio() || session_options->has_video() ||
1479 session_options->has_data());
1480
deadbeefab9b2d12015-10-14 11:33:11 -07001481 // RTP data channel is handled in MediaSessionOptions::AddStream. SCTP streams
1482 // are not signaled in the SDP so does not go through that path and must be
1483 // handled here.
1484 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1485 session_options->data_channel_type = cricket::DCT_SCTP;
1486 }
1487 return true;
1488}
1489
deadbeeffaac4972015-11-12 15:33:07 -08001490void PeerConnection::RemoveTracks(cricket::MediaType media_type) {
1491 UpdateLocalTracks(std::vector<cricket::StreamParams>(), media_type);
1492 UpdateRemoteStreamsList(std::vector<cricket::StreamParams>(), media_type,
1493 nullptr);
1494}
1495
deadbeefab9b2d12015-10-14 11:33:11 -07001496void PeerConnection::UpdateRemoteStreamsList(
1497 const cricket::StreamParamsVec& streams,
1498 cricket::MediaType media_type,
1499 StreamCollection* new_streams) {
1500 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1501
1502 // Find removed tracks. I.e., tracks where the track id or ssrc don't match
deadbeeffac06552015-11-25 11:26:01 -08001503 // the new StreamParam.
deadbeefab9b2d12015-10-14 11:33:11 -07001504 auto track_it = current_tracks->begin();
1505 while (track_it != current_tracks->end()) {
1506 const TrackInfo& info = *track_it;
1507 const cricket::StreamParams* params =
1508 cricket::GetStreamBySsrc(streams, info.ssrc);
1509 if (!params || params->id != info.track_id) {
1510 OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
1511 track_it = current_tracks->erase(track_it);
1512 } else {
1513 ++track_it;
1514 }
1515 }
1516
1517 // Find new and active tracks.
1518 for (const cricket::StreamParams& params : streams) {
1519 // The sync_label is the MediaStream label and the |stream.id| is the
1520 // track id.
1521 const std::string& stream_label = params.sync_label;
1522 const std::string& track_id = params.id;
1523 uint32_t ssrc = params.first_ssrc();
1524
1525 rtc::scoped_refptr<MediaStreamInterface> stream =
1526 remote_streams_->find(stream_label);
1527 if (!stream) {
1528 // This is a new MediaStream. Create a new remote MediaStream.
1529 stream = remote_stream_factory_->CreateMediaStream(stream_label);
1530 remote_streams_->AddStream(stream);
1531 new_streams->AddStream(stream);
1532 }
1533
1534 const TrackInfo* track_info =
1535 FindTrackInfo(*current_tracks, stream_label, track_id);
1536 if (!track_info) {
1537 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1538 OnRemoteTrackSeen(stream_label, track_id, ssrc, media_type);
1539 }
1540 }
1541}
1542
1543void PeerConnection::OnRemoteTrackSeen(const std::string& stream_label,
1544 const std::string& track_id,
1545 uint32_t ssrc,
1546 cricket::MediaType media_type) {
1547 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1548
1549 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1550 AudioTrackInterface* audio_track =
1551 remote_stream_factory_->AddAudioTrack(stream, track_id);
1552 CreateAudioReceiver(stream, audio_track, ssrc);
1553 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1554 VideoTrackInterface* video_track =
1555 remote_stream_factory_->AddVideoTrack(stream, track_id);
1556 CreateVideoReceiver(stream, video_track, ssrc);
1557 } else {
1558 RTC_DCHECK(false && "Invalid media type");
1559 }
1560}
1561
1562void PeerConnection::OnRemoteTrackRemoved(const std::string& stream_label,
1563 const std::string& track_id,
1564 cricket::MediaType media_type) {
1565 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1566
1567 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1568 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1569 stream->FindAudioTrack(track_id);
1570 if (audio_track) {
1571 audio_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1572 stream->RemoveTrack(audio_track);
1573 DestroyAudioReceiver(stream, audio_track);
1574 }
1575 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1576 rtc::scoped_refptr<VideoTrackInterface> video_track =
1577 stream->FindVideoTrack(track_id);
1578 if (video_track) {
1579 video_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1580 stream->RemoveTrack(video_track);
1581 DestroyVideoReceiver(stream, video_track);
1582 }
1583 } else {
1584 ASSERT(false && "Invalid media type");
1585 }
1586}
1587
1588void PeerConnection::UpdateEndedRemoteMediaStreams() {
1589 std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams_to_remove;
1590 for (size_t i = 0; i < remote_streams_->count(); ++i) {
1591 MediaStreamInterface* stream = remote_streams_->at(i);
1592 if (stream->GetAudioTracks().empty() && stream->GetVideoTracks().empty()) {
1593 streams_to_remove.push_back(stream);
1594 }
1595 }
1596
1597 for (const auto& stream : streams_to_remove) {
1598 remote_streams_->RemoveStream(stream);
1599 observer_->OnRemoveStream(stream);
1600 }
1601}
1602
1603void PeerConnection::MaybeCreateDefaultStream() {
1604 if (!remote_info_.IsDefaultMediaStreamNeeded()) {
1605 return;
1606 }
1607
1608 bool default_created = false;
1609
1610 rtc::scoped_refptr<MediaStreamInterface> default_remote_stream =
1611 remote_streams_->find(kDefaultStreamLabel);
1612 if (default_remote_stream == nullptr) {
1613 default_created = true;
1614 default_remote_stream =
1615 remote_stream_factory_->CreateMediaStream(kDefaultStreamLabel);
1616 remote_streams_->AddStream(default_remote_stream);
1617 }
1618 if (remote_info_.default_audio_track_needed &&
1619 default_remote_stream->GetAudioTracks().size() == 0) {
1620 remote_audio_tracks_.push_back(
1621 TrackInfo(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0));
1622 OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0,
1623 cricket::MEDIA_TYPE_AUDIO);
1624 }
1625 if (remote_info_.default_video_track_needed &&
1626 default_remote_stream->GetVideoTracks().size() == 0) {
1627 remote_video_tracks_.push_back(
1628 TrackInfo(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0));
1629 OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0,
1630 cricket::MEDIA_TYPE_VIDEO);
1631 }
1632 if (default_created) {
1633 stats_->AddStream(default_remote_stream);
1634 observer_->OnAddStream(default_remote_stream);
1635 }
1636}
1637
1638void PeerConnection::EndRemoteTracks(cricket::MediaType media_type) {
1639 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1640 for (TrackInfos::iterator track_it = current_tracks->begin();
1641 track_it != current_tracks->end(); ++track_it) {
1642 const TrackInfo& info = *track_it;
1643 MediaStreamInterface* stream = remote_streams_->find(info.stream_label);
1644 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1645 AudioTrackInterface* track = stream->FindAudioTrack(info.track_id);
1646 // There's no guarantee the track is still available, e.g. the track may
1647 // have been removed from the stream by javascript.
1648 if (track) {
1649 track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1650 }
1651 }
1652 if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1653 VideoTrackInterface* track = stream->FindVideoTrack(info.track_id);
1654 // There's no guarantee the track is still available, e.g. the track may
1655 // have been removed from the stream by javascript.
1656 if (track) {
1657 track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1658 }
1659 }
1660 }
1661}
1662
1663void PeerConnection::UpdateLocalTracks(
1664 const std::vector<cricket::StreamParams>& streams,
1665 cricket::MediaType media_type) {
1666 TrackInfos* current_tracks = GetLocalTracks(media_type);
1667
1668 // Find removed tracks. I.e., tracks where the track id, stream label or ssrc
1669 // don't match the new StreamParam.
1670 TrackInfos::iterator track_it = current_tracks->begin();
1671 while (track_it != current_tracks->end()) {
1672 const TrackInfo& info = *track_it;
1673 const cricket::StreamParams* params =
1674 cricket::GetStreamBySsrc(streams, info.ssrc);
1675 if (!params || params->id != info.track_id ||
1676 params->sync_label != info.stream_label) {
1677 OnLocalTrackRemoved(info.stream_label, info.track_id, info.ssrc,
1678 media_type);
1679 track_it = current_tracks->erase(track_it);
1680 } else {
1681 ++track_it;
1682 }
1683 }
1684
1685 // Find new and active tracks.
1686 for (const cricket::StreamParams& params : streams) {
1687 // The sync_label is the MediaStream label and the |stream.id| is the
1688 // track id.
1689 const std::string& stream_label = params.sync_label;
1690 const std::string& track_id = params.id;
1691 uint32_t ssrc = params.first_ssrc();
1692 const TrackInfo* track_info =
1693 FindTrackInfo(*current_tracks, stream_label, track_id);
1694 if (!track_info) {
1695 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1696 OnLocalTrackSeen(stream_label, track_id, params.first_ssrc(), media_type);
1697 }
1698 }
1699}
1700
1701void PeerConnection::OnLocalTrackSeen(const std::string& stream_label,
1702 const std::string& track_id,
1703 uint32_t ssrc,
1704 cricket::MediaType media_type) {
deadbeeffac06552015-11-25 11:26:01 -08001705 RtpSenderInterface* sender = FindSenderById(track_id);
1706 if (!sender) {
1707 LOG(LS_WARNING) << "An unknown RtpSender with id " << track_id
1708 << " has been configured in the local description.";
deadbeefab9b2d12015-10-14 11:33:11 -07001709 return;
1710 }
1711
deadbeeffac06552015-11-25 11:26:01 -08001712 if (sender->media_type() != media_type) {
1713 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
1714 << " description with an unexpected media type.";
1715 return;
deadbeefab9b2d12015-10-14 11:33:11 -07001716 }
deadbeeffac06552015-11-25 11:26:01 -08001717
1718 sender->set_stream_id(stream_label);
1719 sender->SetSsrc(ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -07001720}
1721
1722void PeerConnection::OnLocalTrackRemoved(const std::string& stream_label,
1723 const std::string& track_id,
1724 uint32_t ssrc,
1725 cricket::MediaType media_type) {
deadbeeffac06552015-11-25 11:26:01 -08001726 RtpSenderInterface* sender = FindSenderById(track_id);
1727 if (!sender) {
1728 // This is the normal case. I.e., RemoveStream has been called and the
deadbeefab9b2d12015-10-14 11:33:11 -07001729 // SessionDescriptions has been renegotiated.
1730 return;
1731 }
deadbeeffac06552015-11-25 11:26:01 -08001732
1733 // A sender has been removed from the SessionDescription but it's still
1734 // associated with the PeerConnection. This only occurs if the SDP doesn't
1735 // match with the calls to CreateSender, AddStream and RemoveStream.
1736 if (sender->media_type() != media_type) {
1737 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
1738 << " description with an unexpected media type.";
1739 return;
deadbeefab9b2d12015-10-14 11:33:11 -07001740 }
deadbeeffac06552015-11-25 11:26:01 -08001741
1742 sender->SetSsrc(0);
deadbeefab9b2d12015-10-14 11:33:11 -07001743}
1744
1745void PeerConnection::UpdateLocalRtpDataChannels(
1746 const cricket::StreamParamsVec& streams) {
1747 std::vector<std::string> existing_channels;
1748
1749 // Find new and active data channels.
1750 for (const cricket::StreamParams& params : streams) {
1751 // |it->sync_label| is actually the data channel label. The reason is that
1752 // we use the same naming of data channels as we do for
1753 // MediaStreams and Tracks.
1754 // For MediaStreams, the sync_label is the MediaStream label and the
1755 // track label is the same as |streamid|.
1756 const std::string& channel_label = params.sync_label;
1757 auto data_channel_it = rtp_data_channels_.find(channel_label);
1758 if (!VERIFY(data_channel_it != rtp_data_channels_.end())) {
1759 continue;
1760 }
1761 // Set the SSRC the data channel should use for sending.
1762 data_channel_it->second->SetSendSsrc(params.first_ssrc());
1763 existing_channels.push_back(data_channel_it->first);
1764 }
1765
1766 UpdateClosingRtpDataChannels(existing_channels, true);
1767}
1768
1769void PeerConnection::UpdateRemoteRtpDataChannels(
1770 const cricket::StreamParamsVec& streams) {
1771 std::vector<std::string> existing_channels;
1772
1773 // Find new and active data channels.
1774 for (const cricket::StreamParams& params : streams) {
1775 // The data channel label is either the mslabel or the SSRC if the mslabel
1776 // does not exist. Ex a=ssrc:444330170 mslabel:test1.
1777 std::string label = params.sync_label.empty()
1778 ? rtc::ToString(params.first_ssrc())
1779 : params.sync_label;
1780 auto data_channel_it = rtp_data_channels_.find(label);
1781 if (data_channel_it == rtp_data_channels_.end()) {
1782 // This is a new data channel.
1783 CreateRemoteRtpDataChannel(label, params.first_ssrc());
1784 } else {
1785 data_channel_it->second->SetReceiveSsrc(params.first_ssrc());
1786 }
1787 existing_channels.push_back(label);
1788 }
1789
1790 UpdateClosingRtpDataChannels(existing_channels, false);
1791}
1792
1793void PeerConnection::UpdateClosingRtpDataChannels(
1794 const std::vector<std::string>& active_channels,
1795 bool is_local_update) {
1796 auto it = rtp_data_channels_.begin();
1797 while (it != rtp_data_channels_.end()) {
1798 DataChannel* data_channel = it->second;
1799 if (std::find(active_channels.begin(), active_channels.end(),
1800 data_channel->label()) != active_channels.end()) {
1801 ++it;
1802 continue;
1803 }
1804
1805 if (is_local_update) {
1806 data_channel->SetSendSsrc(0);
1807 } else {
1808 data_channel->RemotePeerRequestClose();
1809 }
1810
1811 if (data_channel->state() == DataChannel::kClosed) {
1812 rtp_data_channels_.erase(it);
1813 it = rtp_data_channels_.begin();
1814 } else {
1815 ++it;
1816 }
1817 }
1818}
1819
1820void PeerConnection::CreateRemoteRtpDataChannel(const std::string& label,
1821 uint32_t remote_ssrc) {
1822 rtc::scoped_refptr<DataChannel> channel(
1823 InternalCreateDataChannel(label, nullptr));
1824 if (!channel.get()) {
1825 LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
1826 << "CreateDataChannel failed.";
1827 return;
1828 }
1829 channel->SetReceiveSsrc(remote_ssrc);
1830 observer_->OnDataChannel(
1831 DataChannelProxy::Create(signaling_thread(), channel));
1832}
1833
1834rtc::scoped_refptr<DataChannel> PeerConnection::InternalCreateDataChannel(
1835 const std::string& label,
1836 const InternalDataChannelInit* config) {
1837 if (IsClosed()) {
1838 return nullptr;
1839 }
1840 if (session_->data_channel_type() == cricket::DCT_NONE) {
1841 LOG(LS_ERROR)
1842 << "InternalCreateDataChannel: Data is not supported in this call.";
1843 return nullptr;
1844 }
1845 InternalDataChannelInit new_config =
1846 config ? (*config) : InternalDataChannelInit();
1847 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1848 if (new_config.id < 0) {
1849 rtc::SSLRole role;
1850 if (session_->GetSslRole(&role) &&
1851 !sid_allocator_.AllocateSid(role, &new_config.id)) {
1852 LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel.";
1853 return nullptr;
1854 }
1855 } else if (!sid_allocator_.ReserveSid(new_config.id)) {
1856 LOG(LS_ERROR) << "Failed to create a SCTP data channel "
1857 << "because the id is already in use or out of range.";
1858 return nullptr;
1859 }
1860 }
1861
1862 rtc::scoped_refptr<DataChannel> channel(DataChannel::Create(
1863 session_.get(), session_->data_channel_type(), label, new_config));
1864 if (!channel) {
1865 sid_allocator_.ReleaseSid(new_config.id);
1866 return nullptr;
1867 }
1868
1869 if (channel->data_channel_type() == cricket::DCT_RTP) {
1870 if (rtp_data_channels_.find(channel->label()) != rtp_data_channels_.end()) {
1871 LOG(LS_ERROR) << "DataChannel with label " << channel->label()
1872 << " already exists.";
1873 return nullptr;
1874 }
1875 rtp_data_channels_[channel->label()] = channel;
1876 } else {
1877 RTC_DCHECK(channel->data_channel_type() == cricket::DCT_SCTP);
1878 sctp_data_channels_.push_back(channel);
1879 channel->SignalClosed.connect(this,
1880 &PeerConnection::OnSctpDataChannelClosed);
1881 }
1882
1883 return channel;
1884}
1885
1886bool PeerConnection::HasDataChannels() const {
1887 return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
1888}
1889
1890void PeerConnection::AllocateSctpSids(rtc::SSLRole role) {
1891 for (const auto& channel : sctp_data_channels_) {
1892 if (channel->id() < 0) {
1893 int sid;
1894 if (!sid_allocator_.AllocateSid(role, &sid)) {
1895 LOG(LS_ERROR) << "Failed to allocate SCTP sid.";
1896 continue;
1897 }
1898 channel->SetSctpSid(sid);
1899 }
1900 }
1901}
1902
1903void PeerConnection::OnSctpDataChannelClosed(DataChannel* channel) {
1904 for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end();
1905 ++it) {
1906 if (it->get() == channel) {
1907 if (channel->id() >= 0) {
1908 sid_allocator_.ReleaseSid(channel->id());
1909 }
deadbeef38686922015-12-07 15:32:23 -08001910 // Since this method is triggered by a signal from the DataChannel,
1911 // we can't free it directly here; we need to free it asynchronously.
1912 signaling_thread()->Post(
1913 this, MSG_DELETE,
1914 new rtc::TypedMessageData<rtc::scoped_refptr<DataChannel>>(channel));
deadbeefab9b2d12015-10-14 11:33:11 -07001915 sctp_data_channels_.erase(it);
1916 return;
1917 }
1918 }
1919}
1920
1921void PeerConnection::OnVoiceChannelDestroyed() {
1922 EndRemoteTracks(cricket::MEDIA_TYPE_AUDIO);
1923}
1924
1925void PeerConnection::OnVideoChannelDestroyed() {
1926 EndRemoteTracks(cricket::MEDIA_TYPE_VIDEO);
1927}
1928
1929void PeerConnection::OnDataChannelCreated() {
1930 for (const auto& channel : sctp_data_channels_) {
1931 channel->OnTransportChannelCreated();
1932 }
1933}
1934
1935void PeerConnection::OnDataChannelDestroyed() {
1936 // Use a temporary copy of the RTP/SCTP DataChannel list because the
1937 // DataChannel may callback to us and try to modify the list.
1938 std::map<std::string, rtc::scoped_refptr<DataChannel>> temp_rtp_dcs;
1939 temp_rtp_dcs.swap(rtp_data_channels_);
1940 for (const auto& kv : temp_rtp_dcs) {
1941 kv.second->OnTransportChannelDestroyed();
1942 }
1943
1944 std::vector<rtc::scoped_refptr<DataChannel>> temp_sctp_dcs;
1945 temp_sctp_dcs.swap(sctp_data_channels_);
1946 for (const auto& channel : temp_sctp_dcs) {
1947 channel->OnTransportChannelDestroyed();
1948 }
1949}
1950
1951void PeerConnection::OnDataChannelOpenMessage(
1952 const std::string& label,
1953 const InternalDataChannelInit& config) {
1954 rtc::scoped_refptr<DataChannel> channel(
1955 InternalCreateDataChannel(label, &config));
1956 if (!channel.get()) {
1957 LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
1958 return;
1959 }
1960
1961 observer_->OnDataChannel(
1962 DataChannelProxy::Create(signaling_thread(), channel));
1963}
1964
deadbeeffac06552015-11-25 11:26:01 -08001965RtpSenderInterface* PeerConnection::FindSenderById(const std::string& id) {
1966 auto it =
1967 std::find_if(senders_.begin(), senders_.end(),
1968 [id](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
1969 return sender->id() == id;
1970 });
1971 return it != senders_.end() ? it->get() : nullptr;
1972}
1973
deadbeef70ab1a12015-09-28 16:53:55 -07001974std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator
1975PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) {
1976 return std::find_if(
1977 senders_.begin(), senders_.end(),
1978 [track](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
1979 return sender->track() == track;
1980 });
1981}
1982
1983std::vector<rtc::scoped_refptr<RtpReceiverInterface>>::iterator
1984PeerConnection::FindReceiverForTrack(MediaStreamTrackInterface* track) {
1985 return std::find_if(
1986 receivers_.begin(), receivers_.end(),
1987 [track](const rtc::scoped_refptr<RtpReceiverInterface>& receiver) {
1988 return receiver->track() == track;
1989 });
1990}
1991
deadbeefab9b2d12015-10-14 11:33:11 -07001992PeerConnection::TrackInfos* PeerConnection::GetRemoteTracks(
1993 cricket::MediaType media_type) {
1994 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
1995 media_type == cricket::MEDIA_TYPE_VIDEO);
1996 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &remote_audio_tracks_
1997 : &remote_video_tracks_;
1998}
1999
2000PeerConnection::TrackInfos* PeerConnection::GetLocalTracks(
2001 cricket::MediaType media_type) {
2002 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
2003 media_type == cricket::MEDIA_TYPE_VIDEO);
2004 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &local_audio_tracks_
2005 : &local_video_tracks_;
2006}
2007
2008const PeerConnection::TrackInfo* PeerConnection::FindTrackInfo(
2009 const PeerConnection::TrackInfos& infos,
2010 const std::string& stream_label,
2011 const std::string track_id) const {
2012 for (const TrackInfo& track_info : infos) {
2013 if (track_info.stream_label == stream_label &&
2014 track_info.track_id == track_id) {
2015 return &track_info;
2016 }
2017 }
2018 return nullptr;
2019}
2020
2021DataChannel* PeerConnection::FindDataChannelBySid(int sid) const {
2022 for (const auto& channel : sctp_data_channels_) {
2023 if (channel->id() == sid) {
2024 return channel;
2025 }
2026 }
2027 return nullptr;
2028}
2029
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002030} // namespace webrtc