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