Upstream version 9.38.198.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/p2p/client/basicportallocator.h"
39 #include "talk/session/media/channelmanager.h"
40 #include "webrtc/base/logging.h"
41 #include "webrtc/base/stringencode.h"
42
43 namespace {
44
45 using webrtc::PeerConnectionInterface;
46
47 // The min number of tokens must present in Turn host uri.
48 // e.g. user@turn.example.org
49 static const size_t kTurnHostTokensNum = 2;
50 // Number of tokens must be preset when TURN uri has transport param.
51 static const size_t kTurnTransportTokensNum = 2;
52 // The default stun port.
53 static const int kDefaultStunPort = 3478;
54 static const int kDefaultStunTlsPort = 5349;
55 static const char kTransport[] = "transport";
56 static const char kUdpTransportType[] = "udp";
57 static const char kTcpTransportType[] = "tcp";
58
59 // NOTE: Must be in the same order as the ServiceType enum.
60 static const char* kValidIceServiceTypes[] = {
61     "stun", "stuns", "turn", "turns", "invalid" };
62
63 enum ServiceType {
64   STUN,     // Indicates a STUN server.
65   STUNS,    // Indicates a STUN server used with a TLS session.
66   TURN,     // Indicates a TURN server
67   TURNS,    // Indicates a TURN server used with a TLS session.
68   INVALID,  // Unknown.
69 };
70
71 enum {
72   MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
73   MSG_SET_SESSIONDESCRIPTION_FAILED,
74   MSG_GETSTATS,
75 };
76
77 struct SetSessionDescriptionMsg : public rtc::MessageData {
78   explicit SetSessionDescriptionMsg(
79       webrtc::SetSessionDescriptionObserver* observer)
80       : observer(observer) {
81   }
82
83   rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
84   std::string error;
85 };
86
87 struct GetStatsMsg : public rtc::MessageData {
88   explicit GetStatsMsg(webrtc::StatsObserver* observer)
89       : observer(observer) {
90   }
91   webrtc::StatsReports reports;
92   rtc::scoped_refptr<webrtc::StatsObserver> observer;
93 };
94
95 // |in_str| should be of format
96 // stunURI       = scheme ":" stun-host [ ":" stun-port ]
97 // scheme        = "stun" / "stuns"
98 // stun-host     = IP-literal / IPv4address / reg-name
99 // stun-port     = *DIGIT
100
101 // draft-petithuguenin-behave-turn-uris-01
102 // turnURI       = scheme ":" turn-host [ ":" turn-port ]
103 // turn-host     = username@IP-literal / IPv4address / reg-name
104 bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
105                                       ServiceType* service_type,
106                                       std::string* hostname) {
107   std::string::size_type colonpos = in_str.find(':');
108   if (colonpos == std::string::npos) {
109     return false;
110   }
111   std::string type = in_str.substr(0, colonpos);
112   for (size_t i = 0; i < ARRAY_SIZE(kValidIceServiceTypes); ++i) {
113     if (type.compare(kValidIceServiceTypes[i]) == 0) {
114       *service_type = static_cast<ServiceType>(i);
115       break;
116     }
117   }
118   if (*service_type == INVALID) {
119     return false;
120   }
121   *hostname = in_str.substr(colonpos + 1, std::string::npos);
122   return true;
123 }
124
125 // This method parses IPv6 and IPv4 literal strings, along with hostnames in
126 // standard hostname:port format.
127 // Consider following formats as correct.
128 // |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
129 // |hostname|, |[IPv6 address]|, |IPv4 address|
130 bool ParseHostnameAndPortFromString(const std::string& in_str,
131                                     std::string* host,
132                                     int* port) {
133   if (in_str.at(0) == '[') {
134     std::string::size_type closebracket = in_str.rfind(']');
135     if (closebracket != std::string::npos) {
136       *host = in_str.substr(1, closebracket - 1);
137       std::string::size_type colonpos = in_str.find(':', closebracket);
138       if (std::string::npos != colonpos) {
139         if (!rtc::FromString(
140             in_str.substr(closebracket + 2, std::string::npos), port)) {
141           return false;
142         }
143       }
144     } else {
145       return false;
146     }
147   } else {
148     std::string::size_type colonpos = in_str.find(':');
149     if (std::string::npos != colonpos) {
150       *host = in_str.substr(0, colonpos);
151       if (!rtc::FromString(
152           in_str.substr(colonpos + 1, std::string::npos), port)) {
153         return false;
154       }
155     } else {
156       *host = in_str;
157     }
158   }
159   return true;
160 }
161
162 typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
163     StunConfiguration;
164 typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
165     TurnConfiguration;
166
167 bool ParseIceServers(const PeerConnectionInterface::IceServers& configuration,
168                      std::vector<StunConfiguration>* stun_config,
169                      std::vector<TurnConfiguration>* turn_config) {
170   // draft-nandakumar-rtcweb-stun-uri-01
171   // stunURI       = scheme ":" stun-host [ ":" stun-port ]
172   // scheme        = "stun" / "stuns"
173   // stun-host     = IP-literal / IPv4address / reg-name
174   // stun-port     = *DIGIT
175
176   // draft-petithuguenin-behave-turn-uris-01
177   // turnURI       = scheme ":" turn-host [ ":" turn-port ]
178   //                 [ "?transport=" transport ]
179   // scheme        = "turn" / "turns"
180   // transport     = "udp" / "tcp" / transport-ext
181   // transport-ext = 1*unreserved
182   // turn-host     = IP-literal / IPv4address / reg-name
183   // turn-port     = *DIGIT
184   for (size_t i = 0; i < configuration.size(); ++i) {
185     webrtc::PeerConnectionInterface::IceServer server = configuration[i];
186     if (server.uri.empty()) {
187       LOG(WARNING) << "Empty uri.";
188       continue;
189     }
190     std::vector<std::string> tokens;
191     std::string turn_transport_type = kUdpTransportType;
192     rtc::tokenize(server.uri, '?', &tokens);
193     std::string uri_without_transport = tokens[0];
194     // Let's look into transport= param, if it exists.
195     if (tokens.size() == kTurnTransportTokensNum) {  // ?transport= is present.
196       std::string uri_transport_param = tokens[1];
197       rtc::tokenize(uri_transport_param, '=', &tokens);
198       if (tokens[0] == kTransport) {
199         // As per above grammar transport param will be consist of lower case
200         // letters.
201         if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
202           LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
203           continue;
204         }
205         turn_transport_type = tokens[1];
206       }
207     }
208
209     std::string hoststring;
210     ServiceType service_type = INVALID;
211     if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
212                                          &service_type,
213                                          &hoststring)) {
214       LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: "
215                       << uri_without_transport;
216       continue;
217     }
218
219     // Let's break hostname.
220     tokens.clear();
221     rtc::tokenize(hoststring, '@', &tokens);
222     hoststring = tokens[0];
223     if (tokens.size() == kTurnHostTokensNum) {
224       server.username = rtc::s_url_decode(tokens[0]);
225       hoststring = tokens[1];
226     }
227
228     int port = kDefaultStunPort;
229     if (service_type == TURNS) {
230       port = kDefaultStunTlsPort;
231       turn_transport_type = kTcpTransportType;
232     }
233
234     std::string address;
235     if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
236       LOG(WARNING) << "Invalid Hostname format: " << uri_without_transport;
237       continue;
238     }
239
240
241     if (port <= 0 || port > 0xffff) {
242       LOG(WARNING) << "Invalid port: " << port;
243       continue;
244     }
245
246     switch (service_type) {
247       case STUN:
248       case STUNS:
249         stun_config->push_back(StunConfiguration(address, port));
250         break;
251       case TURN:
252       case TURNS: {
253         if (server.username.empty()) {
254           // Turn url example from the spec |url:"turn:user@turn.example.org"|.
255           std::vector<std::string> turn_tokens;
256           rtc::tokenize(address, '@', &turn_tokens);
257           if (turn_tokens.size() == kTurnHostTokensNum) {
258             server.username = rtc::s_url_decode(turn_tokens[0]);
259             address = turn_tokens[1];
260           }
261         }
262
263         bool secure = (service_type == TURNS);
264
265         turn_config->push_back(TurnConfiguration(address, port,
266                                                  server.username,
267                                                  server.password,
268                                                  turn_transport_type,
269                                                  secure));
270         break;
271       }
272       case INVALID:
273       default:
274         LOG(WARNING) << "Configuration not supported: " << server.uri;
275         return false;
276     }
277   }
278   return true;
279 }
280
281 // Check if we can send |new_stream| on a PeerConnection.
282 // Currently only one audio but multiple video track is supported per
283 // PeerConnection.
284 bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
285                             webrtc::MediaStreamInterface* new_stream) {
286   if (!new_stream || !current_streams)
287     return false;
288   if (current_streams->find(new_stream->label()) != NULL) {
289     LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
290                   << " is already added.";
291     return false;
292   }
293
294   return true;
295 }
296
297 }  // namespace
298
299 namespace webrtc {
300
301 PeerConnection::PeerConnection(PeerConnectionFactory* factory)
302     : factory_(factory),
303       observer_(NULL),
304       uma_observer_(NULL),
305       signaling_state_(kStable),
306       ice_state_(kIceNew),
307       ice_connection_state_(kIceConnectionNew),
308       ice_gathering_state_(kIceGatheringNew) {
309 }
310
311 PeerConnection::~PeerConnection() {
312   if (mediastream_signaling_)
313     mediastream_signaling_->TearDown();
314   if (stream_handler_container_)
315     stream_handler_container_->TearDown();
316 }
317
318 bool PeerConnection::Initialize(
319     const PeerConnectionInterface::RTCConfiguration& configuration,
320     const MediaConstraintsInterface* constraints,
321     PortAllocatorFactoryInterface* allocator_factory,
322     DTLSIdentityServiceInterface* dtls_identity_service,
323     PeerConnectionObserver* observer) {
324   std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
325   std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
326   if (!ParseIceServers(configuration.servers, &stun_config, &turn_config)) {
327     return false;
328   }
329
330   return DoInitialize(configuration.type, stun_config, turn_config, constraints,
331                       allocator_factory, dtls_identity_service, observer);
332 }
333
334 bool PeerConnection::DoInitialize(
335     IceTransportsType type,
336     const StunConfigurations& stun_config,
337     const TurnConfigurations& turn_config,
338     const MediaConstraintsInterface* constraints,
339     webrtc::PortAllocatorFactoryInterface* allocator_factory,
340     DTLSIdentityServiceInterface* dtls_identity_service,
341     PeerConnectionObserver* observer) {
342   ASSERT(observer != NULL);
343   if (!observer)
344     return false;
345   observer_ = observer;
346   port_allocator_.reset(
347       allocator_factory->CreatePortAllocator(stun_config, turn_config));
348
349   // To handle both internal and externally created port allocator, we will
350   // enable BUNDLE here.
351   int portallocator_flags = cricket::PORTALLOCATOR_ENABLE_BUNDLE |
352                             cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
353                             cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET;
354   bool value;
355   if (FindConstraint(
356         constraints,
357         MediaConstraintsInterface::kEnableIPv6,
358         &value, NULL) && value) {
359     portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6;
360   }
361
362   port_allocator_->set_flags(portallocator_flags);
363   // No step delay is used while allocating ports.
364   port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
365
366   mediastream_signaling_.reset(new MediaStreamSignaling(
367       factory_->signaling_thread(), this, factory_->channel_manager()));
368
369   session_.reset(new WebRtcSession(factory_->channel_manager(),
370                                    factory_->signaling_thread(),
371                                    factory_->worker_thread(),
372                                    port_allocator_.get(),
373                                    mediastream_signaling_.get()));
374   stream_handler_container_.reset(new MediaStreamHandlerContainer(
375       session_.get(), session_.get()));
376   stats_.reset(new StatsCollector(session_.get()));
377
378   // Initialize the WebRtcSession. It creates transport channels etc.
379   if (!session_->Initialize(factory_->options(), constraints,
380                             dtls_identity_service, type))
381     return false;
382
383   // Register PeerConnection as receiver of local ice candidates.
384   // All the callbacks will be posted to the application from PeerConnection.
385   session_->RegisterIceObserver(this);
386   session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
387   return true;
388 }
389
390 rtc::scoped_refptr<StreamCollectionInterface>
391 PeerConnection::local_streams() {
392   return mediastream_signaling_->local_streams();
393 }
394
395 rtc::scoped_refptr<StreamCollectionInterface>
396 PeerConnection::remote_streams() {
397   return mediastream_signaling_->remote_streams();
398 }
399
400 bool PeerConnection::AddStream(MediaStreamInterface* local_stream,
401                                const MediaConstraintsInterface* constraints) {
402   if (IsClosed()) {
403     return false;
404   }
405   if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(),
406                               local_stream))
407     return false;
408
409   // TODO(perkj): Implement support for MediaConstraints in AddStream.
410   if (!mediastream_signaling_->AddLocalStream(local_stream)) {
411     return false;
412   }
413   stats_->AddStream(local_stream);
414   observer_->OnRenegotiationNeeded();
415   return true;
416 }
417
418 void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
419   mediastream_signaling_->RemoveLocalStream(local_stream);
420   if (IsClosed()) {
421     return;
422   }
423   observer_->OnRenegotiationNeeded();
424 }
425
426 rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
427     AudioTrackInterface* track) {
428   if (!track) {
429     LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
430     return NULL;
431   }
432   if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) {
433     LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
434     return NULL;
435   }
436
437   rtc::scoped_refptr<DtmfSenderInterface> sender(
438       DtmfSender::Create(track, signaling_thread(), session_.get()));
439   if (!sender.get()) {
440     LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
441     return NULL;
442   }
443   return DtmfSenderProxy::Create(signaling_thread(), sender.get());
444 }
445
446 bool PeerConnection::GetStats(StatsObserver* observer,
447                               MediaStreamTrackInterface* track,
448                               StatsOutputLevel level) {
449   if (!VERIFY(observer != NULL)) {
450     LOG(LS_ERROR) << "GetStats - observer is NULL.";
451     return false;
452   }
453
454   stats_->UpdateStats(level);
455   rtc::scoped_ptr<GetStatsMsg> msg(new GetStatsMsg(observer));
456   if (!stats_->GetStats(track, &(msg->reports))) {
457     return false;
458   }
459   signaling_thread()->Post(this, MSG_GETSTATS, msg.release());
460   return true;
461 }
462
463 PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
464   return signaling_state_;
465 }
466
467 PeerConnectionInterface::IceState PeerConnection::ice_state() {
468   return ice_state_;
469 }
470
471 PeerConnectionInterface::IceConnectionState
472 PeerConnection::ice_connection_state() {
473   return ice_connection_state_;
474 }
475
476 PeerConnectionInterface::IceGatheringState
477 PeerConnection::ice_gathering_state() {
478   return ice_gathering_state_;
479 }
480
481 rtc::scoped_refptr<DataChannelInterface>
482 PeerConnection::CreateDataChannel(
483     const std::string& label,
484     const DataChannelInit* config) {
485   bool first_datachannel = !mediastream_signaling_->HasDataChannels();
486
487   rtc::scoped_ptr<InternalDataChannelInit> internal_config;
488   if (config) {
489     internal_config.reset(new InternalDataChannelInit(*config));
490   }
491   rtc::scoped_refptr<DataChannelInterface> channel(
492       session_->CreateDataChannel(label, internal_config.get()));
493   if (!channel.get())
494     return NULL;
495
496   // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
497   // the first SCTP DataChannel.
498   if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
499     observer_->OnRenegotiationNeeded();
500   }
501
502   return DataChannelProxy::Create(signaling_thread(), channel.get());
503 }
504
505 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
506                                  const MediaConstraintsInterface* constraints) {
507   if (!VERIFY(observer != NULL)) {
508     LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
509     return;
510   }
511   RTCOfferAnswerOptions options;
512   // Defaults to receiving audio and not receiving video.
513   options.offer_to_receive_audio =
514       RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
515   options.offer_to_receive_video = 0;
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_->UpdateIce(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       param->observer->OnComplete(param->reports);
761       delete param;
762       break;
763     }
764     default:
765       ASSERT(false && "Not implemented");
766       break;
767   }
768 }
769
770 void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
771   stats_->AddStream(stream);
772   observer_->OnAddStream(stream);
773 }
774
775 void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
776   stream_handler_container_->RemoveRemoteStream(stream);
777   observer_->OnRemoveStream(stream);
778 }
779
780 void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
781   observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
782                                                     data_channel));
783 }
784
785 void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
786                                            AudioTrackInterface* audio_track,
787                                            uint32 ssrc) {
788   stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc);
789 }
790
791 void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
792                                            VideoTrackInterface* video_track,
793                                            uint32 ssrc) {
794   stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc);
795 }
796
797 void PeerConnection::OnRemoveRemoteAudioTrack(
798     MediaStreamInterface* stream,
799     AudioTrackInterface* audio_track) {
800   stream_handler_container_->RemoveRemoteTrack(stream, audio_track);
801 }
802
803 void PeerConnection::OnRemoveRemoteVideoTrack(
804     MediaStreamInterface* stream,
805     VideoTrackInterface* video_track) {
806   stream_handler_container_->RemoveRemoteTrack(stream, video_track);
807 }
808 void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
809                                           AudioTrackInterface* audio_track,
810                                           uint32 ssrc) {
811   stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc);
812   stats_->AddLocalAudioTrack(audio_track, ssrc);
813 }
814 void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
815                                           VideoTrackInterface* video_track,
816                                           uint32 ssrc) {
817   stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc);
818 }
819
820 void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
821                                              AudioTrackInterface* audio_track,
822                                              uint32 ssrc) {
823   stream_handler_container_->RemoveLocalTrack(stream, audio_track);
824   stats_->RemoveLocalAudioTrack(audio_track, ssrc);
825 }
826
827 void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
828                                              VideoTrackInterface* video_track) {
829   stream_handler_container_->RemoveLocalTrack(stream, video_track);
830 }
831
832 void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
833   stream_handler_container_->RemoveLocalStream(stream);
834 }
835
836 void PeerConnection::OnIceConnectionChange(
837     PeerConnectionInterface::IceConnectionState new_state) {
838   ASSERT(signaling_thread()->IsCurrent());
839   ice_connection_state_ = new_state;
840   observer_->OnIceConnectionChange(ice_connection_state_);
841 }
842
843 void PeerConnection::OnIceGatheringChange(
844     PeerConnectionInterface::IceGatheringState new_state) {
845   ASSERT(signaling_thread()->IsCurrent());
846   if (IsClosed()) {
847     return;
848   }
849   ice_gathering_state_ = new_state;
850   observer_->OnIceGatheringChange(ice_gathering_state_);
851 }
852
853 void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
854   ASSERT(signaling_thread()->IsCurrent());
855   observer_->OnIceCandidate(candidate);
856 }
857
858 void PeerConnection::OnIceComplete() {
859   ASSERT(signaling_thread()->IsCurrent());
860   observer_->OnIceComplete();
861 }
862
863 void PeerConnection::ChangeSignalingState(
864     PeerConnectionInterface::SignalingState signaling_state) {
865   signaling_state_ = signaling_state;
866   if (signaling_state == kClosed) {
867     ice_connection_state_ = kIceConnectionClosed;
868     observer_->OnIceConnectionChange(ice_connection_state_);
869     if (ice_gathering_state_ != kIceGatheringComplete) {
870       ice_gathering_state_ = kIceGatheringComplete;
871       observer_->OnIceGatheringChange(ice_gathering_state_);
872     }
873   }
874   observer_->OnSignalingChange(signaling_state_);
875   observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
876 }
877
878 }  // namespace webrtc