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