blob: af33d02dd8257a3c1b8484ca8d10b46963db572e [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"
40#include "talk/session/media/channelmanager.h"
41
42namespace {
43
44using webrtc::PeerConnectionInterface;
45
henrike@webrtc.org28e20752013-07-10 00:45:36 +000046// The min number of tokens must present in Turn host uri.
47// e.g. user@turn.example.org
48static const size_t kTurnHostTokensNum = 2;
49// Number of tokens must be preset when TURN uri has transport param.
50static const size_t kTurnTransportTokensNum = 2;
51// The default stun port.
wu@webrtc.org91053e72013-08-10 07:18:04 +000052static const int kDefaultStunPort = 3478;
53static const int kDefaultStunTlsPort = 5349;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000054static const char kTransport[] = "transport";
wu@webrtc.org91053e72013-08-10 07:18:04 +000055static const char kUdpTransportType[] = "udp";
56static const char kTcpTransportType[] = "tcp";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000057
58// NOTE: Must be in the same order as the ServiceType enum.
59static const char* kValidIceServiceTypes[] = {
60 "stun", "stuns", "turn", "turns", "invalid" };
61
62enum ServiceType {
63 STUN, // Indicates a STUN server.
64 STUNS, // Indicates a STUN server used with a TLS session.
65 TURN, // Indicates a TURN server
66 TURNS, // Indicates a TURN server used with a TLS session.
67 INVALID, // Unknown.
68};
69
70enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +000071 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000072 MSG_SET_SESSIONDESCRIPTION_FAILED,
73 MSG_GETSTATS,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000074};
75
henrike@webrtc.org28e20752013-07-10 00:45:36 +000076struct SetSessionDescriptionMsg : public talk_base::MessageData {
77 explicit SetSessionDescriptionMsg(
78 webrtc::SetSessionDescriptionObserver* observer)
79 : observer(observer) {
80 }
81
82 talk_base::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
83 std::string error;
84};
85
86struct GetStatsMsg : public talk_base::MessageData {
87 explicit GetStatsMsg(webrtc::StatsObserver* observer)
88 : observer(observer) {
89 }
90 webrtc::StatsReports reports;
91 talk_base::scoped_refptr<webrtc::StatsObserver> observer;
92};
93
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +000094// |in_str| should be of format
95// stunURI = scheme ":" stun-host [ ":" stun-port ]
96// scheme = "stun" / "stuns"
97// stun-host = IP-literal / IPv4address / reg-name
98// stun-port = *DIGIT
99
100// draft-petithuguenin-behave-turn-uris-01
101// turnURI = scheme ":" turn-host [ ":" turn-port ]
102// turn-host = username@IP-literal / IPv4address / reg-name
103bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
104 ServiceType* service_type,
105 std::string* hostname) {
106 std::string::size_type colonpos = in_str.find(':');
107 if (colonpos == std::string::npos) {
108 return false;
109 }
110 std::string type = in_str.substr(0, colonpos);
111 for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
112 if (type.compare(kValidIceServiceTypes[i]) == 0) {
113 *service_type = static_cast<ServiceType>(i);
114 break;
115 }
116 }
117 if (*service_type == INVALID) {
118 return false;
119 }
120 *hostname = in_str.substr(colonpos + 1, std::string::npos);
121 return true;
122}
123
124// This method parses IPv6 and IPv4 literal strings, along with hostnames in
125// standard hostname:port format.
126// Consider following formats as correct.
127// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
128// |hostname|, |[IPv6 address]|, |IPv4 address|
129bool ParseHostnameAndPortFromString(const std::string& in_str,
130 std::string* host,
131 int* port) {
132 if (in_str.at(0) == '[') {
133 std::string::size_type closebracket = in_str.rfind(']');
134 if (closebracket != std::string::npos) {
135 *host = in_str.substr(1, closebracket - 1);
136 std::string::size_type colonpos = in_str.find(':', closebracket);
137 if (std::string::npos != colonpos) {
138 if (!talk_base::FromString(
139 in_str.substr(closebracket + 2, std::string::npos), port)) {
140 return false;
141 }
142 }
143 } else {
144 return false;
145 }
146 } else {
147 std::string::size_type colonpos = in_str.find(':');
148 if (std::string::npos != colonpos) {
149 *host = in_str.substr(0, colonpos);
150 if (!talk_base::FromString(
151 in_str.substr(colonpos + 1, std::string::npos), port)) {
152 return false;
153 }
154 } else {
155 *host = in_str;
156 }
157 }
158 return true;
159}
160
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000161typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
162 StunConfiguration;
163typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
164 TurnConfiguration;
165
166bool ParseIceServers(const PeerConnectionInterface::IceServers& configuration,
167 std::vector<StunConfiguration>* stun_config,
168 std::vector<TurnConfiguration>* turn_config) {
169 // draft-nandakumar-rtcweb-stun-uri-01
170 // stunURI = scheme ":" stun-host [ ":" stun-port ]
171 // scheme = "stun" / "stuns"
172 // stun-host = IP-literal / IPv4address / reg-name
173 // stun-port = *DIGIT
174
175 // draft-petithuguenin-behave-turn-uris-01
176 // turnURI = scheme ":" turn-host [ ":" turn-port ]
177 // [ "?transport=" transport ]
178 // scheme = "turn" / "turns"
179 // transport = "udp" / "tcp" / transport-ext
180 // transport-ext = 1*unreserved
181 // turn-host = IP-literal / IPv4address / reg-name
182 // turn-port = *DIGIT
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000183 for (size_t i = 0; i < configuration.size(); ++i) {
184 webrtc::PeerConnectionInterface::IceServer server = configuration[i];
185 if (server.uri.empty()) {
186 LOG(WARNING) << "Empty uri.";
187 continue;
188 }
189 std::vector<std::string> tokens;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000190 std::string turn_transport_type = kUdpTransportType;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000191 talk_base::tokenize(server.uri, '?', &tokens);
192 std::string uri_without_transport = tokens[0];
193 // Let's look into transport= param, if it exists.
194 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
195 std::string uri_transport_param = tokens[1];
196 talk_base::tokenize(uri_transport_param, '=', &tokens);
197 if (tokens[0] == kTransport) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000198 // As per above grammar transport param will be consist of lower case
199 // letters.
200 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
201 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
202 continue;
203 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000204 turn_transport_type = tokens[1];
205 }
206 }
207
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000208 std::string hoststring;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000209 ServiceType service_type = INVALID;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000210 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
211 &service_type,
212 &hoststring)) {
213 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: "
214 << uri_without_transport;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000215 continue;
216 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000217
218 // Let's break hostname.
219 tokens.clear();
220 talk_base::tokenize(hoststring, '@', &tokens);
221 hoststring = tokens[0];
222 if (tokens.size() == kTurnHostTokensNum) {
223 server.username = talk_base::s_url_decode(tokens[0]);
224 hoststring = tokens[1];
225 }
226
wu@webrtc.org91053e72013-08-10 07:18:04 +0000227 int port = kDefaultStunPort;
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000228 if (service_type == TURNS) {
229 port = kDefaultStunTlsPort;
230 turn_transport_type = kTcpTransportType;
231 }
232
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000233 std::string address;
234 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
235 LOG(WARNING) << "Invalid Hostname format: " << uri_without_transport;
236 continue;
237 }
238
wu@webrtc.org91053e72013-08-10 07:18:04 +0000239
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000240 if (port <= 0 || port > 0xffff) {
241 LOG(WARNING) << "Invalid port: " << port;
242 continue;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000243 }
244
245 switch (service_type) {
246 case STUN:
247 case STUNS:
248 stun_config->push_back(StunConfiguration(address, port));
249 break;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000250 case TURN:
251 case TURNS: {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000252 if (server.username.empty()) {
253 // Turn url example from the spec |url:"turn:user@turn.example.org"|.
254 std::vector<std::string> turn_tokens;
255 talk_base::tokenize(address, '@', &turn_tokens);
256 if (turn_tokens.size() == kTurnHostTokensNum) {
257 server.username = talk_base::s_url_decode(turn_tokens[0]);
258 address = turn_tokens[1];
259 }
260 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000261
262 bool secure = (service_type == TURNS);
263
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000264 turn_config->push_back(TurnConfiguration(address, port,
265 server.username,
266 server.password,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000267 turn_transport_type,
268 secure));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000269 // STUN functionality is part of TURN.
wu@webrtc.org91053e72013-08-10 07:18:04 +0000270 // Note: If there is only TURNS is supplied as part of configuration,
271 // we will have problem in fetching server reflexive candidate, as
272 // currently we don't have support of TCP/TLS in stunport.cc.
273 // In that case we should fetch server reflexive addess from
274 // TURN allocate response.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000275 stun_config->push_back(StunConfiguration(address, port));
276 break;
277 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000278 case INVALID:
279 default:
280 LOG(WARNING) << "Configuration not supported: " << server.uri;
281 return false;
282 }
283 }
284 return true;
285}
286
287// Check if we can send |new_stream| on a PeerConnection.
288// Currently only one audio but multiple video track is supported per
289// PeerConnection.
290bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
291 webrtc::MediaStreamInterface* new_stream) {
292 if (!new_stream || !current_streams)
293 return false;
294 if (current_streams->find(new_stream->label()) != NULL) {
295 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
296 << " is already added.";
297 return false;
298 }
299
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000300 return true;
301}
302
303} // namespace
304
305namespace webrtc {
306
307PeerConnection::PeerConnection(PeerConnectionFactory* factory)
308 : factory_(factory),
309 observer_(NULL),
310 signaling_state_(kStable),
311 ice_state_(kIceNew),
312 ice_connection_state_(kIceConnectionNew),
313 ice_gathering_state_(kIceGatheringNew) {
314}
315
316PeerConnection::~PeerConnection() {
317 if (mediastream_signaling_)
318 mediastream_signaling_->TearDown();
319 if (stream_handler_container_)
320 stream_handler_container_->TearDown();
321}
322
323bool PeerConnection::Initialize(
324 const PeerConnectionInterface::IceServers& configuration,
325 const MediaConstraintsInterface* constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000326 PortAllocatorFactoryInterface* allocator_factory,
327 DTLSIdentityServiceInterface* dtls_identity_service,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000328 PeerConnectionObserver* observer) {
329 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
330 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
331 if (!ParseIceServers(configuration, &stun_config, &turn_config)) {
332 return false;
333 }
334
335 return DoInitialize(stun_config, turn_config, constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000336 allocator_factory, dtls_identity_service, observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000337}
338
339bool PeerConnection::DoInitialize(
340 const StunConfigurations& stun_config,
341 const TurnConfigurations& turn_config,
342 const MediaConstraintsInterface* constraints,
343 webrtc::PortAllocatorFactoryInterface* allocator_factory,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000344 DTLSIdentityServiceInterface* dtls_identity_service,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000345 PeerConnectionObserver* observer) {
346 ASSERT(observer != NULL);
347 if (!observer)
348 return false;
349 observer_ = observer;
350 port_allocator_.reset(
351 allocator_factory->CreatePortAllocator(stun_config, turn_config));
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000352
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000353 // To handle both internal and externally created port allocator, we will
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000354 // enable BUNDLE here.
355 int portallocator_flags = cricket::PORTALLOCATOR_ENABLE_BUNDLE |
356 cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
357 cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET;
358 bool value;
359 if (FindConstraint(
360 constraints,
361 MediaConstraintsInterface::kEnableIPv6,
362 &value, NULL) && value) {
363 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6;
364 }
365
366 port_allocator_->set_flags(portallocator_flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000367 // No step delay is used while allocating ports.
368 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
369
370 mediastream_signaling_.reset(new MediaStreamSignaling(
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000371 factory_->signaling_thread(), this, factory_->channel_manager()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000372
373 session_.reset(new WebRtcSession(factory_->channel_manager(),
374 factory_->signaling_thread(),
375 factory_->worker_thread(),
376 port_allocator_.get(),
377 mediastream_signaling_.get()));
378 stream_handler_container_.reset(new MediaStreamHandlerContainer(
379 session_.get(), session_.get()));
380 stats_.set_session(session_.get());
381
382 // Initialize the WebRtcSession. It creates transport channels etc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000383 if (!session_->Initialize(factory_->options(), constraints,
384 dtls_identity_service))
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000385 return false;
386
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000387 // Register PeerConnection as receiver of local ice candidates.
388 // All the callbacks will be posted to the application from PeerConnection.
389 session_->RegisterIceObserver(this);
390 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
391 return true;
392}
393
394talk_base::scoped_refptr<StreamCollectionInterface>
395PeerConnection::local_streams() {
396 return mediastream_signaling_->local_streams();
397}
398
399talk_base::scoped_refptr<StreamCollectionInterface>
400PeerConnection::remote_streams() {
401 return mediastream_signaling_->remote_streams();
402}
403
404bool PeerConnection::AddStream(MediaStreamInterface* local_stream,
405 const MediaConstraintsInterface* constraints) {
406 if (IsClosed()) {
407 return false;
408 }
409 if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(),
410 local_stream))
411 return false;
412
413 // TODO(perkj): Implement support for MediaConstraints in AddStream.
414 if (!mediastream_signaling_->AddLocalStream(local_stream)) {
415 return false;
416 }
417 stats_.AddStream(local_stream);
418 observer_->OnRenegotiationNeeded();
419 return true;
420}
421
422void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000423 mediastream_signaling_->RemoveLocalStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000424 if (IsClosed()) {
425 return;
426 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000427 observer_->OnRenegotiationNeeded();
428}
429
430talk_base::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
431 AudioTrackInterface* track) {
432 if (!track) {
433 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
434 return NULL;
435 }
436 if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) {
437 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
438 return NULL;
439 }
440
441 talk_base::scoped_refptr<DtmfSenderInterface> sender(
442 DtmfSender::Create(track, signaling_thread(), session_.get()));
443 if (!sender.get()) {
444 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
445 return NULL;
446 }
447 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
448}
449
450bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000451 webrtc::MediaStreamTrackInterface* track) {
452 return GetStats(observer, track, kStatsOutputLevelStandard);
453}
454
455bool PeerConnection::GetStats(StatsObserver* observer,
456 MediaStreamTrackInterface* track,
457 StatsOutputLevel level) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000458 if (!VERIFY(observer != NULL)) {
459 LOG(LS_ERROR) << "GetStats - observer is NULL.";
460 return false;
461 }
462
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000463 stats_.UpdateStats(level);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000464 talk_base::scoped_ptr<GetStatsMsg> msg(new GetStatsMsg(observer));
465 if (!stats_.GetStats(track, &(msg->reports))) {
466 return false;
467 }
468 signaling_thread()->Post(this, MSG_GETSTATS, msg.release());
469 return true;
470}
471
472PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
473 return signaling_state_;
474}
475
476PeerConnectionInterface::IceState PeerConnection::ice_state() {
477 return ice_state_;
478}
479
480PeerConnectionInterface::IceConnectionState
481PeerConnection::ice_connection_state() {
482 return ice_connection_state_;
483}
484
485PeerConnectionInterface::IceGatheringState
486PeerConnection::ice_gathering_state() {
487 return ice_gathering_state_;
488}
489
490talk_base::scoped_refptr<DataChannelInterface>
491PeerConnection::CreateDataChannel(
492 const std::string& label,
493 const DataChannelInit* config) {
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000494 talk_base::scoped_ptr<InternalDataChannelInit> internal_config;
495 if (config) {
496 internal_config.reset(new InternalDataChannelInit(*config));
497 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000498 talk_base::scoped_refptr<DataChannelInterface> channel(
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000499 session_->CreateDataChannel(label, internal_config.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000500 if (!channel.get())
501 return NULL;
502
503 observer_->OnRenegotiationNeeded();
wu@webrtc.org91053e72013-08-10 07:18:04 +0000504
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000505 return DataChannelProxy::Create(signaling_thread(), channel.get());
506}
507
508void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
509 const MediaConstraintsInterface* constraints) {
510 if (!VERIFY(observer != NULL)) {
511 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
512 return;
513 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000514 session_->CreateOffer(observer, constraints);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000515}
516
517void PeerConnection::CreateAnswer(
518 CreateSessionDescriptionObserver* observer,
519 const MediaConstraintsInterface* constraints) {
520 if (!VERIFY(observer != NULL)) {
521 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
522 return;
523 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000524 session_->CreateAnswer(observer, constraints);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000525}
526
527void PeerConnection::SetLocalDescription(
528 SetSessionDescriptionObserver* observer,
529 SessionDescriptionInterface* desc) {
530 if (!VERIFY(observer != NULL)) {
531 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
532 return;
533 }
534 if (!desc) {
535 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
536 return;
537 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000538 // Update stats here so that we have the most recent stats for tracks and
539 // streams that might be removed by updating the session description.
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000540 stats_.UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000541 std::string error;
542 if (!session_->SetLocalDescription(desc, &error)) {
543 PostSetSessionDescriptionFailure(observer, error);
544 return;
545 }
546 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
547 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
548}
549
550void PeerConnection::SetRemoteDescription(
551 SetSessionDescriptionObserver* observer,
552 SessionDescriptionInterface* desc) {
553 if (!VERIFY(observer != NULL)) {
554 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
555 return;
556 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000557 if (!desc) {
558 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
559 return;
560 }
561 // Update stats here so that we have the most recent stats for tracks and
562 // streams that might be removed by updating the session description.
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000563 stats_.UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000564 std::string error;
565 if (!session_->SetRemoteDescription(desc, &error)) {
566 PostSetSessionDescriptionFailure(observer, error);
567 return;
568 }
569 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
570 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
571}
572
573void PeerConnection::PostSetSessionDescriptionFailure(
574 SetSessionDescriptionObserver* observer,
575 const std::string& error) {
576 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
577 msg->error = error;
578 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
579}
580
581bool PeerConnection::UpdateIce(const IceServers& configuration,
582 const MediaConstraintsInterface* constraints) {
583 // TODO(ronghuawu): Implement UpdateIce.
584 LOG(LS_ERROR) << "UpdateIce is not implemented.";
585 return false;
586}
587
588bool PeerConnection::AddIceCandidate(
589 const IceCandidateInterface* ice_candidate) {
590 return session_->ProcessIceMessage(ice_candidate);
591}
592
593const SessionDescriptionInterface* PeerConnection::local_description() const {
594 return session_->local_description();
595}
596
597const SessionDescriptionInterface* PeerConnection::remote_description() const {
598 return session_->remote_description();
599}
600
601void PeerConnection::Close() {
602 // Update stats here so that we have the most recent stats for tracks and
603 // streams before the channels are closed.
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000604 stats_.UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605
606 session_->Terminate();
607}
608
609void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
610 cricket::BaseSession::State state) {
611 switch (state) {
612 case cricket::BaseSession::STATE_INIT:
613 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000614 break;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000615 case cricket::BaseSession::STATE_SENTINITIATE:
616 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
617 break;
618 case cricket::BaseSession::STATE_SENTPRACCEPT:
619 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
620 break;
621 case cricket::BaseSession::STATE_RECEIVEDINITIATE:
622 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
623 break;
624 case cricket::BaseSession::STATE_RECEIVEDPRACCEPT:
625 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
626 break;
627 case cricket::BaseSession::STATE_SENTACCEPT:
628 case cricket::BaseSession::STATE_RECEIVEDACCEPT:
629 ChangeSignalingState(PeerConnectionInterface::kStable);
630 break;
631 case cricket::BaseSession::STATE_RECEIVEDTERMINATE:
632 ChangeSignalingState(PeerConnectionInterface::kClosed);
633 break;
634 default:
635 break;
636 }
637}
638
639void PeerConnection::OnMessage(talk_base::Message* msg) {
640 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000641 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
642 SetSessionDescriptionMsg* param =
643 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
644 param->observer->OnSuccess();
645 delete param;
646 break;
647 }
648 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
649 SetSessionDescriptionMsg* param =
650 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
651 param->observer->OnFailure(param->error);
652 delete param;
653 break;
654 }
655 case MSG_GETSTATS: {
656 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
657 param->observer->OnComplete(param->reports);
658 delete param;
659 break;
660 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000661 default:
662 ASSERT(false && "Not implemented");
663 break;
664 }
665}
666
667void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
668 stats_.AddStream(stream);
669 observer_->OnAddStream(stream);
670}
671
672void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
673 stream_handler_container_->RemoveRemoteStream(stream);
674 observer_->OnRemoveStream(stream);
675}
676
677void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
678 observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
679 data_channel));
680}
681
682void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
683 AudioTrackInterface* audio_track,
684 uint32 ssrc) {
685 stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc);
686}
687
688void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
689 VideoTrackInterface* video_track,
690 uint32 ssrc) {
691 stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc);
692}
693
694void PeerConnection::OnRemoveRemoteAudioTrack(
695 MediaStreamInterface* stream,
696 AudioTrackInterface* audio_track) {
697 stream_handler_container_->RemoveRemoteTrack(stream, audio_track);
698}
699
700void PeerConnection::OnRemoveRemoteVideoTrack(
701 MediaStreamInterface* stream,
702 VideoTrackInterface* video_track) {
703 stream_handler_container_->RemoveRemoteTrack(stream, video_track);
704}
705void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
706 AudioTrackInterface* audio_track,
707 uint32 ssrc) {
708 stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000709 stats_.AddLocalAudioTrack(audio_track, ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000710}
711void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
712 VideoTrackInterface* video_track,
713 uint32 ssrc) {
714 stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc);
715}
716
717void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000718 AudioTrackInterface* audio_track,
719 uint32 ssrc) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000720 stream_handler_container_->RemoveLocalTrack(stream, audio_track);
henrike@webrtc.org40b3b682014-03-03 18:30:11 +0000721 stats_.RemoveLocalAudioTrack(audio_track, ssrc);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000722}
723
724void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
725 VideoTrackInterface* video_track) {
726 stream_handler_container_->RemoveLocalTrack(stream, video_track);
727}
728
729void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
730 stream_handler_container_->RemoveLocalStream(stream);
731}
732
733void PeerConnection::OnIceConnectionChange(
734 PeerConnectionInterface::IceConnectionState new_state) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000735 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000736 ice_connection_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000737 observer_->OnIceConnectionChange(ice_connection_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000738}
739
740void PeerConnection::OnIceGatheringChange(
741 PeerConnectionInterface::IceGatheringState new_state) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000742 ASSERT(signaling_thread()->IsCurrent());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000743 if (IsClosed()) {
744 return;
745 }
746 ice_gathering_state_ = new_state;
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000747 observer_->OnIceGatheringChange(ice_gathering_state_);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000748}
749
750void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000751 ASSERT(signaling_thread()->IsCurrent());
752 observer_->OnIceCandidate(candidate);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000753}
754
755void PeerConnection::OnIceComplete() {
mallinath@webrtc.orgd3dc4242014-03-01 00:05:52 +0000756 ASSERT(signaling_thread()->IsCurrent());
757 observer_->OnIceComplete();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000758}
759
760void PeerConnection::ChangeSignalingState(
761 PeerConnectionInterface::SignalingState signaling_state) {
762 signaling_state_ = signaling_state;
763 if (signaling_state == kClosed) {
764 ice_connection_state_ = kIceConnectionClosed;
765 observer_->OnIceConnectionChange(ice_connection_state_);
766 if (ice_gathering_state_ != kIceGatheringComplete) {
767 ice_gathering_state_ = kIceGatheringComplete;
768 observer_->OnIceGatheringChange(ice_gathering_state_);
769 }
770 }
771 observer_->OnSignalingChange(signaling_state_);
772 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
773}
774
775} // namespace webrtc