blob: 7e9c9fc7e18cdc03d1073902ad9d7d3b3484205f [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 {
88 explicit GetStatsMsg(webrtc::StatsObserver* observer)
89 : observer(observer) {
90 }
91 webrtc::StatsReports reports;
92 talk_base::scoped_refptr<webrtc::StatsObserver> observer;
93};
94
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +000095// |in_str| should be of format
96// stunURI = scheme ":" stun-host [ ":" stun-port ]
97// scheme = "stun" / "stuns"
98// stun-host = IP-literal / IPv4address / reg-name
99// stun-port = *DIGIT
100
101// draft-petithuguenin-behave-turn-uris-01
102// turnURI = scheme ":" turn-host [ ":" turn-port ]
103// turn-host = username@IP-literal / IPv4address / reg-name
104bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
105 ServiceType* service_type,
106 std::string* hostname) {
107 std::string::size_type colonpos = in_str.find(':');
108 if (colonpos == std::string::npos) {
109 return false;
110 }
111 std::string type = in_str.substr(0, colonpos);
112 for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
113 if (type.compare(kValidIceServiceTypes[i]) == 0) {
114 *service_type = static_cast<ServiceType>(i);
115 break;
116 }
117 }
118 if (*service_type == INVALID) {
119 return false;
120 }
121 *hostname = in_str.substr(colonpos + 1, std::string::npos);
122 return true;
123}
124
125// This method parses IPv6 and IPv4 literal strings, along with hostnames in
126// standard hostname:port format.
127// Consider following formats as correct.
128// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
129// |hostname|, |[IPv6 address]|, |IPv4 address|
130bool ParseHostnameAndPortFromString(const std::string& in_str,
131 std::string* host,
132 int* port) {
133 if (in_str.at(0) == '[') {
134 std::string::size_type closebracket = in_str.rfind(']');
135 if (closebracket != std::string::npos) {
136 *host = in_str.substr(1, closebracket - 1);
137 std::string::size_type colonpos = in_str.find(':', closebracket);
138 if (std::string::npos != colonpos) {
139 if (!talk_base::FromString(
140 in_str.substr(closebracket + 2, std::string::npos), port)) {
141 return false;
142 }
143 }
144 } else {
145 return false;
146 }
147 } else {
148 std::string::size_type colonpos = in_str.find(':');
149 if (std::string::npos != colonpos) {
150 *host = in_str.substr(0, colonpos);
151 if (!talk_base::FromString(
152 in_str.substr(colonpos + 1, std::string::npos), port)) {
153 return false;
154 }
155 } else {
156 *host = in_str;
157 }
158 }
159 return true;
160}
161
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000162typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
163 StunConfiguration;
164typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
165 TurnConfiguration;
166
167bool ParseIceServers(const PeerConnectionInterface::IceServers& configuration,
168 std::vector<StunConfiguration>* stun_config,
169 std::vector<TurnConfiguration>* turn_config) {
170 // draft-nandakumar-rtcweb-stun-uri-01
171 // stunURI = scheme ":" stun-host [ ":" stun-port ]
172 // scheme = "stun" / "stuns"
173 // stun-host = IP-literal / IPv4address / reg-name
174 // stun-port = *DIGIT
175
176 // draft-petithuguenin-behave-turn-uris-01
177 // turnURI = scheme ":" turn-host [ ":" turn-port ]
178 // [ "?transport=" transport ]
179 // scheme = "turn" / "turns"
180 // transport = "udp" / "tcp" / transport-ext
181 // transport-ext = 1*unreserved
182 // turn-host = IP-literal / IPv4address / reg-name
183 // turn-port = *DIGIT
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000184 for (size_t i = 0; i < configuration.size(); ++i) {
185 webrtc::PeerConnectionInterface::IceServer server = configuration[i];
186 if (server.uri.empty()) {
187 LOG(WARNING) << "Empty uri.";
188 continue;
189 }
190 std::vector<std::string> tokens;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000191 std::string turn_transport_type = kUdpTransportType;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000192 talk_base::tokenize(server.uri, '?', &tokens);
193 std::string uri_without_transport = tokens[0];
194 // Let's look into transport= param, if it exists.
195 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
196 std::string uri_transport_param = tokens[1];
197 talk_base::tokenize(uri_transport_param, '=', &tokens);
198 if (tokens[0] == kTransport) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000199 // As per above grammar transport param will be consist of lower case
200 // letters.
201 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
202 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
203 continue;
204 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000205 turn_transport_type = tokens[1];
206 }
207 }
208
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000209 std::string hoststring;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000210 ServiceType service_type = INVALID;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000211 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
212 &service_type,
213 &hoststring)) {
214 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: "
215 << uri_without_transport;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000216 continue;
217 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000218
219 // Let's break hostname.
220 tokens.clear();
221 talk_base::tokenize(hoststring, '@', &tokens);
222 hoststring = tokens[0];
223 if (tokens.size() == kTurnHostTokensNum) {
224 server.username = talk_base::s_url_decode(tokens[0]);
225 hoststring = tokens[1];
226 }
227
wu@webrtc.org91053e72013-08-10 07:18:04 +0000228 int port = kDefaultStunPort;
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000229 if (service_type == TURNS) {
230 port = kDefaultStunTlsPort;
231 turn_transport_type = kTcpTransportType;
232 }
233
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000234 std::string address;
235 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
236 LOG(WARNING) << "Invalid Hostname format: " << uri_without_transport;
237 continue;
238 }
239
wu@webrtc.org91053e72013-08-10 07:18:04 +0000240
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000241 if (port <= 0 || port > 0xffff) {
242 LOG(WARNING) << "Invalid port: " << port;
243 continue;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000244 }
245
246 switch (service_type) {
247 case STUN:
248 case STUNS:
249 stun_config->push_back(StunConfiguration(address, port));
250 break;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000251 case TURN:
252 case TURNS: {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000253 if (server.username.empty()) {
254 // Turn url example from the spec |url:"turn:user@turn.example.org"|.
255 std::vector<std::string> turn_tokens;
256 talk_base::tokenize(address, '@', &turn_tokens);
257 if (turn_tokens.size() == kTurnHostTokensNum) {
258 server.username = talk_base::s_url_decode(turn_tokens[0]);
259 address = turn_tokens[1];
260 }
261 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000262
263 bool secure = (service_type == TURNS);
264
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000265 turn_config->push_back(TurnConfiguration(address, port,
266 server.username,
267 server.password,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000268 turn_transport_type,
269 secure));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000270 break;
271 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000272 case INVALID:
273 default:
274 LOG(WARNING) << "Configuration not supported: " << server.uri;
275 return false;
276 }
277 }
278 return true;
279}
280
281// Check if we can send |new_stream| on a PeerConnection.
282// Currently only one audio but multiple video track is supported per
283// PeerConnection.
284bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
285 webrtc::MediaStreamInterface* new_stream) {
286 if (!new_stream || !current_streams)
287 return false;
288 if (current_streams->find(new_stream->label()) != NULL) {
289 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
290 << " is already added.";
291 return false;
292 }
293
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000294 return true;
295}
296
297} // namespace
298
299namespace webrtc {
300
301PeerConnection::PeerConnection(PeerConnectionFactory* factory)
302 : factory_(factory),
303 observer_(NULL),
304 signaling_state_(kStable),
305 ice_state_(kIceNew),
306 ice_connection_state_(kIceConnectionNew),
307 ice_gathering_state_(kIceGatheringNew) {
308}
309
310PeerConnection::~PeerConnection() {
311 if (mediastream_signaling_)
312 mediastream_signaling_->TearDown();
313 if (stream_handler_container_)
314 stream_handler_container_->TearDown();
315}
316
317bool PeerConnection::Initialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000318 const PeerConnectionInterface::RTCConfiguration& configuration,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000319 const MediaConstraintsInterface* constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000320 PortAllocatorFactoryInterface* allocator_factory,
321 DTLSIdentityServiceInterface* dtls_identity_service,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000322 PeerConnectionObserver* observer) {
323 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
324 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000325 if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000326 return false;
327 }
328
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000329 return DoInitialize(configuration.type, stun_config, turn_config, constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000330 allocator_factory, dtls_identity_service, observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000331}
332
333bool PeerConnection::DoInitialize(
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000334 IceTransportsType type,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000335 const StunConfigurations& stun_config,
336 const TurnConfigurations& turn_config,
337 const MediaConstraintsInterface* constraints,
338 webrtc::PortAllocatorFactoryInterface* allocator_factory,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000339 DTLSIdentityServiceInterface* dtls_identity_service,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000340 PeerConnectionObserver* observer) {
341 ASSERT(observer != NULL);
342 if (!observer)
343 return false;
344 observer_ = observer;
345 port_allocator_.reset(
346 allocator_factory->CreatePortAllocator(stun_config, turn_config));
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000347
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000348 // To handle both internal and externally created port allocator, we will
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000349 // enable BUNDLE here.
350 int portallocator_flags = cricket::PORTALLOCATOR_ENABLE_BUNDLE |
351 cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
352 cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET;
353 bool value;
354 if (FindConstraint(
355 constraints,
356 MediaConstraintsInterface::kEnableIPv6,
357 &value, NULL) && value) {
358 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6;
359 }
360
361 port_allocator_->set_flags(portallocator_flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000362 // No step delay is used while allocating ports.
363 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
364
365 mediastream_signaling_.reset(new MediaStreamSignaling(
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000366 factory_->signaling_thread(), this, factory_->channel_manager()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000367
368 session_.reset(new WebRtcSession(factory_->channel_manager(),
369 factory_->signaling_thread(),
370 factory_->worker_thread(),
371 port_allocator_.get(),
372 mediastream_signaling_.get()));
373 stream_handler_container_.reset(new MediaStreamHandlerContainer(
374 session_.get(), session_.get()));
375 stats_.set_session(session_.get());
376
377 // Initialize the WebRtcSession. It creates transport channels etc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000378 if (!session_->Initialize(factory_->options(), constraints,
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000379 dtls_identity_service, type))
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000380 return false;
381
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000382 // Register PeerConnection as receiver of local ice candidates.
383 // All the callbacks will be posted to the application from PeerConnection.
384 session_->RegisterIceObserver(this);
385 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
386 return true;
387}
388
389talk_base::scoped_refptr<StreamCollectionInterface>
390PeerConnection::local_streams() {
391 return mediastream_signaling_->local_streams();
392}
393
394talk_base::scoped_refptr<StreamCollectionInterface>
395PeerConnection::remote_streams() {
396 return mediastream_signaling_->remote_streams();
397}
398
399bool PeerConnection::AddStream(MediaStreamInterface* local_stream,
400 const MediaConstraintsInterface* constraints) {
401 if (IsClosed()) {
402 return false;
403 }
404 if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(),
405 local_stream))
406 return false;
407
408 // TODO(perkj): Implement support for MediaConstraints in AddStream.
409 if (!mediastream_signaling_->AddLocalStream(local_stream)) {
410 return false;
411 }
412 stats_.AddStream(local_stream);
413 observer_->OnRenegotiationNeeded();
414 return true;
415}
416
417void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000418 mediastream_signaling_->RemoveLocalStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000419 if (IsClosed()) {
420 return;
421 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000422 observer_->OnRenegotiationNeeded();
423}
424
425talk_base::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
426 AudioTrackInterface* track) {
427 if (!track) {
428 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
429 return NULL;
430 }
431 if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) {
432 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
433 return NULL;
434 }
435
436 talk_base::scoped_refptr<DtmfSenderInterface> sender(
437 DtmfSender::Create(track, signaling_thread(), session_.get()));
438 if (!sender.get()) {
439 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
440 return NULL;
441 }
442 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
443}
444
445bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000446 MediaStreamTrackInterface* track,
447 StatsOutputLevel level) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000448 if (!VERIFY(observer != NULL)) {
449 LOG(LS_ERROR) << "GetStats - observer is NULL.";
450 return false;
451 }
452
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000453 stats_.UpdateStats(level);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000454 talk_base::scoped_ptr<GetStatsMsg> msg(new GetStatsMsg(observer));
455 if (!stats_.GetStats(track, &(msg->reports))) {
456 return false;
457 }
458 signaling_thread()->Post(this, MSG_GETSTATS, msg.release());
459 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) {
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000484 talk_base::scoped_ptr<InternalDataChannelInit> internal_config;
485 if (config) {
486 internal_config.reset(new InternalDataChannelInit(*config));
487 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000488 talk_base::scoped_refptr<DataChannelInterface> channel(
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000489 session_->CreateDataChannel(label, internal_config.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000490 if (!channel.get())
491 return NULL;
492
493 observer_->OnRenegotiationNeeded();
wu@webrtc.org91053e72013-08-10 07:18:04 +0000494
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000495 return DataChannelProxy::Create(signaling_thread(), channel.get());
496}
497
498void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
499 const MediaConstraintsInterface* constraints) {
500 if (!VERIFY(observer != NULL)) {
501 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
502 return;
503 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000504 session_->CreateOffer(observer, constraints);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505}
506
507void PeerConnection::CreateAnswer(
508 CreateSessionDescriptionObserver* observer,
509 const MediaConstraintsInterface* constraints) {
510 if (!VERIFY(observer != NULL)) {
511 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
512 return;
513 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000514 session_->CreateAnswer(observer, constraints);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000515}
516
517void PeerConnection::SetLocalDescription(
518 SetSessionDescriptionObserver* observer,
519 SessionDescriptionInterface* desc) {
520 if (!VERIFY(observer != NULL)) {
521 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
522 return;
523 }
524 if (!desc) {
525 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
526 return;
527 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000528 // Update stats here so that we have the most recent stats for tracks and
529 // streams that might be removed by updating the session description.
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000530 stats_.UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000531 std::string error;
532 if (!session_->SetLocalDescription(desc, &error)) {
533 PostSetSessionDescriptionFailure(observer, error);
534 return;
535 }
536 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
537 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
538}
539
540void PeerConnection::SetRemoteDescription(
541 SetSessionDescriptionObserver* observer,
542 SessionDescriptionInterface* desc) {
543 if (!VERIFY(observer != NULL)) {
544 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
545 return;
546 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000547 if (!desc) {
548 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
549 return;
550 }
551 // Update stats here so that we have the most recent stats for tracks and
552 // streams that might be removed by updating the session description.
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000553 stats_.UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000554 std::string error;
555 if (!session_->SetRemoteDescription(desc, &error)) {
556 PostSetSessionDescriptionFailure(observer, error);
557 return;
558 }
559 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
560 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
561}
562
563void PeerConnection::PostSetSessionDescriptionFailure(
564 SetSessionDescriptionObserver* observer,
565 const std::string& error) {
566 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
567 msg->error = error;
568 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
569}
570
571bool PeerConnection::UpdateIce(const IceServers& configuration,
572 const MediaConstraintsInterface* constraints) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000573 return false;
574}
575
buildbot@webrtc.org41451d42014-05-03 05:39:45 +0000576bool PeerConnection::UpdateIce(const RTCConfiguration& config) {
577 if (port_allocator_) {
578 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
579 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
580 if (!ParseIceServers(config.servers, &stuns, &turns)) {
581 return false;
582 }
583
584 std::vector<talk_base::SocketAddress> stun_hosts;
585 typedef std::vector<StunConfiguration>::const_iterator StunIt;
586 for (StunIt stun_it = stuns.begin(); stun_it != stuns.end(); ++stun_it) {
587 stun_hosts.push_back(stun_it->server);
588 }
589
590 talk_base::SocketAddress stun_addr;
591 if (!stun_hosts.empty()) {
592 stun_addr = stun_hosts.front();
593 LOG(LS_INFO) << "UpdateIce: StunServer Address: " << stun_addr.ToString();
594 }
595
596 for (size_t i = 0; i < turns.size(); ++i) {
597 cricket::RelayCredentials credentials(turns[i].username,
598 turns[i].password);
599 cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
600 cricket::ProtocolType protocol;
601 if (cricket::StringToProto(turns[i].transport_type.c_str(), &protocol)) {
602 relay_server.ports.push_back(cricket::ProtocolAddress(
603 turns[i].server, protocol, turns[i].secure));
604 relay_server.credentials = credentials;
605 LOG(LS_INFO) << "UpdateIce: TurnServer Address: "
606 << turns[i].server.ToString();
607 } else {
608 LOG(LS_WARNING) << "Ignoring TURN server " << turns[i].server << ". "
609 << "Reason= Incorrect " << turns[i].transport_type
610 << " transport parameter.";
611 }
612 }
613 }
614 return session_->UpdateIce(config.type);
615}
616
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000617bool PeerConnection::AddIceCandidate(
618 const IceCandidateInterface* ice_candidate) {
619 return session_->ProcessIceMessage(ice_candidate);
620}
621
622const SessionDescriptionInterface* PeerConnection::local_description() const {
623 return session_->local_description();
624}
625
626const SessionDescriptionInterface* PeerConnection::remote_description() const {
627 return session_->remote_description();
628}
629
630void PeerConnection::Close() {
631 // Update stats here so that we have the most recent stats for tracks and
632 // streams before the channels are closed.
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000633 stats_.UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000634
635 session_->Terminate();
636}
637
638void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
639 cricket::BaseSession::State state) {
640 switch (state) {
641 case cricket::BaseSession::STATE_INIT:
642 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000643 break;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000644 case cricket::BaseSession::STATE_SENTINITIATE:
645 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
646 break;
647 case cricket::BaseSession::STATE_SENTPRACCEPT:
648 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
649 break;
650 case cricket::BaseSession::STATE_RECEIVEDINITIATE:
651 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
652 break;
653 case cricket::BaseSession::STATE_RECEIVEDPRACCEPT:
654 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
655 break;
656 case cricket::BaseSession::STATE_SENTACCEPT:
657 case cricket::BaseSession::STATE_RECEIVEDACCEPT:
658 ChangeSignalingState(PeerConnectionInterface::kStable);
659 break;
660 case cricket::BaseSession::STATE_RECEIVEDTERMINATE:
661 ChangeSignalingState(PeerConnectionInterface::kClosed);
662 break;
663 default:
664 break;
665 }
666}
667
668void PeerConnection::OnMessage(talk_base::Message* msg) {
669 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000670 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
671 SetSessionDescriptionMsg* param =
672 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
673 param->observer->OnSuccess();
674 delete param;
675 break;
676 }
677 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
678 SetSessionDescriptionMsg* param =
679 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
680 param->observer->OnFailure(param->error);
681 delete param;
682 break;
683 }
684 case MSG_GETSTATS: {
685 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
686 param->observer->OnComplete(param->reports);
687 delete param;
688 break;
689 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000690 default:
691 ASSERT(false && "Not implemented");
692 break;
693 }
694}
695
696void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
697 stats_.AddStream(stream);
698 observer_->OnAddStream(stream);
699}
700
701void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
702 stream_handler_container_->RemoveRemoteStream(stream);
703 observer_->OnRemoveStream(stream);
704}
705
706void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
707 observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
708 data_channel));
709}
710
711void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
712 AudioTrackInterface* audio_track,
713 uint32 ssrc) {
714 stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc);
715}
716
717void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
718 VideoTrackInterface* video_track,
719 uint32 ssrc) {
720 stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc);
721}
722
723void PeerConnection::OnRemoveRemoteAudioTrack(
724 MediaStreamInterface* stream,
725 AudioTrackInterface* audio_track) {
726 stream_handler_container_->RemoveRemoteTrack(stream, audio_track);
727}
728
729void PeerConnection::OnRemoveRemoteVideoTrack(
730 MediaStreamInterface* stream,
731 VideoTrackInterface* video_track) {
732 stream_handler_container_->RemoveRemoteTrack(stream, video_track);
733}
734void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
735 AudioTrackInterface* audio_track,
736 uint32 ssrc) {
737 stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000738 stats_.AddLocalAudioTrack(audio_track, ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000739}
740void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
741 VideoTrackInterface* video_track,
742 uint32 ssrc) {
743 stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc);
744}
745
746void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000747 AudioTrackInterface* audio_track,
748 uint32 ssrc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000749 stream_handler_container_->RemoveLocalTrack(stream, audio_track);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000750 stats_.RemoveLocalAudioTrack(audio_track, ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000751}
752
753void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
754 VideoTrackInterface* video_track) {
755 stream_handler_container_->RemoveLocalTrack(stream, video_track);
756}
757
758void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
759 stream_handler_container_->RemoveLocalStream(stream);
760}
761
762void PeerConnection::OnIceConnectionChange(
763 PeerConnectionInterface::IceConnectionState new_state) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000764 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000765 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000766 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000767}
768
769void PeerConnection::OnIceGatheringChange(
770 PeerConnectionInterface::IceGatheringState new_state) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000771 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000772 if (IsClosed()) {
773 return;
774 }
775 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000776 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000777}
778
779void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000780 ASSERT(signaling_thread()->IsCurrent());
781 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000782}
783
784void PeerConnection::OnIceComplete() {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000785 ASSERT(signaling_thread()->IsCurrent());
786 observer_->OnIceComplete();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000787}
788
789void PeerConnection::ChangeSignalingState(
790 PeerConnectionInterface::SignalingState signaling_state) {
791 signaling_state_ = signaling_state;
792 if (signaling_state == kClosed) {
793 ice_connection_state_ = kIceConnectionClosed;
794 observer_->OnIceConnectionChange(ice_connection_state_);
795 if (ice_gathering_state_ != kIceGatheringComplete) {
796 ice_gathering_state_ = kIceGatheringComplete;
797 observer_->OnIceGatheringChange(ice_gathering_state_);
798 }
799 }
800 observer_->OnSignalingChange(signaling_state_);
801 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
802}
803
804} // namespace webrtc