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 "talk/p2p/client/basicportallocator.h"
39 #include "talk/session/media/channelmanager.h"
40 #include "webrtc/base/logging.h"
41 #include "webrtc/base/stringencode.h"
45 using webrtc::PeerConnectionInterface;
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";
59 // NOTE: Must be in the same order as the ServiceType enum.
60 static const char* kValidIceServiceTypes[] = {
61 "stun", "stuns", "turn", "turns", "invalid" };
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.
72 MSG_SET_SESSIONDESCRIPTION_SUCCESS = 0,
73 MSG_SET_SESSIONDESCRIPTION_FAILED,
77 struct SetSessionDescriptionMsg : public rtc::MessageData {
78 explicit SetSessionDescriptionMsg(
79 webrtc::SetSessionDescriptionObserver* observer)
80 : observer(observer) {
83 rtc::scoped_refptr<webrtc::SetSessionDescriptionObserver> observer;
87 struct GetStatsMsg : public rtc::MessageData {
88 explicit GetStatsMsg(webrtc::StatsObserver* observer)
89 : observer(observer) {
91 webrtc::StatsReports reports;
92 rtc::scoped_refptr<webrtc::StatsObserver> observer;
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
101 // draft-petithuguenin-behave-turn-uris-01
102 // turnURI = scheme ":" turn-host [ ":" turn-port ]
103 // turn-host = username@IP-literal / IPv4address / reg-name
104 bool GetServiceTypeAndHostnameFromUri(const std::string& in_str,
105 ServiceType* service_type,
106 std::string* hostname) {
107 std::string::size_type colonpos = in_str.find(':');
108 if (colonpos == std::string::npos) {
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);
118 if (*service_type == INVALID) {
121 *hostname = in_str.substr(colonpos + 1, std::string::npos);
125 // This method parses IPv6 and IPv4 literal strings, along with hostnames in
126 // standard hostname:port format.
127 // Consider following formats as correct.
128 // |hostname:port|, |[IPV6 address]:port|, |IPv4 address|:port,
129 // |hostname|, |[IPv6 address]|, |IPv4 address|
130 bool ParseHostnameAndPortFromString(const std::string& in_str,
133 if (in_str.at(0) == '[') {
134 std::string::size_type closebracket = in_str.rfind(']');
135 if (closebracket != std::string::npos) {
136 *host = in_str.substr(1, closebracket - 1);
137 std::string::size_type colonpos = in_str.find(':', closebracket);
138 if (std::string::npos != colonpos) {
139 if (!rtc::FromString(
140 in_str.substr(closebracket + 2, std::string::npos), port)) {
148 std::string::size_type colonpos = in_str.find(':');
149 if (std::string::npos != colonpos) {
150 *host = in_str.substr(0, colonpos);
151 if (!rtc::FromString(
152 in_str.substr(colonpos + 1, std::string::npos), port)) {
162 typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
164 typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
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
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.";
190 std::vector<std::string> tokens;
191 std::string turn_transport_type = kUdpTransportType;
192 rtc::tokenize(server.uri, '?', &tokens);
193 std::string uri_without_transport = tokens[0];
194 // Let's look into transport= param, if it exists.
195 if (tokens.size() == kTurnTransportTokensNum) { // ?transport= is present.
196 std::string uri_transport_param = tokens[1];
197 rtc::tokenize(uri_transport_param, '=', &tokens);
198 if (tokens[0] == kTransport) {
199 // As per above grammar transport param will be consist of lower case
201 if (tokens[1] != kUdpTransportType && tokens[1] != kTcpTransportType) {
202 LOG(LS_WARNING) << "Transport param should always be udp or tcp.";
205 turn_transport_type = tokens[1];
209 std::string hoststring;
210 ServiceType service_type = INVALID;
211 if (!GetServiceTypeAndHostnameFromUri(uri_without_transport,
214 LOG(LS_WARNING) << "Invalid transport parameter in ICE URI: "
215 << uri_without_transport;
219 // Let's break hostname.
221 rtc::tokenize(hoststring, '@', &tokens);
222 hoststring = tokens[0];
223 if (tokens.size() == kTurnHostTokensNum) {
224 server.username = rtc::s_url_decode(tokens[0]);
225 hoststring = tokens[1];
228 int port = kDefaultStunPort;
229 if (service_type == TURNS) {
230 port = kDefaultStunTlsPort;
231 turn_transport_type = kTcpTransportType;
235 if (!ParseHostnameAndPortFromString(hoststring, &address, &port)) {
236 LOG(WARNING) << "Invalid Hostname format: " << uri_without_transport;
241 if (port <= 0 || port > 0xffff) {
242 LOG(WARNING) << "Invalid port: " << port;
246 switch (service_type) {
249 stun_config->push_back(StunConfiguration(address, port));
253 if (server.username.empty()) {
254 // Turn url example from the spec |url:"turn:user@turn.example.org"|.
255 std::vector<std::string> turn_tokens;
256 rtc::tokenize(address, '@', &turn_tokens);
257 if (turn_tokens.size() == kTurnHostTokensNum) {
258 server.username = rtc::s_url_decode(turn_tokens[0]);
259 address = turn_tokens[1];
263 bool secure = (service_type == TURNS);
265 turn_config->push_back(TurnConfiguration(address, port,
274 LOG(WARNING) << "Configuration not supported: " << server.uri;
281 // Check if we can send |new_stream| on a PeerConnection.
282 // Currently only one audio but multiple video track is supported per
284 bool CanAddLocalMediaStream(webrtc::StreamCollectionInterface* current_streams,
285 webrtc::MediaStreamInterface* new_stream) {
286 if (!new_stream || !current_streams)
288 if (current_streams->find(new_stream->label()) != NULL) {
289 LOG(LS_ERROR) << "MediaStream with label " << new_stream->label()
290 << " is already added.";
301 PeerConnection::PeerConnection(PeerConnectionFactory* factory)
305 signaling_state_(kStable),
307 ice_connection_state_(kIceConnectionNew),
308 ice_gathering_state_(kIceGatheringNew) {
311 PeerConnection::~PeerConnection() {
312 if (mediastream_signaling_)
313 mediastream_signaling_->TearDown();
314 if (stream_handler_container_)
315 stream_handler_container_->TearDown();
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)) {
330 return DoInitialize(configuration.type, stun_config, turn_config, constraints,
331 allocator_factory, dtls_identity_service, 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);
345 observer_ = observer;
346 port_allocator_.reset(
347 allocator_factory->CreatePortAllocator(stun_config, turn_config));
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;
357 MediaConstraintsInterface::kEnableIPv6,
358 &value, NULL) && value) {
359 portallocator_flags |= cricket::PORTALLOCATOR_ENABLE_IPV6;
362 port_allocator_->set_flags(portallocator_flags);
363 // No step delay is used while allocating ports.
364 port_allocator_->set_step_delay(cricket::kMinimumStepDelay);
366 mediastream_signaling_.reset(new MediaStreamSignaling(
367 factory_->signaling_thread(), this, factory_->channel_manager()));
369 session_.reset(new WebRtcSession(factory_->channel_manager(),
370 factory_->signaling_thread(),
371 factory_->worker_thread(),
372 port_allocator_.get(),
373 mediastream_signaling_.get()));
374 stream_handler_container_.reset(new MediaStreamHandlerContainer(
375 session_.get(), session_.get()));
376 stats_.reset(new StatsCollector(session_.get()));
378 // Initialize the WebRtcSession. It creates transport channels etc.
379 if (!session_->Initialize(factory_->options(), constraints,
380 dtls_identity_service, type))
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);
390 rtc::scoped_refptr<StreamCollectionInterface>
391 PeerConnection::local_streams() {
392 return mediastream_signaling_->local_streams();
395 rtc::scoped_refptr<StreamCollectionInterface>
396 PeerConnection::remote_streams() {
397 return mediastream_signaling_->remote_streams();
400 bool PeerConnection::AddStream(MediaStreamInterface* local_stream,
401 const MediaConstraintsInterface* constraints) {
405 if (!CanAddLocalMediaStream(mediastream_signaling_->local_streams(),
409 // TODO(perkj): Implement support for MediaConstraints in AddStream.
410 if (!mediastream_signaling_->AddLocalStream(local_stream)) {
413 stats_->AddStream(local_stream);
414 observer_->OnRenegotiationNeeded();
418 void PeerConnection::RemoveStream(MediaStreamInterface* local_stream) {
419 mediastream_signaling_->RemoveLocalStream(local_stream);
423 observer_->OnRenegotiationNeeded();
426 rtc::scoped_refptr<DtmfSenderInterface> PeerConnection::CreateDtmfSender(
427 AudioTrackInterface* track) {
429 LOG(LS_ERROR) << "CreateDtmfSender - track is NULL.";
432 if (!mediastream_signaling_->local_streams()->FindAudioTrack(track->id())) {
433 LOG(LS_ERROR) << "CreateDtmfSender is called with a non local audio track.";
437 rtc::scoped_refptr<DtmfSenderInterface> sender(
438 DtmfSender::Create(track, signaling_thread(), session_.get()));
440 LOG(LS_ERROR) << "CreateDtmfSender failed on DtmfSender::Create.";
443 return DtmfSenderProxy::Create(signaling_thread(), sender.get());
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.";
454 stats_->UpdateStats(level);
455 rtc::scoped_ptr<GetStatsMsg> msg(new GetStatsMsg(observer));
456 if (!stats_->GetStats(track, &(msg->reports))) {
459 signaling_thread()->Post(this, MSG_GETSTATS, msg.release());
463 PeerConnectionInterface::SignalingState PeerConnection::signaling_state() {
464 return signaling_state_;
467 PeerConnectionInterface::IceState PeerConnection::ice_state() {
471 PeerConnectionInterface::IceConnectionState
472 PeerConnection::ice_connection_state() {
473 return ice_connection_state_;
476 PeerConnectionInterface::IceGatheringState
477 PeerConnection::ice_gathering_state() {
478 return ice_gathering_state_;
481 rtc::scoped_refptr<DataChannelInterface>
482 PeerConnection::CreateDataChannel(
483 const std::string& label,
484 const DataChannelInit* config) {
485 bool first_datachannel = !mediastream_signaling_->HasDataChannels();
487 rtc::scoped_ptr<InternalDataChannelInit> internal_config;
489 internal_config.reset(new InternalDataChannelInit(*config));
491 rtc::scoped_refptr<DataChannelInterface> channel(
492 session_->CreateDataChannel(label, internal_config.get()));
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();
502 return DataChannelProxy::Create(signaling_thread(), channel.get());
505 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
506 const MediaConstraintsInterface* constraints) {
507 if (!VERIFY(observer != NULL)) {
508 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
511 RTCOfferAnswerOptions options;
512 // Defaults to receiving audio and not receiving video.
513 options.offer_to_receive_audio =
514 RTCOfferAnswerOptions::kOfferToReceiveMediaTrue;
515 options.offer_to_receive_video = 0;
518 size_t mandatory_constraints = 0;
520 if (FindConstraint(constraints,
521 MediaConstraintsInterface::kOfferToReceiveAudio,
523 &mandatory_constraints)) {
524 options.offer_to_receive_audio =
525 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
528 if (FindConstraint(constraints,
529 MediaConstraintsInterface::kOfferToReceiveVideo,
531 &mandatory_constraints)) {
532 options.offer_to_receive_video =
533 value ? RTCOfferAnswerOptions::kOfferToReceiveMediaTrue : 0;
536 if (FindConstraint(constraints,
537 MediaConstraintsInterface::kVoiceActivityDetection,
539 &mandatory_constraints)) {
540 options.voice_activity_detection = value;
543 if (FindConstraint(constraints,
544 MediaConstraintsInterface::kIceRestart,
546 &mandatory_constraints)) {
547 options.ice_restart = value;
550 if (FindConstraint(constraints,
551 MediaConstraintsInterface::kUseRtpMux,
553 &mandatory_constraints)) {
554 options.use_rtp_mux = value;
557 CreateOffer(observer, options);
560 void PeerConnection::CreateOffer(CreateSessionDescriptionObserver* observer,
561 const RTCOfferAnswerOptions& options) {
562 if (!VERIFY(observer != NULL)) {
563 LOG(LS_ERROR) << "CreateOffer - observer is NULL.";
566 session_->CreateOffer(observer, options);
569 void PeerConnection::CreateAnswer(
570 CreateSessionDescriptionObserver* observer,
571 const MediaConstraintsInterface* constraints) {
572 if (!VERIFY(observer != NULL)) {
573 LOG(LS_ERROR) << "CreateAnswer - observer is NULL.";
576 session_->CreateAnswer(observer, constraints);
579 void PeerConnection::SetLocalDescription(
580 SetSessionDescriptionObserver* observer,
581 SessionDescriptionInterface* desc) {
582 if (!VERIFY(observer != NULL)) {
583 LOG(LS_ERROR) << "SetLocalDescription - observer is NULL.";
587 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
590 // Update stats here so that we have the most recent stats for tracks and
591 // streams that might be removed by updating the session description.
592 stats_->UpdateStats(kStatsOutputLevelStandard);
594 if (!session_->SetLocalDescription(desc, &error)) {
595 PostSetSessionDescriptionFailure(observer, error);
598 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
599 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
602 void PeerConnection::SetRemoteDescription(
603 SetSessionDescriptionObserver* observer,
604 SessionDescriptionInterface* desc) {
605 if (!VERIFY(observer != NULL)) {
606 LOG(LS_ERROR) << "SetRemoteDescription - observer is NULL.";
610 PostSetSessionDescriptionFailure(observer, "SessionDescription is NULL.");
613 // Update stats here so that we have the most recent stats for tracks and
614 // streams that might be removed by updating the session description.
615 stats_->UpdateStats(kStatsOutputLevelStandard);
617 if (!session_->SetRemoteDescription(desc, &error)) {
618 PostSetSessionDescriptionFailure(observer, error);
621 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
622 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_SUCCESS, msg);
625 void PeerConnection::PostSetSessionDescriptionFailure(
626 SetSessionDescriptionObserver* observer,
627 const std::string& error) {
628 SetSessionDescriptionMsg* msg = new SetSessionDescriptionMsg(observer);
630 signaling_thread()->Post(this, MSG_SET_SESSIONDESCRIPTION_FAILED, msg);
633 bool PeerConnection::UpdateIce(const IceServers& configuration,
634 const MediaConstraintsInterface* constraints) {
638 bool PeerConnection::UpdateIce(const RTCConfiguration& config) {
639 if (port_allocator_) {
640 std::vector<PortAllocatorFactoryInterface::StunConfiguration> stuns;
641 std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turns;
642 if (!ParseIceServers(config.servers, &stuns, &turns)) {
646 std::vector<rtc::SocketAddress> stun_hosts;
647 typedef std::vector<StunConfiguration>::const_iterator StunIt;
648 for (StunIt stun_it = stuns.begin(); stun_it != stuns.end(); ++stun_it) {
649 stun_hosts.push_back(stun_it->server);
652 rtc::SocketAddress stun_addr;
653 if (!stun_hosts.empty()) {
654 stun_addr = stun_hosts.front();
655 LOG(LS_INFO) << "UpdateIce: StunServer Address: " << stun_addr.ToString();
658 for (size_t i = 0; i < turns.size(); ++i) {
659 cricket::RelayCredentials credentials(turns[i].username,
661 cricket::RelayServerConfig relay_server(cricket::RELAY_TURN);
662 cricket::ProtocolType protocol;
663 if (cricket::StringToProto(turns[i].transport_type.c_str(), &protocol)) {
664 relay_server.ports.push_back(cricket::ProtocolAddress(
665 turns[i].server, protocol, turns[i].secure));
666 relay_server.credentials = credentials;
667 LOG(LS_INFO) << "UpdateIce: TurnServer Address: "
668 << turns[i].server.ToString();
670 LOG(LS_WARNING) << "Ignoring TURN server " << turns[i].server << ". "
671 << "Reason= Incorrect " << turns[i].transport_type
672 << " transport parameter.";
676 return session_->UpdateIce(config.type);
679 bool PeerConnection::AddIceCandidate(
680 const IceCandidateInterface* ice_candidate) {
681 return session_->ProcessIceMessage(ice_candidate);
684 void PeerConnection::RegisterUMAObserver(UMAObserver* observer) {
685 uma_observer_ = observer;
686 // Send information about IPv4/IPv6 status.
687 if (uma_observer_ && port_allocator_) {
688 if (port_allocator_->flags() & cricket::PORTALLOCATOR_ENABLE_IPV6) {
689 uma_observer_->IncrementCounter(kPeerConnection_IPv6);
691 uma_observer_->IncrementCounter(kPeerConnection_IPv4);
696 const SessionDescriptionInterface* PeerConnection::local_description() const {
697 return session_->local_description();
700 const SessionDescriptionInterface* PeerConnection::remote_description() const {
701 return session_->remote_description();
704 void PeerConnection::Close() {
705 // Update stats here so that we have the most recent stats for tracks and
706 // streams before the channels are closed.
707 stats_->UpdateStats(kStatsOutputLevelStandard);
709 session_->Terminate();
712 void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
713 cricket::BaseSession::State state) {
715 case cricket::BaseSession::STATE_INIT:
716 ChangeSignalingState(PeerConnectionInterface::kStable);
718 case cricket::BaseSession::STATE_SENTINITIATE:
719 ChangeSignalingState(PeerConnectionInterface::kHaveLocalOffer);
721 case cricket::BaseSession::STATE_SENTPRACCEPT:
722 ChangeSignalingState(PeerConnectionInterface::kHaveLocalPrAnswer);
724 case cricket::BaseSession::STATE_RECEIVEDINITIATE:
725 ChangeSignalingState(PeerConnectionInterface::kHaveRemoteOffer);
727 case cricket::BaseSession::STATE_RECEIVEDPRACCEPT:
728 ChangeSignalingState(PeerConnectionInterface::kHaveRemotePrAnswer);
730 case cricket::BaseSession::STATE_SENTACCEPT:
731 case cricket::BaseSession::STATE_RECEIVEDACCEPT:
732 ChangeSignalingState(PeerConnectionInterface::kStable);
734 case cricket::BaseSession::STATE_RECEIVEDTERMINATE:
735 ChangeSignalingState(PeerConnectionInterface::kClosed);
742 void PeerConnection::OnMessage(rtc::Message* msg) {
743 switch (msg->message_id) {
744 case MSG_SET_SESSIONDESCRIPTION_SUCCESS: {
745 SetSessionDescriptionMsg* param =
746 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
747 param->observer->OnSuccess();
751 case MSG_SET_SESSIONDESCRIPTION_FAILED: {
752 SetSessionDescriptionMsg* param =
753 static_cast<SetSessionDescriptionMsg*>(msg->pdata);
754 param->observer->OnFailure(param->error);
759 GetStatsMsg* param = static_cast<GetStatsMsg*>(msg->pdata);
760 param->observer->OnComplete(param->reports);
765 ASSERT(false && "Not implemented");
770 void PeerConnection::OnAddRemoteStream(MediaStreamInterface* stream) {
771 stats_->AddStream(stream);
772 observer_->OnAddStream(stream);
775 void PeerConnection::OnRemoveRemoteStream(MediaStreamInterface* stream) {
776 stream_handler_container_->RemoveRemoteStream(stream);
777 observer_->OnRemoveStream(stream);
780 void PeerConnection::OnAddDataChannel(DataChannelInterface* data_channel) {
781 observer_->OnDataChannel(DataChannelProxy::Create(signaling_thread(),
785 void PeerConnection::OnAddRemoteAudioTrack(MediaStreamInterface* stream,
786 AudioTrackInterface* audio_track,
788 stream_handler_container_->AddRemoteAudioTrack(stream, audio_track, ssrc);
791 void PeerConnection::OnAddRemoteVideoTrack(MediaStreamInterface* stream,
792 VideoTrackInterface* video_track,
794 stream_handler_container_->AddRemoteVideoTrack(stream, video_track, ssrc);
797 void PeerConnection::OnRemoveRemoteAudioTrack(
798 MediaStreamInterface* stream,
799 AudioTrackInterface* audio_track) {
800 stream_handler_container_->RemoveRemoteTrack(stream, audio_track);
803 void PeerConnection::OnRemoveRemoteVideoTrack(
804 MediaStreamInterface* stream,
805 VideoTrackInterface* video_track) {
806 stream_handler_container_->RemoveRemoteTrack(stream, video_track);
808 void PeerConnection::OnAddLocalAudioTrack(MediaStreamInterface* stream,
809 AudioTrackInterface* audio_track,
811 stream_handler_container_->AddLocalAudioTrack(stream, audio_track, ssrc);
812 stats_->AddLocalAudioTrack(audio_track, ssrc);
814 void PeerConnection::OnAddLocalVideoTrack(MediaStreamInterface* stream,
815 VideoTrackInterface* video_track,
817 stream_handler_container_->AddLocalVideoTrack(stream, video_track, ssrc);
820 void PeerConnection::OnRemoveLocalAudioTrack(MediaStreamInterface* stream,
821 AudioTrackInterface* audio_track,
823 stream_handler_container_->RemoveLocalTrack(stream, audio_track);
824 stats_->RemoveLocalAudioTrack(audio_track, ssrc);
827 void PeerConnection::OnRemoveLocalVideoTrack(MediaStreamInterface* stream,
828 VideoTrackInterface* video_track) {
829 stream_handler_container_->RemoveLocalTrack(stream, video_track);
832 void PeerConnection::OnRemoveLocalStream(MediaStreamInterface* stream) {
833 stream_handler_container_->RemoveLocalStream(stream);
836 void PeerConnection::OnIceConnectionChange(
837 PeerConnectionInterface::IceConnectionState new_state) {
838 ASSERT(signaling_thread()->IsCurrent());
839 ice_connection_state_ = new_state;
840 observer_->OnIceConnectionChange(ice_connection_state_);
843 void PeerConnection::OnIceGatheringChange(
844 PeerConnectionInterface::IceGatheringState new_state) {
845 ASSERT(signaling_thread()->IsCurrent());
849 ice_gathering_state_ = new_state;
850 observer_->OnIceGatheringChange(ice_gathering_state_);
853 void PeerConnection::OnIceCandidate(const IceCandidateInterface* candidate) {
854 ASSERT(signaling_thread()->IsCurrent());
855 observer_->OnIceCandidate(candidate);
858 void PeerConnection::OnIceComplete() {
859 ASSERT(signaling_thread()->IsCurrent());
860 observer_->OnIceComplete();
863 void PeerConnection::ChangeSignalingState(
864 PeerConnectionInterface::SignalingState signaling_state) {
865 signaling_state_ = signaling_state;
866 if (signaling_state == kClosed) {
867 ice_connection_state_ = kIceConnectionClosed;
868 observer_->OnIceConnectionChange(ice_connection_state_);
869 if (ice_gathering_state_ != kIceGatheringComplete) {
870 ice_gathering_state_ = kIceGatheringComplete;
871 observer_->OnIceGatheringChange(ice_gathering_state_);
874 observer_->OnSignalingChange(signaling_state_);
875 observer_->OnStateChange(PeerConnectionObserver::kSignalingState);
878 } // namespace webrtc