blob: d1338897da2dc91cddc5fda2dea677ea078239ce [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2012, Google Inc.
4 *
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>
31
32#include "talk/app/webrtc/dtmfsender.h"
33#include "talk/app/webrtc/jsepicecandidate.h"
34#include "talk/app/webrtc/jsepsessiondescription.h"
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +000035#include "talk/app/webrtc/mediaconstraintsinterface.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000036#include "talk/app/webrtc/mediastreamhandler.h"
37#include "talk/app/webrtc/streamcollection.h"
buildbot@webrtc.org41451d42014-05-03 05:39:45 +000038#include "talk/p2p/client/basicportallocator.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000039#include "talk/session/media/channelmanager.h"
buildbot@webrtc.orga09a9992014-08-13 17:26:08 +000040#include "webrtc/base/logging.h"
41#include "webrtc/base/stringencode.h"
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +000042#ifdef WEBRTC_CHROMIUM_BUILD
43#include "webrtc/system_wrappers/interface/field_trial.h"
44#endif
henrike@webrtc.org28e20752013-07-10 00:45:36 +000045
46namespace {
47
48using webrtc::PeerConnectionInterface;
49
henrike@webrtc.org28e20752013-07-10 00:45:36 +000050// The min number of tokens must present in Turn host uri.
51// e.g. user@turn.example.org
52static const size_t kTurnHostTokensNum = 2;
53// Number of tokens must be preset when TURN uri has transport param.
54static const size_t kTurnTransportTokensNum = 2;
55// The default stun port.
wu@webrtc.org91053e72013-08-10 07:18:04 +000056static const int kDefaultStunPort = 3478;
57static const int kDefaultStunTlsPort = 5349;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000058static const char kTransport[] = "transport";
wu@webrtc.org91053e72013-08-10 07:18:04 +000059static const char kUdpTransportType[] = "udp";
60static const char kTcpTransportType[] = "tcp";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000061
62// NOTE: Must be in the same order as the ServiceType enum.
63static const char* kValidIceServiceTypes[] = {
64 "stun", "stuns", "turn", "turns", "invalid" };
65
66enum ServiceType {
67 STUN, // Indicates a STUN server.
68 STUNS, // Indicates a STUN server used with a TLS session.
69 TURN, // Indicates a TURN server
70 TURNS, // Indicates a TURN server used with a TLS session.
71 INVALID, // Unknown.
72};
73
74enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +000075 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076 MSG_SET_SESSIONDESCRIPTION_FAILED,
77 MSG_GETSTATS,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000078};
79
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000080struct SetSessionDescriptionMsg : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000081 explicit SetSessionDescriptionMsg(
82 webrtc::SetSessionDescriptionObserver* observer)
83 : observer(observer) {
84 }
85
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000086 rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000087 std::string error;
88};
89
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000090struct GetStatsMsg : public rtc::MessageData {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +000091 GetStatsMsg(webrtc::StatsObserver* observer,
92 webrtc::MediaStreamTrackInterface* track)
93 : observer(observer), track(track) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000094 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000095 rtc::scoped_refptr<webrtc::StatsObserver> observer;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +000096 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000097};
98
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +000099// |in_str| should be of format
100// stunURI = scheme ":" stun-host [ ":" stun-port ]
101// scheme = "stun" / "stuns"
102// stun-host = IP-literal / IPv4address / reg-name
103// stun-port = *DIGIT
104
105// draft-petithuguenin-behave-turn-uris-01
106// turnURI = scheme ":" turn-host [ ":" turn-port ]
107// turn-host = username@IP-literal / IPv4address / reg-name
108bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
109 ServiceType* service_type,
110 std::string* hostname) {
111 std::string::size_type colonpos = in_str.find(':');
112 if (colonpos == std::string::npos) {
113 return false;
114 }
115 std::string type = in_str.substr(0, colonpos);
116 for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
117 if (type.compare(kValidIceServiceTypes[i]) == 0) {
118 *service_type = static_cast<ServiceType>(i);
119 break;
120 }
121 }
122 if (*service_type == INVALID) {
123 return false;
124 }
125 *hostname = in_str.substr(colonpos + 1, std::string::npos);
126 return true;
127}
128
129// This method parses IPv6 and IPv4 literal strings, along with hostnames in
130// standard hostname:port format.
131// Consider following formats as correct.
132// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
133// |hostname|, |[IPv6 address]|, |IPv4 address|
134bool ParseHostnameAndPortFromString(const std::string& in_str,
135 std::string* host,
136 int* port) {
137 if (in_str.at(0) == '[') {
138 std::string::size_type closebracket = in_str.rfind(']');
139 if (closebracket != std::string::npos) {
140 *host = in_str.substr(1, closebracket - 1);
141 std::string::size_type colonpos = in_str.find(':', closebracket);
142 if (std::string::npos != colonpos) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000143 if (!rtc::FromString(
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000144 in_str.substr(closebracket + 2, std::string::npos), port)) {
145 return false;
146 }
147 }
148 } else {
149 return false;
150 }
151 } else {
152 std::string::size_type colonpos = in_str.find(':');
153 if (std::string::npos != colonpos) {
154 *host = in_str.substr(0, colonpos);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000155 if (!rtc::FromString(
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000156 in_str.substr(colonpos + 1, std::string::npos), port)) {
157 return false;
158 }
159 } else {
160 *host = in_str;
161 }
162 }
163 return true;
164}
165
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000166typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
167 StunConfiguration;
168typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
169 TurnConfiguration;
170
171bool ParseIceServers(const PeerConnectionInterface::IceServers& configuration,
172 std::vector<StunConfiguration>* stun_config,
173 std::vector<TurnConfiguration>* turn_config) {
174 // draft-nandakumar-rtcweb-stun-uri-01
175 // stunURI = scheme ":" stun-host [ ":" stun-port ]
176 // scheme = "stun" / "stuns"
177 // stun-host = IP-literal / IPv4address / reg-name
178 // stun-port = *DIGIT
179
180 // draft-petithuguenin-behave-turn-uris-01
181 // turnURI = scheme ":" turn-host [ ":" turn-port ]
182 // [ "?transport=" transport ]
183 // scheme = "turn" / "turns"
184 // transport = "udp" / "tcp" / transport-ext
185 // transport-ext = 1*unreserved
186 // turn-host = IP-literal / IPv4address / reg-name
187 // turn-port = *DIGIT
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000188 for (size_t i = 0; i < configuration.size(); ++i) {
189 webrtc::PeerConnectionInterface::IceServer server = configuration[i];
190 if (server.uri.empty()) {
191 LOG(WARNING) << "Empty uri.";
192 continue;
193 }
194 std::vector<std::string> tokens;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000195 std::string turn_transport_type = kUdpTransportType;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000196 rtc::tokenize(server.uri, '?', &tokens);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000197 std::string uri_without_transport = tokens[0];
198 // Let's look into transport= param, if it exists.
199 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
200 std::string uri_transport_param = tokens[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000201 rtc::tokenize(uri_transport_param, '=', &tokens);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000202 if (tokens[0] == kTransport) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000203 // As per above grammar transport param will be consist of lower case
204 // letters.
205 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
206 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
207 continue;
208 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000209 turn_transport_type = tokens[1];
210 }
211 }
212
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000213 std::string hoststring;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000214 ServiceType service_type = INVALID;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000215 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
216 &service_type,
217 &hoststring)) {
218 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: "
219 << uri_without_transport;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000220 continue;
221 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000222
223 // Let's break hostname.
224 tokens.clear();
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000225 rtc::tokenize(hoststring, '@', &tokens);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000226 hoststring = tokens[0];
227 if (tokens.size() == kTurnHostTokensNum) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000228 server.username = rtc::s_url_decode(tokens[0]);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000229 hoststring = tokens[1];
230 }
231
wu@webrtc.org91053e72013-08-10 07:18:04 +0000232 int port = kDefaultStunPort;
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000233 if (service_type == TURNS) {
234 port = kDefaultStunTlsPort;
235 turn_transport_type = kTcpTransportType;
236 }
237
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000238 std::string address;
239 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
240 LOG(WARNING) << "Invalid Hostname format: " << uri_without_transport;
241 continue;
242 }
243
wu@webrtc.org91053e72013-08-10 07:18:04 +0000244
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000245 if (port <= 0 || port > 0xffff) {
246 LOG(WARNING) << "Invalid port: " << port;
247 continue;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000248 }
249
250 switch (service_type) {
251 case STUN:
252 case STUNS:
253 stun_config->push_back(StunConfiguration(address, port));
254 break;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000255 case TURN:
256 case TURNS: {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000257 if (server.username.empty()) {
258 // Turn url example from the spec |url:"turn:user@turn.example.org"|.
259 std::vector<std::string> turn_tokens;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000260 rtc::tokenize(address, '@', &turn_tokens);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000261 if (turn_tokens.size() == kTurnHostTokensNum) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000262 server.username = rtc::s_url_decode(turn_tokens[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000263 address = turn_tokens[1];
264 }
265 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000266
267 bool secure = (service_type == TURNS);
268
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000269 turn_config->push_back(TurnConfiguration(address, port,
270 server.username,
271 server.password,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000272 turn_transport_type,
273 secure));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000274 break;
275 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000276 case INVALID:
277 default:
278 LOG(WARNING) << "Configuration not supported: " << server.uri;
279 return false;
280 }
281 }
282 return true;
283}
284
285// Check if we can send |new_stream| on a PeerConnection.
286// Currently only one audio but multiple video track is supported per
287// PeerConnection.
288bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
289 webrtc::MediaStreamInterface* new_stream) {
290 if (!new_stream || !current_streams)
291 return false;
292 if (current_streams->find(new_stream->label()) != NULL) {
293 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
294 << " is already added.";
295 return false;
296 }
297
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000298 return true;
299}
300
301} // namespace
302
303namespace webrtc {
304
305PeerConnection::PeerConnection(PeerConnectionFactory* factory)
306 : factory_(factory),
307 observer_(NULL),
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000308 uma_observer_(NULL),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000309 signaling_state_(kStable),
310 ice_state_(kIceNew),
311 ice_connection_state_(kIceConnectionNew),
312 ice_gathering_state_(kIceGatheringNew) {
313}
314
315PeerConnection::~PeerConnection() {
316 if (mediastream_signaling_)
317 mediastream_signaling_->TearDown();
318 if (stream_handler_container_)
319 stream_handler_container_->TearDown();
320}
321
322bool PeerConnection::Initialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000323 const PeerConnectionInterface::RTCConfiguration& configuration,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000324 const MediaConstraintsInterface* constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000325 PortAllocatorFactoryInterface* allocator_factory,
326 DTLSIdentityServiceInterface* dtls_identity_service,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000327 PeerConnectionObserver* observer) {
328 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
329 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000330 if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000331 return false;
332 }
333
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000334 return DoInitialize(configuration.type, stun_config, turn_config, constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000335 allocator_factory, dtls_identity_service, observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000336}
337
338bool PeerConnection::DoInitialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000339 IceTransportsType type,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000340 const StunConfigurations& stun_config,
341 const TurnConfigurations& turn_config,
342 const MediaConstraintsInterface* constraints,
343 webrtc::PortAllocatorFactoryInterface* allocator_factory,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000344 DTLSIdentityServiceInterface* dtls_identity_service,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000345 PeerConnectionObserver* observer) {
346 ASSERT(observer != NULL);
347 if (!observer)
348 return false;
349 observer_ = observer;
350 port_allocator_.reset(
351 allocator_factory->CreatePortAllocator(stun_config, turn_config));
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000352
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000353 // To handle both internal and externally created port allocator, we will
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000354 // enable BUNDLE here.
355 int portallocator_flags = cricket::PORTALLOCATOR_ENABLE_BUNDLE |
356 cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
357 cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET;
358 bool value;
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000359 // If IPv6 flag was specified, we'll not override it by experiment.
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000360 if (FindConstraint(
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000361 constraints, MediaConstraintsInterface::kEnableIPv6, &value, NULL)) {
362 if (value) {
363 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6;
364 }
365 }
366#ifdef WEBRTC_CHROMIUM_BUILD
367 else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default") ==
368 "Enabled") {
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000369 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6;
370 }
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000371#endif // WEBRTC_CHROMIUM_BUILD
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000372
373 port_allocator_->set_flags(portallocator_flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000374 // No step delay is used while allocating ports.
375 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
376
377 mediastream_signaling_.reset(new MediaStreamSignaling(
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000378 factory_->signaling_thread(), this, factory_->channel_manager()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000379
380 session_.reset(new WebRtcSession(factory_->channel_manager(),
381 factory_->signaling_thread(),
382 factory_->worker_thread(),
383 port_allocator_.get(),
384 mediastream_signaling_.get()));
385 stream_handler_container_.reset(new MediaStreamHandlerContainer(
386 session_.get(), session_.get()));
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000387 stats_.reset(new StatsCollector(session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000388
389 // Initialize the WebRtcSession. It creates transport channels etc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000390 if (!session_->Initialize(factory_->options(), constraints,
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000391 dtls_identity_service, type))
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000392 return false;
393
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000394 // Register PeerConnection as receiver of local ice candidates.
395 // All the callbacks will be posted to the application from PeerConnection.
396 session_->RegisterIceObserver(this);
397 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
398 return true;
399}
400
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000401rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000402PeerConnection::local_streams() {
403 return mediastream_signaling_->local_streams();
404}
405
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000406rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000407PeerConnection::remote_streams() {
408 return mediastream_signaling_->remote_streams();
409}
410
411bool PeerConnection::AddStream(MediaStreamInterface* local_stream,
412 const MediaConstraintsInterface* constraints) {
413 if (IsClosed()) {
414 return false;
415 }
416 if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(),
417 local_stream))
418 return false;
419
420 // TODO(perkj): Implement support for MediaConstraints in AddStream.
421 if (!mediastream_signaling_->AddLocalStream(local_stream)) {
422 return false;
423 }
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000424 stats_->AddStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000425 observer_->OnRenegotiationNeeded();
426 return true;
427}
428
429void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000430 mediastream_signaling_->RemoveLocalStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000431 if (IsClosed()) {
432 return;
433 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434 observer_->OnRenegotiationNeeded();
435}
436
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000437rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000438 AudioTrackInterface* track) {
439 if (!track) {
440 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
441 return NULL;
442 }
443 if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) {
444 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
445 return NULL;
446 }
447
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000448 rtc::scoped_refptr<DtmfSenderInterface> sender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000449 DtmfSender::Create(track, signaling_thread(), session_.get()));
450 if (!sender.get()) {
451 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
452 return NULL;
453 }
454 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
455}
456
457bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000458 MediaStreamTrackInterface* track,
459 StatsOutputLevel level) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000460 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000461 if (!VERIFY(observer != NULL)) {
462 LOG(LS_ERROR) << "GetStats - observer is NULL.";
463 return false;
464 }
465
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000466 stats_->UpdateStats(level);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000467 signaling_thread()->Post(this, MSG_GETSTATS,
468 new GetStatsMsg(observer, track));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000469 return true;
470}
471
472PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
473 return signaling_state_;
474}
475
476PeerConnectionInterface::IceState PeerConnection::ice_state() {
477 return ice_state_;
478}
479
480PeerConnectionInterface::IceConnectionState
481PeerConnection::ice_connection_state() {
482 return ice_connection_state_;
483}
484
485PeerConnectionInterface::IceGatheringState
486PeerConnection::ice_gathering_state() {
487 return ice_gathering_state_;
488}
489
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000490rtc::scoped_refptr<DataChannelInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000491PeerConnection::CreateDataChannel(
492 const std::string& label,
493 const DataChannelInit* config) {
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000494 bool first_datachannel = !mediastream_signaling_->HasDataChannels();
495
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000496 rtc::scoped_ptr<InternalDataChannelInit> internal_config;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000497 if (config) {
498 internal_config.reset(new InternalDataChannelInit(*config));
499 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000500 rtc::scoped_refptr<DataChannelInterface> channel(
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000501 session_->CreateDataChannel(label, internal_config.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000502 if (!channel.get())
503 return NULL;
504
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000505 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
506 // the first SCTP DataChannel.
507 if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
508 observer_->OnRenegotiationNeeded();
509 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000510
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000511 return DataChannelProxy::Create(signaling_thread(), channel.get());
512}
513
514void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
515 const MediaConstraintsInterface* constraints) {
516 if (!VERIFY(observer != NULL)) {
517 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
518 return;
519 }
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000520 RTCOfferAnswerOptions options;
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000521
522 bool value;
523 size_t mandatory_constraints = 0;
524
525 if (FindConstraint(constraints,
526 MediaConstraintsInterface::kOfferToReceiveAudio,
527 &value,
528 &mandatory_constraints)) {
529 options.offer_to_receive_audio =
530 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
531 }
532
533 if (FindConstraint(constraints,
534 MediaConstraintsInterface::kOfferToReceiveVideo,
535 &value,
536 &mandatory_constraints)) {
537 options.offer_to_receive_video =
538 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
539 }
540
541 if (FindConstraint(constraints,
542 MediaConstraintsInterface::kVoiceActivityDetection,
543 &value,
544 &mandatory_constraints)) {
545 options.voice_activity_detection = value;
546 }
547
548 if (FindConstraint(constraints,
549 MediaConstraintsInterface::kIceRestart,
550 &value,
551 &mandatory_constraints)) {
552 options.ice_restart = value;
553 }
554
555 if (FindConstraint(constraints,
556 MediaConstraintsInterface::kUseRtpMux,
557 &value,
558 &mandatory_constraints)) {
559 options.use_rtp_mux = value;
560 }
561
562 CreateOffer(observer, options);
563}
564
565void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
566 const RTCOfferAnswerOptions& options) {
567 if (!VERIFY(observer != NULL)) {
568 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
569 return;
570 }
571 session_->CreateOffer(observer, options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000572}
573
574void PeerConnection::CreateAnswer(
575 CreateSessionDescriptionObserver* observer,
576 const MediaConstraintsInterface* constraints) {
577 if (!VERIFY(observer != NULL)) {
578 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
579 return;
580 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000581 session_->CreateAnswer(observer, constraints);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000582}
583
584void PeerConnection::SetLocalDescription(
585 SetSessionDescriptionObserver* observer,
586 SessionDescriptionInterface* desc) {
587 if (!VERIFY(observer != NULL)) {
588 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
589 return;
590 }
591 if (!desc) {
592 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
593 return;
594 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000595 // Update stats here so that we have the most recent stats for tracks and
596 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000597 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000598 std::string error;
599 if (!session_->SetLocalDescription(desc, &error)) {
600 PostSetSessionDescriptionFailure(observer, error);
601 return;
602 }
603 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
604 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
605}
606
607void PeerConnection::SetRemoteDescription(
608 SetSessionDescriptionObserver* observer,
609 SessionDescriptionInterface* desc) {
610 if (!VERIFY(observer != NULL)) {
611 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
612 return;
613 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000614 if (!desc) {
615 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
616 return;
617 }
618 // Update stats here so that we have the most recent stats for tracks and
619 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000620 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000621 std::string error;
622 if (!session_->SetRemoteDescription(desc, &error)) {
623 PostSetSessionDescriptionFailure(observer, error);
624 return;
625 }
626 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
627 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
628}
629
630void PeerConnection::PostSetSessionDescriptionFailure(
631 SetSessionDescriptionObserver* observer,
632 const std::string& error) {
633 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
634 msg->error = error;
635 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
636}
637
638bool PeerConnection::UpdateIce(const IceServers& configuration,
639 const MediaConstraintsInterface* constraints) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000640 return false;
641}
642
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000643bool PeerConnection::UpdateIce(const RTCConfiguration& config) {
644 if (port_allocator_) {
645 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
646 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
647 if (!ParseIceServers(config.servers, &stuns, &turns)) {
648 return false;
649 }
650
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000651 std::vector<rtc::SocketAddress> stun_hosts;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000652 typedef std::vector<StunConfiguration>::const_iterator StunIt;
653 for (StunIt stun_it = stuns.begin(); stun_it != stuns.end(); ++stun_it) {
654 stun_hosts.push_back(stun_it->server);
655 }
656
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000657 rtc::SocketAddress stun_addr;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000658 if (!stun_hosts.empty()) {
659 stun_addr = stun_hosts.front();
660 LOG(LS_INFO) << "UpdateIce: StunServer Address: " << stun_addr.ToString();
661 }
662
663 for (size_t i = 0; i < turns.size(); ++i) {
664 cricket::RelayCredentials credentials(turns[i].username,
665 turns[i].password);
666 cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
667 cricket::ProtocolType protocol;
668 if (cricket::StringToProto(turns[i].transport_type.c_str(), &protocol)) {
669 relay_server.ports.push_back(cricket::ProtocolAddress(
670 turns[i].server, protocol, turns[i].secure));
671 relay_server.credentials = credentials;
672 LOG(LS_INFO) << "UpdateIce: TurnServer Address: "
673 << turns[i].server.ToString();
674 } else {
675 LOG(LS_WARNING) << "Ignoring TURN server " << turns[i].server << ". "
676 << "Reason= Incorrect " << turns[i].transport_type
677 << " transport parameter.";
678 }
679 }
680 }
mallinath@webrtc.org3d81b1b2014-09-09 14:38:10 +0000681 return session_->SetIceTransports(config.type);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000682}
683
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000684bool PeerConnection::AddIceCandidate(
685 const IceCandidateInterface* ice_candidate) {
686 return session_->ProcessIceMessage(ice_candidate);
687}
688
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000689void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
690 uma_observer_ = observer;
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +0000691 // Send information about IPv4/IPv6 status.
692 if (uma_observer_ && port_allocator_) {
693 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +0000694 uma_observer_->IncrementCounter(kPeerConnection_IPv6);
mallinath@webrtc.orgb445f262014-05-23 22:19:37 +0000695 } else {
696 uma_observer_->IncrementCounter(kPeerConnection_IPv4);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +0000697 }
698 }
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000699}
700
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000701const SessionDescriptionInterface* PeerConnection::local_description() const {
702 return session_->local_description();
703}
704
705const SessionDescriptionInterface* PeerConnection::remote_description() const {
706 return session_->remote_description();
707}
708
709void PeerConnection::Close() {
710 // Update stats here so that we have the most recent stats for tracks and
711 // streams before the channels are closed.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000712 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000713
714 session_->Terminate();
715}
716
717void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
718 cricket::BaseSession::State state) {
719 switch (state) {
720 case cricket::BaseSession::STATE_INIT:
721 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000722 break;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000723 case cricket::BaseSession::STATE_SENTINITIATE:
724 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
725 break;
726 case cricket::BaseSession::STATE_SENTPRACCEPT:
727 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
728 break;
729 case cricket::BaseSession::STATE_RECEIVEDINITIATE:
730 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
731 break;
732 case cricket::BaseSession::STATE_RECEIVEDPRACCEPT:
733 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
734 break;
735 case cricket::BaseSession::STATE_SENTACCEPT:
736 case cricket::BaseSession::STATE_RECEIVEDACCEPT:
737 ChangeSignalingState(PeerConnectionInterface::kStable);
738 break;
739 case cricket::BaseSession::STATE_RECEIVEDTERMINATE:
740 ChangeSignalingState(PeerConnectionInterface::kClosed);
741 break;
742 default:
743 break;
744 }
745}
746
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000747void PeerConnection::OnMessage(rtc::Message* msg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000748 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000749 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
750 SetSessionDescriptionMsg* param =
751 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
752 param->observer->OnSuccess();
753 delete param;
754 break;
755 }
756 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
757 SetSessionDescriptionMsg* param =
758 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
759 param->observer->OnFailure(param->error);
760 delete param;
761 break;
762 }
763 case MSG_GETSTATS: {
764 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000765 StatsReports reports;
766 stats_->GetStats(param->track, &reports);
767 param->observer->OnComplete(reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000768 delete param;
769 break;
770 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000771 default:
772 ASSERT(false && "Not implemented");
773 break;
774 }
775}
776
777void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000778 stats_->AddStream(stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000779 observer_->OnAddStream(stream);
780}
781
782void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
783 stream_handler_container_->RemoveRemoteStream(stream);
784 observer_->OnRemoveStream(stream);
785}
786
787void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
788 observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
789 data_channel));
790}
791
792void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
793 AudioTrackInterface* audio_track,
794 uint32 ssrc) {
795 stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc);
796}
797
798void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
799 VideoTrackInterface* video_track,
800 uint32 ssrc) {
801 stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc);
802}
803
804void PeerConnection::OnRemoveRemoteAudioTrack(
805 MediaStreamInterface* stream,
806 AudioTrackInterface* audio_track) {
807 stream_handler_container_->RemoveRemoteTrack(stream, audio_track);
808}
809
810void PeerConnection::OnRemoveRemoteVideoTrack(
811 MediaStreamInterface* stream,
812 VideoTrackInterface* video_track) {
813 stream_handler_container_->RemoveRemoteTrack(stream, video_track);
814}
815void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
816 AudioTrackInterface* audio_track,
817 uint32 ssrc) {
818 stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc);
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000819 stats_->AddLocalAudioTrack(audio_track, ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000820}
821void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
822 VideoTrackInterface* video_track,
823 uint32 ssrc) {
824 stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc);
825}
826
827void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000828 AudioTrackInterface* audio_track,
829 uint32 ssrc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000830 stream_handler_container_->RemoveLocalTrack(stream, audio_track);
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000831 stats_->RemoveLocalAudioTrack(audio_track, ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000832}
833
834void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
835 VideoTrackInterface* video_track) {
836 stream_handler_container_->RemoveLocalTrack(stream, video_track);
837}
838
839void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
840 stream_handler_container_->RemoveLocalStream(stream);
841}
842
843void PeerConnection::OnIceConnectionChange(
844 PeerConnectionInterface::IceConnectionState new_state) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000845 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000846 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000847 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000848}
849
850void PeerConnection::OnIceGatheringChange(
851 PeerConnectionInterface::IceGatheringState new_state) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000852 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000853 if (IsClosed()) {
854 return;
855 }
856 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000857 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000858}
859
860void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000861 ASSERT(signaling_thread()->IsCurrent());
862 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000863}
864
865void PeerConnection::OnIceComplete() {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000866 ASSERT(signaling_thread()->IsCurrent());
867 observer_->OnIceComplete();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000868}
869
870void PeerConnection::ChangeSignalingState(
871 PeerConnectionInterface::SignalingState signaling_state) {
872 signaling_state_ = signaling_state;
873 if (signaling_state == kClosed) {
874 ice_connection_state_ = kIceConnectionClosed;
875 observer_->OnIceConnectionChange(ice_connection_state_);
876 if (ice_gathering_state_ != kIceGatheringComplete) {
877 ice_gathering_state_ = kIceGatheringComplete;
878 observer_->OnIceGatheringChange(ice_gathering_state_);
879 }
880 }
881 observer_->OnSignalingChange(signaling_state_);
882 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
883}
884
885} // namespace webrtc