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 44namespace { 45 46using webrtc::PeerConnectionInterface; 47 48// The min number of tokens must present in Turn host uri. 49// e.g. user@turn.example.org 50static const size_t kTurnHostTokensNum = 2; 51// Number of tokens must be preset when TURN uri has transport param. 52static const size_t kTurnTransportTokensNum = 2; 53// The default stun port. 54static const int kDefaultStunPort = 3478; 55static const int kDefaultStunTlsPort = 5349; 56static const char kTransport[] = "transport"; 57static const char kUdpTransportType[] = "udp"; 58static const char kTcpTransportType[] = "tcp"; 59 60// NOTE: Must be in the same order as the ServiceType enum. 61static const char* kValidIceServiceTypes[] = { 62 "stun", "stuns", "turn", "turns", "invalid" }; 63 64enum 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 72enum { 73 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0, 74 MSG_SET_SESSIONDESCRIPTION_FAILED, 75 MSG_GETSTATS, 76}; 77 78struct 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 88struct 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 106bool 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| 132bool 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 164typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration 165 StunConfiguration; 166typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration 167 TurnConfiguration; 168 169bool 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@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. 286bool 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 301namespace webrtc { 302 303PeerConnection::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 313PeerConnection::~PeerConnection() { 314 if (mediastream_signaling_) 315 mediastream_signaling_->TearDown(); 316 if (stream_handler_container_) 317 stream_handler_container_->TearDown(); 318} 319 320bool 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 336bool 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 396rtc::scoped_refptr<StreamCollectionInterface> 397PeerConnection::local_streams() { 398 return mediastream_signaling_->local_streams(); 399} 400 401rtc::scoped_refptr<StreamCollectionInterface> 402PeerConnection::remote_streams() { 403 return mediastream_signaling_->remote_streams(); 404} 405 406bool 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 424void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) { 425 mediastream_signaling_->RemoveLocalStream(local_stream); 426 if (IsClosed()) { 427 return; 428 } 429 observer_->OnRenegotiationNeeded(); 430} 431 432rtc::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 452bool 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 467PeerConnectionInterface::SignalingState PeerConnection::signaling_state() { 468 return signaling_state_; 469} 470 471PeerConnectionInterface::IceState PeerConnection::ice_state() { 472 return ice_state_; 473} 474 475PeerConnectionInterface::IceConnectionState 476PeerConnection::ice_connection_state() { 477 return ice_connection_state_; 478} 479 480PeerConnectionInterface::IceGatheringState 481PeerConnection::ice_gathering_state() { 482 return ice_gathering_state_; 483} 484 485rtc::scoped_refptr<DataChannelInterface> 486PeerConnection::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 509void 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 560void 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 569void 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 579void 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 602void 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 625void 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 633bool PeerConnection::UpdateIce(const IceServers& configuration, 634 const MediaConstraintsInterface* constraints) { 635 return false; 636} 637 638bool 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 679bool PeerConnection::AddIceCandidate( 680 const IceCandidateInterface* ice_candidate) { 681 return session_->ProcessIceMessage(ice_candidate); 682} 683 684void 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 696const SessionDescriptionInterface* PeerConnection::local_description() const { 697 return session_->local_description(); 698} 699 700const SessionDescriptionInterface* PeerConnection::remote_description() const { 701 return session_->remote_description(); 702} 703 704void 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 712void 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 742void 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 772void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) { 773 stats_->AddStream(stream); 774 observer_->OnAddStream(stream); 775} 776 777void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) { 778 stream_handler_container_->RemoveRemoteStream(stream); 779 observer_->OnRemoveStream(stream); 780} 781 782void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) { 783 observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(), 784 data_channel)); 785} 786 787void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream, 788 AudioTrackInterface* audio_track, 789 uint32 ssrc) { 790 stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc); 791} 792 793void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream, 794 VideoTrackInterface* video_track, 795 uint32 ssrc) { 796 stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc); 797} 798 799void PeerConnection::OnRemoveRemoteAudioTrack( 800 MediaStreamInterface* stream, 801 AudioTrackInterface* audio_track) { 802 stream_handler_container_->RemoveRemoteTrack(stream, audio_track); 803} 804 805void PeerConnection::OnRemoveRemoteVideoTrack( 806 MediaStreamInterface* stream, 807 VideoTrackInterface* video_track) { 808 stream_handler_container_->RemoveRemoteTrack(stream, video_track); 809} 810void 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} 816void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream, 817 VideoTrackInterface* video_track, 818 uint32 ssrc) { 819 stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc); 820} 821 822void 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 829void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream, 830 VideoTrackInterface* video_track) { 831 stream_handler_container_->RemoveLocalTrack(stream, video_track); 832} 833 834void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) { 835 stream_handler_container_->RemoveLocalStream(stream); 836} 837 838void 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 845void 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 855void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) { 856 ASSERT(signaling_thread()->IsCurrent()); 857 observer_->OnIceCandidate(candidate); 858} 859 860void PeerConnection::OnIceComplete() { 861 ASSERT(signaling_thread()->IsCurrent()); 862 observer_->OnIceComplete(); 863} 864 865void 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