blob: 138da5b33a75b98fff5185ce455b06e6b6bf5816 [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.org269fb4b2014-10-28 22:20:11 +000049#include "webrtc/p2p/client/basicportallocator.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000050#include "talk/session/media/channelmanager.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"
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +000054#include "webrtc/system_wrappers/interface/field_trial.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000055
56namespace {
57
deadbeefab9b2d12015-10-14 11:33:11 -070058using webrtc::DataChannel;
59using webrtc::MediaConstraintsInterface;
60using webrtc::MediaStreamInterface;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000061using webrtc::PeerConnectionInterface;
deadbeefac9d92c2015-10-26 11:48:22 -070062using webrtc::RtpSenderInterface;
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};
deadbeef0a6c4ca2015-10-06 11:38:28 -070099static_assert(INVALID == ARRAY_SIZE(kValidIceServiceTypes),
100 "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;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000160 for (size_t i = 0; i < ARRAY_SIZE(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|.
deadbeefac9d92c2015-10-26 11:48:22 -0700369void AddSendStreams(
370 cricket::MediaSessionOptions* session_options,
371 const std::vector<rtc::scoped_refptr<RtpSenderInterface>>& senders,
372 const std::map<std::string, rtc::scoped_refptr<DataChannel>>&
373 rtp_data_channels) {
deadbeefab9b2d12015-10-14 11:33:11 -0700374 session_options->streams.clear();
deadbeefac9d92c2015-10-26 11:48:22 -0700375 for (const auto& sender : senders) {
376 session_options->AddSendStream(sender->media_type(), sender->id(),
377 sender->stream_id());
deadbeefab9b2d12015-10-14 11:33:11 -0700378 }
379
380 // Check for data channels.
381 for (const auto& kv : rtp_data_channels) {
382 const DataChannel* channel = kv.second;
383 if (channel->state() == DataChannel::kConnecting ||
384 channel->state() == DataChannel::kOpen) {
385 // |streamid| and |sync_label| are both set to the DataChannel label
386 // here so they can be signaled the same way as MediaStreams and Tracks.
387 // For MediaStreams, the sync_label is the MediaStream label and the
388 // track label is the same as |streamid|.
389 const std::string& streamid = channel->label();
390 const std::string& sync_label = channel->label();
391 session_options->AddSendStream(cricket::MEDIA_TYPE_DATA, streamid,
392 sync_label);
393 }
394 }
395}
396
deadbeef0a6c4ca2015-10-06 11:38:28 -0700397} // namespace
398
399namespace webrtc {
400
deadbeefab9b2d12015-10-14 11:33:11 -0700401// Factory class for creating remote MediaStreams and MediaStreamTracks.
402class RemoteMediaStreamFactory {
403 public:
404 explicit RemoteMediaStreamFactory(rtc::Thread* signaling_thread,
405 cricket::ChannelManager* channel_manager)
406 : signaling_thread_(signaling_thread),
407 channel_manager_(channel_manager) {}
408
409 rtc::scoped_refptr<MediaStreamInterface> CreateMediaStream(
410 const std::string& stream_label) {
411 return MediaStreamProxy::Create(signaling_thread_,
412 MediaStream::Create(stream_label));
413 }
414
415 AudioTrackInterface* AddAudioTrack(webrtc::MediaStreamInterface* stream,
416 const std::string& track_id) {
417 return AddTrack<AudioTrackInterface, AudioTrack, AudioTrackProxy>(
418 stream, track_id, RemoteAudioSource::Create().get());
419 }
420
421 VideoTrackInterface* AddVideoTrack(webrtc::MediaStreamInterface* stream,
422 const std::string& track_id) {
423 return AddTrack<VideoTrackInterface, VideoTrack, VideoTrackProxy>(
424 stream, track_id,
425 VideoSource::Create(channel_manager_, new RemoteVideoCapturer(),
426 nullptr)
427 .get());
428 }
429
430 private:
431 template <typename TI, typename T, typename TP, typename S>
432 TI* AddTrack(MediaStreamInterface* stream,
433 const std::string& track_id,
434 S* source) {
435 rtc::scoped_refptr<TI> track(
436 TP::Create(signaling_thread_, T::Create(track_id, source)));
437 track->set_state(webrtc::MediaStreamTrackInterface::kLive);
438 if (stream->AddTrack(track)) {
439 return track;
440 }
441 return nullptr;
442 }
443
444 rtc::Thread* signaling_thread_;
445 cricket::ChannelManager* channel_manager_;
446};
447
448bool ConvertRtcOptionsForOffer(
449 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
450 cricket::MediaSessionOptions* session_options) {
451 typedef PeerConnectionInterface::RTCOfferAnswerOptions RTCOfferAnswerOptions;
452 if (!IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_audio) ||
453 !IsValidOfferToReceiveMedia(rtc_options.offer_to_receive_video)) {
454 return false;
455 }
456
deadbeefc80741f2015-10-22 13:14:45 -0700457 if (rtc_options.offer_to_receive_audio != RTCOfferAnswerOptions::kUndefined) {
deadbeefab9b2d12015-10-14 11:33:11 -0700458 session_options->recv_audio = (rtc_options.offer_to_receive_audio > 0);
459 }
deadbeefc80741f2015-10-22 13:14:45 -0700460 if (rtc_options.offer_to_receive_video != RTCOfferAnswerOptions::kUndefined) {
deadbeefab9b2d12015-10-14 11:33:11 -0700461 session_options->recv_video = (rtc_options.offer_to_receive_video > 0);
462 }
463
464 session_options->vad_enabled = rtc_options.voice_activity_detection;
465 session_options->transport_options.ice_restart = rtc_options.ice_restart;
deadbeefc80741f2015-10-22 13:14:45 -0700466 session_options->bundle_enabled = rtc_options.use_rtp_mux;
deadbeefab9b2d12015-10-14 11:33:11 -0700467
468 return true;
469}
470
471bool ParseConstraintsForAnswer(const MediaConstraintsInterface* constraints,
472 cricket::MediaSessionOptions* session_options) {
473 bool value = false;
474 size_t mandatory_constraints_satisfied = 0;
475
476 // kOfferToReceiveAudio defaults to true according to spec.
477 if (!FindConstraint(constraints,
478 MediaConstraintsInterface::kOfferToReceiveAudio, &value,
479 &mandatory_constraints_satisfied) ||
480 value) {
481 session_options->recv_audio = true;
482 }
483
484 // kOfferToReceiveVideo defaults to false according to spec. But
485 // if it is an answer and video is offered, we should still accept video
486 // per default.
487 value = false;
488 if (!FindConstraint(constraints,
489 MediaConstraintsInterface::kOfferToReceiveVideo, &value,
490 &mandatory_constraints_satisfied) ||
491 value) {
492 session_options->recv_video = true;
493 }
494
495 if (FindConstraint(constraints,
496 MediaConstraintsInterface::kVoiceActivityDetection, &value,
497 &mandatory_constraints_satisfied)) {
498 session_options->vad_enabled = value;
499 }
500
501 if (FindConstraint(constraints, MediaConstraintsInterface::kUseRtpMux, &value,
502 &mandatory_constraints_satisfied)) {
503 session_options->bundle_enabled = value;
504 } else {
505 // kUseRtpMux defaults to true according to spec.
506 session_options->bundle_enabled = true;
507 }
deadbeefab9b2d12015-10-14 11:33:11 -0700508
509 if (FindConstraint(constraints, MediaConstraintsInterface::kIceRestart,
510 &value, &mandatory_constraints_satisfied)) {
511 session_options->transport_options.ice_restart = value;
512 } else {
513 // kIceRestart defaults to false according to spec.
514 session_options->transport_options.ice_restart = false;
515 }
516
517 if (!constraints) {
518 return true;
519 }
520 return mandatory_constraints_satisfied == constraints->GetMandatory().size();
521}
522
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200523bool ParseIceServers(const PeerConnectionInterface::IceServers& servers,
deadbeef0a6c4ca2015-10-06 11:38:28 -0700524 StunConfigurations* stun_config,
525 TurnConfigurations* turn_config) {
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200526 for (const webrtc::PeerConnectionInterface::IceServer& server : servers) {
527 if (!server.urls.empty()) {
528 for (const std::string& url : server.urls) {
Joachim Bauchd935f912015-05-29 22:14:21 +0200529 if (url.empty()) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700530 LOG(LS_ERROR) << "Empty uri.";
531 return false;
Joachim Bauchd935f912015-05-29 22:14:21 +0200532 }
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200533 if (!ParseIceServerUrl(server, url, stun_config, turn_config)) {
534 return false;
535 }
536 }
537 } else if (!server.uri.empty()) {
538 // Fallback to old .uri if new .urls isn't present.
539 if (!ParseIceServerUrl(server, server.uri, stun_config, turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000540 return false;
Joachim Bauch7c4e7452015-05-28 23:06:30 +0200541 }
542 } else {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700543 LOG(LS_ERROR) << "Empty uri.";
544 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000545 }
546 }
547 return true;
548}
549
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550PeerConnection::PeerConnection(PeerConnectionFactory* factory)
551 : factory_(factory),
552 observer_(NULL),
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000553 uma_observer_(NULL),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000554 signaling_state_(kStable),
555 ice_state_(kIceNew),
556 ice_connection_state_(kIceConnectionNew),
deadbeefab9b2d12015-10-14 11:33:11 -0700557 ice_gathering_state_(kIceGatheringNew),
558 local_streams_(StreamCollection::Create()),
559 remote_streams_(StreamCollection::Create()) {}
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000560
561PeerConnection::~PeerConnection() {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700562 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeef70ab1a12015-09-28 16:53:55 -0700563 // Need to detach RTP senders/receivers from WebRtcSession,
564 // since it's about to be destroyed.
565 for (const auto& sender : senders_) {
566 sender->Stop();
567 }
568 for (const auto& receiver : receivers_) {
569 receiver->Stop();
570 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000571}
572
573bool PeerConnection::Initialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000574 const PeerConnectionInterface::RTCConfiguration& configuration,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000575 const MediaConstraintsInterface* constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000576 PortAllocatorFactoryInterface* allocator_factory,
Henrik Boström5e56c592015-08-11 10:33:13 +0200577 rtc::scoped_ptr<DtlsIdentityStoreInterface> dtls_identity_store,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000578 PeerConnectionObserver* observer) {
deadbeefab9b2d12015-10-14 11:33:11 -0700579 RTC_DCHECK(observer != nullptr);
580 if (!observer) {
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000581 return false;
deadbeefab9b2d12015-10-14 11:33:11 -0700582 }
pthatcher@webrtc.org877ac762015-02-04 22:03:09 +0000583 observer_ = observer;
584
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000585 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
586 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000587 if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000588 return false;
589 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000590 port_allocator_.reset(
591 allocator_factory->CreatePortAllocator(stun_config, turn_config));
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000592
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000593 // To handle both internal and externally created port allocator, we will
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000594 // enable BUNDLE here.
braveyao@webrtc.org1732df62014-10-27 03:01:37 +0000595 int portallocator_flags = port_allocator_->flags();
Peter Thatcher7cbd1882015-09-17 18:54:52 -0700596 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET |
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000597 cricket::PORTALLOCATOR_ENABLE_IPV6;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000598 bool value;
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000599 // If IPv6 flag was specified, we'll not override it by experiment.
deadbeefab9b2d12015-10-14 11:33:11 -0700600 if (FindConstraint(constraints, MediaConstraintsInterface::kEnableIPv6,
601 &value, nullptr)) {
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000602 if (!value) {
603 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000604 }
guoweis@webrtc.org2c1bcea2014-09-23 16:23:02 +0000605 } else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default") ==
guoweis@webrtc.orgbbce5ef2015-03-05 04:38:29 +0000606 "Disabled") {
607 portallocator_flags &= ~(cricket::PORTALLOCATOR_ENABLE_IPV6);
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000608 }
609
Jiayang Liucac1b382015-04-30 12:35:24 -0700610 if (configuration.tcp_candidate_policy == kTcpCandidatePolicyDisabled) {
611 portallocator_flags |= cricket::PORTALLOCATOR_DISABLE_TCP;
612 LOG(LS_INFO) << "TCP candidates are disabled.";
613 }
614
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000615 port_allocator_->set_flags(portallocator_flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000616 // No step delay is used while allocating ports.
617 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
618
stefanc1aeaf02015-10-15 07:26:07 -0700619 media_controller_.reset(factory_->CreateMediaController());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000620
stefanc1aeaf02015-10-15 07:26:07 -0700621 remote_stream_factory_.reset(new RemoteMediaStreamFactory(
622 factory_->signaling_thread(), media_controller_->channel_manager()));
623
624 session_.reset(
625 new WebRtcSession(media_controller_.get(), factory_->signaling_thread(),
626 factory_->worker_thread(), port_allocator_.get()));
deadbeefab9b2d12015-10-14 11:33:11 -0700627 stats_.reset(new StatsCollector(this));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000628
629 // Initialize the WebRtcSession. It creates transport channels etc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000630 if (!session_->Initialize(factory_->options(), constraints,
deadbeefab9b2d12015-10-14 11:33:11 -0700631 dtls_identity_store.Pass(), configuration)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000632 return false;
deadbeefab9b2d12015-10-14 11:33:11 -0700633 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000634
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000635 // Register PeerConnection as receiver of local ice candidates.
636 // All the callbacks will be posted to the application from PeerConnection.
637 session_->RegisterIceObserver(this);
638 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
deadbeefab9b2d12015-10-14 11:33:11 -0700639 session_->SignalVoiceChannelDestroyed.connect(
640 this, &PeerConnection::OnVoiceChannelDestroyed);
641 session_->SignalVideoChannelDestroyed.connect(
642 this, &PeerConnection::OnVideoChannelDestroyed);
643 session_->SignalDataChannelCreated.connect(
644 this, &PeerConnection::OnDataChannelCreated);
645 session_->SignalDataChannelDestroyed.connect(
646 this, &PeerConnection::OnDataChannelDestroyed);
647 session_->SignalDataChannelOpenMessage.connect(
648 this, &PeerConnection::OnDataChannelOpenMessage);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000649 return true;
650}
651
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000652rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000653PeerConnection::local_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -0700654 return local_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000655}
656
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000657rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000658PeerConnection::remote_streams() {
deadbeefab9b2d12015-10-14 11:33:11 -0700659 return remote_streams_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000660}
661
perkj@webrtc.orgc2dd5ee2014-11-04 11:31:29 +0000662bool PeerConnection::AddStream(MediaStreamInterface* local_stream) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000663 if (IsClosed()) {
664 return false;
665 }
deadbeefab9b2d12015-10-14 11:33:11 -0700666 if (!CanAddLocalMediaStream(local_streams_, local_stream)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000667 return false;
668 }
deadbeefab9b2d12015-10-14 11:33:11 -0700669
670 local_streams_->AddStream(local_stream);
671
deadbeefab9b2d12015-10-14 11:33:11 -0700672 for (const auto& track : local_stream->GetAudioTracks()) {
deadbeefac9d92c2015-10-26 11:48:22 -0700673 auto sender = FindSenderForTrack(track.get());
674 if (sender == senders_.end()) {
675 // Normal case; we've never seen this track before.
676 AudioRtpSender* new_sender = new AudioRtpSender(
677 track.get(), local_stream->label(), session_.get(), stats_.get());
678 senders_.push_back(new_sender);
679 // If the sender has already been configured in SDP, we call SetSsrc,
680 // which will connect the sender to the underlying transport. This can
681 // occur if a local session description that contains the ID of the sender
682 // is set before AddStream is called. It can also occur if the local
683 // session description is not changed and RemoveStream is called, and
684 // later AddStream is called again with the same stream.
685 const TrackInfo* track_info = FindTrackInfo(
686 local_audio_tracks_, local_stream->label(), track->id());
687 if (track_info) {
688 new_sender->SetSsrc(track_info->ssrc);
689 }
690 } else {
691 // We already have a sender for this track, so just change the stream_id
692 // so that it's correct in the next call to CreateOffer.
693 (*sender)->set_stream_id(local_stream->label());
deadbeefab9b2d12015-10-14 11:33:11 -0700694 }
695 }
696 for (const auto& track : local_stream->GetVideoTracks()) {
deadbeefac9d92c2015-10-26 11:48:22 -0700697 auto sender = FindSenderForTrack(track.get());
698 if (sender == senders_.end()) {
699 // Normal case; we've never seen this track before.
700 VideoRtpSender* new_sender = new VideoRtpSender(
701 track.get(), local_stream->label(), session_.get());
702 senders_.push_back(new_sender);
703 const TrackInfo* track_info = FindTrackInfo(
704 local_video_tracks_, local_stream->label(), track->id());
705 if (track_info) {
706 new_sender->SetSsrc(track_info->ssrc);
707 }
708 } else {
709 // We already have a sender for this track, so just change the stream_id
710 // so that it's correct in the next call to CreateOffer.
711 (*sender)->set_stream_id(local_stream->label());
deadbeefab9b2d12015-10-14 11:33:11 -0700712 }
713 }
714
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000715 stats_->AddStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000716 observer_->OnRenegotiationNeeded();
717 return true;
718}
719
deadbeefab9b2d12015-10-14 11:33:11 -0700720// TODO(deadbeef): Don't destroy RtpSenders here; they should be kept around
deadbeefac9d92c2015-10-26 11:48:22 -0700721// indefinitely, when we have unified plan SDP.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000722void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
deadbeefab9b2d12015-10-14 11:33:11 -0700723 for (const auto& track : local_stream->GetAudioTracks()) {
deadbeefac9d92c2015-10-26 11:48:22 -0700724 auto sender = FindSenderForTrack(track.get());
725 if (sender == senders_.end()) {
726 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
727 << " doesn't exist.";
728 continue;
deadbeefab9b2d12015-10-14 11:33:11 -0700729 }
deadbeefac9d92c2015-10-26 11:48:22 -0700730 (*sender)->Stop();
731 senders_.erase(sender);
deadbeefab9b2d12015-10-14 11:33:11 -0700732 }
733 for (const auto& track : local_stream->GetVideoTracks()) {
deadbeefac9d92c2015-10-26 11:48:22 -0700734 auto sender = FindSenderForTrack(track.get());
735 if (sender == senders_.end()) {
736 LOG(LS_WARNING) << "RtpSender for track with id " << track->id()
737 << " doesn't exist.";
738 continue;
deadbeefab9b2d12015-10-14 11:33:11 -0700739 }
deadbeefac9d92c2015-10-26 11:48:22 -0700740 (*sender)->Stop();
741 senders_.erase(sender);
deadbeefab9b2d12015-10-14 11:33:11 -0700742 }
743
744 local_streams_->RemoveStream(local_stream);
745
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000746 if (IsClosed()) {
747 return;
748 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000749 observer_->OnRenegotiationNeeded();
750}
751
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000752rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000753 AudioTrackInterface* track) {
754 if (!track) {
755 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
756 return NULL;
757 }
deadbeefab9b2d12015-10-14 11:33:11 -0700758 if (!local_streams_->FindAudioTrack(track->id())) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000759 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
760 return NULL;
761 }
762
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000763 rtc::scoped_refptr<DtmfSenderInterface> sender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000764 DtmfSender::Create(track, signaling_thread(), session_.get()));
765 if (!sender.get()) {
766 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
767 return NULL;
768 }
769 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
770}
771
deadbeefac9d92c2015-10-26 11:48:22 -0700772rtc::scoped_refptr<RtpSenderInterface> PeerConnection::CreateSender(
773 const std::string& kind) {
774 RtpSenderInterface* new_sender;
775 if (kind == MediaStreamTrackInterface::kAudioTrackKind) {
776 new_sender = new AudioRtpSender(session_.get(), stats_.get());
777 } else if (kind == MediaStreamTrackInterface::kVideoTrackKind) {
778 new_sender = new VideoRtpSender(session_.get());
779 } else {
780 LOG(LS_ERROR) << "CreateSender called with invalid kind: " << kind;
781 return rtc::scoped_refptr<RtpSenderInterface>();
782 }
783 senders_.push_back(new_sender);
784 return RtpSenderProxy::Create(signaling_thread(), new_sender);
785}
786
deadbeef70ab1a12015-09-28 16:53:55 -0700787std::vector<rtc::scoped_refptr<RtpSenderInterface>> PeerConnection::GetSenders()
788 const {
789 std::vector<rtc::scoped_refptr<RtpSenderInterface>> senders;
790 for (const auto& sender : senders_) {
791 senders.push_back(RtpSenderProxy::Create(signaling_thread(), sender.get()));
792 }
793 return senders;
794}
795
796std::vector<rtc::scoped_refptr<RtpReceiverInterface>>
797PeerConnection::GetReceivers() const {
798 std::vector<rtc::scoped_refptr<RtpReceiverInterface>> receivers;
799 for (const auto& receiver : receivers_) {
800 receivers.push_back(
801 RtpReceiverProxy::Create(signaling_thread(), receiver.get()));
802 }
803 return receivers;
804}
805
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000806bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000807 MediaStreamTrackInterface* track,
808 StatsOutputLevel level) {
deadbeef0a6c4ca2015-10-06 11:38:28 -0700809 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000810 if (!VERIFY(observer != NULL)) {
811 LOG(LS_ERROR) << "GetStats - observer is NULL.";
812 return false;
813 }
814
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000815 stats_->UpdateStats(level);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000816 signaling_thread()->Post(this, MSG_GETSTATS,
817 new GetStatsMsg(observer, track));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000818 return true;
819}
820
821PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
822 return signaling_state_;
823}
824
825PeerConnectionInterface::IceState PeerConnection::ice_state() {
826 return ice_state_;
827}
828
829PeerConnectionInterface::IceConnectionState
830PeerConnection::ice_connection_state() {
831 return ice_connection_state_;
832}
833
834PeerConnectionInterface::IceGatheringState
835PeerConnection::ice_gathering_state() {
836 return ice_gathering_state_;
837}
838
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000839rtc::scoped_refptr<DataChannelInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000840PeerConnection::CreateDataChannel(
841 const std::string& label,
842 const DataChannelInit* config) {
deadbeefab9b2d12015-10-14 11:33:11 -0700843 bool first_datachannel = !HasDataChannels();
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000844
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000845 rtc::scoped_ptr<InternalDataChannelInit> internal_config;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000846 if (config) {
847 internal_config.reset(new InternalDataChannelInit(*config));
848 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000849 rtc::scoped_refptr<DataChannelInterface> channel(
deadbeefab9b2d12015-10-14 11:33:11 -0700850 InternalCreateDataChannel(label, internal_config.get()));
851 if (!channel.get()) {
852 return nullptr;
853 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000854
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000855 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
856 // the first SCTP DataChannel.
857 if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
858 observer_->OnRenegotiationNeeded();
859 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000860
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000861 return DataChannelProxy::Create(signaling_thread(), channel.get());
862}
863
864void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
865 const MediaConstraintsInterface* constraints) {
deadbeefab9b2d12015-10-14 11:33:11 -0700866 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000867 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
868 return;
869 }
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000870 RTCOfferAnswerOptions options;
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000871
872 bool value;
873 size_t mandatory_constraints = 0;
874
875 if (FindConstraint(constraints,
876 MediaConstraintsInterface::kOfferToReceiveAudio,
877 &value,
878 &mandatory_constraints)) {
879 options.offer_to_receive_audio =
880 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
881 }
882
883 if (FindConstraint(constraints,
884 MediaConstraintsInterface::kOfferToReceiveVideo,
885 &value,
886 &mandatory_constraints)) {
887 options.offer_to_receive_video =
888 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
889 }
890
891 if (FindConstraint(constraints,
892 MediaConstraintsInterface::kVoiceActivityDetection,
893 &value,
894 &mandatory_constraints)) {
895 options.voice_activity_detection = value;
896 }
897
898 if (FindConstraint(constraints,
899 MediaConstraintsInterface::kIceRestart,
900 &value,
901 &mandatory_constraints)) {
902 options.ice_restart = value;
903 }
904
905 if (FindConstraint(constraints,
906 MediaConstraintsInterface::kUseRtpMux,
907 &value,
908 &mandatory_constraints)) {
909 options.use_rtp_mux = value;
910 }
911
912 CreateOffer(observer, options);
913}
914
915void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
916 const RTCOfferAnswerOptions& options) {
deadbeefab9b2d12015-10-14 11:33:11 -0700917 if (!VERIFY(observer != nullptr)) {
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000918 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
919 return;
920 }
deadbeefab9b2d12015-10-14 11:33:11 -0700921
922 cricket::MediaSessionOptions session_options;
923 if (!GetOptionsForOffer(options, &session_options)) {
924 std::string error = "CreateOffer called with invalid options.";
925 LOG(LS_ERROR) << error;
926 PostCreateSessionDescriptionFailure(observer, error);
927 return;
928 }
929
930 session_->CreateOffer(observer, options, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000931}
932
933void PeerConnection::CreateAnswer(
934 CreateSessionDescriptionObserver* observer,
935 const MediaConstraintsInterface* constraints) {
deadbeefab9b2d12015-10-14 11:33:11 -0700936 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000937 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
938 return;
939 }
deadbeefab9b2d12015-10-14 11:33:11 -0700940
941 cricket::MediaSessionOptions session_options;
942 if (!GetOptionsForAnswer(constraints, &session_options)) {
943 std::string error = "CreateAnswer called with invalid constraints.";
944 LOG(LS_ERROR) << error;
945 PostCreateSessionDescriptionFailure(observer, error);
946 return;
947 }
948
949 session_->CreateAnswer(observer, constraints, session_options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000950}
951
952void PeerConnection::SetLocalDescription(
953 SetSessionDescriptionObserver* observer,
954 SessionDescriptionInterface* desc) {
deadbeefab9b2d12015-10-14 11:33:11 -0700955 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000956 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
957 return;
958 }
959 if (!desc) {
960 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
961 return;
962 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000963 // Update stats here so that we have the most recent stats for tracks and
964 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000965 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000966 std::string error;
967 if (!session_->SetLocalDescription(desc, &error)) {
968 PostSetSessionDescriptionFailure(observer, error);
969 return;
970 }
deadbeefab9b2d12015-10-14 11:33:11 -0700971
972 // If setting the description decided our SSL role, allocate any necessary
973 // SCTP sids.
974 rtc::SSLRole role;
975 if (session_->data_channel_type() == cricket::DCT_SCTP &&
976 session_->GetSslRole(&role)) {
977 AllocateSctpSids(role);
978 }
979
980 // Update state and SSRC of local MediaStreams and DataChannels based on the
981 // local session description.
982 const cricket::ContentInfo* audio_content =
983 GetFirstAudioContent(desc->description());
984 if (audio_content) {
985 const cricket::AudioContentDescription* audio_desc =
986 static_cast<const cricket::AudioContentDescription*>(
987 audio_content->description);
988 UpdateLocalTracks(audio_desc->streams(), audio_desc->type());
989 }
990
991 const cricket::ContentInfo* video_content =
992 GetFirstVideoContent(desc->description());
993 if (video_content) {
994 const cricket::VideoContentDescription* video_desc =
995 static_cast<const cricket::VideoContentDescription*>(
996 video_content->description);
997 UpdateLocalTracks(video_desc->streams(), video_desc->type());
998 }
999
1000 const cricket::ContentInfo* data_content =
1001 GetFirstDataContent(desc->description());
1002 if (data_content) {
1003 const cricket::DataContentDescription* data_desc =
1004 static_cast<const cricket::DataContentDescription*>(
1005 data_content->description);
1006 if (rtc::starts_with(data_desc->protocol().data(),
1007 cricket::kMediaProtocolRtpPrefix)) {
1008 UpdateLocalRtpDataChannels(data_desc->streams());
1009 }
1010 }
1011
1012 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001013 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeefab9b2d12015-10-14 11:33:11 -07001014
deadbeefcbecd352015-09-23 11:50:27 -07001015 // MaybeStartGathering needs to be called after posting
1016 // MSG_SET_SESSIONDESCRIPTION_SUCCESS, so that we don't signal any candidates
1017 // before signaling that SetLocalDescription completed.
1018 session_->MaybeStartGathering();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001019}
1020
1021void PeerConnection::SetRemoteDescription(
1022 SetSessionDescriptionObserver* observer,
1023 SessionDescriptionInterface* desc) {
deadbeefab9b2d12015-10-14 11:33:11 -07001024 if (!VERIFY(observer != nullptr)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001025 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
1026 return;
1027 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001028 if (!desc) {
1029 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
1030 return;
1031 }
1032 // Update stats here so that we have the most recent stats for tracks and
1033 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001034 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001035 std::string error;
1036 if (!session_->SetRemoteDescription(desc, &error)) {
1037 PostSetSessionDescriptionFailure(observer, error);
1038 return;
1039 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001040
deadbeefab9b2d12015-10-14 11:33:11 -07001041 // If setting the description decided our SSL role, allocate any necessary
1042 // SCTP sids.
1043 rtc::SSLRole role;
1044 if (session_->data_channel_type() == cricket::DCT_SCTP &&
1045 session_->GetSslRole(&role)) {
1046 AllocateSctpSids(role);
1047 }
1048
1049 const cricket::SessionDescription* remote_desc = desc->description();
1050
1051 // We wait to signal new streams until we finish processing the description,
1052 // since only at that point will new streams have all their tracks.
1053 rtc::scoped_refptr<StreamCollection> new_streams(StreamCollection::Create());
1054
1055 // Find all audio rtp streams and create corresponding remote AudioTracks
1056 // and MediaStreams.
1057 const cricket::ContentInfo* audio_content = GetFirstAudioContent(remote_desc);
1058 if (audio_content) {
1059 const cricket::AudioContentDescription* desc =
1060 static_cast<const cricket::AudioContentDescription*>(
1061 audio_content->description);
deadbeef5e97fb52015-10-15 12:49:08 -07001062 UpdateRemoteStreamsList(GetActiveStreams(desc), desc->type(), new_streams);
deadbeefab9b2d12015-10-14 11:33:11 -07001063 remote_info_.default_audio_track_needed =
deadbeefc80741f2015-10-22 13:14:45 -07001064 !remote_desc->msid_supported() && desc->streams().empty() &&
1065 MediaContentDirectionHasSend(desc->direction());
deadbeefab9b2d12015-10-14 11:33:11 -07001066 }
1067
1068 // Find all video rtp streams and create corresponding remote VideoTracks
1069 // and MediaStreams.
1070 const cricket::ContentInfo* video_content = GetFirstVideoContent(remote_desc);
1071 if (video_content) {
1072 const cricket::VideoContentDescription* desc =
1073 static_cast<const cricket::VideoContentDescription*>(
1074 video_content->description);
deadbeef5e97fb52015-10-15 12:49:08 -07001075 UpdateRemoteStreamsList(GetActiveStreams(desc), desc->type(), new_streams);
deadbeefab9b2d12015-10-14 11:33:11 -07001076 remote_info_.default_video_track_needed =
deadbeefc80741f2015-10-22 13:14:45 -07001077 !remote_desc->msid_supported() && desc->streams().empty() &&
1078 MediaContentDirectionHasSend(desc->direction());
deadbeefab9b2d12015-10-14 11:33:11 -07001079 }
1080
1081 // Update the DataChannels with the information from the remote peer.
1082 const cricket::ContentInfo* data_content = GetFirstDataContent(remote_desc);
1083 if (data_content) {
deadbeef5e97fb52015-10-15 12:49:08 -07001084 const cricket::DataContentDescription* desc =
deadbeefab9b2d12015-10-14 11:33:11 -07001085 static_cast<const cricket::DataContentDescription*>(
1086 data_content->description);
deadbeef5e97fb52015-10-15 12:49:08 -07001087 if (rtc::starts_with(desc->protocol().data(),
deadbeefab9b2d12015-10-14 11:33:11 -07001088 cricket::kMediaProtocolRtpPrefix)) {
deadbeef5e97fb52015-10-15 12:49:08 -07001089 UpdateRemoteRtpDataChannels(GetActiveStreams(desc));
deadbeefab9b2d12015-10-14 11:33:11 -07001090 }
1091 }
1092
1093 // Iterate new_streams and notify the observer about new MediaStreams.
1094 for (size_t i = 0; i < new_streams->count(); ++i) {
1095 MediaStreamInterface* new_stream = new_streams->at(i);
1096 stats_->AddStream(new_stream);
1097 observer_->OnAddStream(new_stream);
1098 }
1099
1100 // Find removed MediaStreams.
1101 if (remote_info_.IsDefaultMediaStreamNeeded() &&
1102 remote_streams_->find(kDefaultStreamLabel) != nullptr) {
1103 // The default media stream already exists. No need to do anything.
1104 } else {
1105 UpdateEndedRemoteMediaStreams();
1106 remote_info_.msid_supported |= remote_streams_->count() > 0;
1107 }
1108 MaybeCreateDefaultStream();
1109
1110 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1111 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
deadbeeffc648b62015-10-13 16:42:33 -07001112}
1113
deadbeefa67696b2015-09-29 11:56:26 -07001114bool PeerConnection::SetConfiguration(const RTCConfiguration& config) {
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001115 if (port_allocator_) {
1116 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
1117 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
1118 if (!ParseIceServers(config.servers, &stuns, &turns)) {
1119 return false;
1120 }
1121
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001122 std::vector<rtc::SocketAddress> stun_hosts;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001123 typedef std::vector<StunConfiguration>::const_iterator StunIt;
1124 for (StunIt stun_it = stuns.begin(); stun_it != stuns.end(); ++stun_it) {
1125 stun_hosts.push_back(stun_it->server);
1126 }
1127
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001128 rtc::SocketAddress stun_addr;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001129 if (!stun_hosts.empty()) {
1130 stun_addr = stun_hosts.front();
deadbeefa67696b2015-09-29 11:56:26 -07001131 LOG(LS_INFO) << "SetConfiguration: StunServer Address: "
1132 << stun_addr.ToString();
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001133 }
1134
1135 for (size_t i = 0; i < turns.size(); ++i) {
1136 cricket::RelayCredentials credentials(turns[i].username,
1137 turns[i].password);
1138 cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
1139 cricket::ProtocolType protocol;
1140 if (cricket::StringToProto(turns[i].transport_type.c_str(), &protocol)) {
1141 relay_server.ports.push_back(cricket::ProtocolAddress(
1142 turns[i].server, protocol, turns[i].secure));
1143 relay_server.credentials = credentials;
deadbeefa67696b2015-09-29 11:56:26 -07001144 LOG(LS_INFO) << "SetConfiguration: TurnServer Address: "
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001145 << turns[i].server.ToString();
1146 } else {
1147 LOG(LS_WARNING) << "Ignoring TURN server " << turns[i].server << ". "
1148 << "Reason= Incorrect " << turns[i].transport_type
1149 << " transport parameter.";
1150 }
1151 }
1152 }
honghaiz1f429e32015-09-28 07:57:34 -07001153 session_->SetIceConfig(session_->ParseIceConfig(config));
mallinath@webrtc.org3d81b1b2014-09-09 14:38:10 +00001154 return session_->SetIceTransports(config.type);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +00001155}
1156
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001157bool PeerConnection::AddIceCandidate(
1158 const IceCandidateInterface* ice_candidate) {
1159 return session_->ProcessIceMessage(ice_candidate);
1160}
1161
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001162void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
1163 uma_observer_ = observer;
guoweis@webrtc.org7169afd2014-12-04 17:59:29 +00001164
1165 if (session_) {
1166 session_->set_metrics_observer(uma_observer_);
1167 }
1168
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001169 // Send information about IPv4/IPv6 status.
1170 if (uma_observer_ && port_allocator_) {
1171 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001172 uma_observer_->IncrementEnumCounter(
1173 kEnumCounterAddressFamily, kPeerConnection_IPv6,
1174 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgb445f262014-05-23 22:19:37 +00001175 } else {
Guo-wei Shiehdfbe6792015-09-03 17:12:07 -07001176 uma_observer_->IncrementEnumCounter(
1177 kEnumCounterAddressFamily, kPeerConnection_IPv4,
1178 kPeerConnectionAddressFamilyCounter_Max);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +00001179 }
1180 }
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +00001181}
1182
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001183const SessionDescriptionInterface* PeerConnection::local_description() const {
1184 return session_->local_description();
1185}
1186
1187const SessionDescriptionInterface* PeerConnection::remote_description() const {
1188 return session_->remote_description();
1189}
1190
1191void PeerConnection::Close() {
1192 // Update stats here so that we have the most recent stats for tracks and
1193 // streams before the channels are closed.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +00001194 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001195
deadbeefd59daf82015-10-14 15:02:44 -07001196 session_->Close();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001197}
1198
deadbeefd59daf82015-10-14 15:02:44 -07001199void PeerConnection::OnSessionStateChange(WebRtcSession* /*session*/,
1200 WebRtcSession::State state) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001201 switch (state) {
deadbeefd59daf82015-10-14 15:02:44 -07001202 case WebRtcSession::STATE_INIT:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001203 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +00001204 break;
deadbeefd59daf82015-10-14 15:02:44 -07001205 case WebRtcSession::STATE_SENTOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001206 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
1207 break;
deadbeefd59daf82015-10-14 15:02:44 -07001208 case WebRtcSession::STATE_SENTPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001209 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
1210 break;
deadbeefd59daf82015-10-14 15:02:44 -07001211 case WebRtcSession::STATE_RECEIVEDOFFER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001212 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
1213 break;
deadbeefd59daf82015-10-14 15:02:44 -07001214 case WebRtcSession::STATE_RECEIVEDPRANSWER:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001215 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
1216 break;
deadbeefd59daf82015-10-14 15:02:44 -07001217 case WebRtcSession::STATE_INPROGRESS:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001218 ChangeSignalingState(PeerConnectionInterface::kStable);
1219 break;
deadbeefd59daf82015-10-14 15:02:44 -07001220 case WebRtcSession::STATE_CLOSED:
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001221 ChangeSignalingState(PeerConnectionInterface::kClosed);
1222 break;
1223 default:
1224 break;
1225 }
1226}
1227
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +00001228void PeerConnection::OnMessage(rtc::Message* msg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001229 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001230 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
1231 SetSessionDescriptionMsg* param =
1232 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1233 param->observer->OnSuccess();
1234 delete param;
1235 break;
1236 }
1237 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
1238 SetSessionDescriptionMsg* param =
1239 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
1240 param->observer->OnFailure(param->error);
1241 delete param;
1242 break;
1243 }
deadbeefab9b2d12015-10-14 11:33:11 -07001244 case MSG_CREATE_SESSIONDESCRIPTION_FAILED: {
1245 CreateSessionDescriptionMsg* param =
1246 static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
1247 param->observer->OnFailure(param->error);
1248 delete param;
1249 break;
1250 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001251 case MSG_GETSTATS: {
1252 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +00001253 StatsReports reports;
1254 stats_->GetStats(param->track, &reports);
1255 param->observer->OnComplete(reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001256 delete param;
1257 break;
1258 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001259 default:
deadbeef0a6c4ca2015-10-06 11:38:28 -07001260 RTC_DCHECK(false && "Not implemented");
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001261 break;
1262 }
1263}
1264
deadbeefab9b2d12015-10-14 11:33:11 -07001265void PeerConnection::CreateAudioReceiver(MediaStreamInterface* stream,
1266 AudioTrackInterface* audio_track,
1267 uint32_t ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -07001268 receivers_.push_back(new AudioRtpReceiver(audio_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001269}
1270
deadbeefab9b2d12015-10-14 11:33:11 -07001271void PeerConnection::CreateVideoReceiver(MediaStreamInterface* stream,
1272 VideoTrackInterface* video_track,
1273 uint32_t ssrc) {
deadbeef70ab1a12015-09-28 16:53:55 -07001274 receivers_.push_back(new VideoRtpReceiver(video_track, ssrc, session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001275}
1276
deadbeef70ab1a12015-09-28 16:53:55 -07001277// TODO(deadbeef): Keep RtpReceivers around even if track goes away in remote
1278// description.
deadbeefab9b2d12015-10-14 11:33:11 -07001279void PeerConnection::DestroyAudioReceiver(MediaStreamInterface* stream,
1280 AudioTrackInterface* audio_track) {
deadbeef70ab1a12015-09-28 16:53:55 -07001281 auto it = FindReceiverForTrack(audio_track);
1282 if (it == receivers_.end()) {
1283 LOG(LS_WARNING) << "RtpReceiver for track with id " << audio_track->id()
1284 << " doesn't exist.";
1285 } else {
1286 (*it)->Stop();
1287 receivers_.erase(it);
1288 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001289}
1290
deadbeefab9b2d12015-10-14 11:33:11 -07001291void PeerConnection::DestroyVideoReceiver(MediaStreamInterface* stream,
1292 VideoTrackInterface* video_track) {
deadbeef70ab1a12015-09-28 16:53:55 -07001293 auto it = FindReceiverForTrack(video_track);
1294 if (it == receivers_.end()) {
1295 LOG(LS_WARNING) << "RtpReceiver for track with id " << video_track->id()
1296 << " doesn't exist.";
1297 } else {
1298 (*it)->Stop();
1299 receivers_.erase(it);
1300 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001301}
deadbeef70ab1a12015-09-28 16:53:55 -07001302
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001303void PeerConnection::OnIceConnectionChange(
1304 PeerConnectionInterface::IceConnectionState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001305 RTC_DCHECK(signaling_thread()->IsCurrent());
deadbeefcbecd352015-09-23 11:50:27 -07001306 // After transitioning to "closed", ignore any additional states from
1307 // WebRtcSession (such as "disconnected").
deadbeefab9b2d12015-10-14 11:33:11 -07001308 if (IsClosed()) {
deadbeefcbecd352015-09-23 11:50:27 -07001309 return;
1310 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001311 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001312 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001313}
1314
1315void PeerConnection::OnIceGatheringChange(
1316 PeerConnectionInterface::IceGatheringState new_state) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001317 RTC_DCHECK(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001318 if (IsClosed()) {
1319 return;
1320 }
1321 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001322 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001323}
1324
1325void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001326 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001327 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001328}
1329
1330void PeerConnection::OnIceComplete() {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001331 RTC_DCHECK(signaling_thread()->IsCurrent());
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +00001332 observer_->OnIceComplete();
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001333}
1334
Peter Thatcher54360512015-07-08 11:08:35 -07001335void PeerConnection::OnIceConnectionReceivingChange(bool receiving) {
deadbeef0a6c4ca2015-10-06 11:38:28 -07001336 RTC_DCHECK(signaling_thread()->IsCurrent());
Peter Thatcher54360512015-07-08 11:08:35 -07001337 observer_->OnIceConnectionReceivingChange(receiving);
1338}
1339
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001340void PeerConnection::ChangeSignalingState(
1341 PeerConnectionInterface::SignalingState signaling_state) {
1342 signaling_state_ = signaling_state;
1343 if (signaling_state == kClosed) {
1344 ice_connection_state_ = kIceConnectionClosed;
1345 observer_->OnIceConnectionChange(ice_connection_state_);
1346 if (ice_gathering_state_ != kIceGatheringComplete) {
1347 ice_gathering_state_ = kIceGatheringComplete;
1348 observer_->OnIceGatheringChange(ice_gathering_state_);
1349 }
1350 }
1351 observer_->OnSignalingChange(signaling_state_);
1352 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
1353}
1354
deadbeefab9b2d12015-10-14 11:33:11 -07001355void PeerConnection::PostSetSessionDescriptionFailure(
1356 SetSessionDescriptionObserver* observer,
1357 const std::string& error) {
1358 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
1359 msg->error = error;
1360 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
1361}
1362
1363void PeerConnection::PostCreateSessionDescriptionFailure(
1364 CreateSessionDescriptionObserver* observer,
1365 const std::string& error) {
1366 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
1367 msg->error = error;
1368 signaling_thread()->Post(this, MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
1369}
1370
1371bool PeerConnection::GetOptionsForOffer(
1372 const PeerConnectionInterface::RTCOfferAnswerOptions& rtc_options,
1373 cricket::MediaSessionOptions* session_options) {
deadbeefab9b2d12015-10-14 11:33:11 -07001374 if (!ConvertRtcOptionsForOffer(rtc_options, session_options)) {
1375 return false;
1376 }
1377
deadbeefac9d92c2015-10-26 11:48:22 -07001378 AddSendStreams(session_options, senders_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001379 // Offer to receive audio/video if the constraint is not set and there are
1380 // send streams, or we're currently receiving.
1381 if (rtc_options.offer_to_receive_audio == RTCOfferAnswerOptions::kUndefined) {
1382 session_options->recv_audio =
1383 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_AUDIO) ||
1384 !remote_audio_tracks_.empty();
1385 }
1386 if (rtc_options.offer_to_receive_video == RTCOfferAnswerOptions::kUndefined) {
1387 session_options->recv_video =
1388 session_options->HasSendMediaStream(cricket::MEDIA_TYPE_VIDEO) ||
1389 !remote_video_tracks_.empty();
1390 }
1391 session_options->bundle_enabled =
1392 session_options->bundle_enabled &&
1393 (session_options->has_audio() || session_options->has_video() ||
1394 session_options->has_data());
1395
deadbeefab9b2d12015-10-14 11:33:11 -07001396 if (session_->data_channel_type() == cricket::DCT_SCTP && HasDataChannels()) {
1397 session_options->data_channel_type = cricket::DCT_SCTP;
1398 }
1399 return true;
1400}
1401
1402bool PeerConnection::GetOptionsForAnswer(
1403 const MediaConstraintsInterface* constraints,
1404 cricket::MediaSessionOptions* session_options) {
deadbeefab9b2d12015-10-14 11:33:11 -07001405 session_options->recv_audio = false;
1406 session_options->recv_video = false;
deadbeefab9b2d12015-10-14 11:33:11 -07001407 if (!ParseConstraintsForAnswer(constraints, session_options)) {
1408 return false;
1409 }
1410
deadbeefac9d92c2015-10-26 11:48:22 -07001411 AddSendStreams(session_options, senders_, rtp_data_channels_);
deadbeefc80741f2015-10-22 13:14:45 -07001412 session_options->bundle_enabled =
1413 session_options->bundle_enabled &&
1414 (session_options->has_audio() || session_options->has_video() ||
1415 session_options->has_data());
1416
deadbeefab9b2d12015-10-14 11:33:11 -07001417 // RTP data channel is handled in MediaSessionOptions::AddStream. SCTP streams
1418 // are not signaled in the SDP so does not go through that path and must be
1419 // handled here.
1420 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1421 session_options->data_channel_type = cricket::DCT_SCTP;
1422 }
1423 return true;
1424}
1425
1426void PeerConnection::UpdateRemoteStreamsList(
1427 const cricket::StreamParamsVec& streams,
1428 cricket::MediaType media_type,
1429 StreamCollection* new_streams) {
1430 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1431
1432 // Find removed tracks. I.e., tracks where the track id or ssrc don't match
deadbeefac9d92c2015-10-26 11:48:22 -07001433 // the new StreamParam.
deadbeefab9b2d12015-10-14 11:33:11 -07001434 auto track_it = current_tracks->begin();
1435 while (track_it != current_tracks->end()) {
1436 const TrackInfo& info = *track_it;
1437 const cricket::StreamParams* params =
1438 cricket::GetStreamBySsrc(streams, info.ssrc);
1439 if (!params || params->id != info.track_id) {
1440 OnRemoteTrackRemoved(info.stream_label, info.track_id, media_type);
1441 track_it = current_tracks->erase(track_it);
1442 } else {
1443 ++track_it;
1444 }
1445 }
1446
1447 // Find new and active tracks.
1448 for (const cricket::StreamParams& params : streams) {
1449 // The sync_label is the MediaStream label and the |stream.id| is the
1450 // track id.
1451 const std::string& stream_label = params.sync_label;
1452 const std::string& track_id = params.id;
1453 uint32_t ssrc = params.first_ssrc();
1454
1455 rtc::scoped_refptr<MediaStreamInterface> stream =
1456 remote_streams_->find(stream_label);
1457 if (!stream) {
1458 // This is a new MediaStream. Create a new remote MediaStream.
1459 stream = remote_stream_factory_->CreateMediaStream(stream_label);
1460 remote_streams_->AddStream(stream);
1461 new_streams->AddStream(stream);
1462 }
1463
1464 const TrackInfo* track_info =
1465 FindTrackInfo(*current_tracks, stream_label, track_id);
1466 if (!track_info) {
1467 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1468 OnRemoteTrackSeen(stream_label, track_id, ssrc, media_type);
1469 }
1470 }
1471}
1472
1473void PeerConnection::OnRemoteTrackSeen(const std::string& stream_label,
1474 const std::string& track_id,
1475 uint32_t ssrc,
1476 cricket::MediaType media_type) {
1477 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1478
1479 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1480 AudioTrackInterface* audio_track =
1481 remote_stream_factory_->AddAudioTrack(stream, track_id);
1482 CreateAudioReceiver(stream, audio_track, ssrc);
1483 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1484 VideoTrackInterface* video_track =
1485 remote_stream_factory_->AddVideoTrack(stream, track_id);
1486 CreateVideoReceiver(stream, video_track, ssrc);
1487 } else {
1488 RTC_DCHECK(false && "Invalid media type");
1489 }
1490}
1491
1492void PeerConnection::OnRemoteTrackRemoved(const std::string& stream_label,
1493 const std::string& track_id,
1494 cricket::MediaType media_type) {
1495 MediaStreamInterface* stream = remote_streams_->find(stream_label);
1496
1497 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1498 rtc::scoped_refptr<AudioTrackInterface> audio_track =
1499 stream->FindAudioTrack(track_id);
1500 if (audio_track) {
1501 audio_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1502 stream->RemoveTrack(audio_track);
1503 DestroyAudioReceiver(stream, audio_track);
1504 }
1505 } else if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1506 rtc::scoped_refptr<VideoTrackInterface> video_track =
1507 stream->FindVideoTrack(track_id);
1508 if (video_track) {
1509 video_track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1510 stream->RemoveTrack(video_track);
1511 DestroyVideoReceiver(stream, video_track);
1512 }
1513 } else {
1514 ASSERT(false && "Invalid media type");
1515 }
1516}
1517
1518void PeerConnection::UpdateEndedRemoteMediaStreams() {
1519 std::vector<rtc::scoped_refptr<MediaStreamInterface>> streams_to_remove;
1520 for (size_t i = 0; i < remote_streams_->count(); ++i) {
1521 MediaStreamInterface* stream = remote_streams_->at(i);
1522 if (stream->GetAudioTracks().empty() && stream->GetVideoTracks().empty()) {
1523 streams_to_remove.push_back(stream);
1524 }
1525 }
1526
1527 for (const auto& stream : streams_to_remove) {
1528 remote_streams_->RemoveStream(stream);
1529 observer_->OnRemoveStream(stream);
1530 }
1531}
1532
1533void PeerConnection::MaybeCreateDefaultStream() {
1534 if (!remote_info_.IsDefaultMediaStreamNeeded()) {
1535 return;
1536 }
1537
1538 bool default_created = false;
1539
1540 rtc::scoped_refptr<MediaStreamInterface> default_remote_stream =
1541 remote_streams_->find(kDefaultStreamLabel);
1542 if (default_remote_stream == nullptr) {
1543 default_created = true;
1544 default_remote_stream =
1545 remote_stream_factory_->CreateMediaStream(kDefaultStreamLabel);
1546 remote_streams_->AddStream(default_remote_stream);
1547 }
1548 if (remote_info_.default_audio_track_needed &&
1549 default_remote_stream->GetAudioTracks().size() == 0) {
1550 remote_audio_tracks_.push_back(
1551 TrackInfo(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0));
1552 OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultAudioTrackLabel, 0,
1553 cricket::MEDIA_TYPE_AUDIO);
1554 }
1555 if (remote_info_.default_video_track_needed &&
1556 default_remote_stream->GetVideoTracks().size() == 0) {
1557 remote_video_tracks_.push_back(
1558 TrackInfo(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0));
1559 OnRemoteTrackSeen(kDefaultStreamLabel, kDefaultVideoTrackLabel, 0,
1560 cricket::MEDIA_TYPE_VIDEO);
1561 }
1562 if (default_created) {
1563 stats_->AddStream(default_remote_stream);
1564 observer_->OnAddStream(default_remote_stream);
1565 }
1566}
1567
1568void PeerConnection::EndRemoteTracks(cricket::MediaType media_type) {
1569 TrackInfos* current_tracks = GetRemoteTracks(media_type);
1570 for (TrackInfos::iterator track_it = current_tracks->begin();
1571 track_it != current_tracks->end(); ++track_it) {
1572 const TrackInfo& info = *track_it;
1573 MediaStreamInterface* stream = remote_streams_->find(info.stream_label);
1574 if (media_type == cricket::MEDIA_TYPE_AUDIO) {
1575 AudioTrackInterface* track = stream->FindAudioTrack(info.track_id);
1576 // There's no guarantee the track is still available, e.g. the track may
1577 // have been removed from the stream by javascript.
1578 if (track) {
1579 track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1580 }
1581 }
1582 if (media_type == cricket::MEDIA_TYPE_VIDEO) {
1583 VideoTrackInterface* track = stream->FindVideoTrack(info.track_id);
1584 // There's no guarantee the track is still available, e.g. the track may
1585 // have been removed from the stream by javascript.
1586 if (track) {
1587 track->set_state(webrtc::MediaStreamTrackInterface::kEnded);
1588 }
1589 }
1590 }
1591}
1592
1593void PeerConnection::UpdateLocalTracks(
1594 const std::vector<cricket::StreamParams>& streams,
1595 cricket::MediaType media_type) {
1596 TrackInfos* current_tracks = GetLocalTracks(media_type);
1597
1598 // Find removed tracks. I.e., tracks where the track id, stream label or ssrc
1599 // don't match the new StreamParam.
1600 TrackInfos::iterator track_it = current_tracks->begin();
1601 while (track_it != current_tracks->end()) {
1602 const TrackInfo& info = *track_it;
1603 const cricket::StreamParams* params =
1604 cricket::GetStreamBySsrc(streams, info.ssrc);
1605 if (!params || params->id != info.track_id ||
1606 params->sync_label != info.stream_label) {
1607 OnLocalTrackRemoved(info.stream_label, info.track_id, info.ssrc,
1608 media_type);
1609 track_it = current_tracks->erase(track_it);
1610 } else {
1611 ++track_it;
1612 }
1613 }
1614
1615 // Find new and active tracks.
1616 for (const cricket::StreamParams& params : streams) {
1617 // The sync_label is the MediaStream label and the |stream.id| is the
1618 // track id.
1619 const std::string& stream_label = params.sync_label;
1620 const std::string& track_id = params.id;
1621 uint32_t ssrc = params.first_ssrc();
1622 const TrackInfo* track_info =
1623 FindTrackInfo(*current_tracks, stream_label, track_id);
1624 if (!track_info) {
1625 current_tracks->push_back(TrackInfo(stream_label, track_id, ssrc));
1626 OnLocalTrackSeen(stream_label, track_id, params.first_ssrc(), media_type);
1627 }
1628 }
1629}
1630
1631void PeerConnection::OnLocalTrackSeen(const std::string& stream_label,
1632 const std::string& track_id,
1633 uint32_t ssrc,
1634 cricket::MediaType media_type) {
deadbeefac9d92c2015-10-26 11:48:22 -07001635 RtpSenderInterface* sender = FindSenderById(track_id);
1636 if (!sender) {
1637 LOG(LS_WARNING) << "An unknown RtpSender with id " << track_id
1638 << " has been configured in the local description.";
deadbeefab9b2d12015-10-14 11:33:11 -07001639 return;
1640 }
1641
deadbeefac9d92c2015-10-26 11:48:22 -07001642 if (sender->media_type() != media_type) {
1643 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
1644 << " description with an unexpected media type.";
1645 return;
deadbeefab9b2d12015-10-14 11:33:11 -07001646 }
deadbeefac9d92c2015-10-26 11:48:22 -07001647
1648 sender->set_stream_id(stream_label);
1649 sender->SetSsrc(ssrc);
deadbeefab9b2d12015-10-14 11:33:11 -07001650}
1651
1652void PeerConnection::OnLocalTrackRemoved(const std::string& stream_label,
1653 const std::string& track_id,
1654 uint32_t ssrc,
1655 cricket::MediaType media_type) {
deadbeefac9d92c2015-10-26 11:48:22 -07001656 RtpSenderInterface* sender = FindSenderById(track_id);
1657 if (!sender) {
1658 // This is the normal case. I.e., RemoveStream has been called and the
deadbeefab9b2d12015-10-14 11:33:11 -07001659 // SessionDescriptions has been renegotiated.
1660 return;
1661 }
deadbeefac9d92c2015-10-26 11:48:22 -07001662
1663 // A sender has been removed from the SessionDescription but it's still
1664 // associated with the PeerConnection. This only occurs if the SDP doesn't
1665 // match with the calls to CreateSender, AddStream and RemoveStream.
1666 if (sender->media_type() != media_type) {
1667 LOG(LS_WARNING) << "An RtpSender has been configured in the local"
1668 << " description with an unexpected media type.";
1669 return;
deadbeefab9b2d12015-10-14 11:33:11 -07001670 }
deadbeefac9d92c2015-10-26 11:48:22 -07001671
1672 sender->SetSsrc(0);
deadbeefab9b2d12015-10-14 11:33:11 -07001673}
1674
1675void PeerConnection::UpdateLocalRtpDataChannels(
1676 const cricket::StreamParamsVec& streams) {
1677 std::vector<std::string> existing_channels;
1678
1679 // Find new and active data channels.
1680 for (const cricket::StreamParams& params : streams) {
1681 // |it->sync_label| is actually the data channel label. The reason is that
1682 // we use the same naming of data channels as we do for
1683 // MediaStreams and Tracks.
1684 // For MediaStreams, the sync_label is the MediaStream label and the
1685 // track label is the same as |streamid|.
1686 const std::string& channel_label = params.sync_label;
1687 auto data_channel_it = rtp_data_channels_.find(channel_label);
1688 if (!VERIFY(data_channel_it != rtp_data_channels_.end())) {
1689 continue;
1690 }
1691 // Set the SSRC the data channel should use for sending.
1692 data_channel_it->second->SetSendSsrc(params.first_ssrc());
1693 existing_channels.push_back(data_channel_it->first);
1694 }
1695
1696 UpdateClosingRtpDataChannels(existing_channels, true);
1697}
1698
1699void PeerConnection::UpdateRemoteRtpDataChannels(
1700 const cricket::StreamParamsVec& streams) {
1701 std::vector<std::string> existing_channels;
1702
1703 // Find new and active data channels.
1704 for (const cricket::StreamParams& params : streams) {
1705 // The data channel label is either the mslabel or the SSRC if the mslabel
1706 // does not exist. Ex a=ssrc:444330170 mslabel:test1.
1707 std::string label = params.sync_label.empty()
1708 ? rtc::ToString(params.first_ssrc())
1709 : params.sync_label;
1710 auto data_channel_it = rtp_data_channels_.find(label);
1711 if (data_channel_it == rtp_data_channels_.end()) {
1712 // This is a new data channel.
1713 CreateRemoteRtpDataChannel(label, params.first_ssrc());
1714 } else {
1715 data_channel_it->second->SetReceiveSsrc(params.first_ssrc());
1716 }
1717 existing_channels.push_back(label);
1718 }
1719
1720 UpdateClosingRtpDataChannels(existing_channels, false);
1721}
1722
1723void PeerConnection::UpdateClosingRtpDataChannels(
1724 const std::vector<std::string>& active_channels,
1725 bool is_local_update) {
1726 auto it = rtp_data_channels_.begin();
1727 while (it != rtp_data_channels_.end()) {
1728 DataChannel* data_channel = it->second;
1729 if (std::find(active_channels.begin(), active_channels.end(),
1730 data_channel->label()) != active_channels.end()) {
1731 ++it;
1732 continue;
1733 }
1734
1735 if (is_local_update) {
1736 data_channel->SetSendSsrc(0);
1737 } else {
1738 data_channel->RemotePeerRequestClose();
1739 }
1740
1741 if (data_channel->state() == DataChannel::kClosed) {
1742 rtp_data_channels_.erase(it);
1743 it = rtp_data_channels_.begin();
1744 } else {
1745 ++it;
1746 }
1747 }
1748}
1749
1750void PeerConnection::CreateRemoteRtpDataChannel(const std::string& label,
1751 uint32_t remote_ssrc) {
1752 rtc::scoped_refptr<DataChannel> channel(
1753 InternalCreateDataChannel(label, nullptr));
1754 if (!channel.get()) {
1755 LOG(LS_WARNING) << "Remote peer requested a DataChannel but"
1756 << "CreateDataChannel failed.";
1757 return;
1758 }
1759 channel->SetReceiveSsrc(remote_ssrc);
1760 observer_->OnDataChannel(
1761 DataChannelProxy::Create(signaling_thread(), channel));
1762}
1763
1764rtc::scoped_refptr<DataChannel> PeerConnection::InternalCreateDataChannel(
1765 const std::string& label,
1766 const InternalDataChannelInit* config) {
1767 if (IsClosed()) {
1768 return nullptr;
1769 }
1770 if (session_->data_channel_type() == cricket::DCT_NONE) {
1771 LOG(LS_ERROR)
1772 << "InternalCreateDataChannel: Data is not supported in this call.";
1773 return nullptr;
1774 }
1775 InternalDataChannelInit new_config =
1776 config ? (*config) : InternalDataChannelInit();
1777 if (session_->data_channel_type() == cricket::DCT_SCTP) {
1778 if (new_config.id < 0) {
1779 rtc::SSLRole role;
1780 if (session_->GetSslRole(&role) &&
1781 !sid_allocator_.AllocateSid(role, &new_config.id)) {
1782 LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel.";
1783 return nullptr;
1784 }
1785 } else if (!sid_allocator_.ReserveSid(new_config.id)) {
1786 LOG(LS_ERROR) << "Failed to create a SCTP data channel "
1787 << "because the id is already in use or out of range.";
1788 return nullptr;
1789 }
1790 }
1791
1792 rtc::scoped_refptr<DataChannel> channel(DataChannel::Create(
1793 session_.get(), session_->data_channel_type(), label, new_config));
1794 if (!channel) {
1795 sid_allocator_.ReleaseSid(new_config.id);
1796 return nullptr;
1797 }
1798
1799 if (channel->data_channel_type() == cricket::DCT_RTP) {
1800 if (rtp_data_channels_.find(channel->label()) != rtp_data_channels_.end()) {
1801 LOG(LS_ERROR) << "DataChannel with label " << channel->label()
1802 << " already exists.";
1803 return nullptr;
1804 }
1805 rtp_data_channels_[channel->label()] = channel;
1806 } else {
1807 RTC_DCHECK(channel->data_channel_type() == cricket::DCT_SCTP);
1808 sctp_data_channels_.push_back(channel);
1809 channel->SignalClosed.connect(this,
1810 &PeerConnection::OnSctpDataChannelClosed);
1811 }
1812
1813 return channel;
1814}
1815
1816bool PeerConnection::HasDataChannels() const {
1817 return !rtp_data_channels_.empty() || !sctp_data_channels_.empty();
1818}
1819
1820void PeerConnection::AllocateSctpSids(rtc::SSLRole role) {
1821 for (const auto& channel : sctp_data_channels_) {
1822 if (channel->id() < 0) {
1823 int sid;
1824 if (!sid_allocator_.AllocateSid(role, &sid)) {
1825 LOG(LS_ERROR) << "Failed to allocate SCTP sid.";
1826 continue;
1827 }
1828 channel->SetSctpSid(sid);
1829 }
1830 }
1831}
1832
1833void PeerConnection::OnSctpDataChannelClosed(DataChannel* channel) {
1834 for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end();
1835 ++it) {
1836 if (it->get() == channel) {
1837 if (channel->id() >= 0) {
1838 sid_allocator_.ReleaseSid(channel->id());
1839 }
1840 sctp_data_channels_.erase(it);
1841 return;
1842 }
1843 }
1844}
1845
1846void PeerConnection::OnVoiceChannelDestroyed() {
1847 EndRemoteTracks(cricket::MEDIA_TYPE_AUDIO);
1848}
1849
1850void PeerConnection::OnVideoChannelDestroyed() {
1851 EndRemoteTracks(cricket::MEDIA_TYPE_VIDEO);
1852}
1853
1854void PeerConnection::OnDataChannelCreated() {
1855 for (const auto& channel : sctp_data_channels_) {
1856 channel->OnTransportChannelCreated();
1857 }
1858}
1859
1860void PeerConnection::OnDataChannelDestroyed() {
1861 // Use a temporary copy of the RTP/SCTP DataChannel list because the
1862 // DataChannel may callback to us and try to modify the list.
1863 std::map<std::string, rtc::scoped_refptr<DataChannel>> temp_rtp_dcs;
1864 temp_rtp_dcs.swap(rtp_data_channels_);
1865 for (const auto& kv : temp_rtp_dcs) {
1866 kv.second->OnTransportChannelDestroyed();
1867 }
1868
1869 std::vector<rtc::scoped_refptr<DataChannel>> temp_sctp_dcs;
1870 temp_sctp_dcs.swap(sctp_data_channels_);
1871 for (const auto& channel : temp_sctp_dcs) {
1872 channel->OnTransportChannelDestroyed();
1873 }
1874}
1875
1876void PeerConnection::OnDataChannelOpenMessage(
1877 const std::string& label,
1878 const InternalDataChannelInit& config) {
1879 rtc::scoped_refptr<DataChannel> channel(
1880 InternalCreateDataChannel(label, &config));
1881 if (!channel.get()) {
1882 LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
1883 return;
1884 }
1885
1886 observer_->OnDataChannel(
1887 DataChannelProxy::Create(signaling_thread(), channel));
1888}
1889
deadbeefac9d92c2015-10-26 11:48:22 -07001890RtpSenderInterface* PeerConnection::FindSenderById(const std::string& id) {
1891 auto it =
1892 std::find_if(senders_.begin(), senders_.end(),
1893 [id](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
1894 return sender->id() == id;
1895 });
1896 return it != senders_.end() ? it->get() : nullptr;
1897}
1898
deadbeef70ab1a12015-09-28 16:53:55 -07001899std::vector<rtc::scoped_refptr<RtpSenderInterface>>::iterator
1900PeerConnection::FindSenderForTrack(MediaStreamTrackInterface* track) {
1901 return std::find_if(
1902 senders_.begin(), senders_.end(),
1903 [track](const rtc::scoped_refptr<RtpSenderInterface>& sender) {
1904 return sender->track() == track;
1905 });
1906}
1907
1908std::vector<rtc::scoped_refptr<RtpReceiverInterface>>::iterator
1909PeerConnection::FindReceiverForTrack(MediaStreamTrackInterface* track) {
1910 return std::find_if(
1911 receivers_.begin(), receivers_.end(),
1912 [track](const rtc::scoped_refptr<RtpReceiverInterface>& receiver) {
1913 return receiver->track() == track;
1914 });
1915}
1916
deadbeefab9b2d12015-10-14 11:33:11 -07001917PeerConnection::TrackInfos* PeerConnection::GetRemoteTracks(
1918 cricket::MediaType media_type) {
1919 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
1920 media_type == cricket::MEDIA_TYPE_VIDEO);
1921 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &remote_audio_tracks_
1922 : &remote_video_tracks_;
1923}
1924
1925PeerConnection::TrackInfos* PeerConnection::GetLocalTracks(
1926 cricket::MediaType media_type) {
1927 RTC_DCHECK(media_type == cricket::MEDIA_TYPE_AUDIO ||
1928 media_type == cricket::MEDIA_TYPE_VIDEO);
1929 return (media_type == cricket::MEDIA_TYPE_AUDIO) ? &local_audio_tracks_
1930 : &local_video_tracks_;
1931}
1932
1933const PeerConnection::TrackInfo* PeerConnection::FindTrackInfo(
1934 const PeerConnection::TrackInfos& infos,
1935 const std::string& stream_label,
1936 const std::string track_id) const {
1937 for (const TrackInfo& track_info : infos) {
1938 if (track_info.stream_label == stream_label &&
1939 track_info.track_id == track_id) {
1940 return &track_info;
1941 }
1942 }
1943 return nullptr;
1944}
1945
1946DataChannel* PeerConnection::FindDataChannelBySid(int sid) const {
1947 for (const auto& channel : sctp_data_channels_) {
1948 if (channel->id() == sid) {
1949 return channel;
1950 }
1951 }
1952 return nullptr;
1953}
1954
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001955} // namespace webrtc