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