Update To 11.40.268.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 "webrtc/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 = port_allocator_->flags();
354   portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_BUNDLE |
355                          cricket::PORTALLOCATOR_ENABLE_SHARED_UFRAG |
356                          cricket::PORTALLOCATOR_ENABLE_SHARED_SOCKET;
357   bool value;
358   // If IPv6 flag was specified, we'll not override it by experiment.
359   if (FindConstraint(
360           constraints, MediaConstraintsInterface::kEnableIPv6, &value, NULL)) {
361     if (value) {
362       portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6;
363     }
364   } else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default") ==
365              "Enabled") {
366     portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6;
367   }
368
369   port_allocator_->set_flags(portallocator_flags);
370   // No step delay is used while allocating ports.
371   port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
372
373   mediastream_signaling_.reset(new MediaStreamSignaling(
374       factory_->signaling_thread(), this, factory_->channel_manager()));
375
376   session_.reset(new WebRtcSession(factory_->channel_manager(),
377                                    factory_->signaling_thread(),
378                                    factory_->worker_thread(),
379                                    port_allocator_.get(),
380                                    mediastream_signaling_.get()));
381   stream_handler_container_.reset(new MediaStreamHandlerContainer(
382       session_.get(), session_.get()));
383   stats_.reset(new StatsCollector(session_.get()));
384
385   // Initialize the WebRtcSession. It creates transport channels etc.
386   if (!session_->Initialize(factory_->options(), constraints,
387                             dtls_identity_service, type))
388     return false;
389
390   // Register PeerConnection as receiver of local ice candidates.
391   // All the callbacks will be posted to the application from PeerConnection.
392   session_->RegisterIceObserver(this);
393   session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
394   return true;
395 }
396
397 rtc::scoped_refptr<StreamCollectionInterface>
398 PeerConnection::local_streams() {
399   return mediastream_signaling_->local_streams();
400 }
401
402 rtc::scoped_refptr<StreamCollectionInterface>
403 PeerConnection::remote_streams() {
404   return mediastream_signaling_->remote_streams();
405 }
406
407 bool PeerConnection::AddStream(MediaStreamInterface* local_stream) {
408   if (IsClosed()) {
409     return false;
410   }
411   if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(),
412                               local_stream))
413     return false;
414
415   if (!mediastream_signaling_->AddLocalStream(local_stream)) {
416     return false;
417   }
418   stats_->AddStream(local_stream);
419   observer_->OnRenegotiationNeeded();
420   return true;
421 }
422
423 void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
424   mediastream_signaling_->RemoveLocalStream(local_stream);
425   if (IsClosed()) {
426     return;
427   }
428   observer_->OnRenegotiationNeeded();
429 }
430
431 rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
432     AudioTrackInterface* track) {
433   if (!track) {
434     LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
435     return NULL;
436   }
437   if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) {
438     LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
439     return NULL;
440   }
441
442   rtc::scoped_refptr<DtmfSenderInterface> sender(
443       DtmfSender::Create(track, signaling_thread(), session_.get()));
444   if (!sender.get()) {
445     LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
446     return NULL;
447   }
448   return DtmfSenderProxy::Create(signaling_thread(), sender.get());
449 }
450
451 bool PeerConnection::GetStats(StatsObserver* observer,
452                               MediaStreamTrackInterface* track,
453                               StatsOutputLevel level) {
454   ASSERT(signaling_thread()->IsCurrent());
455   if (!VERIFY(observer != NULL)) {
456     LOG(LS_ERROR) << "GetStats - observer is NULL.";
457     return false;
458   }
459
460   stats_->UpdateStats(level);
461   signaling_thread()->Post(this, MSG_GETSTATS,
462                            new GetStatsMsg(observer, track));
463   return true;
464 }
465
466 PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
467   return signaling_state_;
468 }
469
470 PeerConnectionInterface::IceState PeerConnection::ice_state() {
471   return ice_state_;
472 }
473
474 PeerConnectionInterface::IceConnectionState
475 PeerConnection::ice_connection_state() {
476   return ice_connection_state_;
477 }
478
479 PeerConnectionInterface::IceGatheringState
480 PeerConnection::ice_gathering_state() {
481   return ice_gathering_state_;
482 }
483
484 rtc::scoped_refptr<DataChannelInterface>
485 PeerConnection::CreateDataChannel(
486     const std::string& label,
487     const DataChannelInit* config) {
488   bool first_datachannel = !mediastream_signaling_->HasDataChannels();
489
490   rtc::scoped_ptr<InternalDataChannelInit> internal_config;
491   if (config) {
492     internal_config.reset(new InternalDataChannelInit(*config));
493   }
494   rtc::scoped_refptr<DataChannelInterface> channel(
495       session_->CreateDataChannel(label, internal_config.get()));
496   if (!channel.get())
497     return NULL;
498
499   // Trigger the onRenegotiationNeeded event for every new RTP DataChannel, or
500   // the first SCTP DataChannel.
501   if (session_->data_channel_type() == cricket::DCT_RTP || first_datachannel) {
502     observer_->OnRenegotiationNeeded();
503   }
504
505   return DataChannelProxy::Create(signaling_thread(), channel.get());
506 }
507
508 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
509                                  const MediaConstraintsInterface* constraints) {
510   if (!VERIFY(observer != NULL)) {
511     LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
512     return;
513   }
514   RTCOfferAnswerOptions options;
515
516   bool value;
517   size_t mandatory_constraints = 0;
518
519   if (FindConstraint(constraints,
520                      MediaConstraintsInterface::kOfferToReceiveAudio,
521                      &value,
522                      &mandatory_constraints)) {
523     options.offer_to_receive_audio =
524         value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
525   }
526
527   if (FindConstraint(constraints,
528                      MediaConstraintsInterface::kOfferToReceiveVideo,
529                      &value,
530                      &mandatory_constraints)) {
531     options.offer_to_receive_video =
532         value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
533   }
534
535   if (FindConstraint(constraints,
536                      MediaConstraintsInterface::kVoiceActivityDetection,
537                      &value,
538                      &mandatory_constraints)) {
539     options.voice_activity_detection = value;
540   }
541
542   if (FindConstraint(constraints,
543                      MediaConstraintsInterface::kIceRestart,
544                      &value,
545                      &mandatory_constraints)) {
546     options.ice_restart = value;
547   }
548
549   if (FindConstraint(constraints,
550                      MediaConstraintsInterface::kUseRtpMux,
551                      &value,
552                      &mandatory_constraints)) {
553     options.use_rtp_mux = value;
554   }
555
556   CreateOffer(observer, options);
557 }
558
559 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
560                                  const RTCOfferAnswerOptions& options) {
561   if (!VERIFY(observer != NULL)) {
562     LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
563     return;
564   }
565   session_->CreateOffer(observer, options);
566 }
567
568 void PeerConnection::CreateAnswer(
569     CreateSessionDescriptionObserver* observer,
570     const MediaConstraintsInterface* constraints) {
571   if (!VERIFY(observer != NULL)) {
572     LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
573     return;
574   }
575   session_->CreateAnswer(observer, constraints);
576 }
577
578 void PeerConnection::SetLocalDescription(
579     SetSessionDescriptionObserver* observer,
580     SessionDescriptionInterface* desc) {
581   if (!VERIFY(observer != NULL)) {
582     LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
583     return;
584   }
585   if (!desc) {
586     PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
587     return;
588   }
589   // Update stats here so that we have the most recent stats for tracks and
590   // streams that might be removed by updating the session description.
591   stats_->UpdateStats(kStatsOutputLevelStandard);
592   std::string error;
593   if (!session_->SetLocalDescription(desc, &error)) {
594     PostSetSessionDescriptionFailure(observer, error);
595     return;
596   }
597   SetSessionDescriptionMsg* msg =  new SetSessionDescriptionMsg(observer);
598   signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
599 }
600
601 void PeerConnection::SetRemoteDescription(
602     SetSessionDescriptionObserver* observer,
603     SessionDescriptionInterface* desc) {
604   if (!VERIFY(observer != NULL)) {
605     LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
606     return;
607   }
608   if (!desc) {
609     PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
610     return;
611   }
612   // Update stats here so that we have the most recent stats for tracks and
613   // streams that might be removed by updating the session description.
614   stats_->UpdateStats(kStatsOutputLevelStandard);
615   std::string error;
616   if (!session_->SetRemoteDescription(desc, &error)) {
617     PostSetSessionDescriptionFailure(observer, error);
618     return;
619   }
620   SetSessionDescriptionMsg* msg  = new SetSessionDescriptionMsg(observer);
621   signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
622 }
623
624 void PeerConnection::PostSetSessionDescriptionFailure(
625     SetSessionDescriptionObserver* observer,
626     const std::string& error) {
627   SetSessionDescriptionMsg* msg  = new SetSessionDescriptionMsg(observer);
628   msg->error = error;
629   signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
630 }
631
632 bool PeerConnection::UpdateIce(const IceServers& configuration,
633                                const MediaConstraintsInterface* constraints) {
634   return false;
635 }
636
637 bool PeerConnection::UpdateIce(const RTCConfiguration& config) {
638   if (port_allocator_) {
639     std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
640     std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
641     if (!ParseIceServers(config.servers, &stuns, &turns)) {
642       return false;
643     }
644
645     std::vector<rtc::SocketAddress> stun_hosts;
646     typedef std::vector<StunConfiguration>::const_iterator StunIt;
647     for (StunIt stun_it = stuns.begin(); stun_it != stuns.end(); ++stun_it) {
648       stun_hosts.push_back(stun_it->server);
649     }
650
651     rtc::SocketAddress stun_addr;
652     if (!stun_hosts.empty()) {
653       stun_addr = stun_hosts.front();
654       LOG(LS_INFO) << "UpdateIce: StunServer Address: " << stun_addr.ToString();
655     }
656
657     for (size_t i = 0; i < turns.size(); ++i) {
658       cricket::RelayCredentials credentials(turns[i].username,
659                                             turns[i].password);
660       cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
661       cricket::ProtocolType protocol;
662       if (cricket::StringToProto(turns[i].transport_type.c_str(), &protocol)) {
663         relay_server.ports.push_back(cricket::ProtocolAddress(
664             turns[i].server, protocol, turns[i].secure));
665         relay_server.credentials = credentials;
666         LOG(LS_INFO) << "UpdateIce: TurnServer Address: "
667                      << turns[i].server.ToString();
668       } else {
669         LOG(LS_WARNING) << "Ignoring TURN server " << turns[i].server << ". "
670                         << "Reason= Incorrect " << turns[i].transport_type
671                         << " transport parameter.";
672       }
673     }
674   }
675   return session_->SetIceTransports(config.type);
676 }
677
678 bool PeerConnection::AddIceCandidate(
679     const IceCandidateInterface* ice_candidate) {
680   return session_->ProcessIceMessage(ice_candidate);
681 }
682
683 void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
684   uma_observer_ = observer;
685   // Send information about IPv4/IPv6 status.
686   if (uma_observer_ && port_allocator_) {
687     if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
688       uma_observer_->IncrementCounter(kPeerConnection_IPv6);
689     } else {
690       uma_observer_->IncrementCounter(kPeerConnection_IPv4);
691     }
692   }
693 }
694
695 const SessionDescriptionInterface* PeerConnection::local_description() const {
696   return session_->local_description();
697 }
698
699 const SessionDescriptionInterface* PeerConnection::remote_description() const {
700   return session_->remote_description();
701 }
702
703 void PeerConnection::Close() {
704   // Update stats here so that we have the most recent stats for tracks and
705   // streams before the channels are closed.
706   stats_->UpdateStats(kStatsOutputLevelStandard);
707
708   session_->Terminate();
709 }
710
711 void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
712                                           cricket::BaseSession::State state) {
713   switch (state) {
714     case cricket::BaseSession::STATE_INIT:
715       ChangeSignalingState(PeerConnectionInterface::kStable);
716       break;
717     case cricket::BaseSession::STATE_SENTINITIATE:
718       ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
719       break;
720     case cricket::BaseSession::STATE_SENTPRACCEPT:
721       ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
722       break;
723     case cricket::BaseSession::STATE_RECEIVEDINITIATE:
724       ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
725       break;
726     case cricket::BaseSession::STATE_RECEIVEDPRACCEPT:
727       ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
728       break;
729     case cricket::BaseSession::STATE_SENTACCEPT:
730     case cricket::BaseSession::STATE_RECEIVEDACCEPT:
731       ChangeSignalingState(PeerConnectionInterface::kStable);
732       break;
733     case cricket::BaseSession::STATE_RECEIVEDTERMINATE:
734       ChangeSignalingState(PeerConnectionInterface::kClosed);
735       break;
736     default:
737       break;
738   }
739 }
740
741 void PeerConnection::OnMessage(rtc::Message* msg) {
742   switch (msg->message_id) {
743     case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
744       SetSessionDescriptionMsg* param =
745           static_cast<SetSessionDescriptionMsg*>(msg->pdata);
746       param->observer->OnSuccess();
747       delete param;
748       break;
749     }
750     case MSG_SET_SESSIONDESCRIPTION_FAILED: {
751       SetSessionDescriptionMsg* param =
752           static_cast<SetSessionDescriptionMsg*>(msg->pdata);
753       param->observer->OnFailure(param->error);
754       delete param;
755       break;
756     }
757     case MSG_GETSTATS: {
758       GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
759       StatsReports reports;
760       stats_->GetStats(param->track, &reports);
761       param->observer->OnComplete(reports);
762       delete param;
763       break;
764     }
765     default:
766       ASSERT(false && "Not implemented");
767       break;
768   }
769 }
770
771 void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
772   stats_->AddStream(stream);
773   observer_->OnAddStream(stream);
774 }
775
776 void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
777   stream_handler_container_->RemoveRemoteStream(stream);
778   observer_->OnRemoveStream(stream);
779 }
780
781 void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
782   observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
783                                                     data_channel));
784 }
785
786 void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
787                                            AudioTrackInterface* audio_track,
788                                            uint32 ssrc) {
789   stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc);
790 }
791
792 void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
793                                            VideoTrackInterface* video_track,
794                                            uint32 ssrc) {
795   stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc);
796 }
797
798 void PeerConnection::OnRemoveRemoteAudioTrack(
799     MediaStreamInterface* stream,
800     AudioTrackInterface* audio_track) {
801   stream_handler_container_->RemoveRemoteTrack(stream, audio_track);
802 }
803
804 void PeerConnection::OnRemoveRemoteVideoTrack(
805     MediaStreamInterface* stream,
806     VideoTrackInterface* video_track) {
807   stream_handler_container_->RemoveRemoteTrack(stream, video_track);
808 }
809 void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
810                                           AudioTrackInterface* audio_track,
811                                           uint32 ssrc) {
812   stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc);
813   stats_->AddLocalAudioTrack(audio_track, ssrc);
814 }
815 void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
816                                           VideoTrackInterface* video_track,
817                                           uint32 ssrc) {
818   stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc);
819 }
820
821 void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
822                                              AudioTrackInterface* audio_track,
823                                              uint32 ssrc) {
824   stream_handler_container_->RemoveLocalTrack(stream, audio_track);
825   stats_->RemoveLocalAudioTrack(audio_track, ssrc);
826 }
827
828 void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
829                                              VideoTrackInterface* video_track) {
830   stream_handler_container_->RemoveLocalTrack(stream, video_track);
831 }
832
833 void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
834   stream_handler_container_->RemoveLocalStream(stream);
835 }
836
837 void PeerConnection::OnIceConnectionChange(
838     PeerConnectionInterface::IceConnectionState new_state) {
839   ASSERT(signaling_thread()->IsCurrent());
840   ice_connection_state_ = new_state;
841   observer_->OnIceConnectionChange(ice_connection_state_);
842 }
843
844 void PeerConnection::OnIceGatheringChange(
845     PeerConnectionInterface::IceGatheringState new_state) {
846   ASSERT(signaling_thread()->IsCurrent());
847   if (IsClosed()) {
848     return;
849   }
850   ice_gathering_state_ = new_state;
851   observer_->OnIceGatheringChange(ice_gathering_state_);
852 }
853
854 void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
855   ASSERT(signaling_thread()->IsCurrent());
856   observer_->OnIceCandidate(candidate);
857 }
858
859 void PeerConnection::OnIceComplete() {
860   ASSERT(signaling_thread()->IsCurrent());
861   observer_->OnIceComplete();
862 }
863
864 void PeerConnection::ChangeSignalingState(
865     PeerConnectionInterface::SignalingState signaling_state) {
866   signaling_state_ = signaling_state;
867   if (signaling_state == kClosed) {
868     ice_connection_state_ = kIceConnectionClosed;
869     observer_->OnIceConnectionChange(ice_connection_state_);
870     if (ice_gathering_state_ != kIceGatheringComplete) {
871       ice_gathering_state_ = kIceGatheringComplete;
872       observer_->OnIceGatheringChange(ice_gathering_state_);
873     }
874   }
875   observer_->OnSignalingChange(signaling_state_);
876   observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
877 }
878
879 }  // namespace webrtc