3 * Copyright 2012, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
28 #include "talk/app/webrtc/peerconnection.h"
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"
46 using webrtc::PeerConnectionInterface;
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";
60 // NOTE: Must be in the same order as the ServiceType enum.
61 static const char* kValidIceServiceTypes[] = {
62 "stun", "stuns", "turn", "turns", "invalid" };
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.
73 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
74 MSG_SET_SESSIONDESCRIPTION_FAILED,
78 struct SetSessionDescriptionMsg : public rtc::MessageData {
79 explicit SetSessionDescriptionMsg(
80 webrtc::SetSessionDescriptionObserver* observer)
81 : observer(observer) {
84 rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
88 struct GetStatsMsg : public rtc::MessageData {
89 GetStatsMsg(webrtc::StatsObserver* observer,
90 webrtc::MediaStreamTrackInterface* track)
91 : observer(observer), track(track) {
93 rtc::scoped_refptr<webrtc::StatsObserver> observer;
94 rtc::scoped_refptr<webrtc::MediaStreamTrackInterface> track;
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
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) {
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);
120 if (*service_type == INVALID) {
123 *hostname = in_str.substr(colonpos + 1, std::string::npos);
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,
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)) {
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)) {
164 typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
166 typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
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
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.";
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
203 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
204 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
207 turn_transport_type = tokens[1];
211 std::string hoststring;
212 ServiceType service_type = INVALID;
213 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
216 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: "
217 << uri_without_transport;
221 // Let's break hostname.
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];
230 int port = kDefaultStunPort;
231 if (service_type == TURNS) {
232 port = kDefaultStunTlsPort;
233 turn_transport_type = kTcpTransportType;
237 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
238 LOG(WARNING) << "Invalid Hostname format: " << uri_without_transport;
243 if (port <= 0 || port > 0xffff) {
244 LOG(WARNING) << "Invalid port: " << port;
248 switch (service_type) {
251 stun_config->push_back(StunConfiguration(address, port));
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];
265 bool secure = (service_type == TURNS);
267 turn_config->push_back(TurnConfiguration(address, port,
276 LOG(WARNING) << "Configuration not supported: " << server.uri;
283 // Check if we can send |new_stream| on a PeerConnection.
284 // Currently only one audio but multiple video track is supported per
286 bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
287 webrtc::MediaStreamInterface* new_stream) {
288 if (!new_stream || !current_streams)
290 if (current_streams->find(new_stream->label()) != NULL) {
291 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
292 << " is already added.";
303 PeerConnection::PeerConnection(PeerConnectionFactory* factory)
307 signaling_state_(kStable),
309 ice_connection_state_(kIceConnectionNew),
310 ice_gathering_state_(kIceGatheringNew) {
313 PeerConnection::~PeerConnection() {
314 if (mediastream_signaling_)
315 mediastream_signaling_->TearDown();
316 if (stream_handler_container_)
317 stream_handler_container_->TearDown();
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)) {
332 return DoInitialize(configuration.type, stun_config, turn_config, constraints,
333 allocator_factory, dtls_identity_service, observer);
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);
347 observer_ = observer;
348 port_allocator_.reset(
349 allocator_factory->CreatePortAllocator(stun_config, turn_config));
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;
358 // If IPv6 flag was specified, we'll not override it by experiment.
360 constraints, MediaConstraintsInterface::kEnableIPv6, &value, NULL)) {
362 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6;
364 } else if (webrtc::field_trial::FindFullName("WebRTC-IPv6Default") ==
366 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6;
369 port_allocator_->set_flags(portallocator_flags);
370 // No step delay is used while allocating ports.
371 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
373 mediastream_signaling_.reset(new MediaStreamSignaling(
374 factory_->signaling_thread(), this, factory_->channel_manager()));
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()));
385 // Initialize the WebRtcSession. It creates transport channels etc.
386 if (!session_->Initialize(factory_->options(), constraints,
387 dtls_identity_service, type))
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);
397 rtc::scoped_refptr<StreamCollectionInterface>
398 PeerConnection::local_streams() {
399 return mediastream_signaling_->local_streams();
402 rtc::scoped_refptr<StreamCollectionInterface>
403 PeerConnection::remote_streams() {
404 return mediastream_signaling_->remote_streams();
407 bool PeerConnection::AddStream(MediaStreamInterface* local_stream) {
411 if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(),
415 if (!mediastream_signaling_->AddLocalStream(local_stream)) {
418 stats_->AddStream(local_stream);
419 observer_->OnRenegotiationNeeded();
423 void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
424 mediastream_signaling_->RemoveLocalStream(local_stream);
428 observer_->OnRenegotiationNeeded();
431 rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
432 AudioTrackInterface* track) {
434 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
437 if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) {
438 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
442 rtc::scoped_refptr<DtmfSenderInterface> sender(
443 DtmfSender::Create(track, signaling_thread(), session_.get()));
445 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
448 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
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.";
460 stats_->UpdateStats(level);
461 signaling_thread()->Post(this, MSG_GETSTATS,
462 new GetStatsMsg(observer, track));
466 PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
467 return signaling_state_;
470 PeerConnectionInterface::IceState PeerConnection::ice_state() {
474 PeerConnectionInterface::IceConnectionState
475 PeerConnection::ice_connection_state() {
476 return ice_connection_state_;
479 PeerConnectionInterface::IceGatheringState
480 PeerConnection::ice_gathering_state() {
481 return ice_gathering_state_;
484 rtc::scoped_refptr<DataChannelInterface>
485 PeerConnection::CreateDataChannel(
486 const std::string& label,
487 const DataChannelInit* config) {
488 bool first_datachannel = !mediastream_signaling_->HasDataChannels();
490 rtc::scoped_ptr<InternalDataChannelInit> internal_config;
492 internal_config.reset(new InternalDataChannelInit(*config));
494 rtc::scoped_refptr<DataChannelInterface> channel(
495 session_->CreateDataChannel(label, internal_config.get()));
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();
505 return DataChannelProxy::Create(signaling_thread(), channel.get());
508 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
509 const MediaConstraintsInterface* constraints) {
510 if (!VERIFY(observer != NULL)) {
511 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
514 RTCOfferAnswerOptions options;
517 size_t mandatory_constraints = 0;
519 if (FindConstraint(constraints,
520 MediaConstraintsInterface::kOfferToReceiveAudio,
522 &mandatory_constraints)) {
523 options.offer_to_receive_audio =
524 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
527 if (FindConstraint(constraints,
528 MediaConstraintsInterface::kOfferToReceiveVideo,
530 &mandatory_constraints)) {
531 options.offer_to_receive_video =
532 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
535 if (FindConstraint(constraints,
536 MediaConstraintsInterface::kVoiceActivityDetection,
538 &mandatory_constraints)) {
539 options.voice_activity_detection = value;
542 if (FindConstraint(constraints,
543 MediaConstraintsInterface::kIceRestart,
545 &mandatory_constraints)) {
546 options.ice_restart = value;
549 if (FindConstraint(constraints,
550 MediaConstraintsInterface::kUseRtpMux,
552 &mandatory_constraints)) {
553 options.use_rtp_mux = value;
556 CreateOffer(observer, options);
559 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
560 const RTCOfferAnswerOptions& options) {
561 if (!VERIFY(observer != NULL)) {
562 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
565 session_->CreateOffer(observer, options);
568 void PeerConnection::CreateAnswer(
569 CreateSessionDescriptionObserver* observer,
570 const MediaConstraintsInterface* constraints) {
571 if (!VERIFY(observer != NULL)) {
572 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
575 session_->CreateAnswer(observer, constraints);
578 void PeerConnection::SetLocalDescription(
579 SetSessionDescriptionObserver* observer,
580 SessionDescriptionInterface* desc) {
581 if (!VERIFY(observer != NULL)) {
582 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
586 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
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);
593 if (!session_->SetLocalDescription(desc, &error)) {
594 PostSetSessionDescriptionFailure(observer, error);
597 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
598 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
601 void PeerConnection::SetRemoteDescription(
602 SetSessionDescriptionObserver* observer,
603 SessionDescriptionInterface* desc) {
604 if (!VERIFY(observer != NULL)) {
605 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
609 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
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);
616 if (!session_->SetRemoteDescription(desc, &error)) {
617 PostSetSessionDescriptionFailure(observer, error);
620 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
621 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
624 void PeerConnection::PostSetSessionDescriptionFailure(
625 SetSessionDescriptionObserver* observer,
626 const std::string& error) {
627 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
629 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
632 bool PeerConnection::UpdateIce(const IceServers& configuration,
633 const MediaConstraintsInterface* constraints) {
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)) {
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);
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();
657 for (size_t i = 0; i < turns.size(); ++i) {
658 cricket::RelayCredentials credentials(turns[i].username,
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();
669 LOG(LS_WARNING) << "Ignoring TURN server " << turns[i].server << ". "
670 << "Reason= Incorrect " << turns[i].transport_type
671 << " transport parameter.";
675 return session_->SetIceTransports(config.type);
678 bool PeerConnection::AddIceCandidate(
679 const IceCandidateInterface* ice_candidate) {
680 return session_->ProcessIceMessage(ice_candidate);
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);
690 uma_observer_->IncrementCounter(kPeerConnection_IPv4);
695 const SessionDescriptionInterface* PeerConnection::local_description() const {
696 return session_->local_description();
699 const SessionDescriptionInterface* PeerConnection::remote_description() const {
700 return session_->remote_description();
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);
708 session_->Terminate();
711 void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
712 cricket::BaseSession::State state) {
714 case cricket::BaseSession::STATE_INIT:
715 ChangeSignalingState(PeerConnectionInterface::kStable);
717 case cricket::BaseSession::STATE_SENTINITIATE:
718 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
720 case cricket::BaseSession::STATE_SENTPRACCEPT:
721 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
723 case cricket::BaseSession::STATE_RECEIVEDINITIATE:
724 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
726 case cricket::BaseSession::STATE_RECEIVEDPRACCEPT:
727 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
729 case cricket::BaseSession::STATE_SENTACCEPT:
730 case cricket::BaseSession::STATE_RECEIVEDACCEPT:
731 ChangeSignalingState(PeerConnectionInterface::kStable);
733 case cricket::BaseSession::STATE_RECEIVEDTERMINATE:
734 ChangeSignalingState(PeerConnectionInterface::kClosed);
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();
750 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
751 SetSessionDescriptionMsg* param =
752 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
753 param->observer->OnFailure(param->error);
758 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
759 StatsReports reports;
760 stats_->GetStats(param->track, &reports);
761 param->observer->OnComplete(reports);
766 ASSERT(false && "Not implemented");
771 void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
772 stats_->AddStream(stream);
773 observer_->OnAddStream(stream);
776 void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
777 stream_handler_container_->RemoveRemoteStream(stream);
778 observer_->OnRemoveStream(stream);
781 void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
782 observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
786 void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
787 AudioTrackInterface* audio_track,
789 stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc);
792 void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
793 VideoTrackInterface* video_track,
795 stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc);
798 void PeerConnection::OnRemoveRemoteAudioTrack(
799 MediaStreamInterface* stream,
800 AudioTrackInterface* audio_track) {
801 stream_handler_container_->RemoveRemoteTrack(stream, audio_track);
804 void PeerConnection::OnRemoveRemoteVideoTrack(
805 MediaStreamInterface* stream,
806 VideoTrackInterface* video_track) {
807 stream_handler_container_->RemoveRemoteTrack(stream, video_track);
809 void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
810 AudioTrackInterface* audio_track,
812 stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc);
813 stats_->AddLocalAudioTrack(audio_track, ssrc);
815 void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
816 VideoTrackInterface* video_track,
818 stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc);
821 void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
822 AudioTrackInterface* audio_track,
824 stream_handler_container_->RemoveLocalTrack(stream, audio_track);
825 stats_->RemoveLocalAudioTrack(audio_track, ssrc);
828 void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
829 VideoTrackInterface* video_track) {
830 stream_handler_container_->RemoveLocalTrack(stream, video_track);
833 void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
834 stream_handler_container_->RemoveLocalStream(stream);
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_);
844 void PeerConnection::OnIceGatheringChange(
845 PeerConnectionInterface::IceGatheringState new_state) {
846 ASSERT(signaling_thread()->IsCurrent());
850 ice_gathering_state_ = new_state;
851 observer_->OnIceGatheringChange(ice_gathering_state_);
854 void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
855 ASSERT(signaling_thread()->IsCurrent());
856 observer_->OnIceCandidate(candidate);
859 void PeerConnection::OnIceComplete() {
860 ASSERT(signaling_thread()->IsCurrent());
861 observer_->OnIceComplete();
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_);
875 observer_->OnSignalingChange(signaling_state_);
876 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
879 } // namespace webrtc