• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libjingle
3  * Copyright 2012, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "talk/app/webrtc/peerconnection.h"
29 
30 #include <vector>
31 
32 #include "talk/app/webrtc/dtmfsender.h"
33 #include "talk/app/webrtc/jsepicecandidate.h"
34 #include "talk/app/webrtc/jsepsessiondescription.h"
35 #include "talk/app/webrtc/mediaconstraintsinterface.h"
36 #include "talk/app/webrtc/mediastreamhandler.h"
37 #include "talk/app/webrtc/streamcollection.h"
38 #include "talk/base/logging.h"
39 #include "talk/base/stringencode.h"
40 #include "talk/p2p/client/basicportallocator.h"
41 #include "talk/session/media/channelmanager.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 talk_base::MessageData {
SetSessionDescriptionMsg__anone78ef5780111::SetSessionDescriptionMsg78   explicit SetSessionDescriptionMsg(
79       webrtc::SetSessionDescriptionObserver* observer)
80       : observer(observer) {
81   }
82 
83   talk_base::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
84   std::string error;
85 };
86 
87 struct GetStatsMsg : public talk_base::MessageData {
GetStatsMsg__anone78ef5780111::GetStatsMsg88   explicit GetStatsMsg(webrtc::StatsObserver* observer)
89       : observer(observer) {
90   }
91   webrtc::StatsReports reports;
92   talk_base::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
GetServiceTypeAndHostnameFromUri(const std::string & in_str,ServiceType * service_type,std::string * hostname)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|
ParseHostnameAndPortFromString(const std::string & in_str,std::string * host,int * port)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 (!talk_base::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 (!talk_base::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 
ParseIceServers(const PeerConnectionInterface::IceServers & configuration,std::vector<StunConfiguration> * stun_config,std::vector<TurnConfiguration> * turn_config)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     talk_base::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       talk_base::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     talk_base::tokenize(hoststring, '@', &tokens);
222     hoststring = tokens[0];
223     if (tokens.size() == kTurnHostTokensNum) {
224       server.username = talk_base::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           talk_base::tokenize(address, '@', &turn_tokens);
257           if (turn_tokens.size() == kTurnHostTokensNum) {
258             server.username = talk_base::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.
CanAddLocalMediaStream(webrtc::StreamCollectionInterface * current_streams,webrtc::MediaStreamInterface * new_stream)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 
PeerConnection(PeerConnectionFactory * factory)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 
~PeerConnection()311 PeerConnection::~PeerConnection() {
312   if (mediastream_signaling_)
313     mediastream_signaling_->TearDown();
314   if (stream_handler_container_)
315     stream_handler_container_->TearDown();
316 }
317 
Initialize(const PeerConnectionInterface::RTCConfiguration & configuration,const MediaConstraintsInterface * constraints,PortAllocatorFactoryInterface * allocator_factory,DTLSIdentityServiceInterface * dtls_identity_service,PeerConnectionObserver * observer)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 
DoInitialize(IceTransportsType type,const StunConfigurations & stun_config,const TurnConfigurations & turn_config,const MediaConstraintsInterface * constraints,webrtc::PortAllocatorFactoryInterface * allocator_factory,DTLSIdentityServiceInterface * dtls_identity_service,PeerConnectionObserver * observer)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_.set_session(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 talk_base::scoped_refptr<StreamCollectionInterface>
local_streams()391 PeerConnection::local_streams() {
392   return mediastream_signaling_->local_streams();
393 }
394 
395 talk_base::scoped_refptr<StreamCollectionInterface>
remote_streams()396 PeerConnection::remote_streams() {
397   return mediastream_signaling_->remote_streams();
398 }
399 
AddStream(MediaStreamInterface * local_stream,const MediaConstraintsInterface * constraints)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 
RemoveStream(MediaStreamInterface * local_stream)418 void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
419   mediastream_signaling_->RemoveLocalStream(local_stream);
420   if (IsClosed()) {
421     return;
422   }
423   observer_->OnRenegotiationNeeded();
424 }
425 
CreateDtmfSender(AudioTrackInterface * track)426 talk_base::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   talk_base::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 
GetStats(StatsObserver * observer,MediaStreamTrackInterface * track,StatsOutputLevel level)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   talk_base::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 
signaling_state()463 PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
464   return signaling_state_;
465 }
466 
ice_state()467 PeerConnectionInterface::IceState PeerConnection::ice_state() {
468   return ice_state_;
469 }
470 
471 PeerConnectionInterface::IceConnectionState
ice_connection_state()472 PeerConnection::ice_connection_state() {
473   return ice_connection_state_;
474 }
475 
476 PeerConnectionInterface::IceGatheringState
ice_gathering_state()477 PeerConnection::ice_gathering_state() {
478   return ice_gathering_state_;
479 }
480 
481 talk_base::scoped_refptr<DataChannelInterface>
CreateDataChannel(const std::string & label,const DataChannelInit * config)482 PeerConnection::CreateDataChannel(
483     const std::string& label,
484     const DataChannelInit* config) {
485   bool first_datachannel = !mediastream_signaling_->HasDataChannels();
486 
487   talk_base::scoped_ptr<InternalDataChannelInit> internal_config;
488   if (config) {
489     internal_config.reset(new InternalDataChannelInit(*config));
490   }
491   talk_base::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 
CreateOffer(CreateSessionDescriptionObserver * observer,const MediaConstraintsInterface * constraints)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   session_->CreateOffer(observer, constraints);
512 }
513 
CreateAnswer(CreateSessionDescriptionObserver * observer,const MediaConstraintsInterface * constraints)514 void PeerConnection::CreateAnswer(
515     CreateSessionDescriptionObserver* observer,
516     const MediaConstraintsInterface* constraints) {
517   if (!VERIFY(observer != NULL)) {
518     LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
519     return;
520   }
521   session_->CreateAnswer(observer, constraints);
522 }
523 
SetLocalDescription(SetSessionDescriptionObserver * observer,SessionDescriptionInterface * desc)524 void PeerConnection::SetLocalDescription(
525     SetSessionDescriptionObserver* observer,
526     SessionDescriptionInterface* desc) {
527   if (!VERIFY(observer != NULL)) {
528     LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
529     return;
530   }
531   if (!desc) {
532     PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
533     return;
534   }
535   // Update stats here so that we have the most recent stats for tracks and
536   // streams that might be removed by updating the session description.
537   stats_.UpdateStats(kStatsOutputLevelStandard);
538   std::string error;
539   if (!session_->SetLocalDescription(desc, &error)) {
540     PostSetSessionDescriptionFailure(observer, error);
541     return;
542   }
543   SetSessionDescriptionMsg* msg =  new SetSessionDescriptionMsg(observer);
544   signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
545 }
546 
SetRemoteDescription(SetSessionDescriptionObserver * observer,SessionDescriptionInterface * desc)547 void PeerConnection::SetRemoteDescription(
548     SetSessionDescriptionObserver* observer,
549     SessionDescriptionInterface* desc) {
550   if (!VERIFY(observer != NULL)) {
551     LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
552     return;
553   }
554   if (!desc) {
555     PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
556     return;
557   }
558   // Update stats here so that we have the most recent stats for tracks and
559   // streams that might be removed by updating the session description.
560   stats_.UpdateStats(kStatsOutputLevelStandard);
561   std::string error;
562   if (!session_->SetRemoteDescription(desc, &error)) {
563     PostSetSessionDescriptionFailure(observer, error);
564     return;
565   }
566   SetSessionDescriptionMsg* msg  = new SetSessionDescriptionMsg(observer);
567   signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
568 }
569 
PostSetSessionDescriptionFailure(SetSessionDescriptionObserver * observer,const std::string & error)570 void PeerConnection::PostSetSessionDescriptionFailure(
571     SetSessionDescriptionObserver* observer,
572     const std::string& error) {
573   SetSessionDescriptionMsg* msg  = new SetSessionDescriptionMsg(observer);
574   msg->error = error;
575   signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
576 }
577 
UpdateIce(const IceServers & configuration,const MediaConstraintsInterface * constraints)578 bool PeerConnection::UpdateIce(const IceServers& configuration,
579                                const MediaConstraintsInterface* constraints) {
580   return false;
581 }
582 
UpdateIce(const RTCConfiguration & config)583 bool PeerConnection::UpdateIce(const RTCConfiguration& config) {
584   if (port_allocator_) {
585     std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
586     std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
587     if (!ParseIceServers(config.servers, &stuns, &turns)) {
588       return false;
589     }
590 
591     std::vector<talk_base::SocketAddress> stun_hosts;
592     typedef std::vector<StunConfiguration>::const_iterator StunIt;
593     for (StunIt stun_it = stuns.begin(); stun_it != stuns.end(); ++stun_it) {
594       stun_hosts.push_back(stun_it->server);
595     }
596 
597     talk_base::SocketAddress stun_addr;
598     if (!stun_hosts.empty()) {
599       stun_addr = stun_hosts.front();
600       LOG(LS_INFO) << "UpdateIce: StunServer Address: " << stun_addr.ToString();
601     }
602 
603     for (size_t i = 0; i < turns.size(); ++i) {
604       cricket::RelayCredentials credentials(turns[i].username,
605                                             turns[i].password);
606       cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
607       cricket::ProtocolType protocol;
608       if (cricket::StringToProto(turns[i].transport_type.c_str(), &protocol)) {
609         relay_server.ports.push_back(cricket::ProtocolAddress(
610             turns[i].server, protocol, turns[i].secure));
611         relay_server.credentials = credentials;
612         LOG(LS_INFO) << "UpdateIce: TurnServer Address: "
613                      << turns[i].server.ToString();
614       } else {
615         LOG(LS_WARNING) << "Ignoring TURN server " << turns[i].server << ". "
616                         << "Reason= Incorrect " << turns[i].transport_type
617                         << " transport parameter.";
618       }
619     }
620   }
621   return session_->UpdateIce(config.type);
622 }
623 
AddIceCandidate(const IceCandidateInterface * ice_candidate)624 bool PeerConnection::AddIceCandidate(
625     const IceCandidateInterface* ice_candidate) {
626   return session_->ProcessIceMessage(ice_candidate);
627 }
628 
RegisterUMAObserver(UMAObserver * observer)629 void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
630   uma_observer_ = observer;
631   // Send information about IPv4/IPv6 status.
632   if (uma_observer_ && port_allocator_) {
633     if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
634       uma_observer_->IncrementCounter(kPeerConnection_IPv6);
635     } else {
636       uma_observer_->IncrementCounter(kPeerConnection_IPv4);
637     }
638   }
639 }
640 
local_description() const641 const SessionDescriptionInterface* PeerConnection::local_description() const {
642   return session_->local_description();
643 }
644 
remote_description() const645 const SessionDescriptionInterface* PeerConnection::remote_description() const {
646   return session_->remote_description();
647 }
648 
Close()649 void PeerConnection::Close() {
650   // Update stats here so that we have the most recent stats for tracks and
651   // streams before the channels are closed.
652   stats_.UpdateStats(kStatsOutputLevelStandard);
653 
654   session_->Terminate();
655 }
656 
OnSessionStateChange(cricket::BaseSession *,cricket::BaseSession::State state)657 void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
658                                           cricket::BaseSession::State state) {
659   switch (state) {
660     case cricket::BaseSession::STATE_INIT:
661       ChangeSignalingState(PeerConnectionInterface::kStable);
662       break;
663     case cricket::BaseSession::STATE_SENTINITIATE:
664       ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
665       break;
666     case cricket::BaseSession::STATE_SENTPRACCEPT:
667       ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
668       break;
669     case cricket::BaseSession::STATE_RECEIVEDINITIATE:
670       ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
671       break;
672     case cricket::BaseSession::STATE_RECEIVEDPRACCEPT:
673       ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
674       break;
675     case cricket::BaseSession::STATE_SENTACCEPT:
676     case cricket::BaseSession::STATE_RECEIVEDACCEPT:
677       ChangeSignalingState(PeerConnectionInterface::kStable);
678       break;
679     case cricket::BaseSession::STATE_RECEIVEDTERMINATE:
680       ChangeSignalingState(PeerConnectionInterface::kClosed);
681       break;
682     default:
683       break;
684   }
685 }
686 
OnMessage(talk_base::Message * msg)687 void PeerConnection::OnMessage(talk_base::Message* msg) {
688   switch (msg->message_id) {
689     case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
690       SetSessionDescriptionMsg* param =
691           static_cast<SetSessionDescriptionMsg*>(msg->pdata);
692       param->observer->OnSuccess();
693       delete param;
694       break;
695     }
696     case MSG_SET_SESSIONDESCRIPTION_FAILED: {
697       SetSessionDescriptionMsg* param =
698           static_cast<SetSessionDescriptionMsg*>(msg->pdata);
699       param->observer->OnFailure(param->error);
700       delete param;
701       break;
702     }
703     case MSG_GETSTATS: {
704       GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
705       param->observer->OnComplete(param->reports);
706       delete param;
707       break;
708     }
709     default:
710       ASSERT(false && "Not implemented");
711       break;
712   }
713 }
714 
OnAddRemoteStream(MediaStreamInterface * stream)715 void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
716   stats_.AddStream(stream);
717   observer_->OnAddStream(stream);
718 }
719 
OnRemoveRemoteStream(MediaStreamInterface * stream)720 void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
721   stream_handler_container_->RemoveRemoteStream(stream);
722   observer_->OnRemoveStream(stream);
723 }
724 
OnAddDataChannel(DataChannelInterface * data_channel)725 void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
726   observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
727                                                     data_channel));
728 }
729 
OnAddRemoteAudioTrack(MediaStreamInterface * stream,AudioTrackInterface * audio_track,uint32 ssrc)730 void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
731                                            AudioTrackInterface* audio_track,
732                                            uint32 ssrc) {
733   stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc);
734 }
735 
OnAddRemoteVideoTrack(MediaStreamInterface * stream,VideoTrackInterface * video_track,uint32 ssrc)736 void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
737                                            VideoTrackInterface* video_track,
738                                            uint32 ssrc) {
739   stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc);
740 }
741 
OnRemoveRemoteAudioTrack(MediaStreamInterface * stream,AudioTrackInterface * audio_track)742 void PeerConnection::OnRemoveRemoteAudioTrack(
743     MediaStreamInterface* stream,
744     AudioTrackInterface* audio_track) {
745   stream_handler_container_->RemoveRemoteTrack(stream, audio_track);
746 }
747 
OnRemoveRemoteVideoTrack(MediaStreamInterface * stream,VideoTrackInterface * video_track)748 void PeerConnection::OnRemoveRemoteVideoTrack(
749     MediaStreamInterface* stream,
750     VideoTrackInterface* video_track) {
751   stream_handler_container_->RemoveRemoteTrack(stream, video_track);
752 }
OnAddLocalAudioTrack(MediaStreamInterface * stream,AudioTrackInterface * audio_track,uint32 ssrc)753 void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
754                                           AudioTrackInterface* audio_track,
755                                           uint32 ssrc) {
756   stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc);
757   stats_.AddLocalAudioTrack(audio_track, ssrc);
758 }
OnAddLocalVideoTrack(MediaStreamInterface * stream,VideoTrackInterface * video_track,uint32 ssrc)759 void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
760                                           VideoTrackInterface* video_track,
761                                           uint32 ssrc) {
762   stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc);
763 }
764 
OnRemoveLocalAudioTrack(MediaStreamInterface * stream,AudioTrackInterface * audio_track,uint32 ssrc)765 void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
766                                              AudioTrackInterface* audio_track,
767                                              uint32 ssrc) {
768   stream_handler_container_->RemoveLocalTrack(stream, audio_track);
769   stats_.RemoveLocalAudioTrack(audio_track, ssrc);
770 }
771 
OnRemoveLocalVideoTrack(MediaStreamInterface * stream,VideoTrackInterface * video_track)772 void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
773                                              VideoTrackInterface* video_track) {
774   stream_handler_container_->RemoveLocalTrack(stream, video_track);
775 }
776 
OnRemoveLocalStream(MediaStreamInterface * stream)777 void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
778   stream_handler_container_->RemoveLocalStream(stream);
779 }
780 
OnIceConnectionChange(PeerConnectionInterface::IceConnectionState new_state)781 void PeerConnection::OnIceConnectionChange(
782     PeerConnectionInterface::IceConnectionState new_state) {
783   ASSERT(signaling_thread()->IsCurrent());
784   ice_connection_state_ = new_state;
785   observer_->OnIceConnectionChange(ice_connection_state_);
786 }
787 
OnIceGatheringChange(PeerConnectionInterface::IceGatheringState new_state)788 void PeerConnection::OnIceGatheringChange(
789     PeerConnectionInterface::IceGatheringState new_state) {
790   ASSERT(signaling_thread()->IsCurrent());
791   if (IsClosed()) {
792     return;
793   }
794   ice_gathering_state_ = new_state;
795   observer_->OnIceGatheringChange(ice_gathering_state_);
796 }
797 
OnIceCandidate(const IceCandidateInterface * candidate)798 void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
799   ASSERT(signaling_thread()->IsCurrent());
800   observer_->OnIceCandidate(candidate);
801 }
802 
OnIceComplete()803 void PeerConnection::OnIceComplete() {
804   ASSERT(signaling_thread()->IsCurrent());
805   observer_->OnIceComplete();
806 }
807 
ChangeSignalingState(PeerConnectionInterface::SignalingState signaling_state)808 void PeerConnection::ChangeSignalingState(
809     PeerConnectionInterface::SignalingState signaling_state) {
810   signaling_state_ = signaling_state;
811   if (signaling_state == kClosed) {
812     ice_connection_state_ = kIceConnectionClosed;
813     observer_->OnIceConnectionChange(ice_connection_state_);
814     if (ice_gathering_state_ != kIceGatheringComplete) {
815       ice_gathering_state_ = kIceGatheringComplete;
816       observer_->OnIceGatheringChange(ice_gathering_state_);
817     }
818   }
819   observer_->OnSignalingChange(signaling_state_);
820   observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
821 }
822 
823 }  // namespace webrtc
824