3 * Copyright 2004 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/media/base/fakemediaengine.h"
29 #include "talk/media/base/fakenetworkinterface.h"
30 #include "talk/media/base/fakevideocapturer.h"
31 #include "talk/media/base/hybridvideoengine.h"
32 #include "talk/media/base/mediachannel.h"
33 #include "talk/media/base/testutils.h"
34 #include "webrtc/base/gunit.h"
36 static const cricket::VideoCodec kGenericCodec(97, "Generic", 640, 360, 30, 0);
37 static const cricket::VideoCodec kVp8Codec(100, "VP8", 640, 360, 30, 0);
38 static const cricket::VideoCodec kCodecsVp8Only[] = { kVp8Codec };
39 static const cricket::VideoCodec kCodecsGenericOnly[] = { kGenericCodec };
40 static const cricket::VideoCodec kCodecsVp8First[] = { kVp8Codec,
42 static const cricket::VideoCodec kCodecsGenericFirst[] = { kGenericCodec,
45 using cricket::StreamParams;
47 class FakeVp8VideoEngine : public cricket::FakeVideoEngine {
49 FakeVp8VideoEngine() {
50 SetCodecs(MAKE_VECTOR(kCodecsVp8Only));
53 class FakeGenericVideoEngine : public cricket::FakeVideoEngine {
55 FakeGenericVideoEngine() {
56 SetCodecs(MAKE_VECTOR(kCodecsGenericOnly));
59 // For testing purposes, mimic the behavior of a media engine that throws out
60 // resolutions that don't match the codec list. A width or height of 0
61 // trivially will never match the codec list, so this is sufficient for
62 // testing the case we want (0x0).
63 virtual bool FindCodec(const cricket::VideoCodec& codec) {
64 if (codec.width == 0 || codec.height == 0) {
67 return cricket::FakeVideoEngine::FindCodec(codec);
71 class HybridVideoEngineForTest : public cricket::HybridVideoEngine<
72 FakeVp8VideoEngine, FakeGenericVideoEngine> {
74 HybridVideoEngineForTest()
80 cricket::FakeVideoEngine* sub_engine1() { return &video1_; }
81 cricket::FakeVideoEngine* sub_engine2() { return &video2_; }
83 // From base class HybridVideoEngine.
84 void OnSendChange1(cricket::VideoMediaChannel* channel1, bool send) {
91 // From base class HybridVideoEngine
92 void OnNewSendResolution(int width, int height) {
94 send_height_ = height;
97 int num_ch1_send_on() const { return num_ch1_send_on_; }
98 int num_ch1_send_off() const { return num_ch1_send_off_; }
100 int send_width() const { return send_width_; }
101 int send_height() const { return send_height_; }
104 int num_ch1_send_on_;
105 int num_ch1_send_off_;
111 class HybridVideoEngineTest : public testing::Test {
113 HybridVideoEngineTest() : sub_channel1_(NULL), sub_channel2_(NULL) {
115 ~HybridVideoEngineTest() {
119 bool result = engine_.Init(rtc::Thread::Current());
121 channel_.reset(engine_.CreateChannel(NULL));
122 result = (channel_.get() != NULL);
123 sub_channel1_ = engine_.sub_engine1()->GetChannel(0);
124 sub_channel2_ = engine_.sub_engine2()->GetChannel(0);
128 bool SetupRenderAndAddStream(const StreamParams& sp) {
131 channel_->SetInterface(transport_.get());
132 return channel_->SetRecvCodecs(engine_.codecs()) &&
133 channel_->AddSendStream(sp) &&
134 channel_->SetRender(true);
136 void DeliverPacket(const void* data, int len) {
137 rtc::Buffer packet(data, len);
138 channel_->OnPacketReceived(&packet, rtc::CreatePacketTime(0));
140 void DeliverRtcp(const void* data, int len) {
141 rtc::Buffer packet(data, len);
142 channel_->OnRtcpReceived(&packet, rtc::CreatePacketTime(0));
146 void TestSetSendCodecs(cricket::FakeVideoEngine* sub_engine,
147 const std::vector<cricket::VideoCodec>& codecs) {
148 EXPECT_TRUE(SetupRenderAndAddStream(StreamParams::CreateLegacy(1234)));
149 EXPECT_TRUE(channel_->SetSendCodecs(codecs));
150 cricket::FakeVideoMediaChannel* sub_channel = sub_engine->GetChannel(0);
151 ASSERT_EQ(1U, sub_channel->send_codecs().size());
152 EXPECT_EQ(codecs[0], sub_channel->send_codecs()[0]);
153 EXPECT_TRUE(channel_->SetSend(true));
154 EXPECT_TRUE(sub_channel->sending());
156 void TestSetSendBandwidth(cricket::FakeVideoEngine* sub_engine,
157 const std::vector<cricket::VideoCodec>& codecs,
160 EXPECT_TRUE(SetupRenderAndAddStream(StreamParams::CreateLegacy(1234)));
161 EXPECT_TRUE(channel_->SetSendCodecs(codecs));
162 EXPECT_TRUE(channel_->SetStartSendBandwidth(start_bitrate));
163 EXPECT_TRUE(channel_->SetMaxSendBandwidth(max_bitrate));
164 cricket::FakeVideoMediaChannel* sub_channel = sub_engine->GetChannel(0);
165 EXPECT_EQ(start_bitrate, sub_channel->start_bps());
166 EXPECT_EQ(max_bitrate, sub_channel->max_bps());
168 HybridVideoEngineForTest engine_;
169 rtc::scoped_ptr<cricket::HybridVideoMediaChannel> channel_;
170 rtc::scoped_ptr<cricket::FakeNetworkInterface> transport_;
171 cricket::FakeVideoMediaChannel* sub_channel1_;
172 cricket::FakeVideoMediaChannel* sub_channel2_;
175 TEST_F(HybridVideoEngineTest, StartupShutdown) {
176 EXPECT_TRUE(engine_.Init(rtc::Thread::Current()));
180 // Tests that SetDefaultVideoEncoderConfig passes down to both engines.
181 TEST_F(HybridVideoEngineTest, SetDefaultVideoEncoderConfig) {
182 cricket::VideoEncoderConfig config(
183 cricket::VideoCodec(105, "", 640, 400, 30, 0), 1, 2);
184 EXPECT_TRUE(engine_.SetDefaultEncoderConfig(config));
186 cricket::VideoEncoderConfig config_1 = config;
187 config_1.max_codec.name = kCodecsVp8Only[0].name;
188 EXPECT_EQ(config_1, engine_.sub_engine1()->default_encoder_config());
190 cricket::VideoEncoderConfig config_2 = config;
191 config_2.max_codec.name = kCodecsGenericOnly[0].name;
192 EXPECT_EQ(config_2, engine_.sub_engine2()->default_encoder_config());
195 // Tests that GetDefaultVideoEncoderConfig picks a meaningful encoder config
196 // based on the underlying engine config and then after a call to
197 // SetDefaultEncoderConfig on the hybrid engine.
198 TEST_F(HybridVideoEngineTest, SetDefaultVideoEncoderConfigDefaultValue) {
199 cricket::VideoEncoderConfig blank_config;
200 cricket::VideoEncoderConfig meaningful_config1(
201 cricket::VideoCodec(111, "abcd", 320, 240, 30, 0), 1, 2);
202 cricket::VideoEncoderConfig meaningful_config2(
203 cricket::VideoCodec(111, "abcd", 1280, 720, 30, 0), 1, 2);
204 cricket::VideoEncoderConfig meaningful_config3(
205 cricket::VideoCodec(111, "abcd", 640, 360, 30, 0), 1, 2);
206 engine_.sub_engine1()->SetDefaultEncoderConfig(blank_config);
207 engine_.sub_engine2()->SetDefaultEncoderConfig(blank_config);
208 EXPECT_EQ(blank_config, engine_.GetDefaultEncoderConfig());
210 engine_.sub_engine2()->SetDefaultEncoderConfig(meaningful_config2);
211 EXPECT_EQ(meaningful_config2, engine_.GetDefaultEncoderConfig());
213 engine_.sub_engine1()->SetDefaultEncoderConfig(meaningful_config1);
214 EXPECT_EQ(meaningful_config1, engine_.GetDefaultEncoderConfig());
216 EXPECT_TRUE(engine_.SetDefaultEncoderConfig(meaningful_config3));
217 // The overall config should now match, though the codec name will have been
218 // rewritten for the first media engine.
219 meaningful_config3.max_codec.name = kCodecsVp8Only[0].name;
220 EXPECT_EQ(meaningful_config3, engine_.GetDefaultEncoderConfig());
223 // Tests that our engine has the right codecs in the right order.
224 TEST_F(HybridVideoEngineTest, CheckCodecs) {
225 const std::vector<cricket::VideoCodec>& c = engine_.codecs();
226 ASSERT_EQ(2U, c.size());
227 EXPECT_EQ(kVp8Codec, c[0]);
228 EXPECT_EQ(kGenericCodec, c[1]);
231 // Tests that our engine has the right caps.
232 TEST_F(HybridVideoEngineTest, CheckCaps) {
233 EXPECT_EQ(cricket::VIDEO_SEND | cricket::VIDEO_RECV,
234 engine_.GetCapabilities());
237 // Tests that we can create and destroy a channel.
238 TEST_F(HybridVideoEngineTest, CreateChannel) {
239 EXPECT_TRUE(SetupEngine());
240 EXPECT_TRUE(sub_channel1_ != NULL);
241 EXPECT_TRUE(sub_channel2_ != NULL);
244 // Tests that we properly handle failures in CreateChannel.
245 TEST_F(HybridVideoEngineTest, CreateChannelFail) {
246 engine_.sub_engine1()->set_fail_create_channel(true);
247 EXPECT_FALSE(SetupEngine());
248 EXPECT_TRUE(channel_.get() == NULL);
249 EXPECT_TRUE(sub_channel1_ == NULL);
250 EXPECT_TRUE(sub_channel2_ == NULL);
251 engine_.sub_engine1()->set_fail_create_channel(false);
252 engine_.sub_engine2()->set_fail_create_channel(true);
253 EXPECT_FALSE(SetupEngine());
254 EXPECT_TRUE(channel_.get() == NULL);
255 EXPECT_TRUE(sub_channel1_ == NULL);
256 EXPECT_TRUE(sub_channel2_ == NULL);
259 // Test that we set our inbound codecs and settings properly.
260 TEST_F(HybridVideoEngineTest, SetLocalDescription) {
261 EXPECT_TRUE(SetupEngine());
262 channel_->SetInterface(transport_.get());
263 EXPECT_TRUE(channel_->SetRecvCodecs(engine_.codecs()));
264 ASSERT_EQ(1U, sub_channel1_->recv_codecs().size());
265 ASSERT_EQ(1U, sub_channel2_->recv_codecs().size());
266 EXPECT_EQ(kVp8Codec, sub_channel1_->recv_codecs()[0]);
267 EXPECT_EQ(kGenericCodec, sub_channel2_->recv_codecs()[0]);
269 stream.id = "TestStream";
270 stream.ssrcs.push_back(1234);
271 stream.cname = "5678";
272 EXPECT_TRUE(channel_->AddSendStream(stream));
273 EXPECT_EQ(1234U, sub_channel1_->send_ssrc());
274 EXPECT_EQ(1234U, sub_channel2_->send_ssrc());
275 EXPECT_EQ("5678", sub_channel1_->rtcp_cname());
276 EXPECT_EQ("5678", sub_channel2_->rtcp_cname());
277 EXPECT_TRUE(channel_->SetRender(true));
278 // We've called SetRender, so we should be playing out, but not yet sending.
279 EXPECT_TRUE(sub_channel1_->playout());
280 EXPECT_TRUE(sub_channel2_->playout());
281 EXPECT_FALSE(sub_channel1_->sending());
282 EXPECT_FALSE(sub_channel2_->sending());
283 // We may get SetSend(false) calls during call setup.
284 // Since this causes no change in state, they should no-op and return true.
285 EXPECT_TRUE(channel_->SetSend(false));
286 EXPECT_FALSE(sub_channel1_->sending());
287 EXPECT_FALSE(sub_channel2_->sending());
290 TEST_F(HybridVideoEngineTest, OnNewSendResolution) {
291 EXPECT_TRUE(SetupEngine());
292 EXPECT_TRUE(channel_->SetSendCodecs(MAKE_VECTOR(kCodecsVp8First)));
293 EXPECT_EQ(640, engine_.send_width());
294 EXPECT_EQ(360, engine_.send_height());
297 // Test that we converge to the active channel for engine 1.
298 TEST_F(HybridVideoEngineTest, SetSendCodecs1) {
299 // This will nuke the object that sub_channel2_ points to.
300 TestSetSendCodecs(engine_.sub_engine1(), MAKE_VECTOR(kCodecsVp8First));
301 EXPECT_TRUE(engine_.sub_engine2()->GetChannel(0) == NULL);
304 // Test that we converge to the active channel for engine 2.
305 TEST_F(HybridVideoEngineTest, SetSendCodecs2) {
306 // This will nuke the object that sub_channel1_ points to.
307 TestSetSendCodecs(engine_.sub_engine2(), MAKE_VECTOR(kCodecsGenericFirst));
308 EXPECT_TRUE(engine_.sub_engine1()->GetChannel(0) == NULL);
311 // Test that we don't accidentally eat 0x0 in SetSendCodecs
312 TEST_F(HybridVideoEngineTest, SetSendCodecs0x0) {
313 EXPECT_TRUE(SetupRenderAndAddStream(StreamParams::CreateLegacy(1234)));
314 // Send using generic codec, but with 0x0 resolution.
315 std::vector<cricket::VideoCodec> codecs(MAKE_VECTOR(kCodecsGenericFirst));
318 codecs[0].height = 0;
319 EXPECT_TRUE(channel_->SetSendCodecs(codecs));
322 // Test setting the send bandwidth for VP8.
323 TEST_F(HybridVideoEngineTest, SetSendBandwidth1) {
324 TestSetSendBandwidth(engine_.sub_engine1(),
325 MAKE_VECTOR(kCodecsVp8First),
330 // Test setting the send bandwidth for a generic codec.
331 TEST_F(HybridVideoEngineTest, SetSendBandwidth2) {
332 TestSetSendBandwidth(engine_.sub_engine2(),
333 MAKE_VECTOR(kCodecsGenericFirst),
338 // Test that we dump RTP packets that arrive early.
339 TEST_F(HybridVideoEngineTest, HandleEarlyRtp) {
340 static const uint8 kPacket[1024] = { 0 };
341 static const uint8 kRtcp[1024] = { 1 };
342 EXPECT_TRUE(SetupRenderAndAddStream(StreamParams::CreateLegacy(1234)));
343 DeliverPacket(kPacket, sizeof(kPacket));
344 DeliverRtcp(kRtcp, sizeof(kRtcp));
345 EXPECT_TRUE(sub_channel1_->CheckNoRtp());
346 EXPECT_TRUE(sub_channel2_->CheckNoRtp());
347 EXPECT_TRUE(sub_channel1_->CheckNoRtcp());
348 EXPECT_TRUE(sub_channel2_->CheckNoRtcp());
351 // Test that we properly pass on normal RTP packets.
352 TEST_F(HybridVideoEngineTest, HandleRtp) {
353 static const uint8 kPacket[1024] = { 0 };
354 static const uint8 kRtcp[1024] = { 1 };
355 EXPECT_TRUE(SetupRenderAndAddStream(StreamParams::CreateLegacy(1234)));
356 EXPECT_TRUE(channel_->SetSendCodecs(MAKE_VECTOR(kCodecsVp8First)));
357 EXPECT_TRUE(channel_->SetSend(true));
358 DeliverPacket(kPacket, sizeof(kPacket));
359 DeliverRtcp(kRtcp, sizeof(kRtcp));
360 EXPECT_TRUE(sub_channel1_->CheckRtp(kPacket, sizeof(kPacket)));
361 EXPECT_TRUE(sub_channel1_->CheckRtcp(kRtcp, sizeof(kRtcp)));
364 // Test that we properly connect media error signal.
365 TEST_F(HybridVideoEngineTest, MediaErrorSignal) {
366 cricket::VideoMediaErrorCatcher catcher;
368 // Verify no signal from either channel before the active channel is set.
369 EXPECT_TRUE(SetupEngine());
370 channel_->SignalMediaError.connect(&catcher,
371 &cricket::VideoMediaErrorCatcher::OnError);
372 sub_channel1_->SignalMediaError(1, cricket::VideoMediaChannel::ERROR_OTHER);
373 EXPECT_EQ(0U, catcher.ssrc());
374 sub_channel2_->SignalMediaError(2,
375 cricket::VideoMediaChannel::ERROR_REC_DEVICE_OPEN_FAILED);
376 EXPECT_EQ(0U, catcher.ssrc());
378 // Set vp8 as active channel and verify that a signal comes from it.
379 EXPECT_TRUE(channel_->SetSendCodecs(MAKE_VECTOR(kCodecsVp8First)));
380 sub_channel1_->SignalMediaError(1, cricket::VideoMediaChannel::ERROR_OTHER);
381 EXPECT_EQ(cricket::VideoMediaChannel::ERROR_OTHER, catcher.error());
382 EXPECT_EQ(1U, catcher.ssrc());
384 // Set generic codec as active channel and verify that a signal comes from it.
385 EXPECT_TRUE(SetupEngine());
386 channel_->SignalMediaError.connect(&catcher,
387 &cricket::VideoMediaErrorCatcher::OnError);
388 EXPECT_TRUE(channel_->SetSendCodecs(MAKE_VECTOR(kCodecsGenericFirst)));
389 sub_channel2_->SignalMediaError(2,
390 cricket::VideoMediaChannel::ERROR_REC_DEVICE_OPEN_FAILED);
391 EXPECT_EQ(cricket::VideoMediaChannel::ERROR_REC_DEVICE_OPEN_FAILED,
393 EXPECT_EQ(2U, catcher.ssrc());
396 // Test that SetSend doesn't re-enter.
397 TEST_F(HybridVideoEngineTest, RepeatSetSend) {
398 EXPECT_TRUE(SetupEngine());
399 EXPECT_TRUE(channel_->SetSendCodecs(MAKE_VECTOR(kCodecsVp8First)));
401 // Verify initial status.
402 EXPECT_FALSE(channel_->sending());
403 EXPECT_FALSE(sub_channel1_->sending());
404 EXPECT_EQ(0, engine_.num_ch1_send_on());
405 EXPECT_EQ(0, engine_.num_ch1_send_off());
407 // Verfiy SetSend(true) works correctly.
408 EXPECT_TRUE(channel_->SetSend(true));
409 EXPECT_TRUE(channel_->sending());
410 EXPECT_TRUE(sub_channel1_->sending());
411 EXPECT_EQ(1, engine_.num_ch1_send_on());
412 EXPECT_EQ(0, engine_.num_ch1_send_off());
414 // SetSend(true) again and verify nothing changes.
415 EXPECT_TRUE(channel_->SetSend(true));
416 EXPECT_TRUE(channel_->sending());
417 EXPECT_TRUE(sub_channel1_->sending());
418 EXPECT_EQ(1, engine_.num_ch1_send_on());
419 EXPECT_EQ(0, engine_.num_ch1_send_off());
421 // Verify SetSend(false) works correctly.
422 EXPECT_TRUE(channel_->SetSend(false));
423 EXPECT_FALSE(channel_->sending());
424 EXPECT_FALSE(sub_channel1_->sending());
425 EXPECT_EQ(1, engine_.num_ch1_send_on());
426 EXPECT_EQ(1, engine_.num_ch1_send_off());
428 // SetSend(false) again and verfiy nothing changes.
429 EXPECT_TRUE(channel_->SetSend(false));
430 EXPECT_FALSE(channel_->sending());
431 EXPECT_FALSE(sub_channel1_->sending());
432 EXPECT_EQ(1, engine_.num_ch1_send_on());
433 EXPECT_EQ(1, engine_.num_ch1_send_off());
436 // Test that SetOptions.
437 TEST_F(HybridVideoEngineTest, SetOptions) {
438 cricket::VideoOptions vmo;
439 vmo.video_high_bitrate.Set(true);
440 vmo.system_low_adaptation_threshhold.Set(0.10f);
441 EXPECT_TRUE(SetupEngine());
442 EXPECT_TRUE(channel_->SetOptions(vmo));
446 EXPECT_TRUE(sub_channel1_->GetOptions(&vmo));
447 EXPECT_TRUE(vmo.video_high_bitrate.Get(&high_bitrate));
448 EXPECT_TRUE(high_bitrate);
449 EXPECT_TRUE(vmo.system_low_adaptation_threshhold.Get(&low));
450 EXPECT_EQ(0.10f, low);
451 EXPECT_TRUE(sub_channel2_->GetOptions(&vmo));
452 EXPECT_TRUE(vmo.video_high_bitrate.Get(&high_bitrate));
453 EXPECT_TRUE(high_bitrate);
454 EXPECT_TRUE(vmo.system_low_adaptation_threshhold.Get(&low));
455 EXPECT_EQ(0.10f, low);
457 vmo.video_high_bitrate.Set(false);
458 vmo.system_low_adaptation_threshhold.Set(0.50f);
460 EXPECT_TRUE(channel_->SetOptions(vmo));
461 EXPECT_TRUE(sub_channel1_->GetOptions(&vmo));
462 EXPECT_TRUE(vmo.video_high_bitrate.Get(&high_bitrate));
463 EXPECT_FALSE(high_bitrate);
464 EXPECT_TRUE(vmo.system_low_adaptation_threshhold.Get(&low));
465 EXPECT_EQ(0.50f, low);
466 EXPECT_TRUE(sub_channel2_->GetOptions(&vmo));
467 EXPECT_TRUE(vmo.video_high_bitrate.Get(&high_bitrate));
468 EXPECT_FALSE(high_bitrate);
469 EXPECT_TRUE(vmo.system_low_adaptation_threshhold.Get(&low));
470 EXPECT_EQ(0.50f, low);
473 TEST_F(HybridVideoEngineTest, SetCapturer) {
474 EXPECT_TRUE(SetupEngine());
475 // Set vp8 as active channel and verify that capturer can be set.
476 EXPECT_TRUE(channel_->SetSendCodecs(MAKE_VECTOR(kCodecsVp8First)));
477 cricket::FakeVideoCapturer fake_video_capturer;
478 EXPECT_TRUE(channel_->SetCapturer(0, &fake_video_capturer));
479 EXPECT_TRUE(channel_->SetCapturer(0, NULL));
481 // Set generic codec active channel and verify that capturer can be set.
482 EXPECT_TRUE(SetupEngine());
483 EXPECT_TRUE(channel_->SetSendCodecs(MAKE_VECTOR(kCodecsGenericFirst)));
484 EXPECT_TRUE(channel_->SetCapturer(0, &fake_video_capturer));
485 EXPECT_TRUE(channel_->SetCapturer(0, NULL));