blob: e10e8fc953a08126350660cec2aa54f0076ad30c [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"
35#include "talk/app/webrtc/mediastreamhandler.h"
36#include "talk/app/webrtc/streamcollection.h"
37#include "talk/base/logging.h"
38#include "talk/base/stringencode.h"
39#include "talk/session/media/channelmanager.h"
40
41namespace {
42
43using webrtc::PeerConnectionInterface;
44
henrike@webrtc.org28e20752013-07-10 00:45:36 +000045// The min number of tokens must present in Turn host uri.
46// e.g. user@turn.example.org
47static const size_t kTurnHostTokensNum = 2;
48// Number of tokens must be preset when TURN uri has transport param.
49static const size_t kTurnTransportTokensNum = 2;
50// The default stun port.
wu@webrtc.org91053e72013-08-10 07:18:04 +000051static const int kDefaultStunPort = 3478;
52static const int kDefaultStunTlsPort = 5349;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000053static const char kTransport[] = "transport";
wu@webrtc.org91053e72013-08-10 07:18:04 +000054static const char kUdpTransportType[] = "udp";
55static const char kTcpTransportType[] = "tcp";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056
57// NOTE: Must be in the same order as the ServiceType enum.
58static const char* kValidIceServiceTypes[] = {
59 "stun", "stuns", "turn", "turns", "invalid" };
60
61enum ServiceType {
62 STUN, // Indicates a STUN server.
63 STUNS, // Indicates a STUN server used with a TLS session.
64 TURN, // Indicates a TURN server
65 TURNS, // Indicates a TURN server used with a TLS session.
66 INVALID, // Unknown.
67};
68
69enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +000070 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000071 MSG_SET_SESSIONDESCRIPTION_FAILED,
72 MSG_GETSTATS,
73 MSG_ICECONNECTIONCHANGE,
74 MSG_ICEGATHERINGCHANGE,
75 MSG_ICECANDIDATE,
76 MSG_ICECOMPLETE,
77};
78
79struct CandidateMsg : public talk_base::MessageData {
80 explicit CandidateMsg(const webrtc::JsepIceCandidate* candidate)
81 : candidate(candidate) {
82 }
83 talk_base::scoped_ptr<const webrtc::JsepIceCandidate> candidate;
84};
85
henrike@webrtc.org28e20752013-07-10 00:45:36 +000086struct SetSessionDescriptionMsg : public talk_base::MessageData {
87 explicit SetSessionDescriptionMsg(
88 webrtc::SetSessionDescriptionObserver* observer)
89 : observer(observer) {
90 }
91
92 talk_base::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
93 std::string error;
94};
95
96struct GetStatsMsg : public talk_base::MessageData {
97 explicit GetStatsMsg(webrtc::StatsObserver* observer)
98 : observer(observer) {
99 }
100 webrtc::StatsReports reports;
101 talk_base::scoped_refptr<webrtc::StatsObserver> observer;
102};
103
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000104// |in_str| should be of format
105// stunURI = scheme ":" stun-host [ ":" stun-port ]
106// scheme = "stun" / "stuns"
107// stun-host = IP-literal / IPv4address / reg-name
108// stun-port = *DIGIT
109
110// draft-petithuguenin-behave-turn-uris-01
111// turnURI = scheme ":" turn-host [ ":" turn-port ]
112// turn-host = username@IP-literal / IPv4address / reg-name
113bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
114 ServiceType* service_type,
115 std::string* hostname) {
116 std::string::size_type colonpos = in_str.find(':');
117 if (colonpos == std::string::npos) {
118 return false;
119 }
120 std::string type = in_str.substr(0, colonpos);
121 for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
122 if (type.compare(kValidIceServiceTypes[i]) == 0) {
123 *service_type = static_cast<ServiceType>(i);
124 break;
125 }
126 }
127 if (*service_type == INVALID) {
128 return false;
129 }
130 *hostname = in_str.substr(colonpos + 1, std::string::npos);
131 return true;
132}
133
134// This method parses IPv6 and IPv4 literal strings, along with hostnames in
135// standard hostname:port format.
136// Consider following formats as correct.
137// |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
138// |hostname|, |[IPv6 address]|, |IPv4 address|
139bool ParseHostnameAndPortFromString(const std::string& in_str,
140 std::string* host,
141 int* port) {
142 if (in_str.at(0) == '[') {
143 std::string::size_type closebracket = in_str.rfind(']');
144 if (closebracket != std::string::npos) {
145 *host = in_str.substr(1, closebracket - 1);
146 std::string::size_type colonpos = in_str.find(':', closebracket);
147 if (std::string::npos != colonpos) {
148 if (!talk_base::FromString(
149 in_str.substr(closebracket + 2, std::string::npos), port)) {
150 return false;
151 }
152 }
153 } else {
154 return false;
155 }
156 } else {
157 std::string::size_type colonpos = in_str.find(':');
158 if (std::string::npos != colonpos) {
159 *host = in_str.substr(0, colonpos);
160 if (!talk_base::FromString(
161 in_str.substr(colonpos + 1, std::string::npos), port)) {
162 return false;
163 }
164 } else {
165 *host = in_str;
166 }
167 }
168 return true;
169}
170
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000171typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
172 StunConfiguration;
173typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
174 TurnConfiguration;
175
176bool ParseIceServers(const PeerConnectionInterface::IceServers& configuration,
177 std::vector<StunConfiguration>* stun_config,
178 std::vector<TurnConfiguration>* turn_config) {
179 // draft-nandakumar-rtcweb-stun-uri-01
180 // stunURI = scheme ":" stun-host [ ":" stun-port ]
181 // scheme = "stun" / "stuns"
182 // stun-host = IP-literal / IPv4address / reg-name
183 // stun-port = *DIGIT
184
185 // draft-petithuguenin-behave-turn-uris-01
186 // turnURI = scheme ":" turn-host [ ":" turn-port ]
187 // [ "?transport=" transport ]
188 // scheme = "turn" / "turns"
189 // transport = "udp" / "tcp" / transport-ext
190 // transport-ext = 1*unreserved
191 // turn-host = IP-literal / IPv4address / reg-name
192 // turn-port = *DIGIT
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000193 for (size_t i = 0; i < configuration.size(); ++i) {
194 webrtc::PeerConnectionInterface::IceServer server = configuration[i];
195 if (server.uri.empty()) {
196 LOG(WARNING) << "Empty uri.";
197 continue;
198 }
199 std::vector<std::string> tokens;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000200 std::string turn_transport_type = kUdpTransportType;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000201 talk_base::tokenize(server.uri, '?', &tokens);
202 std::string uri_without_transport = tokens[0];
203 // Let's look into transport= param, if it exists.
204 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
205 std::string uri_transport_param = tokens[1];
206 talk_base::tokenize(uri_transport_param, '=', &tokens);
207 if (tokens[0] == kTransport) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000208 // As per above grammar transport param will be consist of lower case
209 // letters.
210 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
211 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
212 continue;
213 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000214 turn_transport_type = tokens[1];
215 }
216 }
217
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000218 std::string hoststring;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000219 ServiceType service_type = INVALID;
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000220 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
221 &service_type,
222 &hoststring)) {
223 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: "
224 << uri_without_transport;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000225 continue;
226 }
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000227
228 // Let's break hostname.
229 tokens.clear();
230 talk_base::tokenize(hoststring, '@', &tokens);
231 hoststring = tokens[0];
232 if (tokens.size() == kTurnHostTokensNum) {
233 server.username = talk_base::s_url_decode(tokens[0]);
234 hoststring = tokens[1];
235 }
236
wu@webrtc.org91053e72013-08-10 07:18:04 +0000237 int port = kDefaultStunPort;
sergeyu@chromium.org5bc25c42013-12-05 00:24:06 +0000238 if (service_type == TURNS) {
239 port = kDefaultStunTlsPort;
240 turn_transport_type = kTcpTransportType;
241 }
242
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000243 std::string address;
244 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
245 LOG(WARNING) << "Invalid Hostname format: " << uri_without_transport;
246 continue;
247 }
248
wu@webrtc.org91053e72013-08-10 07:18:04 +0000249
sergeyu@chromium.orga23f0ca2013-11-13 22:48:52 +0000250 if (port <= 0 || port > 0xffff) {
251 LOG(WARNING) << "Invalid port: " << port;
252 continue;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000253 }
254
255 switch (service_type) {
256 case STUN:
257 case STUNS:
258 stun_config->push_back(StunConfiguration(address, port));
259 break;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000260 case TURN:
261 case TURNS: {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000262 if (server.username.empty()) {
263 // Turn url example from the spec |url:"turn:user@turn.example.org"|.
264 std::vector<std::string> turn_tokens;
265 talk_base::tokenize(address, '@', &turn_tokens);
266 if (turn_tokens.size() == kTurnHostTokensNum) {
267 server.username = talk_base::s_url_decode(turn_tokens[0]);
268 address = turn_tokens[1];
269 }
270 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000271
272 bool secure = (service_type == TURNS);
273
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000274 turn_config->push_back(TurnConfiguration(address, port,
275 server.username,
276 server.password,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000277 turn_transport_type,
278 secure));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000279 // STUN functionality is part of TURN.
wu@webrtc.org91053e72013-08-10 07:18:04 +0000280 // Note: If there is only TURNS is supplied as part of configuration,
281 // we will have problem in fetching server reflexive candidate, as
282 // currently we don't have support of TCP/TLS in stunport.cc.
283 // In that case we should fetch server reflexive addess from
284 // TURN allocate response.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000285 stun_config->push_back(StunConfiguration(address, port));
286 break;
287 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000288 case INVALID:
289 default:
290 LOG(WARNING) << "Configuration not supported: " << server.uri;
291 return false;
292 }
293 }
294 return true;
295}
296
297// Check if we can send |new_stream| on a PeerConnection.
298// Currently only one audio but multiple video track is supported per
299// PeerConnection.
300bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
301 webrtc::MediaStreamInterface* new_stream) {
302 if (!new_stream || !current_streams)
303 return false;
304 if (current_streams->find(new_stream->label()) != NULL) {
305 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
306 << " is already added.";
307 return false;
308 }
309
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000310 return true;
311}
312
313} // namespace
314
315namespace webrtc {
316
317PeerConnection::PeerConnection(PeerConnectionFactory* factory)
318 : factory_(factory),
319 observer_(NULL),
320 signaling_state_(kStable),
321 ice_state_(kIceNew),
322 ice_connection_state_(kIceConnectionNew),
323 ice_gathering_state_(kIceGatheringNew) {
324}
325
326PeerConnection::~PeerConnection() {
327 if (mediastream_signaling_)
328 mediastream_signaling_->TearDown();
329 if (stream_handler_container_)
330 stream_handler_container_->TearDown();
331}
332
333bool PeerConnection::Initialize(
334 const PeerConnectionInterface::IceServers& configuration,
335 const MediaConstraintsInterface* constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000336 PortAllocatorFactoryInterface* allocator_factory,
337 DTLSIdentityServiceInterface* dtls_identity_service,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000338 PeerConnectionObserver* observer) {
339 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
340 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
341 if (!ParseIceServers(configuration, &stun_config, &turn_config)) {
342 return false;
343 }
344
345 return DoInitialize(stun_config, turn_config, constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000346 allocator_factory, dtls_identity_service, observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000347}
348
349bool PeerConnection::DoInitialize(
350 const StunConfigurations& stun_config,
351 const TurnConfigurations& turn_config,
352 const MediaConstraintsInterface* constraints,
353 webrtc::PortAllocatorFactoryInterface* allocator_factory,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000354 DTLSIdentityServiceInterface* dtls_identity_service,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000355 PeerConnectionObserver* observer) {
356 ASSERT(observer != NULL);
357 if (!observer)
358 return false;
359 observer_ = observer;
360 port_allocator_.reset(
361 allocator_factory->CreatePortAllocator(stun_config, turn_config));
362 // To handle both internal and externally created port allocator, we will
henrika@webrtc.org44461fa2014-01-13 09:35:02 +0000363 // enable BUNDLE here. Also enabling TURN and disable legacy relay service.
364 port_allocator_->set_flags(cricket::PORTALLOCATOR_ENABLE_BUNDLE |
365 cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
366 cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET);
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,
451 MediaStreamTrackInterface* track) {
452 if (!VERIFY(observer != NULL)) {
453 LOG(LS_ERROR) << "GetStats - observer is NULL.";
454 return false;
455 }
456
457 stats_.UpdateStats();
458 talk_base::scoped_ptr<GetStatsMsg> msg(new GetStatsMsg(observer));
459 if (!stats_.GetStats(track, &(msg->reports))) {
460 return false;
461 }
462 signaling_thread()->Post(this, MSG_GETSTATS, msg.release());
463 return true;
464}
465
466PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
467 return signaling_state_;
468}
469
470PeerConnectionInterface::IceState PeerConnection::ice_state() {
471 return ice_state_;
472}
473
474PeerConnectionInterface::IceConnectionState
475PeerConnection::ice_connection_state() {
476 return ice_connection_state_;
477}
478
479PeerConnectionInterface::IceGatheringState
480PeerConnection::ice_gathering_state() {
481 return ice_gathering_state_;
482}
483
484talk_base::scoped_refptr<DataChannelInterface>
485PeerConnection::CreateDataChannel(
486 const std::string& label,
487 const DataChannelInit* config) {
488 talk_base::scoped_refptr<DataChannelInterface> channel(
henrika@webrtc.org44461fa2014-01-13 09:35:02 +0000489 session_->CreateDataChannel(label, config));
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.
530 stats_.UpdateStats();
531 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.
553 stats_.UpdateStats();
554 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) {
573 // TODO(ronghuawu): Implement UpdateIce.
574 LOG(LS_ERROR) << "UpdateIce is not implemented.";
575 return false;
576}
577
578bool PeerConnection::AddIceCandidate(
579 const IceCandidateInterface* ice_candidate) {
580 return session_->ProcessIceMessage(ice_candidate);
581}
582
583const SessionDescriptionInterface* PeerConnection::local_description() const {
584 return session_->local_description();
585}
586
587const SessionDescriptionInterface* PeerConnection::remote_description() const {
588 return session_->remote_description();
589}
590
591void PeerConnection::Close() {
592 // Update stats here so that we have the most recent stats for tracks and
593 // streams before the channels are closed.
594 stats_.UpdateStats();
595
596 session_->Terminate();
597}
598
599void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
600 cricket::BaseSession::State state) {
601 switch (state) {
602 case cricket::BaseSession::STATE_INIT:
603 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000604 break;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000605 case cricket::BaseSession::STATE_SENTINITIATE:
606 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
607 break;
608 case cricket::BaseSession::STATE_SENTPRACCEPT:
609 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
610 break;
611 case cricket::BaseSession::STATE_RECEIVEDINITIATE:
612 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
613 break;
614 case cricket::BaseSession::STATE_RECEIVEDPRACCEPT:
615 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
616 break;
617 case cricket::BaseSession::STATE_SENTACCEPT:
618 case cricket::BaseSession::STATE_RECEIVEDACCEPT:
619 ChangeSignalingState(PeerConnectionInterface::kStable);
620 break;
621 case cricket::BaseSession::STATE_RECEIVEDTERMINATE:
622 ChangeSignalingState(PeerConnectionInterface::kClosed);
623 break;
624 default:
625 break;
626 }
627}
628
629void PeerConnection::OnMessage(talk_base::Message* msg) {
630 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000631 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
632 SetSessionDescriptionMsg* param =
633 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
634 param->observer->OnSuccess();
635 delete param;
636 break;
637 }
638 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
639 SetSessionDescriptionMsg* param =
640 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
641 param->observer->OnFailure(param->error);
642 delete param;
643 break;
644 }
645 case MSG_GETSTATS: {
646 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
647 param->observer->OnComplete(param->reports);
648 delete param;
649 break;
650 }
651 case MSG_ICECONNECTIONCHANGE: {
652 observer_->OnIceConnectionChange(ice_connection_state_);
653 break;
654 }
655 case MSG_ICEGATHERINGCHANGE: {
656 observer_->OnIceGatheringChange(ice_gathering_state_);
657 break;
658 }
659 case MSG_ICECANDIDATE: {
660 CandidateMsg* data = static_cast<CandidateMsg*>(msg->pdata);
661 observer_->OnIceCandidate(data->candidate.get());
662 delete data;
663 break;
664 }
665 case MSG_ICECOMPLETE: {
666 observer_->OnIceComplete();
667 break;
668 }
669 default:
670 ASSERT(false && "Not implemented");
671 break;
672 }
673}
674
675void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
676 stats_.AddStream(stream);
677 observer_->OnAddStream(stream);
678}
679
680void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
681 stream_handler_container_->RemoveRemoteStream(stream);
682 observer_->OnRemoveStream(stream);
683}
684
685void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
686 observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
687 data_channel));
688}
689
690void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
691 AudioTrackInterface* audio_track,
692 uint32 ssrc) {
693 stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc);
694}
695
696void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
697 VideoTrackInterface* video_track,
698 uint32 ssrc) {
699 stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc);
700}
701
702void PeerConnection::OnRemoveRemoteAudioTrack(
703 MediaStreamInterface* stream,
704 AudioTrackInterface* audio_track) {
705 stream_handler_container_->RemoveRemoteTrack(stream, audio_track);
706}
707
708void PeerConnection::OnRemoveRemoteVideoTrack(
709 MediaStreamInterface* stream,
710 VideoTrackInterface* video_track) {
711 stream_handler_container_->RemoveRemoteTrack(stream, video_track);
712}
713void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
714 AudioTrackInterface* audio_track,
715 uint32 ssrc) {
716 stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc);
717}
718void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
719 VideoTrackInterface* video_track,
720 uint32 ssrc) {
721 stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc);
722}
723
724void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
725 AudioTrackInterface* audio_track) {
726 stream_handler_container_->RemoveLocalTrack(stream, audio_track);
727}
728
729void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
730 VideoTrackInterface* video_track) {
731 stream_handler_container_->RemoveLocalTrack(stream, video_track);
732}
733
734void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
735 stream_handler_container_->RemoveLocalStream(stream);
736}
737
738void PeerConnection::OnIceConnectionChange(
739 PeerConnectionInterface::IceConnectionState new_state) {
740 ice_connection_state_ = new_state;
741 signaling_thread()->Post(this, MSG_ICECONNECTIONCHANGE);
742}
743
744void PeerConnection::OnIceGatheringChange(
745 PeerConnectionInterface::IceGatheringState new_state) {
746 if (IsClosed()) {
747 return;
748 }
749 ice_gathering_state_ = new_state;
750 signaling_thread()->Post(this, MSG_ICEGATHERINGCHANGE);
751}
752
753void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
754 JsepIceCandidate* candidate_copy = NULL;
755 if (candidate) {
756 // TODO(ronghuawu): Make IceCandidateInterface reference counted instead
757 // of making a copy.
758 candidate_copy = new JsepIceCandidate(candidate->sdp_mid(),
759 candidate->sdp_mline_index(),
760 candidate->candidate());
761 }
762 // The Post takes the ownership of the |candidate_copy|.
763 signaling_thread()->Post(this, MSG_ICECANDIDATE,
764 new CandidateMsg(candidate_copy));
765}
766
767void PeerConnection::OnIceComplete() {
768 signaling_thread()->Post(this, MSG_ICECOMPLETE);
769}
770
771void PeerConnection::ChangeSignalingState(
772 PeerConnectionInterface::SignalingState signaling_state) {
773 signaling_state_ = signaling_state;
774 if (signaling_state == kClosed) {
775 ice_connection_state_ = kIceConnectionClosed;
776 observer_->OnIceConnectionChange(ice_connection_state_);
777 if (ice_gathering_state_ != kIceGatheringComplete) {
778 ice_gathering_state_ = kIceGatheringComplete;
779 observer_->OnIceGatheringChange(ice_gathering_state_);
780 }
781 }
782 observer_->OnSignalingChange(signaling_state_);
783 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
784}
785
786} // namespace webrtc