blob: bb5f0d40a0e7c86284bed010eea1f624db645604 [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"
38#include "talk/base/logging.h"
39#include "talk/base/stringencode.h"
buildbot@webrtc.org41451d42014-05-03 05:39:45 +000040#include "talk/p2p/client/basicportallocator.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000041#include "talk/session/media/channelmanager.h"
42
43namespace {
44
45using webrtc::PeerConnectionInterface;
46
henrike@webrtc.org28e20752013-07-10 00:45:36 +000047// The min number of tokens must present in Turn host uri.
48// e.g. user@turn.example.org
49static const size_t kTurnHostTokensNum = 2;
50// Number of tokens must be preset when TURN uri has transport param.
51static const size_t kTurnTransportTokensNum = 2;
52// The default stun port.
wu@webrtc.org91053e72013-08-10 07:18:04 +000053static const int kDefaultStunPort = 3478;
54static const int kDefaultStunTlsPort = 5349;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000055static const char kTransport[] = "transport";
wu@webrtc.org91053e72013-08-10 07:18:04 +000056static const char kUdpTransportType[] = "udp";
57static const char kTcpTransportType[] = "tcp";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000058
59// NOTE: Must be in the same order as the ServiceType enum.
60static const char* kValidIceServiceTypes[] = {
61 "stun", "stuns", "turn", "turns", "invalid" };
62
63enum ServiceType {
64 STUN, // Indicates a STUN server.
65 STUNS, // Indicates a STUN server used with a TLS session.
66 TURN, // Indicates a TURN server
67 TURNS, // Indicates a TURN server used with a TLS session.
68 INVALID, // Unknown.
69};
70
71enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +000072 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073 MSG_SET_SESSIONDESCRIPTION_FAILED,
74 MSG_GETSTATS,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000075};
76
henrike@webrtc.org28e20752013-07-10 00:45:36 +000077struct SetSessionDescriptionMsg : public talk_base::MessageData {
78 explicit SetSessionDescriptionMsg(
79 webrtc::SetSessionDescriptionObserver* observer)
80 : observer(observer) {
81 }
82
83 talk_base::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
84 std::string error;
85};
86
87struct GetStatsMsg : public talk_base::MessageData {
tommi@webrtc.org190d2692014-07-25 10:32:30 +000088 GetStatsMsg(webrtc::StatsObserver* observer,
89 webrtc::MediaStreamTrackInterface* track)
90 : observer(observer), track(track) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000091 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +000092 talk_base::scoped_refptr<webrtc::StatsObserver> observer;
tommi@webrtc.org190d2692014-07-25 10:32:30 +000093 talk_base::scoped_refptr<webrtc::MediaStreamTrackInterface> track;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000094};
95
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +000096// |in_str| should be of format
97// stunURI = scheme ":" stun-host [ ":" stun-port ]
98// scheme = "stun" / "stuns"
99// stun-host = IP-literal / IPv4address / reg-name
100// stun-port = *DIGIT
101
102// draft-petithuguenin-behave-turn-uris-01
103// turnURI = scheme ":" turn-host [ ":" turn-port ]
104// turn-host = username@IP-literal / IPv4address / reg-name
105bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
106 ServiceType* service_type,
107 std::string* hostname) {
108 std::string::size_type colonpos = in_str.find(':');
109 if (colonpos == std::string::npos) {
110 return false;
111 }
112 std::string type = in_str.substr(0, colonpos);
113 for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
114 if (type.compare(kValidIceServiceTypes[i]) == 0) {
115 *service_type = static_cast<ServiceType>(i);
116 break;
117 }
118 }
119 if (*service_type == INVALID) {
120 return false;
121 }
122 *hostname = in_str.substr(colonpos + 1, std::string::npos);
123 return true;
124}
125
126// This method parses IPv6 and IPv4 literal strings, along with hostnames in
127// standard hostname:port format.
128// Consider following formats as correct.
129// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
130// |hostname|, |[IPv6 address]|, |IPv4 address|
131bool ParseHostnameAndPortFromString(const std::string& in_str,
132 std::string* host,
133 int* port) {
134 if (in_str.at(0) == '[') {
135 std::string::size_type closebracket = in_str.rfind(']');
136 if (closebracket != std::string::npos) {
137 *host = in_str.substr(1, closebracket - 1);
138 std::string::size_type colonpos = in_str.find(':', closebracket);
139 if (std::string::npos != colonpos) {
140 if (!talk_base::FromString(
141 in_str.substr(closebracket + 2, std::string::npos), port)) {
142 return false;
143 }
144 }
145 } else {
146 return false;
147 }
148 } else {
149 std::string::size_type colonpos = in_str.find(':');
150 if (std::string::npos != colonpos) {
151 *host = in_str.substr(0, colonpos);
152 if (!talk_base::FromString(
153 in_str.substr(colonpos + 1, std::string::npos), port)) {
154 return false;
155 }
156 } else {
157 *host = in_str;
158 }
159 }
160 return true;
161}
162
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000163typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
164 StunConfiguration;
165typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
166 TurnConfiguration;
167
168bool ParseIceServers(const PeerConnectionInterface::IceServers& configuration,
169 std::vector<StunConfiguration>* stun_config,
170 std::vector<TurnConfiguration>* turn_config) {
171 // draft-nandakumar-rtcweb-stun-uri-01
172 // stunURI = scheme ":" stun-host [ ":" stun-port ]
173 // scheme = "stun" / "stuns"
174 // stun-host = IP-literal / IPv4address / reg-name
175 // stun-port = *DIGIT
176
177 // draft-petithuguenin-behave-turn-uris-01
178 // turnURI = scheme ":" turn-host [ ":" turn-port ]
179 // [ "?transport=" transport ]
180 // scheme = "turn" / "turns"
181 // transport = "udp" / "tcp" / transport-ext
182 // transport-ext = 1*unreserved
183 // turn-host = IP-literal / IPv4address / reg-name
184 // turn-port = *DIGIT
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000185 for (size_t i = 0; i < configuration.size(); ++i) {
186 webrtc::PeerConnectionInterface::IceServer server = configuration[i];
187 if (server.uri.empty()) {
188 LOG(WARNING) << "Empty uri.";
189 continue;
190 }
191 std::vector<std::string> tokens;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000192 std::string turn_transport_type = kUdpTransportType;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000193 talk_base::tokenize(server.uri, '?', &tokens);
194 std::string uri_without_transport = tokens[0];
195 // Let's look into transport= param, if it exists.
196 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
197 std::string uri_transport_param = tokens[1];
198 talk_base::tokenize(uri_transport_param, '=', &tokens);
199 if (tokens[0] == kTransport) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000200 // As per above grammar transport param will be consist of lower case
201 // letters.
202 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
203 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
204 continue;
205 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000206 turn_transport_type = tokens[1];
207 }
208 }
209
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000210 std::string hoststring;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000211 ServiceType service_type = INVALID;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000212 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
213 &service_type,
214 &hoststring)) {
215 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: "
216 << uri_without_transport;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000217 continue;
218 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000219
220 // Let's break hostname.
221 tokens.clear();
222 talk_base::tokenize(hoststring, '@', &tokens);
223 hoststring = tokens[0];
224 if (tokens.size() == kTurnHostTokensNum) {
225 server.username = talk_base::s_url_decode(tokens[0]);
226 hoststring = tokens[1];
227 }
228
wu@webrtc.org91053e72013-08-10 07:18:04 +0000229 int port = kDefaultStunPort;
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000230 if (service_type == TURNS) {
231 port = kDefaultStunTlsPort;
232 turn_transport_type = kTcpTransportType;
233 }
234
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000235 std::string address;
236 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
237 LOG(WARNING) << "Invalid Hostname format: " << uri_without_transport;
238 continue;
239 }
240
wu@webrtc.org91053e72013-08-10 07:18:04 +0000241
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000242 if (port <= 0 || port > 0xffff) {
243 LOG(WARNING) << "Invalid port: " << port;
244 continue;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000245 }
246
247 switch (service_type) {
248 case STUN:
249 case STUNS:
250 stun_config->push_back(StunConfiguration(address, port));
251 break;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000252 case TURN:
253 case TURNS: {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000254 if (server.username.empty()) {
255 // Turn url example from the spec |url:"turn:user@turn.example.org"|.
256 std::vector<std::string> turn_tokens;
257 talk_base::tokenize(address, '@', &turn_tokens);
258 if (turn_tokens.size() == kTurnHostTokensNum) {
259 server.username = talk_base::s_url_decode(turn_tokens[0]);
260 address = turn_tokens[1];
261 }
262 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000263
264 bool secure = (service_type == TURNS);
265
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000266 turn_config->push_back(TurnConfiguration(address, port,
267 server.username,
268 server.password,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000269 turn_transport_type,
270 secure));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000271 break;
272 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000273 case INVALID:
274 default:
275 LOG(WARNING) << "Configuration not supported: " << server.uri;
276 return false;
277 }
278 }
279 return true;
280}
281
282// Check if we can send |new_stream| on a PeerConnection.
283// Currently only one audio but multiple video track is supported per
284// PeerConnection.
285bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
286 webrtc::MediaStreamInterface* new_stream) {
287 if (!new_stream || !current_streams)
288 return false;
289 if (current_streams->find(new_stream->label()) != NULL) {
290 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
291 << " is already added.";
292 return false;
293 }
294
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000295 return true;
296}
297
298} // namespace
299
300namespace webrtc {
301
302PeerConnection::PeerConnection(PeerConnectionFactory* factory)
303 : factory_(factory),
304 observer_(NULL),
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000305 uma_observer_(NULL),
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000306 signaling_state_(kStable),
307 ice_state_(kIceNew),
308 ice_connection_state_(kIceConnectionNew),
309 ice_gathering_state_(kIceGatheringNew) {
310}
311
312PeerConnection::~PeerConnection() {
313 if (mediastream_signaling_)
314 mediastream_signaling_->TearDown();
315 if (stream_handler_container_)
316 stream_handler_container_->TearDown();
317}
318
319bool PeerConnection::Initialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000320 const PeerConnectionInterface::RTCConfiguration& configuration,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000321 const MediaConstraintsInterface* constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000322 PortAllocatorFactoryInterface* allocator_factory,
323 DTLSIdentityServiceInterface* dtls_identity_service,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000324 PeerConnectionObserver* observer) {
325 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
326 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000327 if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000328 return false;
329 }
330
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000331 return DoInitialize(configuration.type, stun_config, turn_config, constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000332 allocator_factory, dtls_identity_service, observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000333}
334
335bool PeerConnection::DoInitialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000336 IceTransportsType type,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000337 const StunConfigurations& stun_config,
338 const TurnConfigurations& turn_config,
339 const MediaConstraintsInterface* constraints,
340 webrtc::PortAllocatorFactoryInterface* allocator_factory,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000341 DTLSIdentityServiceInterface* dtls_identity_service,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000342 PeerConnectionObserver* observer) {
343 ASSERT(observer != NULL);
344 if (!observer)
345 return false;
346 observer_ = observer;
347 port_allocator_.reset(
348 allocator_factory->CreatePortAllocator(stun_config, turn_config));
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000349
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000350 // To handle both internal and externally created port allocator, we will
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000351 // enable BUNDLE here.
352 int portallocator_flags = cricket::PORTALLOCATOR_ENABLE_BUNDLE |
353 cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
354 cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET;
355 bool value;
356 if (FindConstraint(
357 constraints,
358 MediaConstraintsInterface::kEnableIPv6,
359 &value, NULL) && value) {
360 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6;
361 }
362
363 port_allocator_->set_flags(portallocator_flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000364 // No step delay is used while allocating ports.
365 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
366
367 mediastream_signaling_.reset(new MediaStreamSignaling(
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000368 factory_->signaling_thread(), this, factory_->channel_manager()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000369
370 session_.reset(new WebRtcSession(factory_->channel_manager(),
371 factory_->signaling_thread(),
372 factory_->worker_thread(),
373 port_allocator_.get(),
374 mediastream_signaling_.get()));
375 stream_handler_container_.reset(new MediaStreamHandlerContainer(
376 session_.get(), session_.get()));
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000377 stats_.reset(new StatsCollector(session_.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000378
379 // Initialize the WebRtcSession. It creates transport channels etc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000380 if (!session_->Initialize(factory_->options(), constraints,
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000381 dtls_identity_service, type))
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000382 return false;
383
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000384 // Register PeerConnection as receiver of local ice candidates.
385 // All the callbacks will be posted to the application from PeerConnection.
386 session_->RegisterIceObserver(this);
387 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
388 return true;
389}
390
391talk_base::scoped_refptr<StreamCollectionInterface>
392PeerConnection::local_streams() {
393 return mediastream_signaling_->local_streams();
394}
395
396talk_base::scoped_refptr<StreamCollectionInterface>
397PeerConnection::remote_streams() {
398 return mediastream_signaling_->remote_streams();
399}
400
401bool PeerConnection::AddStream(MediaStreamInterface* local_stream,
402 const MediaConstraintsInterface* constraints) {
403 if (IsClosed()) {
404 return false;
405 }
406 if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(),
407 local_stream))
408 return false;
409
410 // TODO(perkj): Implement support for MediaConstraints in AddStream.
411 if (!mediastream_signaling_->AddLocalStream(local_stream)) {
412 return false;
413 }
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000414 stats_->AddStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000415 observer_->OnRenegotiationNeeded();
416 return true;
417}
418
419void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000420 mediastream_signaling_->RemoveLocalStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000421 if (IsClosed()) {
422 return;
423 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000424 observer_->OnRenegotiationNeeded();
425}
426
427talk_base::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
428 AudioTrackInterface* track) {
429 if (!track) {
430 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
431 return NULL;
432 }
433 if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) {
434 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
435 return NULL;
436 }
437
438 talk_base::scoped_refptr<DtmfSenderInterface> sender(
439 DtmfSender::Create(track, signaling_thread(), session_.get()));
440 if (!sender.get()) {
441 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
442 return NULL;
443 }
444 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
445}
446
447bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000448 MediaStreamTrackInterface* track,
449 StatsOutputLevel level) {
tommi@webrtc.org190d2692014-07-25 10:32:30 +0000450 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000451 if (!VERIFY(observer != NULL)) {
452 LOG(LS_ERROR) << "GetStats - observer is NULL.";
453 return false;
454 }
455
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000456 stats_->UpdateStats(level);
tommi@webrtc.org190d2692014-07-25 10:32:30 +0000457 signaling_thread()->Post(this, MSG_GETSTATS,
458 new GetStatsMsg(observer, track));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000459 return true;
460}
461
462PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
463 return signaling_state_;
464}
465
466PeerConnectionInterface::IceState PeerConnection::ice_state() {
467 return ice_state_;
468}
469
470PeerConnectionInterface::IceConnectionState
471PeerConnection::ice_connection_state() {
472 return ice_connection_state_;
473}
474
475PeerConnectionInterface::IceGatheringState
476PeerConnection::ice_gathering_state() {
477 return ice_gathering_state_;
478}
479
480talk_base::scoped_refptr<DataChannelInterface>
481PeerConnection::CreateDataChannel(
482 const std::string& label,
483 const DataChannelInit* config) {
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000484 bool first_datachannel = !mediastream_signaling_->HasDataChannels();
485
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000486 talk_base::scoped_ptr<InternalDataChannelInit> internal_config;
487 if (config) {
488 internal_config.reset(new InternalDataChannelInit(*config));
489 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000490 talk_base::scoped_refptr<DataChannelInterface> channel(
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000491 session_->CreateDataChannel(label, internal_config.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000492 if (!channel.get())
493 return NULL;
494
jiayl@webrtc.org001fd2d2014-05-29 15:31:11 +0000495 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
496 // the first SCTP DataChannel.
497 if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
498 observer_->OnRenegotiationNeeded();
499 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000500
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000501 return DataChannelProxy::Create(signaling_thread(), channel.get());
502}
503
504void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
505 const MediaConstraintsInterface* constraints) {
506 if (!VERIFY(observer != NULL)) {
507 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
508 return;
509 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000510 session_->CreateOffer(observer, constraints);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000511}
512
513void PeerConnection::CreateAnswer(
514 CreateSessionDescriptionObserver* observer,
515 const MediaConstraintsInterface* constraints) {
516 if (!VERIFY(observer != NULL)) {
517 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
518 return;
519 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000520 session_->CreateAnswer(observer, constraints);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000521}
522
523void PeerConnection::SetLocalDescription(
524 SetSessionDescriptionObserver* observer,
525 SessionDescriptionInterface* desc) {
526 if (!VERIFY(observer != NULL)) {
527 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
528 return;
529 }
530 if (!desc) {
531 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
532 return;
533 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000534 // Update stats here so that we have the most recent stats for tracks and
535 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000536 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000537 std::string error;
538 if (!session_->SetLocalDescription(desc, &error)) {
539 PostSetSessionDescriptionFailure(observer, error);
540 return;
541 }
542 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
543 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
544}
545
546void PeerConnection::SetRemoteDescription(
547 SetSessionDescriptionObserver* observer,
548 SessionDescriptionInterface* desc) {
549 if (!VERIFY(observer != NULL)) {
550 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
551 return;
552 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000553 if (!desc) {
554 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
555 return;
556 }
557 // Update stats here so that we have the most recent stats for tracks and
558 // streams that might be removed by updating the session description.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000559 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000560 std::string error;
561 if (!session_->SetRemoteDescription(desc, &error)) {
562 PostSetSessionDescriptionFailure(observer, error);
563 return;
564 }
565 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
566 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
567}
568
569void PeerConnection::PostSetSessionDescriptionFailure(
570 SetSessionDescriptionObserver* observer,
571 const std::string& error) {
572 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
573 msg->error = error;
574 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
575}
576
577bool PeerConnection::UpdateIce(const IceServers& configuration,
578 const MediaConstraintsInterface* constraints) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000579 return false;
580}
581
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000582bool PeerConnection::UpdateIce(const RTCConfiguration& config) {
583 if (port_allocator_) {
584 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
585 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
586 if (!ParseIceServers(config.servers, &stuns, &turns)) {
587 return false;
588 }
589
590 std::vector<talk_base::SocketAddress> stun_hosts;
591 typedef std::vector<StunConfiguration>::const_iterator StunIt;
592 for (StunIt stun_it = stuns.begin(); stun_it != stuns.end(); ++stun_it) {
593 stun_hosts.push_back(stun_it->server);
594 }
595
596 talk_base::SocketAddress stun_addr;
597 if (!stun_hosts.empty()) {
598 stun_addr = stun_hosts.front();
599 LOG(LS_INFO) << "UpdateIce: StunServer Address: " << stun_addr.ToString();
600 }
601
602 for (size_t i = 0; i < turns.size(); ++i) {
603 cricket::RelayCredentials credentials(turns[i].username,
604 turns[i].password);
605 cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
606 cricket::ProtocolType protocol;
607 if (cricket::StringToProto(turns[i].transport_type.c_str(), &protocol)) {
608 relay_server.ports.push_back(cricket::ProtocolAddress(
609 turns[i].server, protocol, turns[i].secure));
610 relay_server.credentials = credentials;
611 LOG(LS_INFO) << "UpdateIce: TurnServer Address: "
612 << turns[i].server.ToString();
613 } else {
614 LOG(LS_WARNING) << "Ignoring TURN server " << turns[i].server << ". "
615 << "Reason= Incorrect " << turns[i].transport_type
616 << " transport parameter.";
617 }
618 }
619 }
620 return session_->UpdateIce(config.type);
621}
622
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000623bool PeerConnection::AddIceCandidate(
624 const IceCandidateInterface* ice_candidate) {
625 return session_->ProcessIceMessage(ice_candidate);
626}
627
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000628void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
629 uma_observer_ = observer;
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +0000630 // Send information about IPv4/IPv6 status.
631 if (uma_observer_ && port_allocator_) {
632 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +0000633 uma_observer_->IncrementCounter(kPeerConnection_IPv6);
mallinath@webrtc.orgb445f262014-05-23 22:19:37 +0000634 } else {
635 uma_observer_->IncrementCounter(kPeerConnection_IPv4);
mallinath@webrtc.orgd37bcfa2014-05-12 23:10:18 +0000636 }
637 }
buildbot@webrtc.org1567b8c2014-05-08 19:54:16 +0000638}
639
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000640const SessionDescriptionInterface* PeerConnection::local_description() const {
641 return session_->local_description();
642}
643
644const SessionDescriptionInterface* PeerConnection::remote_description() const {
645 return session_->remote_description();
646}
647
648void PeerConnection::Close() {
649 // Update stats here so that we have the most recent stats for tracks and
650 // streams before the channels are closed.
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000651 stats_->UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000652
653 session_->Terminate();
654}
655
656void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
657 cricket::BaseSession::State state) {
658 switch (state) {
659 case cricket::BaseSession::STATE_INIT:
660 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000661 break;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000662 case cricket::BaseSession::STATE_SENTINITIATE:
663 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
664 break;
665 case cricket::BaseSession::STATE_SENTPRACCEPT:
666 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
667 break;
668 case cricket::BaseSession::STATE_RECEIVEDINITIATE:
669 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
670 break;
671 case cricket::BaseSession::STATE_RECEIVEDPRACCEPT:
672 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
673 break;
674 case cricket::BaseSession::STATE_SENTACCEPT:
675 case cricket::BaseSession::STATE_RECEIVEDACCEPT:
676 ChangeSignalingState(PeerConnectionInterface::kStable);
677 break;
678 case cricket::BaseSession::STATE_RECEIVEDTERMINATE:
679 ChangeSignalingState(PeerConnectionInterface::kClosed);
680 break;
681 default:
682 break;
683 }
684}
685
686void PeerConnection::OnMessage(talk_base::Message* msg) {
687 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000688 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
689 SetSessionDescriptionMsg* param =
690 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
691 param->observer->OnSuccess();
692 delete param;
693 break;
694 }
695 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
696 SetSessionDescriptionMsg* param =
697 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
698 param->observer->OnFailure(param->error);
699 delete param;
700 break;
701 }
702 case MSG_GETSTATS: {
703 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
tommi@webrtc.org190d2692014-07-25 10:32:30 +0000704 StatsReports reports;
705 stats_->GetStats(param->track, &reports);
706 param->observer->OnComplete(reports);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000707 delete param;
708 break;
709 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000710 default:
711 ASSERT(false && "Not implemented");
712 break;
713 }
714}
715
716void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000717 stats_->AddStream(stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000718 observer_->OnAddStream(stream);
719}
720
721void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
722 stream_handler_container_->RemoveRemoteStream(stream);
723 observer_->OnRemoveStream(stream);
724}
725
726void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
727 observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
728 data_channel));
729}
730
731void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
732 AudioTrackInterface* audio_track,
733 uint32 ssrc) {
734 stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc);
735}
736
737void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
738 VideoTrackInterface* video_track,
739 uint32 ssrc) {
740 stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc);
741}
742
743void PeerConnection::OnRemoveRemoteAudioTrack(
744 MediaStreamInterface* stream,
745 AudioTrackInterface* audio_track) {
746 stream_handler_container_->RemoveRemoteTrack(stream, audio_track);
747}
748
749void PeerConnection::OnRemoveRemoteVideoTrack(
750 MediaStreamInterface* stream,
751 VideoTrackInterface* video_track) {
752 stream_handler_container_->RemoveRemoteTrack(stream, video_track);
753}
754void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
755 AudioTrackInterface* audio_track,
756 uint32 ssrc) {
757 stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc);
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000758 stats_->AddLocalAudioTrack(audio_track, ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000759}
760void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
761 VideoTrackInterface* video_track,
762 uint32 ssrc) {
763 stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc);
764}
765
766void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000767 AudioTrackInterface* audio_track,
768 uint32 ssrc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000769 stream_handler_container_->RemoveLocalTrack(stream, audio_track);
tommi@webrtc.org03505bc2014-07-14 20:15:26 +0000770 stats_->RemoveLocalAudioTrack(audio_track, ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000771}
772
773void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
774 VideoTrackInterface* video_track) {
775 stream_handler_container_->RemoveLocalTrack(stream, video_track);
776}
777
778void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
779 stream_handler_container_->RemoveLocalStream(stream);
780}
781
782void PeerConnection::OnIceConnectionChange(
783 PeerConnectionInterface::IceConnectionState new_state) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000784 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000785 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000786 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000787}
788
789void PeerConnection::OnIceGatheringChange(
790 PeerConnectionInterface::IceGatheringState new_state) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000791 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000792 if (IsClosed()) {
793 return;
794 }
795 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000796 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000797}
798
799void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000800 ASSERT(signaling_thread()->IsCurrent());
801 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000802}
803
804void PeerConnection::OnIceComplete() {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000805 ASSERT(signaling_thread()->IsCurrent());
806 observer_->OnIceComplete();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000807}
808
809void PeerConnection::ChangeSignalingState(
810 PeerConnectionInterface::SignalingState signaling_state) {
811 signaling_state_ = signaling_state;
812 if (signaling_state == kClosed) {
813 ice_connection_state_ = kIceConnectionClosed;
814 observer_->OnIceConnectionChange(ice_connection_state_);
815 if (ice_gathering_state_ != kIceGatheringComplete) {
816 ice_gathering_state_ = kIceGatheringComplete;
817 observer_->OnIceGatheringChange(ice_gathering_state_);
818 }
819 }
820 observer_->OnSignalingChange(signaling_state_);
821 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
822}
823
824} // namespace webrtc