blob: bc7cb361550943a6d8c4393c72e758825d77cc05 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
jlmiller@webrtc.org5f93d0a2015-01-20 21:36:13 +00003 * Copyright 2012 Google Inc.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00004 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "talk/app/webrtc/peerconnection.h"
29
30#include <vector>
deadbeef0a6c4ca2015-10-06 11:38:28 -070031#include <cctype> // for isdigit
henrike@webrtc.org28e20752013-07-10 00:45:36 +000032
deadbeefab9b2d12015-10-14 11:33:11 -070033#include "talk/app/webrtc/audiotrack.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000034#include "talk/app/webrtc/dtmfsender.h"
35#include "talk/app/webrtc/jsepicecandidate.h"
36#include "talk/app/webrtc/jsepsessiondescription.h"
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +000037#include "talk/app/webrtc/mediaconstraintsinterface.h"
deadbeefab9b2d12015-10-14 11:33:11 -070038#include "talk/app/webrtc/mediastream.h"
39#include "talk/app/webrtc/mediastreamproxy.h"
40#include "talk/app/webrtc/mediastreamtrackproxy.h"
41#include "talk/app/webrtc/remoteaudiosource.h"
42#include "talk/app/webrtc/remotevideocapturer.h"
deadbeef70ab1a12015-09-28 16:53:55 -070043#include "talk/app/webrtc/rtpreceiver.h"
44#include "talk/app/webrtc/rtpsender.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000045#include "talk/app/webrtc/streamcollection.h"
deadbeefab9b2d12015-10-14 11:33:11 -070046#include "talk/app/webrtc/videosource.h"
47#include "talk/app/webrtc/videotrack.h"
48#include "talk/media/sctp/sctpdataengine.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000049#include "talk/session/media/channelmanager.h"
tfarina5237aaf2015-11-10 23:44:30 -080050#include "webrtc/base/arraysize.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000051#include "webrtc/base/logging.h"
52#include "webrtc/base/stringencode.h"
deadbeefab9b2d12015-10-14 11:33:11 -070053#include "webrtc/base/stringutils.h"
tfarina5237aaf2015-11-10 23:44:30 -080054#include "webrtc/p2p/client/basicportallocator.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010055#include "webrtc/system_wrappers/include/field_trial.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056
57namespace {
58
deadbeefab9b2d12015-10-14 11:33:11 -070059using webrtc::DataChannel;
60using webrtc::MediaConstraintsInterface;
61using webrtc::MediaStreamInterface;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000062using webrtc::PeerConnectionInterface;
deadbeefab9b2d12015-10-14 11:33:11 -070063using webrtc::StreamCollection;
deadbeef0a6c4ca2015-10-06 11:38:28 -070064using webrtc::StunConfigurations;
65using webrtc::TurnConfigurations;
66typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
67 StunConfiguration;
68typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
69 TurnConfiguration;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000070
deadbeefab9b2d12015-10-14 11:33:11 -070071static const char kDefaultStreamLabel[] = "default";
72static const char kDefaultAudioTrackLabel[] = "defaulta0";
73static const char kDefaultVideoTrackLabel[] = "defaultv0";
74
henrike@webrtc.org28e20752013-07-10 00:45:36 +000075// The min number of tokens must present in Turn host uri.
76// e.g. user@turn.example.org
77static const size_t kTurnHostTokensNum = 2;
78// Number of tokens must be preset when TURN uri has transport param.
79static const size_t kTurnTransportTokensNum = 2;
80// The default stun port.
wu@webrtc.org91053e72013-08-10 07:18:04 +000081static const int kDefaultStunPort = 3478;
82static const int kDefaultStunTlsPort = 5349;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000083static const char kTransport[] = "transport";
wu@webrtc.org91053e72013-08-10 07:18:04 +000084static const char kUdpTransportType[] = "udp";
85static const char kTcpTransportType[] = "tcp";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000086
87// NOTE: Must be in the same order as the ServiceType enum.
deadbeef0a6c4ca2015-10-06 11:38:28 -070088static const char* kValidIceServiceTypes[] = {"stun", "stuns", "turn", "turns"};
henrike@webrtc.org28e20752013-07-10 00:45:36 +000089
deadbeef0a6c4ca2015-10-06 11:38:28 -070090// NOTE: A loop below assumes that the first value of this enum is 0 and all
91// other values are incremental.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000092enum ServiceType {
deadbeef0a6c4ca2015-10-06 11:38:28 -070093 STUN = 0, // Indicates a STUN server.
94 STUNS, // Indicates a STUN server used with a TLS session.
95 TURN, // Indicates a TURN server
96 TURNS, // Indicates a TURN server used with a TLS session.
97 INVALID, // Unknown.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000098};
tfarina5237aaf2015-11-10 23:44:30 -080099static_assert(INVALID == arraysize(kValidIceServiceTypes),
deadbeef0a6c4ca2015-10-06 11:38:28 -0700100 "kValidIceServiceTypes must have as many strings as ServiceType "
101 "has values.");
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000102
103enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000104 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000105 MSG_SET_SESSIONDESCRIPTION_FAILED,
deadbeefab9b2d12015-10-14 11:33:11 -0700106 MSG_CREATE_SESSIONDESCRIPTION_FAILED,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000107 MSG_GETSTATS,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000108};
109
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000110struct SetSessionDescriptionMsg : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000111 explicit SetSessionDescriptionMsg(
112 webrtc::SetSessionDescriptionObserver* observer)
113 : observer(observer) {
114 }
115
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000116 rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000117 std::string error;
118};
119
deadbeefab9b2d12015-10-14 11:33:11 -0700120struct CreateSessionDescriptionMsg : public rtc::MessageData {
121 explicit CreateSessionDescriptionMsg(
122 webrtc::CreateSessionDescriptionObserver* observer)
123 : observer(observer) {}
124
125 rtc::scoped_refptr<webrtc::CreateSessionDescriptionObserver> observer;
126 std::string error;
127};
128
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000129struct GetStatsMsg : public rtc::MessageData {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000130 GetStatsMsg(webrtc::StatsObserver* observer,
131 webrtc::MediaStreamTrackInterface* track)
132 : observer(observer), track(track) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000133 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000134 rtc::scoped_refptr<webrtc::StatsObserver> observer;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000135 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000136};
137
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000138// |in_str| should be of format
139// stunURI = scheme ":" stun-host [ ":" stun-port ]
140// scheme = "stun" / "stuns"
141// stun-host = IP-literal / IPv4address / reg-name
142// stun-port = *DIGIT
deadbeef0a6c4ca2015-10-06 11:38:28 -0700143//
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000144// draft-petithuguenin-behave-turn-uris-01
145// turnURI = scheme ":" turn-host [ ":" turn-port ]
146// turn-host = username@IP-literal / IPv4address / reg-name
147bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
148 ServiceType* service_type,
149 std::string* hostname) {
Tommi77d444a2015-04-24 15:38:38 +0200150 const std::string::size_type colonpos = in_str.find(':');
deadbeef0a6c4ca2015-10-06 11:38:28 -0700151 if (colonpos == std::string::npos) {
152 LOG(LS_WARNING) << "Missing ':' in ICE URI: " << in_str;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000153 return false;
154 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700155 if ((colonpos + 1) == in_str.length()) {
156 LOG(LS_WARNING) << "Empty hostname in ICE URI: " << in_str;
157 return false;
158 }
159 *service_type = INVALID;
tfarina5237aaf2015-11-10 23:44:30 -0800160 for (size_t i = 0; i < arraysize(kValidIceServiceTypes); ++i) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700161 if (in_str.compare(0, colonpos, kValidIceServiceTypes[i]) == 0) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000162 *service_type = static_cast<ServiceType>(i);
163 break;
164 }
165 }
166 if (*service_type == INVALID) {
167 return false;
168 }
169 *hostname = in_str.substr(colonpos + 1, std::string::npos);
170 return true;
171}
172
deadbeef0a6c4ca2015-10-06 11:38:28 -0700173bool ParsePort(const std::string& in_str, int* port) {
174 // Make sure port only contains digits. FromString doesn't check this.
175 for (const char& c : in_str) {
176 if (!std::isdigit(c)) {
177 return false;
178 }
179 }
180 return rtc::FromString(in_str, port);
181}
182
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000183// This method parses IPv6 and IPv4 literal strings, along with hostnames in
184// standard hostname:port format.
185// Consider following formats as correct.
186// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700187// |hostname|, |[IPv6 address]|, |IPv4 address|.
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000188bool ParseHostnameAndPortFromString(const std::string& in_str,
189 std::string* host,
190 int* port) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700191 RTC_DCHECK(host->empty());
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000192 if (in_str.at(0) == '[') {
193 std::string::size_type closebracket = in_str.rfind(']');
194 if (closebracket != std::string::npos) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000195 std::string::size_type colonpos = in_str.find(':', closebracket);
196 if (std::string::npos != colonpos) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700197 if (!ParsePort(in_str.substr(closebracket + 2, std::string::npos),
198 port)) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000199 return false;
200 }
201 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700202 *host = in_str.substr(1, closebracket - 1);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000203 } else {
204 return false;
205 }
206 } else {
207 std::string::size_type colonpos = in_str.find(':');
208 if (std::string::npos != colonpos) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700209 if (!ParsePort(in_str.substr(colonpos + 1, std::string::npos), port)) {
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000210 return false;
211 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700212 *host = in_str.substr(0, colonpos);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000213 } else {
214 *host = in_str;
215 }
216 }
deadbeef0a6c4ca2015-10-06 11:38:28 -0700217 return !host->empty();
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000218}
219
deadbeef0a6c4ca2015-10-06 11:38:28 -0700220// Adds a StunConfiguration or TurnConfiguration to the appropriate list,
221// by parsing |url| and using the username/password in |server|.
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200222bool ParseIceServerUrl(const PeerConnectionInterface::IceServer& server,
223 const std::string& url,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700224 StunConfigurations* stun_config,
225 TurnConfigurations* turn_config) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000226 // draft-nandakumar-rtcweb-stun-uri-01
227 // stunURI = scheme ":" stun-host [ ":" stun-port ]
228 // scheme = "stun" / "stuns"
229 // stun-host = IP-literal / IPv4address / reg-name
230 // stun-port = *DIGIT
231
232 // draft-petithuguenin-behave-turn-uris-01
233 // turnURI = scheme ":" turn-host [ ":" turn-port ]
234 // [ "?transport=" transport ]
235 // scheme = "turn" / "turns"
236 // transport = "udp" / "tcp" / transport-ext
237 // transport-ext = 1*unreserved
238 // turn-host = IP-literal / IPv4address / reg-name
239 // turn-port = *DIGIT
deadbeef0a6c4ca2015-10-06 11:38:28 -0700240 RTC_DCHECK(stun_config != nullptr);
241 RTC_DCHECK(turn_config != nullptr);
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200242 std::vector<std::string> tokens;
243 std::string turn_transport_type = kUdpTransportType;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700244 RTC_DCHECK(!url.empty());
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200245 rtc::tokenize(url, '?', &tokens);
246 std::string uri_without_transport = tokens[0];
247 // Let's look into transport= param, if it exists.
248 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
249 std::string uri_transport_param = tokens[1];
250 rtc::tokenize(uri_transport_param, '=', &tokens);
251 if (tokens[0] == kTransport) {
252 // As per above grammar transport param will be consist of lower case
253 // letters.
254 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
255 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
deadbeef0a6c4ca2015-10-06 11:38:28 -0700256 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000257 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200258 turn_transport_type = tokens[1];
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000259 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200260 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000261
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200262 std::string hoststring;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700263 ServiceType service_type;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200264 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
265 &service_type,
266 &hoststring)) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700267 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: " << url;
268 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200269 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000270
deadbeef0a6c4ca2015-10-06 11:38:28 -0700271 // GetServiceTypeAndHostnameFromUri should never give an empty hoststring
272 RTC_DCHECK(!hoststring.empty());
Tommi77d444a2015-04-24 15:38:38 +0200273
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200274 // Let's break hostname.
275 tokens.clear();
deadbeef0a6c4ca2015-10-06 11:38:28 -0700276 rtc::tokenize_with_empty_tokens(hoststring, '@', &tokens);
277
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200278 std::string username(server.username);
deadbeef0a6c4ca2015-10-06 11:38:28 -0700279 if (tokens.size() > kTurnHostTokensNum) {
280 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring;
281 return false;
282 }
283 if (tokens.size() == kTurnHostTokensNum) {
284 if (tokens[0].empty() || tokens[1].empty()) {
285 LOG(LS_WARNING) << "Invalid user@hostname format: " << hoststring;
286 return false;
287 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200288 username.assign(rtc::s_url_decode(tokens[0]));
289 hoststring = tokens[1];
290 } else {
291 hoststring = tokens[0];
292 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000293
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200294 int port = kDefaultStunPort;
295 if (service_type == TURNS) {
296 port = kDefaultStunTlsPort;
297 turn_transport_type = kTcpTransportType;
298 }
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000299
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200300 std::string address;
301 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700302 LOG(WARNING) << "Invalid hostname format: " << uri_without_transport;
303 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200304 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000305
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200306 if (port <= 0 || port > 0xffff) {
307 LOG(WARNING) << "Invalid port: " << port;
deadbeef0a6c4ca2015-10-06 11:38:28 -0700308 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200309 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000310
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200311 switch (service_type) {
312 case STUN:
313 case STUNS:
314 stun_config->push_back(StunConfiguration(address, port));
315 break;
316 case TURN:
317 case TURNS: {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200318 bool secure = (service_type == TURNS);
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200319 turn_config->push_back(TurnConfiguration(address, port,
320 username,
321 server.password,
322 turn_transport_type,
323 secure));
324 break;
325 }
326 case INVALID:
327 default:
328 LOG(WARNING) << "Configuration not supported: " << url;
329 return false;
330 }
331 return true;
332}
333
deadbeefab9b2d12015-10-14 11:33:11 -0700334// Check if we can send |new_stream| on a PeerConnection.
335bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
336 webrtc::MediaStreamInterface* new_stream) {
337 if (!new_stream || !current_streams) {
338 return false;
339 }
340 if (current_streams->find(new_stream->label()) != nullptr) {
341 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
342 << " is already added.";
343 return false;
344 }
345 return true;
346}
347
348bool MediaContentDirectionHasSend(cricket::MediaContentDirection dir) {
349 return dir == cricket::MD_SENDONLY || dir == cricket::MD_SENDRECV;
350}
351
deadbeef5e97fb52015-10-15 12:49:08 -0700352// If the direction is "recvonly" or "inactive", treat the description
353// as containing no streams.
354// See: https://code.google.com/p/webrtc/issues/detail?id=5054
355std::vector<cricket::StreamParams> GetActiveStreams(
356 const cricket::MediaContentDescription* desc) {
357 return MediaContentDirectionHasSend(desc->direction())
358 ? desc->streams()
359 : std::vector<cricket::StreamParams>();
360}
361
deadbeefab9b2d12015-10-14 11:33:11 -0700362bool IsValidOfferToReceiveMedia(int value) {
363 typedef PeerConnectionInterface::RTCOfferAnswerOptions Options;
364 return (value >= Options::kUndefined) &&
365 (value <= Options::kMaxOfferToReceiveMedia);
366}
367
368// Add the stream and RTP data channel info to |session_options|.
deadbeef8f46c632015-10-26 14:11:17 -0700369void SetStreams(cricket::MediaSessionOptions* session_options,
370 rtc::scoped_refptr<StreamCollection> streams,
371 const std::map<std::string, rtc::scoped_refptr<DataChannel>>&
372 rtp_data_channels) {
deadbeefab9b2d12015-10-14 11:33:11 -0700373 session_options->streams.clear();
deadbeef8f46c632015-10-26 14:11:17 -0700374 if (streams != nullptr) {
375 for (size_t i = 0; i < streams->count(); ++i) {
376 MediaStreamInterface* stream = streams->at(i);
377 // For each audio track in the stream, add it to the MediaSessionOptions.
378 for (const auto& track : stream->GetAudioTracks()) {
379 session_options->AddSendStream(cricket::MEDIA_TYPE_AUDIO, track->id(),
380 stream->label());
381 }
382 // For each video track in the stream, add it to the MediaSessionOptions.
383 for (const auto& track : stream->GetVideoTracks()) {
384 session_options->AddSendStream(cricket::MEDIA_TYPE_VIDEO, track->id(),
385 stream->label());
386 }
387 }
deadbeefab9b2d12015-10-14 11:33:11 -0700388 }
389
390 // Check for data channels.
391 for (const auto& kv : rtp_data_channels) {
392 const DataChannel* channel = kv.second;
393 if (channel->state() == DataChannel::kConnecting ||
394 channel->state() == DataChannel::kOpen) {
395 // |streamid| and |sync_label| are both set to the DataChannel label
396 // here so they can be signaled the same way as MediaStreams and Tracks.
397 // For MediaStreams, the sync_label is the MediaStream label and the
398 // track label is the same as |streamid|.
399 const std::string& streamid = channel->label();
400 const std::string& sync_label = channel->label();
401 session_options->AddSendStream(cricket::MEDIA_TYPE_DATA, streamid,
402 sync_label);
403 }
404 }
405}
406
deadbeef0a6c4ca2015-10-06 11:38:28 -0700407} // namespace
408
409namespace webrtc {
410
deadbeefab9b2d12015-10-14 11:33:11 -0700411// Factory class for creating remote MediaStreams and MediaStreamTracks.
412class RemoteMediaStreamFactory {
413 public:
414 explicit RemoteMediaStreamFactory(rtc::Thread* signaling_thread,
415 cricket::ChannelManager* channel_manager)
416 : signaling_thread_(signaling_thread),
417 channel_manager_(channel_manager) {}
418
419 rtc::scoped_refptr<MediaStreamInterface> CreateMediaStream(
420 const std::string& stream_label) {
421 return MediaStreamProxy::Create(signaling_thread_,
422 MediaStream::Create(stream_label));
423 }
424
425 AudioTrackInterface* AddAudioTrack(webrtc::MediaStreamInterface* stream,
426 const std::string& track_id) {
427 return AddTrack<AudioTrackInterface, AudioTrack, AudioTrackProxy>(
428 stream, track_id, RemoteAudioSource::Create().get());
429 }
430
431 VideoTrackInterface* AddVideoTrack(webrtc::MediaStreamInterface* stream,
432 const std::string& track_id) {
433 return AddTrack<VideoTrackInterface, VideoTrack, VideoTrackProxy>(
434 stream, track_id,
435 VideoSource::Create(channel_manager_, new RemoteVideoCapturer(),
436 nullptr)
437 .get());
438 }
439
440 private:
441 template <typename TI, typename T, typename TP, typename S>
442 TI* AddTrack(MediaStreamInterface* stream,
443 const std::string& track_id,
444 S* source) {
445 rtc::scoped_refptr<TI> track(
446 TP::Create(signaling_thread_, T::Create(track_id, source)));
447 track->set_state(webrtc::MediaStreamTrackInterface::kLive);
448 if (stream->AddTrack(track)) {
449 return track;
450 }
451 return nullptr;
452 }
453
454 rtc::Thread* signaling_thread_;
455 cricket::ChannelManager* channel_manager_;
456};
457
458bool ConvertRtcOptionsForOffer(
459 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
460 cricket::MediaSessionOptions* session_options) {
461 typedef PeerConnectionInterface::RTCOfferAnswerOptions RTCOfferAnswerOptions;
462 if (!IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_audio) ||
463 !IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_video)) {
464 return false;
465 }
466
deadbeefc80741f2015-10-22 13:14:45 -0700467 if (rtc_options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) {
deadbeefab9b2d12015-10-14 11:33:11 -0700468 session_options->recv_audio = (rtc_options.offer_to_receive_audio > 0);
469 }
deadbeefc80741f2015-10-22 13:14:45 -0700470 if (rtc_options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) {
deadbeefab9b2d12015-10-14 11:33:11 -0700471 session_options->recv_video = (rtc_options.offer_to_receive_video > 0);
472 }
473
474 session_options->vad_enabled = rtc_options.voice_activity_detection;
475 session_options->transport_options.ice_restart = rtc_options.ice_restart;
deadbeefc80741f2015-10-22 13:14:45 -0700476 session_options->bundle_enabled = rtc_options.use_rtp_mux;
deadbeefab9b2d12015-10-14 11:33:11 -0700477
478 return true;
479}
480
481bool ParseConstraintsForAnswer(const MediaConstraintsInterface* constraints,
482 cricket::MediaSessionOptions* session_options) {
483 bool value = false;
484 size_t mandatory_constraints_satisfied = 0;
485
486 // kOfferToReceiveAudio defaults to true according to spec.
487 if (!FindConstraint(constraints,
488 MediaConstraintsInterface::kOfferToReceiveAudio, &value,
489 &mandatory_constraints_satisfied) ||
490 value) {
491 session_options->recv_audio = true;
492 }
493
494 // kOfferToReceiveVideo defaults to false according to spec. But
495 // if it is an answer and video is offered, we should still accept video
496 // per default.
497 value = false;
498 if (!FindConstraint(constraints,
499 MediaConstraintsInterface::kOfferToReceiveVideo, &value,
500 &mandatory_constraints_satisfied) ||
501 value) {
502 session_options->recv_video = true;
503 }
504
505 if (FindConstraint(constraints,
506 MediaConstraintsInterface::kVoiceActivityDetection, &value,
507 &mandatory_constraints_satisfied)) {
508 session_options->vad_enabled = value;
509 }
510
511 if (FindConstraint(constraints, MediaConstraintsInterface::kUseRtpMux, &value,
512 &mandatory_constraints_satisfied)) {
513 session_options->bundle_enabled = value;
514 } else {
515 // kUseRtpMux defaults to true according to spec.
516 session_options->bundle_enabled = true;
517 }
deadbeefab9b2d12015-10-14 11:33:11 -0700518
519 if (FindConstraint(constraints, MediaConstraintsInterface::kIceRestart,
520 &value, &mandatory_constraints_satisfied)) {
521 session_options->transport_options.ice_restart = value;
522 } else {
523 // kIceRestart defaults to false according to spec.
524 session_options->transport_options.ice_restart = false;
525 }
526
527 if (!constraints) {
528 return true;
529 }
530 return mandatory_constraints_satisfied == constraints->GetMandatory().size();
531}
532
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200533bool ParseIceServers(const PeerConnectionInterface::IceServers& servers,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700534 StunConfigurations* stun_config,
535 TurnConfigurations* turn_config) {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200536 for (const webrtc::PeerConnectionInterface::IceServer& server : servers) {
537 if (!server.urls.empty()) {
538 for (const std::string& url : server.urls) {
Joachim Bauchd935f912015-05-29 22:14:21 +0200539 if (url.empty()) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700540 LOG(LS_ERROR) << "Empty uri.";
541 return false;
Joachim Bauchd935f912015-05-29 22:14:21 +0200542 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200543 if (!ParseIceServerUrl(server, url, stun_config, turn_config)) {
544 return false;
545 }
546 }
547 } else if (!server.uri.empty()) {
548 // Fallback to old .uri if new .urls isn't present.
549 if (!ParseIceServerUrl(server, server.uri, stun_config, turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200551 }
552 } else {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700553 LOG(LS_ERROR) << "Empty uri.";
554 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000555 }
556 }
557 return true;
558}
559
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000560PeerConnection::PeerConnection(PeerConnectionFactory* factory)
561 : factory_(factory),
562 observer_(NULL),
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000563 uma_observer_(NULL),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000564 signaling_state_(kStable),
565 ice_state_(kIceNew),
566 ice_connection_state_(kIceConnectionNew),
deadbeefab9b2d12015-10-14 11:33:11 -0700567 ice_gathering_state_(kIceGatheringNew),
568 local_streams_(StreamCollection::Create()),
569 remote_streams_(StreamCollection::Create()) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000570
571PeerConnection::~PeerConnection() {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700572 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeef70ab1a12015-09-28 16:53:55 -0700573 // Need to detach RTP senders/receivers from WebRtcSession,
574 // since it's about to be destroyed.
575 for (const auto& sender : senders_) {
576 sender->Stop();
577 }
578 for (const auto& receiver : receivers_) {
579 receiver->Stop();
580 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000581}
582
583bool PeerConnection::Initialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000584 const PeerConnectionInterface::RTCConfiguration& configuration,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000585 const MediaConstraintsInterface* constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000586 PortAllocatorFactoryInterface* allocator_factory,
Henrik Boström5e56c592015-08-11 10:33:13 +0200587 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000588 PeerConnectionObserver* observer) {
deadbeefab9b2d12015-10-14 11:33:11 -0700589 RTC_DCHECK(observer != nullptr);
590 if (!observer) {
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000591 return false;
deadbeefab9b2d12015-10-14 11:33:11 -0700592 }
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000593 observer_ = observer;
594
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000595 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
596 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000597 if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 return false;
599 }
deadbeef18a944b2015-10-26 19:21:40 -0700600 port_allocator_.reset(
601 allocator_factory->CreatePortAllocator(stun_config, turn_config));
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000602
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000603 // To handle both internal and externally created port allocator, we will
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000604 // enable BUNDLE here.
braveyao@webrtc.org1732df62014-10-27 03:01:37 +0000605 int portallocator_flags = port_allocator_->flags();
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700606 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000607 cricket::PORTALLOCATOR_ENABLE_IPV6;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000608 bool value;
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000609 // If IPv6 flag was specified, we'll not override it by experiment.
deadbeefab9b2d12015-10-14 11:33:11 -0700610 if (FindConstraint(constraints, MediaConstraintsInterface::kEnableIPv6,
611 &value, nullptr)) {
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000612 if (!value) {
613 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000614 }
guoweis@webrtc.org2c1bcea2014-09-23 16:23:02 +0000615 } else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default") ==
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000616 "Disabled") {
617 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000618 }
619
Jiayang Liucac1b382015-04-30 12:35:24 -0700620 if (configuration.tcp_candidate_policy == kTcpCandidatePolicyDisabled) {
621 portallocator_flags |= cricket::PORTALLOCATOR_DISABLE_TCP;
622 LOG(LS_INFO) << "TCP candidates are disabled.";
623 }
624
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000625 port_allocator_->set_flags(portallocator_flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000626 // No step delay is used while allocating ports.
627 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
628
stefanc1aeaf02015-10-15 07:26:07 -0700629 media_controller_.reset(factory_->CreateMediaController());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000630
stefanc1aeaf02015-10-15 07:26:07 -0700631 remote_stream_factory_.reset(new RemoteMediaStreamFactory(
632 factory_->signaling_thread(), media_controller_->channel_manager()));
633
634 session_.reset(
635 new WebRtcSession(media_controller_.get(), factory_->signaling_thread(),
636 factory_->worker_thread(), port_allocator_.get()));
deadbeefab9b2d12015-10-14 11:33:11 -0700637 stats_.reset(new StatsCollector(this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000638
639 // Initialize the WebRtcSession. It creates transport channels etc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000640 if (!session_->Initialize(factory_->options(), constraints,
deadbeefab9b2d12015-10-14 11:33:11 -0700641 dtls_identity_store.Pass(), configuration)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000642 return false;
deadbeefab9b2d12015-10-14 11:33:11 -0700643 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000644
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000645 // Register PeerConnection as receiver of local ice candidates.
646 // All the callbacks will be posted to the application from PeerConnection.
647 session_->RegisterIceObserver(this);
648 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
deadbeefab9b2d12015-10-14 11:33:11 -0700649 session_->SignalVoiceChannelDestroyed.connect(
650 this, &PeerConnection::OnVoiceChannelDestroyed);
651 session_->SignalVideoChannelDestroyed.connect(
652 this, &PeerConnection::OnVideoChannelDestroyed);
653 session_->SignalDataChannelCreated.connect(
654 this, &PeerConnection::OnDataChannelCreated);
655 session_->SignalDataChannelDestroyed.connect(
656 this, &PeerConnection::OnDataChannelDestroyed);
657 session_->SignalDataChannelOpenMessage.connect(
658 this, &PeerConnection::OnDataChannelOpenMessage);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000659 return true;
660}
661
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000662rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663PeerConnection::local_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -0700664 return local_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000665}
666
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000667rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000668PeerConnection::remote_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -0700669 return remote_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000670}
671
deadbeef8f46c632015-10-26 14:11:17 -0700672// TODO(deadbeef): Create RtpSenders immediately here, even if local
673// description hasn't yet been set.
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +0000674bool PeerConnection::AddStream(MediaStreamInterface* local_stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000675 if (IsClosed()) {
676 return false;
677 }
deadbeefab9b2d12015-10-14 11:33:11 -0700678 if (!CanAddLocalMediaStream(local_streams_, local_stream)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000679 return false;
680 }
deadbeefab9b2d12015-10-14 11:33:11 -0700681
682 local_streams_->AddStream(local_stream);
683
deadbeef8f46c632015-10-26 14:11:17 -0700684 // Find tracks that have already been configured in SDP. This can occur if a
685 // local session description that contains the MSID of these tracks is set
686 // before AddLocalStream is called. It can also occur if the local session
687 // description is not changed and RemoveLocalStream is called and later
688 // AddLocalStream is called again with the same stream.
deadbeefab9b2d12015-10-14 11:33:11 -0700689 for (const auto& track : local_stream->GetAudioTracks()) {
deadbeef8f46c632015-10-26 14:11:17 -0700690 const TrackInfo* track_info =
691 FindTrackInfo(local_audio_tracks_, local_stream->label(), track->id());
692 if (track_info) {
693 CreateAudioSender(local_stream, track.get(), track_info->ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -0700694 }
695 }
696 for (const auto& track : local_stream->GetVideoTracks()) {
deadbeef8f46c632015-10-26 14:11:17 -0700697 const TrackInfo* track_info =
698 FindTrackInfo(local_video_tracks_, local_stream->label(), track->id());
699 if (track_info) {
700 CreateVideoSender(local_stream, track.get(), track_info->ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -0700701 }
702 }
703
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000704 stats_->AddStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000705 observer_->OnRenegotiationNeeded();
706 return true;
707}
708
deadbeefab9b2d12015-10-14 11:33:11 -0700709// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around
deadbeef8f46c632015-10-26 14:11:17 -0700710// indefinitely.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000711void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
deadbeefab9b2d12015-10-14 11:33:11 -0700712 for (const auto& track : local_stream->GetAudioTracks()) {
deadbeef8f46c632015-10-26 14:11:17 -0700713 const TrackInfo* track_info =
714 FindTrackInfo(local_audio_tracks_, local_stream->label(), track->id());
715 if (track_info) {
716 DestroyAudioSender(local_stream, track.get(), track_info->ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -0700717 }
718 }
719 for (const auto& track : local_stream->GetVideoTracks()) {
deadbeef8f46c632015-10-26 14:11:17 -0700720 const TrackInfo* track_info =
721 FindTrackInfo(local_video_tracks_, local_stream->label(), track->id());
722 if (track_info) {
723 DestroyVideoSender(local_stream, track.get());
deadbeefab9b2d12015-10-14 11:33:11 -0700724 }
725 }
726
727 local_streams_->RemoveStream(local_stream);
728
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000729 if (IsClosed()) {
730 return;
731 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000732 observer_->OnRenegotiationNeeded();
733}
734
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000735rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000736 AudioTrackInterface* track) {
737 if (!track) {
738 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
739 return NULL;
740 }
deadbeefab9b2d12015-10-14 11:33:11 -0700741 if (!local_streams_->FindAudioTrack(track->id())) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000742 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
743 return NULL;
744 }
745
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000746 rtc::scoped_refptr<DtmfSenderInterface> sender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000747 DtmfSender::Create(track, signaling_thread(), session_.get()));
748 if (!sender.get()) {
749 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
750 return NULL;
751 }
752 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
753}
754
deadbeef70ab1a12015-09-28 16:53:55 -0700755std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders()
756 const {
757 std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders;
758 for (const auto& sender : senders_) {
759 senders.push_back(RtpSenderProxy::Create(signaling_thread(), sender.get()));
760 }
761 return senders;
762}
763
764std::vector<rtc::scoped_refptr<RtpReceiverInterface>>
765PeerConnection::GetReceivers() const {
766 std::vector<rtc::scoped_refptr<RtpReceiverInterface>> receivers;
767 for (const auto& receiver : receivers_) {
768 receivers.push_back(
769 RtpReceiverProxy::Create(signaling_thread(), receiver.get()));
770 }
771 return receivers;
772}
773
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000774bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000775 MediaStreamTrackInterface* track,
776 StatsOutputLevel level) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700777 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000778 if (!VERIFY(observer != NULL)) {
779 LOG(LS_ERROR) << "GetStats - observer is NULL.";
780 return false;
781 }
782
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000783 stats_->UpdateStats(level);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000784 signaling_thread()->Post(this, MSG_GETSTATS,
785 new GetStatsMsg(observer, track));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000786 return true;
787}
788
789PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
790 return signaling_state_;
791}
792
793PeerConnectionInterface::IceState PeerConnection::ice_state() {
794 return ice_state_;
795}
796
797PeerConnectionInterface::IceConnectionState
798PeerConnection::ice_connection_state() {
799 return ice_connection_state_;
800}
801
802PeerConnectionInterface::IceGatheringState
803PeerConnection::ice_gathering_state() {
804 return ice_gathering_state_;
805}
806
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000807rtc::scoped_refptr<DataChannelInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000808PeerConnection::CreateDataChannel(
809 const std::string& label,
810 const DataChannelInit* config) {
deadbeefab9b2d12015-10-14 11:33:11 -0700811 bool first_datachannel = !HasDataChannels();
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000812
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000813 rtc::scoped_ptr<InternalDataChannelInit> internal_config;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000814 if (config) {
815 internal_config.reset(new InternalDataChannelInit(*config));
816 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000817 rtc::scoped_refptr<DataChannelInterface> channel(
deadbeefab9b2d12015-10-14 11:33:11 -0700818 InternalCreateDataChannel(label, internal_config.get()));
819 if (!channel.get()) {
820 return nullptr;
821 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000822
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000823 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
824 // the first SCTP DataChannel.
825 if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
826 observer_->OnRenegotiationNeeded();
827 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000828
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000829 return DataChannelProxy::Create(signaling_thread(), channel.get());
830}
831
832void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
833 const MediaConstraintsInterface* constraints) {
deadbeefab9b2d12015-10-14 11:33:11 -0700834 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000835 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
836 return;
837 }
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000838 RTCOfferAnswerOptions options;
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000839
840 bool value;
841 size_t mandatory_constraints = 0;
842
843 if (FindConstraint(constraints,
844 MediaConstraintsInterface::kOfferToReceiveAudio,
845 &value,
846 &mandatory_constraints)) {
847 options.offer_to_receive_audio =
848 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
849 }
850
851 if (FindConstraint(constraints,
852 MediaConstraintsInterface::kOfferToReceiveVideo,
853 &value,
854 &mandatory_constraints)) {
855 options.offer_to_receive_video =
856 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
857 }
858
859 if (FindConstraint(constraints,
860 MediaConstraintsInterface::kVoiceActivityDetection,
861 &value,
862 &mandatory_constraints)) {
863 options.voice_activity_detection = value;
864 }
865
866 if (FindConstraint(constraints,
867 MediaConstraintsInterface::kIceRestart,
868 &value,
869 &mandatory_constraints)) {
870 options.ice_restart = value;
871 }
872
873 if (FindConstraint(constraints,
874 MediaConstraintsInterface::kUseRtpMux,
875 &value,
876 &mandatory_constraints)) {
877 options.use_rtp_mux = value;
878 }
879
880 CreateOffer(observer, options);
881}
882
883void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
884 const RTCOfferAnswerOptions& options) {
deadbeefab9b2d12015-10-14 11:33:11 -0700885 if (!VERIFY(observer != nullptr)) {
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000886 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
887 return;
888 }
deadbeefab9b2d12015-10-14 11:33:11 -0700889
890 cricket::MediaSessionOptions session_options;
891 if (!GetOptionsForOffer(options, &session_options)) {
892 std::string error = "CreateOffer called with invalid options.";
893 LOG(LS_ERROR) << error;
894 PostCreateSessionDescriptionFailure(observer, error);
895 return;
896 }
897
898 session_->CreateOffer(observer, options, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000899}
900
901void PeerConnection::CreateAnswer(
902 CreateSessionDescriptionObserver* observer,
903 const MediaConstraintsInterface* constraints) {
deadbeefab9b2d12015-10-14 11:33:11 -0700904 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000905 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
906 return;
907 }
deadbeefab9b2d12015-10-14 11:33:11 -0700908
909 cricket::MediaSessionOptions session_options;
910 if (!GetOptionsForAnswer(constraints, &session_options)) {
911 std::string error = "CreateAnswer called with invalid constraints.";
912 LOG(LS_ERROR) << error;
913 PostCreateSessionDescriptionFailure(observer, error);
914 return;
915 }
916
917 session_->CreateAnswer(observer, constraints, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000918}
919
920void PeerConnection::SetLocalDescription(
921 SetSessionDescriptionObserver* observer,
922 SessionDescriptionInterface* desc) {
deadbeefab9b2d12015-10-14 11:33:11 -0700923 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000924 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
925 return;
926 }
927 if (!desc) {
928 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
929 return;
930 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000931 // Update stats here so that we have the most recent stats for tracks and
932 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000933 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000934 std::string error;
935 if (!session_->SetLocalDescription(desc, &error)) {
936 PostSetSessionDescriptionFailure(observer, error);
937 return;
938 }
deadbeefab9b2d12015-10-14 11:33:11 -0700939
940 // If setting the description decided our SSL role, allocate any necessary
941 // SCTP sids.
942 rtc::SSLRole role;
943 if (session_->data_channel_type() == cricket::DCT_SCTP &&
944 session_->GetSslRole(&role)) {
945 AllocateSctpSids(role);
946 }
947
948 // Update state and SSRC of local MediaStreams and DataChannels based on the
949 // local session description.
950 const cricket::ContentInfo* audio_content =
951 GetFirstAudioContent(desc->description());
952 if (audio_content) {
953 const cricket::AudioContentDescription* audio_desc =
954 static_cast<const cricket::AudioContentDescription*>(
955 audio_content->description);
956 UpdateLocalTracks(audio_desc->streams(), audio_desc->type());
957 }
958
959 const cricket::ContentInfo* video_content =
960 GetFirstVideoContent(desc->description());
961 if (video_content) {
962 const cricket::VideoContentDescription* video_desc =
963 static_cast<const cricket::VideoContentDescription*>(
964 video_content->description);
965 UpdateLocalTracks(video_desc->streams(), video_desc->type());
966 }
967
968 const cricket::ContentInfo* data_content =
969 GetFirstDataContent(desc->description());
970 if (data_content) {
971 const cricket::DataContentDescription* data_desc =
972 static_cast<const cricket::DataContentDescription*>(
973 data_content->description);
974 if (rtc::starts_with(data_desc->protocol().data(),
975 cricket::kMediaProtocolRtpPrefix)) {
976 UpdateLocalRtpDataChannels(data_desc->streams());
977 }
978 }
979
980 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000981 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeefab9b2d12015-10-14 11:33:11 -0700982
deadbeefcbecd352015-09-23 11:50:27 -0700983 // MaybeStartGathering needs to be called after posting
984 // MSG_SET_SESSIONDESCRIPTION_SUCCESS, so that we don't signal any candidates
985 // before signaling that SetLocalDescription completed.
986 session_->MaybeStartGathering();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000987}
988
989void PeerConnection::SetRemoteDescription(
990 SetSessionDescriptionObserver* observer,
991 SessionDescriptionInterface* desc) {
deadbeefab9b2d12015-10-14 11:33:11 -0700992 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000993 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
994 return;
995 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000996 if (!desc) {
997 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
998 return;
999 }
1000 // Update stats here so that we have the most recent stats for tracks and
1001 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001002 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001003 std::string error;
1004 if (!session_->SetRemoteDescription(desc, &error)) {
1005 PostSetSessionDescriptionFailure(observer, error);
1006 return;
1007 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001008
deadbeefab9b2d12015-10-14 11:33:11 -07001009 // If setting the description decided our SSL role, allocate any necessary
1010 // SCTP sids.
1011 rtc::SSLRole role;
1012 if (session_->data_channel_type() == cricket::DCT_SCTP &&
1013 session_->GetSslRole(&role)) {
1014 AllocateSctpSids(role);
1015 }
1016
1017 const cricket::SessionDescription* remote_desc = desc->description();
1018
1019 // We wait to signal new streams until we finish processing the description,
1020 // since only at that point will new streams have all their tracks.
1021 rtc::scoped_refptr<StreamCollection> new_streams(StreamCollection::Create());
1022
1023 // Find all audio rtp streams and create corresponding remote AudioTracks
1024 // and MediaStreams.
1025 const cricket::ContentInfo* audio_content = GetFirstAudioContent(remote_desc);
1026 if (audio_content) {
1027 const cricket::AudioContentDescription* desc =
1028 static_cast<const cricket::AudioContentDescription*>(
1029 audio_content->description);
deadbeef5e97fb52015-10-15 12:49:08 -07001030 UpdateRemoteStreamsList(GetActiveStreams(desc), desc->type(), new_streams);
deadbeefab9b2d12015-10-14 11:33:11 -07001031 remote_info_.default_audio_track_needed =
deadbeefc80741f2015-10-22 13:14:45 -07001032 !remote_desc->msid_supported() && desc->streams().empty() &&
1033 MediaContentDirectionHasSend(desc->direction());
deadbeefab9b2d12015-10-14 11:33:11 -07001034 }
1035
1036 // Find all video rtp streams and create corresponding remote VideoTracks
1037 // and MediaStreams.
1038 const cricket::ContentInfo* video_content = GetFirstVideoContent(remote_desc);
1039 if (video_content) {
1040 const cricket::VideoContentDescription* desc =
1041 static_cast<const cricket::VideoContentDescription*>(
1042 video_content->description);
deadbeef5e97fb52015-10-15 12:49:08 -07001043 UpdateRemoteStreamsList(GetActiveStreams(desc), desc->type(), new_streams);
deadbeefab9b2d12015-10-14 11:33:11 -07001044 remote_info_.default_video_track_needed =
deadbeefc80741f2015-10-22 13:14:45 -07001045 !remote_desc->msid_supported() && desc->streams().empty() &&
1046 MediaContentDirectionHasSend(desc->direction());
deadbeefab9b2d12015-10-14 11:33:11 -07001047 }
1048
1049 // Update the DataChannels with the information from the remote peer.
1050 const cricket::ContentInfo* data_content = GetFirstDataContent(remote_desc);
1051 if (data_content) {
deadbeef5e97fb52015-10-15 12:49:08 -07001052 const cricket::DataContentDescription* desc =
deadbeefab9b2d12015-10-14 11:33:11 -07001053 static_cast<const cricket::DataContentDescription*>(
1054 data_content->description);
deadbeef5e97fb52015-10-15 12:49:08 -07001055 if (rtc::starts_with(desc->protocol().data(),
deadbeefab9b2d12015-10-14 11:33:11 -07001056 cricket::kMediaProtocolRtpPrefix)) {
deadbeef5e97fb52015-10-15 12:49:08 -07001057 UpdateRemoteRtpDataChannels(GetActiveStreams(desc));
deadbeefab9b2d12015-10-14 11:33:11 -07001058 }
1059 }
1060
1061 // Iterate new_streams and notify the observer about new MediaStreams.
1062 for (size_t i = 0; i < new_streams->count(); ++i) {
1063 MediaStreamInterface* new_stream = new_streams->at(i);
1064 stats_->AddStream(new_stream);
1065 observer_->OnAddStream(new_stream);
1066 }
1067
1068 // Find removed MediaStreams.
1069 if (remote_info_.IsDefaultMediaStreamNeeded() &&
1070 remote_streams_->find(kDefaultStreamLabel) != nullptr) {
1071 // The default media stream already exists. No need to do anything.
1072 } else {
1073 UpdateEndedRemoteMediaStreams();
1074 remote_info_.msid_supported |= remote_streams_->count() > 0;
1075 }
1076 MaybeCreateDefaultStream();
1077
1078 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1079 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeeffc648b62015-10-13 16:42:33 -07001080}
1081
deadbeefa67696b2015-09-29 11:56:26 -07001082bool PeerConnection::SetConfiguration(const RTCConfiguration& config) {
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001083 if (port_allocator_) {
1084 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
1085 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
1086 if (!ParseIceServers(config.servers, &stuns, &turns)) {
1087 return false;
1088 }
1089
deadbeef18a944b2015-10-26 19:21:40 -07001090 std::vector<rtc::SocketAddress> stun_hosts;
1091 typedef std::vector<StunConfiguration>::const_iterator StunIt;
1092 for (StunIt stun_it = stuns.begin(); stun_it != stuns.end(); ++stun_it) {
1093 stun_hosts.push_back(stun_it->server);
1094 }
1095
1096 rtc::SocketAddress stun_addr;
1097 if (!stun_hosts.empty()) {
1098 stun_addr = stun_hosts.front();
1099 LOG(LS_INFO) << "SetConfiguration: StunServer Address: "
1100 << stun_addr.ToString();
1101 }
1102
1103 for (size_t i = 0; i < turns.size(); ++i) {
1104 cricket::RelayCredentials credentials(turns[i].username,
1105 turns[i].password);
1106 cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
1107 cricket::ProtocolType protocol;
1108 if (cricket::StringToProto(turns[i].transport_type.c_str(), &protocol)) {
1109 relay_server.ports.push_back(cricket::ProtocolAddress(
1110 turns[i].server, protocol, turns[i].secure));
1111 relay_server.credentials = credentials;
1112 LOG(LS_INFO) << "SetConfiguration: TurnServer Address: "
1113 << turns[i].server.ToString();
1114 } else {
1115 LOG(LS_WARNING) << "Ignoring TURN server " << turns[i].server << ". "
1116 << "Reason= Incorrect " << turns[i].transport_type
1117 << " transport parameter.";
1118 }
1119 }
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001120 }
honghaiz1f429e32015-09-28 07:57:34 -07001121 session_->SetIceConfig(session_->ParseIceConfig(config));
mallinath@webrtc.org3d81b1b2014-09-09 14:38:10 +00001122 return session_->SetIceTransports(config.type);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001123}
1124
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001125bool PeerConnection::AddIceCandidate(
1126 const IceCandidateInterface* ice_candidate) {
1127 return session_->ProcessIceMessage(ice_candidate);
1128}
1129
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001130void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
1131 uma_observer_ = observer;
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +00001132
1133 if (session_) {
1134 session_->set_metrics_observer(uma_observer_);
1135 }
1136
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001137 // Send information about IPv4/IPv6 status.
1138 if (uma_observer_ && port_allocator_) {
1139 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001140 uma_observer_->IncrementEnumCounter(
1141 kEnumCounterAddressFamily, kPeerConnection_IPv6,
1142 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgb445f262014-05-23 22:19:37 +00001143 } else {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001144 uma_observer_->IncrementEnumCounter(
1145 kEnumCounterAddressFamily, kPeerConnection_IPv4,
1146 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001147 }
1148 }
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001149}
1150
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001151const SessionDescriptionInterface* PeerConnection::local_description() const {
1152 return session_->local_description();
1153}
1154
1155const SessionDescriptionInterface* PeerConnection::remote_description() const {
1156 return session_->remote_description();
1157}
1158
1159void PeerConnection::Close() {
1160 // Update stats here so that we have the most recent stats for tracks and
1161 // streams before the channels are closed.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001162 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001163
deadbeefd59daf82015-10-14 15:02:44 -07001164 session_->Close();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001165}
1166
deadbeefd59daf82015-10-14 15:02:44 -07001167void PeerConnection::OnSessionStateChange(WebRtcSession* /*session*/,
1168 WebRtcSession::State state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001169 switch (state) {
deadbeefd59daf82015-10-14 15:02:44 -07001170 case WebRtcSession::STATE_INIT:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001171 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001172 break;
deadbeefd59daf82015-10-14 15:02:44 -07001173 case WebRtcSession::STATE_SENTOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001174 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
1175 break;
deadbeefd59daf82015-10-14 15:02:44 -07001176 case WebRtcSession::STATE_SENTPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001177 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
1178 break;
deadbeefd59daf82015-10-14 15:02:44 -07001179 case WebRtcSession::STATE_RECEIVEDOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001180 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
1181 break;
deadbeefd59daf82015-10-14 15:02:44 -07001182 case WebRtcSession::STATE_RECEIVEDPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001183 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
1184 break;
deadbeefd59daf82015-10-14 15:02:44 -07001185 case WebRtcSession::STATE_INPROGRESS:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001186 ChangeSignalingState(PeerConnectionInterface::kStable);
1187 break;
deadbeefd59daf82015-10-14 15:02:44 -07001188 case WebRtcSession::STATE_CLOSED:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001189 ChangeSignalingState(PeerConnectionInterface::kClosed);
1190 break;
1191 default:
1192 break;
1193 }
1194}
1195
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001196void PeerConnection::OnMessage(rtc::Message* msg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001197 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001198 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
1199 SetSessionDescriptionMsg* param =
1200 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1201 param->observer->OnSuccess();
1202 delete param;
1203 break;
1204 }
1205 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
1206 SetSessionDescriptionMsg* param =
1207 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1208 param->observer->OnFailure(param->error);
1209 delete param;
1210 break;
1211 }
deadbeefab9b2d12015-10-14 11:33:11 -07001212 case MSG_CREATE_SESSIONDESCRIPTION_FAILED: {
1213 CreateSessionDescriptionMsg* param =
1214 static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
1215 param->observer->OnFailure(param->error);
1216 delete param;
1217 break;
1218 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001219 case MSG_GETSTATS: {
1220 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +00001221 StatsReports reports;
1222 stats_->GetStats(param->track, &reports);
1223 param->observer->OnComplete(reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001224 delete param;
1225 break;
1226 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001227 default:
deadbeef0a6c4ca2015-10-06 11:38:28 -07001228 RTC_DCHECK(false && "Not implemented");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001229 break;
1230 }
1231}
1232
deadbeefab9b2d12015-10-14 11:33:11 -07001233void PeerConnection::CreateAudioReceiver(MediaStreamInterface* stream,
1234 AudioTrackInterface* audio_track,
1235 uint32_t ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -07001236 receivers_.push_back(new AudioRtpReceiver(audio_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001237}
1238
deadbeefab9b2d12015-10-14 11:33:11 -07001239void PeerConnection::CreateVideoReceiver(MediaStreamInterface* stream,
1240 VideoTrackInterface* video_track,
1241 uint32_t ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -07001242 receivers_.push_back(new VideoRtpReceiver(video_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001243}
1244
deadbeef70ab1a12015-09-28 16:53:55 -07001245// TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote
1246// description.
deadbeefab9b2d12015-10-14 11:33:11 -07001247void PeerConnection::DestroyAudioReceiver(MediaStreamInterface* stream,
1248 AudioTrackInterface* audio_track) {
deadbeef70ab1a12015-09-28 16:53:55 -07001249 auto it = FindReceiverForTrack(audio_track);
1250 if (it == receivers_.end()) {
1251 LOG(LS_WARNING) << "RtpReceiver for track with id " << audio_track->id()
1252 << " doesn't exist.";
1253 } else {
1254 (*it)->Stop();
1255 receivers_.erase(it);
1256 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001257}
1258
deadbeefab9b2d12015-10-14 11:33:11 -07001259void PeerConnection::DestroyVideoReceiver(MediaStreamInterface* stream,
1260 VideoTrackInterface* video_track) {
deadbeef70ab1a12015-09-28 16:53:55 -07001261 auto it = FindReceiverForTrack(video_track);
1262 if (it == receivers_.end()) {
1263 LOG(LS_WARNING) << "RtpReceiver for track with id " << video_track->id()
1264 << " doesn't exist.";
1265 } else {
1266 (*it)->Stop();
1267 receivers_.erase(it);
1268 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001269}
deadbeef70ab1a12015-09-28 16:53:55 -07001270
deadbeef8f46c632015-10-26 14:11:17 -07001271void PeerConnection::CreateAudioSender(MediaStreamInterface* stream,
1272 AudioTrackInterface* audio_track,
1273 uint32_t ssrc) {
1274 senders_.push_back(new AudioRtpSender(audio_track, ssrc, session_.get()));
1275 stats_->AddLocalAudioTrack(audio_track, ssrc);
1276}
1277
1278void PeerConnection::CreateVideoSender(MediaStreamInterface* stream,
1279 VideoTrackInterface* video_track,
1280 uint32_t ssrc) {
1281 senders_.push_back(new VideoRtpSender(video_track, ssrc, session_.get()));
1282}
1283
1284// TODO(deadbeef): Keep RtpSenders around even if track goes away in local
1285// description.
1286void PeerConnection::DestroyAudioSender(MediaStreamInterface* stream,
1287 AudioTrackInterface* audio_track,
1288 uint32_t ssrc) {
1289 auto it = FindSenderForTrack(audio_track);
1290 if (it == senders_.end()) {
1291 LOG(LS_WARNING) << "RtpSender for track with id " << audio_track->id()
1292 << " doesn't exist.";
1293 return;
1294 } else {
1295 (*it)->Stop();
1296 senders_.erase(it);
1297 }
1298 stats_->RemoveLocalAudioTrack(audio_track, ssrc);
1299}
1300
1301void PeerConnection::DestroyVideoSender(MediaStreamInterface* stream,
1302 VideoTrackInterface* video_track) {
1303 auto it = FindSenderForTrack(video_track);
1304 if (it == senders_.end()) {
1305 LOG(LS_WARNING) << "RtpSender for track with id " << video_track->id()
1306 << " doesn't exist.";
1307 return;
1308 } else {
1309 (*it)->Stop();
1310 senders_.erase(it);
1311 }
1312}
1313
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001314void PeerConnection::OnIceConnectionChange(
1315 PeerConnectionInterface::IceConnectionState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001316 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefcbecd352015-09-23 11:50:27 -07001317 // After transitioning to "closed", ignore any additional states from
1318 // WebRtcSession (such as "disconnected").
deadbeefab9b2d12015-10-14 11:33:11 -07001319 if (IsClosed()) {
deadbeefcbecd352015-09-23 11:50:27 -07001320 return;
1321 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001322 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001323 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001324}
1325
1326void PeerConnection::OnIceGatheringChange(
1327 PeerConnectionInterface::IceGatheringState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001328 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001329 if (IsClosed()) {
1330 return;
1331 }
1332 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001333 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001334}
1335
1336void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001337 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001338 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001339}
1340
1341void PeerConnection::OnIceComplete() {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001342 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001343 observer_->OnIceComplete();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001344}
1345
Peter Thatcher54360512015-07-08 11:08:35 -07001346void PeerConnection::OnIceConnectionReceivingChange(bool receiving) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001347 RTC_DCHECK(signaling_thread()->IsCurrent());
Peter Thatcher54360512015-07-08 11:08:35 -07001348 observer_->OnIceConnectionReceivingChange(receiving);
1349}
1350
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001351void PeerConnection::ChangeSignalingState(
1352 PeerConnectionInterface::SignalingState signaling_state) {
1353 signaling_state_ = signaling_state;
1354 if (signaling_state == kClosed) {
1355 ice_connection_state_ = kIceConnectionClosed;
1356 observer_->OnIceConnectionChange(ice_connection_state_);
1357 if (ice_gathering_state_ != kIceGatheringComplete) {
1358 ice_gathering_state_ = kIceGatheringComplete;
1359 observer_->OnIceGatheringChange(ice_gathering_state_);
1360 }
1361 }
1362 observer_->OnSignalingChange(signaling_state_);
1363 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
1364}
1365
deadbeefab9b2d12015-10-14 11:33:11 -07001366void PeerConnection::PostSetSessionDescriptionFailure(
1367 SetSessionDescriptionObserver* observer,
1368 const std::string& error) {
1369 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1370 msg->error = error;
1371 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
1372}
1373
1374void PeerConnection::PostCreateSessionDescriptionFailure(
1375 CreateSessionDescriptionObserver* observer,
1376 const std::string& error) {
1377 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
1378 msg->error = error;
1379 signaling_thread()->Post(this, MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
1380}
1381
1382bool PeerConnection::GetOptionsForOffer(
1383 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
1384 cricket::MediaSessionOptions* session_options) {
deadbeefab9b2d12015-10-14 11:33:11 -07001385 if (!ConvertRtcOptionsForOffer(rtc_options, session_options)) {
1386 return false;
1387 }
1388
deadbeef8f46c632015-10-26 14:11:17 -07001389 SetStreams(session_options, local_streams_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001390 // Offer to receive audio/video if the constraint is not set and there are
1391 // send streams, or we're currently receiving.
1392 if (rtc_options.offer_to_receive_audio == RTCOfferAnswerOptions::kUndefined) {
1393 session_options->recv_audio =
1394 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_AUDIO) ||
1395 !remote_audio_tracks_.empty();
1396 }
1397 if (rtc_options.offer_to_receive_video == RTCOfferAnswerOptions::kUndefined) {
1398 session_options->recv_video =
1399 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_VIDEO) ||
1400 !remote_video_tracks_.empty();
1401 }
1402 session_options->bundle_enabled =
1403 session_options->bundle_enabled &&
1404 (session_options->has_audio() || session_options->has_video() ||
1405 session_options->has_data());
1406
deadbeefab9b2d12015-10-14 11:33:11 -07001407 if (session_->data_channel_type() == cricket::DCT_SCTP && HasDataChannels()) {
1408 session_options->data_channel_type = cricket::DCT_SCTP;
1409 }
1410 return true;
1411}
1412
1413bool PeerConnection::GetOptionsForAnswer(
1414 const MediaConstraintsInterface* constraints,
1415 cricket::MediaSessionOptions* session_options) {
deadbeefab9b2d12015-10-14 11:33:11 -07001416 session_options->recv_audio = false;
1417 session_options->recv_video = false;
deadbeefab9b2d12015-10-14 11:33:11 -07001418 if (!ParseConstraintsForAnswer(constraints, session_options)) {
1419 return false;
1420 }
1421
deadbeef8f46c632015-10-26 14:11:17 -07001422 SetStreams(session_options, local_streams_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001423 session_options->bundle_enabled =
1424 session_options->bundle_enabled &&
1425 (session_options->has_audio() || session_options->has_video() ||
1426 session_options->has_data());
1427
deadbeefab9b2d12015-10-14 11:33:11 -07001428 // RTP data channel is handled in MediaSessionOptions::AddStream. SCTP streams
1429 // are not signaled in the SDP so does not go through that path and must be
1430 // handled here.
1431 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1432 session_options->data_channel_type = cricket::DCT_SCTP;
1433 }
1434 return true;
1435}
1436
1437void PeerConnection::UpdateRemoteStreamsList(
1438 const cricket::StreamParamsVec& streams,
1439 cricket::MediaType media_type,
1440 StreamCollection* new_streams) {
1441 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1442
1443 // Find removed tracks. I.e., tracks where the track id or ssrc don't match
deadbeef8f46c632015-10-26 14:11:17 -07001444 // the
1445 // new StreamParam.
deadbeefab9b2d12015-10-14 11:33:11 -07001446 auto track_it = current_tracks->begin();
1447 while (track_it != current_tracks->end()) {
1448 const TrackInfo& info = *track_it;
1449 const cricket::StreamParams* params =
1450 cricket::GetStreamBySsrc(streams, info.ssrc);
1451 if (!params || params->id != info.track_id) {
1452 OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
1453 track_it = current_tracks->erase(track_it);
1454 } else {
1455 ++track_it;
1456 }
1457 }
1458
1459 // Find new and active tracks.
1460 for (const cricket::StreamParams& params : streams) {
1461 // The sync_label is the MediaStream label and the |stream.id| is the
1462 // track id.
1463 const std::string& stream_label = params.sync_label;
1464 const std::string& track_id = params.id;
1465 uint32_t ssrc = params.first_ssrc();
1466
1467 rtc::scoped_refptr<MediaStreamInterface> stream =
1468 remote_streams_->find(stream_label);
1469 if (!stream) {
1470 // This is a new MediaStream. Create a new remote MediaStream.
1471 stream = remote_stream_factory_->CreateMediaStream(stream_label);
1472 remote_streams_->AddStream(stream);
1473 new_streams->AddStream(stream);
1474 }
1475
1476 const TrackInfo* track_info =
1477 FindTrackInfo(*current_tracks, stream_label, track_id);
1478 if (!track_info) {
1479 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1480 OnRemoteTrackSeen(stream_label, track_id, ssrc, media_type);
1481 }
1482 }
1483}
1484
1485void PeerConnection::OnRemoteTrackSeen(const std::string& stream_label,
1486 const std::string& track_id,
1487 uint32_t ssrc,
1488 cricket::MediaType media_type) {
1489 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1490
1491 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1492 AudioTrackInterface* audio_track =
1493 remote_stream_factory_->AddAudioTrack(stream, track_id);
1494 CreateAudioReceiver(stream, audio_track, ssrc);
1495 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1496 VideoTrackInterface* video_track =
1497 remote_stream_factory_->AddVideoTrack(stream, track_id);
1498 CreateVideoReceiver(stream, video_track, ssrc);
1499 } else {
1500 RTC_DCHECK(false && "Invalid media type");
1501 }
1502}
1503
1504void PeerConnection::OnRemoteTrackRemoved(const std::string& stream_label,
1505 const std::string& track_id,
1506 cricket::MediaType media_type) {
1507 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1508
1509 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1510 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1511 stream->FindAudioTrack(track_id);
1512 if (audio_track) {
1513 audio_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1514 stream->RemoveTrack(audio_track);
1515 DestroyAudioReceiver(stream, audio_track);
1516 }
1517 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1518 rtc::scoped_refptr<VideoTrackInterface> video_track =
1519 stream->FindVideoTrack(track_id);
1520 if (video_track) {
1521 video_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1522 stream->RemoveTrack(video_track);
1523 DestroyVideoReceiver(stream, video_track);
1524 }
1525 } else {
1526 ASSERT(false && "Invalid media type");
1527 }
1528}
1529
1530void PeerConnection::UpdateEndedRemoteMediaStreams() {
1531 std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams_to_remove;
1532 for (size_t i = 0; i < remote_streams_->count(); ++i) {
1533 MediaStreamInterface* stream = remote_streams_->at(i);
1534 if (stream->GetAudioTracks().empty() && stream->GetVideoTracks().empty()) {
1535 streams_to_remove.push_back(stream);
1536 }
1537 }
1538
1539 for (const auto& stream : streams_to_remove) {
1540 remote_streams_->RemoveStream(stream);
1541 observer_->OnRemoveStream(stream);
1542 }
1543}
1544
1545void PeerConnection::MaybeCreateDefaultStream() {
1546 if (!remote_info_.IsDefaultMediaStreamNeeded()) {
1547 return;
1548 }
1549
1550 bool default_created = false;
1551
1552 rtc::scoped_refptr<MediaStreamInterface> default_remote_stream =
1553 remote_streams_->find(kDefaultStreamLabel);
1554 if (default_remote_stream == nullptr) {
1555 default_created = true;
1556 default_remote_stream =
1557 remote_stream_factory_->CreateMediaStream(kDefaultStreamLabel);
1558 remote_streams_->AddStream(default_remote_stream);
1559 }
1560 if (remote_info_.default_audio_track_needed &&
1561 default_remote_stream->GetAudioTracks().size() == 0) {
1562 remote_audio_tracks_.push_back(
1563 TrackInfo(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0));
1564 OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0,
1565 cricket::MEDIA_TYPE_AUDIO);
1566 }
1567 if (remote_info_.default_video_track_needed &&
1568 default_remote_stream->GetVideoTracks().size() == 0) {
1569 remote_video_tracks_.push_back(
1570 TrackInfo(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0));
1571 OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0,
1572 cricket::MEDIA_TYPE_VIDEO);
1573 }
1574 if (default_created) {
1575 stats_->AddStream(default_remote_stream);
1576 observer_->OnAddStream(default_remote_stream);
1577 }
1578}
1579
1580void PeerConnection::EndRemoteTracks(cricket::MediaType media_type) {
1581 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1582 for (TrackInfos::iterator track_it = current_tracks->begin();
1583 track_it != current_tracks->end(); ++track_it) {
1584 const TrackInfo& info = *track_it;
1585 MediaStreamInterface* stream = remote_streams_->find(info.stream_label);
1586 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1587 AudioTrackInterface* track = stream->FindAudioTrack(info.track_id);
1588 // There's no guarantee the track is still available, e.g. the track may
1589 // have been removed from the stream by javascript.
1590 if (track) {
1591 track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1592 }
1593 }
1594 if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1595 VideoTrackInterface* track = stream->FindVideoTrack(info.track_id);
1596 // There's no guarantee the track is still available, e.g. the track may
1597 // have been removed from the stream by javascript.
1598 if (track) {
1599 track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1600 }
1601 }
1602 }
1603}
1604
1605void PeerConnection::UpdateLocalTracks(
1606 const std::vector<cricket::StreamParams>& streams,
1607 cricket::MediaType media_type) {
1608 TrackInfos* current_tracks = GetLocalTracks(media_type);
1609
1610 // Find removed tracks. I.e., tracks where the track id, stream label or ssrc
1611 // don't match the new StreamParam.
1612 TrackInfos::iterator track_it = current_tracks->begin();
1613 while (track_it != current_tracks->end()) {
1614 const TrackInfo& info = *track_it;
1615 const cricket::StreamParams* params =
1616 cricket::GetStreamBySsrc(streams, info.ssrc);
1617 if (!params || params->id != info.track_id ||
1618 params->sync_label != info.stream_label) {
1619 OnLocalTrackRemoved(info.stream_label, info.track_id, info.ssrc,
1620 media_type);
1621 track_it = current_tracks->erase(track_it);
1622 } else {
1623 ++track_it;
1624 }
1625 }
1626
1627 // Find new and active tracks.
1628 for (const cricket::StreamParams& params : streams) {
1629 // The sync_label is the MediaStream label and the |stream.id| is the
1630 // track id.
1631 const std::string& stream_label = params.sync_label;
1632 const std::string& track_id = params.id;
1633 uint32_t ssrc = params.first_ssrc();
1634 const TrackInfo* track_info =
1635 FindTrackInfo(*current_tracks, stream_label, track_id);
1636 if (!track_info) {
1637 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1638 OnLocalTrackSeen(stream_label, track_id, params.first_ssrc(), media_type);
1639 }
1640 }
1641}
1642
1643void PeerConnection::OnLocalTrackSeen(const std::string& stream_label,
1644 const std::string& track_id,
1645 uint32_t ssrc,
1646 cricket::MediaType media_type) {
deadbeef8f46c632015-10-26 14:11:17 -07001647 MediaStreamInterface* stream = local_streams_->find(stream_label);
1648 if (!stream) {
1649 LOG(LS_WARNING) << "An unknown local MediaStream with label "
1650 << stream_label << " has been configured.";
deadbeefab9b2d12015-10-14 11:33:11 -07001651 return;
1652 }
1653
deadbeef8f46c632015-10-26 14:11:17 -07001654 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1655 AudioTrackInterface* audio_track = stream->FindAudioTrack(track_id);
1656 if (!audio_track) {
1657 LOG(LS_WARNING) << "An unknown local AudioTrack with id , " << track_id
1658 << " has been configured.";
1659 return;
1660 }
1661 CreateAudioSender(stream, audio_track, ssrc);
1662 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1663 VideoTrackInterface* video_track = stream->FindVideoTrack(track_id);
1664 if (!video_track) {
1665 LOG(LS_WARNING) << "An unknown local VideoTrack with id , " << track_id
1666 << " has been configured.";
1667 return;
1668 }
1669 CreateVideoSender(stream, video_track, ssrc);
1670 } else {
1671 RTC_DCHECK(false && "Invalid media type");
deadbeefab9b2d12015-10-14 11:33:11 -07001672 }
1673}
1674
1675void PeerConnection::OnLocalTrackRemoved(const std::string& stream_label,
1676 const std::string& track_id,
1677 uint32_t ssrc,
1678 cricket::MediaType media_type) {
deadbeef8f46c632015-10-26 14:11:17 -07001679 MediaStreamInterface* stream = local_streams_->find(stream_label);
1680 if (!stream) {
1681 // This is the normal case. I.e., RemoveLocalStream has been called and the
deadbeefab9b2d12015-10-14 11:33:11 -07001682 // SessionDescriptions has been renegotiated.
1683 return;
1684 }
deadbeef8f46c632015-10-26 14:11:17 -07001685 // A track has been removed from the SessionDescription but the MediaStream
1686 // is still associated with PeerConnection. This only occurs if the SDP
1687 // doesn't match with the calls to AddLocalStream and RemoveLocalStream.
1688 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1689 AudioTrackInterface* audio_track = stream->FindAudioTrack(track_id);
1690 if (!audio_track) {
1691 return;
1692 }
1693 DestroyAudioSender(stream, audio_track, ssrc);
1694 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1695 VideoTrackInterface* video_track = stream->FindVideoTrack(track_id);
1696 if (!video_track) {
1697 return;
1698 }
1699 DestroyVideoSender(stream, video_track);
1700 } else {
1701 RTC_DCHECK(false && "Invalid media type.");
deadbeefab9b2d12015-10-14 11:33:11 -07001702 }
1703}
1704
1705void PeerConnection::UpdateLocalRtpDataChannels(
1706 const cricket::StreamParamsVec& streams) {
1707 std::vector<std::string> existing_channels;
1708
1709 // Find new and active data channels.
1710 for (const cricket::StreamParams& params : streams) {
1711 // |it->sync_label| is actually the data channel label. The reason is that
1712 // we use the same naming of data channels as we do for
1713 // MediaStreams and Tracks.
1714 // For MediaStreams, the sync_label is the MediaStream label and the
1715 // track label is the same as |streamid|.
1716 const std::string& channel_label = params.sync_label;
1717 auto data_channel_it = rtp_data_channels_.find(channel_label);
1718 if (!VERIFY(data_channel_it != rtp_data_channels_.end())) {
1719 continue;
1720 }
1721 // Set the SSRC the data channel should use for sending.
1722 data_channel_it->second->SetSendSsrc(params.first_ssrc());
1723 existing_channels.push_back(data_channel_it->first);
1724 }
1725
1726 UpdateClosingRtpDataChannels(existing_channels, true);
1727}
1728
1729void PeerConnection::UpdateRemoteRtpDataChannels(
1730 const cricket::StreamParamsVec& streams) {
1731 std::vector<std::string> existing_channels;
1732
1733 // Find new and active data channels.
1734 for (const cricket::StreamParams& params : streams) {
1735 // The data channel label is either the mslabel or the SSRC if the mslabel
1736 // does not exist. Ex a=ssrc:444330170 mslabel:test1.
1737 std::string label = params.sync_label.empty()
1738 ? rtc::ToString(params.first_ssrc())
1739 : params.sync_label;
1740 auto data_channel_it = rtp_data_channels_.find(label);
1741 if (data_channel_it == rtp_data_channels_.end()) {
1742 // This is a new data channel.
1743 CreateRemoteRtpDataChannel(label, params.first_ssrc());
1744 } else {
1745 data_channel_it->second->SetReceiveSsrc(params.first_ssrc());
1746 }
1747 existing_channels.push_back(label);
1748 }
1749
1750 UpdateClosingRtpDataChannels(existing_channels, false);
1751}
1752
1753void PeerConnection::UpdateClosingRtpDataChannels(
1754 const std::vector<std::string>& active_channels,
1755 bool is_local_update) {
1756 auto it = rtp_data_channels_.begin();
1757 while (it != rtp_data_channels_.end()) {
1758 DataChannel* data_channel = it->second;
1759 if (std::find(active_channels.begin(), active_channels.end(),
1760 data_channel->label()) != active_channels.end()) {
1761 ++it;
1762 continue;
1763 }
1764
1765 if (is_local_update) {
1766 data_channel->SetSendSsrc(0);
1767 } else {
1768 data_channel->RemotePeerRequestClose();
1769 }
1770
1771 if (data_channel->state() == DataChannel::kClosed) {
1772 rtp_data_channels_.erase(it);
1773 it = rtp_data_channels_.begin();
1774 } else {
1775 ++it;
1776 }
1777 }
1778}
1779
1780void PeerConnection::CreateRemoteRtpDataChannel(const std::string& label,
1781 uint32_t remote_ssrc) {
1782 rtc::scoped_refptr<DataChannel> channel(
1783 InternalCreateDataChannel(label, nullptr));
1784 if (!channel.get()) {
1785 LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
1786 << "CreateDataChannel failed.";
1787 return;
1788 }
1789 channel->SetReceiveSsrc(remote_ssrc);
1790 observer_->OnDataChannel(
1791 DataChannelProxy::Create(signaling_thread(), channel));
1792}
1793
1794rtc::scoped_refptr<DataChannel> PeerConnection::InternalCreateDataChannel(
1795 const std::string& label,
1796 const InternalDataChannelInit* config) {
1797 if (IsClosed()) {
1798 return nullptr;
1799 }
1800 if (session_->data_channel_type() == cricket::DCT_NONE) {
1801 LOG(LS_ERROR)
1802 << "InternalCreateDataChannel: Data is not supported in this call.";
1803 return nullptr;
1804 }
1805 InternalDataChannelInit new_config =
1806 config ? (*config) : InternalDataChannelInit();
1807 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1808 if (new_config.id < 0) {
1809 rtc::SSLRole role;
1810 if (session_->GetSslRole(&role) &&
1811 !sid_allocator_.AllocateSid(role, &new_config.id)) {
1812 LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel.";
1813 return nullptr;
1814 }
1815 } else if (!sid_allocator_.ReserveSid(new_config.id)) {
1816 LOG(LS_ERROR) << "Failed to create a SCTP data channel "
1817 << "because the id is already in use or out of range.";
1818 return nullptr;
1819 }
1820 }
1821
1822 rtc::scoped_refptr<DataChannel> channel(DataChannel::Create(
1823 session_.get(), session_->data_channel_type(), label, new_config));
1824 if (!channel) {
1825 sid_allocator_.ReleaseSid(new_config.id);
1826 return nullptr;
1827 }
1828
1829 if (channel->data_channel_type() == cricket::DCT_RTP) {
1830 if (rtp_data_channels_.find(channel->label()) != rtp_data_channels_.end()) {
1831 LOG(LS_ERROR) << "DataChannel with label " << channel->label()
1832 << " already exists.";
1833 return nullptr;
1834 }
1835 rtp_data_channels_[channel->label()] = channel;
1836 } else {
1837 RTC_DCHECK(channel->data_channel_type() == cricket::DCT_SCTP);
1838 sctp_data_channels_.push_back(channel);
1839 channel->SignalClosed.connect(this,
1840 &PeerConnection::OnSctpDataChannelClosed);
1841 }
1842
1843 return channel;
1844}
1845
1846bool PeerConnection::HasDataChannels() const {
1847 return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
1848}
1849
1850void PeerConnection::AllocateSctpSids(rtc::SSLRole role) {
1851 for (const auto& channel : sctp_data_channels_) {
1852 if (channel->id() < 0) {
1853 int sid;
1854 if (!sid_allocator_.AllocateSid(role, &sid)) {
1855 LOG(LS_ERROR) << "Failed to allocate SCTP sid.";
1856 continue;
1857 }
1858 channel->SetSctpSid(sid);
1859 }
1860 }
1861}
1862
1863void PeerConnection::OnSctpDataChannelClosed(DataChannel* channel) {
1864 for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end();
1865 ++it) {
1866 if (it->get() == channel) {
1867 if (channel->id() >= 0) {
1868 sid_allocator_.ReleaseSid(channel->id());
1869 }
1870 sctp_data_channels_.erase(it);
1871 return;
1872 }
1873 }
1874}
1875
1876void PeerConnection::OnVoiceChannelDestroyed() {
1877 EndRemoteTracks(cricket::MEDIA_TYPE_AUDIO);
1878}
1879
1880void PeerConnection::OnVideoChannelDestroyed() {
1881 EndRemoteTracks(cricket::MEDIA_TYPE_VIDEO);
1882}
1883
1884void PeerConnection::OnDataChannelCreated() {
1885 for (const auto& channel : sctp_data_channels_) {
1886 channel->OnTransportChannelCreated();
1887 }
1888}
1889
1890void PeerConnection::OnDataChannelDestroyed() {
1891 // Use a temporary copy of the RTP/SCTP DataChannel list because the
1892 // DataChannel may callback to us and try to modify the list.
1893 std::map<std::string, rtc::scoped_refptr<DataChannel>> temp_rtp_dcs;
1894 temp_rtp_dcs.swap(rtp_data_channels_);
1895 for (const auto& kv : temp_rtp_dcs) {
1896 kv.second->OnTransportChannelDestroyed();
1897 }
1898
1899 std::vector<rtc::scoped_refptr<DataChannel>> temp_sctp_dcs;
1900 temp_sctp_dcs.swap(sctp_data_channels_);
1901 for (const auto& channel : temp_sctp_dcs) {
1902 channel->OnTransportChannelDestroyed();
1903 }
1904}
1905
1906void PeerConnection::OnDataChannelOpenMessage(
1907 const std::string& label,
1908 const InternalDataChannelInit& config) {
1909 rtc::scoped_refptr<DataChannel> channel(
1910 InternalCreateDataChannel(label, &config));
1911 if (!channel.get()) {
1912 LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
1913 return;
1914 }
1915
1916 observer_->OnDataChannel(
1917 DataChannelProxy::Create(signaling_thread(), channel));
1918}
1919
deadbeef70ab1a12015-09-28 16:53:55 -07001920std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator
1921PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) {
1922 return std::find_if(
1923 senders_.begin(), senders_.end(),
1924 [track](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
1925 return sender->track() == track;
1926 });
1927}
1928
1929std::vector<rtc::scoped_refptr<RtpReceiverInterface>>::iterator
1930PeerConnection::FindReceiverForTrack(MediaStreamTrackInterface* track) {
1931 return std::find_if(
1932 receivers_.begin(), receivers_.end(),
1933 [track](const rtc::scoped_refptr<RtpReceiverInterface>& receiver) {
1934 return receiver->track() == track;
1935 });
1936}
1937
deadbeefab9b2d12015-10-14 11:33:11 -07001938PeerConnection::TrackInfos* PeerConnection::GetRemoteTracks(
1939 cricket::MediaType media_type) {
1940 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
1941 media_type == cricket::MEDIA_TYPE_VIDEO);
1942 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &remote_audio_tracks_
1943 : &remote_video_tracks_;
1944}
1945
1946PeerConnection::TrackInfos* PeerConnection::GetLocalTracks(
1947 cricket::MediaType media_type) {
1948 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
1949 media_type == cricket::MEDIA_TYPE_VIDEO);
1950 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &local_audio_tracks_
1951 : &local_video_tracks_;
1952}
1953
1954const PeerConnection::TrackInfo* PeerConnection::FindTrackInfo(
1955 const PeerConnection::TrackInfos& infos,
1956 const std::string& stream_label,
1957 const std::string track_id) const {
1958 for (const TrackInfo& track_info : infos) {
1959 if (track_info.stream_label == stream_label &&
1960 track_info.track_id == track_id) {
1961 return &track_info;
1962 }
1963 }
1964 return nullptr;
1965}
1966
1967DataChannel* PeerConnection::FindDataChannelBySid(int sid) const {
1968 for (const auto& channel : sctp_data_channels_) {
1969 if (channel->id() == sid) {
1970 return channel;
1971 }
1972 }
1973 return nullptr;
1974}
1975
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001976} // namespace webrtc