blob: 5f1e3ebdc5e22809a45bba59a85f9005fbc5e500 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
jlmiller@webrtc.org5f93d0a2015-01-20 21:36:13 +00003 * Copyright 2012 Google Inc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "talk/app/webrtc/peerconnection.h"
29
deadbeefeb459812015-12-15 19:24:43 -080030#include <algorithm>
deadbeef0a6c4ca2015-10-06 11:38:28 -070031#include <cctype> // for isdigit
kwiberg0eb15ed2015-12-17 03:04:15 -080032#include <utility>
33#include <vector>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000034
deadbeefab9b2d12015-10-14 11:33:11 -070035#include "talk/app/webrtc/audiotrack.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000036#include "talk/app/webrtc/dtmfsender.h"
37#include "talk/app/webrtc/jsepicecandidate.h"
38#include "talk/app/webrtc/jsepsessiondescription.h"
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +000039#include "talk/app/webrtc/mediaconstraintsinterface.h"
deadbeefab9b2d12015-10-14 11:33:11 -070040#include "talk/app/webrtc/mediastream.h"
deadbeefeb459812015-12-15 19:24:43 -080041#include "talk/app/webrtc/mediastreamobserver.h"
deadbeefab9b2d12015-10-14 11:33:11 -070042#include "talk/app/webrtc/mediastreamproxy.h"
43#include "talk/app/webrtc/mediastreamtrackproxy.h"
44#include "talk/app/webrtc/remoteaudiosource.h"
45#include "talk/app/webrtc/remotevideocapturer.h"
deadbeef70ab1a12015-09-28 16:53:55 -070046#include "talk/app/webrtc/rtpreceiver.h"
47#include "talk/app/webrtc/rtpsender.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000048#include "talk/app/webrtc/streamcollection.h"
deadbeefab9b2d12015-10-14 11:33:11 -070049#include "talk/app/webrtc/videosource.h"
50#include "talk/app/webrtc/videotrack.h"
51#include "talk/media/sctp/sctpdataengine.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000052#include "talk/session/media/channelmanager.h"
tfarina5237aaf2015-11-10 23:44:30 -080053#include "webrtc/base/arraysize.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000054#include "webrtc/base/logging.h"
55#include "webrtc/base/stringencode.h"
deadbeefab9b2d12015-10-14 11:33:11 -070056#include "webrtc/base/stringutils.h"
Peter Boström1a9d6152015-12-08 22:15:17 +010057#include "webrtc/base/trace_event.h"
tfarina5237aaf2015-11-10 23:44:30 -080058#include "webrtc/p2p/client/basicportallocator.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010059#include "webrtc/system_wrappers/include/field_trial.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060
61namespace {
62
deadbeefab9b2d12015-10-14 11:33:11 -070063using webrtc::DataChannel;
64using webrtc::MediaConstraintsInterface;
65using webrtc::MediaStreamInterface;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000066using webrtc::PeerConnectionInterface;
deadbeeffac06552015-11-25 11:26:01 -080067using webrtc::RtpSenderInterface;
deadbeefab9b2d12015-10-14 11:33:11 -070068using webrtc::StreamCollection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000069
deadbeefab9b2d12015-10-14 11:33:11 -070070static const char kDefaultStreamLabel[] = "default";
71static const char kDefaultAudioTrackLabel[] = "defaulta0";
72static const char kDefaultVideoTrackLabel[] = "defaultv0";
73
henrike@webrtc.org28e20752013-07-10 00:45:36 +000074// The min number of tokens must present in Turn host uri.
75// e.g. user@turn.example.org
76static const size_t kTurnHostTokensNum = 2;
77// Number of tokens must be preset when TURN uri has transport param.
78static const size_t kTurnTransportTokensNum = 2;
79// The default stun port.
wu@webrtc.org91053e72013-08-10 07:18:04 +000080static const int kDefaultStunPort = 3478;
81static const int kDefaultStunTlsPort = 5349;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000082static const char kTransport[] = "transport";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000083
84// NOTE: Must be in the same order as the ServiceType enum.
deadbeef0a6c4ca2015-10-06 11:38:28 -070085static const char* kValidIceServiceTypes[] = {"stun", "stuns", "turn", "turns"};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000086
deadbeef0a6c4ca2015-10-06 11:38:28 -070087// NOTE: A loop below assumes that the first value of this enum is 0 and all
88// other values are incremental.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000089enum ServiceType {
deadbeef0a6c4ca2015-10-06 11:38:28 -070090 STUN = 0, // Indicates a STUN server.
91 STUNS, // Indicates a STUN server used with a TLS session.
92 TURN, // Indicates a TURN server
93 TURNS, // Indicates a TURN server used with a TLS session.
94 INVALID, // Unknown.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000095};
tfarina5237aaf2015-11-10 23:44:30 -080096static_assert(INVALID == arraysize(kValidIceServiceTypes),
deadbeef0a6c4ca2015-10-06 11:38:28 -070097 "kValidIceServiceTypes must have as many strings as ServiceType "
98 "has values.");
henrike@webrtc.org28e20752013-07-10 00:45:36 +000099
100enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000101 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000102 MSG_SET_SESSIONDESCRIPTION_FAILED,
deadbeefab9b2d12015-10-14 11:33:11 -0700103 MSG_CREATE_SESSIONDESCRIPTION_FAILED,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000104 MSG_GETSTATS,
deadbeefbd292462015-12-14 18:15:29 -0800105 MSG_FREE_DATACHANNELS,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106};
107
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000108struct SetSessionDescriptionMsg : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000109 explicit SetSessionDescriptionMsg(
110 webrtc::SetSessionDescriptionObserver* observer)
111 : observer(observer) {
112 }
113
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000114 rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000115 std::string error;
116};
117
deadbeefab9b2d12015-10-14 11:33:11 -0700118struct CreateSessionDescriptionMsg : public rtc::MessageData {
119 explicit CreateSessionDescriptionMsg(
120 webrtc::CreateSessionDescriptionObserver* observer)
121 : observer(observer) {}
122
123 rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserver> observer;
124 std::string error;
125};
126
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000127struct GetStatsMsg : public rtc::MessageData {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000128 GetStatsMsg(webrtc::StatsObserver* observer,
129 webrtc::MediaStreamTrackInterface* track)
130 : observer(observer), track(track) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000132 rtc::scoped_refptr<webrtc::StatsObserver> observer;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000133 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000134};
135
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000136// |in_str| should be of format
137// stunURI = scheme ":" stun-host [ ":" stun-port ]
138// scheme = "stun" / "stuns"
139// stun-host = IP-literal / IPv4address / reg-name
140// stun-port = *DIGIT
deadbeef0a6c4ca2015-10-06 11:38:28 -0700141//
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000142// draft-petithuguenin-behave-turn-uris-01
143// turnURI = scheme ":" turn-host [ ":" turn-port ]
144// turn-host = username@IP-literal / IPv4address / reg-name
145bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
146 ServiceType* service_type,
147 std::string* hostname) {
Tommi77d444a2015-04-24 15:38:38 +0200148 const std::string::size_type colonpos = in_str.find(':');
deadbeef0a6c4ca2015-10-06 11:38:28 -0700149 if (colonpos == std::string::npos) {
150 LOG(LS_WARNING) << "Missing ':' in ICE URI: " << in_str;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000151 return false;
152 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700153 if ((colonpos + 1) == in_str.length()) {
154 LOG(LS_WARNING) << "Empty hostname in ICE URI: " << in_str;
155 return false;
156 }
157 *service_type = INVALID;
tfarina5237aaf2015-11-10 23:44:30 -0800158 for (size_t i = 0; i < arraysize(kValidIceServiceTypes); ++i) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700159 if (in_str.compare(0, colonpos, kValidIceServiceTypes[i]) == 0) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000160 *service_type = static_cast<ServiceType>(i);
161 break;
162 }
163 }
164 if (*service_type == INVALID) {
165 return false;
166 }
167 *hostname = in_str.substr(colonpos + 1, std::string::npos);
168 return true;
169}
170
deadbeef0a6c4ca2015-10-06 11:38:28 -0700171bool ParsePort(const std::string& in_str, int* port) {
172 // Make sure port only contains digits. FromString doesn't check this.
173 for (const char& c : in_str) {
174 if (!std::isdigit(c)) {
175 return false;
176 }
177 }
178 return rtc::FromString(in_str, port);
179}
180
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000181// This method parses IPv6 and IPv4 literal strings, along with hostnames in
182// standard hostname:port format.
183// Consider following formats as correct.
184// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700185// |hostname|, |[IPv6 address]|, |IPv4 address|.
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000186bool ParseHostnameAndPortFromString(const std::string& in_str,
187 std::string* host,
188 int* port) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700189 RTC_DCHECK(host->empty());
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000190 if (in_str.at(0) == '[') {
191 std::string::size_type closebracket = in_str.rfind(']');
192 if (closebracket != std::string::npos) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000193 std::string::size_type colonpos = in_str.find(':', closebracket);
194 if (std::string::npos != colonpos) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700195 if (!ParsePort(in_str.substr(closebracket + 2, std::string::npos),
196 port)) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000197 return false;
198 }
199 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700200 *host = in_str.substr(1, closebracket - 1);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000201 } else {
202 return false;
203 }
204 } else {
205 std::string::size_type colonpos = in_str.find(':');
206 if (std::string::npos != colonpos) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700207 if (!ParsePort(in_str.substr(colonpos + 1, std::string::npos), port)) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000208 return false;
209 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700210 *host = in_str.substr(0, colonpos);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000211 } else {
212 *host = in_str;
213 }
214 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700215 return !host->empty();
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000216}
217
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800218// Adds a STUN or TURN server to the appropriate list,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700219// by parsing |url| and using the username/password in |server|.
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200220bool ParseIceServerUrl(const PeerConnectionInterface::IceServer& server,
221 const std::string& url,
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800222 cricket::ServerAddresses* stun_servers,
223 std::vector<cricket::RelayServerConfig>* turn_servers) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000224 // draft-nandakumar-rtcweb-stun-uri-01
225 // stunURI = scheme ":" stun-host [ ":" stun-port ]
226 // scheme = "stun" / "stuns"
227 // stun-host = IP-literal / IPv4address / reg-name
228 // stun-port = *DIGIT
229
230 // draft-petithuguenin-behave-turn-uris-01
231 // turnURI = scheme ":" turn-host [ ":" turn-port ]
232 // [ "?transport=" transport ]
233 // scheme = "turn" / "turns"
234 // transport = "udp" / "tcp" / transport-ext
235 // transport-ext = 1*unreserved
236 // turn-host = IP-literal / IPv4address / reg-name
237 // turn-port = *DIGIT
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800238 RTC_DCHECK(stun_servers != nullptr);
239 RTC_DCHECK(turn_servers != nullptr);
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200240 std::vector<std::string> tokens;
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800241 cricket::ProtocolType turn_transport_type = cricket::PROTO_UDP;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700242 RTC_DCHECK(!url.empty());
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200243 rtc::tokenize(url, '?', &tokens);
244 std::string uri_without_transport = tokens[0];
245 // Let's look into transport= param, if it exists.
246 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
247 std::string uri_transport_param = tokens[1];
248 rtc::tokenize(uri_transport_param, '=', &tokens);
249 if (tokens[0] == kTransport) {
250 // As per above grammar transport param will be consist of lower case
251 // letters.
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800252 if (!cricket::StringToProto(tokens[1].c_str(), &turn_transport_type) ||
253 (turn_transport_type != cricket::PROTO_UDP &&
254 turn_transport_type != cricket::PROTO_TCP)) {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200255 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
deadbeef0a6c4ca2015-10-06 11:38:28 -0700256 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000257 }
258 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200259 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000260
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200261 std::string hoststring;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700262 ServiceType service_type;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200263 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
264 &service_type,
265 &hoststring)) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700266 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: " << url;
267 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200268 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000269
deadbeef0a6c4ca2015-10-06 11:38:28 -0700270 // GetServiceTypeAndHostnameFromUri should never give an empty hoststring
271 RTC_DCHECK(!hoststring.empty());
Tommi77d444a2015-04-24 15:38:38 +0200272
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200273 // Let's break hostname.
274 tokens.clear();
deadbeef0a6c4ca2015-10-06 11:38:28 -0700275 rtc::tokenize_with_empty_tokens(hoststring, '@', &tokens);
276
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200277 std::string username(server.username);
deadbeef0a6c4ca2015-10-06 11:38:28 -0700278 if (tokens.size() > kTurnHostTokensNum) {
279 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring;
280 return false;
281 }
282 if (tokens.size() == kTurnHostTokensNum) {
283 if (tokens[0].empty() || tokens[1].empty()) {
284 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring;
285 return false;
286 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200287 username.assign(rtc::s_url_decode(tokens[0]));
288 hoststring = tokens[1];
289 } else {
290 hoststring = tokens[0];
291 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000292
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200293 int port = kDefaultStunPort;
294 if (service_type == TURNS) {
295 port = kDefaultStunTlsPort;
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800296 turn_transport_type = cricket::PROTO_TCP;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200297 }
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000298
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200299 std::string address;
300 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700301 LOG(WARNING) << "Invalid hostname format: " << uri_without_transport;
302 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200303 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000304
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200305 if (port <= 0 || port > 0xffff) {
306 LOG(WARNING) << "Invalid port: " << port;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700307 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200308 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000309
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200310 switch (service_type) {
311 case STUN:
312 case STUNS:
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800313 stun_servers->insert(rtc::SocketAddress(address, port));
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200314 break;
315 case TURN:
316 case TURNS: {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200317 bool secure = (service_type == TURNS);
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800318 turn_servers->push_back(
319 cricket::RelayServerConfig(address, port, username, server.password,
320 turn_transport_type, secure));
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200321 break;
322 }
323 case INVALID:
324 default:
325 LOG(WARNING) << "Configuration not supported: " << url;
326 return false;
327 }
328 return true;
329}
330
deadbeefab9b2d12015-10-14 11:33:11 -0700331// Check if we can send |new_stream| on a PeerConnection.
332bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
333 webrtc::MediaStreamInterface* new_stream) {
334 if (!new_stream || !current_streams) {
335 return false;
336 }
337 if (current_streams->find(new_stream->label()) != nullptr) {
338 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
339 << " is already added.";
340 return false;
341 }
342 return true;
343}
344
345bool MediaContentDirectionHasSend(cricket::MediaContentDirection dir) {
346 return dir == cricket::MD_SENDONLY || dir == cricket::MD_SENDRECV;
347}
348
deadbeef5e97fb52015-10-15 12:49:08 -0700349// If the direction is "recvonly" or "inactive", treat the description
350// as containing no streams.
351// See: https://code.google.com/p/webrtc/issues/detail?id=5054
352std::vector<cricket::StreamParams> GetActiveStreams(
353 const cricket::MediaContentDescription* desc) {
354 return MediaContentDirectionHasSend(desc->direction())
355 ? desc->streams()
356 : std::vector<cricket::StreamParams>();
357}
358
deadbeefab9b2d12015-10-14 11:33:11 -0700359bool IsValidOfferToReceiveMedia(int value) {
360 typedef PeerConnectionInterface::RTCOfferAnswerOptions Options;
361 return (value >= Options::kUndefined) &&
362 (value <= Options::kMaxOfferToReceiveMedia);
363}
364
365// Add the stream and RTP data channel info to |session_options|.
deadbeeffac06552015-11-25 11:26:01 -0800366void AddSendStreams(
367 cricket::MediaSessionOptions* session_options,
368 const std::vector<rtc::scoped_refptr<RtpSenderInterface>>& senders,
369 const std::map<std::string, rtc::scoped_refptr<DataChannel>>&
370 rtp_data_channels) {
deadbeefab9b2d12015-10-14 11:33:11 -0700371 session_options->streams.clear();
deadbeeffac06552015-11-25 11:26:01 -0800372 for (const auto& sender : senders) {
373 session_options->AddSendStream(sender->media_type(), sender->id(),
374 sender->stream_id());
deadbeefab9b2d12015-10-14 11:33:11 -0700375 }
376
377 // Check for data channels.
378 for (const auto& kv : rtp_data_channels) {
379 const DataChannel* channel = kv.second;
380 if (channel->state() == DataChannel::kConnecting ||
381 channel->state() == DataChannel::kOpen) {
382 // |streamid| and |sync_label| are both set to the DataChannel label
383 // here so they can be signaled the same way as MediaStreams and Tracks.
384 // For MediaStreams, the sync_label is the MediaStream label and the
385 // track label is the same as |streamid|.
386 const std::string& streamid = channel->label();
387 const std::string& sync_label = channel->label();
388 session_options->AddSendStream(cricket::MEDIA_TYPE_DATA, streamid,
389 sync_label);
390 }
391 }
392}
393
deadbeef0a6c4ca2015-10-06 11:38:28 -0700394} // namespace
395
396namespace webrtc {
397
deadbeefab9b2d12015-10-14 11:33:11 -0700398// Factory class for creating remote MediaStreams and MediaStreamTracks.
399class RemoteMediaStreamFactory {
400 public:
401 explicit RemoteMediaStreamFactory(rtc::Thread* signaling_thread,
402 cricket::ChannelManager* channel_manager)
403 : signaling_thread_(signaling_thread),
404 channel_manager_(channel_manager) {}
405
406 rtc::scoped_refptr<MediaStreamInterface> CreateMediaStream(
407 const std::string& stream_label) {
408 return MediaStreamProxy::Create(signaling_thread_,
409 MediaStream::Create(stream_label));
410 }
411
Tommif888bb52015-12-12 01:37:01 +0100412 AudioTrackInterface* AddAudioTrack(uint32_t ssrc,
413 AudioProviderInterface* provider,
414 webrtc::MediaStreamInterface* stream,
deadbeefab9b2d12015-10-14 11:33:11 -0700415 const std::string& track_id) {
tommi6eca7e32015-12-15 04:27:11 -0800416 return AddTrack<AudioTrackInterface, AudioTrack, AudioTrackProxy>(
Tommif888bb52015-12-12 01:37:01 +0100417 stream, track_id, RemoteAudioSource::Create(ssrc, provider));
deadbeefab9b2d12015-10-14 11:33:11 -0700418 }
419
420 VideoTrackInterface* AddVideoTrack(webrtc::MediaStreamInterface* stream,
421 const std::string& track_id) {
422 return AddTrack<VideoTrackInterface, VideoTrack, VideoTrackProxy>(
423 stream, track_id,
424 VideoSource::Create(channel_manager_, new RemoteVideoCapturer(),
tommi6eca7e32015-12-15 04:27:11 -0800425 nullptr, true)
deadbeefab9b2d12015-10-14 11:33:11 -0700426 .get());
427 }
428
429 private:
430 template <typename TI, typename T, typename TP, typename S>
431 TI* AddTrack(MediaStreamInterface* stream,
432 const std::string& track_id,
Tommif888bb52015-12-12 01:37:01 +0100433 const S& source) {
deadbeefab9b2d12015-10-14 11:33:11 -0700434 rtc::scoped_refptr<TI> track(
435 TP::Create(signaling_thread_, T::Create(track_id, source)));
436 track->set_state(webrtc::MediaStreamTrackInterface::kLive);
437 if (stream->AddTrack(track)) {
438 return track;
439 }
440 return nullptr;
441 }
442
443 rtc::Thread* signaling_thread_;
444 cricket::ChannelManager* channel_manager_;
445};
446
447bool ConvertRtcOptionsForOffer(
448 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
449 cricket::MediaSessionOptions* session_options) {
450 typedef PeerConnectionInterface::RTCOfferAnswerOptions RTCOfferAnswerOptions;
451 if (!IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_audio) ||
452 !IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_video)) {
453 return false;
454 }
455
deadbeefc80741f2015-10-22 13:14:45 -0700456 if (rtc_options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) {
deadbeefab9b2d12015-10-14 11:33:11 -0700457 session_options->recv_audio = (rtc_options.offer_to_receive_audio > 0);
458 }
deadbeefc80741f2015-10-22 13:14:45 -0700459 if (rtc_options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) {
deadbeefab9b2d12015-10-14 11:33:11 -0700460 session_options->recv_video = (rtc_options.offer_to_receive_video > 0);
461 }
462
463 session_options->vad_enabled = rtc_options.voice_activity_detection;
464 session_options->transport_options.ice_restart = rtc_options.ice_restart;
deadbeefc80741f2015-10-22 13:14:45 -0700465 session_options->bundle_enabled = rtc_options.use_rtp_mux;
deadbeefab9b2d12015-10-14 11:33:11 -0700466
467 return true;
468}
469
470bool ParseConstraintsForAnswer(const MediaConstraintsInterface* constraints,
471 cricket::MediaSessionOptions* session_options) {
472 bool value = false;
473 size_t mandatory_constraints_satisfied = 0;
474
475 // kOfferToReceiveAudio defaults to true according to spec.
476 if (!FindConstraint(constraints,
477 MediaConstraintsInterface::kOfferToReceiveAudio, &value,
478 &mandatory_constraints_satisfied) ||
479 value) {
480 session_options->recv_audio = true;
481 }
482
483 // kOfferToReceiveVideo defaults to false according to spec. But
484 // if it is an answer and video is offered, we should still accept video
485 // per default.
486 value = false;
487 if (!FindConstraint(constraints,
488 MediaConstraintsInterface::kOfferToReceiveVideo, &value,
489 &mandatory_constraints_satisfied) ||
490 value) {
491 session_options->recv_video = true;
492 }
493
494 if (FindConstraint(constraints,
495 MediaConstraintsInterface::kVoiceActivityDetection, &value,
496 &mandatory_constraints_satisfied)) {
497 session_options->vad_enabled = value;
498 }
499
500 if (FindConstraint(constraints, MediaConstraintsInterface::kUseRtpMux, &value,
501 &mandatory_constraints_satisfied)) {
502 session_options->bundle_enabled = value;
503 } else {
504 // kUseRtpMux defaults to true according to spec.
505 session_options->bundle_enabled = true;
506 }
deadbeefab9b2d12015-10-14 11:33:11 -0700507
508 if (FindConstraint(constraints, MediaConstraintsInterface::kIceRestart,
509 &value, &mandatory_constraints_satisfied)) {
510 session_options->transport_options.ice_restart = value;
511 } else {
512 // kIceRestart defaults to false according to spec.
513 session_options->transport_options.ice_restart = false;
514 }
515
516 if (!constraints) {
517 return true;
518 }
519 return mandatory_constraints_satisfied == constraints->GetMandatory().size();
520}
521
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200522bool ParseIceServers(const PeerConnectionInterface::IceServers& servers,
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800523 cricket::ServerAddresses* stun_servers,
524 std::vector<cricket::RelayServerConfig>* turn_servers) {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200525 for (const webrtc::PeerConnectionInterface::IceServer& server : servers) {
526 if (!server.urls.empty()) {
527 for (const std::string& url : server.urls) {
Joachim Bauchd935f912015-05-29 22:14:21 +0200528 if (url.empty()) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700529 LOG(LS_ERROR) << "Empty uri.";
530 return false;
Joachim Bauchd935f912015-05-29 22:14:21 +0200531 }
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800532 if (!ParseIceServerUrl(server, url, stun_servers, turn_servers)) {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200533 return false;
534 }
535 }
536 } else if (!server.uri.empty()) {
537 // Fallback to old .uri if new .urls isn't present.
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800538 if (!ParseIceServerUrl(server, server.uri, stun_servers, turn_servers)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000539 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200540 }
541 } else {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700542 LOG(LS_ERROR) << "Empty uri.";
543 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000544 }
545 }
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800546 // Candidates must have unique priorities, so that connectivity checks
547 // are performed in a well-defined order.
548 int priority = static_cast<int>(turn_servers->size() - 1);
549 for (cricket::RelayServerConfig& turn_server : *turn_servers) {
550 // First in the list gets highest priority.
551 turn_server.priority = priority--;
552 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000553 return true;
554}
555
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000556PeerConnection::PeerConnection(PeerConnectionFactory* factory)
557 : factory_(factory),
558 observer_(NULL),
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000559 uma_observer_(NULL),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000560 signaling_state_(kStable),
561 ice_state_(kIceNew),
562 ice_connection_state_(kIceConnectionNew),
deadbeefab9b2d12015-10-14 11:33:11 -0700563 ice_gathering_state_(kIceGatheringNew),
564 local_streams_(StreamCollection::Create()),
565 remote_streams_(StreamCollection::Create()) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000566
567PeerConnection::~PeerConnection() {
Peter Boström1a9d6152015-12-08 22:15:17 +0100568 TRACE_EVENT0("webrtc", "PeerConnection::~PeerConnection");
deadbeef0a6c4ca2015-10-06 11:38:28 -0700569 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeef70ab1a12015-09-28 16:53:55 -0700570 // Need to detach RTP senders/receivers from WebRtcSession,
571 // since it's about to be destroyed.
572 for (const auto& sender : senders_) {
573 sender->Stop();
574 }
575 for (const auto& receiver : receivers_) {
576 receiver->Stop();
577 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000578}
579
580bool PeerConnection::Initialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000581 const PeerConnectionInterface::RTCConfiguration& configuration,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582 const MediaConstraintsInterface* constraints,
deadbeef653b8e02015-11-11 12:55:10 -0800583 rtc::scoped_ptr<cricket::PortAllocator> allocator,
584 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
585 PeerConnectionObserver* observer) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100586 TRACE_EVENT0("webrtc", "PeerConnection::Initialize");
deadbeef653b8e02015-11-11 12:55:10 -0800587 RTC_DCHECK(observer != nullptr);
588 if (!observer) {
589 return false;
590 }
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000591 observer_ = observer;
592
kwiberg0eb15ed2015-12-17 03:04:15 -0800593 port_allocator_ = std::move(allocator);
deadbeef653b8e02015-11-11 12:55:10 -0800594
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800595 cricket::ServerAddresses stun_servers;
596 std::vector<cricket::RelayServerConfig> turn_servers;
597 if (!ParseIceServers(configuration.servers, &stun_servers, &turn_servers)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 return false;
599 }
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800600 port_allocator_->SetIceServers(stun_servers, turn_servers);
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000601
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000602 // To handle both internal and externally created port allocator, we will
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000603 // enable BUNDLE here.
braveyao@webrtc.org1732df62014-10-27 03:01:37 +0000604 int portallocator_flags = port_allocator_->flags();
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700605 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000606 cricket::PORTALLOCATOR_ENABLE_IPV6;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000607 bool value;
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000608 // If IPv6 flag was specified, we'll not override it by experiment.
deadbeefab9b2d12015-10-14 11:33:11 -0700609 if (FindConstraint(constraints, MediaConstraintsInterface::kEnableIPv6,
610 &value, nullptr)) {
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000611 if (!value) {
612 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000613 }
guoweis@webrtc.org2c1bcea2014-09-23 16:23:02 +0000614 } else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default") ==
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000615 "Disabled") {
616 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000617 }
618
Jiayang Liucac1b382015-04-30 12:35:24 -0700619 if (configuration.tcp_candidate_policy == kTcpCandidatePolicyDisabled) {
620 portallocator_flags |= cricket::PORTALLOCATOR_DISABLE_TCP;
621 LOG(LS_INFO) << "TCP candidates are disabled.";
622 }
623
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000624 port_allocator_->set_flags(portallocator_flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000625 // No step delay is used while allocating ports.
626 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
627
stefanc1aeaf02015-10-15 07:26:07 -0700628 media_controller_.reset(factory_->CreateMediaController());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000629
stefanc1aeaf02015-10-15 07:26:07 -0700630 remote_stream_factory_.reset(new RemoteMediaStreamFactory(
631 factory_->signaling_thread(), media_controller_->channel_manager()));
632
633 session_.reset(
634 new WebRtcSession(media_controller_.get(), factory_->signaling_thread(),
635 factory_->worker_thread(), port_allocator_.get()));
deadbeefab9b2d12015-10-14 11:33:11 -0700636 stats_.reset(new StatsCollector(this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000637
638 // Initialize the WebRtcSession. It creates transport channels etc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000639 if (!session_->Initialize(factory_->options(), constraints,
kwiberg0eb15ed2015-12-17 03:04:15 -0800640 std::move(dtls_identity_store), configuration)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000641 return false;
deadbeefab9b2d12015-10-14 11:33:11 -0700642 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000643
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000644 // Register PeerConnection as receiver of local ice candidates.
645 // All the callbacks will be posted to the application from PeerConnection.
646 session_->RegisterIceObserver(this);
647 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
deadbeefab9b2d12015-10-14 11:33:11 -0700648 session_->SignalVoiceChannelDestroyed.connect(
649 this, &PeerConnection::OnVoiceChannelDestroyed);
650 session_->SignalVideoChannelDestroyed.connect(
651 this, &PeerConnection::OnVideoChannelDestroyed);
652 session_->SignalDataChannelCreated.connect(
653 this, &PeerConnection::OnDataChannelCreated);
654 session_->SignalDataChannelDestroyed.connect(
655 this, &PeerConnection::OnDataChannelDestroyed);
656 session_->SignalDataChannelOpenMessage.connect(
657 this, &PeerConnection::OnDataChannelOpenMessage);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658 return true;
659}
660
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000661rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000662PeerConnection::local_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -0700663 return local_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000664}
665
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000666rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000667PeerConnection::remote_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -0700668 return remote_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000669}
670
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +0000671bool PeerConnection::AddStream(MediaStreamInterface* local_stream) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100672 TRACE_EVENT0("webrtc", "PeerConnection::AddStream");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000673 if (IsClosed()) {
674 return false;
675 }
deadbeefab9b2d12015-10-14 11:33:11 -0700676 if (!CanAddLocalMediaStream(local_streams_, local_stream)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000677 return false;
678 }
deadbeefab9b2d12015-10-14 11:33:11 -0700679
680 local_streams_->AddStream(local_stream);
deadbeefeb459812015-12-15 19:24:43 -0800681 MediaStreamObserver* observer = new MediaStreamObserver(local_stream);
682 observer->SignalAudioTrackAdded.connect(this,
683 &PeerConnection::OnAudioTrackAdded);
684 observer->SignalAudioTrackRemoved.connect(
685 this, &PeerConnection::OnAudioTrackRemoved);
686 observer->SignalVideoTrackAdded.connect(this,
687 &PeerConnection::OnVideoTrackAdded);
688 observer->SignalVideoTrackRemoved.connect(
689 this, &PeerConnection::OnVideoTrackRemoved);
690 stream_observers_.push_back(rtc::scoped_ptr<MediaStreamObserver>(observer));
deadbeefab9b2d12015-10-14 11:33:11 -0700691
deadbeefab9b2d12015-10-14 11:33:11 -0700692 for (const auto& track : local_stream->GetAudioTracks()) {
deadbeefeb459812015-12-15 19:24:43 -0800693 OnAudioTrackAdded(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -0700694 }
695 for (const auto& track : local_stream->GetVideoTracks()) {
deadbeefeb459812015-12-15 19:24:43 -0800696 OnVideoTrackAdded(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -0700697 }
698
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000699 stats_->AddStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000700 observer_->OnRenegotiationNeeded();
701 return true;
702}
703
704void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100705 TRACE_EVENT0("webrtc", "PeerConnection::RemoveStream");
deadbeefab9b2d12015-10-14 11:33:11 -0700706 for (const auto& track : local_stream->GetAudioTracks()) {
deadbeefeb459812015-12-15 19:24:43 -0800707 OnAudioTrackRemoved(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -0700708 }
709 for (const auto& track : local_stream->GetVideoTracks()) {
deadbeefeb459812015-12-15 19:24:43 -0800710 OnVideoTrackRemoved(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -0700711 }
712
713 local_streams_->RemoveStream(local_stream);
deadbeefeb459812015-12-15 19:24:43 -0800714 stream_observers_.erase(
715 std::remove_if(
716 stream_observers_.begin(), stream_observers_.end(),
717 [local_stream](const rtc::scoped_ptr<MediaStreamObserver>& observer) {
718 return observer->stream()->label().compare(local_stream->label()) ==
719 0;
720 }),
721 stream_observers_.end());
deadbeefab9b2d12015-10-14 11:33:11 -0700722
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000723 if (IsClosed()) {
724 return;
725 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000726 observer_->OnRenegotiationNeeded();
727}
728
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000729rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000730 AudioTrackInterface* track) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100731 TRACE_EVENT0("webrtc", "PeerConnection::CreateDtmfSender");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000732 if (!track) {
733 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
734 return NULL;
735 }
deadbeefab9b2d12015-10-14 11:33:11 -0700736 if (!local_streams_->FindAudioTrack(track->id())) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000737 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
738 return NULL;
739 }
740
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000741 rtc::scoped_refptr<DtmfSenderInterface> sender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000742 DtmfSender::Create(track, signaling_thread(), session_.get()));
743 if (!sender.get()) {
744 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
745 return NULL;
746 }
747 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
748}
749
deadbeeffac06552015-11-25 11:26:01 -0800750rtc::scoped_refptr<RtpSenderInterface> PeerConnection::CreateSender(
deadbeefbd7d8f72015-12-18 16:58:44 -0800751 const std::string& kind,
752 const std::string& stream_id) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100753 TRACE_EVENT0("webrtc", "PeerConnection::CreateSender");
deadbeeffac06552015-11-25 11:26:01 -0800754 RtpSenderInterface* new_sender;
755 if (kind == MediaStreamTrackInterface::kAudioKind) {
756 new_sender = new AudioRtpSender(session_.get(), stats_.get());
757 } else if (kind == MediaStreamTrackInterface::kVideoKind) {
758 new_sender = new VideoRtpSender(session_.get());
759 } else {
760 LOG(LS_ERROR) << "CreateSender called with invalid kind: " << kind;
761 return rtc::scoped_refptr<RtpSenderInterface>();
762 }
deadbeefbd7d8f72015-12-18 16:58:44 -0800763 if (!stream_id.empty()) {
764 new_sender->set_stream_id(stream_id);
765 }
deadbeeffac06552015-11-25 11:26:01 -0800766 senders_.push_back(new_sender);
767 return RtpSenderProxy::Create(signaling_thread(), new_sender);
768}
769
deadbeef70ab1a12015-09-28 16:53:55 -0700770std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders()
771 const {
772 std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders;
773 for (const auto& sender : senders_) {
774 senders.push_back(RtpSenderProxy::Create(signaling_thread(), sender.get()));
775 }
776 return senders;
777}
778
779std::vector<rtc::scoped_refptr<RtpReceiverInterface>>
780PeerConnection::GetReceivers() const {
781 std::vector<rtc::scoped_refptr<RtpReceiverInterface>> receivers;
782 for (const auto& receiver : receivers_) {
783 receivers.push_back(
784 RtpReceiverProxy::Create(signaling_thread(), receiver.get()));
785 }
786 return receivers;
787}
788
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000789bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000790 MediaStreamTrackInterface* track,
791 StatsOutputLevel level) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100792 TRACE_EVENT0("webrtc", "PeerConnection::GetStats");
deadbeef0a6c4ca2015-10-06 11:38:28 -0700793 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000794 if (!VERIFY(observer != NULL)) {
795 LOG(LS_ERROR) << "GetStats - observer is NULL.";
796 return false;
797 }
798
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000799 stats_->UpdateStats(level);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000800 signaling_thread()->Post(this, MSG_GETSTATS,
801 new GetStatsMsg(observer, track));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000802 return true;
803}
804
805PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
806 return signaling_state_;
807}
808
809PeerConnectionInterface::IceState PeerConnection::ice_state() {
810 return ice_state_;
811}
812
813PeerConnectionInterface::IceConnectionState
814PeerConnection::ice_connection_state() {
815 return ice_connection_state_;
816}
817
818PeerConnectionInterface::IceGatheringState
819PeerConnection::ice_gathering_state() {
820 return ice_gathering_state_;
821}
822
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000823rtc::scoped_refptr<DataChannelInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000824PeerConnection::CreateDataChannel(
825 const std::string& label,
826 const DataChannelInit* config) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100827 TRACE_EVENT0("webrtc", "PeerConnection::CreateDataChannel");
deadbeefab9b2d12015-10-14 11:33:11 -0700828 bool first_datachannel = !HasDataChannels();
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000829
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000830 rtc::scoped_ptr<InternalDataChannelInit> internal_config;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000831 if (config) {
832 internal_config.reset(new InternalDataChannelInit(*config));
833 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000834 rtc::scoped_refptr<DataChannelInterface> channel(
deadbeefab9b2d12015-10-14 11:33:11 -0700835 InternalCreateDataChannel(label, internal_config.get()));
836 if (!channel.get()) {
837 return nullptr;
838 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000839
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000840 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
841 // the first SCTP DataChannel.
842 if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
843 observer_->OnRenegotiationNeeded();
844 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000845
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000846 return DataChannelProxy::Create(signaling_thread(), channel.get());
847}
848
849void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
850 const MediaConstraintsInterface* constraints) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100851 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer");
deadbeefab9b2d12015-10-14 11:33:11 -0700852 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000853 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
854 return;
855 }
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000856 RTCOfferAnswerOptions options;
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000857
858 bool value;
859 size_t mandatory_constraints = 0;
860
861 if (FindConstraint(constraints,
862 MediaConstraintsInterface::kOfferToReceiveAudio,
863 &value,
864 &mandatory_constraints)) {
865 options.offer_to_receive_audio =
866 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
867 }
868
869 if (FindConstraint(constraints,
870 MediaConstraintsInterface::kOfferToReceiveVideo,
871 &value,
872 &mandatory_constraints)) {
873 options.offer_to_receive_video =
874 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
875 }
876
877 if (FindConstraint(constraints,
878 MediaConstraintsInterface::kVoiceActivityDetection,
879 &value,
880 &mandatory_constraints)) {
881 options.voice_activity_detection = value;
882 }
883
884 if (FindConstraint(constraints,
885 MediaConstraintsInterface::kIceRestart,
886 &value,
887 &mandatory_constraints)) {
888 options.ice_restart = value;
889 }
890
891 if (FindConstraint(constraints,
892 MediaConstraintsInterface::kUseRtpMux,
893 &value,
894 &mandatory_constraints)) {
895 options.use_rtp_mux = value;
896 }
897
898 CreateOffer(observer, options);
899}
900
901void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
902 const RTCOfferAnswerOptions& options) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100903 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer");
deadbeefab9b2d12015-10-14 11:33:11 -0700904 if (!VERIFY(observer != nullptr)) {
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000905 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
906 return;
907 }
deadbeefab9b2d12015-10-14 11:33:11 -0700908
909 cricket::MediaSessionOptions session_options;
910 if (!GetOptionsForOffer(options, &session_options)) {
911 std::string error = "CreateOffer called with invalid options.";
912 LOG(LS_ERROR) << error;
913 PostCreateSessionDescriptionFailure(observer, error);
914 return;
915 }
916
917 session_->CreateOffer(observer, options, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000918}
919
920void PeerConnection::CreateAnswer(
921 CreateSessionDescriptionObserver* observer,
922 const MediaConstraintsInterface* constraints) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100923 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer");
deadbeefab9b2d12015-10-14 11:33:11 -0700924 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000925 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
926 return;
927 }
deadbeefab9b2d12015-10-14 11:33:11 -0700928
929 cricket::MediaSessionOptions session_options;
930 if (!GetOptionsForAnswer(constraints, &session_options)) {
931 std::string error = "CreateAnswer called with invalid constraints.";
932 LOG(LS_ERROR) << error;
933 PostCreateSessionDescriptionFailure(observer, error);
934 return;
935 }
936
937 session_->CreateAnswer(observer, constraints, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000938}
939
940void PeerConnection::SetLocalDescription(
941 SetSessionDescriptionObserver* observer,
942 SessionDescriptionInterface* desc) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100943 TRACE_EVENT0("webrtc", "PeerConnection::SetLocalDescription");
deadbeefab9b2d12015-10-14 11:33:11 -0700944 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000945 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
946 return;
947 }
948 if (!desc) {
949 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
950 return;
951 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000952 // Update stats here so that we have the most recent stats for tracks and
953 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000954 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000955 std::string error;
956 if (!session_->SetLocalDescription(desc, &error)) {
957 PostSetSessionDescriptionFailure(observer, error);
958 return;
959 }
deadbeefab9b2d12015-10-14 11:33:11 -0700960
961 // If setting the description decided our SSL role, allocate any necessary
962 // SCTP sids.
963 rtc::SSLRole role;
964 if (session_->data_channel_type() == cricket::DCT_SCTP &&
965 session_->GetSslRole(&role)) {
966 AllocateSctpSids(role);
967 }
968
969 // Update state and SSRC of local MediaStreams and DataChannels based on the
970 // local session description.
971 const cricket::ContentInfo* audio_content =
972 GetFirstAudioContent(desc->description());
973 if (audio_content) {
deadbeeffaac4972015-11-12 15:33:07 -0800974 if (audio_content->rejected) {
975 RemoveTracks(cricket::MEDIA_TYPE_AUDIO);
976 } else {
977 const cricket::AudioContentDescription* audio_desc =
978 static_cast<const cricket::AudioContentDescription*>(
979 audio_content->description);
980 UpdateLocalTracks(audio_desc->streams(), audio_desc->type());
981 }
deadbeefab9b2d12015-10-14 11:33:11 -0700982 }
983
984 const cricket::ContentInfo* video_content =
985 GetFirstVideoContent(desc->description());
986 if (video_content) {
deadbeeffaac4972015-11-12 15:33:07 -0800987 if (video_content->rejected) {
988 RemoveTracks(cricket::MEDIA_TYPE_VIDEO);
989 } else {
990 const cricket::VideoContentDescription* video_desc =
991 static_cast<const cricket::VideoContentDescription*>(
992 video_content->description);
993 UpdateLocalTracks(video_desc->streams(), video_desc->type());
994 }
deadbeefab9b2d12015-10-14 11:33:11 -0700995 }
996
997 const cricket::ContentInfo* data_content =
998 GetFirstDataContent(desc->description());
999 if (data_content) {
1000 const cricket::DataContentDescription* data_desc =
1001 static_cast<const cricket::DataContentDescription*>(
1002 data_content->description);
1003 if (rtc::starts_with(data_desc->protocol().data(),
1004 cricket::kMediaProtocolRtpPrefix)) {
1005 UpdateLocalRtpDataChannels(data_desc->streams());
1006 }
1007 }
1008
1009 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001010 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeefab9b2d12015-10-14 11:33:11 -07001011
deadbeefcbecd352015-09-23 11:50:27 -07001012 // MaybeStartGathering needs to be called after posting
1013 // MSG_SET_SESSIONDESCRIPTION_SUCCESS, so that we don't signal any candidates
1014 // before signaling that SetLocalDescription completed.
1015 session_->MaybeStartGathering();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001016}
1017
1018void PeerConnection::SetRemoteDescription(
1019 SetSessionDescriptionObserver* observer,
1020 SessionDescriptionInterface* desc) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001021 TRACE_EVENT0("webrtc", "PeerConnection::SetRemoteDescription");
deadbeefab9b2d12015-10-14 11:33:11 -07001022 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001023 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
1024 return;
1025 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001026 if (!desc) {
1027 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
1028 return;
1029 }
1030 // Update stats here so that we have the most recent stats for tracks and
1031 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001032 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001033 std::string error;
1034 if (!session_->SetRemoteDescription(desc, &error)) {
1035 PostSetSessionDescriptionFailure(observer, error);
1036 return;
1037 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001038
deadbeefab9b2d12015-10-14 11:33:11 -07001039 // If setting the description decided our SSL role, allocate any necessary
1040 // SCTP sids.
1041 rtc::SSLRole role;
1042 if (session_->data_channel_type() == cricket::DCT_SCTP &&
1043 session_->GetSslRole(&role)) {
1044 AllocateSctpSids(role);
1045 }
1046
1047 const cricket::SessionDescription* remote_desc = desc->description();
deadbeefbda7e0b2015-12-08 17:13:40 -08001048 const cricket::ContentInfo* audio_content = GetFirstAudioContent(remote_desc);
1049 const cricket::ContentInfo* video_content = GetFirstVideoContent(remote_desc);
1050 const cricket::AudioContentDescription* audio_desc =
1051 GetFirstAudioContentDescription(remote_desc);
1052 const cricket::VideoContentDescription* video_desc =
1053 GetFirstVideoContentDescription(remote_desc);
1054 const cricket::DataContentDescription* data_desc =
1055 GetFirstDataContentDescription(remote_desc);
1056
1057 // Check if the descriptions include streams, just in case the peer supports
1058 // MSID, but doesn't indicate so with "a=msid-semantic".
1059 if (remote_desc->msid_supported() ||
1060 (audio_desc && !audio_desc->streams().empty()) ||
1061 (video_desc && !video_desc->streams().empty())) {
1062 remote_peer_supports_msid_ = true;
1063 }
deadbeefab9b2d12015-10-14 11:33:11 -07001064
1065 // We wait to signal new streams until we finish processing the description,
1066 // since only at that point will new streams have all their tracks.
1067 rtc::scoped_refptr<StreamCollection> new_streams(StreamCollection::Create());
1068
1069 // Find all audio rtp streams and create corresponding remote AudioTracks
1070 // and MediaStreams.
deadbeefab9b2d12015-10-14 11:33:11 -07001071 if (audio_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001072 if (audio_content->rejected) {
1073 RemoveTracks(cricket::MEDIA_TYPE_AUDIO);
1074 } else {
deadbeefbda7e0b2015-12-08 17:13:40 -08001075 bool default_audio_track_needed =
1076 !remote_peer_supports_msid_ &&
1077 MediaContentDirectionHasSend(audio_desc->direction());
1078 UpdateRemoteStreamsList(GetActiveStreams(audio_desc),
1079 default_audio_track_needed, audio_desc->type(),
deadbeeffaac4972015-11-12 15:33:07 -08001080 new_streams);
deadbeeffaac4972015-11-12 15:33:07 -08001081 }
deadbeefab9b2d12015-10-14 11:33:11 -07001082 }
1083
1084 // Find all video rtp streams and create corresponding remote VideoTracks
1085 // and MediaStreams.
deadbeefab9b2d12015-10-14 11:33:11 -07001086 if (video_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001087 if (video_content->rejected) {
1088 RemoveTracks(cricket::MEDIA_TYPE_VIDEO);
1089 } else {
deadbeefbda7e0b2015-12-08 17:13:40 -08001090 bool default_video_track_needed =
1091 !remote_peer_supports_msid_ &&
1092 MediaContentDirectionHasSend(video_desc->direction());
1093 UpdateRemoteStreamsList(GetActiveStreams(video_desc),
1094 default_video_track_needed, video_desc->type(),
deadbeeffaac4972015-11-12 15:33:07 -08001095 new_streams);
deadbeeffaac4972015-11-12 15:33:07 -08001096 }
deadbeefab9b2d12015-10-14 11:33:11 -07001097 }
1098
1099 // Update the DataChannels with the information from the remote peer.
deadbeefbda7e0b2015-12-08 17:13:40 -08001100 if (data_desc) {
1101 if (rtc::starts_with(data_desc->protocol().data(),
deadbeefab9b2d12015-10-14 11:33:11 -07001102 cricket::kMediaProtocolRtpPrefix)) {
deadbeefbda7e0b2015-12-08 17:13:40 -08001103 UpdateRemoteRtpDataChannels(GetActiveStreams(data_desc));
deadbeefab9b2d12015-10-14 11:33:11 -07001104 }
1105 }
1106
1107 // Iterate new_streams and notify the observer about new MediaStreams.
1108 for (size_t i = 0; i < new_streams->count(); ++i) {
1109 MediaStreamInterface* new_stream = new_streams->at(i);
1110 stats_->AddStream(new_stream);
1111 observer_->OnAddStream(new_stream);
1112 }
1113
deadbeefbda7e0b2015-12-08 17:13:40 -08001114 UpdateEndedRemoteMediaStreams();
deadbeefab9b2d12015-10-14 11:33:11 -07001115
1116 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1117 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeeffc648b62015-10-13 16:42:33 -07001118}
1119
deadbeefa67696b2015-09-29 11:56:26 -07001120bool PeerConnection::SetConfiguration(const RTCConfiguration& config) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001121 TRACE_EVENT0("webrtc", "PeerConnection::SetConfiguration");
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001122 if (port_allocator_) {
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -08001123 cricket::ServerAddresses stun_servers;
1124 std::vector<cricket::RelayServerConfig> turn_servers;
1125 if (!ParseIceServers(config.servers, &stun_servers, &turn_servers)) {
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001126 return false;
1127 }
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -08001128 port_allocator_->SetIceServers(stun_servers, turn_servers);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001129 }
honghaiz1f429e32015-09-28 07:57:34 -07001130 session_->SetIceConfig(session_->ParseIceConfig(config));
mallinath@webrtc.org3d81b1b2014-09-09 14:38:10 +00001131 return session_->SetIceTransports(config.type);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001132}
1133
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001134bool PeerConnection::AddIceCandidate(
1135 const IceCandidateInterface* ice_candidate) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001136 TRACE_EVENT0("webrtc", "PeerConnection::AddIceCandidate");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001137 return session_->ProcessIceMessage(ice_candidate);
1138}
1139
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001140void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001141 TRACE_EVENT0("webrtc", "PeerConnection::RegisterUmaObserver");
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001142 uma_observer_ = observer;
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +00001143
1144 if (session_) {
1145 session_->set_metrics_observer(uma_observer_);
1146 }
1147
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001148 // Send information about IPv4/IPv6 status.
1149 if (uma_observer_ && port_allocator_) {
1150 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001151 uma_observer_->IncrementEnumCounter(
1152 kEnumCounterAddressFamily, kPeerConnection_IPv6,
1153 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgb445f262014-05-23 22:19:37 +00001154 } else {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001155 uma_observer_->IncrementEnumCounter(
1156 kEnumCounterAddressFamily, kPeerConnection_IPv4,
1157 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001158 }
1159 }
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001160}
1161
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001162const SessionDescriptionInterface* PeerConnection::local_description() const {
1163 return session_->local_description();
1164}
1165
1166const SessionDescriptionInterface* PeerConnection::remote_description() const {
1167 return session_->remote_description();
1168}
1169
1170void PeerConnection::Close() {
Peter Boström1a9d6152015-12-08 22:15:17 +01001171 TRACE_EVENT0("webrtc", "PeerConnection::Close");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001172 // Update stats here so that we have the most recent stats for tracks and
1173 // streams before the channels are closed.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001174 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001175
deadbeefd59daf82015-10-14 15:02:44 -07001176 session_->Close();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001177}
1178
deadbeefd59daf82015-10-14 15:02:44 -07001179void PeerConnection::OnSessionStateChange(WebRtcSession* /*session*/,
1180 WebRtcSession::State state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001181 switch (state) {
deadbeefd59daf82015-10-14 15:02:44 -07001182 case WebRtcSession::STATE_INIT:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001183 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001184 break;
deadbeefd59daf82015-10-14 15:02:44 -07001185 case WebRtcSession::STATE_SENTOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001186 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
1187 break;
deadbeefd59daf82015-10-14 15:02:44 -07001188 case WebRtcSession::STATE_SENTPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001189 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
1190 break;
deadbeefd59daf82015-10-14 15:02:44 -07001191 case WebRtcSession::STATE_RECEIVEDOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001192 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
1193 break;
deadbeefd59daf82015-10-14 15:02:44 -07001194 case WebRtcSession::STATE_RECEIVEDPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001195 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
1196 break;
deadbeefd59daf82015-10-14 15:02:44 -07001197 case WebRtcSession::STATE_INPROGRESS:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001198 ChangeSignalingState(PeerConnectionInterface::kStable);
1199 break;
deadbeefd59daf82015-10-14 15:02:44 -07001200 case WebRtcSession::STATE_CLOSED:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001201 ChangeSignalingState(PeerConnectionInterface::kClosed);
1202 break;
1203 default:
1204 break;
1205 }
1206}
1207
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001208void PeerConnection::OnMessage(rtc::Message* msg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001209 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001210 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
1211 SetSessionDescriptionMsg* param =
1212 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1213 param->observer->OnSuccess();
1214 delete param;
1215 break;
1216 }
1217 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
1218 SetSessionDescriptionMsg* param =
1219 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1220 param->observer->OnFailure(param->error);
1221 delete param;
1222 break;
1223 }
deadbeefab9b2d12015-10-14 11:33:11 -07001224 case MSG_CREATE_SESSIONDESCRIPTION_FAILED: {
1225 CreateSessionDescriptionMsg* param =
1226 static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
1227 param->observer->OnFailure(param->error);
1228 delete param;
1229 break;
1230 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001231 case MSG_GETSTATS: {
1232 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +00001233 StatsReports reports;
1234 stats_->GetStats(param->track, &reports);
1235 param->observer->OnComplete(reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001236 delete param;
1237 break;
1238 }
deadbeefbd292462015-12-14 18:15:29 -08001239 case MSG_FREE_DATACHANNELS: {
1240 sctp_data_channels_to_free_.clear();
1241 break;
1242 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001243 default:
deadbeef0a6c4ca2015-10-06 11:38:28 -07001244 RTC_DCHECK(false && "Not implemented");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001245 break;
1246 }
1247}
1248
deadbeefab9b2d12015-10-14 11:33:11 -07001249void PeerConnection::CreateAudioReceiver(MediaStreamInterface* stream,
1250 AudioTrackInterface* audio_track,
1251 uint32_t ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -07001252 receivers_.push_back(new AudioRtpReceiver(audio_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001253}
1254
deadbeefab9b2d12015-10-14 11:33:11 -07001255void PeerConnection::CreateVideoReceiver(MediaStreamInterface* stream,
1256 VideoTrackInterface* video_track,
1257 uint32_t ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -07001258 receivers_.push_back(new VideoRtpReceiver(video_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001259}
1260
deadbeef70ab1a12015-09-28 16:53:55 -07001261// TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote
1262// description.
deadbeefab9b2d12015-10-14 11:33:11 -07001263void PeerConnection::DestroyAudioReceiver(MediaStreamInterface* stream,
1264 AudioTrackInterface* audio_track) {
deadbeef70ab1a12015-09-28 16:53:55 -07001265 auto it = FindReceiverForTrack(audio_track);
1266 if (it == receivers_.end()) {
1267 LOG(LS_WARNING) << "RtpReceiver for track with id " << audio_track->id()
1268 << " doesn't exist.";
1269 } else {
1270 (*it)->Stop();
1271 receivers_.erase(it);
1272 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001273}
1274
deadbeefab9b2d12015-10-14 11:33:11 -07001275void PeerConnection::DestroyVideoReceiver(MediaStreamInterface* stream,
1276 VideoTrackInterface* video_track) {
deadbeef70ab1a12015-09-28 16:53:55 -07001277 auto it = FindReceiverForTrack(video_track);
1278 if (it == receivers_.end()) {
1279 LOG(LS_WARNING) << "RtpReceiver for track with id " << video_track->id()
1280 << " doesn't exist.";
1281 } else {
1282 (*it)->Stop();
1283 receivers_.erase(it);
1284 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001285}
deadbeef70ab1a12015-09-28 16:53:55 -07001286
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001287void PeerConnection::OnIceConnectionChange(
1288 PeerConnectionInterface::IceConnectionState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001289 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefcbecd352015-09-23 11:50:27 -07001290 // After transitioning to "closed", ignore any additional states from
1291 // WebRtcSession (such as "disconnected").
deadbeefab9b2d12015-10-14 11:33:11 -07001292 if (IsClosed()) {
deadbeefcbecd352015-09-23 11:50:27 -07001293 return;
1294 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001295 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001296 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001297}
1298
1299void PeerConnection::OnIceGatheringChange(
1300 PeerConnectionInterface::IceGatheringState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001301 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001302 if (IsClosed()) {
1303 return;
1304 }
1305 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001306 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001307}
1308
1309void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001310 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001311 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001312}
1313
1314void PeerConnection::OnIceComplete() {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001315 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001316 observer_->OnIceComplete();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001317}
1318
Peter Thatcher54360512015-07-08 11:08:35 -07001319void PeerConnection::OnIceConnectionReceivingChange(bool receiving) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001320 RTC_DCHECK(signaling_thread()->IsCurrent());
Peter Thatcher54360512015-07-08 11:08:35 -07001321 observer_->OnIceConnectionReceivingChange(receiving);
1322}
1323
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001324void PeerConnection::ChangeSignalingState(
1325 PeerConnectionInterface::SignalingState signaling_state) {
1326 signaling_state_ = signaling_state;
1327 if (signaling_state == kClosed) {
1328 ice_connection_state_ = kIceConnectionClosed;
1329 observer_->OnIceConnectionChange(ice_connection_state_);
1330 if (ice_gathering_state_ != kIceGatheringComplete) {
1331 ice_gathering_state_ = kIceGatheringComplete;
1332 observer_->OnIceGatheringChange(ice_gathering_state_);
1333 }
1334 }
1335 observer_->OnSignalingChange(signaling_state_);
1336 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
1337}
1338
deadbeefeb459812015-12-15 19:24:43 -08001339void PeerConnection::OnAudioTrackAdded(AudioTrackInterface* track,
1340 MediaStreamInterface* stream) {
1341 auto sender = FindSenderForTrack(track);
1342 if (sender != senders_.end()) {
1343 // We already have a sender for this track, so just change the stream_id
1344 // so that it's correct in the next call to CreateOffer.
1345 (*sender)->set_stream_id(stream->label());
1346 return;
1347 }
1348
1349 // Normal case; we've never seen this track before.
1350 AudioRtpSender* new_sender =
1351 new AudioRtpSender(track, stream->label(), session_.get(), stats_.get());
1352 senders_.push_back(new_sender);
1353 // If the sender has already been configured in SDP, we call SetSsrc,
1354 // which will connect the sender to the underlying transport. This can
1355 // occur if a local session description that contains the ID of the sender
1356 // is set before AddStream is called. It can also occur if the local
1357 // session description is not changed and RemoveStream is called, and
1358 // later AddStream is called again with the same stream.
1359 const TrackInfo* track_info =
1360 FindTrackInfo(local_audio_tracks_, stream->label(), track->id());
1361 if (track_info) {
1362 new_sender->SetSsrc(track_info->ssrc);
1363 }
1364}
1365
1366// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around
1367// indefinitely, when we have unified plan SDP.
1368void PeerConnection::OnAudioTrackRemoved(AudioTrackInterface* track,
1369 MediaStreamInterface* stream) {
1370 auto sender = FindSenderForTrack(track);
1371 if (sender == senders_.end()) {
1372 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
1373 << " doesn't exist.";
1374 return;
1375 }
1376 (*sender)->Stop();
1377 senders_.erase(sender);
1378}
1379
1380void PeerConnection::OnVideoTrackAdded(VideoTrackInterface* track,
1381 MediaStreamInterface* stream) {
1382 auto sender = FindSenderForTrack(track);
1383 if (sender != senders_.end()) {
1384 // We already have a sender for this track, so just change the stream_id
1385 // so that it's correct in the next call to CreateOffer.
1386 (*sender)->set_stream_id(stream->label());
1387 return;
1388 }
1389
1390 // Normal case; we've never seen this track before.
1391 VideoRtpSender* new_sender =
1392 new VideoRtpSender(track, stream->label(), session_.get());
1393 senders_.push_back(new_sender);
1394 const TrackInfo* track_info =
1395 FindTrackInfo(local_video_tracks_, stream->label(), track->id());
1396 if (track_info) {
1397 new_sender->SetSsrc(track_info->ssrc);
1398 }
1399}
1400
1401void PeerConnection::OnVideoTrackRemoved(VideoTrackInterface* track,
1402 MediaStreamInterface* stream) {
1403 auto sender = FindSenderForTrack(track);
1404 if (sender == senders_.end()) {
1405 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
1406 << " doesn't exist.";
1407 return;
1408 }
1409 (*sender)->Stop();
1410 senders_.erase(sender);
1411}
1412
deadbeefab9b2d12015-10-14 11:33:11 -07001413void PeerConnection::PostSetSessionDescriptionFailure(
1414 SetSessionDescriptionObserver* observer,
1415 const std::string& error) {
1416 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1417 msg->error = error;
1418 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
1419}
1420
1421void PeerConnection::PostCreateSessionDescriptionFailure(
1422 CreateSessionDescriptionObserver* observer,
1423 const std::string& error) {
1424 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
1425 msg->error = error;
1426 signaling_thread()->Post(this, MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
1427}
1428
1429bool PeerConnection::GetOptionsForOffer(
1430 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
1431 cricket::MediaSessionOptions* session_options) {
deadbeefab9b2d12015-10-14 11:33:11 -07001432 if (!ConvertRtcOptionsForOffer(rtc_options, session_options)) {
1433 return false;
1434 }
1435
deadbeeffac06552015-11-25 11:26:01 -08001436 AddSendStreams(session_options, senders_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001437 // Offer to receive audio/video if the constraint is not set and there are
1438 // send streams, or we're currently receiving.
1439 if (rtc_options.offer_to_receive_audio == RTCOfferAnswerOptions::kUndefined) {
1440 session_options->recv_audio =
1441 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_AUDIO) ||
1442 !remote_audio_tracks_.empty();
1443 }
1444 if (rtc_options.offer_to_receive_video == RTCOfferAnswerOptions::kUndefined) {
1445 session_options->recv_video =
1446 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_VIDEO) ||
1447 !remote_video_tracks_.empty();
1448 }
1449 session_options->bundle_enabled =
1450 session_options->bundle_enabled &&
1451 (session_options->has_audio() || session_options->has_video() ||
1452 session_options->has_data());
1453
deadbeefab9b2d12015-10-14 11:33:11 -07001454 if (session_->data_channel_type() == cricket::DCT_SCTP && HasDataChannels()) {
1455 session_options->data_channel_type = cricket::DCT_SCTP;
1456 }
1457 return true;
1458}
1459
1460bool PeerConnection::GetOptionsForAnswer(
1461 const MediaConstraintsInterface* constraints,
1462 cricket::MediaSessionOptions* session_options) {
deadbeefab9b2d12015-10-14 11:33:11 -07001463 session_options->recv_audio = false;
1464 session_options->recv_video = false;
deadbeefab9b2d12015-10-14 11:33:11 -07001465 if (!ParseConstraintsForAnswer(constraints, session_options)) {
1466 return false;
1467 }
1468
deadbeeffac06552015-11-25 11:26:01 -08001469 AddSendStreams(session_options, senders_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001470 session_options->bundle_enabled =
1471 session_options->bundle_enabled &&
1472 (session_options->has_audio() || session_options->has_video() ||
1473 session_options->has_data());
1474
deadbeefab9b2d12015-10-14 11:33:11 -07001475 // RTP data channel is handled in MediaSessionOptions::AddStream. SCTP streams
1476 // are not signaled in the SDP so does not go through that path and must be
1477 // handled here.
1478 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1479 session_options->data_channel_type = cricket::DCT_SCTP;
1480 }
1481 return true;
1482}
1483
deadbeeffaac4972015-11-12 15:33:07 -08001484void PeerConnection::RemoveTracks(cricket::MediaType media_type) {
1485 UpdateLocalTracks(std::vector<cricket::StreamParams>(), media_type);
deadbeefbda7e0b2015-12-08 17:13:40 -08001486 UpdateRemoteStreamsList(std::vector<cricket::StreamParams>(), false,
1487 media_type, nullptr);
deadbeeffaac4972015-11-12 15:33:07 -08001488}
1489
deadbeefab9b2d12015-10-14 11:33:11 -07001490void PeerConnection::UpdateRemoteStreamsList(
1491 const cricket::StreamParamsVec& streams,
deadbeefbda7e0b2015-12-08 17:13:40 -08001492 bool default_track_needed,
deadbeefab9b2d12015-10-14 11:33:11 -07001493 cricket::MediaType media_type,
1494 StreamCollection* new_streams) {
1495 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1496
1497 // Find removed tracks. I.e., tracks where the track id or ssrc don't match
deadbeeffac06552015-11-25 11:26:01 -08001498 // the new StreamParam.
deadbeefab9b2d12015-10-14 11:33:11 -07001499 auto track_it = current_tracks->begin();
1500 while (track_it != current_tracks->end()) {
1501 const TrackInfo& info = *track_it;
1502 const cricket::StreamParams* params =
1503 cricket::GetStreamBySsrc(streams, info.ssrc);
deadbeefbda7e0b2015-12-08 17:13:40 -08001504 bool track_exists = params && params->id == info.track_id;
1505 // If this is a default track, and we still need it, don't remove it.
1506 if ((info.stream_label == kDefaultStreamLabel && default_track_needed) ||
1507 track_exists) {
1508 ++track_it;
1509 } else {
deadbeefab9b2d12015-10-14 11:33:11 -07001510 OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
1511 track_it = current_tracks->erase(track_it);
deadbeefab9b2d12015-10-14 11:33:11 -07001512 }
1513 }
1514
1515 // Find new and active tracks.
1516 for (const cricket::StreamParams& params : streams) {
1517 // The sync_label is the MediaStream label and the |stream.id| is the
1518 // track id.
1519 const std::string& stream_label = params.sync_label;
1520 const std::string& track_id = params.id;
1521 uint32_t ssrc = params.first_ssrc();
1522
1523 rtc::scoped_refptr<MediaStreamInterface> stream =
1524 remote_streams_->find(stream_label);
1525 if (!stream) {
1526 // This is a new MediaStream. Create a new remote MediaStream.
1527 stream = remote_stream_factory_->CreateMediaStream(stream_label);
1528 remote_streams_->AddStream(stream);
1529 new_streams->AddStream(stream);
1530 }
1531
1532 const TrackInfo* track_info =
1533 FindTrackInfo(*current_tracks, stream_label, track_id);
1534 if (!track_info) {
1535 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1536 OnRemoteTrackSeen(stream_label, track_id, ssrc, media_type);
1537 }
1538 }
deadbeefbda7e0b2015-12-08 17:13:40 -08001539
1540 // Add default track if necessary.
1541 if (default_track_needed) {
1542 rtc::scoped_refptr<MediaStreamInterface> default_stream =
1543 remote_streams_->find(kDefaultStreamLabel);
1544 if (!default_stream) {
1545 // Create the new default MediaStream.
1546 default_stream =
1547 remote_stream_factory_->CreateMediaStream(kDefaultStreamLabel);
1548 remote_streams_->AddStream(default_stream);
1549 new_streams->AddStream(default_stream);
1550 }
1551 std::string default_track_id = (media_type == cricket::MEDIA_TYPE_AUDIO)
1552 ? kDefaultAudioTrackLabel
1553 : kDefaultVideoTrackLabel;
1554 const TrackInfo* default_track_info =
1555 FindTrackInfo(*current_tracks, kDefaultStreamLabel, default_track_id);
1556 if (!default_track_info) {
1557 current_tracks->push_back(
1558 TrackInfo(kDefaultStreamLabel, default_track_id, 0));
1559 OnRemoteTrackSeen(kDefaultStreamLabel, default_track_id, 0, media_type);
1560 }
1561 }
deadbeefab9b2d12015-10-14 11:33:11 -07001562}
1563
1564void PeerConnection::OnRemoteTrackSeen(const std::string& stream_label,
1565 const std::string& track_id,
1566 uint32_t ssrc,
1567 cricket::MediaType media_type) {
1568 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1569
1570 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
Tommif888bb52015-12-12 01:37:01 +01001571 AudioTrackInterface* audio_track = remote_stream_factory_->AddAudioTrack(
1572 ssrc, session_.get(), stream, track_id);
deadbeefab9b2d12015-10-14 11:33:11 -07001573 CreateAudioReceiver(stream, audio_track, ssrc);
1574 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1575 VideoTrackInterface* video_track =
1576 remote_stream_factory_->AddVideoTrack(stream, track_id);
1577 CreateVideoReceiver(stream, video_track, ssrc);
1578 } else {
1579 RTC_DCHECK(false && "Invalid media type");
1580 }
1581}
1582
1583void PeerConnection::OnRemoteTrackRemoved(const std::string& stream_label,
1584 const std::string& track_id,
1585 cricket::MediaType media_type) {
1586 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1587
1588 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1589 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1590 stream->FindAudioTrack(track_id);
1591 if (audio_track) {
1592 audio_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1593 stream->RemoveTrack(audio_track);
1594 DestroyAudioReceiver(stream, audio_track);
1595 }
1596 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1597 rtc::scoped_refptr<VideoTrackInterface> video_track =
1598 stream->FindVideoTrack(track_id);
1599 if (video_track) {
1600 video_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1601 stream->RemoveTrack(video_track);
1602 DestroyVideoReceiver(stream, video_track);
1603 }
1604 } else {
1605 ASSERT(false && "Invalid media type");
1606 }
1607}
1608
1609void PeerConnection::UpdateEndedRemoteMediaStreams() {
1610 std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams_to_remove;
1611 for (size_t i = 0; i < remote_streams_->count(); ++i) {
1612 MediaStreamInterface* stream = remote_streams_->at(i);
1613 if (stream->GetAudioTracks().empty() && stream->GetVideoTracks().empty()) {
1614 streams_to_remove.push_back(stream);
1615 }
1616 }
1617
1618 for (const auto& stream : streams_to_remove) {
1619 remote_streams_->RemoveStream(stream);
1620 observer_->OnRemoveStream(stream);
1621 }
1622}
1623
deadbeefab9b2d12015-10-14 11:33:11 -07001624void PeerConnection::EndRemoteTracks(cricket::MediaType media_type) {
1625 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1626 for (TrackInfos::iterator track_it = current_tracks->begin();
1627 track_it != current_tracks->end(); ++track_it) {
1628 const TrackInfo& info = *track_it;
1629 MediaStreamInterface* stream = remote_streams_->find(info.stream_label);
1630 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1631 AudioTrackInterface* track = stream->FindAudioTrack(info.track_id);
1632 // There's no guarantee the track is still available, e.g. the track may
1633 // have been removed from the stream by javascript.
1634 if (track) {
1635 track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1636 }
1637 }
1638 if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1639 VideoTrackInterface* track = stream->FindVideoTrack(info.track_id);
1640 // There's no guarantee the track is still available, e.g. the track may
1641 // have been removed from the stream by javascript.
1642 if (track) {
1643 track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1644 }
1645 }
1646 }
1647}
1648
1649void PeerConnection::UpdateLocalTracks(
1650 const std::vector<cricket::StreamParams>& streams,
1651 cricket::MediaType media_type) {
1652 TrackInfos* current_tracks = GetLocalTracks(media_type);
1653
1654 // Find removed tracks. I.e., tracks where the track id, stream label or ssrc
1655 // don't match the new StreamParam.
1656 TrackInfos::iterator track_it = current_tracks->begin();
1657 while (track_it != current_tracks->end()) {
1658 const TrackInfo& info = *track_it;
1659 const cricket::StreamParams* params =
1660 cricket::GetStreamBySsrc(streams, info.ssrc);
1661 if (!params || params->id != info.track_id ||
1662 params->sync_label != info.stream_label) {
1663 OnLocalTrackRemoved(info.stream_label, info.track_id, info.ssrc,
1664 media_type);
1665 track_it = current_tracks->erase(track_it);
1666 } else {
1667 ++track_it;
1668 }
1669 }
1670
1671 // Find new and active tracks.
1672 for (const cricket::StreamParams& params : streams) {
1673 // The sync_label is the MediaStream label and the |stream.id| is the
1674 // track id.
1675 const std::string& stream_label = params.sync_label;
1676 const std::string& track_id = params.id;
1677 uint32_t ssrc = params.first_ssrc();
1678 const TrackInfo* track_info =
1679 FindTrackInfo(*current_tracks, stream_label, track_id);
1680 if (!track_info) {
1681 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1682 OnLocalTrackSeen(stream_label, track_id, params.first_ssrc(), media_type);
1683 }
1684 }
1685}
1686
1687void PeerConnection::OnLocalTrackSeen(const std::string& stream_label,
1688 const std::string& track_id,
1689 uint32_t ssrc,
1690 cricket::MediaType media_type) {
deadbeeffac06552015-11-25 11:26:01 -08001691 RtpSenderInterface* sender = FindSenderById(track_id);
1692 if (!sender) {
1693 LOG(LS_WARNING) << "An unknown RtpSender with id " << track_id
1694 << " has been configured in the local description.";
deadbeefab9b2d12015-10-14 11:33:11 -07001695 return;
1696 }
1697
deadbeeffac06552015-11-25 11:26:01 -08001698 if (sender->media_type() != media_type) {
1699 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
1700 << " description with an unexpected media type.";
1701 return;
deadbeefab9b2d12015-10-14 11:33:11 -07001702 }
deadbeeffac06552015-11-25 11:26:01 -08001703
1704 sender->set_stream_id(stream_label);
1705 sender->SetSsrc(ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -07001706}
1707
1708void PeerConnection::OnLocalTrackRemoved(const std::string& stream_label,
1709 const std::string& track_id,
1710 uint32_t ssrc,
1711 cricket::MediaType media_type) {
deadbeeffac06552015-11-25 11:26:01 -08001712 RtpSenderInterface* sender = FindSenderById(track_id);
1713 if (!sender) {
1714 // This is the normal case. I.e., RemoveStream has been called and the
deadbeefab9b2d12015-10-14 11:33:11 -07001715 // SessionDescriptions has been renegotiated.
1716 return;
1717 }
deadbeeffac06552015-11-25 11:26:01 -08001718
1719 // A sender has been removed from the SessionDescription but it's still
1720 // associated with the PeerConnection. This only occurs if the SDP doesn't
1721 // match with the calls to CreateSender, AddStream and RemoveStream.
1722 if (sender->media_type() != media_type) {
1723 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
1724 << " description with an unexpected media type.";
1725 return;
deadbeefab9b2d12015-10-14 11:33:11 -07001726 }
deadbeeffac06552015-11-25 11:26:01 -08001727
1728 sender->SetSsrc(0);
deadbeefab9b2d12015-10-14 11:33:11 -07001729}
1730
1731void PeerConnection::UpdateLocalRtpDataChannels(
1732 const cricket::StreamParamsVec& streams) {
1733 std::vector<std::string> existing_channels;
1734
1735 // Find new and active data channels.
1736 for (const cricket::StreamParams& params : streams) {
1737 // |it->sync_label| is actually the data channel label. The reason is that
1738 // we use the same naming of data channels as we do for
1739 // MediaStreams and Tracks.
1740 // For MediaStreams, the sync_label is the MediaStream label and the
1741 // track label is the same as |streamid|.
1742 const std::string& channel_label = params.sync_label;
1743 auto data_channel_it = rtp_data_channels_.find(channel_label);
1744 if (!VERIFY(data_channel_it != rtp_data_channels_.end())) {
1745 continue;
1746 }
1747 // Set the SSRC the data channel should use for sending.
1748 data_channel_it->second->SetSendSsrc(params.first_ssrc());
1749 existing_channels.push_back(data_channel_it->first);
1750 }
1751
1752 UpdateClosingRtpDataChannels(existing_channels, true);
1753}
1754
1755void PeerConnection::UpdateRemoteRtpDataChannels(
1756 const cricket::StreamParamsVec& streams) {
1757 std::vector<std::string> existing_channels;
1758
1759 // Find new and active data channels.
1760 for (const cricket::StreamParams& params : streams) {
1761 // The data channel label is either the mslabel or the SSRC if the mslabel
1762 // does not exist. Ex a=ssrc:444330170 mslabel:test1.
1763 std::string label = params.sync_label.empty()
1764 ? rtc::ToString(params.first_ssrc())
1765 : params.sync_label;
1766 auto data_channel_it = rtp_data_channels_.find(label);
1767 if (data_channel_it == rtp_data_channels_.end()) {
1768 // This is a new data channel.
1769 CreateRemoteRtpDataChannel(label, params.first_ssrc());
1770 } else {
1771 data_channel_it->second->SetReceiveSsrc(params.first_ssrc());
1772 }
1773 existing_channels.push_back(label);
1774 }
1775
1776 UpdateClosingRtpDataChannels(existing_channels, false);
1777}
1778
1779void PeerConnection::UpdateClosingRtpDataChannels(
1780 const std::vector<std::string>& active_channels,
1781 bool is_local_update) {
1782 auto it = rtp_data_channels_.begin();
1783 while (it != rtp_data_channels_.end()) {
1784 DataChannel* data_channel = it->second;
1785 if (std::find(active_channels.begin(), active_channels.end(),
1786 data_channel->label()) != active_channels.end()) {
1787 ++it;
1788 continue;
1789 }
1790
1791 if (is_local_update) {
1792 data_channel->SetSendSsrc(0);
1793 } else {
1794 data_channel->RemotePeerRequestClose();
1795 }
1796
1797 if (data_channel->state() == DataChannel::kClosed) {
1798 rtp_data_channels_.erase(it);
1799 it = rtp_data_channels_.begin();
1800 } else {
1801 ++it;
1802 }
1803 }
1804}
1805
1806void PeerConnection::CreateRemoteRtpDataChannel(const std::string& label,
1807 uint32_t remote_ssrc) {
1808 rtc::scoped_refptr<DataChannel> channel(
1809 InternalCreateDataChannel(label, nullptr));
1810 if (!channel.get()) {
1811 LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
1812 << "CreateDataChannel failed.";
1813 return;
1814 }
1815 channel->SetReceiveSsrc(remote_ssrc);
1816 observer_->OnDataChannel(
1817 DataChannelProxy::Create(signaling_thread(), channel));
1818}
1819
1820rtc::scoped_refptr<DataChannel> PeerConnection::InternalCreateDataChannel(
1821 const std::string& label,
1822 const InternalDataChannelInit* config) {
1823 if (IsClosed()) {
1824 return nullptr;
1825 }
1826 if (session_->data_channel_type() == cricket::DCT_NONE) {
1827 LOG(LS_ERROR)
1828 << "InternalCreateDataChannel: Data is not supported in this call.";
1829 return nullptr;
1830 }
1831 InternalDataChannelInit new_config =
1832 config ? (*config) : InternalDataChannelInit();
1833 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1834 if (new_config.id < 0) {
1835 rtc::SSLRole role;
1836 if (session_->GetSslRole(&role) &&
1837 !sid_allocator_.AllocateSid(role, &new_config.id)) {
1838 LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel.";
1839 return nullptr;
1840 }
1841 } else if (!sid_allocator_.ReserveSid(new_config.id)) {
1842 LOG(LS_ERROR) << "Failed to create a SCTP data channel "
1843 << "because the id is already in use or out of range.";
1844 return nullptr;
1845 }
1846 }
1847
1848 rtc::scoped_refptr<DataChannel> channel(DataChannel::Create(
1849 session_.get(), session_->data_channel_type(), label, new_config));
1850 if (!channel) {
1851 sid_allocator_.ReleaseSid(new_config.id);
1852 return nullptr;
1853 }
1854
1855 if (channel->data_channel_type() == cricket::DCT_RTP) {
1856 if (rtp_data_channels_.find(channel->label()) != rtp_data_channels_.end()) {
1857 LOG(LS_ERROR) << "DataChannel with label " << channel->label()
1858 << " already exists.";
1859 return nullptr;
1860 }
1861 rtp_data_channels_[channel->label()] = channel;
1862 } else {
1863 RTC_DCHECK(channel->data_channel_type() == cricket::DCT_SCTP);
1864 sctp_data_channels_.push_back(channel);
1865 channel->SignalClosed.connect(this,
1866 &PeerConnection::OnSctpDataChannelClosed);
1867 }
1868
1869 return channel;
1870}
1871
1872bool PeerConnection::HasDataChannels() const {
1873 return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
1874}
1875
1876void PeerConnection::AllocateSctpSids(rtc::SSLRole role) {
1877 for (const auto& channel : sctp_data_channels_) {
1878 if (channel->id() < 0) {
1879 int sid;
1880 if (!sid_allocator_.AllocateSid(role, &sid)) {
1881 LOG(LS_ERROR) << "Failed to allocate SCTP sid.";
1882 continue;
1883 }
1884 channel->SetSctpSid(sid);
1885 }
1886 }
1887}
1888
1889void PeerConnection::OnSctpDataChannelClosed(DataChannel* channel) {
deadbeefbd292462015-12-14 18:15:29 -08001890 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefab9b2d12015-10-14 11:33:11 -07001891 for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end();
1892 ++it) {
1893 if (it->get() == channel) {
1894 if (channel->id() >= 0) {
1895 sid_allocator_.ReleaseSid(channel->id());
1896 }
deadbeefbd292462015-12-14 18:15:29 -08001897 // Since this method is triggered by a signal from the DataChannel,
1898 // we can't free it directly here; we need to free it asynchronously.
1899 sctp_data_channels_to_free_.push_back(*it);
deadbeefab9b2d12015-10-14 11:33:11 -07001900 sctp_data_channels_.erase(it);
deadbeefbd292462015-12-14 18:15:29 -08001901 signaling_thread()->Post(this, MSG_FREE_DATACHANNELS, nullptr);
deadbeefab9b2d12015-10-14 11:33:11 -07001902 return;
1903 }
1904 }
1905}
1906
1907void PeerConnection::OnVoiceChannelDestroyed() {
1908 EndRemoteTracks(cricket::MEDIA_TYPE_AUDIO);
1909}
1910
1911void PeerConnection::OnVideoChannelDestroyed() {
1912 EndRemoteTracks(cricket::MEDIA_TYPE_VIDEO);
1913}
1914
1915void PeerConnection::OnDataChannelCreated() {
1916 for (const auto& channel : sctp_data_channels_) {
1917 channel->OnTransportChannelCreated();
1918 }
1919}
1920
1921void PeerConnection::OnDataChannelDestroyed() {
1922 // Use a temporary copy of the RTP/SCTP DataChannel list because the
1923 // DataChannel may callback to us and try to modify the list.
1924 std::map<std::string, rtc::scoped_refptr<DataChannel>> temp_rtp_dcs;
1925 temp_rtp_dcs.swap(rtp_data_channels_);
1926 for (const auto& kv : temp_rtp_dcs) {
1927 kv.second->OnTransportChannelDestroyed();
1928 }
1929
1930 std::vector<rtc::scoped_refptr<DataChannel>> temp_sctp_dcs;
1931 temp_sctp_dcs.swap(sctp_data_channels_);
1932 for (const auto& channel : temp_sctp_dcs) {
1933 channel->OnTransportChannelDestroyed();
1934 }
1935}
1936
1937void PeerConnection::OnDataChannelOpenMessage(
1938 const std::string& label,
1939 const InternalDataChannelInit& config) {
1940 rtc::scoped_refptr<DataChannel> channel(
1941 InternalCreateDataChannel(label, &config));
1942 if (!channel.get()) {
1943 LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
1944 return;
1945 }
1946
1947 observer_->OnDataChannel(
1948 DataChannelProxy::Create(signaling_thread(), channel));
1949}
1950
deadbeeffac06552015-11-25 11:26:01 -08001951RtpSenderInterface* PeerConnection::FindSenderById(const std::string& id) {
1952 auto it =
1953 std::find_if(senders_.begin(), senders_.end(),
1954 [id](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
1955 return sender->id() == id;
1956 });
1957 return it != senders_.end() ? it->get() : nullptr;
1958}
1959
deadbeef70ab1a12015-09-28 16:53:55 -07001960std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator
1961PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) {
1962 return std::find_if(
1963 senders_.begin(), senders_.end(),
1964 [track](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
1965 return sender->track() == track;
1966 });
1967}
1968
1969std::vector<rtc::scoped_refptr<RtpReceiverInterface>>::iterator
1970PeerConnection::FindReceiverForTrack(MediaStreamTrackInterface* track) {
1971 return std::find_if(
1972 receivers_.begin(), receivers_.end(),
1973 [track](const rtc::scoped_refptr<RtpReceiverInterface>& receiver) {
1974 return receiver->track() == track;
1975 });
1976}
1977
deadbeefab9b2d12015-10-14 11:33:11 -07001978PeerConnection::TrackInfos* PeerConnection::GetRemoteTracks(
1979 cricket::MediaType media_type) {
1980 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
1981 media_type == cricket::MEDIA_TYPE_VIDEO);
1982 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &remote_audio_tracks_
1983 : &remote_video_tracks_;
1984}
1985
1986PeerConnection::TrackInfos* PeerConnection::GetLocalTracks(
1987 cricket::MediaType media_type) {
1988 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
1989 media_type == cricket::MEDIA_TYPE_VIDEO);
1990 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &local_audio_tracks_
1991 : &local_video_tracks_;
1992}
1993
1994const PeerConnection::TrackInfo* PeerConnection::FindTrackInfo(
1995 const PeerConnection::TrackInfos& infos,
1996 const std::string& stream_label,
1997 const std::string track_id) const {
1998 for (const TrackInfo& track_info : infos) {
1999 if (track_info.stream_label == stream_label &&
2000 track_info.track_id == track_id) {
2001 return &track_info;
2002 }
2003 }
2004 return nullptr;
2005}
2006
2007DataChannel* PeerConnection::FindDataChannelBySid(int sid) const {
2008 for (const auto& channel : sctp_data_channels_) {
2009 if (channel->id() == sid) {
2010 return channel;
2011 }
2012 }
2013 return nullptr;
2014}
2015
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002016} // namespace webrtc