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