blob: 691a512b6af158811e25c111c8662a8cb35328ed [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellanderb24317b2016-02-10 07:54:43 -08002 * Copyright 2012 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellanderb24317b2016-02-10 07:54:43 -08004 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Henrik Kjellander15583c12016-02-10 10:53:12 +010011#include "webrtc/api/peerconnection.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
deadbeefeb459812015-12-15 19:24:43 -080013#include <algorithm>
deadbeef0a6c4ca2015-10-06 11:38:28 -070014#include <cctype> // for isdigit
kwiberg0eb15ed2015-12-17 03:04:15 -080015#include <utility>
16#include <vector>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000017
Henrik Kjellander15583c12016-02-10 10:53:12 +010018#include "webrtc/api/audiotrack.h"
19#include "webrtc/api/dtmfsender.h"
20#include "webrtc/api/jsepicecandidate.h"
21#include "webrtc/api/jsepsessiondescription.h"
22#include "webrtc/api/mediaconstraintsinterface.h"
23#include "webrtc/api/mediastream.h"
24#include "webrtc/api/mediastreamobserver.h"
25#include "webrtc/api/mediastreamproxy.h"
26#include "webrtc/api/mediastreamtrackproxy.h"
27#include "webrtc/api/remoteaudiosource.h"
Henrik Kjellander15583c12016-02-10 10:53:12 +010028#include "webrtc/api/rtpreceiver.h"
29#include "webrtc/api/rtpsender.h"
30#include "webrtc/api/streamcollection.h"
perkja3ede6c2016-03-08 01:27:48 +010031#include "webrtc/api/videocapturertracksource.h"
Henrik Kjellander15583c12016-02-10 10:53:12 +010032#include "webrtc/api/videotrack.h"
tfarina5237aaf2015-11-10 23:44:30 -080033#include "webrtc/base/arraysize.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000034#include "webrtc/base/logging.h"
35#include "webrtc/base/stringencode.h"
deadbeefab9b2d12015-10-14 11:33:11 -070036#include "webrtc/base/stringutils.h"
Peter Boström1a9d6152015-12-08 22:15:17 +010037#include "webrtc/base/trace_event.h"
kjellandera96e2d72016-02-04 23:52:28 -080038#include "webrtc/media/sctp/sctpdataengine.h"
tfarina5237aaf2015-11-10 23:44:30 -080039#include "webrtc/p2p/client/basicportallocator.h"
kjellander@webrtc.org9b8df252016-02-12 06:47:59 +010040#include "webrtc/pc/channelmanager.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010041#include "webrtc/system_wrappers/include/field_trial.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000042
43namespace {
44
deadbeefab9b2d12015-10-14 11:33:11 -070045using webrtc::DataChannel;
46using webrtc::MediaConstraintsInterface;
47using webrtc::MediaStreamInterface;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000048using webrtc::PeerConnectionInterface;
deadbeeffac06552015-11-25 11:26:01 -080049using webrtc::RtpSenderInterface;
deadbeefab9b2d12015-10-14 11:33:11 -070050using webrtc::StreamCollection;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000051
deadbeefab9b2d12015-10-14 11:33:11 -070052static const char kDefaultStreamLabel[] = "default";
53static const char kDefaultAudioTrackLabel[] = "defaulta0";
54static const char kDefaultVideoTrackLabel[] = "defaultv0";
55
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056// The min number of tokens must present in Turn host uri.
57// e.g. user@turn.example.org
58static const size_t kTurnHostTokensNum = 2;
59// Number of tokens must be preset when TURN uri has transport param.
60static const size_t kTurnTransportTokensNum = 2;
61// The default stun port.
wu@webrtc.org91053e72013-08-10 07:18:04 +000062static const int kDefaultStunPort = 3478;
63static const int kDefaultStunTlsPort = 5349;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000064static const char kTransport[] = "transport";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000065
66// NOTE: Must be in the same order as the ServiceType enum.
deadbeef0a6c4ca2015-10-06 11:38:28 -070067static const char* kValidIceServiceTypes[] = {"stun", "stuns", "turn", "turns"};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000068
deadbeef0a6c4ca2015-10-06 11:38:28 -070069// NOTE: A loop below assumes that the first value of this enum is 0 and all
70// other values are incremental.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071enum ServiceType {
deadbeef0a6c4ca2015-10-06 11:38:28 -070072 STUN = 0, // Indicates a STUN server.
73 STUNS, // Indicates a STUN server used with a TLS session.
74 TURN, // Indicates a TURN server
75 TURNS, // Indicates a TURN server used with a TLS session.
76 INVALID, // Unknown.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000077};
tfarina5237aaf2015-11-10 23:44:30 -080078static_assert(INVALID == arraysize(kValidIceServiceTypes),
deadbeef0a6c4ca2015-10-06 11:38:28 -070079 "kValidIceServiceTypes must have as many strings as ServiceType "
80 "has values.");
henrike@webrtc.org28e20752013-07-10 00:45:36 +000081
82enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +000083 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000084 MSG_SET_SESSIONDESCRIPTION_FAILED,
deadbeefab9b2d12015-10-14 11:33:11 -070085 MSG_CREATE_SESSIONDESCRIPTION_FAILED,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000086 MSG_GETSTATS,
deadbeefbd292462015-12-14 18:15:29 -080087 MSG_FREE_DATACHANNELS,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088};
89
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000090struct SetSessionDescriptionMsg : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000091 explicit SetSessionDescriptionMsg(
92 webrtc::SetSessionDescriptionObserver* observer)
93 : observer(observer) {
94 }
95
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000096 rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000097 std::string error;
98};
99
deadbeefab9b2d12015-10-14 11:33:11 -0700100struct CreateSessionDescriptionMsg : public rtc::MessageData {
101 explicit CreateSessionDescriptionMsg(
102 webrtc::CreateSessionDescriptionObserver* observer)
103 : observer(observer) {}
104
105 rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserver> observer;
106 std::string error;
107};
108
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000109struct GetStatsMsg : public rtc::MessageData {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000110 GetStatsMsg(webrtc::StatsObserver* observer,
111 webrtc::MediaStreamTrackInterface* track)
112 : observer(observer), track(track) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000113 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000114 rtc::scoped_refptr<webrtc::StatsObserver> observer;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000115 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000116};
117
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000118// |in_str| should be of format
119// stunURI = scheme ":" stun-host [ ":" stun-port ]
120// scheme = "stun" / "stuns"
121// stun-host = IP-literal / IPv4address / reg-name
122// stun-port = *DIGIT
deadbeef0a6c4ca2015-10-06 11:38:28 -0700123//
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000124// draft-petithuguenin-behave-turn-uris-01
125// turnURI = scheme ":" turn-host [ ":" turn-port ]
126// turn-host = username@IP-literal / IPv4address / reg-name
127bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
128 ServiceType* service_type,
129 std::string* hostname) {
Tommi77d444a2015-04-24 15:38:38 +0200130 const std::string::size_type colonpos = in_str.find(':');
deadbeef0a6c4ca2015-10-06 11:38:28 -0700131 if (colonpos == std::string::npos) {
132 LOG(LS_WARNING) << "Missing ':' in ICE URI: " << in_str;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000133 return false;
134 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700135 if ((colonpos + 1) == in_str.length()) {
136 LOG(LS_WARNING) << "Empty hostname in ICE URI: " << in_str;
137 return false;
138 }
139 *service_type = INVALID;
tfarina5237aaf2015-11-10 23:44:30 -0800140 for (size_t i = 0; i < arraysize(kValidIceServiceTypes); ++i) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700141 if (in_str.compare(0, colonpos, kValidIceServiceTypes[i]) == 0) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000142 *service_type = static_cast<ServiceType>(i);
143 break;
144 }
145 }
146 if (*service_type == INVALID) {
147 return false;
148 }
149 *hostname = in_str.substr(colonpos + 1, std::string::npos);
150 return true;
151}
152
deadbeef0a6c4ca2015-10-06 11:38:28 -0700153bool ParsePort(const std::string& in_str, int* port) {
154 // Make sure port only contains digits. FromString doesn't check this.
155 for (const char& c : in_str) {
156 if (!std::isdigit(c)) {
157 return false;
158 }
159 }
160 return rtc::FromString(in_str, port);
161}
162
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000163// This method parses IPv6 and IPv4 literal strings, along with hostnames in
164// standard hostname:port format.
165// Consider following formats as correct.
166// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700167// |hostname|, |[IPv6 address]|, |IPv4 address|.
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000168bool ParseHostnameAndPortFromString(const std::string& in_str,
169 std::string* host,
170 int* port) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700171 RTC_DCHECK(host->empty());
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000172 if (in_str.at(0) == '[') {
173 std::string::size_type closebracket = in_str.rfind(']');
174 if (closebracket != std::string::npos) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000175 std::string::size_type colonpos = in_str.find(':', closebracket);
176 if (std::string::npos != colonpos) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700177 if (!ParsePort(in_str.substr(closebracket + 2, std::string::npos),
178 port)) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000179 return false;
180 }
181 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700182 *host = in_str.substr(1, closebracket - 1);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000183 } else {
184 return false;
185 }
186 } else {
187 std::string::size_type colonpos = in_str.find(':');
188 if (std::string::npos != colonpos) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700189 if (!ParsePort(in_str.substr(colonpos + 1, std::string::npos), port)) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000190 return false;
191 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700192 *host = in_str.substr(0, colonpos);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000193 } else {
194 *host = in_str;
195 }
196 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700197 return !host->empty();
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000198}
199
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800200// Adds a STUN or TURN server to the appropriate list,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700201// by parsing |url| and using the username/password in |server|.
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200202bool ParseIceServerUrl(const PeerConnectionInterface::IceServer& server,
203 const std::string& url,
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800204 cricket::ServerAddresses* stun_servers,
205 std::vector<cricket::RelayServerConfig>* turn_servers) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000206 // draft-nandakumar-rtcweb-stun-uri-01
207 // stunURI = scheme ":" stun-host [ ":" stun-port ]
208 // scheme = "stun" / "stuns"
209 // stun-host = IP-literal / IPv4address / reg-name
210 // stun-port = *DIGIT
211
212 // draft-petithuguenin-behave-turn-uris-01
213 // turnURI = scheme ":" turn-host [ ":" turn-port ]
214 // [ "?transport=" transport ]
215 // scheme = "turn" / "turns"
216 // transport = "udp" / "tcp" / transport-ext
217 // transport-ext = 1*unreserved
218 // turn-host = IP-literal / IPv4address / reg-name
219 // turn-port = *DIGIT
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800220 RTC_DCHECK(stun_servers != nullptr);
221 RTC_DCHECK(turn_servers != nullptr);
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200222 std::vector<std::string> tokens;
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800223 cricket::ProtocolType turn_transport_type = cricket::PROTO_UDP;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700224 RTC_DCHECK(!url.empty());
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200225 rtc::tokenize(url, '?', &tokens);
226 std::string uri_without_transport = tokens[0];
227 // Let's look into transport= param, if it exists.
228 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
229 std::string uri_transport_param = tokens[1];
230 rtc::tokenize(uri_transport_param, '=', &tokens);
231 if (tokens[0] == kTransport) {
232 // As per above grammar transport param will be consist of lower case
233 // letters.
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800234 if (!cricket::StringToProto(tokens[1].c_str(), &turn_transport_type) ||
235 (turn_transport_type != cricket::PROTO_UDP &&
236 turn_transport_type != cricket::PROTO_TCP)) {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200237 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
deadbeef0a6c4ca2015-10-06 11:38:28 -0700238 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000239 }
240 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200241 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000242
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200243 std::string hoststring;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700244 ServiceType service_type;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200245 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
246 &service_type,
247 &hoststring)) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700248 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: " << url;
249 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200250 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000251
deadbeef0a6c4ca2015-10-06 11:38:28 -0700252 // GetServiceTypeAndHostnameFromUri should never give an empty hoststring
253 RTC_DCHECK(!hoststring.empty());
Tommi77d444a2015-04-24 15:38:38 +0200254
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200255 // Let's break hostname.
256 tokens.clear();
deadbeef0a6c4ca2015-10-06 11:38:28 -0700257 rtc::tokenize_with_empty_tokens(hoststring, '@', &tokens);
258
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200259 std::string username(server.username);
deadbeef0a6c4ca2015-10-06 11:38:28 -0700260 if (tokens.size() > kTurnHostTokensNum) {
261 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring;
262 return false;
263 }
264 if (tokens.size() == kTurnHostTokensNum) {
265 if (tokens[0].empty() || tokens[1].empty()) {
266 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring;
267 return false;
268 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200269 username.assign(rtc::s_url_decode(tokens[0]));
270 hoststring = tokens[1];
271 } else {
272 hoststring = tokens[0];
273 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000274
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200275 int port = kDefaultStunPort;
276 if (service_type == TURNS) {
277 port = kDefaultStunTlsPort;
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800278 turn_transport_type = cricket::PROTO_TCP;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200279 }
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000280
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200281 std::string address;
282 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700283 LOG(WARNING) << "Invalid hostname format: " << uri_without_transport;
284 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200285 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000286
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200287 if (port <= 0 || port > 0xffff) {
288 LOG(WARNING) << "Invalid port: " << port;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700289 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200290 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000291
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200292 switch (service_type) {
293 case STUN:
294 case STUNS:
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800295 stun_servers->insert(rtc::SocketAddress(address, port));
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200296 break;
297 case TURN:
298 case TURNS: {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200299 bool secure = (service_type == TURNS);
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800300 turn_servers->push_back(
301 cricket::RelayServerConfig(address, port, username, server.password,
302 turn_transport_type, secure));
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200303 break;
304 }
305 case INVALID:
306 default:
307 LOG(WARNING) << "Configuration not supported: " << url;
308 return false;
309 }
310 return true;
311}
312
deadbeefab9b2d12015-10-14 11:33:11 -0700313// Check if we can send |new_stream| on a PeerConnection.
314bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
315 webrtc::MediaStreamInterface* new_stream) {
316 if (!new_stream || !current_streams) {
317 return false;
318 }
319 if (current_streams->find(new_stream->label()) != nullptr) {
320 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
321 << " is already added.";
322 return false;
323 }
324 return true;
325}
326
327bool MediaContentDirectionHasSend(cricket::MediaContentDirection dir) {
328 return dir == cricket::MD_SENDONLY || dir == cricket::MD_SENDRECV;
329}
330
deadbeef5e97fb52015-10-15 12:49:08 -0700331// If the direction is "recvonly" or "inactive", treat the description
332// as containing no streams.
333// See: https://code.google.com/p/webrtc/issues/detail?id=5054
334std::vector<cricket::StreamParams> GetActiveStreams(
335 const cricket::MediaContentDescription* desc) {
336 return MediaContentDirectionHasSend(desc->direction())
337 ? desc->streams()
338 : std::vector<cricket::StreamParams>();
339}
340
deadbeefab9b2d12015-10-14 11:33:11 -0700341bool IsValidOfferToReceiveMedia(int value) {
342 typedef PeerConnectionInterface::RTCOfferAnswerOptions Options;
343 return (value >= Options::kUndefined) &&
344 (value <= Options::kMaxOfferToReceiveMedia);
345}
346
347// Add the stream and RTP data channel info to |session_options|.
deadbeeffac06552015-11-25 11:26:01 -0800348void AddSendStreams(
349 cricket::MediaSessionOptions* session_options,
350 const std::vector<rtc::scoped_refptr<RtpSenderInterface>>& senders,
351 const std::map<std::string, rtc::scoped_refptr<DataChannel>>&
352 rtp_data_channels) {
deadbeefab9b2d12015-10-14 11:33:11 -0700353 session_options->streams.clear();
deadbeeffac06552015-11-25 11:26:01 -0800354 for (const auto& sender : senders) {
355 session_options->AddSendStream(sender->media_type(), sender->id(),
356 sender->stream_id());
deadbeefab9b2d12015-10-14 11:33:11 -0700357 }
358
359 // Check for data channels.
360 for (const auto& kv : rtp_data_channels) {
361 const DataChannel* channel = kv.second;
362 if (channel->state() == DataChannel::kConnecting ||
363 channel->state() == DataChannel::kOpen) {
364 // |streamid| and |sync_label| are both set to the DataChannel label
365 // here so they can be signaled the same way as MediaStreams and Tracks.
366 // For MediaStreams, the sync_label is the MediaStream label and the
367 // track label is the same as |streamid|.
368 const std::string& streamid = channel->label();
369 const std::string& sync_label = channel->label();
370 session_options->AddSendStream(cricket::MEDIA_TYPE_DATA, streamid,
371 sync_label);
372 }
373 }
374}
375
deadbeef0a6c4ca2015-10-06 11:38:28 -0700376} // namespace
377
378namespace webrtc {
379
deadbeefab9b2d12015-10-14 11:33:11 -0700380// Factory class for creating remote MediaStreams and MediaStreamTracks.
381class RemoteMediaStreamFactory {
382 public:
perkjf0dcfe22016-03-10 18:32:00 +0100383 explicit RemoteMediaStreamFactory(rtc::Thread* signaling_thread)
384 : signaling_thread_(signaling_thread) {}
deadbeefab9b2d12015-10-14 11:33:11 -0700385
386 rtc::scoped_refptr<MediaStreamInterface> CreateMediaStream(
387 const std::string& stream_label) {
388 return MediaStreamProxy::Create(signaling_thread_,
389 MediaStream::Create(stream_label));
390 }
391
Tommif888bb52015-12-12 01:37:01 +0100392 AudioTrackInterface* AddAudioTrack(uint32_t ssrc,
393 AudioProviderInterface* provider,
394 webrtc::MediaStreamInterface* stream,
deadbeefab9b2d12015-10-14 11:33:11 -0700395 const std::string& track_id) {
tommi6eca7e32015-12-15 04:27:11 -0800396 return AddTrack<AudioTrackInterface, AudioTrack, AudioTrackProxy>(
Tommif888bb52015-12-12 01:37:01 +0100397 stream, track_id, RemoteAudioSource::Create(ssrc, provider));
deadbeefab9b2d12015-10-14 11:33:11 -0700398 }
399
deadbeefab9b2d12015-10-14 11:33:11 -0700400 private:
401 template <typename TI, typename T, typename TP, typename S>
402 TI* AddTrack(MediaStreamInterface* stream,
403 const std::string& track_id,
Tommif888bb52015-12-12 01:37:01 +0100404 const S& source) {
deadbeefab9b2d12015-10-14 11:33:11 -0700405 rtc::scoped_refptr<TI> track(
406 TP::Create(signaling_thread_, T::Create(track_id, source)));
407 track->set_state(webrtc::MediaStreamTrackInterface::kLive);
408 if (stream->AddTrack(track)) {
409 return track;
410 }
411 return nullptr;
412 }
413
414 rtc::Thread* signaling_thread_;
deadbeefab9b2d12015-10-14 11:33:11 -0700415};
416
htaa2a49d92016-03-04 02:51:39 -0800417bool ExtractMediaSessionOptions(
deadbeefab9b2d12015-10-14 11:33:11 -0700418 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
htaaac2dea2016-03-10 13:35:55 -0800419 bool is_offer,
deadbeefab9b2d12015-10-14 11:33:11 -0700420 cricket::MediaSessionOptions* session_options) {
421 typedef PeerConnectionInterface::RTCOfferAnswerOptions RTCOfferAnswerOptions;
422 if (!IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_audio) ||
423 !IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_video)) {
424 return false;
425 }
426
htaaac2dea2016-03-10 13:35:55 -0800427 // If constraints don't prevent us, we always accept video.
deadbeefc80741f2015-10-22 13:14:45 -0700428 if (rtc_options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) {
deadbeefab9b2d12015-10-14 11:33:11 -0700429 session_options->recv_audio = (rtc_options.offer_to_receive_audio > 0);
htaaac2dea2016-03-10 13:35:55 -0800430 } else {
431 session_options->recv_audio = true;
deadbeefab9b2d12015-10-14 11:33:11 -0700432 }
htaaac2dea2016-03-10 13:35:55 -0800433 // For offers, we only offer video if we have it or it's forced by options.
434 // For answers, we will always accept video (if offered).
deadbeefc80741f2015-10-22 13:14:45 -0700435 if (rtc_options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) {
deadbeefab9b2d12015-10-14 11:33:11 -0700436 session_options->recv_video = (rtc_options.offer_to_receive_video > 0);
htaaac2dea2016-03-10 13:35:55 -0800437 } else if (is_offer) {
438 session_options->recv_video = false;
439 } else {
440 session_options->recv_video = true;
deadbeefab9b2d12015-10-14 11:33:11 -0700441 }
442
443 session_options->vad_enabled = rtc_options.voice_activity_detection;
deadbeefc80741f2015-10-22 13:14:45 -0700444 session_options->bundle_enabled = rtc_options.use_rtp_mux;
deadbeef0ed85b22016-02-23 17:24:52 -0800445 for (auto& kv : session_options->transport_options) {
446 kv.second.ice_restart = rtc_options.ice_restart;
447 }
deadbeefab9b2d12015-10-14 11:33:11 -0700448
449 return true;
450}
451
452bool ParseConstraintsForAnswer(const MediaConstraintsInterface* constraints,
453 cricket::MediaSessionOptions* session_options) {
454 bool value = false;
455 size_t mandatory_constraints_satisfied = 0;
456
457 // kOfferToReceiveAudio defaults to true according to spec.
458 if (!FindConstraint(constraints,
459 MediaConstraintsInterface::kOfferToReceiveAudio, &value,
460 &mandatory_constraints_satisfied) ||
461 value) {
462 session_options->recv_audio = true;
463 }
464
465 // kOfferToReceiveVideo defaults to false according to spec. But
466 // if it is an answer and video is offered, we should still accept video
467 // per default.
468 value = false;
469 if (!FindConstraint(constraints,
470 MediaConstraintsInterface::kOfferToReceiveVideo, &value,
471 &mandatory_constraints_satisfied) ||
472 value) {
473 session_options->recv_video = true;
474 }
475
476 if (FindConstraint(constraints,
477 MediaConstraintsInterface::kVoiceActivityDetection, &value,
478 &mandatory_constraints_satisfied)) {
479 session_options->vad_enabled = value;
480 }
481
482 if (FindConstraint(constraints, MediaConstraintsInterface::kUseRtpMux, &value,
483 &mandatory_constraints_satisfied)) {
484 session_options->bundle_enabled = value;
485 } else {
486 // kUseRtpMux defaults to true according to spec.
487 session_options->bundle_enabled = true;
488 }
deadbeefab9b2d12015-10-14 11:33:11 -0700489
deadbeef0ed85b22016-02-23 17:24:52 -0800490 bool ice_restart = false;
deadbeefab9b2d12015-10-14 11:33:11 -0700491 if (FindConstraint(constraints, MediaConstraintsInterface::kIceRestart,
492 &value, &mandatory_constraints_satisfied)) {
deadbeefab9b2d12015-10-14 11:33:11 -0700493 // kIceRestart defaults to false according to spec.
deadbeef0ed85b22016-02-23 17:24:52 -0800494 ice_restart = true;
495 }
496 for (auto& kv : session_options->transport_options) {
497 kv.second.ice_restart = ice_restart;
deadbeefab9b2d12015-10-14 11:33:11 -0700498 }
499
500 if (!constraints) {
501 return true;
502 }
503 return mandatory_constraints_satisfied == constraints->GetMandatory().size();
504}
505
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200506bool ParseIceServers(const PeerConnectionInterface::IceServers& servers,
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800507 cricket::ServerAddresses* stun_servers,
508 std::vector<cricket::RelayServerConfig>* turn_servers) {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200509 for (const webrtc::PeerConnectionInterface::IceServer& server : servers) {
510 if (!server.urls.empty()) {
511 for (const std::string& url : server.urls) {
Joachim Bauchd935f912015-05-29 22:14:21 +0200512 if (url.empty()) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700513 LOG(LS_ERROR) << "Empty uri.";
514 return false;
Joachim Bauchd935f912015-05-29 22:14:21 +0200515 }
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800516 if (!ParseIceServerUrl(server, url, stun_servers, turn_servers)) {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200517 return false;
518 }
519 }
520 } else if (!server.uri.empty()) {
521 // Fallback to old .uri if new .urls isn't present.
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800522 if (!ParseIceServerUrl(server, server.uri, stun_servers, turn_servers)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000523 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200524 }
525 } else {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700526 LOG(LS_ERROR) << "Empty uri.";
527 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000528 }
529 }
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800530 // Candidates must have unique priorities, so that connectivity checks
531 // are performed in a well-defined order.
532 int priority = static_cast<int>(turn_servers->size() - 1);
533 for (cricket::RelayServerConfig& turn_server : *turn_servers) {
534 // First in the list gets highest priority.
535 turn_server.priority = priority--;
536 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000537 return true;
538}
539
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540PeerConnection::PeerConnection(PeerConnectionFactory* factory)
541 : factory_(factory),
542 observer_(NULL),
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000543 uma_observer_(NULL),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000544 signaling_state_(kStable),
545 ice_state_(kIceNew),
546 ice_connection_state_(kIceConnectionNew),
deadbeefab9b2d12015-10-14 11:33:11 -0700547 ice_gathering_state_(kIceGatheringNew),
548 local_streams_(StreamCollection::Create()),
549 remote_streams_(StreamCollection::Create()) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550
551PeerConnection::~PeerConnection() {
Peter Boström1a9d6152015-12-08 22:15:17 +0100552 TRACE_EVENT0("webrtc", "PeerConnection::~PeerConnection");
deadbeef0a6c4ca2015-10-06 11:38:28 -0700553 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeef70ab1a12015-09-28 16:53:55 -0700554 // Need to detach RTP senders/receivers from WebRtcSession,
555 // since it's about to be destroyed.
556 for (const auto& sender : senders_) {
557 sender->Stop();
558 }
559 for (const auto& receiver : receivers_) {
560 receiver->Stop();
561 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000562}
563
564bool PeerConnection::Initialize(
htaa2a49d92016-03-04 02:51:39 -0800565 const cricket::MediaConfig& media_config,
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000566 const PeerConnectionInterface::RTCConfiguration& configuration,
deadbeef653b8e02015-11-11 12:55:10 -0800567 rtc::scoped_ptr<cricket::PortAllocator> allocator,
568 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
569 PeerConnectionObserver* observer) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100570 TRACE_EVENT0("webrtc", "PeerConnection::Initialize");
deadbeef653b8e02015-11-11 12:55:10 -0800571 RTC_DCHECK(observer != nullptr);
572 if (!observer) {
573 return false;
574 }
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000575 observer_ = observer;
576
kwiberg0eb15ed2015-12-17 03:04:15 -0800577 port_allocator_ = std::move(allocator);
deadbeef653b8e02015-11-11 12:55:10 -0800578
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800579 cricket::ServerAddresses stun_servers;
580 std::vector<cricket::RelayServerConfig> turn_servers;
581 if (!ParseIceServers(configuration.servers, &stun_servers, &turn_servers)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582 return false;
583 }
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -0800584 port_allocator_->SetIceServers(stun_servers, turn_servers);
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000585
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000586 // To handle both internal and externally created port allocator, we will
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000587 // enable BUNDLE here.
braveyao@webrtc.org1732df62014-10-27 03:01:37 +0000588 int portallocator_flags = port_allocator_->flags();
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700589 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000590 cricket::PORTALLOCATOR_ENABLE_IPV6;
htaa2a49d92016-03-04 02:51:39 -0800591 // If the disable-IPv6 flag was specified, we'll not override it
592 // by experiment.
593 if (configuration.disable_ipv6) {
594 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
guoweis@webrtc.org2c1bcea2014-09-23 16:23:02 +0000595 } else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default") ==
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000596 "Disabled") {
597 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000598 }
599
Jiayang Liucac1b382015-04-30 12:35:24 -0700600 if (configuration.tcp_candidate_policy == kTcpCandidatePolicyDisabled) {
601 portallocator_flags |= cricket::PORTALLOCATOR_DISABLE_TCP;
602 LOG(LS_INFO) << "TCP candidates are disabled.";
603 }
604
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000605 port_allocator_->set_flags(portallocator_flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000606 // No step delay is used while allocating ports.
607 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
608
nisse51542be2016-02-12 02:27:06 -0800609 media_controller_.reset(factory_->CreateMediaController(media_config));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000610
perkjf0dcfe22016-03-10 18:32:00 +0100611 remote_stream_factory_.reset(
612 new RemoteMediaStreamFactory(factory_->signaling_thread()));
stefanc1aeaf02015-10-15 07:26:07 -0700613
614 session_.reset(
615 new WebRtcSession(media_controller_.get(), factory_->signaling_thread(),
616 factory_->worker_thread(), port_allocator_.get()));
deadbeefab9b2d12015-10-14 11:33:11 -0700617 stats_.reset(new StatsCollector(this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000618
619 // Initialize the WebRtcSession. It creates transport channels etc.
htaa2a49d92016-03-04 02:51:39 -0800620 if (!session_->Initialize(factory_->options(), std::move(dtls_identity_store),
621 configuration)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000622 return false;
deadbeefab9b2d12015-10-14 11:33:11 -0700623 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000624
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000625 // Register PeerConnection as receiver of local ice candidates.
626 // All the callbacks will be posted to the application from PeerConnection.
627 session_->RegisterIceObserver(this);
628 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
deadbeefab9b2d12015-10-14 11:33:11 -0700629 session_->SignalVoiceChannelDestroyed.connect(
630 this, &PeerConnection::OnVoiceChannelDestroyed);
631 session_->SignalVideoChannelDestroyed.connect(
632 this, &PeerConnection::OnVideoChannelDestroyed);
633 session_->SignalDataChannelCreated.connect(
634 this, &PeerConnection::OnDataChannelCreated);
635 session_->SignalDataChannelDestroyed.connect(
636 this, &PeerConnection::OnDataChannelDestroyed);
637 session_->SignalDataChannelOpenMessage.connect(
638 this, &PeerConnection::OnDataChannelOpenMessage);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000639 return true;
640}
641
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000642rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000643PeerConnection::local_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -0700644 return local_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000645}
646
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000647rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000648PeerConnection::remote_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -0700649 return remote_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000650}
651
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +0000652bool PeerConnection::AddStream(MediaStreamInterface* local_stream) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100653 TRACE_EVENT0("webrtc", "PeerConnection::AddStream");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000654 if (IsClosed()) {
655 return false;
656 }
deadbeefab9b2d12015-10-14 11:33:11 -0700657 if (!CanAddLocalMediaStream(local_streams_, local_stream)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658 return false;
659 }
deadbeefab9b2d12015-10-14 11:33:11 -0700660
661 local_streams_->AddStream(local_stream);
deadbeefeb459812015-12-15 19:24:43 -0800662 MediaStreamObserver* observer = new MediaStreamObserver(local_stream);
663 observer->SignalAudioTrackAdded.connect(this,
664 &PeerConnection::OnAudioTrackAdded);
665 observer->SignalAudioTrackRemoved.connect(
666 this, &PeerConnection::OnAudioTrackRemoved);
667 observer->SignalVideoTrackAdded.connect(this,
668 &PeerConnection::OnVideoTrackAdded);
669 observer->SignalVideoTrackRemoved.connect(
670 this, &PeerConnection::OnVideoTrackRemoved);
671 stream_observers_.push_back(rtc::scoped_ptr<MediaStreamObserver>(observer));
deadbeefab9b2d12015-10-14 11:33:11 -0700672
deadbeefab9b2d12015-10-14 11:33:11 -0700673 for (const auto& track : local_stream->GetAudioTracks()) {
deadbeefeb459812015-12-15 19:24:43 -0800674 OnAudioTrackAdded(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -0700675 }
676 for (const auto& track : local_stream->GetVideoTracks()) {
deadbeefeb459812015-12-15 19:24:43 -0800677 OnVideoTrackAdded(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -0700678 }
679
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000680 stats_->AddStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000681 observer_->OnRenegotiationNeeded();
682 return true;
683}
684
685void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100686 TRACE_EVENT0("webrtc", "PeerConnection::RemoveStream");
deadbeefab9b2d12015-10-14 11:33:11 -0700687 for (const auto& track : local_stream->GetAudioTracks()) {
deadbeefeb459812015-12-15 19:24:43 -0800688 OnAudioTrackRemoved(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -0700689 }
690 for (const auto& track : local_stream->GetVideoTracks()) {
deadbeefeb459812015-12-15 19:24:43 -0800691 OnVideoTrackRemoved(track.get(), local_stream);
deadbeefab9b2d12015-10-14 11:33:11 -0700692 }
693
694 local_streams_->RemoveStream(local_stream);
deadbeefeb459812015-12-15 19:24:43 -0800695 stream_observers_.erase(
696 std::remove_if(
697 stream_observers_.begin(), stream_observers_.end(),
698 [local_stream](const rtc::scoped_ptr<MediaStreamObserver>& observer) {
699 return observer->stream()->label().compare(local_stream->label()) ==
700 0;
701 }),
702 stream_observers_.end());
deadbeefab9b2d12015-10-14 11:33:11 -0700703
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000704 if (IsClosed()) {
705 return;
706 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000707 observer_->OnRenegotiationNeeded();
708}
709
deadbeefe1f9d832016-01-14 15:35:42 -0800710rtc::scoped_refptr<RtpSenderInterface> PeerConnection::AddTrack(
711 MediaStreamTrackInterface* track,
712 std::vector<MediaStreamInterface*> streams) {
713 TRACE_EVENT0("webrtc", "PeerConnection::AddTrack");
714 if (IsClosed()) {
715 return nullptr;
716 }
717 if (streams.size() >= 2) {
718 LOG(LS_ERROR)
719 << "Adding a track with two streams is not currently supported.";
720 return nullptr;
721 }
722 // TODO(deadbeef): Support adding a track to two different senders.
723 if (FindSenderForTrack(track) != senders_.end()) {
724 LOG(LS_ERROR) << "Sender for track " << track->id() << " already exists.";
725 return nullptr;
726 }
727
728 // TODO(deadbeef): Support adding a track to multiple streams.
729 rtc::scoped_refptr<RtpSenderInterface> new_sender;
730 if (track->kind() == MediaStreamTrackInterface::kAudioKind) {
731 new_sender = RtpSenderProxy::Create(
732 signaling_thread(),
733 new AudioRtpSender(static_cast<AudioTrackInterface*>(track),
734 session_.get(), stats_.get()));
735 if (!streams.empty()) {
736 new_sender->set_stream_id(streams[0]->label());
737 }
738 const TrackInfo* track_info = FindTrackInfo(
739 local_audio_tracks_, new_sender->stream_id(), track->id());
740 if (track_info) {
741 new_sender->SetSsrc(track_info->ssrc);
742 }
743 } else if (track->kind() == MediaStreamTrackInterface::kVideoKind) {
744 new_sender = RtpSenderProxy::Create(
745 signaling_thread(),
746 new VideoRtpSender(static_cast<VideoTrackInterface*>(track),
747 session_.get()));
748 if (!streams.empty()) {
749 new_sender->set_stream_id(streams[0]->label());
750 }
751 const TrackInfo* track_info = FindTrackInfo(
752 local_video_tracks_, new_sender->stream_id(), track->id());
753 if (track_info) {
754 new_sender->SetSsrc(track_info->ssrc);
755 }
756 } else {
757 LOG(LS_ERROR) << "CreateSender called with invalid kind: " << track->kind();
758 return rtc::scoped_refptr<RtpSenderInterface>();
759 }
760
761 senders_.push_back(new_sender);
762 observer_->OnRenegotiationNeeded();
763 return new_sender;
764}
765
766bool PeerConnection::RemoveTrack(RtpSenderInterface* sender) {
767 TRACE_EVENT0("webrtc", "PeerConnection::RemoveTrack");
768 if (IsClosed()) {
769 return false;
770 }
771
772 auto it = std::find(senders_.begin(), senders_.end(), sender);
773 if (it == senders_.end()) {
774 LOG(LS_ERROR) << "Couldn't find sender " << sender->id() << " to remove.";
775 return false;
776 }
777 (*it)->Stop();
778 senders_.erase(it);
779
780 observer_->OnRenegotiationNeeded();
781 return true;
782}
783
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000784rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000785 AudioTrackInterface* track) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100786 TRACE_EVENT0("webrtc", "PeerConnection::CreateDtmfSender");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000787 if (!track) {
788 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
789 return NULL;
790 }
deadbeefab9b2d12015-10-14 11:33:11 -0700791 if (!local_streams_->FindAudioTrack(track->id())) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000792 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
793 return NULL;
794 }
795
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000796 rtc::scoped_refptr<DtmfSenderInterface> sender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000797 DtmfSender::Create(track, signaling_thread(), session_.get()));
798 if (!sender.get()) {
799 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
800 return NULL;
801 }
802 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
803}
804
deadbeeffac06552015-11-25 11:26:01 -0800805rtc::scoped_refptr<RtpSenderInterface> PeerConnection::CreateSender(
deadbeefbd7d8f72015-12-18 16:58:44 -0800806 const std::string& kind,
807 const std::string& stream_id) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100808 TRACE_EVENT0("webrtc", "PeerConnection::CreateSender");
deadbeefe1f9d832016-01-14 15:35:42 -0800809 rtc::scoped_refptr<RtpSenderInterface> new_sender;
deadbeeffac06552015-11-25 11:26:01 -0800810 if (kind == MediaStreamTrackInterface::kAudioKind) {
deadbeefe1f9d832016-01-14 15:35:42 -0800811 new_sender = RtpSenderProxy::Create(
812 signaling_thread(), new AudioRtpSender(session_.get(), stats_.get()));
deadbeeffac06552015-11-25 11:26:01 -0800813 } else if (kind == MediaStreamTrackInterface::kVideoKind) {
deadbeefe1f9d832016-01-14 15:35:42 -0800814 new_sender = RtpSenderProxy::Create(signaling_thread(),
815 new VideoRtpSender(session_.get()));
deadbeeffac06552015-11-25 11:26:01 -0800816 } else {
817 LOG(LS_ERROR) << "CreateSender called with invalid kind: " << kind;
deadbeefe1f9d832016-01-14 15:35:42 -0800818 return new_sender;
deadbeeffac06552015-11-25 11:26:01 -0800819 }
deadbeefbd7d8f72015-12-18 16:58:44 -0800820 if (!stream_id.empty()) {
821 new_sender->set_stream_id(stream_id);
822 }
deadbeeffac06552015-11-25 11:26:01 -0800823 senders_.push_back(new_sender);
deadbeefe1f9d832016-01-14 15:35:42 -0800824 return new_sender;
deadbeeffac06552015-11-25 11:26:01 -0800825}
826
deadbeef70ab1a12015-09-28 16:53:55 -0700827std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders()
828 const {
deadbeefe1f9d832016-01-14 15:35:42 -0800829 return senders_;
deadbeef70ab1a12015-09-28 16:53:55 -0700830}
831
832std::vector<rtc::scoped_refptr<RtpReceiverInterface>>
833PeerConnection::GetReceivers() const {
deadbeefe1f9d832016-01-14 15:35:42 -0800834 return receivers_;
deadbeef70ab1a12015-09-28 16:53:55 -0700835}
836
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000837bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000838 MediaStreamTrackInterface* track,
839 StatsOutputLevel level) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100840 TRACE_EVENT0("webrtc", "PeerConnection::GetStats");
deadbeef0a6c4ca2015-10-06 11:38:28 -0700841 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000842 if (!VERIFY(observer != NULL)) {
843 LOG(LS_ERROR) << "GetStats - observer is NULL.";
844 return false;
845 }
846
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000847 stats_->UpdateStats(level);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000848 signaling_thread()->Post(this, MSG_GETSTATS,
849 new GetStatsMsg(observer, track));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000850 return true;
851}
852
853PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
854 return signaling_state_;
855}
856
857PeerConnectionInterface::IceState PeerConnection::ice_state() {
858 return ice_state_;
859}
860
861PeerConnectionInterface::IceConnectionState
862PeerConnection::ice_connection_state() {
863 return ice_connection_state_;
864}
865
866PeerConnectionInterface::IceGatheringState
867PeerConnection::ice_gathering_state() {
868 return ice_gathering_state_;
869}
870
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000871rtc::scoped_refptr<DataChannelInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000872PeerConnection::CreateDataChannel(
873 const std::string& label,
874 const DataChannelInit* config) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100875 TRACE_EVENT0("webrtc", "PeerConnection::CreateDataChannel");
deadbeefab9b2d12015-10-14 11:33:11 -0700876 bool first_datachannel = !HasDataChannels();
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000877
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000878 rtc::scoped_ptr<InternalDataChannelInit> internal_config;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000879 if (config) {
880 internal_config.reset(new InternalDataChannelInit(*config));
881 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000882 rtc::scoped_refptr<DataChannelInterface> channel(
deadbeefab9b2d12015-10-14 11:33:11 -0700883 InternalCreateDataChannel(label, internal_config.get()));
884 if (!channel.get()) {
885 return nullptr;
886 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000887
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000888 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
889 // the first SCTP DataChannel.
890 if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
891 observer_->OnRenegotiationNeeded();
892 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000893
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000894 return DataChannelProxy::Create(signaling_thread(), channel.get());
895}
896
897void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
898 const MediaConstraintsInterface* constraints) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100899 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer");
deadbeefab9b2d12015-10-14 11:33:11 -0700900 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000901 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
902 return;
903 }
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000904 RTCOfferAnswerOptions options;
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000905
906 bool value;
907 size_t mandatory_constraints = 0;
908
909 if (FindConstraint(constraints,
910 MediaConstraintsInterface::kOfferToReceiveAudio,
911 &value,
912 &mandatory_constraints)) {
913 options.offer_to_receive_audio =
914 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
915 }
916
917 if (FindConstraint(constraints,
918 MediaConstraintsInterface::kOfferToReceiveVideo,
919 &value,
920 &mandatory_constraints)) {
921 options.offer_to_receive_video =
922 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
923 }
924
925 if (FindConstraint(constraints,
926 MediaConstraintsInterface::kVoiceActivityDetection,
927 &value,
928 &mandatory_constraints)) {
929 options.voice_activity_detection = value;
930 }
931
932 if (FindConstraint(constraints,
933 MediaConstraintsInterface::kIceRestart,
934 &value,
935 &mandatory_constraints)) {
936 options.ice_restart = value;
937 }
938
939 if (FindConstraint(constraints,
940 MediaConstraintsInterface::kUseRtpMux,
941 &value,
942 &mandatory_constraints)) {
943 options.use_rtp_mux = value;
944 }
945
946 CreateOffer(observer, options);
947}
948
949void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
950 const RTCOfferAnswerOptions& options) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100951 TRACE_EVENT0("webrtc", "PeerConnection::CreateOffer");
deadbeefab9b2d12015-10-14 11:33:11 -0700952 if (!VERIFY(observer != nullptr)) {
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000953 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
954 return;
955 }
deadbeefab9b2d12015-10-14 11:33:11 -0700956
957 cricket::MediaSessionOptions session_options;
958 if (!GetOptionsForOffer(options, &session_options)) {
959 std::string error = "CreateOffer called with invalid options.";
960 LOG(LS_ERROR) << error;
961 PostCreateSessionDescriptionFailure(observer, error);
962 return;
963 }
964
965 session_->CreateOffer(observer, options, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000966}
967
968void PeerConnection::CreateAnswer(
969 CreateSessionDescriptionObserver* observer,
970 const MediaConstraintsInterface* constraints) {
Peter Boström1a9d6152015-12-08 22:15:17 +0100971 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer");
deadbeefab9b2d12015-10-14 11:33:11 -0700972 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000973 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
974 return;
975 }
deadbeefab9b2d12015-10-14 11:33:11 -0700976
977 cricket::MediaSessionOptions session_options;
978 if (!GetOptionsForAnswer(constraints, &session_options)) {
979 std::string error = "CreateAnswer called with invalid constraints.";
980 LOG(LS_ERROR) << error;
981 PostCreateSessionDescriptionFailure(observer, error);
982 return;
983 }
984
htaa2a49d92016-03-04 02:51:39 -0800985 session_->CreateAnswer(observer, session_options);
986}
987
988void PeerConnection::CreateAnswer(CreateSessionDescriptionObserver* observer,
989 const RTCOfferAnswerOptions& options) {
990 TRACE_EVENT0("webrtc", "PeerConnection::CreateAnswer");
991 if (!VERIFY(observer != nullptr)) {
992 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
993 return;
994 }
995
996 cricket::MediaSessionOptions session_options;
997 if (!GetOptionsForAnswer(options, &session_options)) {
998 std::string error = "CreateAnswer called with invalid options.";
999 LOG(LS_ERROR) << error;
1000 PostCreateSessionDescriptionFailure(observer, error);
1001 return;
1002 }
1003
1004 session_->CreateAnswer(observer, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001005}
1006
1007void PeerConnection::SetLocalDescription(
1008 SetSessionDescriptionObserver* observer,
1009 SessionDescriptionInterface* desc) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001010 TRACE_EVENT0("webrtc", "PeerConnection::SetLocalDescription");
deadbeefab9b2d12015-10-14 11:33:11 -07001011 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001012 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
1013 return;
1014 }
1015 if (!desc) {
1016 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
1017 return;
1018 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001019 // Update stats here so that we have the most recent stats for tracks and
1020 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001021 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001022 std::string error;
1023 if (!session_->SetLocalDescription(desc, &error)) {
1024 PostSetSessionDescriptionFailure(observer, error);
1025 return;
1026 }
deadbeefab9b2d12015-10-14 11:33:11 -07001027
1028 // If setting the description decided our SSL role, allocate any necessary
1029 // SCTP sids.
1030 rtc::SSLRole role;
1031 if (session_->data_channel_type() == cricket::DCT_SCTP &&
Taylor Brandstetterf475d362016-01-08 15:35:57 -08001032 session_->GetSslRole(session_->data_channel(), &role)) {
deadbeefab9b2d12015-10-14 11:33:11 -07001033 AllocateSctpSids(role);
1034 }
1035
1036 // Update state and SSRC of local MediaStreams and DataChannels based on the
1037 // local session description.
1038 const cricket::ContentInfo* audio_content =
1039 GetFirstAudioContent(desc->description());
1040 if (audio_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001041 if (audio_content->rejected) {
1042 RemoveTracks(cricket::MEDIA_TYPE_AUDIO);
1043 } else {
1044 const cricket::AudioContentDescription* audio_desc =
1045 static_cast<const cricket::AudioContentDescription*>(
1046 audio_content->description);
1047 UpdateLocalTracks(audio_desc->streams(), audio_desc->type());
1048 }
deadbeefab9b2d12015-10-14 11:33:11 -07001049 }
1050
1051 const cricket::ContentInfo* video_content =
1052 GetFirstVideoContent(desc->description());
1053 if (video_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001054 if (video_content->rejected) {
1055 RemoveTracks(cricket::MEDIA_TYPE_VIDEO);
1056 } else {
1057 const cricket::VideoContentDescription* video_desc =
1058 static_cast<const cricket::VideoContentDescription*>(
1059 video_content->description);
1060 UpdateLocalTracks(video_desc->streams(), video_desc->type());
1061 }
deadbeefab9b2d12015-10-14 11:33:11 -07001062 }
1063
1064 const cricket::ContentInfo* data_content =
1065 GetFirstDataContent(desc->description());
1066 if (data_content) {
1067 const cricket::DataContentDescription* data_desc =
1068 static_cast<const cricket::DataContentDescription*>(
1069 data_content->description);
1070 if (rtc::starts_with(data_desc->protocol().data(),
1071 cricket::kMediaProtocolRtpPrefix)) {
1072 UpdateLocalRtpDataChannels(data_desc->streams());
1073 }
1074 }
1075
1076 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001077 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeefab9b2d12015-10-14 11:33:11 -07001078
deadbeefcbecd352015-09-23 11:50:27 -07001079 // MaybeStartGathering needs to be called after posting
1080 // MSG_SET_SESSIONDESCRIPTION_SUCCESS, so that we don't signal any candidates
1081 // before signaling that SetLocalDescription completed.
1082 session_->MaybeStartGathering();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001083}
1084
1085void PeerConnection::SetRemoteDescription(
1086 SetSessionDescriptionObserver* observer,
1087 SessionDescriptionInterface* desc) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001088 TRACE_EVENT0("webrtc", "PeerConnection::SetRemoteDescription");
deadbeefab9b2d12015-10-14 11:33:11 -07001089 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001090 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
1091 return;
1092 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001093 if (!desc) {
1094 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
1095 return;
1096 }
1097 // Update stats here so that we have the most recent stats for tracks and
1098 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001099 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001100 std::string error;
1101 if (!session_->SetRemoteDescription(desc, &error)) {
1102 PostSetSessionDescriptionFailure(observer, error);
1103 return;
1104 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001105
deadbeefab9b2d12015-10-14 11:33:11 -07001106 // If setting the description decided our SSL role, allocate any necessary
1107 // SCTP sids.
1108 rtc::SSLRole role;
1109 if (session_->data_channel_type() == cricket::DCT_SCTP &&
Taylor Brandstetterf475d362016-01-08 15:35:57 -08001110 session_->GetSslRole(session_->data_channel(), &role)) {
deadbeefab9b2d12015-10-14 11:33:11 -07001111 AllocateSctpSids(role);
1112 }
1113
1114 const cricket::SessionDescription* remote_desc = desc->description();
deadbeefbda7e0b2015-12-08 17:13:40 -08001115 const cricket::ContentInfo* audio_content = GetFirstAudioContent(remote_desc);
1116 const cricket::ContentInfo* video_content = GetFirstVideoContent(remote_desc);
1117 const cricket::AudioContentDescription* audio_desc =
1118 GetFirstAudioContentDescription(remote_desc);
1119 const cricket::VideoContentDescription* video_desc =
1120 GetFirstVideoContentDescription(remote_desc);
1121 const cricket::DataContentDescription* data_desc =
1122 GetFirstDataContentDescription(remote_desc);
1123
1124 // Check if the descriptions include streams, just in case the peer supports
1125 // MSID, but doesn't indicate so with "a=msid-semantic".
1126 if (remote_desc->msid_supported() ||
1127 (audio_desc && !audio_desc->streams().empty()) ||
1128 (video_desc && !video_desc->streams().empty())) {
1129 remote_peer_supports_msid_ = true;
1130 }
deadbeefab9b2d12015-10-14 11:33:11 -07001131
1132 // We wait to signal new streams until we finish processing the description,
1133 // since only at that point will new streams have all their tracks.
1134 rtc::scoped_refptr<StreamCollection> new_streams(StreamCollection::Create());
1135
1136 // Find all audio rtp streams and create corresponding remote AudioTracks
1137 // and MediaStreams.
deadbeefab9b2d12015-10-14 11:33:11 -07001138 if (audio_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001139 if (audio_content->rejected) {
1140 RemoveTracks(cricket::MEDIA_TYPE_AUDIO);
1141 } else {
deadbeefbda7e0b2015-12-08 17:13:40 -08001142 bool default_audio_track_needed =
1143 !remote_peer_supports_msid_ &&
1144 MediaContentDirectionHasSend(audio_desc->direction());
1145 UpdateRemoteStreamsList(GetActiveStreams(audio_desc),
1146 default_audio_track_needed, audio_desc->type(),
deadbeeffaac4972015-11-12 15:33:07 -08001147 new_streams);
deadbeeffaac4972015-11-12 15:33:07 -08001148 }
deadbeefab9b2d12015-10-14 11:33:11 -07001149 }
1150
1151 // Find all video rtp streams and create corresponding remote VideoTracks
1152 // and MediaStreams.
deadbeefab9b2d12015-10-14 11:33:11 -07001153 if (video_content) {
deadbeeffaac4972015-11-12 15:33:07 -08001154 if (video_content->rejected) {
1155 RemoveTracks(cricket::MEDIA_TYPE_VIDEO);
1156 } else {
deadbeefbda7e0b2015-12-08 17:13:40 -08001157 bool default_video_track_needed =
1158 !remote_peer_supports_msid_ &&
1159 MediaContentDirectionHasSend(video_desc->direction());
1160 UpdateRemoteStreamsList(GetActiveStreams(video_desc),
1161 default_video_track_needed, video_desc->type(),
deadbeeffaac4972015-11-12 15:33:07 -08001162 new_streams);
deadbeeffaac4972015-11-12 15:33:07 -08001163 }
deadbeefab9b2d12015-10-14 11:33:11 -07001164 }
1165
1166 // Update the DataChannels with the information from the remote peer.
deadbeefbda7e0b2015-12-08 17:13:40 -08001167 if (data_desc) {
1168 if (rtc::starts_with(data_desc->protocol().data(),
deadbeefab9b2d12015-10-14 11:33:11 -07001169 cricket::kMediaProtocolRtpPrefix)) {
deadbeefbda7e0b2015-12-08 17:13:40 -08001170 UpdateRemoteRtpDataChannels(GetActiveStreams(data_desc));
deadbeefab9b2d12015-10-14 11:33:11 -07001171 }
1172 }
1173
1174 // Iterate new_streams and notify the observer about new MediaStreams.
1175 for (size_t i = 0; i < new_streams->count(); ++i) {
1176 MediaStreamInterface* new_stream = new_streams->at(i);
1177 stats_->AddStream(new_stream);
1178 observer_->OnAddStream(new_stream);
1179 }
1180
deadbeefbda7e0b2015-12-08 17:13:40 -08001181 UpdateEndedRemoteMediaStreams();
deadbeefab9b2d12015-10-14 11:33:11 -07001182
1183 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1184 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeeffc648b62015-10-13 16:42:33 -07001185}
1186
deadbeefa67696b2015-09-29 11:56:26 -07001187bool PeerConnection::SetConfiguration(const RTCConfiguration& config) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001188 TRACE_EVENT0("webrtc", "PeerConnection::SetConfiguration");
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001189 if (port_allocator_) {
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -08001190 cricket::ServerAddresses stun_servers;
1191 std::vector<cricket::RelayServerConfig> turn_servers;
1192 if (!ParseIceServers(config.servers, &stun_servers, &turn_servers)) {
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001193 return false;
1194 }
Taylor Brandstetter0c7e9f52015-12-29 14:14:52 -08001195 port_allocator_->SetIceServers(stun_servers, turn_servers);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001196 }
honghaiz1f429e32015-09-28 07:57:34 -07001197 session_->SetIceConfig(session_->ParseIceConfig(config));
mallinath@webrtc.org3d81b1b2014-09-09 14:38:10 +00001198 return session_->SetIceTransports(config.type);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001199}
1200
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001201bool PeerConnection::AddIceCandidate(
1202 const IceCandidateInterface* ice_candidate) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001203 TRACE_EVENT0("webrtc", "PeerConnection::AddIceCandidate");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001204 return session_->ProcessIceMessage(ice_candidate);
1205}
1206
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001207bool PeerConnection::RemoveIceCandidates(
1208 const std::vector<cricket::Candidate>& candidates) {
1209 TRACE_EVENT0("webrtc", "PeerConnection::RemoveIceCandidates");
1210 return session_->RemoveRemoteIceCandidates(candidates);
1211}
1212
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001213void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
Peter Boström1a9d6152015-12-08 22:15:17 +01001214 TRACE_EVENT0("webrtc", "PeerConnection::RegisterUmaObserver");
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001215 uma_observer_ = observer;
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +00001216
1217 if (session_) {
1218 session_->set_metrics_observer(uma_observer_);
1219 }
1220
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001221 // Send information about IPv4/IPv6 status.
1222 if (uma_observer_ && port_allocator_) {
1223 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001224 uma_observer_->IncrementEnumCounter(
1225 kEnumCounterAddressFamily, kPeerConnection_IPv6,
1226 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgb445f262014-05-23 22:19:37 +00001227 } else {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001228 uma_observer_->IncrementEnumCounter(
1229 kEnumCounterAddressFamily, kPeerConnection_IPv4,
1230 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001231 }
1232 }
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001233}
1234
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001235const SessionDescriptionInterface* PeerConnection::local_description() const {
1236 return session_->local_description();
1237}
1238
1239const SessionDescriptionInterface* PeerConnection::remote_description() const {
1240 return session_->remote_description();
1241}
1242
1243void PeerConnection::Close() {
Peter Boström1a9d6152015-12-08 22:15:17 +01001244 TRACE_EVENT0("webrtc", "PeerConnection::Close");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001245 // Update stats here so that we have the most recent stats for tracks and
1246 // streams before the channels are closed.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001247 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001248
deadbeefd59daf82015-10-14 15:02:44 -07001249 session_->Close();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001250}
1251
deadbeefd59daf82015-10-14 15:02:44 -07001252void PeerConnection::OnSessionStateChange(WebRtcSession* /*session*/,
1253 WebRtcSession::State state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001254 switch (state) {
deadbeefd59daf82015-10-14 15:02:44 -07001255 case WebRtcSession::STATE_INIT:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001256 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001257 break;
deadbeefd59daf82015-10-14 15:02:44 -07001258 case WebRtcSession::STATE_SENTOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001259 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
1260 break;
deadbeefd59daf82015-10-14 15:02:44 -07001261 case WebRtcSession::STATE_SENTPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001262 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
1263 break;
deadbeefd59daf82015-10-14 15:02:44 -07001264 case WebRtcSession::STATE_RECEIVEDOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001265 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
1266 break;
deadbeefd59daf82015-10-14 15:02:44 -07001267 case WebRtcSession::STATE_RECEIVEDPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001268 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
1269 break;
deadbeefd59daf82015-10-14 15:02:44 -07001270 case WebRtcSession::STATE_INPROGRESS:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001271 ChangeSignalingState(PeerConnectionInterface::kStable);
1272 break;
deadbeefd59daf82015-10-14 15:02:44 -07001273 case WebRtcSession::STATE_CLOSED:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001274 ChangeSignalingState(PeerConnectionInterface::kClosed);
1275 break;
1276 default:
1277 break;
1278 }
1279}
1280
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001281void PeerConnection::OnMessage(rtc::Message* msg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001282 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001283 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
1284 SetSessionDescriptionMsg* param =
1285 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1286 param->observer->OnSuccess();
1287 delete param;
1288 break;
1289 }
1290 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
1291 SetSessionDescriptionMsg* param =
1292 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1293 param->observer->OnFailure(param->error);
1294 delete param;
1295 break;
1296 }
deadbeefab9b2d12015-10-14 11:33:11 -07001297 case MSG_CREATE_SESSIONDESCRIPTION_FAILED: {
1298 CreateSessionDescriptionMsg* param =
1299 static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
1300 param->observer->OnFailure(param->error);
1301 delete param;
1302 break;
1303 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001304 case MSG_GETSTATS: {
1305 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +00001306 StatsReports reports;
1307 stats_->GetStats(param->track, &reports);
1308 param->observer->OnComplete(reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001309 delete param;
1310 break;
1311 }
deadbeefbd292462015-12-14 18:15:29 -08001312 case MSG_FREE_DATACHANNELS: {
1313 sctp_data_channels_to_free_.clear();
1314 break;
1315 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001316 default:
deadbeef0a6c4ca2015-10-06 11:38:28 -07001317 RTC_DCHECK(false && "Not implemented");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001318 break;
1319 }
1320}
1321
deadbeefab9b2d12015-10-14 11:33:11 -07001322void PeerConnection::CreateAudioReceiver(MediaStreamInterface* stream,
1323 AudioTrackInterface* audio_track,
1324 uint32_t ssrc) {
deadbeefe1f9d832016-01-14 15:35:42 -08001325 receivers_.push_back(RtpReceiverProxy::Create(
1326 signaling_thread(),
1327 new AudioRtpReceiver(audio_track, ssrc, session_.get())));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001328}
1329
deadbeefab9b2d12015-10-14 11:33:11 -07001330void PeerConnection::CreateVideoReceiver(MediaStreamInterface* stream,
perkjf0dcfe22016-03-10 18:32:00 +01001331 const std::string& track_id,
deadbeefab9b2d12015-10-14 11:33:11 -07001332 uint32_t ssrc) {
perkjf0dcfe22016-03-10 18:32:00 +01001333 VideoRtpReceiver* video_receiver = new VideoRtpReceiver(
1334 stream, track_id, factory_->worker_thread(), ssrc, session_.get());
1335 receivers_.push_back(
1336 RtpReceiverProxy::Create(signaling_thread(), video_receiver));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001337}
1338
deadbeef70ab1a12015-09-28 16:53:55 -07001339// TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote
1340// description.
deadbeefab9b2d12015-10-14 11:33:11 -07001341void PeerConnection::DestroyAudioReceiver(MediaStreamInterface* stream,
1342 AudioTrackInterface* audio_track) {
deadbeef70ab1a12015-09-28 16:53:55 -07001343 auto it = FindReceiverForTrack(audio_track);
1344 if (it == receivers_.end()) {
1345 LOG(LS_WARNING) << "RtpReceiver for track with id " << audio_track->id()
1346 << " doesn't exist.";
1347 } else {
1348 (*it)->Stop();
1349 receivers_.erase(it);
1350 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001351}
1352
deadbeefab9b2d12015-10-14 11:33:11 -07001353void PeerConnection::DestroyVideoReceiver(MediaStreamInterface* stream,
1354 VideoTrackInterface* video_track) {
deadbeef70ab1a12015-09-28 16:53:55 -07001355 auto it = FindReceiverForTrack(video_track);
1356 if (it == receivers_.end()) {
1357 LOG(LS_WARNING) << "RtpReceiver for track with id " << video_track->id()
1358 << " doesn't exist.";
1359 } else {
1360 (*it)->Stop();
1361 receivers_.erase(it);
1362 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001363}
deadbeef70ab1a12015-09-28 16:53:55 -07001364
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001365void PeerConnection::OnIceConnectionChange(
1366 PeerConnectionInterface::IceConnectionState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001367 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefcbecd352015-09-23 11:50:27 -07001368 // After transitioning to "closed", ignore any additional states from
1369 // WebRtcSession (such as "disconnected").
deadbeefab9b2d12015-10-14 11:33:11 -07001370 if (IsClosed()) {
deadbeefcbecd352015-09-23 11:50:27 -07001371 return;
1372 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001373 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001374 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001375}
1376
1377void PeerConnection::OnIceGatheringChange(
1378 PeerConnectionInterface::IceGatheringState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001379 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001380 if (IsClosed()) {
1381 return;
1382 }
1383 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001384 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001385}
1386
1387void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001388 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001389 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001390}
1391
Honghai Zhang7fb69db2016-03-14 11:59:18 -07001392void PeerConnection::OnIceCandidatesRemoved(
1393 const std::vector<cricket::Candidate>& candidates) {
1394 RTC_DCHECK(signaling_thread()->IsCurrent());
1395 observer_->OnIceCandidatesRemoved(candidates);
1396}
1397
Peter Thatcher54360512015-07-08 11:08:35 -07001398void PeerConnection::OnIceConnectionReceivingChange(bool receiving) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001399 RTC_DCHECK(signaling_thread()->IsCurrent());
Peter Thatcher54360512015-07-08 11:08:35 -07001400 observer_->OnIceConnectionReceivingChange(receiving);
1401}
1402
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001403void PeerConnection::ChangeSignalingState(
1404 PeerConnectionInterface::SignalingState signaling_state) {
1405 signaling_state_ = signaling_state;
1406 if (signaling_state == kClosed) {
1407 ice_connection_state_ = kIceConnectionClosed;
1408 observer_->OnIceConnectionChange(ice_connection_state_);
1409 if (ice_gathering_state_ != kIceGatheringComplete) {
1410 ice_gathering_state_ = kIceGatheringComplete;
1411 observer_->OnIceGatheringChange(ice_gathering_state_);
1412 }
1413 }
1414 observer_->OnSignalingChange(signaling_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001415}
1416
deadbeefeb459812015-12-15 19:24:43 -08001417void PeerConnection::OnAudioTrackAdded(AudioTrackInterface* track,
1418 MediaStreamInterface* stream) {
1419 auto sender = FindSenderForTrack(track);
1420 if (sender != senders_.end()) {
1421 // We already have a sender for this track, so just change the stream_id
1422 // so that it's correct in the next call to CreateOffer.
1423 (*sender)->set_stream_id(stream->label());
1424 return;
1425 }
1426
1427 // Normal case; we've never seen this track before.
deadbeefe1f9d832016-01-14 15:35:42 -08001428 rtc::scoped_refptr<RtpSenderInterface> new_sender = RtpSenderProxy::Create(
1429 signaling_thread(),
1430 new AudioRtpSender(track, stream->label(), session_.get(), stats_.get()));
deadbeefeb459812015-12-15 19:24:43 -08001431 senders_.push_back(new_sender);
1432 // If the sender has already been configured in SDP, we call SetSsrc,
1433 // which will connect the sender to the underlying transport. This can
1434 // occur if a local session description that contains the ID of the sender
1435 // is set before AddStream is called. It can also occur if the local
1436 // session description is not changed and RemoveStream is called, and
1437 // later AddStream is called again with the same stream.
1438 const TrackInfo* track_info =
1439 FindTrackInfo(local_audio_tracks_, stream->label(), track->id());
1440 if (track_info) {
1441 new_sender->SetSsrc(track_info->ssrc);
1442 }
1443}
1444
1445// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around
1446// indefinitely, when we have unified plan SDP.
1447void PeerConnection::OnAudioTrackRemoved(AudioTrackInterface* track,
1448 MediaStreamInterface* stream) {
1449 auto sender = FindSenderForTrack(track);
1450 if (sender == senders_.end()) {
1451 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
1452 << " doesn't exist.";
1453 return;
1454 }
1455 (*sender)->Stop();
1456 senders_.erase(sender);
1457}
1458
1459void PeerConnection::OnVideoTrackAdded(VideoTrackInterface* track,
1460 MediaStreamInterface* stream) {
1461 auto sender = FindSenderForTrack(track);
1462 if (sender != senders_.end()) {
1463 // We already have a sender for this track, so just change the stream_id
1464 // so that it's correct in the next call to CreateOffer.
1465 (*sender)->set_stream_id(stream->label());
1466 return;
1467 }
1468
1469 // Normal case; we've never seen this track before.
deadbeefe1f9d832016-01-14 15:35:42 -08001470 rtc::scoped_refptr<RtpSenderInterface> new_sender = RtpSenderProxy::Create(
1471 signaling_thread(),
1472 new VideoRtpSender(track, stream->label(), session_.get()));
deadbeefeb459812015-12-15 19:24:43 -08001473 senders_.push_back(new_sender);
1474 const TrackInfo* track_info =
1475 FindTrackInfo(local_video_tracks_, stream->label(), track->id());
1476 if (track_info) {
1477 new_sender->SetSsrc(track_info->ssrc);
1478 }
1479}
1480
1481void PeerConnection::OnVideoTrackRemoved(VideoTrackInterface* track,
1482 MediaStreamInterface* stream) {
1483 auto sender = FindSenderForTrack(track);
1484 if (sender == senders_.end()) {
1485 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
1486 << " doesn't exist.";
1487 return;
1488 }
1489 (*sender)->Stop();
1490 senders_.erase(sender);
1491}
1492
deadbeefab9b2d12015-10-14 11:33:11 -07001493void PeerConnection::PostSetSessionDescriptionFailure(
1494 SetSessionDescriptionObserver* observer,
1495 const std::string& error) {
1496 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1497 msg->error = error;
1498 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
1499}
1500
1501void PeerConnection::PostCreateSessionDescriptionFailure(
1502 CreateSessionDescriptionObserver* observer,
1503 const std::string& error) {
1504 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
1505 msg->error = error;
1506 signaling_thread()->Post(this, MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
1507}
1508
1509bool PeerConnection::GetOptionsForOffer(
1510 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
1511 cricket::MediaSessionOptions* session_options) {
deadbeef0ed85b22016-02-23 17:24:52 -08001512 // TODO(deadbeef): Once we have transceivers, enumerate them here instead of
1513 // ContentInfos.
1514 if (session_->local_description()) {
1515 for (const cricket::ContentInfo& content :
1516 session_->local_description()->description()->contents()) {
1517 session_options->transport_options[content.name] =
1518 cricket::TransportOptions();
1519 }
1520 }
htaaac2dea2016-03-10 13:35:55 -08001521 if (!ExtractMediaSessionOptions(rtc_options, true, session_options)) {
deadbeefab9b2d12015-10-14 11:33:11 -07001522 return false;
1523 }
1524
deadbeeffac06552015-11-25 11:26:01 -08001525 AddSendStreams(session_options, senders_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001526 // Offer to receive audio/video if the constraint is not set and there are
1527 // send streams, or we're currently receiving.
1528 if (rtc_options.offer_to_receive_audio == RTCOfferAnswerOptions::kUndefined) {
1529 session_options->recv_audio =
1530 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_AUDIO) ||
1531 !remote_audio_tracks_.empty();
1532 }
1533 if (rtc_options.offer_to_receive_video == RTCOfferAnswerOptions::kUndefined) {
1534 session_options->recv_video =
1535 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_VIDEO) ||
1536 !remote_video_tracks_.empty();
1537 }
1538 session_options->bundle_enabled =
1539 session_options->bundle_enabled &&
1540 (session_options->has_audio() || session_options->has_video() ||
1541 session_options->has_data());
1542
deadbeefab9b2d12015-10-14 11:33:11 -07001543 if (session_->data_channel_type() == cricket::DCT_SCTP && HasDataChannels()) {
1544 session_options->data_channel_type = cricket::DCT_SCTP;
1545 }
1546 return true;
1547}
1548
htaa2a49d92016-03-04 02:51:39 -08001549void PeerConnection::FinishOptionsForAnswer(
deadbeefab9b2d12015-10-14 11:33:11 -07001550 cricket::MediaSessionOptions* session_options) {
deadbeef0ed85b22016-02-23 17:24:52 -08001551 // TODO(deadbeef): Once we have transceivers, enumerate them here instead of
1552 // ContentInfos.
1553 if (session_->remote_description()) {
1554 // Initialize the transport_options map.
1555 for (const cricket::ContentInfo& content :
1556 session_->remote_description()->description()->contents()) {
1557 session_options->transport_options[content.name] =
1558 cricket::TransportOptions();
1559 }
1560 }
deadbeeffac06552015-11-25 11:26:01 -08001561 AddSendStreams(session_options, senders_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001562 session_options->bundle_enabled =
1563 session_options->bundle_enabled &&
1564 (session_options->has_audio() || session_options->has_video() ||
1565 session_options->has_data());
1566
deadbeefab9b2d12015-10-14 11:33:11 -07001567 // RTP data channel is handled in MediaSessionOptions::AddStream. SCTP streams
1568 // are not signaled in the SDP so does not go through that path and must be
1569 // handled here.
1570 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1571 session_options->data_channel_type = cricket::DCT_SCTP;
1572 }
htaa2a49d92016-03-04 02:51:39 -08001573}
1574
1575bool PeerConnection::GetOptionsForAnswer(
1576 const MediaConstraintsInterface* constraints,
1577 cricket::MediaSessionOptions* session_options) {
1578 session_options->recv_audio = false;
1579 session_options->recv_video = false;
1580 if (!ParseConstraintsForAnswer(constraints, session_options)) {
1581 return false;
1582 }
1583 FinishOptionsForAnswer(session_options);
1584 return true;
1585}
1586
1587bool PeerConnection::GetOptionsForAnswer(
1588 const RTCOfferAnswerOptions& options,
1589 cricket::MediaSessionOptions* session_options) {
1590 session_options->recv_audio = false;
1591 session_options->recv_video = false;
htaaac2dea2016-03-10 13:35:55 -08001592 if (!ExtractMediaSessionOptions(options, false, session_options)) {
htaa2a49d92016-03-04 02:51:39 -08001593 return false;
1594 }
1595 FinishOptionsForAnswer(session_options);
deadbeefab9b2d12015-10-14 11:33:11 -07001596 return true;
1597}
1598
deadbeeffaac4972015-11-12 15:33:07 -08001599void PeerConnection::RemoveTracks(cricket::MediaType media_type) {
1600 UpdateLocalTracks(std::vector<cricket::StreamParams>(), media_type);
deadbeefbda7e0b2015-12-08 17:13:40 -08001601 UpdateRemoteStreamsList(std::vector<cricket::StreamParams>(), false,
1602 media_type, nullptr);
deadbeeffaac4972015-11-12 15:33:07 -08001603}
1604
deadbeefab9b2d12015-10-14 11:33:11 -07001605void PeerConnection::UpdateRemoteStreamsList(
1606 const cricket::StreamParamsVec& streams,
deadbeefbda7e0b2015-12-08 17:13:40 -08001607 bool default_track_needed,
deadbeefab9b2d12015-10-14 11:33:11 -07001608 cricket::MediaType media_type,
1609 StreamCollection* new_streams) {
1610 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1611
1612 // Find removed tracks. I.e., tracks where the track id or ssrc don't match
deadbeeffac06552015-11-25 11:26:01 -08001613 // the new StreamParam.
deadbeefab9b2d12015-10-14 11:33:11 -07001614 auto track_it = current_tracks->begin();
1615 while (track_it != current_tracks->end()) {
1616 const TrackInfo& info = *track_it;
1617 const cricket::StreamParams* params =
1618 cricket::GetStreamBySsrc(streams, info.ssrc);
deadbeefbda7e0b2015-12-08 17:13:40 -08001619 bool track_exists = params && params->id == info.track_id;
1620 // If this is a default track, and we still need it, don't remove it.
1621 if ((info.stream_label == kDefaultStreamLabel && default_track_needed) ||
1622 track_exists) {
1623 ++track_it;
1624 } else {
deadbeefab9b2d12015-10-14 11:33:11 -07001625 OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
1626 track_it = current_tracks->erase(track_it);
deadbeefab9b2d12015-10-14 11:33:11 -07001627 }
1628 }
1629
1630 // Find new and active tracks.
1631 for (const cricket::StreamParams& params : streams) {
1632 // The sync_label is the MediaStream label and the |stream.id| is the
1633 // track id.
1634 const std::string& stream_label = params.sync_label;
1635 const std::string& track_id = params.id;
1636 uint32_t ssrc = params.first_ssrc();
1637
1638 rtc::scoped_refptr<MediaStreamInterface> stream =
1639 remote_streams_->find(stream_label);
1640 if (!stream) {
1641 // This is a new MediaStream. Create a new remote MediaStream.
1642 stream = remote_stream_factory_->CreateMediaStream(stream_label);
1643 remote_streams_->AddStream(stream);
1644 new_streams->AddStream(stream);
1645 }
1646
1647 const TrackInfo* track_info =
1648 FindTrackInfo(*current_tracks, stream_label, track_id);
1649 if (!track_info) {
1650 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1651 OnRemoteTrackSeen(stream_label, track_id, ssrc, media_type);
1652 }
1653 }
deadbeefbda7e0b2015-12-08 17:13:40 -08001654
1655 // Add default track if necessary.
1656 if (default_track_needed) {
1657 rtc::scoped_refptr<MediaStreamInterface> default_stream =
1658 remote_streams_->find(kDefaultStreamLabel);
1659 if (!default_stream) {
1660 // Create the new default MediaStream.
1661 default_stream =
1662 remote_stream_factory_->CreateMediaStream(kDefaultStreamLabel);
1663 remote_streams_->AddStream(default_stream);
1664 new_streams->AddStream(default_stream);
1665 }
1666 std::string default_track_id = (media_type == cricket::MEDIA_TYPE_AUDIO)
1667 ? kDefaultAudioTrackLabel
1668 : kDefaultVideoTrackLabel;
1669 const TrackInfo* default_track_info =
1670 FindTrackInfo(*current_tracks, kDefaultStreamLabel, default_track_id);
1671 if (!default_track_info) {
1672 current_tracks->push_back(
1673 TrackInfo(kDefaultStreamLabel, default_track_id, 0));
1674 OnRemoteTrackSeen(kDefaultStreamLabel, default_track_id, 0, media_type);
1675 }
1676 }
deadbeefab9b2d12015-10-14 11:33:11 -07001677}
1678
1679void PeerConnection::OnRemoteTrackSeen(const std::string& stream_label,
1680 const std::string& track_id,
1681 uint32_t ssrc,
1682 cricket::MediaType media_type) {
1683 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1684
1685 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
Tommif888bb52015-12-12 01:37:01 +01001686 AudioTrackInterface* audio_track = remote_stream_factory_->AddAudioTrack(
1687 ssrc, session_.get(), stream, track_id);
deadbeefab9b2d12015-10-14 11:33:11 -07001688 CreateAudioReceiver(stream, audio_track, ssrc);
1689 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
perkjf0dcfe22016-03-10 18:32:00 +01001690 CreateVideoReceiver(stream, track_id, ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -07001691 } else {
1692 RTC_DCHECK(false && "Invalid media type");
1693 }
1694}
1695
1696void PeerConnection::OnRemoteTrackRemoved(const std::string& stream_label,
1697 const std::string& track_id,
1698 cricket::MediaType media_type) {
1699 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1700
1701 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1702 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1703 stream->FindAudioTrack(track_id);
1704 if (audio_track) {
1705 audio_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1706 stream->RemoveTrack(audio_track);
1707 DestroyAudioReceiver(stream, audio_track);
1708 }
1709 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1710 rtc::scoped_refptr<VideoTrackInterface> video_track =
1711 stream->FindVideoTrack(track_id);
1712 if (video_track) {
deadbeefab9b2d12015-10-14 11:33:11 -07001713 stream->RemoveTrack(video_track);
perkjf0dcfe22016-03-10 18:32:00 +01001714 // Stopping or destroying a VideoRtpReceiver will end the
1715 // VideoRtpReceiver::track().
deadbeefab9b2d12015-10-14 11:33:11 -07001716 DestroyVideoReceiver(stream, video_track);
1717 }
1718 } else {
1719 ASSERT(false && "Invalid media type");
1720 }
1721}
1722
1723void PeerConnection::UpdateEndedRemoteMediaStreams() {
1724 std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams_to_remove;
1725 for (size_t i = 0; i < remote_streams_->count(); ++i) {
1726 MediaStreamInterface* stream = remote_streams_->at(i);
1727 if (stream->GetAudioTracks().empty() && stream->GetVideoTracks().empty()) {
1728 streams_to_remove.push_back(stream);
1729 }
1730 }
1731
1732 for (const auto& stream : streams_to_remove) {
1733 remote_streams_->RemoveStream(stream);
1734 observer_->OnRemoveStream(stream);
1735 }
1736}
1737
deadbeefab9b2d12015-10-14 11:33:11 -07001738void PeerConnection::EndRemoteTracks(cricket::MediaType media_type) {
1739 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1740 for (TrackInfos::iterator track_it = current_tracks->begin();
1741 track_it != current_tracks->end(); ++track_it) {
1742 const TrackInfo& info = *track_it;
1743 MediaStreamInterface* stream = remote_streams_->find(info.stream_label);
1744 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1745 AudioTrackInterface* track = stream->FindAudioTrack(info.track_id);
1746 // There's no guarantee the track is still available, e.g. the track may
1747 // have been removed from the stream by javascript.
1748 if (track) {
1749 track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1750 }
1751 }
1752 if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1753 VideoTrackInterface* track = stream->FindVideoTrack(info.track_id);
1754 // There's no guarantee the track is still available, e.g. the track may
1755 // have been removed from the stream by javascript.
1756 if (track) {
1757 track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1758 }
1759 }
1760 }
1761}
1762
1763void PeerConnection::UpdateLocalTracks(
1764 const std::vector<cricket::StreamParams>& streams,
1765 cricket::MediaType media_type) {
1766 TrackInfos* current_tracks = GetLocalTracks(media_type);
1767
1768 // Find removed tracks. I.e., tracks where the track id, stream label or ssrc
1769 // don't match the new StreamParam.
1770 TrackInfos::iterator track_it = current_tracks->begin();
1771 while (track_it != current_tracks->end()) {
1772 const TrackInfo& info = *track_it;
1773 const cricket::StreamParams* params =
1774 cricket::GetStreamBySsrc(streams, info.ssrc);
1775 if (!params || params->id != info.track_id ||
1776 params->sync_label != info.stream_label) {
1777 OnLocalTrackRemoved(info.stream_label, info.track_id, info.ssrc,
1778 media_type);
1779 track_it = current_tracks->erase(track_it);
1780 } else {
1781 ++track_it;
1782 }
1783 }
1784
1785 // Find new and active tracks.
1786 for (const cricket::StreamParams& params : streams) {
1787 // The sync_label is the MediaStream label and the |stream.id| is the
1788 // track id.
1789 const std::string& stream_label = params.sync_label;
1790 const std::string& track_id = params.id;
1791 uint32_t ssrc = params.first_ssrc();
1792 const TrackInfo* track_info =
1793 FindTrackInfo(*current_tracks, stream_label, track_id);
1794 if (!track_info) {
1795 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1796 OnLocalTrackSeen(stream_label, track_id, params.first_ssrc(), media_type);
1797 }
1798 }
1799}
1800
1801void PeerConnection::OnLocalTrackSeen(const std::string& stream_label,
1802 const std::string& track_id,
1803 uint32_t ssrc,
1804 cricket::MediaType media_type) {
deadbeeffac06552015-11-25 11:26:01 -08001805 RtpSenderInterface* sender = FindSenderById(track_id);
1806 if (!sender) {
1807 LOG(LS_WARNING) << "An unknown RtpSender with id " << track_id
1808 << " has been configured in the local description.";
deadbeefab9b2d12015-10-14 11:33:11 -07001809 return;
1810 }
1811
deadbeeffac06552015-11-25 11:26:01 -08001812 if (sender->media_type() != media_type) {
1813 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
1814 << " description with an unexpected media type.";
1815 return;
deadbeefab9b2d12015-10-14 11:33:11 -07001816 }
deadbeeffac06552015-11-25 11:26:01 -08001817
1818 sender->set_stream_id(stream_label);
1819 sender->SetSsrc(ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -07001820}
1821
1822void PeerConnection::OnLocalTrackRemoved(const std::string& stream_label,
1823 const std::string& track_id,
1824 uint32_t ssrc,
1825 cricket::MediaType media_type) {
deadbeeffac06552015-11-25 11:26:01 -08001826 RtpSenderInterface* sender = FindSenderById(track_id);
1827 if (!sender) {
1828 // This is the normal case. I.e., RemoveStream has been called and the
deadbeefab9b2d12015-10-14 11:33:11 -07001829 // SessionDescriptions has been renegotiated.
1830 return;
1831 }
deadbeeffac06552015-11-25 11:26:01 -08001832
1833 // A sender has been removed from the SessionDescription but it's still
1834 // associated with the PeerConnection. This only occurs if the SDP doesn't
1835 // match with the calls to CreateSender, AddStream and RemoveStream.
1836 if (sender->media_type() != media_type) {
1837 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
1838 << " description with an unexpected media type.";
1839 return;
deadbeefab9b2d12015-10-14 11:33:11 -07001840 }
deadbeeffac06552015-11-25 11:26:01 -08001841
1842 sender->SetSsrc(0);
deadbeefab9b2d12015-10-14 11:33:11 -07001843}
1844
1845void PeerConnection::UpdateLocalRtpDataChannels(
1846 const cricket::StreamParamsVec& streams) {
1847 std::vector<std::string> existing_channels;
1848
1849 // Find new and active data channels.
1850 for (const cricket::StreamParams& params : streams) {
1851 // |it->sync_label| is actually the data channel label. The reason is that
1852 // we use the same naming of data channels as we do for
1853 // MediaStreams and Tracks.
1854 // For MediaStreams, the sync_label is the MediaStream label and the
1855 // track label is the same as |streamid|.
1856 const std::string& channel_label = params.sync_label;
1857 auto data_channel_it = rtp_data_channels_.find(channel_label);
1858 if (!VERIFY(data_channel_it != rtp_data_channels_.end())) {
1859 continue;
1860 }
1861 // Set the SSRC the data channel should use for sending.
1862 data_channel_it->second->SetSendSsrc(params.first_ssrc());
1863 existing_channels.push_back(data_channel_it->first);
1864 }
1865
1866 UpdateClosingRtpDataChannels(existing_channels, true);
1867}
1868
1869void PeerConnection::UpdateRemoteRtpDataChannels(
1870 const cricket::StreamParamsVec& streams) {
1871 std::vector<std::string> existing_channels;
1872
1873 // Find new and active data channels.
1874 for (const cricket::StreamParams& params : streams) {
1875 // The data channel label is either the mslabel or the SSRC if the mslabel
1876 // does not exist. Ex a=ssrc:444330170 mslabel:test1.
1877 std::string label = params.sync_label.empty()
1878 ? rtc::ToString(params.first_ssrc())
1879 : params.sync_label;
1880 auto data_channel_it = rtp_data_channels_.find(label);
1881 if (data_channel_it == rtp_data_channels_.end()) {
1882 // This is a new data channel.
1883 CreateRemoteRtpDataChannel(label, params.first_ssrc());
1884 } else {
1885 data_channel_it->second->SetReceiveSsrc(params.first_ssrc());
1886 }
1887 existing_channels.push_back(label);
1888 }
1889
1890 UpdateClosingRtpDataChannels(existing_channels, false);
1891}
1892
1893void PeerConnection::UpdateClosingRtpDataChannels(
1894 const std::vector<std::string>& active_channels,
1895 bool is_local_update) {
1896 auto it = rtp_data_channels_.begin();
1897 while (it != rtp_data_channels_.end()) {
1898 DataChannel* data_channel = it->second;
1899 if (std::find(active_channels.begin(), active_channels.end(),
1900 data_channel->label()) != active_channels.end()) {
1901 ++it;
1902 continue;
1903 }
1904
1905 if (is_local_update) {
1906 data_channel->SetSendSsrc(0);
1907 } else {
1908 data_channel->RemotePeerRequestClose();
1909 }
1910
1911 if (data_channel->state() == DataChannel::kClosed) {
1912 rtp_data_channels_.erase(it);
1913 it = rtp_data_channels_.begin();
1914 } else {
1915 ++it;
1916 }
1917 }
1918}
1919
1920void PeerConnection::CreateRemoteRtpDataChannel(const std::string& label,
1921 uint32_t remote_ssrc) {
1922 rtc::scoped_refptr<DataChannel> channel(
1923 InternalCreateDataChannel(label, nullptr));
1924 if (!channel.get()) {
1925 LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
1926 << "CreateDataChannel failed.";
1927 return;
1928 }
1929 channel->SetReceiveSsrc(remote_ssrc);
1930 observer_->OnDataChannel(
1931 DataChannelProxy::Create(signaling_thread(), channel));
1932}
1933
1934rtc::scoped_refptr<DataChannel> PeerConnection::InternalCreateDataChannel(
1935 const std::string& label,
1936 const InternalDataChannelInit* config) {
1937 if (IsClosed()) {
1938 return nullptr;
1939 }
1940 if (session_->data_channel_type() == cricket::DCT_NONE) {
1941 LOG(LS_ERROR)
1942 << "InternalCreateDataChannel: Data is not supported in this call.";
1943 return nullptr;
1944 }
1945 InternalDataChannelInit new_config =
1946 config ? (*config) : InternalDataChannelInit();
1947 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1948 if (new_config.id < 0) {
1949 rtc::SSLRole role;
Taylor Brandstetterf475d362016-01-08 15:35:57 -08001950 if ((session_->GetSslRole(session_->data_channel(), &role)) &&
deadbeefab9b2d12015-10-14 11:33:11 -07001951 !sid_allocator_.AllocateSid(role, &new_config.id)) {
1952 LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel.";
1953 return nullptr;
1954 }
1955 } else if (!sid_allocator_.ReserveSid(new_config.id)) {
1956 LOG(LS_ERROR) << "Failed to create a SCTP data channel "
1957 << "because the id is already in use or out of range.";
1958 return nullptr;
1959 }
1960 }
1961
1962 rtc::scoped_refptr<DataChannel> channel(DataChannel::Create(
1963 session_.get(), session_->data_channel_type(), label, new_config));
1964 if (!channel) {
1965 sid_allocator_.ReleaseSid(new_config.id);
1966 return nullptr;
1967 }
1968
1969 if (channel->data_channel_type() == cricket::DCT_RTP) {
1970 if (rtp_data_channels_.find(channel->label()) != rtp_data_channels_.end()) {
1971 LOG(LS_ERROR) << "DataChannel with label " << channel->label()
1972 << " already exists.";
1973 return nullptr;
1974 }
1975 rtp_data_channels_[channel->label()] = channel;
1976 } else {
1977 RTC_DCHECK(channel->data_channel_type() == cricket::DCT_SCTP);
1978 sctp_data_channels_.push_back(channel);
1979 channel->SignalClosed.connect(this,
1980 &PeerConnection::OnSctpDataChannelClosed);
1981 }
1982
1983 return channel;
1984}
1985
1986bool PeerConnection::HasDataChannels() const {
1987 return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
1988}
1989
1990void PeerConnection::AllocateSctpSids(rtc::SSLRole role) {
1991 for (const auto& channel : sctp_data_channels_) {
1992 if (channel->id() < 0) {
1993 int sid;
1994 if (!sid_allocator_.AllocateSid(role, &sid)) {
1995 LOG(LS_ERROR) << "Failed to allocate SCTP sid.";
1996 continue;
1997 }
1998 channel->SetSctpSid(sid);
1999 }
2000 }
2001}
2002
2003void PeerConnection::OnSctpDataChannelClosed(DataChannel* channel) {
deadbeefbd292462015-12-14 18:15:29 -08002004 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefab9b2d12015-10-14 11:33:11 -07002005 for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end();
2006 ++it) {
2007 if (it->get() == channel) {
2008 if (channel->id() >= 0) {
2009 sid_allocator_.ReleaseSid(channel->id());
2010 }
deadbeefbd292462015-12-14 18:15:29 -08002011 // Since this method is triggered by a signal from the DataChannel,
2012 // we can't free it directly here; we need to free it asynchronously.
2013 sctp_data_channels_to_free_.push_back(*it);
deadbeefab9b2d12015-10-14 11:33:11 -07002014 sctp_data_channels_.erase(it);
deadbeefbd292462015-12-14 18:15:29 -08002015 signaling_thread()->Post(this, MSG_FREE_DATACHANNELS, nullptr);
deadbeefab9b2d12015-10-14 11:33:11 -07002016 return;
2017 }
2018 }
2019}
2020
2021void PeerConnection::OnVoiceChannelDestroyed() {
2022 EndRemoteTracks(cricket::MEDIA_TYPE_AUDIO);
2023}
2024
2025void PeerConnection::OnVideoChannelDestroyed() {
2026 EndRemoteTracks(cricket::MEDIA_TYPE_VIDEO);
2027}
2028
2029void PeerConnection::OnDataChannelCreated() {
2030 for (const auto& channel : sctp_data_channels_) {
2031 channel->OnTransportChannelCreated();
2032 }
2033}
2034
2035void PeerConnection::OnDataChannelDestroyed() {
2036 // Use a temporary copy of the RTP/SCTP DataChannel list because the
2037 // DataChannel may callback to us and try to modify the list.
2038 std::map<std::string, rtc::scoped_refptr<DataChannel>> temp_rtp_dcs;
2039 temp_rtp_dcs.swap(rtp_data_channels_);
2040 for (const auto& kv : temp_rtp_dcs) {
2041 kv.second->OnTransportChannelDestroyed();
2042 }
2043
2044 std::vector<rtc::scoped_refptr<DataChannel>> temp_sctp_dcs;
2045 temp_sctp_dcs.swap(sctp_data_channels_);
2046 for (const auto& channel : temp_sctp_dcs) {
2047 channel->OnTransportChannelDestroyed();
2048 }
2049}
2050
2051void PeerConnection::OnDataChannelOpenMessage(
2052 const std::string& label,
2053 const InternalDataChannelInit& config) {
2054 rtc::scoped_refptr<DataChannel> channel(
2055 InternalCreateDataChannel(label, &config));
2056 if (!channel.get()) {
2057 LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
2058 return;
2059 }
2060
2061 observer_->OnDataChannel(
2062 DataChannelProxy::Create(signaling_thread(), channel));
2063}
2064
deadbeeffac06552015-11-25 11:26:01 -08002065RtpSenderInterface* PeerConnection::FindSenderById(const std::string& id) {
2066 auto it =
2067 std::find_if(senders_.begin(), senders_.end(),
2068 [id](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
2069 return sender->id() == id;
2070 });
2071 return it != senders_.end() ? it->get() : nullptr;
2072}
2073
deadbeef70ab1a12015-09-28 16:53:55 -07002074std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator
2075PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) {
2076 return std::find_if(
2077 senders_.begin(), senders_.end(),
2078 [track](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
2079 return sender->track() == track;
2080 });
2081}
2082
2083std::vector<rtc::scoped_refptr<RtpReceiverInterface>>::iterator
2084PeerConnection::FindReceiverForTrack(MediaStreamTrackInterface* track) {
2085 return std::find_if(
2086 receivers_.begin(), receivers_.end(),
2087 [track](const rtc::scoped_refptr<RtpReceiverInterface>& receiver) {
2088 return receiver->track() == track;
2089 });
2090}
2091
deadbeefab9b2d12015-10-14 11:33:11 -07002092PeerConnection::TrackInfos* PeerConnection::GetRemoteTracks(
2093 cricket::MediaType media_type) {
2094 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
2095 media_type == cricket::MEDIA_TYPE_VIDEO);
2096 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &remote_audio_tracks_
2097 : &remote_video_tracks_;
2098}
2099
2100PeerConnection::TrackInfos* PeerConnection::GetLocalTracks(
2101 cricket::MediaType media_type) {
2102 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
2103 media_type == cricket::MEDIA_TYPE_VIDEO);
2104 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &local_audio_tracks_
2105 : &local_video_tracks_;
2106}
2107
2108const PeerConnection::TrackInfo* PeerConnection::FindTrackInfo(
2109 const PeerConnection::TrackInfos& infos,
2110 const std::string& stream_label,
2111 const std::string track_id) const {
2112 for (const TrackInfo& track_info : infos) {
2113 if (track_info.stream_label == stream_label &&
2114 track_info.track_id == track_id) {
2115 return &track_info;
2116 }
2117 }
2118 return nullptr;
2119}
2120
2121DataChannel* PeerConnection::FindDataChannelBySid(int sid) const {
2122 for (const auto& channel : sctp_data_channels_) {
2123 if (channel->id() == sid) {
2124 return channel;
2125 }
2126 }
2127 return nullptr;
2128}
2129
henrike@webrtc.org28e20752013-07-10 00:45:36 +00002130} // namespace webrtc