blob: de88f88629eab562be1a9348a6e8daa96941e1d7 [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
45// The min number of tokens in the ice uri.
46static const size_t kMinIceUriTokens = 2;
47// The min number of tokens must present in Turn host uri.
48// e.g. user@turn.example.org
49static const size_t kTurnHostTokensNum = 2;
50// Number of tokens must be preset when TURN uri has transport param.
51static const size_t kTurnTransportTokensNum = 2;
52// The default stun port.
wu@webrtc.org91053e72013-08-10 07:18:04 +000053static const int kDefaultStunPort = 3478;
54static const int kDefaultStunTlsPort = 5349;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000055static const char kTransport[] = "transport";
wu@webrtc.org91053e72013-08-10 07:18:04 +000056static const char kUdpTransportType[] = "udp";
57static const char kTcpTransportType[] = "tcp";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000058
59// NOTE: Must be in the same order as the ServiceType enum.
60static const char* kValidIceServiceTypes[] = {
61 "stun", "stuns", "turn", "turns", "invalid" };
62
63enum ServiceType {
64 STUN, // Indicates a STUN server.
65 STUNS, // Indicates a STUN server used with a TLS session.
66 TURN, // Indicates a TURN server
67 TURNS, // Indicates a TURN server used with a TLS session.
68 INVALID, // Unknown.
69};
70
71enum {
wu@webrtc.org91053e72013-08-10 07:18:04 +000072 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073 MSG_SET_SESSIONDESCRIPTION_FAILED,
74 MSG_GETSTATS,
75 MSG_ICECONNECTIONCHANGE,
76 MSG_ICEGATHERINGCHANGE,
77 MSG_ICECANDIDATE,
78 MSG_ICECOMPLETE,
79};
80
81struct CandidateMsg : public talk_base::MessageData {
82 explicit CandidateMsg(const webrtc::JsepIceCandidate* candidate)
83 : candidate(candidate) {
84 }
85 talk_base::scoped_ptr<const webrtc::JsepIceCandidate> candidate;
86};
87
henrike@webrtc.org28e20752013-07-10 00:45:36 +000088struct SetSessionDescriptionMsg : public talk_base::MessageData {
89 explicit SetSessionDescriptionMsg(
90 webrtc::SetSessionDescriptionObserver* observer)
91 : observer(observer) {
92 }
93
94 talk_base::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
95 std::string error;
96};
97
98struct GetStatsMsg : public talk_base::MessageData {
99 explicit GetStatsMsg(webrtc::StatsObserver* observer)
100 : observer(observer) {
101 }
102 webrtc::StatsReports reports;
103 talk_base::scoped_refptr<webrtc::StatsObserver> observer;
104};
105
106typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
107 StunConfiguration;
108typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
109 TurnConfiguration;
110
111bool ParseIceServers(const PeerConnectionInterface::IceServers& configuration,
112 std::vector<StunConfiguration>* stun_config,
113 std::vector<TurnConfiguration>* turn_config) {
114 // draft-nandakumar-rtcweb-stun-uri-01
115 // stunURI = scheme ":" stun-host [ ":" stun-port ]
116 // scheme = "stun" / "stuns"
117 // stun-host = IP-literal / IPv4address / reg-name
118 // stun-port = *DIGIT
119
120 // draft-petithuguenin-behave-turn-uris-01
121 // turnURI = scheme ":" turn-host [ ":" turn-port ]
122 // [ "?transport=" transport ]
123 // scheme = "turn" / "turns"
124 // transport = "udp" / "tcp" / transport-ext
125 // transport-ext = 1*unreserved
126 // turn-host = IP-literal / IPv4address / reg-name
127 // turn-port = *DIGIT
128
129 // TODO(ronghuawu): Handle IPV6 address
130 for (size_t i = 0; i < configuration.size(); ++i) {
131 webrtc::PeerConnectionInterface::IceServer server = configuration[i];
132 if (server.uri.empty()) {
133 LOG(WARNING) << "Empty uri.";
134 continue;
135 }
136 std::vector<std::string> tokens;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000137 std::string turn_transport_type = kUdpTransportType;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000138 talk_base::tokenize(server.uri, '?', &tokens);
139 std::string uri_without_transport = tokens[0];
140 // Let's look into transport= param, if it exists.
141 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
142 std::string uri_transport_param = tokens[1];
143 talk_base::tokenize(uri_transport_param, '=', &tokens);
144 if (tokens[0] == kTransport) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000145 // As per above grammar transport param will be consist of lower case
146 // letters.
147 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
148 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
149 continue;
150 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000151 turn_transport_type = tokens[1];
152 }
153 }
154
155 tokens.clear();
156 talk_base::tokenize(uri_without_transport, ':', &tokens);
157 if (tokens.size() < kMinIceUriTokens) {
158 LOG(WARNING) << "Invalid uri: " << server.uri;
159 continue;
160 }
161 ServiceType service_type = INVALID;
162 const std::string& type = tokens[0];
163 for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
164 if (type.compare(kValidIceServiceTypes[i]) == 0) {
165 service_type = static_cast<ServiceType>(i);
166 break;
167 }
168 }
169 if (service_type == INVALID) {
170 LOG(WARNING) << "Invalid service type: " << type;
171 continue;
172 }
173 std::string address = tokens[1];
wu@webrtc.org91053e72013-08-10 07:18:04 +0000174 int port = kDefaultStunPort;
wu@webrtc.org78187522013-10-07 23:32:02 +0000175 if (service_type == TURNS) {
wu@webrtc.org91053e72013-08-10 07:18:04 +0000176 port = kDefaultStunTlsPort;
wu@webrtc.org78187522013-10-07 23:32:02 +0000177 turn_transport_type = kTcpTransportType;
178 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000179
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000180 if (tokens.size() > kMinIceUriTokens) {
181 if (!talk_base::FromString(tokens[2], &port)) {
182 LOG(LS_WARNING) << "Failed to parse port string: " << tokens[2];
183 continue;
184 }
185
186 if (port <= 0 || port > 0xffff) {
187 LOG(WARNING) << "Invalid port: " << port;
188 continue;
189 }
190 }
191
192 switch (service_type) {
193 case STUN:
194 case STUNS:
195 stun_config->push_back(StunConfiguration(address, port));
196 break;
wu@webrtc.org91053e72013-08-10 07:18:04 +0000197 case TURN:
198 case TURNS: {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000199 if (server.username.empty()) {
200 // Turn url example from the spec |url:"turn:user@turn.example.org"|.
201 std::vector<std::string> turn_tokens;
202 talk_base::tokenize(address, '@', &turn_tokens);
203 if (turn_tokens.size() == kTurnHostTokensNum) {
204 server.username = talk_base::s_url_decode(turn_tokens[0]);
205 address = turn_tokens[1];
206 }
207 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000208
209 bool secure = (service_type == TURNS);
210
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000211 turn_config->push_back(TurnConfiguration(address, port,
212 server.username,
213 server.password,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000214 turn_transport_type,
215 secure));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000216 // STUN functionality is part of TURN.
wu@webrtc.org91053e72013-08-10 07:18:04 +0000217 // Note: If there is only TURNS is supplied as part of configuration,
218 // we will have problem in fetching server reflexive candidate, as
219 // currently we don't have support of TCP/TLS in stunport.cc.
220 // In that case we should fetch server reflexive addess from
221 // TURN allocate response.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000222 stun_config->push_back(StunConfiguration(address, port));
223 break;
224 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000225 case INVALID:
226 default:
227 LOG(WARNING) << "Configuration not supported: " << server.uri;
228 return false;
229 }
230 }
231 return true;
232}
233
234// Check if we can send |new_stream| on a PeerConnection.
235// Currently only one audio but multiple video track is supported per
236// PeerConnection.
237bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
238 webrtc::MediaStreamInterface* new_stream) {
239 if (!new_stream || !current_streams)
240 return false;
241 if (current_streams->find(new_stream->label()) != NULL) {
242 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
243 << " is already added.";
244 return false;
245 }
246
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000247 return true;
248}
249
250} // namespace
251
252namespace webrtc {
253
254PeerConnection::PeerConnection(PeerConnectionFactory* factory)
255 : factory_(factory),
256 observer_(NULL),
257 signaling_state_(kStable),
258 ice_state_(kIceNew),
259 ice_connection_state_(kIceConnectionNew),
260 ice_gathering_state_(kIceGatheringNew) {
261}
262
263PeerConnection::~PeerConnection() {
264 if (mediastream_signaling_)
265 mediastream_signaling_->TearDown();
266 if (stream_handler_container_)
267 stream_handler_container_->TearDown();
268}
269
270bool PeerConnection::Initialize(
271 const PeerConnectionInterface::IceServers& configuration,
272 const MediaConstraintsInterface* constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000273 PortAllocatorFactoryInterface* allocator_factory,
274 DTLSIdentityServiceInterface* dtls_identity_service,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000275 PeerConnectionObserver* observer) {
276 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
277 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
278 if (!ParseIceServers(configuration, &stun_config, &turn_config)) {
279 return false;
280 }
281
282 return DoInitialize(stun_config, turn_config, constraints,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000283 allocator_factory, dtls_identity_service, observer);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000284}
285
286bool PeerConnection::DoInitialize(
287 const StunConfigurations& stun_config,
288 const TurnConfigurations& turn_config,
289 const MediaConstraintsInterface* constraints,
290 webrtc::PortAllocatorFactoryInterface* allocator_factory,
wu@webrtc.org91053e72013-08-10 07:18:04 +0000291 DTLSIdentityServiceInterface* dtls_identity_service,
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000292 PeerConnectionObserver* observer) {
293 ASSERT(observer != NULL);
294 if (!observer)
295 return false;
296 observer_ = observer;
297 port_allocator_.reset(
298 allocator_factory->CreatePortAllocator(stun_config, turn_config));
299 // To handle both internal and externally created port allocator, we will
300 // enable BUNDLE here. Also enabling TURN and disable legacy relay service.
301 port_allocator_->set_flags(cricket::PORTALLOCATOR_ENABLE_BUNDLE |
302 cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
303 cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET);
304 // No step delay is used while allocating ports.
305 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
306
307 mediastream_signaling_.reset(new MediaStreamSignaling(
wu@webrtc.org967bfff2013-09-19 05:49:50 +0000308 factory_->signaling_thread(), this, factory_->channel_manager()));
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000309
310 session_.reset(new WebRtcSession(factory_->channel_manager(),
311 factory_->signaling_thread(),
312 factory_->worker_thread(),
313 port_allocator_.get(),
314 mediastream_signaling_.get()));
315 stream_handler_container_.reset(new MediaStreamHandlerContainer(
316 session_.get(), session_.get()));
317 stats_.set_session(session_.get());
318
319 // Initialize the WebRtcSession. It creates transport channels etc.
wu@webrtc.org97077a32013-10-25 21:18:33 +0000320 if (!session_->Initialize(factory_->options(), constraints,
321 dtls_identity_service))
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000322 return false;
323
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000324 // Register PeerConnection as receiver of local ice candidates.
325 // All the callbacks will be posted to the application from PeerConnection.
326 session_->RegisterIceObserver(this);
327 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
328 return true;
329}
330
331talk_base::scoped_refptr<StreamCollectionInterface>
332PeerConnection::local_streams() {
333 return mediastream_signaling_->local_streams();
334}
335
336talk_base::scoped_refptr<StreamCollectionInterface>
337PeerConnection::remote_streams() {
338 return mediastream_signaling_->remote_streams();
339}
340
341bool PeerConnection::AddStream(MediaStreamInterface* local_stream,
342 const MediaConstraintsInterface* constraints) {
343 if (IsClosed()) {
344 return false;
345 }
346 if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(),
347 local_stream))
348 return false;
349
350 // TODO(perkj): Implement support for MediaConstraints in AddStream.
351 if (!mediastream_signaling_->AddLocalStream(local_stream)) {
352 return false;
353 }
354 stats_.AddStream(local_stream);
355 observer_->OnRenegotiationNeeded();
356 return true;
357}
358
359void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
fischman@webrtc.org32001ef2013-08-12 23:26:21 +0000360 mediastream_signaling_->RemoveLocalStream(local_stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000361 if (IsClosed()) {
362 return;
363 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000364 observer_->OnRenegotiationNeeded();
365}
366
367talk_base::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
368 AudioTrackInterface* track) {
369 if (!track) {
370 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
371 return NULL;
372 }
373 if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) {
374 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
375 return NULL;
376 }
377
378 talk_base::scoped_refptr<DtmfSenderInterface> sender(
379 DtmfSender::Create(track, signaling_thread(), session_.get()));
380 if (!sender.get()) {
381 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
382 return NULL;
383 }
384 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
385}
386
387bool PeerConnection::GetStats(StatsObserver* observer,
388 MediaStreamTrackInterface* track) {
389 if (!VERIFY(observer != NULL)) {
390 LOG(LS_ERROR) << "GetStats - observer is NULL.";
391 return false;
392 }
393
394 stats_.UpdateStats();
395 talk_base::scoped_ptr<GetStatsMsg> msg(new GetStatsMsg(observer));
396 if (!stats_.GetStats(track, &(msg->reports))) {
397 return false;
398 }
399 signaling_thread()->Post(this, MSG_GETSTATS, msg.release());
400 return true;
401}
402
403PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
404 return signaling_state_;
405}
406
407PeerConnectionInterface::IceState PeerConnection::ice_state() {
408 return ice_state_;
409}
410
411PeerConnectionInterface::IceConnectionState
412PeerConnection::ice_connection_state() {
413 return ice_connection_state_;
414}
415
416PeerConnectionInterface::IceGatheringState
417PeerConnection::ice_gathering_state() {
418 return ice_gathering_state_;
419}
420
421talk_base::scoped_refptr<DataChannelInterface>
422PeerConnection::CreateDataChannel(
423 const std::string& label,
424 const DataChannelInit* config) {
425 talk_base::scoped_refptr<DataChannelInterface> channel(
426 session_->CreateDataChannel(label, config));
427 if (!channel.get())
428 return NULL;
429
wu@webrtc.org91053e72013-08-10 07:18:04 +0000430 // If we've already passed the underlying channel's setup phase, have the
431 // MediaStreamSignaling update data channels manually.
432 if (session_->data_channel() != NULL &&
433 session_->data_channel_type() == cricket::DCT_SCTP) {
434 mediastream_signaling_->UpdateLocalSctpDataChannels();
435 mediastream_signaling_->UpdateRemoteSctpDataChannels();
436 }
437
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000438 observer_->OnRenegotiationNeeded();
wu@webrtc.org91053e72013-08-10 07:18:04 +0000439
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000440 return DataChannelProxy::Create(signaling_thread(), channel.get());
441}
442
443void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
444 const MediaConstraintsInterface* constraints) {
445 if (!VERIFY(observer != NULL)) {
446 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
447 return;
448 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000449 session_->CreateOffer(observer, constraints);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000450}
451
452void PeerConnection::CreateAnswer(
453 CreateSessionDescriptionObserver* observer,
454 const MediaConstraintsInterface* constraints) {
455 if (!VERIFY(observer != NULL)) {
456 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
457 return;
458 }
wu@webrtc.org91053e72013-08-10 07:18:04 +0000459 session_->CreateAnswer(observer, constraints);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000460}
461
462void PeerConnection::SetLocalDescription(
463 SetSessionDescriptionObserver* observer,
464 SessionDescriptionInterface* desc) {
465 if (!VERIFY(observer != NULL)) {
466 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
467 return;
468 }
469 if (!desc) {
470 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
471 return;
472 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000473 // Update stats here so that we have the most recent stats for tracks and
474 // streams that might be removed by updating the session description.
475 stats_.UpdateStats();
476 std::string error;
477 if (!session_->SetLocalDescription(desc, &error)) {
478 PostSetSessionDescriptionFailure(observer, error);
479 return;
480 }
481 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
482 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
483}
484
485void PeerConnection::SetRemoteDescription(
486 SetSessionDescriptionObserver* observer,
487 SessionDescriptionInterface* desc) {
488 if (!VERIFY(observer != NULL)) {
489 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
490 return;
491 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000492 if (!desc) {
493 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
494 return;
495 }
496 // Update stats here so that we have the most recent stats for tracks and
497 // streams that might be removed by updating the session description.
498 stats_.UpdateStats();
499 std::string error;
500 if (!session_->SetRemoteDescription(desc, &error)) {
501 PostSetSessionDescriptionFailure(observer, error);
502 return;
503 }
504 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
505 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
506}
507
508void PeerConnection::PostSetSessionDescriptionFailure(
509 SetSessionDescriptionObserver* observer,
510 const std::string& error) {
511 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
512 msg->error = error;
513 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
514}
515
516bool PeerConnection::UpdateIce(const IceServers& configuration,
517 const MediaConstraintsInterface* constraints) {
518 // TODO(ronghuawu): Implement UpdateIce.
519 LOG(LS_ERROR) << "UpdateIce is not implemented.";
520 return false;
521}
522
523bool PeerConnection::AddIceCandidate(
524 const IceCandidateInterface* ice_candidate) {
525 return session_->ProcessIceMessage(ice_candidate);
526}
527
528const SessionDescriptionInterface* PeerConnection::local_description() const {
529 return session_->local_description();
530}
531
532const SessionDescriptionInterface* PeerConnection::remote_description() const {
533 return session_->remote_description();
534}
535
536void PeerConnection::Close() {
537 // Update stats here so that we have the most recent stats for tracks and
538 // streams before the channels are closed.
539 stats_.UpdateStats();
540
541 session_->Terminate();
542}
543
544void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
545 cricket::BaseSession::State state) {
546 switch (state) {
547 case cricket::BaseSession::STATE_INIT:
548 ChangeSignalingState(PeerConnectionInterface::kStable);
mallinath@webrtc.org19f27e62013-10-13 17:18:27 +0000549 break;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000550 case cricket::BaseSession::STATE_SENTINITIATE:
551 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
552 break;
553 case cricket::BaseSession::STATE_SENTPRACCEPT:
554 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
555 break;
556 case cricket::BaseSession::STATE_RECEIVEDINITIATE:
557 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
558 break;
559 case cricket::BaseSession::STATE_RECEIVEDPRACCEPT:
560 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
561 break;
562 case cricket::BaseSession::STATE_SENTACCEPT:
563 case cricket::BaseSession::STATE_RECEIVEDACCEPT:
564 ChangeSignalingState(PeerConnectionInterface::kStable);
565 break;
566 case cricket::BaseSession::STATE_RECEIVEDTERMINATE:
567 ChangeSignalingState(PeerConnectionInterface::kClosed);
568 break;
569 default:
570 break;
571 }
572}
573
574void PeerConnection::OnMessage(talk_base::Message* msg) {
575 switch (msg->message_id) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000576 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
577 SetSessionDescriptionMsg* param =
578 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
579 param->observer->OnSuccess();
580 delete param;
581 break;
582 }
583 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
584 SetSessionDescriptionMsg* param =
585 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
586 param->observer->OnFailure(param->error);
587 delete param;
588 break;
589 }
590 case MSG_GETSTATS: {
591 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
592 param->observer->OnComplete(param->reports);
593 delete param;
594 break;
595 }
596 case MSG_ICECONNECTIONCHANGE: {
597 observer_->OnIceConnectionChange(ice_connection_state_);
598 break;
599 }
600 case MSG_ICEGATHERINGCHANGE: {
601 observer_->OnIceGatheringChange(ice_gathering_state_);
602 break;
603 }
604 case MSG_ICECANDIDATE: {
605 CandidateMsg* data = static_cast<CandidateMsg*>(msg->pdata);
606 observer_->OnIceCandidate(data->candidate.get());
607 delete data;
608 break;
609 }
610 case MSG_ICECOMPLETE: {
611 observer_->OnIceComplete();
612 break;
613 }
614 default:
615 ASSERT(false && "Not implemented");
616 break;
617 }
618}
619
620void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
621 stats_.AddStream(stream);
622 observer_->OnAddStream(stream);
623}
624
625void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
626 stream_handler_container_->RemoveRemoteStream(stream);
627 observer_->OnRemoveStream(stream);
628}
629
630void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
631 observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
632 data_channel));
633}
634
635void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
636 AudioTrackInterface* audio_track,
637 uint32 ssrc) {
638 stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc);
639}
640
641void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
642 VideoTrackInterface* video_track,
643 uint32 ssrc) {
644 stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc);
645}
646
647void PeerConnection::OnRemoveRemoteAudioTrack(
648 MediaStreamInterface* stream,
649 AudioTrackInterface* audio_track) {
650 stream_handler_container_->RemoveRemoteTrack(stream, audio_track);
651}
652
653void PeerConnection::OnRemoveRemoteVideoTrack(
654 MediaStreamInterface* stream,
655 VideoTrackInterface* video_track) {
656 stream_handler_container_->RemoveRemoteTrack(stream, video_track);
657}
658void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
659 AudioTrackInterface* audio_track,
660 uint32 ssrc) {
661 stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc);
662}
663void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
664 VideoTrackInterface* video_track,
665 uint32 ssrc) {
666 stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc);
667}
668
669void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
670 AudioTrackInterface* audio_track) {
671 stream_handler_container_->RemoveLocalTrack(stream, audio_track);
672}
673
674void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
675 VideoTrackInterface* video_track) {
676 stream_handler_container_->RemoveLocalTrack(stream, video_track);
677}
678
679void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
680 stream_handler_container_->RemoveLocalStream(stream);
681}
682
683void PeerConnection::OnIceConnectionChange(
684 PeerConnectionInterface::IceConnectionState new_state) {
685 ice_connection_state_ = new_state;
686 signaling_thread()->Post(this, MSG_ICECONNECTIONCHANGE);
687}
688
689void PeerConnection::OnIceGatheringChange(
690 PeerConnectionInterface::IceGatheringState new_state) {
691 if (IsClosed()) {
692 return;
693 }
694 ice_gathering_state_ = new_state;
695 signaling_thread()->Post(this, MSG_ICEGATHERINGCHANGE);
696}
697
698void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
699 JsepIceCandidate* candidate_copy = NULL;
700 if (candidate) {
701 // TODO(ronghuawu): Make IceCandidateInterface reference counted instead
702 // of making a copy.
703 candidate_copy = new JsepIceCandidate(candidate->sdp_mid(),
704 candidate->sdp_mline_index(),
705 candidate->candidate());
706 }
707 // The Post takes the ownership of the |candidate_copy|.
708 signaling_thread()->Post(this, MSG_ICECANDIDATE,
709 new CandidateMsg(candidate_copy));
710}
711
712void PeerConnection::OnIceComplete() {
713 signaling_thread()->Post(this, MSG_ICECOMPLETE);
714}
715
716void PeerConnection::ChangeSignalingState(
717 PeerConnectionInterface::SignalingState signaling_state) {
718 signaling_state_ = signaling_state;
719 if (signaling_state == kClosed) {
720 ice_connection_state_ = kIceConnectionClosed;
721 observer_->OnIceConnectionChange(ice_connection_state_);
722 if (ice_gathering_state_ != kIceGatheringComplete) {
723 ice_gathering_state_ = kIceGatheringComplete;
724 observer_->OnIceGatheringChange(ice_gathering_state_);
725 }
726 }
727 observer_->OnSignalingChange(signaling_state_);
728 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
729}
730
731} // namespace webrtc