3
* Copyright 2011, 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/peerconnectionimpl.h"
32
#include "talk/app/webrtc/mediastreamhandler.h"
33
#include "talk/app/webrtc/streamcollectionimpl.h"
34
#include "talk/base/logging.h"
35
#include "talk/base/stringencode.h"
36
#include "talk/session/phone/channelmanager.h"
37
#include "talk/session/phone/webrtcvideocapturer.h"
41
// The number of the tokens in the config string.
42
static const size_t kConfigTokens = 2;
43
// Only the STUN or TURN server address appears in the config string.
44
static const size_t kConfigAddress = 1;
45
// Both of the STUN or TURN server address and port appear in the config string.
46
static const size_t kConfigAddressAndPort = 2;
47
static const size_t kServiceCount = 5;
48
// The default stun port.
49
static const int kDefaultPort = 3478;
51
// NOTE: Must be in the same order as the ServiceType enum.
52
static const char* kValidServiceTypes[kServiceCount] = {
53
"STUN", "STUNS", "TURN", "TURNS", "INVALID" };
56
STUN, // Indicates a STUN server.
57
STUNS, // Indicates a STUN server used with a TLS session.
58
TURN, // Indicates a TURN server
59
TURNS, // Indicates a TURN server used with a TLS session.
66
MSG_COMMITSTREAMCHANGES = 3,
67
MSG_PROCESSSIGNALINGMESSAGE = 4,
68
MSG_RETURNLOCALMEDIASTREAMS = 5,
69
MSG_RETURNREMOTEMEDIASTREAMS = 6,
76
MSG_CREATEANSWER = 13,
77
MSG_SETLOCALDESCRIPTION = 14,
78
MSG_SETREMOTEDESCRIPTION = 15,
79
MSG_PROCESSICEMESSAGE = 16,
80
MSG_GETLOCALDESCRIPTION = 17,
81
MSG_GETREMOTEDESCRIPTION = 18,
84
typedef webrtc::PortAllocatorFactoryInterface::StunConfiguration
86
typedef webrtc::PortAllocatorFactoryInterface::TurnConfiguration
89
bool static ParseConfigString(const std::string& config,
90
std::vector<StunConfiguration>* stun_config,
91
std::vector<TurnConfiguration>* turn_config) {
92
std::vector<std::string> tokens;
93
talk_base::tokenize(config, ' ', &tokens);
95
if (tokens.size() != kConfigTokens) {
96
LOG(WARNING) << "Invalid config string";
100
ServiceType service_type = INVALID;
102
const std::string& type = tokens[0];
103
for (size_t i = 0; i < kServiceCount; ++i) {
104
if (type.compare(kValidServiceTypes[i]) == 0) {
105
service_type = static_cast<ServiceType>(i);
110
if (service_type == INVALID) {
111
LOG(WARNING) << "Invalid service type: " << type;
114
std::string service_address = tokens[1];
119
talk_base::tokenize(service_address, ':', &tokens);
120
if (tokens.size() != kConfigAddress &&
121
tokens.size() != kConfigAddressAndPort) {
122
LOG(WARNING) << "Invalid server address and port: " << service_address;
126
if (tokens.size() == kConfigAddress) {
131
port = talk_base::FromString<int>(tokens[1]);
132
if (port <= 0 || port > 0xffff) {
133
LOG(WARNING) << "Invalid port: " << tokens[1];
138
// TODO: Currently the specification does not tell us how to parse
139
// multiple addresses, username and password from the configuration string.
140
switch (service_type) {
142
stun_config->push_back(StunConfiguration(address, port));
145
turn_config->push_back(TurnConfiguration(address, port, "", ""));
151
LOG(WARNING) << "Configuration not supported";
157
typedef talk_base::TypedMessageData<webrtc::LocalMediaStreamInterface*>
158
LocalMediaStreamParams;
160
typedef talk_base::TypedMessageData<std::string> RoapSignalingParams;
162
struct IceOptionsParams : public talk_base::MessageData {
163
explicit IceOptionsParams(webrtc::JsepInterface::IceOptions options)
167
webrtc::JsepInterface::IceOptions options;
171
struct JsepSessionDescriptionParams : public talk_base::MessageData {
172
JsepSessionDescriptionParams()
177
webrtc::MediaHints hints;
178
webrtc::JsepInterface::Action action;
179
webrtc::SessionDescriptionInterface* desc;
180
const webrtc::SessionDescriptionInterface* const_desc;
183
struct JsepIceCandidateParams : public talk_base::MessageData {
184
explicit JsepIceCandidateParams(
185
const webrtc::IceCandidateInterface* candidate)
187
candidate(candidate) {}
189
const webrtc::IceCandidateInterface* candidate;
192
struct StreamCollectionParams : public talk_base::MessageData {
193
explicit StreamCollectionParams(webrtc::StreamCollectionInterface* streams)
194
: streams(streams) {}
195
talk_base::scoped_refptr<webrtc::StreamCollectionInterface> streams;
198
struct MediaStreamParams : public talk_base::MessageData {
199
explicit MediaStreamParams(webrtc::MediaStreamInterface* stream)
201
talk_base::scoped_refptr<webrtc::MediaStreamInterface> stream;
204
struct ReadyStateMessage : public talk_base::MessageData {
205
ReadyStateMessage() : state(webrtc::PeerConnectionInterface::kNew) {}
206
webrtc::PeerConnectionInterface::ReadyState state;
209
struct SdpStateMessage : public talk_base::MessageData {
210
SdpStateMessage() : state(webrtc::PeerConnectionInterface::kSdpNew) {}
211
webrtc::PeerConnectionInterface::SdpState state;
218
cricket::VideoCapturer* CreateVideoCapturer(VideoCaptureModule* vcm) {
219
cricket::WebRtcVideoCapturer* video_capturer =
220
new cricket::WebRtcVideoCapturer;
221
if (!video_capturer->Init(vcm)) {
222
delete video_capturer;
223
video_capturer = NULL;
225
return video_capturer;
228
PeerConnection::PeerConnection(PeerConnectionFactory* factory)
233
local_media_streams_(StreamCollection::Create()) {
236
PeerConnection::~PeerConnection() {
237
signaling_thread()->Clear(this);
238
signaling_thread()->Send(this, MSG_TERMINATE);
241
// Clean up what needs to be cleaned up on the signaling thread.
242
void PeerConnection::Terminate_s() {
243
stream_handler_.reset();
244
roap_signaling_.reset();
245
mediastream_signaling_.reset();
247
port_allocator_.reset();
250
bool PeerConnection::Initialize(bool use_roap,
251
const std::string& configuration,
252
PeerConnectionObserver* observer) {
253
ASSERT(observer != NULL);
256
observer_ = observer;
257
std::vector<PortAllocatorFactoryInterface::StunConfiguration> stun_config;
258
std::vector<PortAllocatorFactoryInterface::TurnConfiguration> turn_config;
260
ParseConfigString(configuration, &stun_config, &turn_config);
262
port_allocator_.reset(factory_->port_allocator_factory()->CreatePortAllocator(
263
stun_config, turn_config));
265
mediastream_signaling_.reset(new MediaStreamSignaling(
266
factory_->signaling_thread(), this));
268
session_.reset(new WebRtcSession(factory_->channel_manager(),
269
factory_->signaling_thread(),
270
factory_->worker_thread(),
271
port_allocator_.get(),
272
mediastream_signaling_.get()));
273
stream_handler_.reset(new MediaStreamHandlers(session_.get()));
275
// Initialize the WebRtcSession. It creates transport channels etc.
276
if (!session_->Initialize())
280
roap_signaling_.reset(new RoapSignaling(
281
mediastream_signaling_.get(),
283
// Register Roap as receiver of local ice candidates.
284
session_->RegisterObserver(roap_signaling_.get());
285
roap_signaling_->SignalNewPeerConnectionMessage.connect(
286
this, &PeerConnection::OnNewPeerConnectionMessage);
287
roap_signaling_->SignalStateChange.connect(
288
this, &PeerConnection::OnSignalingStateChange);
289
ChangeReadyState(PeerConnectionInterface::kNegotiating);
291
// Register PeerConnection observer as receiver of local ice candidates.
292
session_->RegisterObserver(observer_);
293
session_->SignalState.connect(this, &PeerConnection::OnSessionStateChange);
298
talk_base::scoped_refptr<StreamCollectionInterface>
299
PeerConnection::local_streams() {
300
StreamCollectionParams msg(NULL);
301
signaling_thread()->Send(this, MSG_RETURNLOCALMEDIASTREAMS, &msg);
305
talk_base::scoped_refptr<StreamCollectionInterface>
306
PeerConnection::remote_streams() {
307
StreamCollectionParams msg(NULL);
308
signaling_thread()->Send(this, MSG_RETURNREMOTEMEDIASTREAMS, &msg);
312
void PeerConnection::ProcessSignalingMessage(const std::string& msg) {
313
RoapSignalingParams parameter(msg);
314
signaling_thread()->Send(this, MSG_PROCESSSIGNALINGMESSAGE, ¶meter);
317
void PeerConnection::AddStream(LocalMediaStreamInterface* local_stream) {
318
LocalMediaStreamParams msg(local_stream);
319
signaling_thread()->Send(this, MSG_ADDSTREAM, &msg);
322
void PeerConnection::RemoveStream(LocalMediaStreamInterface* remove_stream) {
323
LocalMediaStreamParams msg(remove_stream);
324
signaling_thread()->Send(this, MSG_REMOVESTREAM, &msg);
327
void PeerConnection::CommitStreamChanges() {
328
signaling_thread()->Send(this, MSG_COMMITSTREAMCHANGES);
331
void PeerConnection::Close() {
332
signaling_thread()->Send(this, MSG_CLOSE);
335
PeerConnectionInterface::ReadyState PeerConnection::ready_state() {
336
ReadyStateMessage msg;
337
signaling_thread()->Send(this, MSG_READYSTATE, &msg);
341
PeerConnectionInterface::SdpState PeerConnection::sdp_state() {
343
signaling_thread()->Send(this, MSG_SDPSTATE, &msg);
347
bool PeerConnection::StartIce(IceOptions options) {
348
IceOptionsParams msg(options);
349
signaling_thread()->Send(this, MSG_STARTICE, &msg);
353
SessionDescriptionInterface* PeerConnection::CreateOffer(
354
const MediaHints& hints) {
355
JsepSessionDescriptionParams msg;
357
signaling_thread()->Send(this, MSG_CREATEOFFER, &msg);
361
SessionDescriptionInterface* PeerConnection::CreateAnswer(
362
const MediaHints& hints,
363
const SessionDescriptionInterface* offer) {
364
JsepSessionDescriptionParams msg;
366
msg.const_desc = offer;
367
signaling_thread()->Send(this, MSG_CREATEANSWER, &msg);
371
bool PeerConnection::SetLocalDescription(Action action,
372
SessionDescriptionInterface* desc) {
373
JsepSessionDescriptionParams msg;
376
signaling_thread()->Send(this, MSG_SETLOCALDESCRIPTION, &msg);
380
bool PeerConnection::SetRemoteDescription(Action action,
381
SessionDescriptionInterface* desc) {
382
JsepSessionDescriptionParams msg;
385
signaling_thread()->Send(this, MSG_SETREMOTEDESCRIPTION, &msg);
389
bool PeerConnection::ProcessIceMessage(
390
const IceCandidateInterface* ice_candidate) {
391
JsepIceCandidateParams msg(ice_candidate);
392
signaling_thread()->Send(this, MSG_PROCESSICEMESSAGE, &msg);
396
const SessionDescriptionInterface* PeerConnection::local_description() const {
397
JsepSessionDescriptionParams msg;
398
signaling_thread()->Send(const_cast<PeerConnection*>(this),
399
MSG_GETLOCALDESCRIPTION, &msg);
400
return msg.const_desc;
403
const SessionDescriptionInterface* PeerConnection::remote_description() const {
404
JsepSessionDescriptionParams msg;
405
signaling_thread()->Send(const_cast<PeerConnection*>(this),
406
MSG_GETREMOTEDESCRIPTION, &msg);
407
return msg.const_desc;
410
void PeerConnection::OnMessage(talk_base::Message* msg) {
411
talk_base::MessageData* data = msg->pdata;
412
switch (msg->message_id) {
413
case MSG_ADDSTREAM: {
414
LocalMediaStreamParams* msg(static_cast<LocalMediaStreamParams*> (data));
415
local_media_streams_->AddStream(msg->data());
418
case MSG_REMOVESTREAM: {
419
LocalMediaStreamParams* msg(static_cast<LocalMediaStreamParams*> (data));
420
local_media_streams_->RemoveStream(msg->data());
423
case MSG_COMMITSTREAMCHANGES: {
424
if (ready_state_ != PeerConnectionInterface::kClosed ||
425
ready_state_ != PeerConnectionInterface::kClosing) {
426
mediastream_signaling_->SetLocalStreams(local_media_streams_);
427
// If we use ROAP an offer is created and we setup the local
429
if (roap_signaling_.get() != NULL) {
430
roap_signaling_->CreateOffer(local_media_streams_);
431
stream_handler_->CommitLocalStreams(local_media_streams_);
436
case MSG_PROCESSSIGNALINGMESSAGE: {
437
if (ready_state_ != PeerConnectionInterface::kClosed &&
438
roap_signaling_.get() != NULL) {
439
RoapSignalingParams* params(static_cast<RoapSignalingParams*> (data));
440
roap_signaling_->ProcessSignalingMessage(params->data(),
441
local_media_streams_);
445
case MSG_RETURNLOCALMEDIASTREAMS: {
446
StreamCollectionParams* param(
447
static_cast<StreamCollectionParams*> (data));
448
param->streams = StreamCollection::Create(local_media_streams_);
451
case MSG_RETURNREMOTEMEDIASTREAMS: {
452
StreamCollectionParams* param(
453
static_cast<StreamCollectionParams*> (data));
454
param->streams = mediastream_signaling_->remote_streams();
458
if (ready_state_ != PeerConnectionInterface::kClosed &&
459
roap_signaling_.get() != NULL) {
460
ChangeReadyState(PeerConnectionInterface::kClosing);
461
roap_signaling_->SendShutDown();
465
case MSG_READYSTATE: {
466
ReadyStateMessage* msg(static_cast<ReadyStateMessage*> (data));
467
msg->state = ready_state_;
471
SdpStateMessage* msg(static_cast<SdpStateMessage*> (data));
472
msg->state = sdp_state_;
476
if (ready_state_ != PeerConnectionInterface::kClosed &&
477
ready_state_ != PeerConnectionInterface::kClosing) {
478
IceOptionsParams* param(
479
static_cast<IceOptionsParams*> (data));
480
param->result = session_->StartIce(param->options);
484
case MSG_CREATEOFFER: {
485
if (ready_state_ != PeerConnectionInterface::kClosed &&
486
ready_state_ != PeerConnectionInterface::kClosing) {
487
JsepSessionDescriptionParams* param(
488
static_cast<JsepSessionDescriptionParams*> (data));
489
param->desc = session_->CreateOffer(param->hints);
493
case MSG_CREATEANSWER: {
494
if (ready_state_ != PeerConnectionInterface::kClosed &&
495
ready_state_ != PeerConnectionInterface::kClosing) {
496
JsepSessionDescriptionParams* param(
497
static_cast<JsepSessionDescriptionParams*> (data));
498
param->desc = session_->CreateAnswer(param->hints,
503
case MSG_SETLOCALDESCRIPTION: {
504
if (ready_state_ != PeerConnectionInterface::kClosed &&
505
ready_state_ != PeerConnectionInterface::kClosing) {
506
JsepSessionDescriptionParams* param(
507
static_cast<JsepSessionDescriptionParams*> (data));
508
param->result = session_->SetLocalDescription(param->action,
510
stream_handler_->CommitLocalStreams(local_media_streams_);
514
case MSG_SETREMOTEDESCRIPTION: {
515
if (ready_state_ != PeerConnectionInterface::kClosed &&
516
ready_state_ != PeerConnectionInterface::kClosing) {
517
JsepSessionDescriptionParams* param(
518
static_cast<JsepSessionDescriptionParams*> (data));
519
param->result = session_->SetRemoteDescription(param->action,
524
case MSG_PROCESSICEMESSAGE: {
525
if (ready_state_ != PeerConnectionInterface::kClosed ||
526
ready_state_ != PeerConnectionInterface::kClosing) {
527
JsepIceCandidateParams * param(
528
static_cast<JsepIceCandidateParams*> (data));
529
param->result = session_->ProcessIceMessage(param->candidate);
533
case MSG_GETLOCALDESCRIPTION: {
534
JsepSessionDescriptionParams* param(
535
static_cast<JsepSessionDescriptionParams*> (data));
536
param->const_desc = session_->local_description();
539
case MSG_GETREMOTEDESCRIPTION: {
540
JsepSessionDescriptionParams* param(
541
static_cast<JsepSessionDescriptionParams*> (data));
542
param->const_desc = session_->remote_description();
545
case MSG_TERMINATE: {
550
ASSERT(!"NOT IMPLEMENTED");
555
void PeerConnection::OnNewPeerConnectionMessage(const std::string& message) {
556
observer_->OnSignalingMessage(message);
559
void PeerConnection::OnSignalingStateChange(
560
RoapSignaling::State state) {
562
case RoapSignaling::kInitializing:
564
case RoapSignaling::kIdle:
565
if (ready_state_ == PeerConnectionInterface::kNegotiating)
566
ChangeReadyState(PeerConnectionInterface::kActive);
567
ChangeSdpState(PeerConnectionInterface::kSdpIdle);
569
case RoapSignaling::kWaitingForAnswer:
570
ChangeSdpState(PeerConnectionInterface::kSdpWaiting);
572
case RoapSignaling::kWaitingForOK:
573
ChangeSdpState(PeerConnectionInterface::kSdpWaiting);
575
case RoapSignaling::kShutingDown:
576
ChangeReadyState(PeerConnectionInterface::kClosing);
578
case RoapSignaling::kShutdownComplete:
579
ChangeReadyState(PeerConnectionInterface::kClosed);
580
signaling_thread()->Post(this, MSG_TERMINATE);
583
ASSERT(!"NOT IMPLEMENTED");
588
void PeerConnection::OnSessionStateChange(cricket::BaseSession* /*session*/,
589
cricket::BaseSession::State state) {
591
case cricket::BaseSession::STATE_INIT:
592
ChangeReadyState(PeerConnectionInterface::kNew);
593
case cricket::BaseSession::STATE_SENTINITIATE:
594
case cricket::BaseSession::STATE_RECEIVEDINITIATE:
595
ChangeReadyState(PeerConnectionInterface::kNegotiating);
597
case cricket::BaseSession::STATE_SENTACCEPT:
598
case cricket::BaseSession::STATE_RECEIVEDACCEPT:
599
ChangeReadyState(PeerConnectionInterface::kActive);
606
void PeerConnection::OnAddStream(MediaStreamInterface* stream) {
607
stream_handler_->AddRemoteStream(stream);
608
observer_->OnAddStream(stream);
611
void PeerConnection::OnRemoveStream(MediaStreamInterface* stream) {
612
stream_handler_->RemoveRemoteStream(stream);
613
observer_->OnRemoveStream(stream);
616
void PeerConnection::ChangeReadyState(
617
PeerConnectionInterface::ReadyState ready_state) {
618
ready_state_ = ready_state;
619
observer_->OnStateChange(PeerConnectionObserver::kReadyState);
622
void PeerConnection::ChangeSdpState(
623
PeerConnectionInterface::SdpState sdp_state) {
624
sdp_state_ = sdp_state;
625
observer_->OnStateChange(PeerConnectionObserver::kSdpState);
628
} // namespace webrtc