blob: 6d3417aab66a4ca67be0773ef447c55e551cb6a7 [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.
53static const int kDefaultPort = 3478;
54static const char kTransport[] = "transport";
55static const char kDefaultTransportType[] = "udp";
56
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 {
70 MSG_CREATE_SESSIONDESCRIPTION_SUCCESS = 0,
71 MSG_CREATE_SESSIONDESCRIPTION_FAILED,
72 MSG_SET_SESSIONDESCRIPTION_SUCCESS,
73 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
88struct CreateSessionDescriptionMsg : public talk_base::MessageData {
89 explicit CreateSessionDescriptionMsg(
90 webrtc::CreateSessionDescriptionObserver* observer)
91 : observer(observer) {
92 }
93
94 talk_base::scoped_refptr<webrtc::CreateSessionDescriptionObserver> observer;
95 std::string error;
96 talk_base::scoped_ptr<webrtc::SessionDescriptionInterface> description;
97};
98
99struct SetSessionDescriptionMsg : public talk_base::MessageData {
100 explicit SetSessionDescriptionMsg(
101 webrtc::SetSessionDescriptionObserver* observer)
102 : observer(observer) {
103 }
104
105 talk_base::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
106 std::string error;
107};
108
109struct GetStatsMsg : public talk_base::MessageData {
110 explicit GetStatsMsg(webrtc::StatsObserver* observer)
111 : observer(observer) {
112 }
113 webrtc::StatsReports reports;
114 talk_base::scoped_refptr<webrtc::StatsObserver> observer;
115};
116
117typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
118 StunConfiguration;
119typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
120 TurnConfiguration;
121
122bool ParseIceServers(const PeerConnectionInterface::IceServers& configuration,
123 std::vector<StunConfiguration>* stun_config,
124 std::vector<TurnConfiguration>* turn_config) {
125 // draft-nandakumar-rtcweb-stun-uri-01
126 // stunURI = scheme ":" stun-host [ ":" stun-port ]
127 // scheme = "stun" / "stuns"
128 // stun-host = IP-literal / IPv4address / reg-name
129 // stun-port = *DIGIT
130
131 // draft-petithuguenin-behave-turn-uris-01
132 // turnURI = scheme ":" turn-host [ ":" turn-port ]
133 // [ "?transport=" transport ]
134 // scheme = "turn" / "turns"
135 // transport = "udp" / "tcp" / transport-ext
136 // transport-ext = 1*unreserved
137 // turn-host = IP-literal / IPv4address / reg-name
138 // turn-port = *DIGIT
139
140 // TODO(ronghuawu): Handle IPV6 address
141 for (size_t i = 0; i < configuration.size(); ++i) {
142 webrtc::PeerConnectionInterface::IceServer server = configuration[i];
143 if (server.uri.empty()) {
144 LOG(WARNING) << "Empty uri.";
145 continue;
146 }
147 std::vector<std::string> tokens;
148 std::string turn_transport_type = kDefaultTransportType;
149 talk_base::tokenize(server.uri, '?', &tokens);
150 std::string uri_without_transport = tokens[0];
151 // Let's look into transport= param, if it exists.
152 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
153 std::string uri_transport_param = tokens[1];
154 talk_base::tokenize(uri_transport_param, '=', &tokens);
155 if (tokens[0] == kTransport) {
156 turn_transport_type = tokens[1];
157 }
158 }
159
160 tokens.clear();
161 talk_base::tokenize(uri_without_transport, ':', &tokens);
162 if (tokens.size() < kMinIceUriTokens) {
163 LOG(WARNING) << "Invalid uri: " << server.uri;
164 continue;
165 }
166 ServiceType service_type = INVALID;
167 const std::string& type = tokens[0];
168 for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
169 if (type.compare(kValidIceServiceTypes[i]) == 0) {
170 service_type = static_cast<ServiceType>(i);
171 break;
172 }
173 }
174 if (service_type == INVALID) {
175 LOG(WARNING) << "Invalid service type: " << type;
176 continue;
177 }
178 std::string address = tokens[1];
179 int port = kDefaultPort;
180 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;
197 case TURN: {
198 if (server.username.empty()) {
199 // Turn url example from the spec |url:"turn:user@turn.example.org"|.
200 std::vector<std::string> turn_tokens;
201 talk_base::tokenize(address, '@', &turn_tokens);
202 if (turn_tokens.size() == kTurnHostTokensNum) {
203 server.username = talk_base::s_url_decode(turn_tokens[0]);
204 address = turn_tokens[1];
205 }
206 }
207 turn_config->push_back(TurnConfiguration(address, port,
208 server.username,
209 server.password,
210 turn_transport_type));
211 // STUN functionality is part of TURN.
212 stun_config->push_back(StunConfiguration(address, port));
213 break;
214 }
215 case TURNS:
216 case INVALID:
217 default:
218 LOG(WARNING) << "Configuration not supported: " << server.uri;
219 return false;
220 }
221 }
222 return true;
223}
224
225// Check if we can send |new_stream| on a PeerConnection.
226// Currently only one audio but multiple video track is supported per
227// PeerConnection.
228bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
229 webrtc::MediaStreamInterface* new_stream) {
230 if (!new_stream || !current_streams)
231 return false;
232 if (current_streams->find(new_stream->label()) != NULL) {
233 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
234 << " is already added.";
235 return false;
236 }
237
238 bool audio_track_exist = false;
239 for (size_t j = 0; j < current_streams->count(); ++j) {
240 if (!audio_track_exist) {
241 audio_track_exist = current_streams->at(j)->GetAudioTracks().size() > 0;
242 }
243 }
244 if (audio_track_exist && (new_stream->GetAudioTracks().size() > 0)) {
245 LOG(LS_ERROR) << "AddStream - Currently only one audio track is supported"
246 << "per PeerConnection.";
247 return false;
248 }
249 return true;
250}
251
252} // namespace
253
254namespace webrtc {
255
256PeerConnection::PeerConnection(PeerConnectionFactory* factory)
257 : factory_(factory),
258 observer_(NULL),
259 signaling_state_(kStable),
260 ice_state_(kIceNew),
261 ice_connection_state_(kIceConnectionNew),
262 ice_gathering_state_(kIceGatheringNew) {
263}
264
265PeerConnection::~PeerConnection() {
266 if (mediastream_signaling_)
267 mediastream_signaling_->TearDown();
268 if (stream_handler_container_)
269 stream_handler_container_->TearDown();
270}
271
272bool PeerConnection::Initialize(
273 const PeerConnectionInterface::IceServers& configuration,
274 const MediaConstraintsInterface* constraints,
275 webrtc::PortAllocatorFactoryInterface* allocator_factory,
276 PeerConnectionObserver* observer) {
277 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
278 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
279 if (!ParseIceServers(configuration, &stun_config, &turn_config)) {
280 return false;
281 }
282
283 return DoInitialize(stun_config, turn_config, constraints,
284 allocator_factory, observer);
285}
286
287bool PeerConnection::DoInitialize(
288 const StunConfigurations& stun_config,
289 const TurnConfigurations& turn_config,
290 const MediaConstraintsInterface* constraints,
291 webrtc::PortAllocatorFactoryInterface* allocator_factory,
292 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(
308 factory_->signaling_thread(), this));
309
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.
320 if (!session_->Initialize(constraints))
321 return false;
322
323
324 // 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) {
360 if (IsClosed()) {
361 return;
362 }
363 mediastream_signaling_->RemoveLocalStream(local_stream);
364 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
430 observer_->OnRenegotiationNeeded();
431 return DataChannelProxy::Create(signaling_thread(), channel.get());
432}
433
434void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
435 const MediaConstraintsInterface* constraints) {
436 if (!VERIFY(observer != NULL)) {
437 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
438 return;
439 }
440 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
441 msg->description.reset(
442 session_->CreateOffer(constraints));
443
444 if (!msg->description) {
445 msg->error = "CreateOffer failed.";
446 signaling_thread()->Post(this, MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
447 return;
448 }
449
450 signaling_thread()->Post(this, MSG_CREATE_SESSIONDESCRIPTION_SUCCESS, msg);
451}
452
453void PeerConnection::CreateAnswer(
454 CreateSessionDescriptionObserver* observer,
455 const MediaConstraintsInterface* constraints) {
456 if (!VERIFY(observer != NULL)) {
457 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
458 return;
459 }
460 CreateSessionDescriptionMsg* msg = new CreateSessionDescriptionMsg(observer);
461 msg->description.reset(session_->CreateAnswer(constraints));
462 if (!msg->description) {
463 msg->error = "CreateAnswer failed.";
464 signaling_thread()->Post(this, MSG_CREATE_SESSIONDESCRIPTION_FAILED, msg);
465 return;
466 }
467
468 signaling_thread()->Post(this, MSG_CREATE_SESSIONDESCRIPTION_SUCCESS, msg);
469}
470
471void PeerConnection::SetLocalDescription(
472 SetSessionDescriptionObserver* observer,
473 SessionDescriptionInterface* desc) {
474 if (!VERIFY(observer != NULL)) {
475 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
476 return;
477 }
478 if (!desc) {
479 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
480 return;
481 }
482
483 // Update stats here so that we have the most recent stats for tracks and
484 // streams that might be removed by updating the session description.
485 stats_.UpdateStats();
486 std::string error;
487 if (!session_->SetLocalDescription(desc, &error)) {
488 PostSetSessionDescriptionFailure(observer, error);
489 return;
490 }
491 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
492 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
493}
494
495void PeerConnection::SetRemoteDescription(
496 SetSessionDescriptionObserver* observer,
497 SessionDescriptionInterface* desc) {
498 if (!VERIFY(observer != NULL)) {
499 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
500 return;
501 }
502
503 if (!desc) {
504 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
505 return;
506 }
507 // Update stats here so that we have the most recent stats for tracks and
508 // streams that might be removed by updating the session description.
509 stats_.UpdateStats();
510 std::string error;
511 if (!session_->SetRemoteDescription(desc, &error)) {
512 PostSetSessionDescriptionFailure(observer, error);
513 return;
514 }
515 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
516 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
517}
518
519void PeerConnection::PostSetSessionDescriptionFailure(
520 SetSessionDescriptionObserver* observer,
521 const std::string& error) {
522 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
523 msg->error = error;
524 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
525}
526
527bool PeerConnection::UpdateIce(const IceServers& configuration,
528 const MediaConstraintsInterface* constraints) {
529 // TODO(ronghuawu): Implement UpdateIce.
530 LOG(LS_ERROR) << "UpdateIce is not implemented.";
531 return false;
532}
533
534bool PeerConnection::AddIceCandidate(
535 const IceCandidateInterface* ice_candidate) {
536 return session_->ProcessIceMessage(ice_candidate);
537}
538
539const SessionDescriptionInterface* PeerConnection::local_description() const {
540 return session_->local_description();
541}
542
543const SessionDescriptionInterface* PeerConnection::remote_description() const {
544 return session_->remote_description();
545}
546
547void PeerConnection::Close() {
548 // Update stats here so that we have the most recent stats for tracks and
549 // streams before the channels are closed.
550 stats_.UpdateStats();
551
552 session_->Terminate();
553}
554
555void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
556 cricket::BaseSession::State state) {
557 switch (state) {
558 case cricket::BaseSession::STATE_INIT:
559 ChangeSignalingState(PeerConnectionInterface::kStable);
560 case cricket::BaseSession::STATE_SENTINITIATE:
561 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
562 break;
563 case cricket::BaseSession::STATE_SENTPRACCEPT:
564 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
565 break;
566 case cricket::BaseSession::STATE_RECEIVEDINITIATE:
567 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
568 break;
569 case cricket::BaseSession::STATE_RECEIVEDPRACCEPT:
570 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
571 break;
572 case cricket::BaseSession::STATE_SENTACCEPT:
573 case cricket::BaseSession::STATE_RECEIVEDACCEPT:
574 ChangeSignalingState(PeerConnectionInterface::kStable);
575 break;
576 case cricket::BaseSession::STATE_RECEIVEDTERMINATE:
577 ChangeSignalingState(PeerConnectionInterface::kClosed);
578 break;
579 default:
580 break;
581 }
582}
583
584void PeerConnection::OnMessage(talk_base::Message* msg) {
585 switch (msg->message_id) {
586 case MSG_CREATE_SESSIONDESCRIPTION_SUCCESS: {
587 CreateSessionDescriptionMsg* param =
588 static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
589 param->observer->OnSuccess(param->description.release());
590 delete param;
591 break;
592 }
593 case MSG_CREATE_SESSIONDESCRIPTION_FAILED: {
594 CreateSessionDescriptionMsg* param =
595 static_cast<CreateSessionDescriptionMsg*>(msg->pdata);
596 param->observer->OnFailure(param->error);
597 delete param;
598 break;
599 }
600 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
601 SetSessionDescriptionMsg* param =
602 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
603 param->observer->OnSuccess();
604 delete param;
605 break;
606 }
607 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
608 SetSessionDescriptionMsg* param =
609 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
610 param->observer->OnFailure(param->error);
611 delete param;
612 break;
613 }
614 case MSG_GETSTATS: {
615 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
616 param->observer->OnComplete(param->reports);
617 delete param;
618 break;
619 }
620 case MSG_ICECONNECTIONCHANGE: {
621 observer_->OnIceConnectionChange(ice_connection_state_);
622 break;
623 }
624 case MSG_ICEGATHERINGCHANGE: {
625 observer_->OnIceGatheringChange(ice_gathering_state_);
626 break;
627 }
628 case MSG_ICECANDIDATE: {
629 CandidateMsg* data = static_cast<CandidateMsg*>(msg->pdata);
630 observer_->OnIceCandidate(data->candidate.get());
631 delete data;
632 break;
633 }
634 case MSG_ICECOMPLETE: {
635 observer_->OnIceComplete();
636 break;
637 }
638 default:
639 ASSERT(false && "Not implemented");
640 break;
641 }
642}
643
644void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
645 stats_.AddStream(stream);
646 observer_->OnAddStream(stream);
647}
648
649void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
650 stream_handler_container_->RemoveRemoteStream(stream);
651 observer_->OnRemoveStream(stream);
652}
653
654void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
655 observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
656 data_channel));
657}
658
659void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
660 AudioTrackInterface* audio_track,
661 uint32 ssrc) {
662 stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc);
663}
664
665void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
666 VideoTrackInterface* video_track,
667 uint32 ssrc) {
668 stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc);
669}
670
671void PeerConnection::OnRemoveRemoteAudioTrack(
672 MediaStreamInterface* stream,
673 AudioTrackInterface* audio_track) {
674 stream_handler_container_->RemoveRemoteTrack(stream, audio_track);
675}
676
677void PeerConnection::OnRemoveRemoteVideoTrack(
678 MediaStreamInterface* stream,
679 VideoTrackInterface* video_track) {
680 stream_handler_container_->RemoveRemoteTrack(stream, video_track);
681}
682void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
683 AudioTrackInterface* audio_track,
684 uint32 ssrc) {
685 stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc);
686}
687void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
688 VideoTrackInterface* video_track,
689 uint32 ssrc) {
690 stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc);
691}
692
693void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
694 AudioTrackInterface* audio_track) {
695 stream_handler_container_->RemoveLocalTrack(stream, audio_track);
696}
697
698void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
699 VideoTrackInterface* video_track) {
700 stream_handler_container_->RemoveLocalTrack(stream, video_track);
701}
702
703void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
704 stream_handler_container_->RemoveLocalStream(stream);
705}
706
707void PeerConnection::OnIceConnectionChange(
708 PeerConnectionInterface::IceConnectionState new_state) {
709 ice_connection_state_ = new_state;
710 signaling_thread()->Post(this, MSG_ICECONNECTIONCHANGE);
711}
712
713void PeerConnection::OnIceGatheringChange(
714 PeerConnectionInterface::IceGatheringState new_state) {
715 if (IsClosed()) {
716 return;
717 }
718 ice_gathering_state_ = new_state;
719 signaling_thread()->Post(this, MSG_ICEGATHERINGCHANGE);
720}
721
722void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
723 JsepIceCandidate* candidate_copy = NULL;
724 if (candidate) {
725 // TODO(ronghuawu): Make IceCandidateInterface reference counted instead
726 // of making a copy.
727 candidate_copy = new JsepIceCandidate(candidate->sdp_mid(),
728 candidate->sdp_mline_index(),
729 candidate->candidate());
730 }
731 // The Post takes the ownership of the |candidate_copy|.
732 signaling_thread()->Post(this, MSG_ICECANDIDATE,
733 new CandidateMsg(candidate_copy));
734}
735
736void PeerConnection::OnIceComplete() {
737 signaling_thread()->Post(this, MSG_ICECOMPLETE);
738}
739
740void PeerConnection::ChangeSignalingState(
741 PeerConnectionInterface::SignalingState signaling_state) {
742 signaling_state_ = signaling_state;
743 if (signaling_state == kClosed) {
744 ice_connection_state_ = kIceConnectionClosed;
745 observer_->OnIceConnectionChange(ice_connection_state_);
746 if (ice_gathering_state_ != kIceGatheringComplete) {
747 ice_gathering_state_ = kIceGatheringComplete;
748 observer_->OnIceGatheringChange(ice_gathering_state_);
749 }
750 }
751 observer_->OnSignalingChange(signaling_state_);
752 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
753}
754
755} // namespace webrtc