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.
30
#include "talk/app/webrtc/audiotrack.h"
31
#include "talk/app/webrtc/mediastream.h"
32
#include "talk/app/webrtc/jsepsessiondescription.h"
33
#include "talk/app/webrtc/mediastreamsignaling.h"
34
#include "talk/app/webrtc/roapsignaling.h"
35
#include "talk/app/webrtc/streamcollectionimpl.h"
36
#include "talk/app/webrtc/videotrack.h"
37
#include "talk/base/gunit.h"
38
#include "talk/base/scoped_ptr.h"
39
#include "talk/base/thread.h"
40
#include "talk/session/phone/channelmanager.h"
42
static const char kStreamLabel1[] = "local_stream_1";
43
static const char kStreamLabel2[] = "local_stream_2";
44
static const char kAudioTrackLabel1[] = "local_audio_1";
45
static const char kAudioTrackLabel2[] = "local_audio_2";
46
static const char kVideoTrackLabel1[] = "local_video_1";
50
// MockSignalingObserver implements functions for listening all signals and
51
// callbacks from a RoapSignaling instance.
52
// The method AnswerPeer can be used to forward messages from one
53
// RoapSignaling instance to another.
54
class MockSignalingObserver : public RemoteMediaStreamObserver,
55
public sigslot::has_slots<> {
57
MockSignalingObserver()
58
: last_error_(-1), // Initialize last_error_ to unused error code.
59
state_(RoapSignaling::kInitializing),
60
remote_streams_(StreamCollection::Create()),
64
virtual ~MockSignalingObserver() {}
66
// Implements RemoteMediaStreamObserver.
67
virtual void OnAddStream(MediaStreamInterface* remote_stream) {
68
EXPECT_EQ(MediaStreamInterface::kLive, remote_stream->ready_state());
69
remote_streams_->AddStream(remote_stream);
71
// Implements RemoteMediaStreamObserver.
72
virtual void OnRemoveStream(MediaStreamInterface* remote_stream) {
73
EXPECT_TRUE(remote_streams_->find(remote_stream->label()) != NULL);
74
EXPECT_EQ(MediaStreamInterface::kEnded, remote_stream->ready_state());
75
remote_streams_->RemoveStream(remote_stream);
78
virtual void OnStateChange(RoapSignaling::State state) {
82
virtual void OnErrorReceived(RoapErrorCode error) {
86
void OnSignalingMessage(const std::string& smessage) {
87
last_message_ = smessage;
89
remote_peer_->ProcessSignalingMessage(smessage, remote_local_collection_);
93
// Tell this object to answer the remote_peer.
94
// remote_local_collection is the local collection the remote peer want to
96
void AnswerPeer(RoapSignaling* remote_peer,
97
StreamCollection* remote_local_collection) {
98
remote_peer_ = remote_peer;
99
remote_local_collection_ = remote_local_collection;
102
void CancelAnswerPeer() {
104
remote_local_collection_.release();
107
MediaStreamInterface* RemoteStream(const std::string& label) {
108
return remote_streams_->find(label);
110
StreamCollectionInterface* remote_streams() {
111
return remote_streams_.get();
114
std::string last_message_;
116
RoapSignaling::State state_;
119
talk_base::scoped_refptr<StreamCollection> remote_streams_;
120
talk_base::scoped_refptr<StreamCollection> remote_local_collection_;
121
RoapSignaling* remote_peer_;
124
// Fake implementation of JsepInterface.
125
// RoapSignaling uses this object to create session descriptions and
126
// create remote MediaStreams.
127
class FakeJsep : public JsepInterface {
130
cricket::ChannelManager* channel_manager,
131
RemoteMediaStreamObserver* media_stream_observer)
132
: update_session_description_counter_(0),
133
stream_signaling_(talk_base::Thread::Current(), media_stream_observer),
134
session_description_factory_(
135
new cricket::MediaSessionDescriptionFactory(channel_manager)),
137
session_description_factory_->set_add_legacy_streams(false);
139
virtual SessionDescriptionInterface* CreateOffer(const MediaHints& hints) {
140
cricket::MediaSessionOptions options =
141
stream_signaling_.GetMediaSessionOptions(hints);
142
const cricket::SessionDescription* desc =
143
local_desc_.get() != NULL ? local_desc_->description() : NULL;
144
return new JsepSessionDescription(
145
session_description_factory_->CreateOffer(options,
148
virtual SessionDescriptionInterface* CreateAnswer(
149
const MediaHints& hints,
150
const SessionDescriptionInterface* offer) {
151
cricket::MediaSessionOptions options =
152
stream_signaling_.GetMediaSessionOptions(hints);
153
const cricket::SessionDescription* desc =
154
local_desc_.get() != NULL ? local_desc_->description() : NULL;
155
return new JsepSessionDescription(
156
session_description_factory_->CreateAnswer(offer->description(),
160
virtual bool StartIce(IceOptions options) {
163
virtual bool SetLocalDescription(Action action,
164
SessionDescriptionInterface* desc) {
165
local_desc_.reset(desc);
166
UpdateNegotiationState(action);
169
virtual bool SetRemoteDescription(Action action,
170
SessionDescriptionInterface* desc) {
171
UpdateNegotiationState(action);
172
remote_desc_.reset(desc);
173
stream_signaling_.UpdateRemoteStreams(desc);
176
virtual bool ProcessIceMessage(const IceCandidateInterface* ice_candidate) {
179
virtual const SessionDescriptionInterface* local_description() const {
180
return local_desc_.get();
182
virtual const SessionDescriptionInterface* remote_description() const {
183
return remote_desc_.get();
185
MediaStreamSignaling* mediastream_signaling() { return &stream_signaling_; }
186
// |update_session_description_counter_| is the number of successful
187
// negotiations / re-negotiations.
188
size_t update_session_description_counter_;
191
void UpdateNegotiationState(JsepInterface::Action action) {
192
if (action == kAnswer && offer_set_) {
193
// We have received and offer and now we receive an answer.
194
// Negotiation is done. Update the counter to indicate this.
195
++update_session_description_counter_;
198
// Received an offer when expecting an answer?
199
EXPECT_FALSE(offer_set_);
203
MediaStreamSignaling stream_signaling_;
204
talk_base::scoped_ptr<cricket::MediaSessionDescriptionFactory>
205
session_description_factory_;
206
talk_base::scoped_ptr<SessionDescriptionInterface> local_desc_;
207
talk_base::scoped_ptr<SessionDescriptionInterface> remote_desc_;
211
// RoapSignalingTest create two RoapSignaling instances
212
// and connects the signals to two MockSignalingObservers.
213
// This is used in tests to test the signaling between to peers.
214
class RoapSignalingTest: public testing::Test {
216
virtual void SetUp() {
217
channel_manager_.reset(new cricket::ChannelManager(
218
talk_base::Thread::Current()));
219
EXPECT_TRUE(channel_manager_->Init());
221
observer1_.reset(new MockSignalingObserver());
222
provider1_.reset(new FakeJsep(channel_manager_.get(),
224
signaling1_.reset(new RoapSignaling(provider1_->mediastream_signaling(),
226
signaling1_->SignalNewPeerConnectionMessage.connect(
227
observer1_.get(), &MockSignalingObserver::OnSignalingMessage);
228
signaling1_->SignalErrorMessageReceived.connect(
229
observer1_.get(), &MockSignalingObserver::OnErrorReceived);
230
signaling1_->SignalStateChange.connect(
231
observer1_.get(), &MockSignalingObserver::OnStateChange);
233
observer2_.reset(new MockSignalingObserver());
234
provider2_.reset(new FakeJsep(channel_manager_.get(),
236
signaling2_.reset(new RoapSignaling(provider2_->mediastream_signaling(),
238
signaling2_->SignalNewPeerConnectionMessage.connect(
239
observer2_.get(), &MockSignalingObserver::OnSignalingMessage);
240
signaling2_->SignalErrorMessageReceived.connect(
241
observer2_.get(), &MockSignalingObserver::OnErrorReceived);
242
signaling2_->SignalStateChange.connect(
243
observer2_.get(), &MockSignalingObserver::OnStateChange);
246
// Create a collection of streams be sent on signaling1__
247
talk_base::scoped_refptr<StreamCollection> CreateLocalCollection1() {
248
std::string label(kStreamLabel1);
249
talk_base::scoped_refptr<LocalMediaStreamInterface> stream1(
250
MediaStream::Create(label));
252
// Add a local audio track.
253
talk_base::scoped_refptr<LocalAudioTrackInterface>
254
audio_track(AudioTrack::CreateLocal(kAudioTrackLabel1, NULL));
255
stream1->AddTrack(audio_track);
257
// Add a local video track.
258
talk_base::scoped_refptr<LocalVideoTrackInterface>
259
video_track(VideoTrack::CreateLocal(kVideoTrackLabel1, NULL));
260
stream1->AddTrack(video_track);
262
talk_base::scoped_refptr<StreamCollection> local_collection1(
263
StreamCollection::Create());
264
local_collection1->AddStream(stream1);
266
return local_collection1;
269
talk_base::scoped_refptr<StreamCollection> CreateLocalCollection2() {
270
std::string label(kStreamLabel2);
271
talk_base::scoped_refptr<LocalMediaStreamInterface> stream2(
272
MediaStream::Create(label));
274
// Add a local audio track.
275
talk_base::scoped_refptr<LocalAudioTrackInterface>
276
audio_track(AudioTrack::CreateLocal(kAudioTrackLabel2, NULL));
277
stream2->AddTrack(audio_track);
279
talk_base::scoped_refptr<StreamCollection> local_collection2(
280
StreamCollection::Create());
281
local_collection2->AddStream(stream2);
283
return local_collection2;
286
// Initialize and setup a simple call between signaling1_ and signaling2_.
287
// signaling1_ send stream with label kStreamLabel1 to signaling2_.
288
void SetUpOneWayCall() {
289
// Create a local stream collection to be sent on signaling1_.
290
talk_base::scoped_refptr<StreamCollection> local_collection1(
291
CreateLocalCollection1());
293
talk_base::scoped_refptr<StreamCollection> local_collection2(
294
StreamCollection::Create());
296
// Connect all messages sent from signaling1_ to be received on signaling2_
297
observer1_->AnswerPeer(signaling2_.get(), local_collection2);
298
// Connect all messages sent from Peer2 to be received on Peer1
299
observer2_->AnswerPeer(signaling1_.get(), local_collection1);
301
signaling1_->CreateOffer(local_collection1);
302
EXPECT_EQ(RoapSignaling::kInitializing,
303
signaling1_->GetState());
304
// Initialize signaling1_ by providing the candidates.
305
signaling1_->OnIceComplete();
306
EXPECT_EQ(RoapSignaling::kWaitingForAnswer,
307
signaling1_->GetState());
309
EXPECT_EQ(RoapSignaling::kInitializing, signaling2_->GetState());
310
signaling2_->OnIceComplete();
312
// Make sure all is setup.
313
EXPECT_EQ(RoapSignaling::kIdle, signaling1_->GetState());
314
EXPECT_EQ(RoapSignaling::kIdle, signaling2_->GetState());
316
EXPECT_TRUE(observer2_->RemoteStream(kStreamLabel1) != NULL);
317
EXPECT_EQ(0u, observer1_->remote_streams()->count());
318
EXPECT_EQ(1u, observer2_->remote_streams()->count());
321
talk_base::scoped_ptr<MockSignalingObserver> observer1_;
322
talk_base::scoped_ptr<MockSignalingObserver> observer2_;
323
talk_base::scoped_ptr<FakeJsep> provider1_;
324
talk_base::scoped_ptr<FakeJsep> provider2_;
325
talk_base::scoped_ptr<RoapSignaling> signaling1_;
326
talk_base::scoped_ptr<RoapSignaling> signaling2_;
327
talk_base::scoped_ptr<cricket::ChannelManager> channel_manager_;
330
TEST_F(RoapSignalingTest, SimpleOneWayCall) {
331
// Peer 1 create an offer with only one audio track.
332
talk_base::scoped_refptr<StreamCollection> local_collection1(
333
CreateLocalCollection1());
335
// Peer 2 only receive. Create an empty collection
336
talk_base::scoped_refptr<StreamCollection> local_collection2(
337
StreamCollection::Create());
339
// Connect all messages sent from Peer1 to be received on Peer2
340
observer1_->AnswerPeer(signaling2_.get(), local_collection2);
341
// Connect all messages sent from Peer2 to be received on Peer1
342
observer2_->AnswerPeer(signaling1_.get(), local_collection1);
344
// Peer 1 generates the offer. It is not sent since there is no
345
// local candidates ready.
346
signaling1_->CreateOffer(local_collection1);
348
EXPECT_EQ(RoapSignaling::kInitializing, signaling1_->GetState());
350
// Initialize signaling1_ by providing the candidates.
351
signaling1_->OnIceComplete();
352
EXPECT_EQ(RoapSignaling::kWaitingForAnswer,
353
signaling1_->GetState());
355
// Verify that signaling_2 is still not initialized.
356
// Even though it have received an offer.
357
EXPECT_EQ(RoapSignaling::kInitializing, signaling2_->GetState());
359
// Provide the candidates to signaling_2 and let it process the offer.
360
signaling2_->OnIceComplete();
362
// Verify that the offer/answer have been exchanged and the state is good.
363
EXPECT_EQ(RoapSignaling::kIdle, signaling1_->GetState());
364
EXPECT_EQ(RoapSignaling::kIdle, signaling2_->GetState());
366
// Verify that PeerConnection2 is aware of the sending stream.
367
EXPECT_TRUE(observer2_->RemoteStream(kStreamLabel1) != NULL);
369
// Verify that both peers have updated the session descriptions.
370
EXPECT_EQ(1u, provider1_->update_session_description_counter_);
371
EXPECT_EQ(1u, provider2_->update_session_description_counter_);
374
TEST_F(RoapSignalingTest, Glare) {
378
// Stop sending all messages automatically between Peer 1 and Peer 2.
379
observer1_->CancelAnswerPeer();
380
observer2_->CancelAnswerPeer();
382
// Create an empty collection for Peer 1.
383
talk_base::scoped_refptr<StreamCollection> local_collection1(
384
StreamCollection::Create());
385
// Create a collection for Peer 2.
386
talk_base::scoped_refptr<StreamCollection> local_collection2(
387
CreateLocalCollection2());
389
// Peer 1 create an updated offer.
390
signaling1_->CreateOffer(local_collection1);
391
// Peer 2 create an updated offer.
392
signaling2_->CreateOffer(local_collection2);
394
std::string offer_1 = observer1_->last_message_;
395
std::string offer_2 = observer2_->last_message_;
396
EXPECT_EQ(RoapSignaling::kWaitingForAnswer, signaling1_->GetState());
397
EXPECT_EQ(RoapSignaling::kWaitingForAnswer, signaling2_->GetState());
399
// Connect all messages sent from Peer 1 to be received on Peer 2
400
observer1_->AnswerPeer(signaling2_.get(), local_collection2);
401
// Connect all messages sent from Peer 2 to be received on Peer 1
402
observer2_->AnswerPeer(signaling1_.get(), local_collection1);
404
// Insert the two offers to each Peer to create the Glare.
405
signaling1_->ProcessSignalingMessage(offer_2, local_collection1);
406
signaling2_->ProcessSignalingMessage(offer_1, local_collection2);
408
// Make sure all is good.
409
EXPECT_EQ(RoapSignaling::kIdle, signaling1_->GetState());
410
EXPECT_EQ(RoapSignaling::kIdle, signaling2_->GetState());
412
// Verify that Peer 1 is receiving kStreamLabel2.
413
EXPECT_TRUE(observer1_->RemoteStream(kStreamLabel2) != NULL);
414
// Verify that Peer 2 don't receive any streams
415
// since it has been removed.
416
EXPECT_TRUE(observer2_->RemoteStream(kStreamLabel1) == NULL);
418
// Verify that both peers have updated the session descriptions.
419
EXPECT_EQ(2u, provider1_->update_session_description_counter_);
420
EXPECT_EQ(2u, provider2_->update_session_description_counter_);
423
TEST_F(RoapSignalingTest, AddRemoveStream) {
424
// Create a local stream.
425
std::string label(kStreamLabel1);
426
talk_base::scoped_refptr<LocalMediaStreamInterface> stream(
427
MediaStream::Create(label));
429
// Add a local audio track.
430
talk_base::scoped_refptr<LocalAudioTrackInterface>
431
audio_track(AudioTrack::CreateLocal(kAudioTrackLabel1, NULL));
432
stream->AddTrack(audio_track);
434
// Add a local video track.
435
talk_base::scoped_refptr<LocalVideoTrackInterface>
436
video_track(VideoTrack::CreateLocal(kVideoTrackLabel1, NULL));
437
stream->AddTrack(video_track);
439
// Peer 1 create an empty collection
440
talk_base::scoped_refptr<StreamCollection> local_collection1(
441
StreamCollection::Create());
443
// Peer 2 create an empty collection
444
talk_base::scoped_refptr<StreamCollection> local_collection2(
445
StreamCollection::Create());
447
// Connect all messages sent from Peer1 to be received on Peer2
448
observer1_->AnswerPeer(signaling2_.get(), local_collection2);
449
// Connect all messages sent from Peer2 to be received on Peer1
450
observer2_->AnswerPeer(signaling1_.get(), local_collection1);
452
// Peer 1 creates an empty offer and send it to Peer2.
453
signaling1_->CreateOffer(local_collection1);
455
// Initialize signaling1_ and signaling_2 by providing the candidates.
456
signaling1_->OnIceComplete();
457
signaling2_->OnIceComplete();
459
// Verify that both peers have updated the session descriptions.
460
EXPECT_EQ(1u, provider1_->update_session_description_counter_);
461
EXPECT_EQ(1u, provider2_->update_session_description_counter_);
463
// Peer2 add a stream.
464
local_collection2->AddStream(stream);
466
signaling2_->CreateOffer(local_collection2);
468
// Verify that PeerConnection1 is aware of the sending stream.
469
EXPECT_TRUE(observer1_->RemoteStream(label) != NULL);
471
// Verify that both peers have updated the session descriptions.
472
EXPECT_EQ(2u, provider1_->update_session_description_counter_);
473
EXPECT_EQ(2u, provider2_->update_session_description_counter_);
476
local_collection2->RemoveStream(stream);
478
signaling2_->CreateOffer(local_collection2);
480
// Verify that PeerConnection1 is not aware of the sending stream.
481
EXPECT_TRUE(observer1_->RemoteStream(label) == NULL);
483
// Verify that both peers have updated the session descriptions.
484
EXPECT_EQ(3u, provider1_->update_session_description_counter_);
485
EXPECT_EQ(3u, provider2_->update_session_description_counter_);
488
TEST_F(RoapSignalingTest, ShutDown) {
492
signaling1_->SendShutDown();
494
EXPECT_EQ(RoapSignaling::kShutdownComplete,
495
signaling1_->GetState());
496
EXPECT_EQ(RoapSignaling::kShutdownComplete,
497
signaling2_->GetState());
499
EXPECT_EQ(0u, observer1_->remote_streams()->count());
500
EXPECT_EQ(0u, observer2_->remote_streams()->count());
501
EXPECT_EQ(RoapSignaling::kShutdownComplete, observer1_->state_);
502
EXPECT_EQ(RoapSignaling::kShutdownComplete, observer2_->state_);
504
// Verify that both peers have updated the session descriptions.
505
EXPECT_EQ(2u, provider1_->update_session_description_counter_);
506
EXPECT_EQ(2u, provider2_->update_session_description_counter_);
509
TEST_F(RoapSignalingTest, ReceiveError) {
510
talk_base::scoped_refptr<StreamCollection> local_collection1(
511
CreateLocalCollection1());
513
signaling1_->CreateOffer(local_collection1);
514
// Initialize signaling1_
515
signaling1_->OnIceComplete();
516
EXPECT_EQ(RoapSignaling::kWaitingForAnswer,
517
signaling1_->GetState());
519
RoapSession roap_session;
520
roap_session.Parse(observer1_->last_message_);
521
signaling1_->ProcessSignalingMessage(roap_session.CreateErrorMessage(
522
kNoMatch), local_collection1);
523
EXPECT_EQ(kNoMatch, observer1_->last_error_);
525
// Check signaling have cleaned up.
526
EXPECT_EQ(RoapSignaling::kIdle, signaling1_->GetState());
528
signaling1_->CreateOffer(local_collection1);
529
EXPECT_EQ(RoapSignaling::kWaitingForAnswer,
530
signaling1_->GetState());
533
} // namespace webrtc