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/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