blob: b404ec4a9ef9a7fa6797f0970df86383aad5447d [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,
74 MSG_ICECONNECTIONCHANGE,
75 MSG_ICEGATHERINGCHANGE,
76 MSG_ICECANDIDATE,
77 MSG_ICECOMPLETE,
78};
79
80struct CandidateMsg : public talk_base::MessageData {
81 explicit CandidateMsg(const webrtc::JsepIceCandidate* candidate)
82 : candidate(candidate) {
83 }
84 talk_base::scoped_ptr<const webrtc::JsepIceCandidate> candidate;
85};
86
henrike@webrtc.org28e20752013-07-10 00:45:36 +000087struct SetSessionDescriptionMsg : public talk_base::MessageData {
88 explicit SetSessionDescriptionMsg(
89 webrtc::SetSessionDescriptionObserver* observer)
90 : observer(observer) {
91 }
92
93 talk_base::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
94 std::string error;
95};
96
97struct GetStatsMsg : public talk_base::MessageData {
98 explicit GetStatsMsg(webrtc::StatsObserver* observer)
99 : observer(observer) {
100 }
101 webrtc::StatsReports reports;
102 talk_base::scoped_refptr<webrtc::StatsObserver> observer;
103};
104
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000105// |in_str| should be of format
106// stunURI = scheme ":" stun-host [ ":" stun-port ]
107// scheme = "stun" / "stuns"
108// stun-host = IP-literal / IPv4address / reg-name
109// stun-port = *DIGIT
110
111// draft-petithuguenin-behave-turn-uris-01
112// turnURI = scheme ":" turn-host [ ":" turn-port ]
113// turn-host = username@IP-literal / IPv4address / reg-name
114bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
115 ServiceType* service_type,
116 std::string* hostname) {
117 std::string::size_type colonpos = in_str.find(':');
118 if (colonpos == std::string::npos) {
119 return false;
120 }
121 std::string type = in_str.substr(0, colonpos);
122 for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
123 if (type.compare(kValidIceServiceTypes[i]) == 0) {
124 *service_type = static_cast<ServiceType>(i);
125 break;
126 }
127 }
128 if (*service_type == INVALID) {
129 return false;
130 }
131 *hostname = in_str.substr(colonpos + 1, std::string::npos);
132 return true;
133}
134
135// This method parses IPv6 and IPv4 literal strings, along with hostnames in
136// standard hostname:port format.
137// Consider following formats as correct.
138// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
139// |hostname|, |[IPv6 address]|, |IPv4 address|
140bool ParseHostnameAndPortFromString(const std::string& in_str,
141 std::string* host,
142 int* port) {
143 if (in_str.at(0) == '[') {
144 std::string::size_type closebracket = in_str.rfind(']');
145 if (closebracket != std::string::npos) {
146 *host = in_str.substr(1, closebracket - 1);
147 std::string::size_type colonpos = in_str.find(':', closebracket);
148 if (std::string::npos != colonpos) {
149 if (!talk_base::FromString(
150 in_str.substr(closebracket + 2, std::string::npos), port)) {
151 return false;
152 }
153 }
154 } else {
155 return false;
156 }
157 } else {
158 std::string::size_type colonpos = in_str.find(':');
159 if (std::string::npos != colonpos) {
160 *host = in_str.substr(0, colonpos);
161 if (!talk_base::FromString(
162 in_str.substr(colonpos + 1, std::string::npos), port)) {
163 return false;
164 }
165 } else {
166 *host = in_str;
167 }
168 }
169 return true;
170}
171
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000172typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
173 StunConfiguration;
174typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
175 TurnConfiguration;
176
177bool ParseIceServers(const PeerConnectionInterface::IceServers& configuration,
178 std::vector<StunConfiguration>* stun_config,
179 std::vector<TurnConfiguration>* turn_config) {
180 // draft-nandakumar-rtcweb-stun-uri-01
181 // stunURI = scheme ":" stun-host [ ":" stun-port ]
182 // scheme = "stun" / "stuns"
183 // stun-host = IP-literal / IPv4address / reg-name
184 // stun-port = *DIGIT
185
186 // draft-petithuguenin-behave-turn-uris-01
187 // turnURI = scheme ":" turn-host [ ":" turn-port ]
188 // [ "?transport=" transport ]
189 // scheme = "turn" / "turns"
190 // transport = "udp" / "tcp" / transport-ext
191 // transport-ext = 1*unreserved
192 // turn-host = IP-literal / IPv4address / reg-name
193 // turn-port = *DIGIT
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000194 for (size_t i = 0; i < configuration.size(); ++i) {
195 webrtc::PeerConnectionInterface::IceServer server = configuration[i];
196 if (server.uri.empty()) {
197 LOG(WARNING) << "Empty uri.";
198 continue;
199 }
200 std::vector<std::string> tokens;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000201 std::string turn_transport_type = kUdpTransportType;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000202 talk_base::tokenize(server.uri, '?', &tokens);
203 std::string uri_without_transport = tokens[0];
204 // Let's look into transport= param, if it exists.
205 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
206 std::string uri_transport_param = tokens[1];
207 talk_base::tokenize(uri_transport_param, '=', &tokens);
208 if (tokens[0] == kTransport) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000209 // As per above grammar transport param will be consist of lower case
210 // letters.
211 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
212 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
213 continue;
214 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000215 turn_transport_type = tokens[1];
216 }
217 }
218
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000219 std::string hoststring;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000220 ServiceType service_type = INVALID;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000221 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
222 &service_type,
223 &hoststring)) {
224 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: "
225 << uri_without_transport;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000226 continue;
227 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000228
229 // Let's break hostname.
230 tokens.clear();
231 talk_base::tokenize(hoststring, '@', &tokens);
232 hoststring = tokens[0];
233 if (tokens.size() == kTurnHostTokensNum) {
234 server.username = talk_base::s_url_decode(tokens[0]);
235 hoststring = tokens[1];
236 }
237
wu@webrtc.org91053e72013-08-10 07:18:04 +0000238 int port = kDefaultStunPort;
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000239 if (service_type == TURNS) {
240 port = kDefaultStunTlsPort;
241 turn_transport_type = kTcpTransportType;
242 }
243
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000244 std::string address;
245 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
246 LOG(WARNING) << "Invalid Hostname format: " << uri_without_transport;
247 continue;
248 }
249
wu@webrtc.org91053e72013-08-10 07:18:04 +0000250
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000251 if (port <= 0 || port > 0xffff) {
252 LOG(WARNING) << "Invalid port: " << port;
253 continue;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000254 }
255
256 switch (service_type) {
257 case STUN:
258 case STUNS:
259 stun_config->push_back(StunConfiguration(address, port));
260 break;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000261 case TURN:
262 case TURNS: {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000263 if (server.username.empty()) {
264 // Turn url example from the spec |url:"turn:user@turn.example.org"|.
265 std::vector<std::string> turn_tokens;
266 talk_base::tokenize(address, '@', &turn_tokens);
267 if (turn_tokens.size() == kTurnHostTokensNum) {
268 server.username = talk_base::s_url_decode(turn_tokens[0]);
269 address = turn_tokens[1];
270 }
271 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000272
273 bool secure = (service_type == TURNS);
274
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000275 turn_config->push_back(TurnConfiguration(address, port,
276 server.username,
277 server.password,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000278 turn_transport_type,
279 secure));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000280 // STUN functionality is part of TURN.
wu@webrtc.org91053e72013-08-10 07:18:04 +0000281 // Note: If there is only TURNS is supplied as part of configuration,
282 // we will have problem in fetching server reflexive candidate, as
283 // currently we don't have support of TCP/TLS in stunport.cc.
284 // In that case we should fetch server reflexive addess from
285 // TURN allocate response.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000286 stun_config->push_back(StunConfiguration(address, port));
287 break;
288 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000289 case INVALID:
290 default:
291 LOG(WARNING) << "Configuration not supported: " << server.uri;
292 return false;
293 }
294 }
295 return true;
296}
297
298// Check if we can send |new_stream| on a PeerConnection.
299// Currently only one audio but multiple video track is supported per
300// PeerConnection.
301bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
302 webrtc::MediaStreamInterface* new_stream) {
303 if (!new_stream || !current_streams)
304 return false;
305 if (current_streams->find(new_stream->label()) != NULL) {
306 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
307 << " is already added.";
308 return false;
309 }
310
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000311 return true;
312}
313
314} // namespace
315
316namespace webrtc {
317
318PeerConnection::PeerConnection(PeerConnectionFactory* factory)
319 : factory_(factory),
320 observer_(NULL),
321 signaling_state_(kStable),
322 ice_state_(kIceNew),
323 ice_connection_state_(kIceConnectionNew),
324 ice_gathering_state_(kIceGatheringNew) {
325}
326
327PeerConnection::~PeerConnection() {
328 if (mediastream_signaling_)
329 mediastream_signaling_->TearDown();
330 if (stream_handler_container_)
331 stream_handler_container_->TearDown();
332}
333
334bool PeerConnection::Initialize(
335 const PeerConnectionInterface::IceServers& configuration,
336 const MediaConstraintsInterface* constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000337 PortAllocatorFactoryInterface* allocator_factory,
338 DTLSIdentityServiceInterface* dtls_identity_service,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000339 PeerConnectionObserver* observer) {
340 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
341 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
342 if (!ParseIceServers(configuration, &stun_config, &turn_config)) {
343 return false;
344 }
345
346 return DoInitialize(stun_config, turn_config, constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000347 allocator_factory, dtls_identity_service, observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000348}
349
350bool PeerConnection::DoInitialize(
351 const StunConfigurations& stun_config,
352 const TurnConfigurations& turn_config,
353 const MediaConstraintsInterface* constraints,
354 webrtc::PortAllocatorFactoryInterface* allocator_factory,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000355 DTLSIdentityServiceInterface* dtls_identity_service,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000356 PeerConnectionObserver* observer) {
357 ASSERT(observer != NULL);
358 if (!observer)
359 return false;
360 observer_ = observer;
361 port_allocator_.reset(
362 allocator_factory->CreatePortAllocator(stun_config, turn_config));
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000363
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000364 // To handle both internal and externally created port allocator, we will
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000365 // enable BUNDLE here.
366 int portallocator_flags = cricket::PORTALLOCATOR_ENABLE_BUNDLE |
367 cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
368 cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET;
369 bool value;
370 if (FindConstraint(
371 constraints,
372 MediaConstraintsInterface::kEnableIPv6,
373 &value, NULL) && value) {
374 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6;
375 }
376
377 port_allocator_->set_flags(portallocator_flags);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000378 // No step delay is used while allocating ports.
379 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
380
381 mediastream_signaling_.reset(new MediaStreamSignaling(
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000382 factory_->signaling_thread(), this, factory_->channel_manager()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000383
384 session_.reset(new WebRtcSession(factory_->channel_manager(),
385 factory_->signaling_thread(),
386 factory_->worker_thread(),
387 port_allocator_.get(),
388 mediastream_signaling_.get()));
389 stream_handler_container_.reset(new MediaStreamHandlerContainer(
390 session_.get(), session_.get()));
391 stats_.set_session(session_.get());
392
393 // Initialize the WebRtcSession. It creates transport channels etc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000394 if (!session_->Initialize(factory_->options(), constraints,
395 dtls_identity_service))
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000396 return false;
397
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000398 // Register PeerConnection as receiver of local ice candidates.
399 // All the callbacks will be posted to the application from PeerConnection.
400 session_->RegisterIceObserver(this);
401 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
402 return true;
403}
404
405talk_base::scoped_refptr<StreamCollectionInterface>
406PeerConnection::local_streams() {
407 return mediastream_signaling_->local_streams();
408}
409
410talk_base::scoped_refptr<StreamCollectionInterface>
411PeerConnection::remote_streams() {
412 return mediastream_signaling_->remote_streams();
413}
414
415bool PeerConnection::AddStream(MediaStreamInterface* local_stream,
416 const MediaConstraintsInterface* constraints) {
417 if (IsClosed()) {
418 return false;
419 }
420 if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(),
421 local_stream))
422 return false;
423
424 // TODO(perkj): Implement support for MediaConstraints in AddStream.
425 if (!mediastream_signaling_->AddLocalStream(local_stream)) {
426 return false;
427 }
428 stats_.AddStream(local_stream);
429 observer_->OnRenegotiationNeeded();
430 return true;
431}
432
433void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000434 mediastream_signaling_->RemoveLocalStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000435 if (IsClosed()) {
436 return;
437 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000438 observer_->OnRenegotiationNeeded();
439}
440
441talk_base::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
442 AudioTrackInterface* track) {
443 if (!track) {
444 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
445 return NULL;
446 }
447 if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) {
448 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
449 return NULL;
450 }
451
452 talk_base::scoped_refptr<DtmfSenderInterface> sender(
453 DtmfSender::Create(track, signaling_thread(), session_.get()));
454 if (!sender.get()) {
455 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
456 return NULL;
457 }
458 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
459}
460
461bool PeerConnection::GetStats(StatsObserver* observer,
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000462 webrtc::MediaStreamTrackInterface* track) {
463 return GetStats(observer, track, kStatsOutputLevelStandard);
464}
465
466bool PeerConnection::GetStats(StatsObserver* observer,
467 MediaStreamTrackInterface* track,
468 StatsOutputLevel level) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000469 if (!VERIFY(observer != NULL)) {
470 LOG(LS_ERROR) << "GetStats - observer is NULL.";
471 return false;
472 }
473
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000474 stats_.UpdateStats(level);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000475 talk_base::scoped_ptr<GetStatsMsg> msg(new GetStatsMsg(observer));
476 if (!stats_.GetStats(track, &(msg->reports))) {
477 return false;
478 }
479 signaling_thread()->Post(this, MSG_GETSTATS, msg.release());
480 return true;
481}
482
483PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
484 return signaling_state_;
485}
486
487PeerConnectionInterface::IceState PeerConnection::ice_state() {
488 return ice_state_;
489}
490
491PeerConnectionInterface::IceConnectionState
492PeerConnection::ice_connection_state() {
493 return ice_connection_state_;
494}
495
496PeerConnectionInterface::IceGatheringState
497PeerConnection::ice_gathering_state() {
498 return ice_gathering_state_;
499}
500
501talk_base::scoped_refptr<DataChannelInterface>
502PeerConnection::CreateDataChannel(
503 const std::string& label,
504 const DataChannelInit* config) {
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000505 talk_base::scoped_ptr<InternalDataChannelInit> internal_config;
506 if (config) {
507 internal_config.reset(new InternalDataChannelInit(*config));
508 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000509 talk_base::scoped_refptr<DataChannelInterface> channel(
henrika@webrtc.orgaebb1ad2014-01-14 10:00:58 +0000510 session_->CreateDataChannel(label, internal_config.get()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000511 if (!channel.get())
512 return NULL;
513
514 observer_->OnRenegotiationNeeded();
wu@webrtc.org91053e72013-08-10 07:18:04 +0000515
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000516 return DataChannelProxy::Create(signaling_thread(), channel.get());
517}
518
519void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
520 const MediaConstraintsInterface* constraints) {
521 if (!VERIFY(observer != NULL)) {
522 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
523 return;
524 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000525 session_->CreateOffer(observer, constraints);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000526}
527
528void PeerConnection::CreateAnswer(
529 CreateSessionDescriptionObserver* observer,
530 const MediaConstraintsInterface* constraints) {
531 if (!VERIFY(observer != NULL)) {
532 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
533 return;
534 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000535 session_->CreateAnswer(observer, constraints);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000536}
537
538void PeerConnection::SetLocalDescription(
539 SetSessionDescriptionObserver* observer,
540 SessionDescriptionInterface* desc) {
541 if (!VERIFY(observer != NULL)) {
542 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
543 return;
544 }
545 if (!desc) {
546 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
547 return;
548 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000549 // Update stats here so that we have the most recent stats for tracks and
550 // streams that might be removed by updating the session description.
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000551 stats_.UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000552 std::string error;
553 if (!session_->SetLocalDescription(desc, &error)) {
554 PostSetSessionDescriptionFailure(observer, error);
555 return;
556 }
557 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
558 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
559}
560
561void PeerConnection::SetRemoteDescription(
562 SetSessionDescriptionObserver* observer,
563 SessionDescriptionInterface* desc) {
564 if (!VERIFY(observer != NULL)) {
565 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
566 return;
567 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000568 if (!desc) {
569 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
570 return;
571 }
572 // Update stats here so that we have the most recent stats for tracks and
573 // streams that might be removed by updating the session description.
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000574 stats_.UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000575 std::string error;
576 if (!session_->SetRemoteDescription(desc, &error)) {
577 PostSetSessionDescriptionFailure(observer, error);
578 return;
579 }
580 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
581 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
582}
583
584void PeerConnection::PostSetSessionDescriptionFailure(
585 SetSessionDescriptionObserver* observer,
586 const std::string& error) {
587 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
588 msg->error = error;
589 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
590}
591
592bool PeerConnection::UpdateIce(const IceServers& configuration,
593 const MediaConstraintsInterface* constraints) {
594 // TODO(ronghuawu): Implement UpdateIce.
595 LOG(LS_ERROR) << "UpdateIce is not implemented.";
596 return false;
597}
598
599bool PeerConnection::AddIceCandidate(
600 const IceCandidateInterface* ice_candidate) {
601 return session_->ProcessIceMessage(ice_candidate);
602}
603
604const SessionDescriptionInterface* PeerConnection::local_description() const {
605 return session_->local_description();
606}
607
608const SessionDescriptionInterface* PeerConnection::remote_description() const {
609 return session_->remote_description();
610}
611
612void PeerConnection::Close() {
613 // Update stats here so that we have the most recent stats for tracks and
614 // streams before the channels are closed.
wu@webrtc.orgb9a088b2014-02-13 23:18:49 +0000615 stats_.UpdateStats(kStatsOutputLevelStandard);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000616
617 session_->Terminate();
618}
619
620void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
621 cricket::BaseSession::State state) {
622 switch (state) {
623 case cricket::BaseSession::STATE_INIT:
624 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000625 break;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000626 case cricket::BaseSession::STATE_SENTINITIATE:
627 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
628 break;
629 case cricket::BaseSession::STATE_SENTPRACCEPT:
630 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
631 break;
632 case cricket::BaseSession::STATE_RECEIVEDINITIATE:
633 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
634 break;
635 case cricket::BaseSession::STATE_RECEIVEDPRACCEPT:
636 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
637 break;
638 case cricket::BaseSession::STATE_SENTACCEPT:
639 case cricket::BaseSession::STATE_RECEIVEDACCEPT:
640 ChangeSignalingState(PeerConnectionInterface::kStable);
641 break;
642 case cricket::BaseSession::STATE_RECEIVEDTERMINATE:
643 ChangeSignalingState(PeerConnectionInterface::kClosed);
644 break;
645 default:
646 break;
647 }
648}
649
650void PeerConnection::OnMessage(talk_base::Message* msg) {
651 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000652 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
653 SetSessionDescriptionMsg* param =
654 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
655 param->observer->OnSuccess();
656 delete param;
657 break;
658 }
659 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
660 SetSessionDescriptionMsg* param =
661 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
662 param->observer->OnFailure(param->error);
663 delete param;
664 break;
665 }
666 case MSG_GETSTATS: {
667 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
668 param->observer->OnComplete(param->reports);
669 delete param;
670 break;
671 }
672 case MSG_ICECONNECTIONCHANGE: {
673 observer_->OnIceConnectionChange(ice_connection_state_);
674 break;
675 }
676 case MSG_ICEGATHERINGCHANGE: {
677 observer_->OnIceGatheringChange(ice_gathering_state_);
678 break;
679 }
680 case MSG_ICECANDIDATE: {
681 CandidateMsg* data = static_cast<CandidateMsg*>(msg->pdata);
682 observer_->OnIceCandidate(data->candidate.get());
683 delete data;
684 break;
685 }
686 case MSG_ICECOMPLETE: {
687 observer_->OnIceComplete();
688 break;
689 }
690 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);
738}
739void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
740 VideoTrackInterface* video_track,
741 uint32 ssrc) {
742 stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc);
743}
744
745void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
746 AudioTrackInterface* audio_track) {
747 stream_handler_container_->RemoveLocalTrack(stream, audio_track);
748}
749
750void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
751 VideoTrackInterface* video_track) {
752 stream_handler_container_->RemoveLocalTrack(stream, video_track);
753}
754
755void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
756 stream_handler_container_->RemoveLocalStream(stream);
757}
758
759void PeerConnection::OnIceConnectionChange(
760 PeerConnectionInterface::IceConnectionState new_state) {
761 ice_connection_state_ = new_state;
762 signaling_thread()->Post(this, MSG_ICECONNECTIONCHANGE);
763}
764
765void PeerConnection::OnIceGatheringChange(
766 PeerConnectionInterface::IceGatheringState new_state) {
767 if (IsClosed()) {
768 return;
769 }
770 ice_gathering_state_ = new_state;
771 signaling_thread()->Post(this, MSG_ICEGATHERINGCHANGE);
772}
773
774void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
775 JsepIceCandidate* candidate_copy = NULL;
776 if (candidate) {
777 // TODO(ronghuawu): Make IceCandidateInterface reference counted instead
778 // of making a copy.
779 candidate_copy = new JsepIceCandidate(candidate->sdp_mid(),
780 candidate->sdp_mline_index(),
781 candidate->candidate());
782 }
783 // The Post takes the ownership of the |candidate_copy|.
784 signaling_thread()->Post(this, MSG_ICECANDIDATE,
785 new CandidateMsg(candidate_copy));
786}
787
788void PeerConnection::OnIceComplete() {
789 signaling_thread()->Post(this, MSG_ICECOMPLETE);
790}
791
792void PeerConnection::ChangeSignalingState(
793 PeerConnectionInterface::SignalingState signaling_state) {
794 signaling_state_ = signaling_state;
795 if (signaling_state == kClosed) {
796 ice_connection_state_ = kIceConnectionClosed;
797 observer_->OnIceConnectionChange(ice_connection_state_);
798 if (ice_gathering_state_ != kIceGatheringComplete) {
799 ice_gathering_state_ = kIceGatheringComplete;
800 observer_->OnIceGatheringChange(ice_gathering_state_);
801 }
802 }
803 observer_->OnSignalingChange(signaling_state_);
804 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
805}
806
807} // namespace webrtc