1 /* 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 41 namespace { 42 43 using webrtc::PeerConnectionInterface; 44 45 // The min number of tokens in the ice uri. 46 static const size_t kMinIceUriTokens = 2; 47 // The min number of tokens must present in Turn host uri. 48 // e.g. user (at) turn.example.org 49 static const size_t kTurnHostTokensNum = 2; 50 // Number of tokens must be preset when TURN uri has transport param. 51 static const size_t kTurnTransportTokensNum = 2; 52 // The default stun port. 53 static const int kDefaultStunPort = 3478; 54 static const int kDefaultStunTlsPort = 5349; 55 static const char kTransport[] = "transport"; 56 static const char kUdpTransportType[] = "udp"; 57 static const char kTcpTransportType[] = "tcp"; 58 59 // NOTE: Must be in the same order as the ServiceType enum. 60 static const char* kValidIceServiceTypes[] = { 61 "stun", "stuns", "turn", "turns", "invalid" }; 62 63 enum 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 71 enum { 72 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0, 73 MSG_SET_SESSIONDESCRIPTION_FAILED, 74 MSG_GETSTATS, 75 MSG_ICECONNECTIONCHANGE, 76 MSG_ICEGATHERINGCHANGE, 77 MSG_ICECANDIDATE, 78 MSG_ICECOMPLETE, 79 }; 80 81 struct 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 88 struct 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 98 struct 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 106 typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration 107 StunConfiguration; 108 typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration 109 TurnConfiguration; 110 111 bool 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; 137 std::string turn_transport_type = kUdpTransportType; 138 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) { 145 // 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 } 151 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]; 174 int port = kDefaultStunPort; 175 if (service_type == TURNS) 176 port = kDefaultStunTlsPort; 177 178 if (tokens.size() > kMinIceUriTokens) { 179 if (!talk_base::FromString(tokens[2], &port)) { 180 LOG(LS_WARNING) << "Failed to parse port string: " << tokens[2]; 181 continue; 182 } 183 184 if (port <= 0 || port > 0xffff) { 185 LOG(WARNING) << "Invalid port: " << port; 186 continue; 187 } 188 } 189 190 switch (service_type) { 191 case STUN: 192 case STUNS: 193 stun_config->push_back(StunConfiguration(address, port)); 194 break; 195 case TURN: 196 case TURNS: { 197 if (server.username.empty()) { 198 // Turn url example from the spec |url:"turn:user (at) turn.example.org"|. 199 std::vector<std::string> turn_tokens; 200 talk_base::tokenize(address, '@', &turn_tokens); 201 if (turn_tokens.size() == kTurnHostTokensNum) { 202 server.username = talk_base::s_url_decode(turn_tokens[0]); 203 address = turn_tokens[1]; 204 } 205 } 206 207 bool secure = (service_type == TURNS); 208 209 turn_config->push_back(TurnConfiguration(address, port, 210 server.username, 211 server.password, 212 turn_transport_type, 213 secure)); 214 // STUN functionality is part of TURN. 215 // Note: If there is only TURNS is supplied as part of configuration, 216 // we will have problem in fetching server reflexive candidate, as 217 // currently we don't have support of TCP/TLS in stunport.cc. 218 // In that case we should fetch server reflexive addess from 219 // TURN allocate response. 220 stun_config->push_back(StunConfiguration(address, port)); 221 break; 222 } 223 case INVALID: 224 default: 225 LOG(WARNING) << "Configuration not supported: " << server.uri; 226 return false; 227 } 228 } 229 return true; 230 } 231 232 // Check if we can send |new_stream| on a PeerConnection. 233 // Currently only one audio but multiple video track is supported per 234 // PeerConnection. 235 bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams, 236 webrtc::MediaStreamInterface* new_stream) { 237 if (!new_stream || !current_streams) 238 return false; 239 if (current_streams->find(new_stream->label()) != NULL) { 240 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label() 241 << " is already added."; 242 return false; 243 } 244 245 return true; 246 } 247 248 } // namespace 249 250 namespace webrtc { 251 252 PeerConnection::PeerConnection(PeerConnectionFactory* factory) 253 : factory_(factory), 254 observer_(NULL), 255 signaling_state_(kStable), 256 ice_state_(kIceNew), 257 ice_connection_state_(kIceConnectionNew), 258 ice_gathering_state_(kIceGatheringNew) { 259 } 260 261 PeerConnection::~PeerConnection() { 262 if (mediastream_signaling_) 263 mediastream_signaling_->TearDown(); 264 if (stream_handler_container_) 265 stream_handler_container_->TearDown(); 266 } 267 268 bool PeerConnection::Initialize( 269 const PeerConnectionInterface::IceServers& configuration, 270 const MediaConstraintsInterface* constraints, 271 PortAllocatorFactoryInterface* allocator_factory, 272 DTLSIdentityServiceInterface* dtls_identity_service, 273 PeerConnectionObserver* observer) { 274 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config; 275 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config; 276 if (!ParseIceServers(configuration, &stun_config, &turn_config)) { 277 return false; 278 } 279 280 return DoInitialize(stun_config, turn_config, constraints, 281 allocator_factory, dtls_identity_service, observer); 282 } 283 284 bool PeerConnection::DoInitialize( 285 const StunConfigurations& stun_config, 286 const TurnConfigurations& turn_config, 287 const MediaConstraintsInterface* constraints, 288 webrtc::PortAllocatorFactoryInterface* allocator_factory, 289 DTLSIdentityServiceInterface* dtls_identity_service, 290 PeerConnectionObserver* observer) { 291 ASSERT(observer != NULL); 292 if (!observer) 293 return false; 294 observer_ = observer; 295 port_allocator_.reset( 296 allocator_factory->CreatePortAllocator(stun_config, turn_config)); 297 // To handle both internal and externally created port allocator, we will 298 // enable BUNDLE here. Also enabling TURN and disable legacy relay service. 299 port_allocator_->set_flags(cricket::PORTALLOCATOR_ENABLE_BUNDLE | 300 cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | 301 cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET); 302 // No step delay is used while allocating ports. 303 port_allocator_->set_step_delay(cricket::kMinimumStepDelay); 304 305 mediastream_signaling_.reset(new MediaStreamSignaling( 306 factory_->signaling_thread(), this)); 307 308 session_.reset(new WebRtcSession(factory_->channel_manager(), 309 factory_->signaling_thread(), 310 factory_->worker_thread(), 311 port_allocator_.get(), 312 mediastream_signaling_.get())); 313 stream_handler_container_.reset(new MediaStreamHandlerContainer( 314 session_.get(), session_.get())); 315 stats_.set_session(session_.get()); 316 317 // Initialize the WebRtcSession. It creates transport channels etc. 318 if (!session_->Initialize(constraints, dtls_identity_service)) 319 return false; 320 321 // Register PeerConnection as receiver of local ice candidates. 322 // All the callbacks will be posted to the application from PeerConnection. 323 session_->RegisterIceObserver(this); 324 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange); 325 return true; 326 } 327 328 talk_base::scoped_refptr<StreamCollectionInterface> 329 PeerConnection::local_streams() { 330 return mediastream_signaling_->local_streams(); 331 } 332 333 talk_base::scoped_refptr<StreamCollectionInterface> 334 PeerConnection::remote_streams() { 335 return mediastream_signaling_->remote_streams(); 336 } 337 338 bool PeerConnection::AddStream(MediaStreamInterface* local_stream, 339 const MediaConstraintsInterface* constraints) { 340 if (IsClosed()) { 341 return false; 342 } 343 if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(), 344 local_stream)) 345 return false; 346 347 // TODO(perkj): Implement support for MediaConstraints in AddStream. 348 if (!mediastream_signaling_->AddLocalStream(local_stream)) { 349 return false; 350 } 351 stats_.AddStream(local_stream); 352 observer_->OnRenegotiationNeeded(); 353 return true; 354 } 355 356 void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) { 357 if (IsClosed()) { 358 return; 359 } 360 mediastream_signaling_->RemoveLocalStream(local_stream); 361 observer_->OnRenegotiationNeeded(); 362 } 363 364 talk_base::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender( 365 AudioTrackInterface* track) { 366 if (!track) { 367 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL."; 368 return NULL; 369 } 370 if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) { 371 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track."; 372 return NULL; 373 } 374 375 talk_base::scoped_refptr<DtmfSenderInterface> sender( 376 DtmfSender::Create(track, signaling_thread(), session_.get())); 377 if (!sender.get()) { 378 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create."; 379 return NULL; 380 } 381 return DtmfSenderProxy::Create(signaling_thread(), sender.get()); 382 } 383 384 bool PeerConnection::GetStats(StatsObserver* observer, 385 MediaStreamTrackInterface* track) { 386 if (!VERIFY(observer != NULL)) { 387 LOG(LS_ERROR) << "GetStats - observer is NULL."; 388 return false; 389 } 390 391 stats_.UpdateStats(); 392 talk_base::scoped_ptr<GetStatsMsg> msg(new GetStatsMsg(observer)); 393 if (!stats_.GetStats(track, &(msg->reports))) { 394 return false; 395 } 396 signaling_thread()->Post(this, MSG_GETSTATS, msg.release()); 397 return true; 398 } 399 400 PeerConnectionInterface::SignalingState PeerConnection::signaling_state() { 401 return signaling_state_; 402 } 403 404 PeerConnectionInterface::IceState PeerConnection::ice_state() { 405 return ice_state_; 406 } 407 408 PeerConnectionInterface::IceConnectionState 409 PeerConnection::ice_connection_state() { 410 return ice_connection_state_; 411 } 412 413 PeerConnectionInterface::IceGatheringState 414 PeerConnection::ice_gathering_state() { 415 return ice_gathering_state_; 416 } 417 418 talk_base::scoped_refptr<DataChannelInterface> 419 PeerConnection::CreateDataChannel( 420 const std::string& label, 421 const DataChannelInit* config) { 422 talk_base::scoped_refptr<DataChannelInterface> channel( 423 session_->CreateDataChannel(label, config)); 424 if (!channel.get()) 425 return NULL; 426 427 // If we've already passed the underlying channel's setup phase, have the 428 // MediaStreamSignaling update data channels manually. 429 if (session_->data_channel() != NULL && 430 session_->data_channel_type() == cricket::DCT_SCTP) { 431 mediastream_signaling_->UpdateLocalSctpDataChannels(); 432 mediastream_signaling_->UpdateRemoteSctpDataChannels(); 433 } 434 435 observer_->OnRenegotiationNeeded(); 436 437 return DataChannelProxy::Create(signaling_thread(), channel.get()); 438 } 439 440 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer, 441 const MediaConstraintsInterface* constraints) { 442 if (!VERIFY(observer != NULL)) { 443 LOG(LS_ERROR) << "CreateOffer - observer is NULL."; 444 return; 445 } 446 session_->CreateOffer(observer, constraints); 447 } 448 449 void PeerConnection::CreateAnswer( 450 CreateSessionDescriptionObserver* observer, 451 const MediaConstraintsInterface* constraints) { 452 if (!VERIFY(observer != NULL)) { 453 LOG(LS_ERROR) << "CreateAnswer - observer is NULL."; 454 return; 455 } 456 session_->CreateAnswer(observer, constraints); 457 } 458 459 void PeerConnection::SetLocalDescription( 460 SetSessionDescriptionObserver* observer, 461 SessionDescriptionInterface* desc) { 462 if (!VERIFY(observer != NULL)) { 463 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL."; 464 return; 465 } 466 if (!desc) { 467 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL."); 468 return; 469 } 470 // Update stats here so that we have the most recent stats for tracks and 471 // streams that might be removed by updating the session description. 472 stats_.UpdateStats(); 473 std::string error; 474 if (!session_->SetLocalDescription(desc, &error)) { 475 PostSetSessionDescriptionFailure(observer, error); 476 return; 477 } 478 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer); 479 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg); 480 } 481 482 void PeerConnection::SetRemoteDescription( 483 SetSessionDescriptionObserver* observer, 484 SessionDescriptionInterface* desc) { 485 if (!VERIFY(observer != NULL)) { 486 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL."; 487 return; 488 } 489 if (!desc) { 490 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL."); 491 return; 492 } 493 // Update stats here so that we have the most recent stats for tracks and 494 // streams that might be removed by updating the session description. 495 stats_.UpdateStats(); 496 std::string error; 497 if (!session_->SetRemoteDescription(desc, &error)) { 498 PostSetSessionDescriptionFailure(observer, error); 499 return; 500 } 501 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer); 502 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg); 503 } 504 505 void PeerConnection::PostSetSessionDescriptionFailure( 506 SetSessionDescriptionObserver* observer, 507 const std::string& error) { 508 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer); 509 msg->error = error; 510 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg); 511 } 512 513 bool PeerConnection::UpdateIce(const IceServers& configuration, 514 const MediaConstraintsInterface* constraints) { 515 // TODO(ronghuawu): Implement UpdateIce. 516 LOG(LS_ERROR) << "UpdateIce is not implemented."; 517 return false; 518 } 519 520 bool PeerConnection::AddIceCandidate( 521 const IceCandidateInterface* ice_candidate) { 522 return session_->ProcessIceMessage(ice_candidate); 523 } 524 525 const SessionDescriptionInterface* PeerConnection::local_description() const { 526 return session_->local_description(); 527 } 528 529 const SessionDescriptionInterface* PeerConnection::remote_description() const { 530 return session_->remote_description(); 531 } 532 533 void PeerConnection::Close() { 534 // Update stats here so that we have the most recent stats for tracks and 535 // streams before the channels are closed. 536 stats_.UpdateStats(); 537 538 session_->Terminate(); 539 } 540 541 void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/, 542 cricket::BaseSession::State state) { 543 switch (state) { 544 case cricket::BaseSession::STATE_INIT: 545 ChangeSignalingState(PeerConnectionInterface::kStable); 546 case cricket::BaseSession::STATE_SENTINITIATE: 547 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer); 548 break; 549 case cricket::BaseSession::STATE_SENTPRACCEPT: 550 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer); 551 break; 552 case cricket::BaseSession::STATE_RECEIVEDINITIATE: 553 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer); 554 break; 555 case cricket::BaseSession::STATE_RECEIVEDPRACCEPT: 556 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer); 557 break; 558 case cricket::BaseSession::STATE_SENTACCEPT: 559 case cricket::BaseSession::STATE_RECEIVEDACCEPT: 560 ChangeSignalingState(PeerConnectionInterface::kStable); 561 break; 562 case cricket::BaseSession::STATE_RECEIVEDTERMINATE: 563 ChangeSignalingState(PeerConnectionInterface::kClosed); 564 break; 565 default: 566 break; 567 } 568 } 569 570 void PeerConnection::OnMessage(talk_base::Message* msg) { 571 switch (msg->message_id) { 572 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: { 573 SetSessionDescriptionMsg* param = 574 static_cast<SetSessionDescriptionMsg*>(msg->pdata); 575 param->observer->OnSuccess(); 576 delete param; 577 break; 578 } 579 case MSG_SET_SESSIONDESCRIPTION_FAILED: { 580 SetSessionDescriptionMsg* param = 581 static_cast<SetSessionDescriptionMsg*>(msg->pdata); 582 param->observer->OnFailure(param->error); 583 delete param; 584 break; 585 } 586 case MSG_GETSTATS: { 587 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata); 588 param->observer->OnComplete(param->reports); 589 delete param; 590 break; 591 } 592 case MSG_ICECONNECTIONCHANGE: { 593 observer_->OnIceConnectionChange(ice_connection_state_); 594 break; 595 } 596 case MSG_ICEGATHERINGCHANGE: { 597 observer_->OnIceGatheringChange(ice_gathering_state_); 598 break; 599 } 600 case MSG_ICECANDIDATE: { 601 CandidateMsg* data = static_cast<CandidateMsg*>(msg->pdata); 602 observer_->OnIceCandidate(data->candidate.get()); 603 delete data; 604 break; 605 } 606 case MSG_ICECOMPLETE: { 607 observer_->OnIceComplete(); 608 break; 609 } 610 default: 611 ASSERT(false && "Not implemented"); 612 break; 613 } 614 } 615 616 void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) { 617 stats_.AddStream(stream); 618 observer_->OnAddStream(stream); 619 } 620 621 void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) { 622 stream_handler_container_->RemoveRemoteStream(stream); 623 observer_->OnRemoveStream(stream); 624 } 625 626 void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) { 627 observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(), 628 data_channel)); 629 } 630 631 void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream, 632 AudioTrackInterface* audio_track, 633 uint32 ssrc) { 634 stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc); 635 } 636 637 void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream, 638 VideoTrackInterface* video_track, 639 uint32 ssrc) { 640 stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc); 641 } 642 643 void PeerConnection::OnRemoveRemoteAudioTrack( 644 MediaStreamInterface* stream, 645 AudioTrackInterface* audio_track) { 646 stream_handler_container_->RemoveRemoteTrack(stream, audio_track); 647 } 648 649 void PeerConnection::OnRemoveRemoteVideoTrack( 650 MediaStreamInterface* stream, 651 VideoTrackInterface* video_track) { 652 stream_handler_container_->RemoveRemoteTrack(stream, video_track); 653 } 654 void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream, 655 AudioTrackInterface* audio_track, 656 uint32 ssrc) { 657 stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc); 658 } 659 void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream, 660 VideoTrackInterface* video_track, 661 uint32 ssrc) { 662 stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc); 663 } 664 665 void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream, 666 AudioTrackInterface* audio_track) { 667 stream_handler_container_->RemoveLocalTrack(stream, audio_track); 668 } 669 670 void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream, 671 VideoTrackInterface* video_track) { 672 stream_handler_container_->RemoveLocalTrack(stream, video_track); 673 } 674 675 void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) { 676 stream_handler_container_->RemoveLocalStream(stream); 677 } 678 679 void PeerConnection::OnIceConnectionChange( 680 PeerConnectionInterface::IceConnectionState new_state) { 681 ice_connection_state_ = new_state; 682 signaling_thread()->Post(this, MSG_ICECONNECTIONCHANGE); 683 } 684 685 void PeerConnection::OnIceGatheringChange( 686 PeerConnectionInterface::IceGatheringState new_state) { 687 if (IsClosed()) { 688 return; 689 } 690 ice_gathering_state_ = new_state; 691 signaling_thread()->Post(this, MSG_ICEGATHERINGCHANGE); 692 } 693 694 void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) { 695 JsepIceCandidate* candidate_copy = NULL; 696 if (candidate) { 697 // TODO(ronghuawu): Make IceCandidateInterface reference counted instead 698 // of making a copy. 699 candidate_copy = new JsepIceCandidate(candidate->sdp_mid(), 700 candidate->sdp_mline_index(), 701 candidate->candidate()); 702 } 703 // The Post takes the ownership of the |candidate_copy|. 704 signaling_thread()->Post(this, MSG_ICECANDIDATE, 705 new CandidateMsg(candidate_copy)); 706 } 707 708 void PeerConnection::OnIceComplete() { 709 signaling_thread()->Post(this, MSG_ICECOMPLETE); 710 } 711 712 void PeerConnection::ChangeSignalingState( 713 PeerConnectionInterface::SignalingState signaling_state) { 714 signaling_state_ = signaling_state; 715 if (signaling_state == kClosed) { 716 ice_connection_state_ = kIceConnectionClosed; 717 observer_->OnIceConnectionChange(ice_connection_state_); 718 if (ice_gathering_state_ != kIceGatheringComplete) { 719 ice_gathering_state_ = kIceGatheringComplete; 720 observer_->OnIceGatheringChange(ice_gathering_state_); 721 } 722 } 723 observer_->OnSignalingChange(signaling_state_); 724 observer_->OnStateChange(PeerConnectionObserver::kSignalingState); 725 } 726 727 } // namespace webrtc 728