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/mediaconstraintsinterface.h" 36 #include "talk/app/webrtc/mediastreamhandler.h" 37 #include "talk/app/webrtc/streamcollection.h" 38 #include "talk/p2p/client/basicportallocator.h" 39 #include "talk/session/media/channelmanager.h" 40 #include "webrtc/base/logging.h" 41 #include "webrtc/base/stringencode.h" 42 #include "webrtc/system_wrappers/interface/field_trial.h" 43 44 namespace { 45 46 using webrtc::PeerConnectionInterface; 47 48 // The min number of tokens must present in Turn host uri. 49 // e.g. user (at) turn.example.org 50 static const size_t kTurnHostTokensNum = 2; 51 // Number of tokens must be preset when TURN uri has transport param. 52 static const size_t kTurnTransportTokensNum = 2; 53 // The default stun port. 54 static const int kDefaultStunPort = 3478; 55 static const int kDefaultStunTlsPort = 5349; 56 static const char kTransport[] = "transport"; 57 static const char kUdpTransportType[] = "udp"; 58 static const char kTcpTransportType[] = "tcp"; 59 60 // NOTE: Must be in the same order as the ServiceType enum. 61 static const char* kValidIceServiceTypes[] = { 62 "stun", "stuns", "turn", "turns", "invalid" }; 63 64 enum ServiceType { 65 STUN, // Indicates a STUN server. 66 STUNS, // Indicates a STUN server used with a TLS session. 67 TURN, // Indicates a TURN server 68 TURNS, // Indicates a TURN server used with a TLS session. 69 INVALID, // Unknown. 70 }; 71 72 enum { 73 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0, 74 MSG_SET_SESSIONDESCRIPTION_FAILED, 75 MSG_GETSTATS, 76 }; 77 78 struct SetSessionDescriptionMsg : public rtc::MessageData { 79 explicit SetSessionDescriptionMsg( 80 webrtc::SetSessionDescriptionObserver* observer) 81 : observer(observer) { 82 } 83 84 rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer; 85 std::string error; 86 }; 87 88 struct GetStatsMsg : public rtc::MessageData { 89 GetStatsMsg(webrtc::StatsObserver* observer, 90 webrtc::MediaStreamTrackInterface* track) 91 : observer(observer), track(track) { 92 } 93 rtc::scoped_refptr<webrtc::StatsObserver> observer; 94 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track; 95 }; 96 97 // |in_str| should be of format 98 // stunURI = scheme ":" stun-host [ ":" stun-port ] 99 // scheme = "stun" / "stuns" 100 // stun-host = IP-literal / IPv4address / reg-name 101 // stun-port = *DIGIT 102 103 // draft-petithuguenin-behave-turn-uris-01 104 // turnURI = scheme ":" turn-host [ ":" turn-port ] 105 // turn-host = username@IP-literal / IPv4address / reg-name 106 bool GetServiceTypeAndHostnameFromUri(const std::string& in_str, 107 ServiceType* service_type, 108 std::string* hostname) { 109 std::string::size_type colonpos = in_str.find(':'); 110 if (colonpos == std::string::npos) { 111 return false; 112 } 113 std::string type = in_str.substr(0, colonpos); 114 for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) { 115 if (type.compare(kValidIceServiceTypes[i]) == 0) { 116 *service_type = static_cast<ServiceType>(i); 117 break; 118 } 119 } 120 if (*service_type == INVALID) { 121 return false; 122 } 123 *hostname = in_str.substr(colonpos + 1, std::string::npos); 124 return true; 125 } 126 127 // This method parses IPv6 and IPv4 literal strings, along with hostnames in 128 // standard hostname:port format. 129 // Consider following formats as correct. 130 // |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port, 131 // |hostname|, |[IPv6 address]|, |IPv4 address| 132 bool ParseHostnameAndPortFromString(const std::string& in_str, 133 std::string* host, 134 int* port) { 135 if (in_str.at(0) == '[') { 136 std::string::size_type closebracket = in_str.rfind(']'); 137 if (closebracket != std::string::npos) { 138 *host = in_str.substr(1, closebracket - 1); 139 std::string::size_type colonpos = in_str.find(':', closebracket); 140 if (std::string::npos != colonpos) { 141 if (!rtc::FromString( 142 in_str.substr(closebracket + 2, std::string::npos), port)) { 143 return false; 144 } 145 } 146 } else { 147 return false; 148 } 149 } else { 150 std::string::size_type colonpos = in_str.find(':'); 151 if (std::string::npos != colonpos) { 152 *host = in_str.substr(0, colonpos); 153 if (!rtc::FromString( 154 in_str.substr(colonpos + 1, std::string::npos), port)) { 155 return false; 156 } 157 } else { 158 *host = in_str; 159 } 160 } 161 return true; 162 } 163 164 typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration 165 StunConfiguration; 166 typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration 167 TurnConfiguration; 168 169 bool ParseIceServers(const PeerConnectionInterface::IceServers& configuration, 170 std::vector<StunConfiguration>* stun_config, 171 std::vector<TurnConfiguration>* turn_config) { 172 // draft-nandakumar-rtcweb-stun-uri-01 173 // stunURI = scheme ":" stun-host [ ":" stun-port ] 174 // scheme = "stun" / "stuns" 175 // stun-host = IP-literal / IPv4address / reg-name 176 // stun-port = *DIGIT 177 178 // draft-petithuguenin-behave-turn-uris-01 179 // turnURI = scheme ":" turn-host [ ":" turn-port ] 180 // [ "?transport=" transport ] 181 // scheme = "turn" / "turns" 182 // transport = "udp" / "tcp" / transport-ext 183 // transport-ext = 1*unreserved 184 // turn-host = IP-literal / IPv4address / reg-name 185 // turn-port = *DIGIT 186 for (size_t i = 0; i < configuration.size(); ++i) { 187 webrtc::PeerConnectionInterface::IceServer server = configuration[i]; 188 if (server.uri.empty()) { 189 LOG(WARNING) << "Empty uri."; 190 continue; 191 } 192 std::vector<std::string> tokens; 193 std::string turn_transport_type = kUdpTransportType; 194 rtc::tokenize(server.uri, '?', &tokens); 195 std::string uri_without_transport = tokens[0]; 196 // Let's look into transport= param, if it exists. 197 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present. 198 std::string uri_transport_param = tokens[1]; 199 rtc::tokenize(uri_transport_param, '=', &tokens); 200 if (tokens[0] == kTransport) { 201 // As per above grammar transport param will be consist of lower case 202 // letters. 203 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) { 204 LOG(LS_WARNING) << "Transport param should always be udp or tcp."; 205 continue; 206 } 207 turn_transport_type = tokens[1]; 208 } 209 } 210 211 std::string hoststring; 212 ServiceType service_type = INVALID; 213 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport, 214 &service_type, 215 &hoststring)) { 216 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: " 217 << uri_without_transport; 218 continue; 219 } 220 221 // Let's break hostname. 222 tokens.clear(); 223 rtc::tokenize(hoststring, '@', &tokens); 224 hoststring = tokens[0]; 225 if (tokens.size() == kTurnHostTokensNum) { 226 server.username = rtc::s_url_decode(tokens[0]); 227 hoststring = tokens[1]; 228 } 229 230 int port = kDefaultStunPort; 231 if (service_type == TURNS) { 232 port = kDefaultStunTlsPort; 233 turn_transport_type = kTcpTransportType; 234 } 235 236 std::string address; 237 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) { 238 LOG(WARNING) << "Invalid Hostname format: " << uri_without_transport; 239 continue; 240 } 241 242 243 if (port <= 0 || port > 0xffff) { 244 LOG(WARNING) << "Invalid port: " << port; 245 continue; 246 } 247 248 switch (service_type) { 249 case STUN: 250 case STUNS: 251 stun_config->push_back(StunConfiguration(address, port)); 252 break; 253 case TURN: 254 case TURNS: { 255 if (server.username.empty()) { 256 // Turn url example from the spec |url:"turn:user (at) turn.example.org"|. 257 std::vector<std::string> turn_tokens; 258 rtc::tokenize(address, '@', &turn_tokens); 259 if (turn_tokens.size() == kTurnHostTokensNum) { 260 server.username = rtc::s_url_decode(turn_tokens[0]); 261 address = turn_tokens[1]; 262 } 263 } 264 265 bool secure = (service_type == TURNS); 266 267 turn_config->push_back(TurnConfiguration(address, port, 268 server.username, 269 server.password, 270 turn_transport_type, 271 secure)); 272 break; 273 } 274 case INVALID: 275 default: 276 LOG(WARNING) << "Configuration not supported: " << server.uri; 277 return false; 278 } 279 } 280 return true; 281 } 282 283 // Check if we can send |new_stream| on a PeerConnection. 284 // Currently only one audio but multiple video track is supported per 285 // PeerConnection. 286 bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams, 287 webrtc::MediaStreamInterface* new_stream) { 288 if (!new_stream || !current_streams) 289 return false; 290 if (current_streams->find(new_stream->label()) != NULL) { 291 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label() 292 << " is already added."; 293 return false; 294 } 295 296 return true; 297 } 298 299 } // namespace 300 301 namespace webrtc { 302 303 PeerConnection::PeerConnection(PeerConnectionFactory* factory) 304 : factory_(factory), 305 observer_(NULL), 306 uma_observer_(NULL), 307 signaling_state_(kStable), 308 ice_state_(kIceNew), 309 ice_connection_state_(kIceConnectionNew), 310 ice_gathering_state_(kIceGatheringNew) { 311 } 312 313 PeerConnection::~PeerConnection() { 314 if (mediastream_signaling_) 315 mediastream_signaling_->TearDown(); 316 if (stream_handler_container_) 317 stream_handler_container_->TearDown(); 318 } 319 320 bool PeerConnection::Initialize( 321 const PeerConnectionInterface::RTCConfiguration& configuration, 322 const MediaConstraintsInterface* constraints, 323 PortAllocatorFactoryInterface* allocator_factory, 324 DTLSIdentityServiceInterface* dtls_identity_service, 325 PeerConnectionObserver* observer) { 326 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config; 327 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config; 328 if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) { 329 return false; 330 } 331 332 return DoInitialize(configuration.type, stun_config, turn_config, constraints, 333 allocator_factory, dtls_identity_service, observer); 334 } 335 336 bool PeerConnection::DoInitialize( 337 IceTransportsType type, 338 const StunConfigurations& stun_config, 339 const TurnConfigurations& turn_config, 340 const MediaConstraintsInterface* constraints, 341 webrtc::PortAllocatorFactoryInterface* allocator_factory, 342 DTLSIdentityServiceInterface* dtls_identity_service, 343 PeerConnectionObserver* observer) { 344 ASSERT(observer != NULL); 345 if (!observer) 346 return false; 347 observer_ = observer; 348 port_allocator_.reset( 349 allocator_factory->CreatePortAllocator(stun_config, turn_config)); 350 351 // To handle both internal and externally created port allocator, we will 352 // enable BUNDLE here. 353 int portallocator_flags = cricket::PORTALLOCATOR_ENABLE_BUNDLE | 354 cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG | 355 cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET; 356 bool value; 357 // If IPv6 flag was specified, we'll not override it by experiment. 358 if (FindConstraint( 359 constraints, MediaConstraintsInterface::kEnableIPv6, &value, NULL)) { 360 if (value) { 361 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6; 362 } 363 } else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default") == 364 "Enabled") { 365 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6; 366 } 367 368 port_allocator_->set_flags(portallocator_flags); 369 // No step delay is used while allocating ports. 370 port_allocator_->set_step_delay(cricket::kMinimumStepDelay); 371 372 mediastream_signaling_.reset(new MediaStreamSignaling( 373 factory_->signaling_thread(), this, factory_->channel_manager())); 374 375 session_.reset(new WebRtcSession(factory_->channel_manager(), 376 factory_->signaling_thread(), 377 factory_->worker_thread(), 378 port_allocator_.get(), 379 mediastream_signaling_.get())); 380 stream_handler_container_.reset(new MediaStreamHandlerContainer( 381 session_.get(), session_.get())); 382 stats_.reset(new StatsCollector(session_.get())); 383 384 // Initialize the WebRtcSession. It creates transport channels etc. 385 if (!session_->Initialize(factory_->options(), constraints, 386 dtls_identity_service, type)) 387 return false; 388 389 // Register PeerConnection as receiver of local ice candidates. 390 // All the callbacks will be posted to the application from PeerConnection. 391 session_->RegisterIceObserver(this); 392 session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange); 393 return true; 394 } 395 396 rtc::scoped_refptr<StreamCollectionInterface> 397 PeerConnection::local_streams() { 398 return mediastream_signaling_->local_streams(); 399 } 400 401 rtc::scoped_refptr<StreamCollectionInterface> 402 PeerConnection::remote_streams() { 403 return mediastream_signaling_->remote_streams(); 404 } 405 406 bool PeerConnection::AddStream(MediaStreamInterface* local_stream, 407 const MediaConstraintsInterface* constraints) { 408 if (IsClosed()) { 409 return false; 410 } 411 if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(), 412 local_stream)) 413 return false; 414 415 // TODO(perkj): Implement support for MediaConstraints in AddStream. 416 if (!mediastream_signaling_->AddLocalStream(local_stream)) { 417 return false; 418 } 419 stats_->AddStream(local_stream); 420 observer_->OnRenegotiationNeeded(); 421 return true; 422 } 423 424 void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) { 425 mediastream_signaling_->RemoveLocalStream(local_stream); 426 if (IsClosed()) { 427 return; 428 } 429 observer_->OnRenegotiationNeeded(); 430 } 431 432 rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender( 433 AudioTrackInterface* track) { 434 if (!track) { 435 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL."; 436 return NULL; 437 } 438 if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) { 439 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track."; 440 return NULL; 441 } 442 443 rtc::scoped_refptr<DtmfSenderInterface> sender( 444 DtmfSender::Create(track, signaling_thread(), session_.get())); 445 if (!sender.get()) { 446 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create."; 447 return NULL; 448 } 449 return DtmfSenderProxy::Create(signaling_thread(), sender.get()); 450 } 451 452 bool PeerConnection::GetStats(StatsObserver* observer, 453 MediaStreamTrackInterface* track, 454 StatsOutputLevel level) { 455 ASSERT(signaling_thread()->IsCurrent()); 456 if (!VERIFY(observer != NULL)) { 457 LOG(LS_ERROR) << "GetStats - observer is NULL."; 458 return false; 459 } 460 461 stats_->UpdateStats(level); 462 signaling_thread()->Post(this, MSG_GETSTATS, 463 new GetStatsMsg(observer, track)); 464 return true; 465 } 466 467 PeerConnectionInterface::SignalingState PeerConnection::signaling_state() { 468 return signaling_state_; 469 } 470 471 PeerConnectionInterface::IceState PeerConnection::ice_state() { 472 return ice_state_; 473 } 474 475 PeerConnectionInterface::IceConnectionState 476 PeerConnection::ice_connection_state() { 477 return ice_connection_state_; 478 } 479 480 PeerConnectionInterface::IceGatheringState 481 PeerConnection::ice_gathering_state() { 482 return ice_gathering_state_; 483 } 484 485 rtc::scoped_refptr<DataChannelInterface> 486 PeerConnection::CreateDataChannel( 487 const std::string& label, 488 const DataChannelInit* config) { 489 bool first_datachannel = !mediastream_signaling_->HasDataChannels(); 490 491 rtc::scoped_ptr<InternalDataChannelInit> internal_config; 492 if (config) { 493 internal_config.reset(new InternalDataChannelInit(*config)); 494 } 495 rtc::scoped_refptr<DataChannelInterface> channel( 496 session_->CreateDataChannel(label, internal_config.get())); 497 if (!channel.get()) 498 return NULL; 499 500 // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or 501 // the first SCTP DataChannel. 502 if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) { 503 observer_->OnRenegotiationNeeded(); 504 } 505 506 return DataChannelProxy::Create(signaling_thread(), channel.get()); 507 } 508 509 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer, 510 const MediaConstraintsInterface* constraints) { 511 if (!VERIFY(observer != NULL)) { 512 LOG(LS_ERROR) << "CreateOffer - observer is NULL."; 513 return; 514 } 515 RTCOfferAnswerOptions options; 516 517 bool value; 518 size_t mandatory_constraints = 0; 519 520 if (FindConstraint(constraints, 521 MediaConstraintsInterface::kOfferToReceiveAudio, 522 &value, 523 &mandatory_constraints)) { 524 options.offer_to_receive_audio = 525 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0; 526 } 527 528 if (FindConstraint(constraints, 529 MediaConstraintsInterface::kOfferToReceiveVideo, 530 &value, 531 &mandatory_constraints)) { 532 options.offer_to_receive_video = 533 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0; 534 } 535 536 if (FindConstraint(constraints, 537 MediaConstraintsInterface::kVoiceActivityDetection, 538 &value, 539 &mandatory_constraints)) { 540 options.voice_activity_detection = value; 541 } 542 543 if (FindConstraint(constraints, 544 MediaConstraintsInterface::kIceRestart, 545 &value, 546 &mandatory_constraints)) { 547 options.ice_restart = value; 548 } 549 550 if (FindConstraint(constraints, 551 MediaConstraintsInterface::kUseRtpMux, 552 &value, 553 &mandatory_constraints)) { 554 options.use_rtp_mux = value; 555 } 556 557 CreateOffer(observer, options); 558 } 559 560 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer, 561 const RTCOfferAnswerOptions& options) { 562 if (!VERIFY(observer != NULL)) { 563 LOG(LS_ERROR) << "CreateOffer - observer is NULL."; 564 return; 565 } 566 session_->CreateOffer(observer, options); 567 } 568 569 void PeerConnection::CreateAnswer( 570 CreateSessionDescriptionObserver* observer, 571 const MediaConstraintsInterface* constraints) { 572 if (!VERIFY(observer != NULL)) { 573 LOG(LS_ERROR) << "CreateAnswer - observer is NULL."; 574 return; 575 } 576 session_->CreateAnswer(observer, constraints); 577 } 578 579 void PeerConnection::SetLocalDescription( 580 SetSessionDescriptionObserver* observer, 581 SessionDescriptionInterface* desc) { 582 if (!VERIFY(observer != NULL)) { 583 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL."; 584 return; 585 } 586 if (!desc) { 587 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL."); 588 return; 589 } 590 // Update stats here so that we have the most recent stats for tracks and 591 // streams that might be removed by updating the session description. 592 stats_->UpdateStats(kStatsOutputLevelStandard); 593 std::string error; 594 if (!session_->SetLocalDescription(desc, &error)) { 595 PostSetSessionDescriptionFailure(observer, error); 596 return; 597 } 598 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer); 599 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg); 600 } 601 602 void PeerConnection::SetRemoteDescription( 603 SetSessionDescriptionObserver* observer, 604 SessionDescriptionInterface* desc) { 605 if (!VERIFY(observer != NULL)) { 606 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL."; 607 return; 608 } 609 if (!desc) { 610 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL."); 611 return; 612 } 613 // Update stats here so that we have the most recent stats for tracks and 614 // streams that might be removed by updating the session description. 615 stats_->UpdateStats(kStatsOutputLevelStandard); 616 std::string error; 617 if (!session_->SetRemoteDescription(desc, &error)) { 618 PostSetSessionDescriptionFailure(observer, error); 619 return; 620 } 621 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer); 622 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg); 623 } 624 625 void PeerConnection::PostSetSessionDescriptionFailure( 626 SetSessionDescriptionObserver* observer, 627 const std::string& error) { 628 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer); 629 msg->error = error; 630 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg); 631 } 632 633 bool PeerConnection::UpdateIce(const IceServers& configuration, 634 const MediaConstraintsInterface* constraints) { 635 return false; 636 } 637 638 bool PeerConnection::UpdateIce(const RTCConfiguration& config) { 639 if (port_allocator_) { 640 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns; 641 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns; 642 if (!ParseIceServers(config.servers, &stuns, &turns)) { 643 return false; 644 } 645 646 std::vector<rtc::SocketAddress> stun_hosts; 647 typedef std::vector<StunConfiguration>::const_iterator StunIt; 648 for (StunIt stun_it = stuns.begin(); stun_it != stuns.end(); ++stun_it) { 649 stun_hosts.push_back(stun_it->server); 650 } 651 652 rtc::SocketAddress stun_addr; 653 if (!stun_hosts.empty()) { 654 stun_addr = stun_hosts.front(); 655 LOG(LS_INFO) << "UpdateIce: StunServer Address: " << stun_addr.ToString(); 656 } 657 658 for (size_t i = 0; i < turns.size(); ++i) { 659 cricket::RelayCredentials credentials(turns[i].username, 660 turns[i].password); 661 cricket::RelayServerConfig relay_server(cricket::RELAY_TURN); 662 cricket::ProtocolType protocol; 663 if (cricket::StringToProto(turns[i].transport_type.c_str(), &protocol)) { 664 relay_server.ports.push_back(cricket::ProtocolAddress( 665 turns[i].server, protocol, turns[i].secure)); 666 relay_server.credentials = credentials; 667 LOG(LS_INFO) << "UpdateIce: TurnServer Address: " 668 << turns[i].server.ToString(); 669 } else { 670 LOG(LS_WARNING) << "Ignoring TURN server " << turns[i].server << ". " 671 << "Reason= Incorrect " << turns[i].transport_type 672 << " transport parameter."; 673 } 674 } 675 } 676 return session_->SetIceTransports(config.type); 677 } 678 679 bool PeerConnection::AddIceCandidate( 680 const IceCandidateInterface* ice_candidate) { 681 return session_->ProcessIceMessage(ice_candidate); 682 } 683 684 void PeerConnection::RegisterUMAObserver(UMAObserver* observer) { 685 uma_observer_ = observer; 686 // Send information about IPv4/IPv6 status. 687 if (uma_observer_ && port_allocator_) { 688 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) { 689 uma_observer_->IncrementCounter(kPeerConnection_IPv6); 690 } else { 691 uma_observer_->IncrementCounter(kPeerConnection_IPv4); 692 } 693 } 694 } 695 696 const SessionDescriptionInterface* PeerConnection::local_description() const { 697 return session_->local_description(); 698 } 699 700 const SessionDescriptionInterface* PeerConnection::remote_description() const { 701 return session_->remote_description(); 702 } 703 704 void PeerConnection::Close() { 705 // Update stats here so that we have the most recent stats for tracks and 706 // streams before the channels are closed. 707 stats_->UpdateStats(kStatsOutputLevelStandard); 708 709 session_->Terminate(); 710 } 711 712 void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/, 713 cricket::BaseSession::State state) { 714 switch (state) { 715 case cricket::BaseSession::STATE_INIT: 716 ChangeSignalingState(PeerConnectionInterface::kStable); 717 break; 718 case cricket::BaseSession::STATE_SENTINITIATE: 719 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer); 720 break; 721 case cricket::BaseSession::STATE_SENTPRACCEPT: 722 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer); 723 break; 724 case cricket::BaseSession::STATE_RECEIVEDINITIATE: 725 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer); 726 break; 727 case cricket::BaseSession::STATE_RECEIVEDPRACCEPT: 728 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer); 729 break; 730 case cricket::BaseSession::STATE_SENTACCEPT: 731 case cricket::BaseSession::STATE_RECEIVEDACCEPT: 732 ChangeSignalingState(PeerConnectionInterface::kStable); 733 break; 734 case cricket::BaseSession::STATE_RECEIVEDTERMINATE: 735 ChangeSignalingState(PeerConnectionInterface::kClosed); 736 break; 737 default: 738 break; 739 } 740 } 741 742 void PeerConnection::OnMessage(rtc::Message* msg) { 743 switch (msg->message_id) { 744 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: { 745 SetSessionDescriptionMsg* param = 746 static_cast<SetSessionDescriptionMsg*>(msg->pdata); 747 param->observer->OnSuccess(); 748 delete param; 749 break; 750 } 751 case MSG_SET_SESSIONDESCRIPTION_FAILED: { 752 SetSessionDescriptionMsg* param = 753 static_cast<SetSessionDescriptionMsg*>(msg->pdata); 754 param->observer->OnFailure(param->error); 755 delete param; 756 break; 757 } 758 case MSG_GETSTATS: { 759 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata); 760 StatsReports reports; 761 stats_->GetStats(param->track, &reports); 762 param->observer->OnComplete(reports); 763 delete param; 764 break; 765 } 766 default: 767 ASSERT(false && "Not implemented"); 768 break; 769 } 770 } 771 772 void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) { 773 stats_->AddStream(stream); 774 observer_->OnAddStream(stream); 775 } 776 777 void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) { 778 stream_handler_container_->RemoveRemoteStream(stream); 779 observer_->OnRemoveStream(stream); 780 } 781 782 void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) { 783 observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(), 784 data_channel)); 785 } 786 787 void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream, 788 AudioTrackInterface* audio_track, 789 uint32 ssrc) { 790 stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc); 791 } 792 793 void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream, 794 VideoTrackInterface* video_track, 795 uint32 ssrc) { 796 stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc); 797 } 798 799 void PeerConnection::OnRemoveRemoteAudioTrack( 800 MediaStreamInterface* stream, 801 AudioTrackInterface* audio_track) { 802 stream_handler_container_->RemoveRemoteTrack(stream, audio_track); 803 } 804 805 void PeerConnection::OnRemoveRemoteVideoTrack( 806 MediaStreamInterface* stream, 807 VideoTrackInterface* video_track) { 808 stream_handler_container_->RemoveRemoteTrack(stream, video_track); 809 } 810 void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream, 811 AudioTrackInterface* audio_track, 812 uint32 ssrc) { 813 stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc); 814 stats_->AddLocalAudioTrack(audio_track, ssrc); 815 } 816 void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream, 817 VideoTrackInterface* video_track, 818 uint32 ssrc) { 819 stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc); 820 } 821 822 void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream, 823 AudioTrackInterface* audio_track, 824 uint32 ssrc) { 825 stream_handler_container_->RemoveLocalTrack(stream, audio_track); 826 stats_->RemoveLocalAudioTrack(audio_track, ssrc); 827 } 828 829 void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream, 830 VideoTrackInterface* video_track) { 831 stream_handler_container_->RemoveLocalTrack(stream, video_track); 832 } 833 834 void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) { 835 stream_handler_container_->RemoveLocalStream(stream); 836 } 837 838 void PeerConnection::OnIceConnectionChange( 839 PeerConnectionInterface::IceConnectionState new_state) { 840 ASSERT(signaling_thread()->IsCurrent()); 841 ice_connection_state_ = new_state; 842 observer_->OnIceConnectionChange(ice_connection_state_); 843 } 844 845 void PeerConnection::OnIceGatheringChange( 846 PeerConnectionInterface::IceGatheringState new_state) { 847 ASSERT(signaling_thread()->IsCurrent()); 848 if (IsClosed()) { 849 return; 850 } 851 ice_gathering_state_ = new_state; 852 observer_->OnIceGatheringChange(ice_gathering_state_); 853 } 854 855 void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) { 856 ASSERT(signaling_thread()->IsCurrent()); 857 observer_->OnIceCandidate(candidate); 858 } 859 860 void PeerConnection::OnIceComplete() { 861 ASSERT(signaling_thread()->IsCurrent()); 862 observer_->OnIceComplete(); 863 } 864 865 void PeerConnection::ChangeSignalingState( 866 PeerConnectionInterface::SignalingState signaling_state) { 867 signaling_state_ = signaling_state; 868 if (signaling_state == kClosed) { 869 ice_connection_state_ = kIceConnectionClosed; 870 observer_->OnIceConnectionChange(ice_connection_state_); 871 if (ice_gathering_state_ != kIceGatheringComplete) { 872 ice_gathering_state_ = kIceGatheringComplete; 873 observer_->OnIceGatheringChange(ice_gathering_state_); 874 } 875 } 876 observer_->OnSignalingChange(signaling_state_); 877 observer_->OnStateChange(PeerConnectionObserver::kSignalingState); 878 } 879 880 } // namespace webrtc 881