blob: dcef4ac6c41b36ddbaeafbc180a36eec4abec348 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001// libjingle
2// Copyright 2004 Google Inc. All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are met:
6//
7// 1. Redistributions of source code must retain the above copyright notice,
8// this list of conditions and the following disclaimer.
9// 2. Redistributions in binary form must reproduce the above copyright notice,
10// this list of conditions and the following disclaimer in the documentation
11// and/or other materials provided with the distribution.
12// 3. The name of the author may not be used to endorse or promote products
13// derived from this software without specific prior written permission.
14//
15// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26#ifndef TALK_MEDIA_BASE_VIDEOENGINE_UNITTEST_H_
27#define TALK_MEDIA_BASE_VIDEOENGINE_UNITTEST_H_
28
29#include <string>
30#include <vector>
31
32#include "talk/base/bytebuffer.h"
33#include "talk/base/gunit.h"
34#include "talk/base/timeutils.h"
35#include "talk/media/base/fakenetworkinterface.h"
36#include "talk/media/base/fakevideocapturer.h"
37#include "talk/media/base/fakevideorenderer.h"
38#include "talk/media/base/mediachannel.h"
39#include "talk/media/base/streamparams.h"
40
41#ifdef WIN32
42#include <objbase.h> // NOLINT
43#endif
44
45#define EXPECT_FRAME_WAIT(c, w, h, t) \
46 EXPECT_EQ_WAIT((c), renderer_.num_rendered_frames(), (t)); \
47 EXPECT_EQ((w), renderer_.width()); \
48 EXPECT_EQ((h), renderer_.height()); \
49 EXPECT_EQ(0, renderer_.errors()); \
50
51#define EXPECT_FRAME_ON_RENDERER_WAIT(r, c, w, h, t) \
52 EXPECT_EQ_WAIT((c), (r).num_rendered_frames(), (t)); \
53 EXPECT_EQ((w), (r).width()); \
54 EXPECT_EQ((h), (r).height()); \
55 EXPECT_EQ(0, (r).errors()); \
56
57static const uint32 kTimeout = 5000U;
58static const uint32 kSsrc = 1234u;
59static const uint32 kRtxSsrc = 4321u;
60static const uint32 kSsrcs4[] = {1, 2, 3, 4};
61
62inline bool IsEqualRes(const cricket::VideoCodec& a, int w, int h, int fps) {
63 return a.width == w && a.height == h && a.framerate == fps;
64}
65
66inline bool IsEqualCodec(const cricket::VideoCodec& a,
67 const cricket::VideoCodec& b) {
68 return a.id == b.id && a.name == b.name &&
69 IsEqualRes(a, b.width, b.height, b.framerate);
70}
71
72inline std::ostream& operator<<(std::ostream& s, const cricket::VideoCodec& c) {
73 s << "{" << c.name << "(" << c.id << "), "
74 << c.width << "x" << c.height << "x" << c.framerate << "}";
75 return s;
76}
77
78inline int TimeBetweenSend(const cricket::VideoCodec& codec) {
79 return static_cast<int> (
80 cricket::VideoFormat::FpsToInterval(codec.framerate) /
81 talk_base::kNumNanosecsPerMillisec);
82}
83
84// Fake video engine that makes it possible to test enabling and disabling
85// capturer (checking that the engine state is updated and that the capturer
86// is indeed capturing) without having to create a channel. It also makes it
87// possible to test that the media processors are indeed being called when
88// registered.
89template<class T>
90class VideoEngineOverride : public T {
91 public:
92 VideoEngineOverride() {
93 }
94 virtual ~VideoEngineOverride() {
95 }
96 bool is_camera_on() const { return T::GetVideoCapturer()->IsRunning(); }
97 void set_has_senders(bool has_senders) {
98 if (has_senders) {
99 this->RegisterSender(this,
100 &VideoEngineOverride<T>::OnLocalFrame,
101 &VideoEngineOverride<T>::OnLocalFrameFormat);
102 } else {
103 this->UnregisterSender(this);
104 }
105 }
106 void OnLocalFrame(cricket::VideoCapturer*,
107 const cricket::VideoFrame*) {
108 }
109 void OnLocalFrameFormat(cricket::VideoCapturer*,
110 const cricket::VideoFormat*) {
111 }
112
113 void TriggerMediaFrame(
114 uint32 ssrc, cricket::VideoFrame* frame, bool* drop_frame) {
115 T::SignalMediaFrame(ssrc, frame, drop_frame);
116 }
117};
118
119// Macroes that declare test functions for a given test class, before and after
120// Init().
121// To use, define a test function called FooBody and pass Foo to the macro.
122#define TEST_PRE_VIDEOENGINE_INIT(TestClass, func) \
123 TEST_F(TestClass, func##PreInit) { \
124 func##Body(); \
125 }
126#define TEST_POST_VIDEOENGINE_INIT(TestClass, func) \
127 TEST_F(TestClass, func##PostInit) { \
128 EXPECT_TRUE(engine_.Init(talk_base::Thread::Current())); \
129 func##Body(); \
130 engine_.Terminate(); \
131 }
132
133template<class E>
134class VideoEngineTest : public testing::Test {
135 protected:
136 // Tests starting and stopping the engine, and creating a channel.
137 void StartupShutdown() {
138 EXPECT_TRUE(engine_.Init(talk_base::Thread::Current()));
139 cricket::VideoMediaChannel* channel = engine_.CreateChannel(NULL);
140 EXPECT_TRUE(channel != NULL);
141 delete channel;
142 engine_.Terminate();
143 }
144
145#ifdef WIN32
146 // Tests that the COM reference count is not munged by the engine.
147 // Test to make sure LMI does not munge the CoInitialize reference count.
148 void CheckCoInitialize() {
149 // Initial refcount should be 0.
150 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED));
151
152 // Engine should start even with COM already inited.
153 EXPECT_TRUE(engine_.Init(talk_base::Thread::Current()));
154 engine_.Terminate();
155 // Refcount after terminate should be 1; this tests if it is nonzero.
156 EXPECT_EQ(S_FALSE, CoInitializeEx(NULL, COINIT_MULTITHREADED));
157 // Decrement refcount to (hopefully) 0.
158 CoUninitialize();
159 CoUninitialize();
160
161 // Ensure refcount is 0.
162 EXPECT_EQ(S_OK, CoInitializeEx(NULL, COINIT_MULTITHREADED));
163 CoUninitialize();
164 }
165#endif
166
167 // Tests starting and stopping the capturer.
168 void SetCapture() {
169 EXPECT_FALSE(engine_.GetVideoCapturer());
170 EXPECT_TRUE(engine_.Init(talk_base::Thread::Current()));
171 ResetCapturer();
172 EXPECT_TRUE(engine_.GetVideoCapturer() != NULL);
173 EXPECT_FALSE(engine_.is_camera_on());
174 EXPECT_TRUE(engine_.SetCapture(true));
175 EXPECT_TRUE(engine_.is_camera_on());
176 EXPECT_TRUE(engine_.SetCapture(false));
177 EXPECT_FALSE(engine_.is_camera_on());
178 engine_.set_has_senders(true);
179 EXPECT_TRUE(engine_.is_camera_on());
180 EXPECT_TRUE(engine_.SetCapture(true));
181 EXPECT_TRUE(engine_.is_camera_on());
182 EXPECT_TRUE(engine_.SetCapture(false));
183 EXPECT_TRUE(engine_.is_camera_on());
184 engine_.set_has_senders(false);
185 EXPECT_FALSE(engine_.is_camera_on());
186 EXPECT_TRUE(engine_.SetCapture(true));
187 EXPECT_TRUE(engine_.is_camera_on());
188 EXPECT_TRUE(engine_.SetCapture(false));
189 EXPECT_FALSE(engine_.is_camera_on());
190 EXPECT_TRUE(engine_.SetVideoCapturer(NULL));
191 EXPECT_TRUE(engine_.GetVideoCapturer() == NULL);
192 engine_.Terminate();
193 }
194 void ResetCapturer() {
195 cricket::Device device("test", "device");
196 video_capturer_.reset(new cricket::FakeVideoCapturer);
197 EXPECT_TRUE(engine_.SetVideoCapturer(video_capturer_.get()));
198 }
199
200 void ConstrainNewCodecBody() {
201 cricket::VideoCodec empty, in, out;
202 cricket::VideoCodec max_settings(engine_.codecs()[0].id,
203 engine_.codecs()[0].name,
204 1280, 800, 30, 0);
205
206 // set max settings of 1280x960x30
207 EXPECT_TRUE(engine_.SetDefaultEncoderConfig(
208 cricket::VideoEncoderConfig(max_settings)));
209
210 // don't constrain the max resolution
211 in = max_settings;
212 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
213 EXPECT_PRED2(IsEqualCodec, out, in);
214
215 // constrain resolution greater than the max and wider aspect,
216 // picking best aspect (16:10)
217 in.width = 1380;
218 in.height = 800;
219 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
220 EXPECT_PRED4(IsEqualRes, out, 1280, 720, 30);
221
222 // constrain resolution greater than the max and narrow aspect,
223 // picking best aspect (16:9)
224 in.width = 1280;
225 in.height = 740;
226 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
227 EXPECT_PRED4(IsEqualRes, out, 1280, 720, 30);
228
229 // constrain resolution greater than the max, picking equal aspect (4:3)
230 in.width = 1280;
231 in.height = 960;
232 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
233 EXPECT_PRED4(IsEqualRes, out, 1280, 800, 30);
234
235 // constrain resolution greater than the max, picking equal aspect (16:10)
236 in.width = 1280;
237 in.height = 800;
238 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
239 EXPECT_PRED4(IsEqualRes, out, 1280, 800, 30);
240
241 // reduce max settings to 640x480x30
242 max_settings.width = 640;
243 max_settings.height = 480;
244 EXPECT_TRUE(engine_.SetDefaultEncoderConfig(
245 cricket::VideoEncoderConfig(max_settings)));
246
247 // don't constrain the max resolution
248 in = max_settings;
249 in.width = 640;
250 in.height = 480;
251 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
252 EXPECT_PRED2(IsEqualCodec, out, in);
253
254 // keep 16:10 if they request it
255 in.height = 400;
256 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
257 EXPECT_PRED2(IsEqualCodec, out, in);
258
259 // don't constrain lesser 4:3 resolutions
260 in.width = 320;
261 in.height = 240;
262 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
263 EXPECT_PRED2(IsEqualCodec, out, in);
264
265 // don't constrain lesser 16:10 resolutions
266 in.width = 320;
267 in.height = 200;
268 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
269 EXPECT_PRED2(IsEqualCodec, out, in);
270
271 // requested resolution of 0x0 succeeds
272 in.width = 0;
273 in.height = 0;
274 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
275 EXPECT_PRED2(IsEqualCodec, out, in);
276
277 // constrain resolution lesser than the max and wider aspect,
278 // picking best aspect (16:9)
279 in.width = 350;
280 in.height = 201;
281 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
282 EXPECT_PRED4(IsEqualRes, out, 320, 180, 30);
283
284 // constrain resolution greater than the max and narrow aspect,
285 // picking best aspect (4:3)
286 in.width = 350;
287 in.height = 300;
288 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
289 EXPECT_PRED4(IsEqualRes, out, 320, 240, 30);
290
291 // constrain resolution greater than the max and wider aspect,
292 // picking best aspect (16:9)
293 in.width = 1380;
294 in.height = 800;
295 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
296 EXPECT_PRED4(IsEqualRes, out, 640, 360, 30);
297
298 // constrain resolution greater than the max and narrow aspect,
299 // picking best aspect (4:3)
300 in.width = 1280;
301 in.height = 900;
302 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
303 EXPECT_PRED4(IsEqualRes, out, 640, 480, 30);
304
305 // constrain resolution greater than the max, picking equal aspect (4:3)
306 in.width = 1280;
307 in.height = 960;
308 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
309 EXPECT_PRED4(IsEqualRes, out, 640, 480, 30);
310
311 // constrain resolution greater than the max, picking equal aspect (16:10)
312 in.width = 1280;
313 in.height = 800;
314 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
315 EXPECT_PRED4(IsEqualRes, out, 640, 400, 30);
316
317 // constrain res & fps greater than the max
318 in.framerate = 50;
319 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
320 EXPECT_PRED4(IsEqualRes, out, 640, 400, 30);
321
322 // reduce max settings to 160x100x10
323 max_settings.width = 160;
324 max_settings.height = 100;
325 max_settings.framerate = 10;
326 EXPECT_TRUE(engine_.SetDefaultEncoderConfig(
327 cricket::VideoEncoderConfig(max_settings)));
328
329 // constrain res & fps to new max
330 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
331 EXPECT_PRED4(IsEqualRes, out, 160, 100, 10);
332
333 // allow 4:3 "comparable" resolutions
334 in.width = 160;
335 in.height = 120;
336 in.framerate = 10;
337 EXPECT_TRUE(engine_.CanSendCodec(in, empty, &out));
338 EXPECT_PRED4(IsEqualRes, out, 160, 120, 10);
339 }
340
341 void ConstrainRunningCodecBody() {
342 cricket::VideoCodec in, out, current;
343 cricket::VideoCodec max_settings(engine_.codecs()[0].id,
344 engine_.codecs()[0].name,
345 1280, 800, 30, 0);
346
347 // set max settings of 1280x960x30
348 EXPECT_TRUE(engine_.SetDefaultEncoderConfig(
349 cricket::VideoEncoderConfig(max_settings)));
350
351 // establish current call at 1280x800x30 (16:10)
352 current = max_settings;
353 current.height = 800;
354
355 // Don't constrain current resolution
356 in = current;
357 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
358 EXPECT_PRED2(IsEqualCodec, out, in);
359
360 // requested resolution of 0x0 succeeds
361 in.width = 0;
362 in.height = 0;
363 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
364 EXPECT_PRED2(IsEqualCodec, out, in);
365
366 // Reduce an intermediate resolution down to the next lowest one, preserving
367 // aspect ratio.
368 in.width = 800;
369 in.height = 600;
370 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
371 EXPECT_PRED4(IsEqualRes, out, 640, 400, 30);
372
373 // Clamping by aspect ratio, but still never return a dimension higher than
374 // requested.
375 in.width = 1280;
376 in.height = 720;
377 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
378 EXPECT_PRED4(IsEqualRes, out, 1280, 720, 30);
379
380 in.width = 1279;
381 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
382 EXPECT_PRED4(IsEqualRes, out, 960, 600, 30);
383
384 in.width = 1281;
385 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
386 EXPECT_PRED4(IsEqualRes, out, 1280, 720, 30);
387
388 // Clamp large resolutions down, always preserving aspect
389 in.width = 1920;
390 in.height = 1080;
391 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
392 EXPECT_PRED4(IsEqualRes, out, 1280, 800, 30);
393
394 in.width = 1921;
395 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
396 EXPECT_PRED4(IsEqualRes, out, 1280, 800, 30);
397
398 in.width = 1919;
399 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
400 EXPECT_PRED4(IsEqualRes, out, 1280, 800, 30);
401
402 // reduce max settings to 640x480x30
403 max_settings.width = 640;
404 max_settings.height = 480;
405 EXPECT_TRUE(engine_.SetDefaultEncoderConfig(
406 cricket::VideoEncoderConfig(max_settings)));
407
408 // establish current call at 640x400x30 (16:10)
409 current = max_settings;
410 current.height = 400;
411
412 // Don't constrain current resolution
413 in = current;
414 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
415 EXPECT_PRED2(IsEqualCodec, out, in);
416
417 // requested resolution of 0x0 succeeds
418 in.width = 0;
419 in.height = 0;
420 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
421 EXPECT_PRED2(IsEqualCodec, out, in);
422
423 // Reduce an intermediate resolution down to the next lowest one, preserving
424 // aspect ratio.
425 in.width = 400;
426 in.height = 300;
427 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
428 EXPECT_PRED4(IsEqualRes, out, 320, 200, 30);
429
430 // Clamping by aspect ratio, but still never return a dimension higher than
431 // requested.
432 in.width = 640;
433 in.height = 360;
434 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
435 EXPECT_PRED4(IsEqualRes, out, 640, 360, 30);
436
437 in.width = 639;
438 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
439 EXPECT_PRED4(IsEqualRes, out, 480, 300, 30);
440
441 in.width = 641;
442 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
443 EXPECT_PRED4(IsEqualRes, out, 640, 360, 30);
444
445 // Clamp large resolutions down, always preserving aspect
446 in.width = 1280;
447 in.height = 800;
448 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
449 EXPECT_PRED4(IsEqualRes, out, 640, 400, 30);
450
451 in.width = 1281;
452 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
453 EXPECT_PRED4(IsEqualRes, out, 640, 400, 30);
454
455 in.width = 1279;
456 EXPECT_TRUE(engine_.CanSendCodec(in, current, &out));
457 EXPECT_PRED4(IsEqualRes, out, 640, 400, 30);
458
459 // Should fail for any that are smaller than our supported formats
460 in.width = 80;
461 in.height = 80;
462 EXPECT_FALSE(engine_.CanSendCodec(in, current, &out));
463
464 in.height = 50;
465 EXPECT_FALSE(engine_.CanSendCodec(in, current, &out));
466 }
467
468 VideoEngineOverride<E> engine_;
469 talk_base::scoped_ptr<cricket::FakeVideoCapturer> video_capturer_;
470};
471
472template<class E, class C>
473class VideoMediaChannelTest : public testing::Test,
474 public sigslot::has_slots<> {
475 protected:
476 virtual cricket::VideoCodec DefaultCodec() = 0;
477
478 virtual cricket::StreamParams DefaultSendStreamParams() {
479 return cricket::StreamParams::CreateLegacy(kSsrc);
480 }
481
482 virtual void SetUp() {
483 cricket::Device device("test", "device");
484 EXPECT_TRUE(engine_.Init(talk_base::Thread::Current()));
485 video_capturer_.reset(new cricket::FakeVideoCapturer);
486 EXPECT_TRUE(video_capturer_.get() != NULL);
487 EXPECT_TRUE(engine_.SetVideoCapturer(video_capturer_.get()));
488 channel_.reset(engine_.CreateChannel(NULL));
489 EXPECT_TRUE(channel_.get() != NULL);
490 ConnectVideoChannelError();
491 network_interface_.SetDestination(channel_.get());
492 channel_->SetInterface(&network_interface_);
493 SetRendererAsDefault();
494 media_error_ = cricket::VideoMediaChannel::ERROR_NONE;
495 channel_->SetRecvCodecs(engine_.codecs());
496 EXPECT_TRUE(channel_->AddSendStream(DefaultSendStreamParams()));
497 }
498 void SetUpSecondStream() {
499 EXPECT_TRUE(channel_->AddRecvStream(
500 cricket::StreamParams::CreateLegacy(kSsrc)));
501 EXPECT_TRUE(channel_->AddRecvStream(
502 cricket::StreamParams::CreateLegacy(kSsrc+2)));
503 // SetUp() already added kSsrc make sure duplicate SSRCs cant be added.
504 EXPECT_FALSE(channel_->AddSendStream(
505 cricket::StreamParams::CreateLegacy(kSsrc)));
506 EXPECT_TRUE(channel_->AddSendStream(
507 cricket::StreamParams::CreateLegacy(kSsrc+2)));
508 // Make the second renderer available for use by a new stream.
509 EXPECT_TRUE(channel_->SetRenderer(kSsrc+2, &renderer2_));
510 }
511 virtual void TearDown() {
512 channel_.reset();
513 engine_.Terminate();
514 }
515 void ConnectVideoChannelError() {
516 channel_->SignalMediaError.connect(this,
517 &VideoMediaChannelTest<E, C>::OnVideoChannelError);
518 }
519 bool SetDefaultCodec() {
520 return SetOneCodec(DefaultCodec());
521 }
522 void SetRendererAsDefault() {
523 EXPECT_TRUE(channel_->SetRenderer(0, &renderer_));
524 }
525
526 bool SetOneCodec(int pt, const char* name, int w, int h, int fr) {
527 return SetOneCodec(cricket::VideoCodec(pt, name, w, h, fr, 0));
528 }
529 bool SetOneCodec(const cricket::VideoCodec& codec) {
530 std::vector<cricket::VideoCodec> codecs;
531 codecs.push_back(codec);
532 bool sending = channel_->sending();
533 bool success = SetSend(false);
534 if (success)
535 success = channel_->SetSendCodecs(codecs);
536 if (success)
537 success = SetSend(sending);
538 return success;
539 }
540 bool SetSend(bool send) {
541 return channel_->SetSend(send);
542 }
543 int DrainOutgoingPackets() {
544 int packets = 0;
545 do {
546 packets = NumRtpPackets();
547 // 100 ms should be long enough.
548 talk_base::Thread::Current()->ProcessMessages(100);
549 } while (NumRtpPackets() > packets);
550 return NumRtpPackets();
551 }
552 bool SendFrame() {
553 return video_capturer_.get() &&
554 video_capturer_->CaptureFrame();
555 }
556 bool WaitAndSendFrame(int wait_ms) {
557 bool ret = talk_base::Thread::Current()->ProcessMessages(wait_ms);
558 ret &= SendFrame();
559 return ret;
560 }
561 // Sends frames and waits for the decoder to be fully initialized.
562 // Returns the number of frames that were sent.
563 int WaitForDecoder() {
564#if defined(HAVE_OPENMAX)
565 // Send enough frames for the OpenMAX decoder to continue processing, and
566 // return the number of frames sent.
567 // Send frames for a full kTimeout's worth of 15fps video.
568 int frame_count = 0;
569 while (frame_count < static_cast<int>(kTimeout) / 66) {
570 EXPECT_TRUE(WaitAndSendFrame(66));
571 ++frame_count;
572 }
573 return frame_count;
574#else
575 return 0;
576#endif
577 }
578 bool SendCustomVideoFrame(int w, int h) {
579 if (!video_capturer_.get()) return false;
580 return video_capturer_->CaptureCustomFrame(w, h, cricket::FOURCC_I420);
581 }
582 int NumRtpBytes() {
583 return network_interface_.NumRtpBytes();
584 }
585 int NumRtpBytes(uint32 ssrc) {
586 return network_interface_.NumRtpBytes(ssrc);
587 }
588 int NumRtpPackets() {
589 return network_interface_.NumRtpPackets();
590 }
591 int NumRtpPackets(uint32 ssrc) {
592 return network_interface_.NumRtpPackets(ssrc);
593 }
594 int NumSentSsrcs() {
595 return network_interface_.NumSentSsrcs();
596 }
597 const talk_base::Buffer* GetRtpPacket(int index) {
598 return network_interface_.GetRtpPacket(index);
599 }
600 int NumRtcpPackets() {
601 return network_interface_.NumRtcpPackets();
602 }
603 const talk_base::Buffer* GetRtcpPacket(int index) {
604 return network_interface_.GetRtcpPacket(index);
605 }
606 static int GetPayloadType(const talk_base::Buffer* p) {
607 int pt = -1;
608 ParseRtpPacket(p, NULL, &pt, NULL, NULL, NULL, NULL);
609 return pt;
610 }
611 static bool ParseRtpPacket(const talk_base::Buffer* p, bool* x, int* pt,
612 int* seqnum, uint32* tstamp, uint32* ssrc,
613 std::string* payload) {
614 talk_base::ByteBuffer buf(p->data(), p->length());
615 uint8 u08 = 0;
616 uint16 u16 = 0;
617 uint32 u32 = 0;
618
619 // Read X and CC fields.
620 if (!buf.ReadUInt8(&u08)) return false;
621 bool extension = ((u08 & 0x10) != 0);
622 uint8 cc = (u08 & 0x0F);
623 if (x) *x = extension;
624
625 // Read PT field.
626 if (!buf.ReadUInt8(&u08)) return false;
627 if (pt) *pt = (u08 & 0x7F);
628
629 // Read Sequence Number field.
630 if (!buf.ReadUInt16(&u16)) return false;
631 if (seqnum) *seqnum = u16;
632
633 // Read Timestamp field.
634 if (!buf.ReadUInt32(&u32)) return false;
635 if (tstamp) *tstamp = u32;
636
637 // Read SSRC field.
638 if (!buf.ReadUInt32(&u32)) return false;
639 if (ssrc) *ssrc = u32;
640
641 // Skip CSRCs.
642 for (uint8 i = 0; i < cc; ++i) {
643 if (!buf.ReadUInt32(&u32)) return false;
644 }
645
646 // Skip extension header.
647 if (extension) {
648 // Read Profile-specific extension header ID
649 if (!buf.ReadUInt16(&u16)) return false;
650
651 // Read Extension header length
652 if (!buf.ReadUInt16(&u16)) return false;
653 uint16 ext_header_len = u16;
654
655 // Read Extension header
656 for (uint16 i = 0; i < ext_header_len; ++i) {
657 if (!buf.ReadUInt32(&u32)) return false;
658 }
659 }
660
661 if (payload) {
662 return buf.ReadString(payload, buf.Length());
663 }
664 return true;
665 }
666
667 // Parse all RTCP packet, from start_index to stop_index, and count how many
668 // FIR (PT=206 and FMT=4 according to RFC 5104). If successful, set the count
669 // and return true.
670 bool CountRtcpFir(int start_index, int stop_index, int* fir_count) {
671 int count = 0;
672 for (int i = start_index; i < stop_index; ++i) {
673 talk_base::scoped_ptr<const talk_base::Buffer> p(GetRtcpPacket(i));
674 talk_base::ByteBuffer buf(p->data(), p->length());
675 size_t total_len = 0;
676 // The packet may be a compound RTCP packet.
677 while (total_len < p->length()) {
678 // Read FMT, type and length.
679 uint8 fmt = 0;
680 uint8 type = 0;
681 uint16 length = 0;
682 if (!buf.ReadUInt8(&fmt)) return false;
683 fmt &= 0x1F;
684 if (!buf.ReadUInt8(&type)) return false;
685 if (!buf.ReadUInt16(&length)) return false;
686 buf.Consume(length * 4); // Skip RTCP data.
687 total_len += (length + 1) * 4;
688 if ((192 == type) || ((206 == type) && (4 == fmt))) {
689 ++count;
690 }
691 }
692 }
693
694 if (fir_count) {
695 *fir_count = count;
696 }
697 return true;
698 }
699
700 void OnVideoChannelError(uint32 ssrc,
701 cricket::VideoMediaChannel::Error error) {
702 media_error_ = error;
703 }
704
705 // Test that SetSend works.
706 void SetSend() {
707 EXPECT_FALSE(channel_->sending());
708 EXPECT_TRUE(SetOneCodec(DefaultCodec()));
709 EXPECT_FALSE(channel_->sending());
710 EXPECT_TRUE(SetSend(true));
711 EXPECT_TRUE(channel_->sending());
712 EXPECT_TRUE(SendFrame());
713 EXPECT_TRUE_WAIT(NumRtpPackets() > 0, kTimeout);
714 EXPECT_TRUE(SetSend(false));
715 EXPECT_FALSE(channel_->sending());
716 }
717 // Test that SetSend fails without codecs being set.
718 void SetSendWithoutCodecs() {
719 EXPECT_FALSE(channel_->sending());
720 EXPECT_FALSE(SetSend(true));
721 EXPECT_FALSE(channel_->sending());
722 }
723 // Test that we properly set the send and recv buffer sizes by the time
724 // SetSend is called.
725 void SetSendSetsTransportBufferSizes() {
726 EXPECT_TRUE(SetOneCodec(DefaultCodec()));
727 EXPECT_TRUE(SetSend(true));
728 // TODO(sriniv): Remove or re-enable this.
729 // As part of b/8030474, send-buffer is size now controlled through
730 // portallocator flags. Its not set by channels.
731 // EXPECT_EQ(64 * 1024, network_interface_.sendbuf_size());
732 EXPECT_EQ(64 * 1024, network_interface_.recvbuf_size());
733 }
734 // Tests that we can send frames and the right payload type is used.
735 void Send(const cricket::VideoCodec& codec) {
736 EXPECT_TRUE(SetOneCodec(codec));
737 EXPECT_TRUE(SetSend(true));
738 EXPECT_TRUE(SendFrame());
739 EXPECT_TRUE_WAIT(NumRtpPackets() > 0, kTimeout);
740 talk_base::scoped_ptr<const talk_base::Buffer> p(GetRtpPacket(0));
741 EXPECT_EQ(codec.id, GetPayloadType(p.get()));
742 }
743 // Tests that we can send and receive frames.
744 void SendAndReceive(const cricket::VideoCodec& codec) {
745 EXPECT_TRUE(SetOneCodec(codec));
746 EXPECT_TRUE(SetSend(true));
747 EXPECT_TRUE(channel_->SetRender(true));
748 EXPECT_EQ(0, renderer_.num_rendered_frames());
749 EXPECT_TRUE(SendFrame());
750 EXPECT_FRAME_WAIT(1, codec.width, codec.height, kTimeout);
751 talk_base::scoped_ptr<const talk_base::Buffer> p(GetRtpPacket(0));
752 EXPECT_EQ(codec.id, GetPayloadType(p.get()));
753 }
754 // Tests that we only get a VideoRenderer::SetSize() callback when needed.
755 void SendManyResizeOnce() {
756 cricket::VideoCodec codec(DefaultCodec());
757 EXPECT_TRUE(SetOneCodec(codec));
758 EXPECT_TRUE(SetSend(true));
759 EXPECT_TRUE(channel_->SetRender(true));
760 EXPECT_EQ(0, renderer_.num_rendered_frames());
761 EXPECT_TRUE(WaitAndSendFrame(30));
762 EXPECT_FRAME_WAIT(1, codec.width, codec.height, kTimeout);
763 EXPECT_TRUE(WaitAndSendFrame(30));
764 EXPECT_FRAME_WAIT(2, codec.width, codec.height, kTimeout);
765 talk_base::scoped_ptr<const talk_base::Buffer> p(GetRtpPacket(0));
766 EXPECT_EQ(codec.id, GetPayloadType(p.get()));
767 EXPECT_EQ(1, renderer_.num_set_sizes());
768
769 codec.width /= 2;
770 codec.height /= 2;
771 EXPECT_TRUE(SetOneCodec(codec));
772 EXPECT_TRUE(WaitAndSendFrame(30));
773 EXPECT_FRAME_WAIT(3, codec.width, codec.height, kTimeout);
774 EXPECT_EQ(2, renderer_.num_set_sizes());
775 }
776 // Test that stats work properly for a 1-1 call.
777 void GetStats() {
778 SendAndReceive(DefaultCodec());
779 cricket::VideoMediaInfo info;
780 EXPECT_TRUE(channel_->GetStats(&info));
781
782 ASSERT_EQ(1U, info.senders.size());
783 // TODO(whyuan): bytes_sent and bytes_rcvd are different. Are both payload?
784 EXPECT_GT(info.senders[0].bytes_sent, 0);
785 EXPECT_EQ(NumRtpPackets(), info.senders[0].packets_sent);
786 EXPECT_EQ(0.0, info.senders[0].fraction_lost);
787 EXPECT_EQ(0, info.senders[0].firs_rcvd);
788 EXPECT_EQ(0, info.senders[0].nacks_rcvd);
789 EXPECT_EQ(DefaultCodec().width, info.senders[0].frame_width);
790 EXPECT_EQ(DefaultCodec().height, info.senders[0].frame_height);
791 EXPECT_GT(info.senders[0].framerate_input, 0);
792 EXPECT_GT(info.senders[0].framerate_sent, 0);
793
794 ASSERT_EQ(1U, info.receivers.size());
795 EXPECT_EQ(1U, info.senders[0].ssrcs.size());
796 EXPECT_EQ(1U, info.receivers[0].ssrcs.size());
797 EXPECT_EQ(info.senders[0].ssrcs[0], info.receivers[0].ssrcs[0]);
798 EXPECT_EQ(NumRtpBytes(), info.receivers[0].bytes_rcvd);
799 EXPECT_EQ(NumRtpPackets(), info.receivers[0].packets_rcvd);
800 EXPECT_EQ(0.0, info.receivers[0].fraction_lost);
801 EXPECT_EQ(0, info.receivers[0].packets_lost);
802 EXPECT_EQ(0, info.receivers[0].packets_concealed);
803 EXPECT_EQ(0, info.receivers[0].firs_sent);
804 EXPECT_EQ(0, info.receivers[0].nacks_sent);
805 EXPECT_EQ(DefaultCodec().width, info.receivers[0].frame_width);
806 EXPECT_EQ(DefaultCodec().height, info.receivers[0].frame_height);
807 EXPECT_GT(info.receivers[0].framerate_rcvd, 0);
808 EXPECT_GT(info.receivers[0].framerate_decoded, 0);
809 EXPECT_GT(info.receivers[0].framerate_output, 0);
810 }
811 // Test that stats work properly for a conf call with multiple recv streams.
812 void GetStatsMultipleRecvStreams() {
813 cricket::FakeVideoRenderer renderer1, renderer2;
814 EXPECT_TRUE(SetOneCodec(DefaultCodec()));
815 cricket::VideoOptions vmo;
816 vmo.conference_mode.Set(true);
817 EXPECT_TRUE(channel_->SetOptions(vmo));
818 EXPECT_TRUE(SetSend(true));
819 EXPECT_TRUE(channel_->AddRecvStream(
820 cricket::StreamParams::CreateLegacy(1)));
821 EXPECT_TRUE(channel_->AddRecvStream(
822 cricket::StreamParams::CreateLegacy(2)));
823 EXPECT_TRUE(channel_->SetRenderer(1, &renderer1));
824 EXPECT_TRUE(channel_->SetRenderer(2, &renderer2));
825 EXPECT_TRUE(channel_->SetRender(true));
826 EXPECT_EQ(0, renderer1.num_rendered_frames());
827 EXPECT_EQ(0, renderer2.num_rendered_frames());
828 std::vector<uint32> ssrcs;
829 ssrcs.push_back(1);
830 ssrcs.push_back(2);
831 network_interface_.SetConferenceMode(true, ssrcs);
832 EXPECT_TRUE(SendFrame());
833 EXPECT_FRAME_ON_RENDERER_WAIT(
834 renderer1, 1, DefaultCodec().width, DefaultCodec().height, kTimeout);
835 EXPECT_FRAME_ON_RENDERER_WAIT(
836 renderer2, 1, DefaultCodec().width, DefaultCodec().height, kTimeout);
837 cricket::VideoMediaInfo info;
838 EXPECT_TRUE(channel_->GetStats(&info));
839
840 ASSERT_EQ(1U, info.senders.size());
841 // TODO(whyuan): bytes_sent and bytes_rcvd are different. Are both payload?
842 EXPECT_GT(info.senders[0].bytes_sent, 0);
843 EXPECT_EQ(NumRtpPackets(), info.senders[0].packets_sent);
844 EXPECT_EQ(0.0, info.senders[0].fraction_lost);
845 EXPECT_EQ(0, info.senders[0].firs_rcvd);
846 EXPECT_EQ(0, info.senders[0].nacks_rcvd);
847 EXPECT_EQ(DefaultCodec().width, info.senders[0].frame_width);
848 EXPECT_EQ(DefaultCodec().height, info.senders[0].frame_height);
849 EXPECT_GT(info.senders[0].framerate_input, 0);
850 EXPECT_GT(info.senders[0].framerate_sent, 0);
851
852 ASSERT_EQ(2U, info.receivers.size());
853 for (size_t i = 0; i < info.receivers.size(); ++i) {
854 EXPECT_EQ(1U, info.receivers[i].ssrcs.size());
855 EXPECT_EQ(i + 1, info.receivers[i].ssrcs[0]);
856 EXPECT_EQ(NumRtpBytes(), info.receivers[i].bytes_rcvd);
857 EXPECT_EQ(NumRtpPackets(), info.receivers[i].packets_rcvd);
858 EXPECT_EQ(0.0, info.receivers[i].fraction_lost);
859 EXPECT_EQ(0, info.receivers[i].packets_lost);
860 EXPECT_EQ(0, info.receivers[i].packets_concealed);
861 EXPECT_EQ(0, info.receivers[i].firs_sent);
862 EXPECT_EQ(0, info.receivers[i].nacks_sent);
863 EXPECT_EQ(DefaultCodec().width, info.receivers[i].frame_width);
864 EXPECT_EQ(DefaultCodec().height, info.receivers[i].frame_height);
865 EXPECT_GT(info.receivers[i].framerate_rcvd, 0);
866 EXPECT_GT(info.receivers[i].framerate_decoded, 0);
867 EXPECT_GT(info.receivers[i].framerate_output, 0);
868 }
869 }
870 // Test that stats work properly for a conf call with multiple send streams.
871 void GetStatsMultipleSendStreams() {
872 // Normal setup; note that we set the SSRC explicitly to ensure that
873 // it will come first in the senders map.
874 EXPECT_TRUE(SetOneCodec(DefaultCodec()));
875 cricket::VideoOptions vmo;
876 vmo.conference_mode.Set(true);
877 EXPECT_TRUE(channel_->SetOptions(vmo));
878 EXPECT_TRUE(channel_->AddRecvStream(
879 cricket::StreamParams::CreateLegacy(1234)));
880 EXPECT_TRUE(SetSend(true));
881 EXPECT_TRUE(channel_->SetRender(true));
882 EXPECT_TRUE(SendFrame());
883 EXPECT_TRUE_WAIT(NumRtpPackets() > 0, kTimeout);
884 EXPECT_FRAME_WAIT(1, DefaultCodec().width, DefaultCodec().height, kTimeout);
885
886 // Add an additional capturer, and hook up a renderer to receive it.
887 cricket::FakeVideoRenderer renderer1;
888 talk_base::scoped_ptr<cricket::FakeVideoCapturer> capturer(
889 new cricket::FakeVideoCapturer);
890 capturer->SetScreencast(true);
891 cricket::VideoFormat format(1024, 768,
892 cricket::VideoFormat::FpsToInterval(5), 0);
893 EXPECT_EQ(cricket::CS_RUNNING, capturer->Start(format));
894 EXPECT_TRUE(channel_->AddSendStream(
895 cricket::StreamParams::CreateLegacy(5678)));
896 EXPECT_TRUE(channel_->SetCapturer(5678, capturer.get()));
897 EXPECT_TRUE(channel_->AddRecvStream(
898 cricket::StreamParams::CreateLegacy(5678)));
899 EXPECT_TRUE(channel_->SetRenderer(5678, &renderer1));
900 EXPECT_TRUE(capturer->CaptureCustomFrame(1024, 768, cricket::FOURCC_I420));
901 EXPECT_FRAME_ON_RENDERER_WAIT(renderer1, 1, 1024, 768, kTimeout);
902
903 // Get stats, and make sure they are correct for two senders.
904 cricket::VideoMediaInfo info;
905 EXPECT_TRUE(channel_->GetStats(&info));
906 ASSERT_EQ(2U, info.senders.size());
907 EXPECT_EQ(NumRtpPackets(),
908 info.senders[0].packets_sent + info.senders[1].packets_sent);
909 EXPECT_EQ(1U, info.senders[0].ssrcs.size());
910 EXPECT_EQ(1234U, info.senders[0].ssrcs[0]);
911 EXPECT_EQ(DefaultCodec().width, info.senders[0].frame_width);
912 EXPECT_EQ(DefaultCodec().height, info.senders[0].frame_height);
913 EXPECT_EQ(1U, info.senders[1].ssrcs.size());
914 EXPECT_EQ(5678U, info.senders[1].ssrcs[0]);
915 EXPECT_EQ(1024, info.senders[1].frame_width);
916 EXPECT_EQ(768, info.senders[1].frame_height);
917 // The capturer must be unregistered here as it runs out of it's scope next.
918 EXPECT_TRUE(channel_->SetCapturer(5678, NULL));
919 }
920
921 // Test that we can set the bandwidth to auto or a specific value.
922 void SetSendBandwidth() {
923 EXPECT_TRUE(channel_->SetSendBandwidth(true, -1));
924 EXPECT_TRUE(channel_->SetSendBandwidth(true, 128 * 1024));
925 EXPECT_TRUE(channel_->SetSendBandwidth(false, -1));
926 EXPECT_TRUE(channel_->SetSendBandwidth(false, 128 * 1024));
927 }
928 // Test that we can set the SSRC for the default send source.
929 void SetSendSsrc() {
930 EXPECT_TRUE(SetDefaultCodec());
931 EXPECT_TRUE(SetSend(true));
932 EXPECT_TRUE(SendFrame());
933 EXPECT_TRUE_WAIT(NumRtpPackets() > 0, kTimeout);
934 uint32 ssrc = 0;
935 talk_base::scoped_ptr<const talk_base::Buffer> p(GetRtpPacket(0));
936 ParseRtpPacket(p.get(), NULL, NULL, NULL, NULL, &ssrc, NULL);
937 EXPECT_EQ(kSsrc, ssrc);
938 EXPECT_EQ(NumRtpPackets(), NumRtpPackets(ssrc));
939 EXPECT_EQ(NumRtpBytes(), NumRtpBytes(ssrc));
940 EXPECT_EQ(1, NumSentSsrcs());
941 EXPECT_EQ(0, NumRtpPackets(kSsrc - 1));
942 EXPECT_EQ(0, NumRtpBytes(kSsrc - 1));
943 }
944 // Test that we can set the SSRC even after codecs are set.
945 void SetSendSsrcAfterSetCodecs() {
946 // Remove stream added in Setup.
947 EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
948 EXPECT_TRUE(SetDefaultCodec());
949 EXPECT_TRUE(channel_->AddSendStream(
950 cricket::StreamParams::CreateLegacy(999)));
951 EXPECT_TRUE(SetSend(true));
952 EXPECT_TRUE(WaitAndSendFrame(0));
953 EXPECT_TRUE_WAIT(NumRtpPackets() > 0, kTimeout);
954 uint32 ssrc = 0;
955 talk_base::scoped_ptr<const talk_base::Buffer> p(GetRtpPacket(0));
956 ParseRtpPacket(p.get(), NULL, NULL, NULL, NULL, &ssrc, NULL);
957 EXPECT_EQ(999u, ssrc);
958 EXPECT_EQ(NumRtpPackets(), NumRtpPackets(ssrc));
959 EXPECT_EQ(NumRtpBytes(), NumRtpBytes(ssrc));
960 EXPECT_EQ(1, NumSentSsrcs());
961 EXPECT_EQ(0, NumRtpPackets(kSsrc));
962 EXPECT_EQ(0, NumRtpBytes(kSsrc));
963 }
964 // Test that we can set the default video renderer before and after
965 // media is received.
966 void SetRenderer() {
967 uint8 data1[] = {
968 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
969 };
970
971 talk_base::Buffer packet1(data1, sizeof(data1));
972 talk_base::SetBE32(packet1.data() + 8, kSsrc);
973 channel_->SetRenderer(0, NULL);
974 EXPECT_TRUE(SetDefaultCodec());
975 EXPECT_TRUE(SetSend(true));
976 EXPECT_TRUE(channel_->SetRender(true));
977 EXPECT_EQ(0, renderer_.num_rendered_frames());
978 channel_->OnPacketReceived(&packet1);
979 SetRendererAsDefault();
980 EXPECT_TRUE(SendFrame());
981 EXPECT_FRAME_WAIT(1, DefaultCodec().width, DefaultCodec().height, kTimeout);
982 }
983
984 // Tests empty StreamParams is rejected.
985 void RejectEmptyStreamParams() {
986 // Remove the send stream that was added during Setup.
987 EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
988
989 cricket::StreamParams empty;
990 EXPECT_FALSE(channel_->AddSendStream(empty));
991 EXPECT_TRUE(channel_->AddSendStream(
992 cricket::StreamParams::CreateLegacy(789u)));
993 }
994
995 // Tests setting up and configuring a send stream.
996 void AddRemoveSendStreams() {
997 EXPECT_TRUE(SetOneCodec(DefaultCodec()));
998 EXPECT_TRUE(SetSend(true));
999 EXPECT_TRUE(channel_->SetRender(true));
1000 EXPECT_TRUE(SendFrame());
1001 EXPECT_FRAME_WAIT(1, DefaultCodec().width, DefaultCodec().height, kTimeout);
1002 EXPECT_GE(2, NumRtpPackets());
1003 uint32 ssrc = 0;
1004 size_t last_packet = NumRtpPackets() - 1;
1005 talk_base::scoped_ptr<const talk_base::Buffer> p(GetRtpPacket(last_packet));
1006 ParseRtpPacket(p.get(), NULL, NULL, NULL, NULL, &ssrc, NULL);
1007 EXPECT_EQ(kSsrc, ssrc);
1008
1009 // Remove the send stream that was added during Setup.
1010 EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
1011 int rtp_packets = NumRtpPackets();
1012
1013 EXPECT_TRUE(channel_->AddSendStream(
1014 cricket::StreamParams::CreateLegacy(789u)));
1015 EXPECT_EQ(rtp_packets, NumRtpPackets());
1016 // Wait 30ms to guarantee the engine does not drop the frame.
1017 EXPECT_TRUE(WaitAndSendFrame(30));
1018 EXPECT_TRUE_WAIT(NumRtpPackets() > rtp_packets, kTimeout);
1019
1020 last_packet = NumRtpPackets() - 1;
1021 p.reset(GetRtpPacket(last_packet));
1022 ParseRtpPacket(p.get(), NULL, NULL, NULL, NULL, &ssrc, NULL);
1023 EXPECT_EQ(789u, ssrc);
1024 }
1025
1026 // Tests adding streams already exists returns false.
1027 void AddRecvStreamsAlreadyExist() {
1028 cricket::VideoOptions vmo;
1029 vmo.conference_mode.Set(true);
1030 EXPECT_TRUE(channel_->SetOptions(vmo));
1031
1032 EXPECT_FALSE(channel_->AddRecvStream(
1033 cricket::StreamParams::CreateLegacy(0)));
1034
1035 EXPECT_TRUE(channel_->AddRecvStream(
1036 cricket::StreamParams::CreateLegacy(1)));
1037 EXPECT_FALSE(channel_->AddRecvStream(
1038 cricket::StreamParams::CreateLegacy(1)));
1039
1040 EXPECT_TRUE(channel_->RemoveRecvStream(1));
1041 EXPECT_FALSE(channel_->AddRecvStream(
1042 cricket::StreamParams::CreateLegacy(0)));
1043 EXPECT_TRUE(channel_->AddRecvStream(
1044 cricket::StreamParams::CreateLegacy(1)));
1045 }
1046
1047 // Tests setting up and configuring multiple incoming streams.
1048 void AddRemoveRecvStreams() {
1049 cricket::FakeVideoRenderer renderer1, renderer2;
1050 cricket::VideoOptions vmo;
1051 vmo.conference_mode.Set(true);
1052 EXPECT_TRUE(channel_->SetOptions(vmo));
1053 // Ensure we can't set the renderer on a non-existent stream.
1054 EXPECT_FALSE(channel_->SetRenderer(1, &renderer1));
1055 EXPECT_FALSE(channel_->SetRenderer(2, &renderer2));
1056 cricket::VideoRenderer* renderer;
1057 EXPECT_FALSE(channel_->GetRenderer(1, &renderer));
1058 EXPECT_FALSE(channel_->GetRenderer(2, &renderer));
1059
1060 // Ensure we can add streams.
1061 EXPECT_TRUE(channel_->AddRecvStream(
1062 cricket::StreamParams::CreateLegacy(1)));
1063 EXPECT_TRUE(channel_->AddRecvStream(
1064 cricket::StreamParams::CreateLegacy(2)));
1065 EXPECT_TRUE(channel_->GetRenderer(1, &renderer));
1066 // Verify the first AddRecvStream hook up to the default renderer.
1067 EXPECT_EQ(&renderer_, renderer);
1068 EXPECT_TRUE(channel_->GetRenderer(2, &renderer));
1069 EXPECT_TRUE(NULL == renderer);
1070
1071 // Ensure we can now set the renderers.
1072 EXPECT_TRUE(channel_->SetRenderer(1, &renderer1));
1073 EXPECT_TRUE(channel_->SetRenderer(2, &renderer2));
1074 EXPECT_TRUE(channel_->GetRenderer(1, &renderer));
1075 EXPECT_TRUE(&renderer1 == renderer);
1076 EXPECT_TRUE(channel_->GetRenderer(2, &renderer));
1077 EXPECT_TRUE(&renderer2 == renderer);
1078
1079 // Ensure we can change the renderers if needed.
1080 EXPECT_TRUE(channel_->SetRenderer(1, &renderer2));
1081 EXPECT_TRUE(channel_->SetRenderer(2, &renderer1));
1082 EXPECT_TRUE(channel_->GetRenderer(1, &renderer));
1083 EXPECT_TRUE(&renderer2 == renderer);
1084 EXPECT_TRUE(channel_->GetRenderer(2, &renderer));
1085 EXPECT_TRUE(&renderer1 == renderer);
1086
1087 EXPECT_TRUE(channel_->RemoveRecvStream(2));
1088 EXPECT_TRUE(channel_->RemoveRecvStream(1));
1089 EXPECT_FALSE(channel_->GetRenderer(1, &renderer));
1090 EXPECT_FALSE(channel_->GetRenderer(2, &renderer));
1091 }
1092
1093 // Tests setting up and configuring multiple incoming streams in a
1094 // non-conference call.
1095 void AddRemoveRecvStreamsNoConference() {
1096 cricket::FakeVideoRenderer renderer1, renderer2;
1097 // Ensure we can't set the renderer on a non-existent stream.
1098 EXPECT_FALSE(channel_->SetRenderer(1, &renderer1));
1099 EXPECT_FALSE(channel_->SetRenderer(2, &renderer2));
1100 cricket::VideoRenderer* renderer;
1101 EXPECT_FALSE(channel_->GetRenderer(1, &renderer));
1102 EXPECT_FALSE(channel_->GetRenderer(2, &renderer));
1103
1104 // Ensure we can add streams.
1105 EXPECT_TRUE(channel_->AddRecvStream(
1106 cricket::StreamParams::CreateLegacy(1)));
1107 EXPECT_TRUE(channel_->AddRecvStream(
1108 cricket::StreamParams::CreateLegacy(2)));
1109 EXPECT_TRUE(channel_->GetRenderer(1, &renderer));
1110 // Verify the first AddRecvStream hook up to the default renderer.
1111 EXPECT_EQ(&renderer_, renderer);
1112 EXPECT_TRUE(channel_->GetRenderer(2, &renderer));
1113 EXPECT_TRUE(NULL == renderer);
1114
1115 // Ensure we can now set the renderers.
1116 EXPECT_TRUE(channel_->SetRenderer(1, &renderer1));
1117 EXPECT_TRUE(channel_->SetRenderer(2, &renderer2));
1118 EXPECT_TRUE(channel_->GetRenderer(1, &renderer));
1119 EXPECT_TRUE(&renderer1 == renderer);
1120 EXPECT_TRUE(channel_->GetRenderer(2, &renderer));
1121 EXPECT_TRUE(&renderer2 == renderer);
1122
1123 // Ensure we can change the renderers if needed.
1124 EXPECT_TRUE(channel_->SetRenderer(1, &renderer2));
1125 EXPECT_TRUE(channel_->SetRenderer(2, &renderer1));
1126 EXPECT_TRUE(channel_->GetRenderer(1, &renderer));
1127 EXPECT_TRUE(&renderer2 == renderer);
1128 EXPECT_TRUE(channel_->GetRenderer(2, &renderer));
1129 EXPECT_TRUE(&renderer1 == renderer);
1130
1131 EXPECT_TRUE(channel_->RemoveRecvStream(2));
1132 EXPECT_TRUE(channel_->RemoveRecvStream(1));
1133 EXPECT_FALSE(channel_->GetRenderer(1, &renderer));
1134 EXPECT_FALSE(channel_->GetRenderer(2, &renderer));
1135 }
1136
1137 // Test that no frames are rendered after the receive stream have been
1138 // removed.
1139 void AddRemoveRecvStreamAndRender() {
1140 cricket::FakeVideoRenderer renderer1;
1141 EXPECT_TRUE(SetDefaultCodec());
1142 EXPECT_TRUE(SetSend(true));
1143 EXPECT_TRUE(channel_->SetRender(true));
1144 EXPECT_TRUE(channel_->AddRecvStream(
1145 cricket::StreamParams::CreateLegacy(kSsrc)));
1146 EXPECT_TRUE(channel_->SetRenderer(kSsrc, &renderer1));
1147
1148 EXPECT_TRUE(SendFrame());
1149 EXPECT_FRAME_ON_RENDERER_WAIT(
1150 renderer1, 1, DefaultCodec().width, DefaultCodec().height, kTimeout);
1151 EXPECT_TRUE(channel_->RemoveRecvStream(kSsrc));
1152 // Send three more frames. This is to avoid that the test might be flaky
1153 // due to frame dropping.
1154 for (size_t i = 0; i < 3; ++i)
1155 EXPECT_TRUE(WaitAndSendFrame(100));
1156
1157 // Test that no more frames have been rendered.
1158 EXPECT_EQ(1, renderer1.num_rendered_frames());
1159
1160 // Re-add the stream again and make sure it renders.
1161 EXPECT_TRUE(channel_->AddRecvStream(
1162 cricket::StreamParams::CreateLegacy(kSsrc)));
1163 // Force the next frame to be a key frame to make the receiving
1164 // decoder happy.
1165 EXPECT_TRUE(channel_->SendIntraFrame());
1166
1167 EXPECT_TRUE(channel_->SetRenderer(kSsrc, &renderer1));
1168 EXPECT_TRUE(SendFrame());
1169 EXPECT_FRAME_ON_RENDERER_WAIT(
1170 renderer1, 2, DefaultCodec().width, DefaultCodec().height, kTimeout);
1171 }
1172
1173 // Tests the behavior of incoming streams in a conference scenario.
1174 void SimulateConference() {
1175 cricket::FakeVideoRenderer renderer1, renderer2;
1176 EXPECT_TRUE(SetDefaultCodec());
1177 cricket::VideoOptions vmo;
1178 vmo.conference_mode.Set(true);
1179 EXPECT_TRUE(channel_->SetOptions(vmo));
1180 EXPECT_TRUE(SetSend(true));
1181 EXPECT_TRUE(channel_->SetRender(true));
1182 EXPECT_TRUE(channel_->AddRecvStream(
1183 cricket::StreamParams::CreateLegacy(1)));
1184 EXPECT_TRUE(channel_->AddRecvStream(
1185 cricket::StreamParams::CreateLegacy(2)));
1186 EXPECT_TRUE(channel_->SetRenderer(1, &renderer1));
1187 EXPECT_TRUE(channel_->SetRenderer(2, &renderer2));
1188 EXPECT_EQ(0, renderer1.num_rendered_frames());
1189 EXPECT_EQ(0, renderer2.num_rendered_frames());
1190 std::vector<uint32> ssrcs;
1191 ssrcs.push_back(1);
1192 ssrcs.push_back(2);
1193 network_interface_.SetConferenceMode(true, ssrcs);
1194 EXPECT_TRUE(SendFrame());
1195 EXPECT_FRAME_ON_RENDERER_WAIT(
1196 renderer1, 1, DefaultCodec().width, DefaultCodec().height, kTimeout);
1197 EXPECT_FRAME_ON_RENDERER_WAIT(
1198 renderer2, 1, DefaultCodec().width, DefaultCodec().height, kTimeout);
1199
1200 talk_base::scoped_ptr<const talk_base::Buffer> p(GetRtpPacket(0));
1201 EXPECT_EQ(DefaultCodec().id, GetPayloadType(p.get()));
1202 EXPECT_EQ(DefaultCodec().width, renderer1.width());
1203 EXPECT_EQ(DefaultCodec().height, renderer1.height());
1204 EXPECT_EQ(DefaultCodec().width, renderer2.width());
1205 EXPECT_EQ(DefaultCodec().height, renderer2.height());
1206 EXPECT_TRUE(channel_->RemoveRecvStream(2));
1207 EXPECT_TRUE(channel_->RemoveRecvStream(1));
1208 }
1209
1210 // Tests that we can add and remove capturers and frames are sent out properly
1211 void AddRemoveCapturer() {
1212 const cricket::VideoCodec codec(DefaultCodec());
1213 const int time_between_send = TimeBetweenSend(codec);
1214 EXPECT_TRUE(SetDefaultCodec());
1215 EXPECT_TRUE(SetSend(true));
1216 EXPECT_TRUE(channel_->SetRender(true));
1217 EXPECT_EQ(0, renderer_.num_rendered_frames());
1218 EXPECT_TRUE(SendFrame());
1219 EXPECT_FRAME_WAIT(1, codec.width, codec.height, kTimeout);
1220 talk_base::scoped_ptr<cricket::FakeVideoCapturer> capturer(
1221 new cricket::FakeVideoCapturer);
1222 capturer->SetScreencast(true);
1223 cricket::VideoFormat format(1024, 768,
1224 cricket::VideoFormat::FpsToInterval(30), 0);
1225 EXPECT_EQ(cricket::CS_RUNNING, capturer->Start(format));
1226 // All capturers start generating frames with the same timestamp. ViE does
1227 // not allow the same timestamp to be used. Capture one frame before
1228 // associating the capturer with the channel.
1229 EXPECT_TRUE(capturer->CaptureCustomFrame(format.width, format.height,
1230 cricket::FOURCC_I420));
1231
1232 int captured_frames = 1;
1233 for (int iterations = 0; iterations < 2; ++iterations) {
1234 EXPECT_TRUE(channel_->SetCapturer(kSsrc, capturer.get()));
1235 talk_base::Thread::Current()->ProcessMessages(time_between_send);
1236 EXPECT_TRUE(capturer->CaptureCustomFrame(format.width, format.height,
1237 cricket::FOURCC_I420));
1238 ++captured_frames;
1239 EXPECT_FRAME_WAIT(captured_frames, format.width, format.height, kTimeout);
1240 EXPECT_FALSE(renderer_.black_frame());
1241 EXPECT_TRUE(channel_->SetCapturer(kSsrc, NULL));
1242 // Make sure a black frame is generated as no new frame is captured.
1243 // A black frame should be the resolution of the send codec.
1244 ++captured_frames;
1245 EXPECT_FRAME_WAIT(captured_frames, codec.width, codec.height, kTimeout);
1246 EXPECT_TRUE(renderer_.black_frame());
1247
1248 // The black frame has the same timestamp as the next frame since it's
1249 // timestamp is set to the last frame's timestamp + interval. WebRTC will
1250 // not render a frame with the same timestamp so capture another frame
1251 // with the frame capturer to increment the next frame's timestamp.
1252 EXPECT_TRUE(capturer->CaptureCustomFrame(format.width, format.height,
1253 cricket::FOURCC_I420));
1254 }
1255 }
1256
1257 // Tests that if RemoveCapturer is called without a capturer ever being
1258 // added, the plugin shouldn't crash (and no black frame should be sent).
1259 void RemoveCapturerWithoutAdd() {
1260 EXPECT_TRUE(SetOneCodec(DefaultCodec()));
1261 EXPECT_TRUE(SetSend(true));
1262 EXPECT_TRUE(channel_->SetRender(true));
1263 EXPECT_EQ(0, renderer_.num_rendered_frames());
1264 EXPECT_TRUE(SendFrame());
1265 EXPECT_FRAME_WAIT(1, 640, 400, kTimeout);
1266 // No capturer was added, so this RemoveCapturer should
1267 // fail.
1268 EXPECT_FALSE(channel_->SetCapturer(kSsrc, NULL));
1269 // Wait for kTimeout, to make sure no frames are sent
1270 WAIT(renderer_.num_rendered_frames() != 1, kTimeout);
1271 // Still a single frame, from the original SendFrame() call.
1272 EXPECT_EQ(1, renderer_.num_rendered_frames());
1273 }
1274
1275 // Tests that we can add and remove capturer as unique sources.
1276 void AddRemoveCapturerMultipleSources() {
1277 // WebRTC implementation will drop frames if pushed to quickly. Wait the
1278 // interval time to avoid that.
1279 const cricket::VideoFormat send_format(
1280 1024,
1281 768,
1282 cricket::VideoFormat::FpsToInterval(30),
1283 0);
1284 // WebRTC implementation will drop frames if pushed to quickly. Wait the
1285 // interval time to avoid that.
1286 // Set up the stream associated with the engine.
1287 EXPECT_TRUE(channel_->AddRecvStream(
1288 cricket::StreamParams::CreateLegacy(kSsrc)));
1289 EXPECT_TRUE(channel_->SetRenderer(kSsrc, &renderer_));
1290 cricket::VideoFormat capture_format; // default format
1291 capture_format.interval = cricket::VideoFormat::FpsToInterval(30);
1292 // Set up additional stream 1.
1293 cricket::FakeVideoRenderer renderer1;
1294 EXPECT_FALSE(channel_->SetRenderer(1, &renderer1));
1295 EXPECT_TRUE(channel_->AddRecvStream(
1296 cricket::StreamParams::CreateLegacy(1)));
1297 EXPECT_TRUE(channel_->SetRenderer(1, &renderer1));
1298 EXPECT_TRUE(channel_->AddSendStream(
1299 cricket::StreamParams::CreateLegacy(1)));
1300 talk_base::scoped_ptr<cricket::FakeVideoCapturer> capturer1(
1301 new cricket::FakeVideoCapturer);
1302 capturer1->SetScreencast(true);
1303 EXPECT_EQ(cricket::CS_RUNNING, capturer1->Start(capture_format));
1304 // Set up additional stream 2.
1305 cricket::FakeVideoRenderer renderer2;
1306 EXPECT_FALSE(channel_->SetRenderer(2, &renderer2));
1307 EXPECT_TRUE(channel_->AddRecvStream(
1308 cricket::StreamParams::CreateLegacy(2)));
1309 EXPECT_TRUE(channel_->SetRenderer(2, &renderer2));
1310 EXPECT_TRUE(channel_->AddSendStream(
1311 cricket::StreamParams::CreateLegacy(2)));
1312 talk_base::scoped_ptr<cricket::FakeVideoCapturer> capturer2(
1313 new cricket::FakeVideoCapturer);
1314 capturer2->SetScreencast(true);
1315 EXPECT_EQ(cricket::CS_RUNNING, capturer2->Start(capture_format));
1316 // State for all the streams.
1317 EXPECT_TRUE(SetOneCodec(DefaultCodec()));
1318 // A limitation in the lmi implementation requires that SetCapturer() is
1319 // called after SetOneCodec().
1320 // TODO(hellner): this seems like an unnecessary constraint, fix it.
1321 EXPECT_TRUE(channel_->SetCapturer(1, capturer1.get()));
1322 EXPECT_TRUE(channel_->SetCapturer(2, capturer2.get()));
1323 EXPECT_TRUE(SetSend(true));
1324 EXPECT_TRUE(channel_->SetRender(true));
1325 // Test capturer associated with engine.
1326 EXPECT_TRUE(capturer1->CaptureCustomFrame(1024, 768, cricket::FOURCC_I420));
1327 EXPECT_FRAME_ON_RENDERER_WAIT(renderer1, 1, 1024, 768, kTimeout);
1328 // Capture a frame with additional capturer2, frames should be received
1329 EXPECT_TRUE(capturer2->CaptureCustomFrame(1024, 768, cricket::FOURCC_I420));
1330 EXPECT_FRAME_ON_RENDERER_WAIT(renderer2, 1, 1024, 768, kTimeout);
1331 EXPECT_FALSE(channel_->SetCapturer(kSsrc, NULL));
1332 // The capturers must be unregistered here as it runs out of it's scope
1333 // next.
1334 EXPECT_TRUE(channel_->SetCapturer(1, NULL));
1335 EXPECT_TRUE(channel_->SetCapturer(2, NULL));
1336 }
1337
1338 void HighAspectHighHeightCapturer() {
1339 const int kWidth = 80;
1340 const int kHeight = 10000;
1341 const int kScaledWidth = 20;
1342 const int kScaledHeight = 2500;
1343
1344 cricket::VideoCodec codec(DefaultCodec());
1345 EXPECT_TRUE(SetOneCodec(codec));
1346 EXPECT_TRUE(SetSend(true));
1347
1348 cricket::FakeVideoRenderer renderer;
1349 EXPECT_TRUE(channel_->AddRecvStream(
1350 cricket::StreamParams::CreateLegacy(kSsrc)));
1351 EXPECT_TRUE(channel_->SetRenderer(kSsrc, &renderer));
1352 EXPECT_TRUE(channel_->SetRender(true));
1353 EXPECT_EQ(0, renderer.num_rendered_frames());
1354
1355 EXPECT_TRUE(SendFrame());
1356 EXPECT_FRAME_ON_RENDERER_WAIT(renderer, 1, codec.width, codec.height,
1357 kTimeout);
1358
1359 // Registering an external capturer is currently the same as screen casting
1360 // (update the test when this changes).
1361 talk_base::scoped_ptr<cricket::FakeVideoCapturer> capturer(
1362 new cricket::FakeVideoCapturer);
1363 capturer->SetScreencast(true);
1364 const std::vector<cricket::VideoFormat>* formats =
1365 capturer->GetSupportedFormats();
1366 cricket::VideoFormat capture_format = (*formats)[0];
1367 EXPECT_EQ(cricket::CS_RUNNING, capturer->Start(capture_format));
1368 // Capture frame to not get same frame timestamps as previous capturer.
1369 capturer->CaptureFrame();
1370 EXPECT_TRUE(channel_->SetCapturer(kSsrc, capturer.get()));
1371 EXPECT_TRUE(talk_base::Thread::Current()->ProcessMessages(30));
1372 EXPECT_TRUE(capturer->CaptureCustomFrame(kWidth, kHeight,
1373 cricket::FOURCC_ARGB));
1374 EXPECT_TRUE(capturer->CaptureFrame());
1375 EXPECT_FRAME_ON_RENDERER_WAIT(renderer, 2, kScaledWidth, kScaledHeight,
1376 kTimeout);
1377 EXPECT_TRUE(channel_->SetCapturer(kSsrc, NULL));
1378 }
1379
1380 // Tests that we can adapt video resolution with 16:10 aspect ratio properly.
1381 void AdaptResolution16x10() {
1382 cricket::VideoCodec codec(DefaultCodec());
1383 codec.width = 640;
1384 codec.height = 400;
1385 SendAndReceive(codec);
1386 codec.width /= 2;
1387 codec.height /= 2;
1388 // Adapt the resolution.
1389 EXPECT_TRUE(SetOneCodec(codec));
1390 EXPECT_TRUE(WaitAndSendFrame(30));
1391 EXPECT_FRAME_WAIT(2, codec.width, codec.height, kTimeout);
1392 }
1393 // Tests that we can adapt video resolution with 4:3 aspect ratio properly.
1394 void AdaptResolution4x3() {
1395 cricket::VideoCodec codec(DefaultCodec());
1396 codec.width = 640;
1397 codec.height = 400;
1398 SendAndReceive(codec);
1399 codec.width /= 2;
1400 codec.height /= 2;
1401 // Adapt the resolution.
1402 EXPECT_TRUE(SetOneCodec(codec));
1403 EXPECT_TRUE(WaitAndSendFrame(30));
1404 EXPECT_FRAME_WAIT(2, codec.width, codec.height, kTimeout);
1405 }
1406 // Tests that we can drop all frames properly.
1407 void AdaptDropAllFrames() {
1408 // Set the channel codec's resolution to 0, which will require the adapter
1409 // to drop all frames.
1410 cricket::VideoCodec codec(DefaultCodec());
1411 codec.width = codec.height = codec.framerate = 0;
1412 EXPECT_TRUE(SetOneCodec(codec));
1413 EXPECT_TRUE(SetSend(true));
1414 EXPECT_TRUE(channel_->SetRender(true));
1415 EXPECT_EQ(0, renderer_.num_rendered_frames());
1416 EXPECT_TRUE(SendFrame());
1417 EXPECT_TRUE(SendFrame());
1418 talk_base::Thread::Current()->ProcessMessages(500);
1419 EXPECT_EQ(0, renderer_.num_rendered_frames());
1420 }
1421 // Tests that we can reduce the frame rate on demand properly.
1422 // TODO(fbarchard): This test is flakey on pulse. Fix and re-enable
1423 void AdaptFramerate() {
1424 cricket::VideoCodec codec(DefaultCodec());
1425 int frame_count = 0;
1426 // The capturer runs at 30 fps. The channel requires 30 fps.
1427 EXPECT_TRUE(SetOneCodec(codec));
1428 EXPECT_TRUE(SetSend(true));
1429 EXPECT_TRUE(channel_->SetRender(true));
1430 EXPECT_EQ(frame_count, renderer_.num_rendered_frames());
1431 EXPECT_TRUE(WaitAndSendFrame(0)); // Should be rendered.
1432 EXPECT_TRUE(WaitAndSendFrame(30)); // Should be rendered.
1433 frame_count += 2;
1434 EXPECT_FRAME_WAIT(frame_count, codec.width, codec.height, kTimeout);
1435 talk_base::scoped_ptr<const talk_base::Buffer> p(GetRtpPacket(0));
1436 EXPECT_EQ(codec.id, GetPayloadType(p.get()));
1437
1438 // The channel requires 15 fps.
1439 codec.framerate = 15;
1440 EXPECT_TRUE(SetOneCodec(codec));
1441 EXPECT_TRUE(WaitAndSendFrame(0)); // Should be rendered.
1442 EXPECT_TRUE(WaitAndSendFrame(30)); // Should be dropped.
1443 EXPECT_TRUE(WaitAndSendFrame(30)); // Should be rendered.
1444 frame_count += 2;
1445 EXPECT_EQ_WAIT(frame_count, renderer_.num_rendered_frames(), kTimeout);
1446
1447 // The channel requires 10 fps.
1448 codec.framerate = 10;
1449 EXPECT_TRUE(SetOneCodec(codec));
1450 EXPECT_TRUE(WaitAndSendFrame(0)); // Should be rendered.
1451 EXPECT_TRUE(WaitAndSendFrame(30)); // Should be dropped.
1452 EXPECT_TRUE(WaitAndSendFrame(30)); // Should be dropped.
1453 EXPECT_TRUE(WaitAndSendFrame(30)); // Should be rendered.
1454 frame_count += 2;
1455 EXPECT_EQ_WAIT(frame_count, renderer_.num_rendered_frames(), kTimeout);
1456
1457 // The channel requires 8 fps. The adapter adapts to 10 fps, which is the
1458 // closest factor of 30.
1459 codec.framerate = 8;
1460 EXPECT_TRUE(SetOneCodec(codec));
1461 EXPECT_TRUE(WaitAndSendFrame(0)); // Should be rendered.
1462 EXPECT_TRUE(WaitAndSendFrame(30)); // Should be dropped.
1463 EXPECT_TRUE(WaitAndSendFrame(30)); // Should be dropped.
1464 EXPECT_TRUE(WaitAndSendFrame(30)); // Should be rendered.
1465 frame_count += 2;
1466 EXPECT_EQ_WAIT(frame_count, renderer_.num_rendered_frames(), kTimeout);
1467 }
1468 // Tests that we can set the send stream format properly.
1469 void SetSendStreamFormat() {
1470 cricket::VideoCodec codec(DefaultCodec());
1471 SendAndReceive(codec);
1472 int frame_count = 1;
1473 EXPECT_FRAME_WAIT(frame_count, codec.width, codec.height, kTimeout);
1474
1475 // Adapt the resolution and frame rate to half.
1476 cricket::VideoFormat format(
1477 codec.width / 2,
1478 codec.height / 2,
1479 cricket::VideoFormat::FpsToInterval(codec.framerate / 2),
1480 cricket::FOURCC_I420);
1481 // The SSRC differs from the send SSRC.
1482 EXPECT_FALSE(channel_->SetSendStreamFormat(kSsrc - 1, format));
1483 EXPECT_TRUE(channel_->SetSendStreamFormat(kSsrc, format));
1484
1485 EXPECT_TRUE(WaitAndSendFrame(30)); // Should be dropped.
1486 EXPECT_TRUE(WaitAndSendFrame(30)); // Should be rendered.
1487 EXPECT_TRUE(WaitAndSendFrame(30)); // Should be dropped.
1488 frame_count += 1;
1489 EXPECT_FRAME_WAIT(frame_count, format.width, format.height, kTimeout);
1490
1491 // Adapt the resolution to 0x0, which should drop all frames.
1492 format.width = 0;
1493 format.height = 0;
1494 EXPECT_TRUE(channel_->SetSendStreamFormat(kSsrc, format));
1495 EXPECT_TRUE(SendFrame());
1496 EXPECT_TRUE(SendFrame());
1497 talk_base::Thread::Current()->ProcessMessages(500);
1498 EXPECT_EQ(frame_count, renderer_.num_rendered_frames());
1499 }
1500 // Test that setting send stream format to 0x0 resolution will result in
1501 // frames being dropped.
1502 void SetSendStreamFormat0x0() {
1503 EXPECT_TRUE(SetOneCodec(DefaultCodec()));
1504 EXPECT_TRUE(SetSend(true));
1505 EXPECT_TRUE(channel_->SetRender(true));
1506 EXPECT_EQ(0, renderer_.num_rendered_frames());
1507 // This frame should be received.
1508 EXPECT_TRUE(SendFrame());
1509 EXPECT_FRAME_WAIT(1, DefaultCodec().width, DefaultCodec().height, kTimeout);
1510 const int64 interval = cricket::VideoFormat::FpsToInterval(
1511 DefaultCodec().framerate);
1512 cricket::VideoFormat format(
1513 0,
1514 0,
1515 interval,
1516 cricket::FOURCC_I420);
1517 EXPECT_TRUE(channel_->SetSendStreamFormat(kSsrc, format));
1518 // This frame should not be received.
1519 EXPECT_TRUE(WaitAndSendFrame(
1520 static_cast<int>(interval/talk_base::kNumNanosecsPerMillisec)));
1521 talk_base::Thread::Current()->ProcessMessages(500);
1522 EXPECT_EQ(1, renderer_.num_rendered_frames());
1523 }
1524
1525 // Tests that we can mute and unmute the channel properly.
1526 void MuteStream() {
1527 int frame_count = 0;
1528 EXPECT_TRUE(SetDefaultCodec());
1529 cricket::FakeVideoCapturer video_capturer;
1530 video_capturer.Start(
1531 cricket::VideoFormat(
1532 640, 480,
1533 cricket::VideoFormat::FpsToInterval(30),
1534 cricket::FOURCC_I420));
1535 EXPECT_TRUE(channel_->SetCapturer(kSsrc, &video_capturer));
1536 EXPECT_TRUE(SetSend(true));
1537 EXPECT_TRUE(channel_->SetRender(true));
1538 EXPECT_EQ(frame_count, renderer_.num_rendered_frames());
1539
1540 // Mute the channel and expect black output frame.
1541 EXPECT_TRUE(channel_->MuteStream(kSsrc, true));
1542 EXPECT_TRUE(video_capturer.CaptureFrame());
1543 ++frame_count;
1544 EXPECT_EQ_WAIT(frame_count, renderer_.num_rendered_frames(), kTimeout);
1545 EXPECT_TRUE(renderer_.black_frame());
1546
1547 // Unmute the channel and expect non-black output frame.
1548 EXPECT_TRUE(channel_->MuteStream(kSsrc, false));
1549 EXPECT_TRUE(talk_base::Thread::Current()->ProcessMessages(30));
1550 EXPECT_TRUE(video_capturer.CaptureFrame());
1551 ++frame_count;
1552 EXPECT_EQ_WAIT(frame_count, renderer_.num_rendered_frames(), kTimeout);
1553 EXPECT_FALSE(renderer_.black_frame());
1554
1555 // Test that we can also Mute using the correct send stream SSRC.
1556 EXPECT_TRUE(channel_->MuteStream(kSsrc, true));
1557 EXPECT_TRUE(talk_base::Thread::Current()->ProcessMessages(30));
1558 EXPECT_TRUE(video_capturer.CaptureFrame());
1559 ++frame_count;
1560 EXPECT_EQ_WAIT(frame_count, renderer_.num_rendered_frames(), kTimeout);
1561 EXPECT_TRUE(renderer_.black_frame());
1562
1563 EXPECT_TRUE(channel_->MuteStream(kSsrc, false));
1564 EXPECT_TRUE(talk_base::Thread::Current()->ProcessMessages(30));
1565 EXPECT_TRUE(video_capturer.CaptureFrame());
1566 ++frame_count;
1567 EXPECT_EQ_WAIT(frame_count, renderer_.num_rendered_frames(), kTimeout);
1568 EXPECT_FALSE(renderer_.black_frame());
1569
1570 // Test that muting an invalid stream fails.
1571 EXPECT_FALSE(channel_->MuteStream(kSsrc+1, true));
1572 EXPECT_TRUE(channel_->SetCapturer(kSsrc, NULL));
1573 }
1574
1575 // Test that multiple send streams can be created and deleted properly.
1576 void MultipleSendStreams() {
1577 // Remove stream added in Setup. I.e. remove stream corresponding to default
1578 // channel.
1579 EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
1580 const unsigned int kSsrcsSize = sizeof(kSsrcs4)/sizeof(kSsrcs4[0]);
1581 for (unsigned int i = 0; i < kSsrcsSize; ++i) {
1582 EXPECT_TRUE(channel_->AddSendStream(
1583 cricket::StreamParams::CreateLegacy(kSsrcs4[i])));
1584 }
1585 // Delete one of the non default channel streams, let the destructor delete
1586 // the remaining ones.
1587 EXPECT_TRUE(channel_->RemoveSendStream(kSsrcs4[kSsrcsSize - 1]));
1588 // Stream should already be deleted.
1589 EXPECT_FALSE(channel_->RemoveSendStream(kSsrcs4[kSsrcsSize - 1]));
1590 }
1591
1592
1593 // Two streams one channel tests.
1594
1595 // Tests that we can send and receive frames.
1596 void TwoStreamsSendAndReceive(const cricket::VideoCodec& codec) {
1597 SetUpSecondStream();
1598 // Test sending and receiving on first stream.
1599 SendAndReceive(codec);
1600 // Test sending and receiving on second stream.
1601 EXPECT_EQ_WAIT(1, renderer2_.num_rendered_frames(), kTimeout);
1602 EXPECT_EQ(2, NumRtpPackets());
1603 EXPECT_EQ(1, renderer2_.num_rendered_frames());
1604 }
1605
1606 // Disconnect the first stream and re-use it with another SSRC
1607 void TwoStreamsReUseFirstStream(const cricket::VideoCodec& codec) {
1608 SetUpSecondStream();
1609 EXPECT_TRUE(channel_->RemoveRecvStream(kSsrc));
1610 EXPECT_FALSE(channel_->RemoveRecvStream(kSsrc));
1611 // SSRC 0 should map to the "default" stream. I.e. the first added stream.
1612 EXPECT_TRUE(channel_->RemoveSendStream(0));
1613 // Make sure that the first added stream was indeed the "default" stream.
1614 EXPECT_FALSE(channel_->RemoveSendStream(kSsrc));
1615 // Make sure that the "default" stream is indeed removed and that removing
1616 // the default stream has an effect.
1617 EXPECT_FALSE(channel_->RemoveSendStream(0));
1618
1619 SetRendererAsDefault();
1620 EXPECT_TRUE(channel_->AddSendStream(
1621 cricket::StreamParams::CreateLegacy(kSsrc)));
1622 EXPECT_FALSE(channel_->AddSendStream(
1623 cricket::StreamParams::CreateLegacy(kSsrc)));
1624 EXPECT_TRUE(channel_->AddRecvStream(
1625 cricket::StreamParams::CreateLegacy(kSsrc)));
1626 EXPECT_FALSE(channel_->AddRecvStream(
1627 cricket::StreamParams::CreateLegacy(kSsrc)));
1628
1629 SendAndReceive(codec);
1630 EXPECT_TRUE(channel_->RemoveSendStream(0));
1631 }
1632
1633 VideoEngineOverride<E> engine_;
1634 talk_base::scoped_ptr<cricket::FakeVideoCapturer> video_capturer_;
1635 talk_base::scoped_ptr<C> channel_;
1636 cricket::FakeNetworkInterface network_interface_;
1637 cricket::FakeVideoRenderer renderer_;
1638 cricket::VideoMediaChannel::Error media_error_;
1639
1640 // Used by test cases where 2 streams are run on the same channel.
1641 cricket::FakeVideoRenderer renderer2_;
1642};
1643
1644#endif // TALK_MEDIA_BASE_VIDEOENGINE_UNITTEST_H_