blob: 4799489400db81fb4b0d6c9bce0d87e2286fd354 [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"
henrike@webrtc.org269fb4b2014-10-28 22:20:11 +000038#include "webrtc/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#include "webrtc/system_wrappers/interface/field_trial.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000043
44namespace {
45
46using webrtc::PeerConnectionInterface;
47
henrike@webrtc.org28e20752013-07-10 00:45:36 +000048// The min number of tokens must present in Turn host uri.
49// e.g. user@turn.example.org
50static const size_t kTurnHostTokensNum = 2;
51// Number of tokens must be preset when TURN uri has transport param.
52static const size_t kTurnTransportTokensNum = 2;
53// The default stun port.
wu@webrtc.org91053e72013-08-10 07:18:04 +000054static const int kDefaultStunPort = 3478;
55static const int kDefaultStunTlsPort = 5349;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056static const char kTransport[] = "transport";
wu@webrtc.org91053e72013-08-10 07:18:04 +000057static const char kUdpTransportType[] = "udp";
58static const char kTcpTransportType[] = "tcp";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000059
60// NOTE: Must be in the same order as the ServiceType enum.
61static const char* kValidIceServiceTypes[] = {
62 "stun", "stuns", "turn", "turns", "invalid" };
63
64enum ServiceType {
65 STUN, // Indicates a STUN server.
66 STUNS, // Indicates a STUN server used with a TLS session.
67 TURN, // Indicates a TURN server
68 TURNS, // Indicates a TURN server used with a TLS session.
69 INVALID, // Unknown.
70};
71
72enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +000073 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000074 MSG_SET_SESSIONDESCRIPTION_FAILED,
75 MSG_GETSTATS,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076};
77
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000078struct SetSessionDescriptionMsg : public rtc::MessageData {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000079 explicit SetSessionDescriptionMsg(
80 webrtc::SetSessionDescriptionObserver* observer)
81 : observer(observer) {
82 }
83
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000084 rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000085 std::string error;
86};
87
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000088struct GetStatsMsg : public rtc::MessageData {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +000089 GetStatsMsg(webrtc::StatsObserver* observer,
90 webrtc::MediaStreamTrackInterface* track)
91 : observer(observer), track(track) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000092 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000093 rtc::scoped_refptr<webrtc::StatsObserver> observer;
tommi@webrtc.org5b06b062014-08-15 08:38:30 +000094 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000095};
96
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +000097// |in_str| should be of format
98// stunURI = scheme ":" stun-host [ ":" stun-port ]
99// scheme = "stun" / "stuns"
100// stun-host = IP-literal / IPv4address / reg-name
101// stun-port = *DIGIT
102
103// draft-petithuguenin-behave-turn-uris-01
104// turnURI = scheme ":" turn-host [ ":" turn-port ]
105// turn-host = username@IP-literal / IPv4address / reg-name
106bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
107 ServiceType* service_type,
108 std::string* hostname) {
109 std::string::size_type colonpos = in_str.find(':');
110 if (colonpos == std::string::npos) {
111 return false;
112 }
113 std::string type = in_str.substr(0, colonpos);
114 for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
115 if (type.compare(kValidIceServiceTypes[i]) == 0) {
116 *service_type = static_cast<ServiceType>(i);
117 break;
118 }
119 }
120 if (*service_type == INVALID) {
121 return false;
122 }
123 *hostname = in_str.substr(colonpos + 1, std::string::npos);
124 return true;
125}
126
127// This method parses IPv6 and IPv4 literal strings, along with hostnames in
128// standard hostname:port format.
129// Consider following formats as correct.
130// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
131// |hostname|, |[IPv6 address]|, |IPv4 address|
132bool ParseHostnameAndPortFromString(const std::string& in_str,
133 std::string* host,
134 int* port) {
135 if (in_str.at(0) == '[') {
136 std::string::size_type closebracket = in_str.rfind(']');
137 if (closebracket != std::string::npos) {
138 *host = in_str.substr(1, closebracket - 1);
139 std::string::size_type colonpos = in_str.find(':', closebracket);
140 if (std::string::npos != colonpos) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000141 if (!rtc::FromString(
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000142 in_str.substr(closebracket + 2, std::string::npos), port)) {
143 return false;
144 }
145 }
146 } else {
147 return false;
148 }
149 } else {
150 std::string::size_type colonpos = in_str.find(':');
151 if (std::string::npos != colonpos) {
152 *host = in_str.substr(0, colonpos);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000153 if (!rtc::FromString(
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000154 in_str.substr(colonpos + 1, std::string::npos), port)) {
155 return false;
156 }
157 } else {
158 *host = in_str;
159 }
160 }
161 return true;
162}
163
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000164typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
165 StunConfiguration;
166typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
167 TurnConfiguration;
168
169bool ParseIceServers(const PeerConnectionInterface::IceServers& configuration,
170 std::vector<StunConfiguration>* stun_config,
171 std::vector<TurnConfiguration>* turn_config) {
172 // draft-nandakumar-rtcweb-stun-uri-01
173 // stunURI = scheme ":" stun-host [ ":" stun-port ]
174 // scheme = "stun" / "stuns"
175 // stun-host = IP-literal / IPv4address / reg-name
176 // stun-port = *DIGIT
177
178 // draft-petithuguenin-behave-turn-uris-01
179 // turnURI = scheme ":" turn-host [ ":" turn-port ]
180 // [ "?transport=" transport ]
181 // scheme = "turn" / "turns"
182 // transport = "udp" / "tcp" / transport-ext
183 // transport-ext = 1*unreserved
184 // turn-host = IP-literal / IPv4address / reg-name
185 // turn-port = *DIGIT
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000186 for (size_t i = 0; i < configuration.size(); ++i) {
187 webrtc::PeerConnectionInterface::IceServer server = configuration[i];
188 if (server.uri.empty()) {
189 LOG(WARNING) << "Empty uri.";
190 continue;
191 }
192 std::vector<std::string> tokens;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000193 std::string turn_transport_type = kUdpTransportType;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000194 rtc::tokenize(server.uri, '?', &tokens);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000195 std::string uri_without_transport = tokens[0];
196 // Let's look into transport= param, if it exists.
197 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
198 std::string uri_transport_param = tokens[1];
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000199 rtc::tokenize(uri_transport_param, '=', &tokens);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000200 if (tokens[0] == kTransport) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000201 // As per above grammar transport param will be consist of lower case
202 // letters.
203 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
204 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
205 continue;
206 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000207 turn_transport_type = tokens[1];
208 }
209 }
210
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000211 std::string hoststring;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000212 ServiceType service_type = INVALID;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000213 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
214 &service_type,
215 &hoststring)) {
216 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: "
217 << uri_without_transport;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000218 continue;
219 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000220
221 // Let's break hostname.
222 tokens.clear();
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000223 rtc::tokenize(hoststring, '@', &tokens);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000224 hoststring = tokens[0];
225 if (tokens.size() == kTurnHostTokensNum) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000226 server.username = rtc::s_url_decode(tokens[0]);
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000227 hoststring = tokens[1];
228 }
229
wu@webrtc.org91053e72013-08-10 07:18:04 +0000230 int port = kDefaultStunPort;
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000231 if (service_type == TURNS) {
232 port = kDefaultStunTlsPort;
233 turn_transport_type = kTcpTransportType;
234 }
235
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000236 std::string address;
237 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
238 LOG(WARNING) << "Invalid Hostname format: " << uri_without_transport;
239 continue;
240 }
241
wu@webrtc.org91053e72013-08-10 07:18:04 +0000242
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000243 if (port <= 0 || port > 0xffff) {
244 LOG(WARNING) << "Invalid port: " << port;
245 continue;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000246 }
247
248 switch (service_type) {
249 case STUN:
250 case STUNS:
251 stun_config->push_back(StunConfiguration(address, port));
252 break;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000253 case TURN:
254 case TURNS: {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000255 if (server.username.empty()) {
256 // Turn url example from the spec |url:"turn:user@turn.example.org"|.
257 std::vector<std::string> turn_tokens;
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000258 rtc::tokenize(address, '@', &turn_tokens);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000259 if (turn_tokens.size() == kTurnHostTokensNum) {
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000260 server.username = rtc::s_url_decode(turn_tokens[0]);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000261 address = turn_tokens[1];
262 }
263 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000264
265 bool secure = (service_type == TURNS);
266
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000267 turn_config->push_back(TurnConfiguration(address, port,
268 server.username,
269 server.password,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000270 turn_transport_type,
271 secure));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000272 break;
273 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000274 case INVALID:
275 default:
276 LOG(WARNING) << "Configuration not supported: " << server.uri;
277 return false;
278 }
279 }
280 return true;
281}
282
283// Check if we can send |new_stream| on a PeerConnection.
284// Currently only one audio but multiple video track is supported per
285// PeerConnection.
286bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
287 webrtc::MediaStreamInterface* new_stream) {
288 if (!new_stream || !current_streams)
289 return false;
290 if (current_streams->find(new_stream->label()) != NULL) {
291 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
292 << " is already added.";
293 return false;
294 }
295
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000296 return true;
297}
298
299} // namespace
300
301namespace webrtc {
302
303PeerConnection::PeerConnection(PeerConnectionFactory* factory)
304 : factory_(factory),
305 observer_(NULL),
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000306 uma_observer_(NULL),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000307 signaling_state_(kStable),
308 ice_state_(kIceNew),
309 ice_connection_state_(kIceConnectionNew),
310 ice_gathering_state_(kIceGatheringNew) {
311}
312
313PeerConnection::~PeerConnection() {
314 if (mediastream_signaling_)
315 mediastream_signaling_->TearDown();
316 if (stream_handler_container_)
317 stream_handler_container_->TearDown();
318}
319
320bool PeerConnection::Initialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000321 const PeerConnectionInterface::RTCConfiguration& configuration,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000322 const MediaConstraintsInterface* constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000323 PortAllocatorFactoryInterface* allocator_factory,
324 DTLSIdentityServiceInterface* dtls_identity_service,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000325 PeerConnectionObserver* observer) {
326 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
327 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000328 if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000329 return false;
330 }
331
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000332 return DoInitialize(configuration.type, stun_config, turn_config, constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000333 allocator_factory, dtls_identity_service, observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000334}
335
336bool PeerConnection::DoInitialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000337 IceTransportsType type,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000338 const StunConfigurations& stun_config,
339 const TurnConfigurations& turn_config,
340 const MediaConstraintsInterface* constraints,
341 webrtc::PortAllocatorFactoryInterface* allocator_factory,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000342 DTLSIdentityServiceInterface* dtls_identity_service,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000343 PeerConnectionObserver* observer) {
344 ASSERT(observer != NULL);
345 if (!observer)
346 return false;
347 observer_ = observer;
348 port_allocator_.reset(
349 allocator_factory->CreatePortAllocator(stun_config, turn_config));
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000350
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000351 // To handle both internal and externally created port allocator, we will
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000352 // enable BUNDLE here.
braveyao@webrtc.org1732df62014-10-27 03:01:37 +0000353 int portallocator_flags = port_allocator_->flags();
354 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_BUNDLE |
355 cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
356 cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000357 bool value;
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000358 // If IPv6 flag was specified, we'll not override it by experiment.
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000359 if (FindConstraint(
guoweis@webrtc.org97ed3932014-09-19 21:06:12 +0000360 constraints, MediaConstraintsInterface::kEnableIPv6, &value, NULL)) {
361 if (value) {
362 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6;
363 }
guoweis@webrtc.org2c1bcea2014-09-23 16:23:02 +0000364 } else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default") ==
365 "Enabled") {
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000366 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6;
367 }
368
369 port_allocator_->set_flags(portallocator_flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000370 // No step delay is used while allocating ports.
371 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
372
373 mediastream_signaling_.reset(new MediaStreamSignaling(
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000374 factory_->signaling_thread(), this, factory_->channel_manager()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000375
376 session_.reset(new WebRtcSession(factory_->channel_manager(),
377 factory_->signaling_thread(),
378 factory_->worker_thread(),
379 port_allocator_.get(),
380 mediastream_signaling_.get()));
381 stream_handler_container_.reset(new MediaStreamHandlerContainer(
382 session_.get(), session_.get()));
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000383 stats_.reset(new StatsCollector(session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000384
385 // Initialize the WebRtcSession. It creates transport channels etc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000386 if (!session_->Initialize(factory_->options(), constraints,
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000387 dtls_identity_service, type))
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000388 return false;
389
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000390 // Register PeerConnection as receiver of local ice candidates.
391 // All the callbacks will be posted to the application from PeerConnection.
392 session_->RegisterIceObserver(this);
393 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
394 return true;
395}
396
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000397rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000398PeerConnection::local_streams() {
399 return mediastream_signaling_->local_streams();
400}
401
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000402rtc::scoped_refptr<StreamCollectionInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000403PeerConnection::remote_streams() {
404 return mediastream_signaling_->remote_streams();
405}
406
407bool PeerConnection::AddStream(MediaStreamInterface* local_stream,
408 const MediaConstraintsInterface* constraints) {
409 if (IsClosed()) {
410 return false;
411 }
412 if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(),
413 local_stream))
414 return false;
415
416 // TODO(perkj): Implement support for MediaConstraints in AddStream.
417 if (!mediastream_signaling_->AddLocalStream(local_stream)) {
418 return false;
419 }
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000420 stats_->AddStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000421 observer_->OnRenegotiationNeeded();
422 return true;
423}
424
425void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000426 mediastream_signaling_->RemoveLocalStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000427 if (IsClosed()) {
428 return;
429 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000430 observer_->OnRenegotiationNeeded();
431}
432
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000433rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000434 AudioTrackInterface* track) {
435 if (!track) {
436 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
437 return NULL;
438 }
439 if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) {
440 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
441 return NULL;
442 }
443
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000444 rtc::scoped_refptr<DtmfSenderInterface> sender(
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000445 DtmfSender::Create(track, signaling_thread(), session_.get()));
446 if (!sender.get()) {
447 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
448 return NULL;
449 }
450 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
451}
452
453bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000454 MediaStreamTrackInterface* track,
455 StatsOutputLevel level) {
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000456 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000457 if (!VERIFY(observer != NULL)) {
458 LOG(LS_ERROR) << "GetStats - observer is NULL.";
459 return false;
460 }
461
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000462 stats_->UpdateStats(level);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000463 signaling_thread()->Post(this, MSG_GETSTATS,
464 new GetStatsMsg(observer, track));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000465 return true;
466}
467
468PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
469 return signaling_state_;
470}
471
472PeerConnectionInterface::IceState PeerConnection::ice_state() {
473 return ice_state_;
474}
475
476PeerConnectionInterface::IceConnectionState
477PeerConnection::ice_connection_state() {
478 return ice_connection_state_;
479}
480
481PeerConnectionInterface::IceGatheringState
482PeerConnection::ice_gathering_state() {
483 return ice_gathering_state_;
484}
485
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000486rtc::scoped_refptr<DataChannelInterface>
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000487PeerConnection::CreateDataChannel(
488 const std::string& label,
489 const DataChannelInit* config) {
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000490 bool first_datachannel = !mediastream_signaling_->HasDataChannels();
491
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000492 rtc::scoped_ptr<InternalDataChannelInit> internal_config;
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000493 if (config) {
494 internal_config.reset(new InternalDataChannelInit(*config));
495 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000496 rtc::scoped_refptr<DataChannelInterface> channel(
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000497 session_->CreateDataChannel(label, internal_config.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000498 if (!channel.get())
499 return NULL;
500
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000501 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
502 // the first SCTP DataChannel.
503 if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
504 observer_->OnRenegotiationNeeded();
505 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000506
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000507 return DataChannelProxy::Create(signaling_thread(), channel.get());
508}
509
510void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
511 const MediaConstraintsInterface* constraints) {
512 if (!VERIFY(observer != NULL)) {
513 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
514 return;
515 }
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000516 RTCOfferAnswerOptions options;
jiayl@webrtc.orgb18bf5e2014-08-04 18:34:16 +0000517
518 bool value;
519 size_t mandatory_constraints = 0;
520
521 if (FindConstraint(constraints,
522 MediaConstraintsInterface::kOfferToReceiveAudio,
523 &value,
524 &mandatory_constraints)) {
525 options.offer_to_receive_audio =
526 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
527 }
528
529 if (FindConstraint(constraints,
530 MediaConstraintsInterface::kOfferToReceiveVideo,
531 &value,
532 &mandatory_constraints)) {
533 options.offer_to_receive_video =
534 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
535 }
536
537 if (FindConstraint(constraints,
538 MediaConstraintsInterface::kVoiceActivityDetection,
539 &value,
540 &mandatory_constraints)) {
541 options.voice_activity_detection = value;
542 }
543
544 if (FindConstraint(constraints,
545 MediaConstraintsInterface::kIceRestart,
546 &value,
547 &mandatory_constraints)) {
548 options.ice_restart = value;
549 }
550
551 if (FindConstraint(constraints,
552 MediaConstraintsInterface::kUseRtpMux,
553 &value,
554 &mandatory_constraints)) {
555 options.use_rtp_mux = value;
556 }
557
558 CreateOffer(observer, options);
559}
560
561void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
562 const RTCOfferAnswerOptions& options) {
563 if (!VERIFY(observer != NULL)) {
564 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
565 return;
566 }
567 session_->CreateOffer(observer, options);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000568}
569
570void PeerConnection::CreateAnswer(
571 CreateSessionDescriptionObserver* observer,
572 const MediaConstraintsInterface* constraints) {
573 if (!VERIFY(observer != NULL)) {
574 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
575 return;
576 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000577 session_->CreateAnswer(observer, constraints);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000578}
579
580void PeerConnection::SetLocalDescription(
581 SetSessionDescriptionObserver* observer,
582 SessionDescriptionInterface* desc) {
583 if (!VERIFY(observer != NULL)) {
584 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
585 return;
586 }
587 if (!desc) {
588 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
589 return;
590 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000591 // Update stats here so that we have the most recent stats for tracks and
592 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000593 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000594 std::string error;
595 if (!session_->SetLocalDescription(desc, &error)) {
596 PostSetSessionDescriptionFailure(observer, error);
597 return;
598 }
599 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
600 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
601}
602
603void PeerConnection::SetRemoteDescription(
604 SetSessionDescriptionObserver* observer,
605 SessionDescriptionInterface* desc) {
606 if (!VERIFY(observer != NULL)) {
607 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
608 return;
609 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000610 if (!desc) {
611 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
612 return;
613 }
614 // Update stats here so that we have the most recent stats for tracks and
615 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000616 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617 std::string error;
618 if (!session_->SetRemoteDescription(desc, &error)) {
619 PostSetSessionDescriptionFailure(observer, error);
620 return;
621 }
622 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
623 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
624}
625
626void PeerConnection::PostSetSessionDescriptionFailure(
627 SetSessionDescriptionObserver* observer,
628 const std::string& error) {
629 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
630 msg->error = error;
631 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
632}
633
634bool PeerConnection::UpdateIce(const IceServers& configuration,
635 const MediaConstraintsInterface* constraints) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000636 return false;
637}
638
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000639bool PeerConnection::UpdateIce(const RTCConfiguration& config) {
640 if (port_allocator_) {
641 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
642 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
643 if (!ParseIceServers(config.servers, &stuns, &turns)) {
644 return false;
645 }
646
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000647 std::vector<rtc::SocketAddress> stun_hosts;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000648 typedef std::vector<StunConfiguration>::const_iterator StunIt;
649 for (StunIt stun_it = stuns.begin(); stun_it != stuns.end(); ++stun_it) {
650 stun_hosts.push_back(stun_it->server);
651 }
652
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000653 rtc::SocketAddress stun_addr;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000654 if (!stun_hosts.empty()) {
655 stun_addr = stun_hosts.front();
656 LOG(LS_INFO) << "UpdateIce: StunServer Address: " << stun_addr.ToString();
657 }
658
659 for (size_t i = 0; i < turns.size(); ++i) {
660 cricket::RelayCredentials credentials(turns[i].username,
661 turns[i].password);
662 cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
663 cricket::ProtocolType protocol;
664 if (cricket::StringToProto(turns[i].transport_type.c_str(), &protocol)) {
665 relay_server.ports.push_back(cricket::ProtocolAddress(
666 turns[i].server, protocol, turns[i].secure));
667 relay_server.credentials = credentials;
668 LOG(LS_INFO) << "UpdateIce: TurnServer Address: "
669 << turns[i].server.ToString();
670 } else {
671 LOG(LS_WARNING) << "Ignoring TURN server " << turns[i].server << ". "
672 << "Reason= Incorrect " << turns[i].transport_type
673 << " transport parameter.";
674 }
675 }
676 }
mallinath@webrtc.org3d81b1b2014-09-09 14:38:10 +0000677 return session_->SetIceTransports(config.type);
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000678}
679
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000680bool PeerConnection::AddIceCandidate(
681 const IceCandidateInterface* ice_candidate) {
682 return session_->ProcessIceMessage(ice_candidate);
683}
684
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000685void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
686 uma_observer_ = observer;
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +0000687 // Send information about IPv4/IPv6 status.
688 if (uma_observer_ && port_allocator_) {
689 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +0000690 uma_observer_->IncrementCounter(kPeerConnection_IPv6);
mallinath@webrtc.orgb445f262014-05-23 22:19:37 +0000691 } else {
692 uma_observer_->IncrementCounter(kPeerConnection_IPv4);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +0000693 }
694 }
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000695}
696
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000697const SessionDescriptionInterface* PeerConnection::local_description() const {
698 return session_->local_description();
699}
700
701const SessionDescriptionInterface* PeerConnection::remote_description() const {
702 return session_->remote_description();
703}
704
705void PeerConnection::Close() {
706 // Update stats here so that we have the most recent stats for tracks and
707 // streams before the channels are closed.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000708 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000709
710 session_->Terminate();
711}
712
713void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
714 cricket::BaseSession::State state) {
715 switch (state) {
716 case cricket::BaseSession::STATE_INIT:
717 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000718 break;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000719 case cricket::BaseSession::STATE_SENTINITIATE:
720 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
721 break;
722 case cricket::BaseSession::STATE_SENTPRACCEPT:
723 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
724 break;
725 case cricket::BaseSession::STATE_RECEIVEDINITIATE:
726 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
727 break;
728 case cricket::BaseSession::STATE_RECEIVEDPRACCEPT:
729 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
730 break;
731 case cricket::BaseSession::STATE_SENTACCEPT:
732 case cricket::BaseSession::STATE_RECEIVEDACCEPT:
733 ChangeSignalingState(PeerConnectionInterface::kStable);
734 break;
735 case cricket::BaseSession::STATE_RECEIVEDTERMINATE:
736 ChangeSignalingState(PeerConnectionInterface::kClosed);
737 break;
738 default:
739 break;
740 }
741}
742
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000743void PeerConnection::OnMessage(rtc::Message* msg) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000744 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000745 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
746 SetSessionDescriptionMsg* param =
747 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
748 param->observer->OnSuccess();
749 delete param;
750 break;
751 }
752 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
753 SetSessionDescriptionMsg* param =
754 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
755 param->observer->OnFailure(param->error);
756 delete param;
757 break;
758 }
759 case MSG_GETSTATS: {
760 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
tommi@webrtc.org5b06b062014-08-15 08:38:30 +0000761 StatsReports reports;
762 stats_->GetStats(param->track, &reports);
763 param->observer->OnComplete(reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000764 delete param;
765 break;
766 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000767 default:
768 ASSERT(false && "Not implemented");
769 break;
770 }
771}
772
773void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000774 stats_->AddStream(stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000775 observer_->OnAddStream(stream);
776}
777
778void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
779 stream_handler_container_->RemoveRemoteStream(stream);
780 observer_->OnRemoveStream(stream);
781}
782
783void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
784 observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
785 data_channel));
786}
787
788void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
789 AudioTrackInterface* audio_track,
790 uint32 ssrc) {
791 stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc);
792}
793
794void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
795 VideoTrackInterface* video_track,
796 uint32 ssrc) {
797 stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc);
798}
799
800void PeerConnection::OnRemoveRemoteAudioTrack(
801 MediaStreamInterface* stream,
802 AudioTrackInterface* audio_track) {
803 stream_handler_container_->RemoveRemoteTrack(stream, audio_track);
804}
805
806void PeerConnection::OnRemoveRemoteVideoTrack(
807 MediaStreamInterface* stream,
808 VideoTrackInterface* video_track) {
809 stream_handler_container_->RemoveRemoteTrack(stream, video_track);
810}
811void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
812 AudioTrackInterface* audio_track,
813 uint32 ssrc) {
814 stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc);
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000815 stats_->AddLocalAudioTrack(audio_track, ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000816}
817void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
818 VideoTrackInterface* video_track,
819 uint32 ssrc) {
820 stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc);
821}
822
823void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000824 AudioTrackInterface* audio_track,
825 uint32 ssrc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000826 stream_handler_container_->RemoveLocalTrack(stream, audio_track);
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000827 stats_->RemoveLocalAudioTrack(audio_track, ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000828}
829
830void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
831 VideoTrackInterface* video_track) {
832 stream_handler_container_->RemoveLocalTrack(stream, video_track);
833}
834
835void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
836 stream_handler_container_->RemoveLocalStream(stream);
837}
838
839void PeerConnection::OnIceConnectionChange(
840 PeerConnectionInterface::IceConnectionState new_state) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000841 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000842 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000843 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000844}
845
846void PeerConnection::OnIceGatheringChange(
847 PeerConnectionInterface::IceGatheringState new_state) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000848 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000849 if (IsClosed()) {
850 return;
851 }
852 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000853 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000854}
855
856void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000857 ASSERT(signaling_thread()->IsCurrent());
858 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000859}
860
861void PeerConnection::OnIceComplete() {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000862 ASSERT(signaling_thread()->IsCurrent());
863 observer_->OnIceComplete();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000864}
865
866void PeerConnection::ChangeSignalingState(
867 PeerConnectionInterface::SignalingState signaling_state) {
868 signaling_state_ = signaling_state;
869 if (signaling_state == kClosed) {
870 ice_connection_state_ = kIceConnectionClosed;
871 observer_->OnIceConnectionChange(ice_connection_state_);
872 if (ice_gathering_state_ != kIceGatheringComplete) {
873 ice_gathering_state_ = kIceGatheringComplete;
874 observer_->OnIceGatheringChange(ice_gathering_state_);
875 }
876 }
877 observer_->OnSignalingChange(signaling_state_);
878 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
879}
880
881} // namespace webrtc