webrtc/talk/media/webrtc/webrtcvideoengine_unittest.cc
Shao Changbin e62202fedf Support handling multiple RTX but only generate SDP with RTX associated with VP8.
This implementation registers RTX-APT map inside RTP sender and receiver.
While it only generates SDP with RTX associated with VP8 to make it
compatible with previous Chrome versions.

Should add following changes after reaches stable,
* Use RTX-APT map for building and restoring RTP packets.
* Add RTX support for RED or VP9 in Video engine.
* Set RTX payload type for RED inside FecConfig in EndToEndTest.

BUG=4024
R=mflodman@webrtc.org, pbos@webrtc.org, pthatcher@webrtc.org, stefan@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/36889004

Cr-Commit-Position: refs/heads/master@{#9040}
2015-04-21 12:25:42 +00:00

4645 lines
184 KiB
C++

/*
* libjingle
* Copyright 2004 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <algorithm>
#include "talk/media/base/constants.h"
#include "talk/media/base/fakenetworkinterface.h"
#include "talk/media/base/fakevideorenderer.h"
#include "talk/media/base/mediachannel.h"
#include "talk/media/base/testutils.h"
#include "talk/media/base/videoadapter.h"
#include "talk/media/base/videoengine_unittest.h"
#include "talk/media/webrtc/fakewebrtcvideoengine.h"
#include "talk/media/webrtc/simulcast.h"
#include "talk/media/webrtc/webrtcvideoengine.h"
#include "talk/media/webrtc/webrtcvideoframe.h"
#include "talk/media/webrtc/webrtcvoiceengine.h"
#include "talk/session/media/mediasession.h"
#include "webrtc/base/fakecpumonitor.h"
#include "webrtc/base/gunit.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/stream.h"
#include "webrtc/system_wrappers/interface/trace.h"
// Tests for the WebRtcVideoEngine/VideoChannel code.
using cricket::kRtpTimestampOffsetHeaderExtension;
using cricket::kRtpAbsoluteSenderTimeHeaderExtension;
using cricket::kRtpVideoRotationHeaderExtension;
static const cricket::VideoCodec kVP8Codec720p(100, "VP8", 1280, 720, 30, 0);
static const cricket::VideoCodec kVP8Codec360p(100, "VP8", 640, 360, 30, 0);
static const cricket::VideoCodec kVP8Codec270p(100, "VP8", 480, 270, 30, 0);
static const cricket::VideoCodec kVP8Codec(100, "VP8", 640, 400, 30, 0);
static const cricket::VideoCodec kH264Codec(127, "H264", 640, 400, 30, 0);
static const cricket::VideoCodec kRedCodec(101, "red", 0, 0, 0, 0);
static const cricket::VideoCodec kUlpFecCodec(102, "ulpfec", 0, 0, 0, 0);
static const cricket::VideoCodec* const kVideoCodecs[] = {
&kVP8Codec,
&kRedCodec,
&kUlpFecCodec
};
static const unsigned int kStartBandwidthKbps = 300;
static const unsigned int kMinBandwidthKbps = 30;
static const unsigned int kMaxBandwidthKbps = 2000;
static const uint32 kSsrcs1[] = {1};
static const uint32 kSsrcs2[] = {1, 2};
static const uint32 kSsrcs3[] = {1, 2, 3};
static const uint32 kRtxSsrcs1[] = {4};
static const uint32 kRtxSsrcs3[] = {4, 5, 6};
static const int kPayloadTypes1[] = {96};
static const int kPayloadTypes2[] = {96, 97};
class FakeViEWrapper : public cricket::ViEWrapper {
public:
explicit FakeViEWrapper(cricket::FakeWebRtcVideoEngine* engine)
: cricket::ViEWrapper(engine, // base
engine, // codec
engine, // capture
engine, // network
engine, // render
engine, // rtp
engine, // image
engine) { // external decoder
}
};
// Test fixture to test WebRtcVideoEngine with a fake webrtc::VideoEngine.
// Useful for testing failure paths.
class WebRtcVideoEngineTestFake : public testing::Test,
public sigslot::has_slots<> {
public:
WebRtcVideoEngineTestFake()
: vie_(kVideoCodecs, ARRAY_SIZE(kVideoCodecs)),
cpu_monitor_(new rtc::FakeCpuMonitor(
rtc::Thread::Current())),
engine_(NULL, // cricket::WebRtcVoiceEngine
new FakeViEWrapper(&vie_), cpu_monitor_),
channel_(NULL),
voice_channel_(NULL),
last_error_(cricket::VideoMediaChannel::ERROR_NONE) {
}
bool SetupEngine() {
bool result = engine_.Init(rtc::Thread::Current());
if (result) {
channel_ = engine_.CreateChannel(cricket::VideoOptions(), voice_channel_);
channel_->SignalMediaError.connect(this,
&WebRtcVideoEngineTestFake::OnMediaError);
result = (channel_ != NULL);
}
return result;
}
void OnMediaError(uint32 ssrc, cricket::VideoMediaChannel::Error error) {
last_error_ = error;
}
bool SendI420Frame(int width, int height) {
if (NULL == channel_) {
return false;
}
cricket::WebRtcVideoFrame frame;
if (!frame.InitToBlack(width, height, 1, 1, 0, 0)) {
return false;
}
cricket::FakeVideoCapturer capturer;
channel_->SendFrame(&capturer, &frame);
return true;
}
bool SendI420ScreencastFrame(int width, int height) {
return SendI420ScreencastFrameWithTimestamp(width, height, 0);
}
bool SendI420ScreencastFrameWithTimestamp(
int width, int height, int64 timestamp) {
if (NULL == channel_) {
return false;
}
cricket::WebRtcVideoFrame frame;
if (!frame.InitToBlack(width, height, 1, 1, 0, 0)) {
return false;
}
cricket::FakeVideoCapturer capturer;
capturer.SetScreencast(true);
channel_->SendFrame(&capturer, &frame);
return true;
}
void TestSetSendRtpHeaderExtensions(const std::string& ext) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
// Verify extensions are off by default.
EXPECT_EQ(-1, vie_.GetSendRtpExtensionId(channel_num, ext));
// Enable extension.
const int id = 1;
std::vector<cricket::RtpHeaderExtension> extensions;
extensions.push_back(cricket::RtpHeaderExtension(ext, id));
// Verify the send extension id.
EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
EXPECT_EQ(id, vie_.GetSendRtpExtensionId(channel_num, ext));
// Verify call with same set of extensions returns true.
EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
EXPECT_EQ(id, vie_.GetSendRtpExtensionId(channel_num, ext));
// Add a new send stream and verify the extension is set.
// The first send stream to occupy the default channel.
EXPECT_TRUE(
channel_->AddSendStream(cricket::StreamParams::CreateLegacy(123)));
EXPECT_TRUE(
channel_->AddSendStream(cricket::StreamParams::CreateLegacy(234)));
int new_send_channel_num = vie_.GetLastChannel();
EXPECT_NE(channel_num, new_send_channel_num);
EXPECT_EQ(id, vie_.GetSendRtpExtensionId(new_send_channel_num, ext));
// Remove the extension id.
std::vector<cricket::RtpHeaderExtension> empty_extensions;
EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(empty_extensions));
EXPECT_EQ(-1, vie_.GetSendRtpExtensionId(channel_num, ext));
EXPECT_EQ(-1, vie_.GetSendRtpExtensionId(new_send_channel_num, ext));
}
void TestSetRecvRtpHeaderExtensions(const std::string& ext) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
// Verify extensions are off by default.
EXPECT_EQ(-1, vie_.GetReceiveRtpExtensionId(channel_num, ext));
// Enable extension.
const int id = 2;
std::vector<cricket::RtpHeaderExtension> extensions;
extensions.push_back(cricket::RtpHeaderExtension(ext, id));
// Verify receive extension id.
EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
EXPECT_EQ(id, vie_.GetReceiveRtpExtensionId(channel_num, ext));
// Verify call with same set of extensions returns true.
EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(extensions));
EXPECT_EQ(id, vie_.GetReceiveRtpExtensionId(channel_num, ext));
// Add a new receive stream and verify the extension is set.
// The first send stream to occupy the default channel.
EXPECT_TRUE(
channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(345)));
EXPECT_TRUE(
channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(456)));
int new_recv_channel_num = vie_.GetLastChannel();
EXPECT_NE(channel_num, new_recv_channel_num);
EXPECT_EQ(id, vie_.GetReceiveRtpExtensionId(new_recv_channel_num, ext));
// Remove the extension id.
std::vector<cricket::RtpHeaderExtension> empty_extensions;
EXPECT_TRUE(channel_->SetRecvRtpHeaderExtensions(empty_extensions));
EXPECT_EQ(-1, vie_.GetReceiveRtpExtensionId(channel_num, ext));
EXPECT_EQ(-1, vie_.GetReceiveRtpExtensionId(new_recv_channel_num, ext));
}
void VerifyCodecFeedbackParams(const cricket::VideoCodec& codec) {
EXPECT_TRUE(codec.HasFeedbackParam(
cricket::FeedbackParam(cricket::kRtcpFbParamNack,
cricket::kParamValueEmpty)));
EXPECT_TRUE(codec.HasFeedbackParam(
cricket::FeedbackParam(cricket::kRtcpFbParamNack,
cricket::kRtcpFbNackParamPli)));
EXPECT_TRUE(codec.HasFeedbackParam(
cricket::FeedbackParam(cricket::kRtcpFbParamRemb,
cricket::kParamValueEmpty)));
EXPECT_TRUE(codec.HasFeedbackParam(
cricket::FeedbackParam(cricket::kRtcpFbParamCcm,
cricket::kRtcpFbCcmParamFir)));
}
void VerifyVP8SendCodec(int channel_num,
unsigned int width,
unsigned int height,
unsigned int layers = 0,
unsigned int max_bitrate = kMaxBandwidthKbps,
unsigned int min_bitrate = kMinBandwidthKbps,
unsigned int start_bitrate = kStartBandwidthKbps,
unsigned int fps = 30,
unsigned int max_quantization = 0
) {
webrtc::VideoCodec gcodec;
EXPECT_EQ(0, vie_.GetSendCodec(channel_num, gcodec));
// Video codec properties.
EXPECT_EQ(webrtc::kVideoCodecVP8, gcodec.codecType);
EXPECT_STREQ("VP8", gcodec.plName);
EXPECT_EQ(100, gcodec.plType);
EXPECT_EQ(width, gcodec.width);
EXPECT_EQ(height, gcodec.height);
EXPECT_EQ(std::min(start_bitrate, max_bitrate), gcodec.startBitrate);
EXPECT_EQ(max_bitrate, gcodec.maxBitrate);
EXPECT_EQ(min_bitrate, gcodec.minBitrate);
EXPECT_EQ(fps, gcodec.maxFramerate);
// VP8 specific.
EXPECT_FALSE(gcodec.codecSpecific.VP8.pictureLossIndicationOn);
EXPECT_FALSE(gcodec.codecSpecific.VP8.feedbackModeOn);
EXPECT_EQ(webrtc::kComplexityNormal, gcodec.codecSpecific.VP8.complexity);
EXPECT_EQ(webrtc::kResilienceOff, gcodec.codecSpecific.VP8.resilience);
EXPECT_EQ(max_quantization, gcodec.qpMax);
}
virtual void TearDown() {
delete channel_;
engine_.Terminate();
}
protected:
cricket::FakeWebRtcVideoEngine vie_;
cricket::FakeWebRtcVideoDecoderFactory decoder_factory_;
cricket::FakeWebRtcVideoEncoderFactory encoder_factory_;
rtc::FakeCpuMonitor* cpu_monitor_;
cricket::WebRtcVideoEngine engine_;
cricket::WebRtcVideoMediaChannel* channel_;
cricket::WebRtcVoiceMediaChannel* voice_channel_;
cricket::VideoMediaChannel::Error last_error_;
};
// Test fixtures to test WebRtcVideoEngine with a real webrtc::VideoEngine.
class WebRtcVideoEngineTest
: public VideoEngineTest<cricket::WebRtcVideoEngine> {
protected:
typedef VideoEngineTest<cricket::WebRtcVideoEngine> Base;
};
class WebRtcVideoMediaChannelTest
: public VideoMediaChannelTest<
cricket::WebRtcVideoEngine, cricket::WebRtcVideoMediaChannel> {
protected:
typedef VideoMediaChannelTest<cricket::WebRtcVideoEngine,
cricket::WebRtcVideoMediaChannel> Base;
virtual cricket::VideoCodec DefaultCodec() { return kVP8Codec; }
virtual void SetUp() {
Base::SetUp();
}
virtual void TearDown() {
Base::TearDown();
}
};
/////////////////////////
// Tests with fake ViE //
/////////////////////////
// Tests that our stub library "works".
TEST_F(WebRtcVideoEngineTestFake, StartupShutdown) {
EXPECT_FALSE(vie_.IsInited());
EXPECT_TRUE(engine_.Init(rtc::Thread::Current()));
EXPECT_TRUE(vie_.IsInited());
engine_.Terminate();
}
// Tests that webrtc logs are logged when they should be.
TEST_F(WebRtcVideoEngineTest, WebRtcShouldLog) {
const char webrtc_log[] = "WebRtcVideoEngineTest.WebRtcShouldLog";
EXPECT_TRUE(engine_.Init(rtc::Thread::Current()));
engine_.SetLogging(rtc::LS_INFO, "");
std::string str;
rtc::StringStream stream(str);
rtc::LogMessage::AddLogToStream(&stream, rtc::LS_INFO);
EXPECT_EQ(rtc::LS_INFO, rtc::LogMessage::GetLogToStream(&stream));
webrtc::Trace::Add(webrtc::kTraceStateInfo, webrtc::kTraceUndefined, 0,
webrtc_log);
rtc::Thread::Current()->ProcessMessages(100);
rtc::LogMessage::RemoveLogToStream(&stream);
// Access |str| after LogMessage is done with it to avoid data racing.
EXPECT_NE(std::string::npos, str.find(webrtc_log));
}
// Tests that webrtc logs are not logged when they should't be.
TEST_F(WebRtcVideoEngineTest, WebRtcShouldNotLog) {
const char webrtc_log[] = "WebRtcVideoEngineTest.WebRtcShouldNotLog";
EXPECT_TRUE(engine_.Init(rtc::Thread::Current()));
// WebRTC should never be logged lower than LS_INFO.
engine_.SetLogging(rtc::LS_WARNING, "");
std::string str;
rtc::StringStream stream(str);
// Make sure that WebRTC is not logged, even at lowest severity
rtc::LogMessage::AddLogToStream(&stream, rtc::LS_SENSITIVE);
EXPECT_EQ(rtc::LS_SENSITIVE,
rtc::LogMessage::GetLogToStream(&stream));
webrtc::Trace::Add(webrtc::kTraceStateInfo, webrtc::kTraceUndefined, 0,
webrtc_log);
rtc::Thread::Current()->ProcessMessages(10);
EXPECT_EQ(std::string::npos, str.find(webrtc_log));
rtc::LogMessage::RemoveLogToStream(&stream);
}
// Tests that we can create and destroy a channel.
TEST_F(WebRtcVideoEngineTestFake, CreateChannel) {
EXPECT_TRUE(engine_.Init(rtc::Thread::Current()));
channel_ = engine_.CreateChannel(cricket::VideoOptions(), voice_channel_);
EXPECT_TRUE(channel_ != NULL);
EXPECT_EQ(1, engine_.GetNumOfChannels());
delete channel_;
channel_ = NULL;
EXPECT_EQ(0, engine_.GetNumOfChannels());
}
// Tests that we properly handle failures in CreateChannel.
TEST_F(WebRtcVideoEngineTestFake, CreateChannelFail) {
vie_.set_fail_create_channel(true);
EXPECT_TRUE(engine_.Init(rtc::Thread::Current()));
channel_ = engine_.CreateChannel(cricket::VideoOptions(), voice_channel_);
EXPECT_TRUE(channel_ == NULL);
}
// Tests that we properly handle failures in AllocateExternalCaptureDevice.
TEST_F(WebRtcVideoEngineTestFake, AllocateExternalCaptureDeviceFail) {
vie_.set_fail_alloc_capturer(true);
EXPECT_TRUE(engine_.Init(rtc::Thread::Current()));
channel_ = engine_.CreateChannel(cricket::VideoOptions(), voice_channel_);
EXPECT_TRUE(channel_ == NULL);
}
// Test that we apply our default codecs properly.
TEST_F(WebRtcVideoEngineTestFake, SetSendCodecs) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs(engine_.codecs());
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(vie_.GetHybridNackFecStatus(channel_num));
EXPECT_FALSE(vie_.GetNackStatus(channel_num));
EXPECT_EQ(1, vie_.GetNumSetSendCodecs());
// TODO(juberti): Check RTCP, PLI, TMMBR.
}
TEST_F(WebRtcVideoEngineTestFake, SetSendCodecsBeforeFrameRegistersTinyFormat) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs(engine_.codecs());
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
VerifyVP8SendCodec(channel_num, 176, 144);
}
// Test that ViE Channel doesn't call SetSendCodec again if same codec is tried
// to apply.
TEST_F(WebRtcVideoEngineTestFake, DontResetSetSendCodec) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs(engine_.codecs());
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(vie_.GetHybridNackFecStatus(channel_num));
EXPECT_FALSE(vie_.GetNackStatus(channel_num));
EXPECT_EQ(1, vie_.GetNumSetSendCodecs());
// Try setting same code again.
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
// Since it's exact same codec which is already set, media channel shouldn't
// send the codec to ViE.
EXPECT_EQ(1, vie_.GetNumSetSendCodecs());
}
TEST_F(WebRtcVideoEngineTestFake, SetSendCodecsWithMinMaxBitrate) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs(engine_.codecs());
codecs[0].params[cricket::kCodecParamMinBitrate] = "10";
codecs[0].params[cricket::kCodecParamMaxBitrate] = "20";
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
VerifyVP8SendCodec(
channel_num, kVP8Codec.width, kVP8Codec.height, 0, 20, 10, 20);
cricket::VideoCodec codec;
EXPECT_TRUE(channel_->GetSendCodec(&codec));
EXPECT_EQ("10", codec.params[cricket::kCodecParamMinBitrate]);
EXPECT_EQ("20", codec.params[cricket::kCodecParamMaxBitrate]);
}
TEST_F(WebRtcVideoEngineTestFake, SetSendCodecsWithStartBitrate) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs(engine_.codecs());
codecs[0].params[cricket::kCodecParamStartBitrate] = "450";
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
VerifyVP8SendCodec(channel_num,
kVP8Codec.width,
kVP8Codec.height,
0,
kMaxBandwidthKbps,
kMinBandwidthKbps,
450);
cricket::VideoCodec codec;
EXPECT_TRUE(channel_->GetSendCodec(&codec));
EXPECT_EQ("450", codec.params[cricket::kCodecParamStartBitrate]);
}
TEST_F(WebRtcVideoEngineTestFake, SetSendCodecsWithMinMaxStartBitrate) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs(engine_.codecs());
codecs[0].params[cricket::kCodecParamMinBitrate] = "10";
codecs[0].params[cricket::kCodecParamMaxBitrate] = "20";
codecs[0].params[cricket::kCodecParamStartBitrate] = "14";
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
VerifyVP8SendCodec(
channel_num, kVP8Codec.width, kVP8Codec.height, 0, 20, 10, 14);
cricket::VideoCodec codec;
EXPECT_TRUE(channel_->GetSendCodec(&codec));
EXPECT_EQ("10", codec.params[cricket::kCodecParamMinBitrate]);
EXPECT_EQ("20", codec.params[cricket::kCodecParamMaxBitrate]);
EXPECT_EQ("14", codec.params[cricket::kCodecParamStartBitrate]);
}
TEST_F(WebRtcVideoEngineTestFake, SetSendCodecsWithMinMaxBitrateInvalid) {
EXPECT_TRUE(SetupEngine());
std::vector<cricket::VideoCodec> codecs(engine_.codecs());
codecs[0].params[cricket::kCodecParamMinBitrate] = "30";
codecs[0].params[cricket::kCodecParamMaxBitrate] = "20";
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_FALSE(channel_->SetSendCodecs(codecs));
}
TEST_F(WebRtcVideoEngineTestFake, SetSendCodecsWithLargeMinMaxBitrate) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs(engine_.codecs());
codecs[0].params[cricket::kCodecParamMinBitrate] = "1000";
codecs[0].params[cricket::kCodecParamMaxBitrate] = "3000";
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
VerifyVP8SendCodec(
channel_num, kVP8Codec.width, kVP8Codec.height, 0, 3000, 1000,
1000);
}
TEST_F(WebRtcVideoEngineTestFake, SetSendCodecsWithMaxQuantization) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs(engine_.codecs());
codecs[0].params[cricket::kCodecParamMaxQuantization] = "21";
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
VerifyVP8SendCodec(channel_num,
kVP8Codec.width,
kVP8Codec.height,
0,
kMaxBandwidthKbps,
kMinBandwidthKbps,
300,
30,
21);
cricket::VideoCodec codec;
EXPECT_TRUE(channel_->GetSendCodec(&codec));
EXPECT_EQ("21", codec.params[cricket::kCodecParamMaxQuantization]);
}
TEST_F(WebRtcVideoEngineTestFake, SetOptionsWithMaxBitrate) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs(engine_.codecs());
codecs[0].params[cricket::kCodecParamMinBitrate] = "10";
codecs[0].params[cricket::kCodecParamMaxBitrate] = "20";
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
VerifyVP8SendCodec(
channel_num, kVP8Codec.width, kVP8Codec.height, 0, 20, 10, 20);
// Verify that max bitrate doesn't change after SetOptions().
cricket::VideoOptions options;
options.video_noise_reduction.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
VerifyVP8SendCodec(
channel_num, kVP8Codec.width, kVP8Codec.height, 0, 20, 10, 20);
options.video_noise_reduction.Set(false);
options.conference_mode.Set(false);
EXPECT_TRUE(channel_->SetOptions(options));
VerifyVP8SendCodec(
channel_num, kVP8Codec.width, kVP8Codec.height, 0, 20, 10, 20);
}
TEST_F(WebRtcVideoEngineTestFake, MaxBitrateResetWithConferenceMode) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs(engine_.codecs());
codecs[0].params[cricket::kCodecParamMinBitrate] = "10";
codecs[0].params[cricket::kCodecParamMaxBitrate] = "20";
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
VerifyVP8SendCodec(
channel_num, kVP8Codec.width, kVP8Codec.height, 0, 20, 10, 20);
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
options.conference_mode.Set(false);
EXPECT_TRUE(channel_->SetOptions(options));
VerifyVP8SendCodec(
channel_num, kVP8Codec.width, kVP8Codec.height, 0,
kMaxBandwidthKbps, 10, kStartBandwidthKbps);
}
// Verify the current send bitrate is used as start bitrate when reconfiguring
// the send codec.
TEST_F(WebRtcVideoEngineTestFake, StartSendBitrate) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(1)));
int send_channel = vie_.GetLastChannel();
cricket::VideoCodec codec(kVP8Codec);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
VerifyVP8SendCodec(send_channel, kVP8Codec.width, kVP8Codec.height, 0,
kMaxBandwidthKbps, kMinBandwidthKbps,
kStartBandwidthKbps);
EXPECT_EQ(0, vie_.StartSend(send_channel));
// Increase the send bitrate and verify it is used as start bitrate.
const unsigned int kIncreasedSendBitrateBps = 768000;
vie_.SetSendBitrates(send_channel, kIncreasedSendBitrateBps, 0, 0);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
VerifyVP8SendCodec(send_channel, kVP8Codec.width, kVP8Codec.height, 0,
kMaxBandwidthKbps, kMinBandwidthKbps,
kIncreasedSendBitrateBps / 1000);
// Never set a start bitrate higher than the max bitrate.
vie_.SetSendBitrates(send_channel, kMaxBandwidthKbps + 500, 0, 0);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
VerifyVP8SendCodec(send_channel, kVP8Codec.width, kVP8Codec.height, 0,
kMaxBandwidthKbps, kMinBandwidthKbps,
kStartBandwidthKbps);
// Use the default start bitrate if the send bitrate is lower.
vie_.SetSendBitrates(send_channel, kStartBandwidthKbps - 50, 0,
0);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
VerifyVP8SendCodec(send_channel, kVP8Codec.width, kVP8Codec.height, 0,
kMaxBandwidthKbps, kMinBandwidthKbps,
kStartBandwidthKbps);
}
// Test that we constrain send codecs properly.
TEST_F(WebRtcVideoEngineTestFake, ConstrainSendCodecs) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
// Set max settings of 640x400x30.
EXPECT_TRUE(engine_.SetDefaultEncoderConfig(
cricket::VideoEncoderConfig(kVP8Codec)));
// Send codec format bigger than max setting.
cricket::VideoCodec codec(kVP8Codec);
codec.width = 1280;
codec.height = 800;
codec.framerate = 60;
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
// Set send codec and verify codec has been constrained.
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height);
}
// Test that SetSendCodecs rejects bad format.
TEST_F(WebRtcVideoEngineTestFake, SetSendCodecsRejectBadFormat) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
// Set w = 0.
cricket::VideoCodec codec(kVP8Codec);
codec.width = 0;
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
// Verify SetSendCodecs failed and send codec is not changed on engine.
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_FALSE(channel_->SetSendCodecs(codec_list));
webrtc::VideoCodec gcodec;
// Set plType to something other than the value to test against ensuring
// that failure will happen if it is not changed.
gcodec.plType = 1;
EXPECT_EQ(0, vie_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(0, gcodec.plType);
// Set h = 0.
codec_list[0].width = 640;
codec_list[0].height = 0;
// Verify SetSendCodecs failed and send codec is not changed on engine.
EXPECT_FALSE(channel_->SetSendCodecs(codec_list));
// Set plType to something other than the value to test against ensuring
// that failure will happen if it is not changed.
gcodec.plType = 1;
EXPECT_EQ(0, vie_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(0, gcodec.plType);
}
// Test that SetSendCodecs rejects bad codec.
TEST_F(WebRtcVideoEngineTestFake, SetSendCodecsRejectBadCodec) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
// Set bad codec name.
cricket::VideoCodec codec(kVP8Codec);
codec.name = "bad";
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
// Verify SetSendCodecs failed and send codec is not changed on engine.
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_FALSE(channel_->SetSendCodecs(codec_list));
webrtc::VideoCodec gcodec;
// Set plType to something other than the value to test against ensuring
// that failure will happen if it is not changed.
gcodec.plType = 1;
EXPECT_EQ(0, vie_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(0, gcodec.plType);
}
// Test that vie send codec is reset on new video frame size.
TEST_F(WebRtcVideoEngineTestFake, ResetVieSendCodecOnNewFrameSize) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
// Set send codec.
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(kVP8Codec);
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(123)));
EXPECT_TRUE(channel_->SetSend(true));
// Capture a smaller frame and verify vie send codec has been reset to
// the new size.
SendI420Frame(kVP8Codec.width / 2, kVP8Codec.height / 2);
VerifyVP8SendCodec(channel_num, kVP8Codec.width / 2, kVP8Codec.height / 2);
// Capture a frame bigger than send_codec_ and verify vie send codec has been
// reset (and clipped) to send_codec_.
SendI420Frame(kVP8Codec.width * 2, kVP8Codec.height * 2);
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height);
}
// Test that we set our inbound codecs properly.
TEST_F(WebRtcVideoEngineTestFake, SetRecvCodecs) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
webrtc::VideoCodec wcodec;
EXPECT_TRUE(engine_.ConvertFromCricketVideoCodec(kVP8Codec, &wcodec));
EXPECT_TRUE(vie_.ReceiveCodecRegistered(channel_num, wcodec));
}
// Test that we set our inbound RTX codecs properly.
TEST_F(WebRtcVideoEngineTestFake, SetRecvCodecsWithRtx) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs;
cricket::VideoCodec rtx_codec(96, "rtx", 0, 0, 0, 0);
codecs.push_back(rtx_codec);
// Should fail since there's no associated payload type set.
EXPECT_FALSE(channel_->SetRecvCodecs(codecs));
codecs[0].SetParam("apt", 97);
// Should still fail since the we don't support RTX on this APT.
EXPECT_FALSE(channel_->SetRecvCodecs(codecs));
codecs[0].SetParam("apt", kVP8Codec.id);
// Should still fail since the associated payload type is unknown.
EXPECT_FALSE(channel_->SetRecvCodecs(codecs));
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
webrtc::VideoCodec wcodec;
// Should not have been registered as a WebRTC codec.
EXPECT_TRUE(engine_.ConvertFromCricketVideoCodec(rtx_codec, &wcodec));
EXPECT_STREQ("rtx", wcodec.plName);
EXPECT_FALSE(vie_.ReceiveCodecRegistered(channel_num, wcodec));
EXPECT_EQ(vie_.GetRtxRecvPayloadTypes(channel_num),
MAKE_VECTOR(kPayloadTypes1));
}
// Test that RTX packets are routed to the default video channel if
// there's only one recv stream.
TEST_F(WebRtcVideoEngineTestFake, TestReceiveRtxOneStream) {
EXPECT_TRUE(SetupEngine());
// Setup one channel with an associated RTX stream.
cricket::StreamParams params =
cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
EXPECT_TRUE(channel_->AddRecvStream(params));
int channel_num = vie_.GetLastChannel();
EXPECT_EQ(static_cast<int>(kRtxSsrcs1[0]),
vie_.GetRemoteRtxSsrc(channel_num));
// Register codecs.
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(kVP8Codec720p);
cricket::VideoCodec rtx_codec(96, "rtx", 0, 0, 0, 0);
rtx_codec.SetParam("apt", kVP8Codec.id);
codec_list.push_back(rtx_codec);
EXPECT_TRUE(channel_->SetRecvCodecs(codec_list));
// Construct a fake RTX packet and verify that it is passed to the
// right WebRTC channel.
const size_t kDataLength = 12;
uint8_t data[kDataLength];
memset(data, 0, sizeof(data));
data[0] = 0x80;
data[1] = rtx_codec.id;
rtc::SetBE32(&data[8], kRtxSsrcs1[0]);
rtc::Buffer packet(data, kDataLength);
rtc::PacketTime packet_time;
channel_->OnPacketReceived(&packet, packet_time);
EXPECT_EQ(rtx_codec.id, vie_.GetLastRecvdPayloadType(channel_num));
}
// Verify we don't crash when inserting packets after removing the default
// receive channel.
TEST_F(WebRtcVideoEngineTestFake, TestReceiveRtxWithRemovedDefaultChannel) {
EXPECT_TRUE(SetupEngine());
// Setup one channel with an associated RTX stream.
cricket::StreamParams params =
cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
EXPECT_TRUE(channel_->AddRecvStream(params));
int channel_num = vie_.GetLastChannel();
EXPECT_EQ(static_cast<int>(kRtxSsrcs1[0]),
vie_.GetRemoteRtxSsrc(channel_num));
// Register codecs.
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(kVP8Codec720p);
cricket::VideoCodec rtx_codec(96, "rtx", 0, 0, 0, 0);
rtx_codec.SetParam("apt", kVP8Codec.id);
codec_list.push_back(rtx_codec);
EXPECT_TRUE(channel_->SetRecvCodecs(codec_list));
// Construct a fake RTX packet and verify that it is passed to the
// right WebRTC channel.
const size_t kDataLength = 12;
uint8_t data[kDataLength];
memset(data, 0, sizeof(data));
data[0] = 0x80;
data[1] = rtx_codec.id;
rtc::SetBE32(&data[8], kRtxSsrcs1[0]);
rtc::Buffer packet(data, kDataLength);
rtc::PacketTime packet_time;
channel_->OnPacketReceived(&packet, packet_time);
EXPECT_EQ(rtx_codec.id, vie_.GetLastRecvdPayloadType(channel_num));
// Remove the default channel and insert one more packet.
EXPECT_TRUE(channel_->RemoveRecvStream(kSsrcs1[0]));
channel_->OnPacketReceived(&packet, packet_time);
}
// Test that RTX packets are routed to the correct video channel.
TEST_F(WebRtcVideoEngineTestFake, TestReceiveRtxThreeStreams) {
EXPECT_TRUE(SetupEngine());
// Setup three channels with associated RTX streams.
int channel_num[ARRAY_SIZE(kSsrcs3)];
for (size_t i = 0; i < ARRAY_SIZE(kSsrcs3); ++i) {
cricket::StreamParams params =
cricket::StreamParams::CreateLegacy(kSsrcs3[i]);
params.AddFidSsrc(kSsrcs3[i], kRtxSsrcs3[i]);
EXPECT_TRUE(channel_->AddRecvStream(params));
channel_num[i] = vie_.GetLastChannel();
}
// Register codecs.
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(kVP8Codec720p);
cricket::VideoCodec rtx_codec(96, "rtx", 0, 0, 0, 0);
rtx_codec.SetParam("apt", kVP8Codec.id);
codec_list.push_back(rtx_codec);
EXPECT_TRUE(channel_->SetRecvCodecs(codec_list));
// Construct a fake RTX packet and verify that it is passed to the
// right WebRTC channel.
const size_t kDataLength = 12;
uint8_t data[kDataLength];
memset(data, 0, sizeof(data));
data[0] = 0x80;
data[1] = rtx_codec.id;
rtc::SetBE32(&data[8], kRtxSsrcs3[1]);
rtc::Buffer packet(data, kDataLength);
rtc::PacketTime packet_time;
channel_->OnPacketReceived(&packet, packet_time);
EXPECT_NE(rtx_codec.id, vie_.GetLastRecvdPayloadType(channel_num[0]));
EXPECT_EQ(rtx_codec.id, vie_.GetLastRecvdPayloadType(channel_num[1]));
EXPECT_NE(rtx_codec.id, vie_.GetLastRecvdPayloadType(channel_num[2]));
}
// Test that channel connects and disconnects external capturer correctly.
TEST_F(WebRtcVideoEngineTestFake, HasExternalCapturer) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
EXPECT_EQ(1, vie_.GetNumCapturers());
int capture_id = vie_.GetCaptureId(channel_num);
EXPECT_EQ(channel_num, vie_.GetCaptureChannelId(capture_id));
// Delete the channel should disconnect the capturer.
delete channel_;
channel_ = NULL;
EXPECT_EQ(0, vie_.GetNumCapturers());
}
// Test that channel adds and removes renderer correctly.
TEST_F(WebRtcVideoEngineTestFake, HasRenderer) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
EXPECT_TRUE(vie_.GetHasRenderer(channel_num));
EXPECT_FALSE(vie_.GetRenderStarted(channel_num));
}
// Test that rtcp is enabled on the channel.
TEST_F(WebRtcVideoEngineTestFake, RtcpEnabled) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
EXPECT_EQ(webrtc::kRtcpCompound_RFC4585, vie_.GetRtcpStatus(channel_num));
}
// Test that key frame request method is set on the channel.
TEST_F(WebRtcVideoEngineTestFake, KeyFrameRequestEnabled) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
EXPECT_EQ(webrtc::kViEKeyFrameRequestPliRtcp,
vie_.GetKeyFrameRequestMethod(channel_num));
}
// Test that remb receive and send is enabled for the default channel in a 1:1
// call.
TEST_F(WebRtcVideoEngineTestFake, RembEnabled) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(1)));
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
EXPECT_TRUE(vie_.GetRembStatusBwPartition(channel_num));
EXPECT_TRUE(channel_->SetSend(true));
EXPECT_TRUE(vie_.GetRembStatusBwPartition(channel_num));
EXPECT_TRUE(vie_.GetRembStatusContribute(channel_num));
}
// When in conference mode, test that remb is enabled on a receive channel but
// not for the default channel and that it uses the default channel for sending
// remb packets.
TEST_F(WebRtcVideoEngineTestFake, RembEnabledOnReceiveChannels) {
EXPECT_TRUE(SetupEngine());
int default_channel = vie_.GetLastChannel();
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(1)));
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
EXPECT_TRUE(vie_.GetRembStatusBwPartition(default_channel));
EXPECT_TRUE(vie_.GetRembStatusContribute(default_channel));
EXPECT_TRUE(channel_->SetSend(true));
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1)));
int new_channel_num = vie_.GetLastChannel();
EXPECT_NE(default_channel, new_channel_num);
EXPECT_TRUE(vie_.GetRembStatusBwPartition(default_channel));
EXPECT_TRUE(vie_.GetRembStatusContribute(default_channel));
EXPECT_FALSE(vie_.GetRembStatusBwPartition(new_channel_num));
EXPECT_TRUE(vie_.GetRembStatusContribute(new_channel_num));
}
TEST_F(WebRtcVideoEngineTestFake, RecvStreamWithRtx) {
EXPECT_TRUE(SetupEngine());
int default_channel = vie_.GetLastChannel();
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimWithRtxStreamParams("cname",
MAKE_VECTOR(kSsrcs3),
MAKE_VECTOR(kRtxSsrcs3))));
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
EXPECT_TRUE(channel_->SetSend(true));
EXPECT_TRUE(channel_->AddRecvStream(
cricket::CreateSimWithRtxStreamParams("cname",
MAKE_VECTOR(kSsrcs1),
MAKE_VECTOR(kRtxSsrcs1))));
int new_channel_num = vie_.GetLastChannel();
EXPECT_NE(default_channel, new_channel_num);
EXPECT_EQ(4, vie_.GetRemoteRtxSsrc(new_channel_num));
}
TEST_F(WebRtcVideoEngineTestFake, RecvStreamNoRtx) {
EXPECT_TRUE(SetupEngine());
int default_channel = vie_.GetLastChannel();
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimWithRtxStreamParams("cname",
MAKE_VECTOR(kSsrcs3),
MAKE_VECTOR(kRtxSsrcs3))));
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
EXPECT_TRUE(channel_->SetSend(true));
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1)));
int new_channel_num = vie_.GetLastChannel();
EXPECT_NE(default_channel, new_channel_num);
EXPECT_EQ(-1, vie_.GetRemoteRtxSsrc(new_channel_num));
}
// Test support for RTP timestamp offset header extension.
TEST_F(WebRtcVideoEngineTestFake, SendRtpTimestampOffsetHeaderExtensions) {
TestSetSendRtpHeaderExtensions(kRtpTimestampOffsetHeaderExtension);
}
TEST_F(WebRtcVideoEngineTestFake, RecvRtpTimestampOffsetHeaderExtensions) {
TestSetRecvRtpHeaderExtensions(kRtpTimestampOffsetHeaderExtension);
}
// Test support for absolute send time header extension.
TEST_F(WebRtcVideoEngineTestFake, SendAbsoluteSendTimeHeaderExtensions) {
TestSetSendRtpHeaderExtensions(kRtpAbsoluteSenderTimeHeaderExtension);
}
TEST_F(WebRtcVideoEngineTestFake, RecvAbsoluteSendTimeHeaderExtensions) {
TestSetRecvRtpHeaderExtensions(kRtpAbsoluteSenderTimeHeaderExtension);
}
// Test support for Coordination of Video Orientation (CVO) header extension.
TEST_F(WebRtcVideoEngineTestFake, SendVideoRotationHeaderExtensions) {
TestSetSendRtpHeaderExtensions(kRtpVideoRotationHeaderExtension);
}
TEST_F(WebRtcVideoEngineTestFake, RecvVideoRotationHeaderExtensions) {
TestSetRecvRtpHeaderExtensions(kRtpVideoRotationHeaderExtension);
}
TEST_F(WebRtcVideoEngineTestFake, LeakyBucketTest) {
EXPECT_TRUE(SetupEngine());
// Verify this is on by default.
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
int first_send_channel = vie_.GetLastChannel();
EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
// Add a new send stream and verify leaky bucket is enabled.
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(3)));
int second_send_channel = vie_.GetLastChannel();
EXPECT_NE(first_send_channel, second_send_channel);
EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(second_send_channel));
}
// Verify that SuspendBelowMinBitrate is enabled if it is set in the options.
TEST_F(WebRtcVideoEngineTestFake, SuspendBelowMinBitrateTest) {
EXPECT_TRUE(SetupEngine());
// Verify this is off by default.
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
int first_send_channel = vie_.GetLastChannel();
EXPECT_FALSE(vie_.GetSuspendBelowMinBitrateStatus(first_send_channel));
// Enable the experiment and verify.
cricket::VideoOptions options;
options.suspend_below_min_bitrate.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_TRUE(vie_.GetSuspendBelowMinBitrateStatus(first_send_channel));
// Add a new send stream and verify suspend_below_min_bitrate is enabled.
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(2)));
int second_send_channel = vie_.GetLastChannel();
EXPECT_NE(first_send_channel, second_send_channel);
EXPECT_TRUE(vie_.GetSuspendBelowMinBitrateStatus(second_send_channel));
}
TEST_F(WebRtcVideoEngineTestFake, BufferedModeLatency) {
EXPECT_TRUE(SetupEngine());
// Verify this is off by default.
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
int first_send_channel = vie_.GetLastChannel();
EXPECT_EQ(0, vie_.GetSenderTargetDelay(first_send_channel));
EXPECT_EQ(0, vie_.GetReceiverTargetDelay(first_send_channel));
// Enable the experiment and verify. The default channel will have both
// sender and receiver buffered mode enabled.
cricket::VideoOptions options;
options.conference_mode.Set(true);
options.buffered_mode_latency.Set(100);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_EQ(100, vie_.GetSenderTargetDelay(first_send_channel));
EXPECT_EQ(100, vie_.GetReceiverTargetDelay(first_send_channel));
// Add a receive channel and verify sender buffered mode isn't enabled.
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
int recv_channel_num = vie_.GetLastChannel();
EXPECT_NE(first_send_channel, recv_channel_num);
EXPECT_EQ(0, vie_.GetSenderTargetDelay(recv_channel_num));
EXPECT_EQ(100, vie_.GetReceiverTargetDelay(recv_channel_num));
// Add a new send stream and verify sender buffered mode is enabled.
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(3)));
int second_send_channel = vie_.GetLastChannel();
EXPECT_NE(first_send_channel, second_send_channel);
EXPECT_EQ(100, vie_.GetSenderTargetDelay(second_send_channel));
EXPECT_EQ(0, vie_.GetReceiverTargetDelay(second_send_channel));
// Disable sender buffered mode and verify.
options.buffered_mode_latency.Set(cricket::kBufferedModeDisabled);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_EQ(0, vie_.GetSenderTargetDelay(first_send_channel));
EXPECT_EQ(0, vie_.GetReceiverTargetDelay(first_send_channel));
EXPECT_EQ(0, vie_.GetSenderTargetDelay(second_send_channel));
EXPECT_EQ(0, vie_.GetReceiverTargetDelay(second_send_channel));
EXPECT_EQ(0, vie_.GetSenderTargetDelay(recv_channel_num));
EXPECT_EQ(0, vie_.GetReceiverTargetDelay(recv_channel_num));
}
TEST_F(WebRtcVideoEngineTestFake, AdditiveVideoOptions) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
channel_->SetSendCodecs(engine_.codecs());
int first_send_channel = vie_.GetLastChannel();
EXPECT_EQ(0, vie_.GetSenderTargetDelay(first_send_channel));
EXPECT_EQ(0, vie_.GetReceiverTargetDelay(first_send_channel));
cricket::VideoOptions options1;
options1.buffered_mode_latency.Set(100);
EXPECT_TRUE(channel_->SetOptions(options1));
EXPECT_EQ(100, vie_.GetSenderTargetDelay(first_send_channel));
EXPECT_EQ(100, vie_.GetReceiverTargetDelay(first_send_channel));
EXPECT_TRUE(vie_.GetTransmissionSmoothingStatus(first_send_channel));
int kBoostedStartBandwidthKbps = 1000;
cricket::VideoOptions options2;
options2.video_start_bitrate.Set(kBoostedStartBandwidthKbps);
EXPECT_TRUE(channel_->SetOptions(options2));
// Check that start bitrate has changed to the new value.
VerifyVP8SendCodec(first_send_channel, kVP8Codec.width, kVP8Codec.height, 0,
kMaxBandwidthKbps, kMinBandwidthKbps, kBoostedStartBandwidthKbps);
// The buffered_mode_latency should still take effect.
EXPECT_EQ(100, vie_.GetSenderTargetDelay(first_send_channel));
EXPECT_EQ(100, vie_.GetReceiverTargetDelay(first_send_channel));
}
TEST_F(WebRtcVideoEngineTestFake, SetCpuOveruseOptionsWithCaptureJitterMethod) {
EXPECT_TRUE(SetupEngine());
// Verify this is off by default.
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
int first_send_channel = vie_.GetLastChannel();
webrtc::CpuOveruseOptions cpu_option =
vie_.GetCpuOveruseOptions(first_send_channel);
EXPECT_EQ(0, cpu_option.low_capture_jitter_threshold_ms);
EXPECT_EQ(0, cpu_option.high_capture_jitter_threshold_ms);
EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
EXPECT_FALSE(cpu_option.enable_encode_usage_method);
// Set low and high threshold and verify that cpu options are set.
cricket::VideoOptions options;
options.conference_mode.Set(true);
options.cpu_underuse_threshold.Set(10);
options.cpu_overuse_threshold.Set(20);
EXPECT_TRUE(channel_->SetOptions(options));
cpu_option = vie_.GetCpuOveruseOptions(first_send_channel);
EXPECT_EQ(10, cpu_option.low_capture_jitter_threshold_ms);
EXPECT_EQ(20, cpu_option.high_capture_jitter_threshold_ms);
EXPECT_TRUE(cpu_option.enable_capture_jitter_method);
EXPECT_FALSE(cpu_option.enable_encode_usage_method);
// Add a receive channel and verify that cpu options are not set.
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(2)));
int recv_channel_num = vie_.GetLastChannel();
EXPECT_NE(first_send_channel, recv_channel_num);
cpu_option = vie_.GetCpuOveruseOptions(recv_channel_num);
EXPECT_EQ(0, cpu_option.low_capture_jitter_threshold_ms);
EXPECT_EQ(0, cpu_option.high_capture_jitter_threshold_ms);
EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
EXPECT_FALSE(cpu_option.enable_encode_usage_method);
// Add a new send stream and verify that cpu options are set from start.
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(3)));
int second_send_channel = vie_.GetLastChannel();
EXPECT_NE(first_send_channel, second_send_channel);
cpu_option = vie_.GetCpuOveruseOptions(second_send_channel);
EXPECT_EQ(10, cpu_option.low_capture_jitter_threshold_ms);
EXPECT_EQ(20, cpu_option.high_capture_jitter_threshold_ms);
EXPECT_TRUE(cpu_option.enable_capture_jitter_method);
EXPECT_FALSE(cpu_option.enable_encode_usage_method);
}
TEST_F(WebRtcVideoEngineTestFake, SetInvalidCpuOveruseThresholds) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
int channel_num = vie_.GetLastChannel();
// Only low threshold set. Verify that cpu options are not set.
cricket::VideoOptions options;
options.conference_mode.Set(true);
options.cpu_underuse_threshold.Set(10);
EXPECT_TRUE(channel_->SetOptions(options));
webrtc::CpuOveruseOptions cpu_option = vie_.GetCpuOveruseOptions(channel_num);
EXPECT_EQ(0, cpu_option.low_capture_jitter_threshold_ms);
EXPECT_EQ(0, cpu_option.high_capture_jitter_threshold_ms);
EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
EXPECT_FALSE(cpu_option.enable_encode_usage_method);
// Set high threshold to a negative value. Verify that options are not set.
options.cpu_overuse_threshold.Set(-1);
EXPECT_TRUE(channel_->SetOptions(options));
cpu_option = vie_.GetCpuOveruseOptions(channel_num);
EXPECT_EQ(0, cpu_option.low_capture_jitter_threshold_ms);
EXPECT_EQ(0, cpu_option.high_capture_jitter_threshold_ms);
EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
EXPECT_FALSE(cpu_option.enable_encode_usage_method);
// Low and high threshold valid. Verify that cpu options are set.
options.cpu_overuse_threshold.Set(20);
EXPECT_TRUE(channel_->SetOptions(options));
cpu_option = vie_.GetCpuOveruseOptions(channel_num);
EXPECT_EQ(10, cpu_option.low_capture_jitter_threshold_ms);
EXPECT_EQ(20, cpu_option.high_capture_jitter_threshold_ms);
EXPECT_TRUE(cpu_option.enable_capture_jitter_method);
EXPECT_FALSE(cpu_option.enable_encode_usage_method);
}
TEST_F(WebRtcVideoEngineTestFake, SetCpuOveruseOptionsWithEncodeUsageMethod) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
int first_send_channel = vie_.GetLastChannel();
// Set low and high threshold and enable encode usage method.
// Verify that cpu options are set.
cricket::VideoOptions options;
options.conference_mode.Set(true);
options.cpu_underuse_threshold.Set(10);
options.cpu_overuse_threshold.Set(20);
options.cpu_overuse_encode_usage.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
webrtc::CpuOveruseOptions cpu_option =
vie_.GetCpuOveruseOptions(first_send_channel);
EXPECT_EQ(10, cpu_option.low_encode_usage_threshold_percent);
EXPECT_EQ(20, cpu_option.high_encode_usage_threshold_percent);
EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
EXPECT_TRUE(cpu_option.enable_encode_usage_method);
// Verify that optional encode rsd thresholds are not set.
EXPECT_EQ(-1, cpu_option.low_encode_time_rsd_threshold);
EXPECT_EQ(-1, cpu_option.high_encode_time_rsd_threshold);
// Add a new send stream and verify that cpu options are set from start.
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(3)));
int second_send_channel = vie_.GetLastChannel();
EXPECT_NE(first_send_channel, second_send_channel);
cpu_option = vie_.GetCpuOveruseOptions(second_send_channel);
EXPECT_EQ(10, cpu_option.low_encode_usage_threshold_percent);
EXPECT_EQ(20, cpu_option.high_encode_usage_threshold_percent);
EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
EXPECT_TRUE(cpu_option.enable_encode_usage_method);
// Verify that optional encode rsd thresholds are not set.
EXPECT_EQ(-1, cpu_option.low_encode_time_rsd_threshold);
EXPECT_EQ(-1, cpu_option.high_encode_time_rsd_threshold);
}
TEST_F(WebRtcVideoEngineTestFake, SetCpuOveruseOptionsWithEncodeRsdThresholds) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
int first_send_channel = vie_.GetLastChannel();
// Set optional encode rsd thresholds and verify cpu options.
cricket::VideoOptions options;
options.conference_mode.Set(true);
options.cpu_underuse_threshold.Set(10);
options.cpu_overuse_threshold.Set(20);
options.cpu_underuse_encode_rsd_threshold.Set(30);
options.cpu_overuse_encode_rsd_threshold.Set(40);
options.cpu_overuse_encode_usage.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
webrtc::CpuOveruseOptions cpu_option =
vie_.GetCpuOveruseOptions(first_send_channel);
EXPECT_EQ(10, cpu_option.low_encode_usage_threshold_percent);
EXPECT_EQ(20, cpu_option.high_encode_usage_threshold_percent);
EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
EXPECT_TRUE(cpu_option.enable_encode_usage_method);
EXPECT_EQ(30, cpu_option.low_encode_time_rsd_threshold);
EXPECT_EQ(40, cpu_option.high_encode_time_rsd_threshold);
// Add a new send stream and verify that cpu options are set from start.
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(3)));
int second_send_channel = vie_.GetLastChannel();
EXPECT_NE(first_send_channel, second_send_channel);
cpu_option = vie_.GetCpuOveruseOptions(second_send_channel);
EXPECT_EQ(10, cpu_option.low_encode_usage_threshold_percent);
EXPECT_EQ(20, cpu_option.high_encode_usage_threshold_percent);
EXPECT_FALSE(cpu_option.enable_capture_jitter_method);
EXPECT_TRUE(cpu_option.enable_encode_usage_method);
EXPECT_EQ(30, cpu_option.low_encode_time_rsd_threshold);
EXPECT_EQ(40, cpu_option.high_encode_time_rsd_threshold);
}
// Test that AddRecvStream doesn't create new channel for 1:1 call.
TEST_F(WebRtcVideoEngineTestFake, AddRecvStream1On1) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1)));
EXPECT_EQ(channel_num, vie_.GetLastChannel());
}
// Test that NACK, PLI and REMB are enabled for internal codec.
TEST_F(WebRtcVideoEngineTestFake, InternalCodecFeedbackParams) {
EXPECT_TRUE(SetupEngine());
std::vector<cricket::VideoCodec> codecs(engine_.codecs());
// Vp8 will appear at the beginning.
size_t pos = 0;
EXPECT_EQ("VP8", codecs[pos].name);
VerifyCodecFeedbackParams(codecs[pos]);
}
// Test that AddRecvStream doesn't change remb for 1:1 call.
TEST_F(WebRtcVideoEngineTestFake, NoRembChangeAfterAddRecvStream) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(1)));
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
EXPECT_TRUE(vie_.GetRembStatusBwPartition(channel_num));
EXPECT_TRUE(vie_.GetRembStatusContribute(channel_num));
EXPECT_TRUE(channel_->SetSend(true));
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1)));
EXPECT_TRUE(vie_.GetRembStatusBwPartition(channel_num));
EXPECT_TRUE(vie_.GetRembStatusContribute(channel_num));
}
// Verify default REMB setting and that it can be turned on and off.
TEST_F(WebRtcVideoEngineTestFake, RembOnOff) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
// Verify REMB sending is always off by default.
EXPECT_FALSE(vie_.GetRembStatusBwPartition(channel_num));
// Verify that REMB is turned on when setting default codecs since the
// default codecs have REMB enabled.
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
EXPECT_TRUE(vie_.GetRembStatusBwPartition(channel_num));
// Verify that REMB is turned off when codecs without REMB are set.
std::vector<cricket::VideoCodec> codecs = engine_.codecs();
// Clearing the codecs' FeedbackParams and setting send codecs should disable
// REMB.
for (std::vector<cricket::VideoCodec>::iterator iter = codecs.begin();
iter != codecs.end(); ++iter) {
// Intersecting with empty will clear the FeedbackParams.
cricket::FeedbackParams empty_params;
iter->feedback_params.Intersect(empty_params);
EXPECT_TRUE(iter->feedback_params.params().empty());
}
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_FALSE(vie_.GetRembStatusBwPartition(channel_num));
}
// Test that nack is enabled on the channel if we don't offer red/fec.
TEST_F(WebRtcVideoEngineTestFake, NackEnabled) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs(engine_.codecs());
codecs.resize(1); // toss out red and ulpfec
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_TRUE(vie_.GetNackStatus(channel_num));
}
// Test that we enable hybrid NACK FEC mode.
TEST_F(WebRtcVideoEngineTestFake, HybridNackFec) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
EXPECT_TRUE(channel_->SetRecvCodecs(engine_.codecs()));
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
EXPECT_TRUE(vie_.GetHybridNackFecStatus(channel_num));
EXPECT_FALSE(vie_.GetNackStatus(channel_num));
}
// Test that we enable hybrid NACK FEC mode when calling SetSendCodecs and
// SetReceiveCodecs in reversed order.
TEST_F(WebRtcVideoEngineTestFake, HybridNackFecReversedOrder) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
EXPECT_TRUE(channel_->SetRecvCodecs(engine_.codecs()));
EXPECT_TRUE(vie_.GetHybridNackFecStatus(channel_num));
EXPECT_FALSE(vie_.GetNackStatus(channel_num));
}
// Test NACK vs Hybrid NACK/FEC interop call setup, i.e. only use NACK even if
// red/fec is offered as receive codec.
TEST_F(WebRtcVideoEngineTestFake, VideoProtectionInterop) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> recv_codecs(engine_.codecs());
std::vector<cricket::VideoCodec> send_codecs(engine_.codecs());
// Only add VP8 as send codec.
send_codecs.resize(1);
EXPECT_TRUE(channel_->SetRecvCodecs(recv_codecs));
EXPECT_TRUE(channel_->SetSendCodecs(send_codecs));
EXPECT_FALSE(vie_.GetHybridNackFecStatus(channel_num));
EXPECT_TRUE(vie_.GetNackStatus(channel_num));
}
// Test NACK vs Hybrid NACK/FEC interop call setup, i.e. only use NACK even if
// red/fec is offered as receive codec. Call order reversed compared to
// VideoProtectionInterop.
TEST_F(WebRtcVideoEngineTestFake, VideoProtectionInteropReversed) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> recv_codecs(engine_.codecs());
std::vector<cricket::VideoCodec> send_codecs(engine_.codecs());
// Only add VP8 as send codec.
send_codecs.resize(1);
EXPECT_TRUE(channel_->SetSendCodecs(send_codecs));
EXPECT_TRUE(channel_->SetRecvCodecs(recv_codecs));
EXPECT_FALSE(vie_.GetHybridNackFecStatus(channel_num));
EXPECT_TRUE(vie_.GetNackStatus(channel_num));
}
// Test that NACK, not hybrid mode, is enabled in conference mode.
TEST_F(WebRtcVideoEngineTestFake, HybridNackFecConference) {
EXPECT_TRUE(SetupEngine());
// Setup the send channel.
int send_channel_num = vie_.GetLastChannel();
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_TRUE(channel_->SetRecvCodecs(engine_.codecs()));
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
EXPECT_FALSE(vie_.GetHybridNackFecStatus(send_channel_num));
EXPECT_TRUE(vie_.GetNackStatus(send_channel_num));
// Add a receive stream.
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1)));
int receive_channel_num = vie_.GetLastChannel();
EXPECT_FALSE(vie_.GetHybridNackFecStatus(receive_channel_num));
EXPECT_TRUE(vie_.GetNackStatus(receive_channel_num));
}
// Test that when AddRecvStream in conference mode, a new channel is created
// for receiving. And the new channel's "original channel" is the send channel.
TEST_F(WebRtcVideoEngineTestFake, AddRemoveRecvStreamConference) {
EXPECT_TRUE(SetupEngine());
// Setup the send channel.
int send_channel_num = vie_.GetLastChannel();
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
// Add a receive stream.
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1)));
int receive_channel_num = vie_.GetLastChannel();
EXPECT_EQ(send_channel_num, vie_.GetOriginalChannelId(receive_channel_num));
EXPECT_TRUE(channel_->RemoveRecvStream(1));
EXPECT_FALSE(vie_.IsChannel(receive_channel_num));
}
// Test that adding/removing stream with 0 ssrc should fail (and not crash).
// For crbug/351699 and 350988.
TEST_F(WebRtcVideoEngineTestFake, AddRemoveRecvStreamWith0Ssrc) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1)));
EXPECT_FALSE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(0)));
EXPECT_FALSE(channel_->RemoveRecvStream(0));
EXPECT_TRUE(channel_->RemoveRecvStream(1));
}
TEST_F(WebRtcVideoEngineTestFake, AddRemoveSendStreamWith0Ssrc) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(1)));
EXPECT_FALSE(channel_->AddSendStream(cricket::StreamParams::CreateLegacy(0)));
EXPECT_FALSE(channel_->RemoveSendStream(0));
EXPECT_TRUE(channel_->RemoveSendStream(1));
}
// Test that we can create a channel and start/stop rendering out on it.
TEST_F(WebRtcVideoEngineTestFake, SetRender) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
// Verify we can start/stop/start/stop rendering.
EXPECT_TRUE(channel_->SetRender(true));
EXPECT_TRUE(vie_.GetRenderStarted(channel_num));
EXPECT_TRUE(channel_->SetRender(false));
EXPECT_FALSE(vie_.GetRenderStarted(channel_num));
EXPECT_TRUE(channel_->SetRender(true));
EXPECT_TRUE(vie_.GetRenderStarted(channel_num));
EXPECT_TRUE(channel_->SetRender(false));
EXPECT_FALSE(vie_.GetRenderStarted(channel_num));
}
// Test that we can create a channel and start/stop sending out on it.
TEST_F(WebRtcVideoEngineTestFake, SetSend) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
// Verify receiving is also started.
EXPECT_TRUE(vie_.GetReceive(channel_num));
// Set send codecs on the channel.
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(123)));
// Verify we can start/stop/start/stop sending.
EXPECT_TRUE(channel_->SetSend(true));
EXPECT_TRUE(vie_.GetSend(channel_num));
EXPECT_TRUE(channel_->SetSend(false));
EXPECT_FALSE(vie_.GetSend(channel_num));
EXPECT_TRUE(channel_->SetSend(true));
EXPECT_TRUE(vie_.GetSend(channel_num));
EXPECT_TRUE(channel_->SetSend(false));
EXPECT_FALSE(vie_.GetSend(channel_num));
}
// Test that we set bandwidth properly when using full auto bandwidth mode.
TEST_F(WebRtcVideoEngineTestFake, SetBandwidthAuto) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
EXPECT_TRUE(channel_->SetMaxSendBandwidth(cricket::kAutoBandwidth));
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height);
}
// Test that we set bandwidth properly when using auto with upper bound.
TEST_F(WebRtcVideoEngineTestFake, SetBandwidthCapped) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
EXPECT_TRUE(channel_->SetMaxSendBandwidth(768000));
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0, 768U);
}
// Test that we reduce the start bandwidth when the requested max is less than
// the default start bandwidth.
TEST_F(WebRtcVideoEngineTestFake, SetMaxBandwidthBelowDefaultStart) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
int max_bandwidth_kbps = (kMinBandwidthKbps + kStartBandwidthKbps) / 2;
EXPECT_TRUE(channel_->SetMaxSendBandwidth(max_bandwidth_kbps * 1000));
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0,
max_bandwidth_kbps, kMinBandwidthKbps, max_bandwidth_kbps);
}
// Test that we reduce the min bandwidth when the requested max is less than
// the min bandwidth.
TEST_F(WebRtcVideoEngineTestFake, SetMaxBandwidthBelowMin) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
int max_bandwidth_kbps = kMinBandwidthKbps / 2;
EXPECT_TRUE(channel_->SetMaxSendBandwidth(max_bandwidth_kbps * 1000));
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0,
max_bandwidth_kbps, max_bandwidth_kbps, max_bandwidth_kbps);
}
// Test that the start bandwidth can be controlled by VideoOptions.
TEST_F(WebRtcVideoEngineTestFake, SetStartBandwidthOption) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0,
kMaxBandwidthKbps, kMinBandwidthKbps, kStartBandwidthKbps);
// Set the start bitrate option.
unsigned int kBoostedStartBandwidthKbps = 1000;
ASSERT_NE(kStartBandwidthKbps, kBoostedStartBandwidthKbps);
cricket::VideoOptions options;
options.video_start_bitrate.Set(kBoostedStartBandwidthKbps);
EXPECT_TRUE(channel_->SetOptions(options));
// Check that start bitrate has changed to the new value.
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0,
kMaxBandwidthKbps, kMinBandwidthKbps, kBoostedStartBandwidthKbps);
}
// Test that SetMaxSendBandwidth works as expected in conference mode.
TEST_F(WebRtcVideoEngineTestFake, SetBandwidthInConference) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(engine_.codecs()));
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height);
// Set send bandwidth.
EXPECT_TRUE(channel_->SetMaxSendBandwidth(768000));
// Verify that the max bitrate has changed.
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0,
768, kMinBandwidthKbps, kStartBandwidthKbps);
}
// Test that sending screencast frames doesn't change bitrate.
TEST_F(WebRtcVideoEngineTestFake, SetBandwidthScreencast) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
// Set send codec.
cricket::VideoCodec codec(kVP8Codec);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(123)));
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
EXPECT_TRUE(channel_->SetMaxSendBandwidth(111000));
EXPECT_TRUE(channel_->SetSend(true));
SendI420ScreencastFrame(kVP8Codec.width, kVP8Codec.height);
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0, 111);
}
// Test SetSendSsrc.
TEST_F(WebRtcVideoEngineTestFake, SetSendSsrcAndCname) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
cricket::StreamParams stream;
stream.ssrcs.push_back(1234);
stream.cname = "cname";
channel_->AddSendStream(stream);
unsigned int ssrc = 0;
EXPECT_EQ(0, vie_.GetLocalSSRC(channel_num, ssrc));
EXPECT_EQ(1234U, ssrc);
EXPECT_EQ(1, vie_.GetNumSsrcs(channel_num));
char rtcp_cname[256];
EXPECT_EQ(0, vie_.GetRTCPCName(channel_num, rtcp_cname));
EXPECT_STREQ("cname", rtcp_cname);
}
// Test that the local SSRC is the same on sending and receiving channels if the
// receive channel is created before the send channel.
TEST_F(WebRtcVideoEngineTestFake, SetSendSsrcAfterCreatingReceiveChannel) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(1)));
int receive_channel_num = vie_.GetLastChannel();
cricket::StreamParams stream = cricket::StreamParams::CreateLegacy(1234);
EXPECT_TRUE(channel_->AddSendStream(stream));
int send_channel_num = vie_.GetLastChannel();
unsigned int ssrc = 0;
EXPECT_EQ(0, vie_.GetLocalSSRC(send_channel_num, ssrc));
EXPECT_EQ(1234U, ssrc);
EXPECT_EQ(1, vie_.GetNumSsrcs(send_channel_num));
ssrc = 0;
EXPECT_EQ(0, vie_.GetLocalSSRC(receive_channel_num, ssrc));
EXPECT_EQ(1234U, ssrc);
EXPECT_EQ(1, vie_.GetNumSsrcs(receive_channel_num));
}
// Test SetOptions with denoising flag.
TEST_F(WebRtcVideoEngineTestFake, SetOptionsWithDenoising) {
EXPECT_TRUE(SetupEngine());
EXPECT_EQ(1, vie_.GetNumCapturers());
int channel_num = vie_.GetLastChannel();
int capture_id = vie_.GetCaptureId(channel_num);
// Set send codecs on the channel.
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
// Set options with OPT_VIDEO_NOISE_REDUCTION flag.
cricket::VideoOptions options;
options.video_noise_reduction.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
// Verify capture has denoising turned on.
webrtc::VideoCodec send_codec;
memset(&send_codec, 0, sizeof(send_codec)); // avoid uninitialized warning
EXPECT_EQ(0, vie_.GetSendCodec(channel_num, send_codec));
EXPECT_TRUE(send_codec.codecSpecific.VP8.denoisingOn);
EXPECT_FALSE(vie_.GetCaptureDenoising(capture_id));
// Set options back to zero.
options.video_noise_reduction.Set(false);
EXPECT_TRUE(channel_->SetOptions(options));
// Verify capture has denoising turned off.
EXPECT_EQ(0, vie_.GetSendCodec(channel_num, send_codec));
EXPECT_FALSE(send_codec.codecSpecific.VP8.denoisingOn);
EXPECT_FALSE(vie_.GetCaptureDenoising(capture_id));
}
TEST_F(WebRtcVideoEngineTestFake, MultipleSendStreamsWithOneCapturer) {
EXPECT_TRUE(SetupEngine());
// Start the capturer
cricket::FakeVideoCapturer capturer;
cricket::VideoFormat capture_format_vga = cricket::VideoFormat(640, 480,
cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420);
EXPECT_EQ(cricket::CS_RUNNING, capturer.Start(capture_format_vga));
// Add send streams and connect the capturer
for (unsigned int i = 0; i < sizeof(kSsrcs2)/sizeof(kSsrcs2[0]); ++i) {
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(kSsrcs2[i])));
// Register the capturer to the ssrc.
EXPECT_TRUE(channel_->SetCapturer(kSsrcs2[i], &capturer));
}
const int channel0 = vie_.GetChannelFromLocalSsrc(kSsrcs2[0]);
ASSERT_NE(-1, channel0);
const int channel1 = vie_.GetChannelFromLocalSsrc(kSsrcs2[1]);
ASSERT_NE(-1, channel1);
ASSERT_NE(channel0, channel1);
// Both channels should have started receiving after created.
EXPECT_TRUE(vie_.GetReceive(channel0));
EXPECT_TRUE(vie_.GetReceive(channel1));
// Set send codec.
std::vector<cricket::VideoCodec> codecs;
cricket::VideoCodec send_codec(100, "VP8", 640, 480, 30, 0);
codecs.push_back(send_codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_TRUE(channel_->SetSend(true));
EXPECT_TRUE(vie_.GetSend(channel0));
EXPECT_TRUE(vie_.GetSend(channel1));
EXPECT_TRUE(capturer.CaptureFrame());
EXPECT_EQ(1, vie_.GetIncomingFrameNum(channel0));
EXPECT_EQ(1, vie_.GetIncomingFrameNum(channel1));
EXPECT_TRUE(channel_->RemoveSendStream(kSsrcs2[0]));
EXPECT_TRUE(capturer.CaptureFrame());
// channel0 is the default channel, so it won't be deleted.
// But it should be disconnected from the capturer.
EXPECT_EQ(1, vie_.GetIncomingFrameNum(channel0));
EXPECT_EQ(2, vie_.GetIncomingFrameNum(channel1));
EXPECT_TRUE(channel_->RemoveSendStream(kSsrcs2[1]));
EXPECT_TRUE(capturer.CaptureFrame());
EXPECT_EQ(1, vie_.GetIncomingFrameNum(channel0));
// channel1 has already been deleted.
EXPECT_EQ(-1, vie_.GetIncomingFrameNum(channel1));
}
TEST_F(WebRtcVideoEngineTestFake, SendReceiveBitratesStats) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(1)));
int first_send_channel = vie_.GetLastChannel();
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(2)));
int second_send_channel = vie_.GetLastChannel();
cricket::VideoCodec codec(kVP8Codec720p);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
EXPECT_TRUE(channel_->AddRecvStream(
cricket::StreamParams::CreateLegacy(3)));
int first_receive_channel = vie_.GetLastChannel();
EXPECT_NE(first_send_channel, first_receive_channel);
EXPECT_TRUE(channel_->AddRecvStream(
cricket::StreamParams::CreateLegacy(4)));
int second_receive_channel = vie_.GetLastChannel();
EXPECT_NE(first_receive_channel, second_receive_channel);
cricket::VideoMediaInfo info;
EXPECT_TRUE(channel_->GetStats(&info));
ASSERT_EQ(1U, info.bw_estimations.size());
ASSERT_EQ(0, info.bw_estimations[0].actual_enc_bitrate);
ASSERT_EQ(0, info.bw_estimations[0].transmit_bitrate);
ASSERT_EQ(0, info.bw_estimations[0].retransmit_bitrate);
ASSERT_EQ(0, info.bw_estimations[0].available_send_bandwidth);
ASSERT_EQ(0, info.bw_estimations[0].available_recv_bandwidth);
ASSERT_EQ(0, info.bw_estimations[0].target_enc_bitrate);
// Start sending and receiving on one of the channels and verify bitrates.
EXPECT_EQ(0, vie_.StartSend(first_send_channel));
int send_video_bitrate = 800;
int send_fec_bitrate = 100;
int send_nack_bitrate = 20;
int send_total_bitrate = send_video_bitrate + send_fec_bitrate +
send_nack_bitrate;
int send_bandwidth = 1900;
vie_.SetSendBitrates(first_send_channel, send_video_bitrate, send_fec_bitrate,
send_nack_bitrate);
vie_.SetSendBandwidthEstimate(first_send_channel, send_bandwidth);
EXPECT_EQ(0, vie_.StartReceive(first_receive_channel));
int receive_bandwidth = 600;
vie_.SetReceiveBandwidthEstimate(first_receive_channel, receive_bandwidth);
info.Clear();
EXPECT_TRUE(channel_->GetStats(&info));
ASSERT_EQ(1U, info.bw_estimations.size());
ASSERT_EQ(send_video_bitrate, info.bw_estimations[0].actual_enc_bitrate);
ASSERT_EQ(send_total_bitrate, info.bw_estimations[0].transmit_bitrate);
ASSERT_EQ(send_nack_bitrate, info.bw_estimations[0].retransmit_bitrate);
ASSERT_EQ(send_bandwidth, info.bw_estimations[0].available_send_bandwidth);
ASSERT_EQ(receive_bandwidth, info.bw_estimations[0].available_recv_bandwidth);
ASSERT_EQ(send_video_bitrate, info.bw_estimations[0].target_enc_bitrate);
// Start receiving on the second channel and verify received rate.
EXPECT_EQ(0, vie_.StartSend(second_send_channel));
vie_.SetSendBitrates(second_send_channel,
send_video_bitrate,
send_fec_bitrate,
send_nack_bitrate);
EXPECT_EQ(0, vie_.StartReceive(second_receive_channel));
info.Clear();
EXPECT_TRUE(channel_->GetStats(&info));
ASSERT_EQ(1U, info.bw_estimations.size());
ASSERT_EQ(2 * send_video_bitrate, info.bw_estimations[0].actual_enc_bitrate);
ASSERT_EQ(2 * send_total_bitrate, info.bw_estimations[0].transmit_bitrate);
ASSERT_EQ(2 * send_nack_bitrate, info.bw_estimations[0].retransmit_bitrate);
ASSERT_EQ(send_bandwidth, info.bw_estimations[0].available_send_bandwidth);
ASSERT_EQ(receive_bandwidth, info.bw_estimations[0].available_recv_bandwidth);
ASSERT_EQ(2 * send_video_bitrate, info.bw_estimations[0].target_enc_bitrate);
}
TEST_F(WebRtcVideoEngineTestFake, TestSetAdaptInputToCpuUsage) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options_in, options_out;
bool cpu_adapt = false;
channel_->SetOptions(options_in);
EXPECT_TRUE(channel_->GetOptions(&options_out));
EXPECT_FALSE(options_out.adapt_input_to_cpu_usage.Get(&cpu_adapt));
// Set adapt input CPU usage option.
options_in.adapt_input_to_cpu_usage.Set(true);
EXPECT_TRUE(channel_->SetOptions(options_in));
EXPECT_TRUE(channel_->GetOptions(&options_out));
EXPECT_TRUE(options_out.adapt_input_to_cpu_usage.Get(&cpu_adapt));
EXPECT_TRUE(cpu_adapt);
}
TEST_F(WebRtcVideoEngineTestFake, TestSetCpuThreshold) {
EXPECT_TRUE(SetupEngine());
float low, high;
cricket::VideoOptions options_in, options_out;
// Verify that initial values are set.
EXPECT_TRUE(channel_->GetOptions(&options_out));
EXPECT_TRUE(options_out.system_low_adaptation_threshhold.Get(&low));
EXPECT_EQ(low, 0.65f);
EXPECT_TRUE(options_out.system_high_adaptation_threshhold.Get(&high));
EXPECT_EQ(high, 0.85f);
// Set new CPU threshold values.
options_in.system_low_adaptation_threshhold.Set(0.45f);
options_in.system_high_adaptation_threshhold.Set(0.95f);
EXPECT_TRUE(channel_->SetOptions(options_in));
EXPECT_TRUE(channel_->GetOptions(&options_out));
EXPECT_TRUE(options_out.system_low_adaptation_threshhold.Get(&low));
EXPECT_EQ(low, 0.45f);
EXPECT_TRUE(options_out.system_high_adaptation_threshhold.Get(&high));
EXPECT_EQ(high, 0.95f);
}
TEST_F(WebRtcVideoEngineTestFake, TestSetInvalidCpuThreshold) {
EXPECT_TRUE(SetupEngine());
float low, high;
cricket::VideoOptions options_in, options_out;
// Valid range is [0, 1].
options_in.system_low_adaptation_threshhold.Set(-1.5f);
options_in.system_high_adaptation_threshhold.Set(1.5f);
EXPECT_TRUE(channel_->SetOptions(options_in));
EXPECT_TRUE(channel_->GetOptions(&options_out));
EXPECT_TRUE(options_out.system_low_adaptation_threshhold.Get(&low));
EXPECT_EQ(low, 0.0f);
EXPECT_TRUE(options_out.system_high_adaptation_threshhold.Get(&high));
EXPECT_EQ(high, 1.0f);
}
TEST_F(WebRtcVideoEngineTestFake, ResetCodecOnScreencast) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.video_noise_reduction.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
// Set send codec.
cricket::VideoCodec codec(kVP8Codec);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(123)));
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
EXPECT_TRUE(channel_->SetSend(true));
EXPECT_EQ(1, vie_.GetNumSetSendCodecs());
webrtc::VideoCodec gcodec;
memset(&gcodec, 0, sizeof(gcodec));
int channel_num = vie_.GetLastChannel();
EXPECT_EQ(0, vie_.GetSendCodec(channel_num, gcodec));
EXPECT_TRUE(gcodec.codecSpecific.VP8.denoisingOn);
// Send a screencast frame with the same size.
// Verify that denoising is turned off.
SendI420ScreencastFrame(kVP8Codec.width, kVP8Codec.height);
EXPECT_EQ(2, vie_.GetNumSetSendCodecs());
EXPECT_EQ(0, vie_.GetSendCodec(channel_num, gcodec));
EXPECT_FALSE(gcodec.codecSpecific.VP8.denoisingOn);
}
TEST_F(WebRtcVideoEngineTestFake, DontRegisterDecoderIfFactoryIsNotGiven) {
engine_.SetExternalDecoderFactory(NULL);
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
EXPECT_EQ(0, vie_.GetNumExternalDecoderRegistered(channel_num));
}
TEST_F(WebRtcVideoEngineTestFake, RegisterDecoderIfFactoryIsGiven) {
decoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecVP8);
engine_.SetExternalDecoderFactory(&decoder_factory_);
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
EXPECT_TRUE(vie_.ExternalDecoderRegistered(channel_num, 100));
EXPECT_EQ(1, vie_.GetNumExternalDecoderRegistered(channel_num));
}
TEST_F(WebRtcVideoEngineTestFake, DontRegisterDecoderMultipleTimes) {
decoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecVP8);
engine_.SetExternalDecoderFactory(&decoder_factory_);
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
EXPECT_TRUE(vie_.ExternalDecoderRegistered(channel_num, 100));
EXPECT_EQ(1, vie_.GetNumExternalDecoderRegistered(channel_num));
EXPECT_EQ(1, decoder_factory_.GetNumCreatedDecoders());
EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
EXPECT_EQ(1, vie_.GetNumExternalDecoderRegistered(channel_num));
EXPECT_EQ(1, decoder_factory_.GetNumCreatedDecoders());
}
TEST_F(WebRtcVideoEngineTestFake, DontRegisterDecoderForNonVP8) {
decoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecVP8);
engine_.SetExternalDecoderFactory(&decoder_factory_);
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kRedCodec);
EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
EXPECT_EQ(0, vie_.GetNumExternalDecoderRegistered(channel_num));
}
TEST_F(WebRtcVideoEngineTestFake, DontRegisterEncoderIfFactoryIsNotGiven) {
engine_.SetExternalEncoderFactory(NULL);
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_EQ(0, vie_.GetNumExternalEncoderRegistered(channel_num));
}
TEST_F(WebRtcVideoEngineTestFake, RegisterEncoderIfFactoryIsGiven) {
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecVP8, "VP8");
encoder_factory_.set_encoders_have_internal_sources(false);
engine_.SetExternalEncoderFactory(&encoder_factory_);
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(kSsrc)));
EXPECT_TRUE(vie_.ExternalEncoderRegistered(channel_num, 100));
EXPECT_FALSE(vie_.ExternalEncoderHasInternalSource(channel_num, 100));
EXPECT_EQ(1, vie_.GetNumExternalEncoderRegistered(channel_num));
// Remove stream previously added to free the external encoder instance.
EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
}
TEST_F(WebRtcVideoEngineTestFake, RegisterEncoderWithInternalSource) {
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecVP8, "VP8");
encoder_factory_.set_encoders_have_internal_sources(true);
engine_.SetExternalEncoderFactory(&encoder_factory_);
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_TRUE(
channel_->AddSendStream(cricket::StreamParams::CreateLegacy(kSsrc)));
ASSERT_TRUE(vie_.ExternalEncoderRegistered(channel_num, 100));
EXPECT_TRUE(vie_.ExternalEncoderHasInternalSource(channel_num, 100));
EXPECT_EQ(1, vie_.GetNumExternalEncoderRegistered(channel_num));
// Remove stream previously added to free the external encoder instance.
EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
}
TEST_F(WebRtcVideoEngineTestFake, DontRegisterEncoderMultipleTimes) {
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecVP8, "VP8");
engine_.SetExternalEncoderFactory(&encoder_factory_);
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(kSsrc)));
EXPECT_TRUE(vie_.ExternalEncoderRegistered(channel_num, 100));
EXPECT_EQ(1, vie_.GetNumExternalEncoderRegistered(channel_num));
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_EQ(1, vie_.GetNumExternalEncoderRegistered(channel_num));
// Remove stream previously added to free the external encoder instance.
EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
}
TEST_F(WebRtcVideoEngineTestFake, RegisterEncoderWithMultipleSendStreams) {
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecVP8, "VP8");
engine_.SetExternalEncoderFactory(&encoder_factory_);
EXPECT_TRUE(SetupEngine());
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_EQ(1, vie_.GetTotalNumExternalEncoderRegistered());
// When we add the first stream (1234), it reuses the default send channel,
// so it doesn't increase the registration count of external encoders.
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(1234)));
EXPECT_EQ(1, vie_.GetTotalNumExternalEncoderRegistered());
// When we add the second stream (2345), it creates a new channel and
// increments the registration count.
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(2345)));
EXPECT_EQ(2, vie_.GetTotalNumExternalEncoderRegistered());
// At this moment the total registration count is two, but only one encoder
// is registered per channel.
int channel_num = vie_.GetLastChannel();
EXPECT_EQ(1, vie_.GetNumExternalEncoderRegistered(channel_num));
// Removing send streams decrements the registration count.
EXPECT_TRUE(channel_->RemoveSendStream(1234));
EXPECT_EQ(1, vie_.GetTotalNumExternalEncoderRegistered());
// When we remove the last send stream, it also destroys the last send
// channel and causes the registration count to drop to zero. It is a little
// weird, but not a bug.
EXPECT_TRUE(channel_->RemoveSendStream(2345));
EXPECT_EQ(0, vie_.GetTotalNumExternalEncoderRegistered());
}
TEST_F(WebRtcVideoEngineTestFake, DontRegisterEncoderForNonVP8) {
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecGeneric,
"GENERIC");
engine_.SetExternalEncoderFactory(&encoder_factory_);
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
// Note: unlike the SetRecvCodecs, we must set a valid video codec for
// channel_->SetSendCodecs() to succeed.
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_EQ(0, vie_.GetNumExternalEncoderRegistered(channel_num));
}
// Test that NACK, PLI and REMB are enabled for external codec.
TEST_F(WebRtcVideoEngineTestFake, ExternalCodecFeedbackParams) {
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecGeneric,
"GENERIC");
engine_.SetExternalEncoderFactory(&encoder_factory_);
EXPECT_TRUE(SetupEngine());
std::vector<cricket::VideoCodec> codecs(engine_.codecs());
// The external codec will appear at last.
size_t pos = codecs.size() - 1;
EXPECT_EQ("GENERIC", codecs[pos].name);
VerifyCodecFeedbackParams(codecs[pos]);
}
// Test external codec will be added to the end of the supported codec list.
TEST_F(WebRtcVideoEngineTestFake, ExternalCodecAddedToTheEnd) {
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecGeneric,
"GENERIC");
engine_.SetExternalEncoderFactory(&encoder_factory_);
EXPECT_TRUE(SetupEngine());
std::vector<cricket::VideoCodec> codecs(engine_.codecs());
EXPECT_EQ("VP8", codecs[0].name);
codecs = engine_.codecs();
cricket::VideoCodec internal_codec = codecs[0];
cricket::VideoCodec external_codec = codecs[codecs.size() - 1];
// The external codec will appear at last.
EXPECT_EQ("GENERIC", external_codec.name);
// The internal codec is preferred.
EXPECT_GE(internal_codec.preference, external_codec.preference);
}
// Test that external codecs that we support internally are not added as
// duplicate entries to the codecs list.
TEST_F(WebRtcVideoEngineTestFake, ExternalCodecIgnored) {
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecVP8, "VP8");
engine_.SetExternalEncoderFactory(&encoder_factory_);
EXPECT_TRUE(SetupEngine());
std::vector<cricket::VideoCodec> internal_codecs(engine_.codecs());
EXPECT_EQ("VP8", internal_codecs[0].name);
std::vector<cricket::VideoCodec> codecs = engine_.codecs();
EXPECT_EQ("VP8", codecs[0].name);
EXPECT_EQ(internal_codecs[0].height, codecs[0].height);
EXPECT_EQ(internal_codecs[0].width, codecs[0].width);
// Verify the last codec is not the external codec.
EXPECT_NE("VP8", codecs[codecs.size() - 1].name);
}
TEST_F(WebRtcVideoEngineTestFake, SetSendCodecsWithExternalH264) {
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecH264, "H264");
engine_.SetExternalEncoderFactory(&encoder_factory_);
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kH264Codec);
cricket::VideoCodec rtx_codec(96, "rtx", 0, 0, 0, 0);
rtx_codec.SetParam("apt", kH264Codec.id);
codecs.push_back(rtx_codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_EQ(vie_.GetRtxSendPayloadTypes(channel_num),
MAKE_VECTOR(kPayloadTypes1));
cricket::StreamParams params =
cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
EXPECT_TRUE(channel_->AddSendStream(params));
EXPECT_EQ(1, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(1, vie_.GetNumRtxSsrcs(channel_num));
EXPECT_EQ(static_cast<int>(kRtxSsrcs1[0]), vie_.GetRtxSsrc(channel_num, 0));
EXPECT_TRUE(vie_.ExternalEncoderRegistered(channel_num, 127));
EXPECT_EQ(1, vie_.GetNumExternalEncoderRegistered(channel_num));
EXPECT_EQ(1, encoder_factory_.GetNumCreatedEncoders());
EXPECT_TRUE(channel_->RemoveSendStream(kSsrcs1[0]));
}
TEST_F(WebRtcVideoEngineTestFake, SetSendCodecsWithVP8AndExternalH264) {
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecH264, "H264");
engine_.SetExternalEncoderFactory(&encoder_factory_);
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kH264Codec);
cricket::VideoCodec rtx_codec(96, "rtx", 0, 0, 0, 0);
rtx_codec.SetParam("apt", kH264Codec.id);
codecs.push_back(rtx_codec);
codecs.push_back(kVP8Codec);
cricket::VideoCodec rtx_codec2(97, "rtx", 0, 0, 0, 0);
rtx_codec2.SetParam("apt", kVP8Codec.id);
codecs.push_back(rtx_codec2);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
// The first matched codec should be set, i.e., H.264.
EXPECT_EQ(vie_.GetRtxSendPayloadTypes(channel_num),
MAKE_VECTOR(kPayloadTypes1));
cricket::StreamParams params =
cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
EXPECT_TRUE(channel_->AddSendStream(params));
EXPECT_EQ(1, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(1, vie_.GetNumRtxSsrcs(channel_num));
EXPECT_EQ(static_cast<int>(kRtxSsrcs1[0]), vie_.GetRtxSsrc(channel_num, 0));
EXPECT_TRUE(vie_.ExternalEncoderRegistered(channel_num, 127));
EXPECT_EQ(1, vie_.GetNumExternalEncoderRegistered(channel_num));
EXPECT_EQ(1, encoder_factory_.GetNumCreatedEncoders());
EXPECT_TRUE(channel_->RemoveSendStream(kSsrcs1[0]));
}
TEST_F(WebRtcVideoEngineTestFake, SetRecvCodecsWithExternalH264) {
// WebRtcVideoEngine assumes that if we have encode support for a codec, we
// also have decode support. It doesn't support decode only support. Therefore
// we here have to register both an encoder and a decoder factory with H264
// support, to be able to test the decoder factory.
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecH264, "H264");
decoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecH264);
EXPECT_TRUE(SetupEngine());
engine_.SetExternalEncoderFactory(&encoder_factory_);
engine_.SetExternalDecoderFactory(&decoder_factory_);
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kH264Codec);
cricket::VideoCodec rtx_codec(96, "rtx", 0, 0, 0, 0);
rtx_codec.SetParam("apt", kH264Codec.id);
codecs.push_back(rtx_codec);
EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
EXPECT_EQ(vie_.GetRtxRecvPayloadTypes(channel_num),
MAKE_VECTOR(kPayloadTypes1));
cricket::StreamParams params =
cricket::StreamParams::CreateLegacy(kSsrcs1[0]);
params.AddFidSsrc(kSsrcs1[0], kRtxSsrcs1[0]);
EXPECT_TRUE(channel_->AddRecvStream(params));
EXPECT_EQ(1, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(static_cast<int>(kRtxSsrcs1[0]),
vie_.GetRemoteRtxSsrc(channel_num));
EXPECT_TRUE(vie_.ExternalDecoderRegistered(channel_num, 127));
EXPECT_EQ(1, vie_.GetNumExternalDecoderRegistered(channel_num));
EXPECT_EQ(1, decoder_factory_.GetNumCreatedDecoders());
EXPECT_TRUE(channel_->RemoveRecvStream(kSsrcs1[0]));
}
TEST_F(WebRtcVideoEngineTestFake, SetRecvCodecsWithVP8AndExternalH264) {
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecH264, "H264");
decoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecH264);
EXPECT_TRUE(SetupEngine());
engine_.SetExternalEncoderFactory(&encoder_factory_);
engine_.SetExternalDecoderFactory(&decoder_factory_);
int channel_num = vie_.GetLastChannel();
std::vector<cricket::VideoCodec> codecs;
cricket::VideoCodec rtx_codec(97, "rtx", 0, 0, 0, 0);
rtx_codec.SetParam("apt", kH264Codec.id);
codecs.push_back(kH264Codec);
codecs.push_back(rtx_codec);
cricket::VideoCodec rtx_codec2(96, "rtx", 0, 0, 0, 0);
rtx_codec2.SetParam("apt", kVP8Codec.id);
codecs.push_back(kVP8Codec);
codecs.push_back(rtx_codec2);
EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
EXPECT_EQ(vie_.GetRtxRecvPayloadTypes(channel_num),
MAKE_VECTOR(kPayloadTypes2));
codecs.pop_back();
// One RTX codec should be fine.
EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
// TODO(changbin): The Rtx key can still be found from the Rtx-Apt map
// if the new codec list doesn't assign it with a new value.
// Should pass a map to SetRtxRecvPayloadType in future.
EXPECT_EQ(vie_.GetRtxRecvPayloadTypes(channel_num),
MAKE_VECTOR(kPayloadTypes2));
}
// Tests that OnReadyToSend will be propagated into ViE.
TEST_F(WebRtcVideoEngineTestFake, OnReadyToSend) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
EXPECT_TRUE(vie_.GetIsTransmitting(channel_num));
channel_->OnReadyToSend(false);
EXPECT_FALSE(vie_.GetIsTransmitting(channel_num));
channel_->OnReadyToSend(true);
EXPECT_TRUE(vie_.GetIsTransmitting(channel_num));
}
#if 0
TEST_F(WebRtcVideoEngineTestFake, CaptureFrameTimestampToNtpTimestamp) {
EXPECT_TRUE(SetupEngine());
int capture_id = vie_.GetCaptureId(vie_.GetLastChannel());
// Set send codec.
cricket::VideoCodec codec(kVP8Codec);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(123)));
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
EXPECT_TRUE(channel_->SetSend(true));
int64 timestamp = time(NULL) * rtc::kNumNanosecsPerSec;
SendI420ScreencastFrameWithTimestamp(
kVP8Codec.width, kVP8Codec.height, timestamp);
EXPECT_EQ(rtc::UnixTimestampNanosecsToNtpMillisecs(timestamp),
vie_.GetCaptureLastTimestamp(capture_id));
SendI420ScreencastFrameWithTimestamp(kVP8Codec.width, kVP8Codec.height, 0);
EXPECT_EQ(0, vie_.GetCaptureLastTimestamp(capture_id));
}
#endif
/////////////////////////
// Tests with real ViE //
/////////////////////////
// Tests that we can find codecs by name or id.
TEST_F(WebRtcVideoEngineTest, FindCodec) {
// We should not need to init engine in order to get codecs.
const std::vector<cricket::VideoCodec>& c = engine_.codecs();
EXPECT_EQ(cricket::DefaultVideoCodecList().size(), c.size());
cricket::VideoCodec vp8(104, "VP8", 320, 200, 30, 0);
EXPECT_TRUE(engine_.FindCodec(vp8));
cricket::VideoCodec vp8_ci(104, "vp8", 320, 200, 30, 0);
EXPECT_TRUE(engine_.FindCodec(vp8));
cricket::VideoCodec vp8_diff_fr_diff_pref(104, "VP8", 320, 200, 50, 50);
EXPECT_TRUE(engine_.FindCodec(vp8_diff_fr_diff_pref));
cricket::VideoCodec vp8_diff_id(95, "VP8", 320, 200, 30, 0);
EXPECT_FALSE(engine_.FindCodec(vp8_diff_id));
vp8_diff_id.id = 97;
EXPECT_TRUE(engine_.FindCodec(vp8_diff_id));
cricket::VideoCodec vp8_diff_res(104, "VP8", 320, 111, 30, 0);
// FindCodec ignores the codec size.
// Test that FindCodec can accept uncommon codec size.
EXPECT_TRUE(engine_.FindCodec(vp8_diff_res));
// PeerConnection doesn't negotiate the resolution at this point.
// Test that FindCodec can handle the case when width/height is 0.
cricket::VideoCodec vp8_zero_res(104, "VP8", 0, 0, 30, 0);
EXPECT_TRUE(engine_.FindCodec(vp8_zero_res));
cricket::VideoCodec red(101, "RED", 0, 0, 30, 0);
EXPECT_TRUE(engine_.FindCodec(red));
cricket::VideoCodec red_ci(101, "red", 0, 0, 30, 0);
EXPECT_TRUE(engine_.FindCodec(red));
cricket::VideoCodec fec(102, "ULPFEC", 0, 0, 30, 0);
EXPECT_TRUE(engine_.FindCodec(fec));
cricket::VideoCodec fec_ci(102, "ulpfec", 0, 0, 30, 0);
EXPECT_TRUE(engine_.FindCodec(fec));
cricket::VideoCodec rtx(96, "rtx", 0, 0, 30, 0);
rtx.SetParam("apt", kVP8Codec.id);
EXPECT_TRUE(engine_.FindCodec(rtx));
}
TEST_F(WebRtcVideoEngineTest, RtxCodecHasAptSet) {
std::vector<cricket::VideoCodec>::const_iterator it;
bool apt_checked = false;
for (it = engine_.codecs().begin(); it != engine_.codecs().end(); ++it) {
if (_stricmp(cricket::kRtxCodecName, it->name.c_str()) || it->id != 96) {
continue;
}
int apt;
EXPECT_TRUE(it->GetParam("apt", &apt));
EXPECT_EQ(100, apt);
apt_checked = true;
}
EXPECT_TRUE(apt_checked);
}
TEST_F(WebRtcVideoEngineTest, StartupShutdown) {
EXPECT_TRUE(engine_.Init(rtc::Thread::Current()));
engine_.Terminate();
}
TEST_PRE_VIDEOENGINE_INIT(WebRtcVideoEngineTest, ConstrainNewCodec2)
TEST_POST_VIDEOENGINE_INIT(WebRtcVideoEngineTest, ConstrainNewCodec2)
// TODO(juberti): Figure out why ViE is munging the COM refcount.
#ifdef WIN32
TEST_F(WebRtcVideoEngineTest, DISABLED_CheckCoInitialize) {
Base::CheckCoInitialize();
}
#endif
TEST_F(WebRtcVideoEngineTest, CreateChannel) {
EXPECT_TRUE(engine_.Init(rtc::Thread::Current()));
cricket::VideoMediaChannel* channel =
engine_.CreateChannel(cricket::VideoOptions(), NULL);
EXPECT_TRUE(channel != NULL);
delete channel;
}
TEST_F(WebRtcVideoMediaChannelTest, SetRecvCodecs) {
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
}
TEST_F(WebRtcVideoMediaChannelTest, SetRecvCodecsWrongPayloadType) {
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
codecs[0].id = 99;
EXPECT_TRUE(channel_->SetRecvCodecs(codecs));
}
TEST_F(WebRtcVideoMediaChannelTest, SetRecvCodecsUnsupportedCodec) {
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
codecs.push_back(cricket::VideoCodec(101, "VP1", 640, 400, 30, 0));
EXPECT_FALSE(channel_->SetRecvCodecs(codecs));
}
TEST_F(WebRtcVideoMediaChannelTest, GetRtpSendTimeExtension) {
// Enable RTP timestamp extension.
const int id = 12;
std::vector<cricket::RtpHeaderExtension> extensions;
extensions.push_back(cricket::RtpHeaderExtension(
"http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time", id));
// Verify the send extension id.
EXPECT_TRUE(channel_->SetSendRtpHeaderExtensions(extensions));
EXPECT_EQ(id, channel_->GetRtpSendTimeExtnId());
}
TEST_F(WebRtcVideoMediaChannelTest, SetSend) {
Base::SetSend();
}
TEST_F(WebRtcVideoMediaChannelTest, SetSendWithoutCodecs) {
Base::SetSendWithoutCodecs();
}
TEST_F(WebRtcVideoMediaChannelTest, SetSendSetsTransportBufferSizes) {
Base::SetSendSetsTransportBufferSizes();
}
TEST_F(WebRtcVideoMediaChannelTest, SendAndReceiveVp8Vga) {
SendAndReceive(cricket::VideoCodec(100, "VP8", 640, 400, 30, 0));
}
TEST_F(WebRtcVideoMediaChannelTest, SendAndReceiveVp8Qvga) {
SendAndReceive(cricket::VideoCodec(100, "VP8", 320, 200, 30, 0));
}
TEST_F(WebRtcVideoMediaChannelTest, SendAndReceiveVp8Qqvga) {
SendAndReceive(cricket::VideoCodec(100, "VP8", 160, 100, 30, 0));
}
TEST_F(WebRtcVideoMediaChannelTest, SendManyResizeOnce) {
SendManyResizeOnce();
}
TEST_F(WebRtcVideoMediaChannelTest, DISABLED_SendVp8HdAndReceiveAdaptedVp8Vga) {
EXPECT_TRUE(channel_->SetCapturer(kSsrc, NULL));
channel_->UpdateAspectRatio(1280, 720);
video_capturer_.reset(new cricket::FakeVideoCapturer);
const std::vector<cricket::VideoFormat>* formats =
video_capturer_->GetSupportedFormats();
cricket::VideoFormat capture_format_hd = (*formats)[0];
EXPECT_EQ(cricket::CS_RUNNING, video_capturer_->Start(capture_format_hd));
EXPECT_TRUE(channel_->SetCapturer(kSsrc, video_capturer_.get()));
// Capture format HD -> adapt (OnOutputFormatRequest VGA) -> VGA.
cricket::VideoCodec codec(100, "VP8", 1280, 720, 30, 0);
EXPECT_TRUE(SetOneCodec(codec));
codec.width /= 2;
codec.height /= 2;
EXPECT_TRUE(SetSend(true));
EXPECT_TRUE(channel_->SetRender(true));
EXPECT_EQ(0, renderer_.num_rendered_frames());
EXPECT_TRUE(SendFrame());
EXPECT_FRAME_WAIT(1, codec.width, codec.height, kTimeout);
}
TEST_F(WebRtcVideoMediaChannelTest, GetStats) {
Base::GetStats();
}
TEST_F(WebRtcVideoMediaChannelTest, GetStatsMultipleRecvStreams) {
Base::GetStatsMultipleRecvStreams();
}
TEST_F(WebRtcVideoMediaChannelTest, GetStatsMultipleSendStreams) {
Base::GetStatsMultipleSendStreams();
}
TEST_F(WebRtcVideoMediaChannelTest, SetSendBandwidth) {
Base::SetSendBandwidth();
}
TEST_F(WebRtcVideoMediaChannelTest, SetSendSsrc) {
Base::SetSendSsrc();
}
TEST_F(WebRtcVideoMediaChannelTest, SetSendSsrcAfterSetCodecs) {
Base::SetSendSsrcAfterSetCodecs();
}
TEST_F(WebRtcVideoMediaChannelTest, SetRenderer) {
Base::SetRenderer();
}
TEST_F(WebRtcVideoMediaChannelTest, AddRemoveRecvStreams) {
Base::AddRemoveRecvStreams();
}
// Flaky on Linux and Windows. See webrtc:4452.
#if defined(WEBRTC_WIN) || defined(WEBRTC_LINUX)
#define MAYBE_AddRemoveRecvStreamAndRender DISABLED_AddRemoveRecvStreamAndRender
#else
#define MAYBE_AddRemoveRecvStreamAndRender AddRemoveRecvStreamAndRender
#endif
TEST_F(WebRtcVideoMediaChannelTest, MAYBE_AddRemoveRecvStreamAndRender) {
Base::AddRemoveRecvStreamAndRender();
}
TEST_F(WebRtcVideoMediaChannelTest, AddRemoveRecvStreamsNoConference) {
Base::AddRemoveRecvStreamsNoConference();
}
TEST_F(WebRtcVideoMediaChannelTest, AddRemoveSendStreams) {
Base::AddRemoveSendStreams();
}
TEST_F(WebRtcVideoMediaChannelTest, SimulateConference) {
Base::SimulateConference();
}
TEST_F(WebRtcVideoMediaChannelTest, AddRemoveCapturer) {
Base::AddRemoveCapturer();
}
TEST_F(WebRtcVideoMediaChannelTest, RemoveCapturerWithoutAdd) {
Base::RemoveCapturerWithoutAdd();
}
TEST_F(WebRtcVideoMediaChannelTest, AddRemoveCapturerMultipleSources) {
Base::AddRemoveCapturerMultipleSources();
}
// This test verifies DSCP settings are properly applied on video media channel.
TEST_F(WebRtcVideoMediaChannelTest, TestSetDscpOptions) {
rtc::scoped_ptr<cricket::FakeNetworkInterface> network_interface(
new cricket::FakeNetworkInterface);
channel_->SetInterface(network_interface.get());
cricket::VideoOptions options;
options.dscp.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_EQ(rtc::DSCP_AF41, network_interface->dscp());
// Verify previous value is not modified if dscp option is not set.
cricket::VideoOptions options1;
EXPECT_TRUE(channel_->SetOptions(options1));
EXPECT_EQ(rtc::DSCP_AF41, network_interface->dscp());
options.dscp.Set(false);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_EQ(rtc::DSCP_DEFAULT, network_interface->dscp());
channel_->SetInterface(NULL);
}
TEST_F(WebRtcVideoMediaChannelTest, HighAspectHighHeightCapturer) {
Base::HighAspectHighHeightCapturer();
}
TEST_F(WebRtcVideoMediaChannelTest, SetOptionsSucceedsWhenSending) {
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
// Verify SetOptions returns true on a different options.
cricket::VideoOptions options2;
options2.adapt_input_to_cpu_usage.Set(true);
EXPECT_TRUE(channel_->SetOptions(options2));
// Set send codecs on the channel and start sending.
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_TRUE(channel_->SetSend(true));
// Verify SetOptions returns true if channel is already sending.
cricket::VideoOptions options3;
options3.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options3));
}
// Tests empty StreamParams is rejected.
TEST_F(WebRtcVideoMediaChannelTest, RejectEmptyStreamParams) {
Base::RejectEmptyStreamParams();
}
TEST_F(WebRtcVideoMediaChannelTest, AdaptResolution16x10) {
Base::AdaptResolution16x10();
}
TEST_F(WebRtcVideoMediaChannelTest, AdaptResolution4x3) {
Base::AdaptResolution4x3();
}
TEST_F(WebRtcVideoMediaChannelTest, MuteStream) {
Base::MuteStream();
}
TEST_F(WebRtcVideoMediaChannelTest, MultipleSendStreams) {
Base::MultipleSendStreams();
}
// TODO(juberti): Restore this test once we support sending 0 fps.
TEST_F(WebRtcVideoMediaChannelTest, DISABLED_AdaptDropAllFrames) {
Base::AdaptDropAllFrames();
}
// TODO(juberti): Understand why we get decode errors on this test.
TEST_F(WebRtcVideoMediaChannelTest, DISABLED_AdaptFramerate) {
Base::AdaptFramerate();
}
TEST_F(WebRtcVideoMediaChannelTest, SetSendStreamFormat0x0) {
Base::SetSendStreamFormat0x0();
}
// TODO(zhurunz): Fix the flakey test.
TEST_F(WebRtcVideoMediaChannelTest, DISABLED_SetSendStreamFormat) {
Base::SetSendStreamFormat();
}
TEST_F(WebRtcVideoMediaChannelTest, TwoStreamsSendAndReceive) {
Base::TwoStreamsSendAndReceive(cricket::VideoCodec(100, "VP8", 640, 400, 30,
0));
}
TEST_F(WebRtcVideoMediaChannelTest, TwoStreamsReUseFirstStream) {
Base::TwoStreamsReUseFirstStream(cricket::VideoCodec(100, "VP8", 640, 400, 30,
0));
}
TEST_F(WebRtcVideoMediaChannelTest, DISABLED_TwoStreamsSendAndUnsignalledRecv) {
Base::TwoStreamsSendAndUnsignalledRecv(cricket::VideoCodec(100, "VP8", 640,
400, 30, 0));
}
TEST_F(WebRtcVideoMediaChannelTest,
TwoStreamsSendAndFailUnsignalledRecv) {
Base::TwoStreamsSendAndFailUnsignalledRecv(
cricket::VideoCodec(100, "VP8", 640, 400, 30, 0));
}
TEST_F(WebRtcVideoMediaChannelTest,
TwoStreamsSendAndFailUnsignalledRecvInOneToOne) {
Base::TwoStreamsSendAndFailUnsignalledRecvInOneToOne(
cricket::VideoCodec(100, "VP8", 640, 400, 30, 0));
}
TEST_F(WebRtcVideoMediaChannelTest,
TwoStreamsAddAndRemoveUnsignalledRecv) {
Base::TwoStreamsAddAndRemoveUnsignalledRecv(cricket::VideoCodec(100, "VP8",
640, 400, 30,
0));
}
// Test that sequence number are not reset if stopping and then
// resuming a stream.
TEST_F(WebRtcVideoMediaChannelTest, DontResetSequenceNumbers) {
cricket::VideoCodec codec = DefaultCodec();
EXPECT_TRUE(SetOneCodec(codec));
uint16_t seq_before =
engine_.vie()
->rtp()
->GetRtpStateForSsrc(channel_->GetDefaultChannelId(), kSsrc)
.sequence_number;
// Deactive.
EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
EXPECT_TRUE(SetOneCodec(codec));
// Reactivate.
EXPECT_TRUE(channel_->AddSendStream(DefaultSendStreamParams()));
EXPECT_TRUE(SetOneCodec(codec));
// Sequence number should now have changed.
uint16_t seq_after =
engine_.vie()
->rtp()
->GetRtpStateForSsrc(channel_->GetDefaultChannelId(), kSsrc)
.sequence_number;
EXPECT_EQ(seq_before, seq_after);
}
static const unsigned int kNumberOfTemporalLayers = 1;
static const unsigned int kSimulcastNumberOfTemporalLayers = 3;
static const unsigned int kSimStream0Bitrate = 100;
static const unsigned int kSimStream0MaxBitrateBoosted = 200;
static const unsigned int kSimStream0MaxBitrateXd = 200;
static const unsigned int kSimStream0TargetBitrateBoosted = 150;
static const unsigned int kSimStream0TargetBitrateXd = 150;
static const unsigned int kSimStream1Bitrate = 350;
static const unsigned int kSimStream1MaxBitrateBoosted = 450;
static const unsigned int kSimStream1MaxBitrateXd = 450;
static const unsigned int kSimStream1TargetBitrateBoosted = 350;
static const unsigned int kSimStream1TargetBitrateXd = 350;
static const unsigned int kSimStream2Bitrate = 500;
static const unsigned int kSimStream2MaxBitrateBoosted = 700;
static const unsigned int kSimStream2MaxBitrateXd = 700;
static const unsigned int kSimStream2TargetBitrateBoosted = 500;
static const unsigned int kSimStream2TargetBitrateXd = 500;
static const unsigned int kSimStream3Bitrate = 900;
static const unsigned int kSimStream3MaxBitrateBoosted = 900;
static const unsigned int kSimStream3MaxBitrateXd = 900;
static const unsigned int kSimStream3TargetBitrateBoosted = 900;
static const unsigned int kSimStream3TargetBitrateXd = 900;
static const unsigned int kSimStream4Bitrate = 1200;
static const unsigned int kSimStream4MaxBitrateBoosted = 1200;
static const unsigned int kSimStream4MaxBitrateXd = 2500;
static const unsigned int kSimStream4TargetBitrateBoosted = 1200;
static const unsigned int kSimStream4TargetBitrateXd = 2500;
struct SimulcastFormat {
unsigned int width;
unsigned int height;
unsigned int max_layers;
unsigned int max_bitrate[cricket::SBM_COUNT];
unsigned int target_bitrate[cricket::SBM_COUNT];
};
static const SimulcastFormat kSimulcastFormats[] = {
{1280, 720, 3,
{kSimStream4Bitrate, kSimStream4MaxBitrateBoosted,
kSimStream4MaxBitrateXd},
{kSimStream4Bitrate, kSimStream4TargetBitrateBoosted,
kSimStream4TargetBitrateXd}},
{960, 540, 3,
{kSimStream3Bitrate, kSimStream3MaxBitrateBoosted,
kSimStream3MaxBitrateXd},
{kSimStream3Bitrate, kSimStream3TargetBitrateBoosted,
kSimStream3TargetBitrateXd}},
{640, 360, 2,
{kSimStream2Bitrate, kSimStream2MaxBitrateBoosted,
kSimStream2MaxBitrateXd},
{kSimStream2Bitrate, kSimStream2TargetBitrateBoosted,
kSimStream2TargetBitrateXd}},
{480, 270, 2,
{kSimStream1Bitrate, kSimStream1MaxBitrateBoosted,
kSimStream1MaxBitrateXd},
{kSimStream1Bitrate, kSimStream1TargetBitrateBoosted,
kSimStream1TargetBitrateXd}},
{320, 180, 1,
{kSimStream0Bitrate, kSimStream0MaxBitrateBoosted,
kSimStream0MaxBitrateXd},
{kSimStream0Bitrate, kSimStream0TargetBitrateBoosted,
kSimStream0TargetBitrateXd}},
{0, 0, 1,
{kSimStream0Bitrate, kSimStream0MaxBitrateBoosted,
kSimStream0MaxBitrateXd},
{kSimStream0Bitrate, kSimStream0TargetBitrateBoosted,
kSimStream0TargetBitrateXd}}
};
// Test fixture to test WebRtcVideoEngine with a fake webrtc::VideoEngine.
// Useful for testing failure paths.
class WebRtcVideoEngineSimulcastTestFake : public testing::Test,
public sigslot::has_slots<> {
public:
WebRtcVideoEngineSimulcastTestFake()
: vie_(kVideoCodecs, ARRAY_SIZE(kVideoCodecs)),
cpu_monitor_(new rtc::FakeCpuMonitor(
rtc::Thread::Current())),
engine_(NULL, // cricket::WebRtcVoiceEngineExtended
new FakeViEWrapper(&vie_), cpu_monitor_),
channel_(NULL),
voice_channel_(NULL),
last_error_(cricket::VideoMediaChannel::ERROR_NONE) {
}
bool SetupEngine() {
bool result = engine_.Init(rtc::Thread::Current());
if (result) {
channel_ = engine_.CreateChannel(cricket::VideoOptions(), voice_channel_);
channel_->SignalMediaError.connect(this,
&WebRtcVideoEngineSimulcastTestFake::OnMediaError);
result = (channel_ != NULL);
}
return result;
}
void OnMediaError(uint32 ssrc, cricket::VideoMediaChannel::Error error) {
last_error_ = error;
}
bool SendI420Frame(int width, int height) {
cricket::FakeVideoCapturer capturer;
return SendI420Frame(&capturer, width, height);
}
bool SendI420Frame(
cricket::FakeVideoCapturer* capturer, int width, int height) {
if (NULL == channel_) {
return false;
}
cricket::WebRtcVideoFrame frame;
if (!frame.InitToBlack(width, height, 1, 1, 0, 0)) {
return false;
}
channel_->SendFrame(capturer, &frame);
return true;
}
bool SendI420ScreencastFrame(int width, int height) {
return SendI420ScreencastFrameWithTimestamp(width, height, 0);
}
bool SendI420ScreencastFrameWithTimestamp(
int width, int height, int64 timestamp) {
if (NULL == channel_) {
return false;
}
cricket::WebRtcVideoFrame frame;
if (!frame.InitToBlack(width, height, 1, 1, 0, 0)) {
return false;
}
cricket::FakeVideoCapturer capturer;
capturer.SetScreencast(true);
channel_->SendFrame(&capturer, &frame);
return true;
}
void VerifyVP8SendCodec(
int channel_num,
unsigned int width,
unsigned int height,
unsigned int layers = 0,
unsigned int max_bitrate = kMaxBandwidthKbps,
unsigned int min_bitrate = kMinBandwidthKbps,
unsigned int start_bitrate = kStartBandwidthKbps,
unsigned int fps = 30,
unsigned int max_quantization = 0,
cricket::SimulcastBitrateMode bitrate_mode = cricket::SBM_NORMAL) {
webrtc::VideoCodec gcodec;
EXPECT_EQ(0, vie_.GetSendCodec(channel_num, gcodec));
// Video codec properties.
EXPECT_EQ(webrtc::kVideoCodecVP8, gcodec.codecType);
EXPECT_STREQ("VP8", gcodec.plName);
EXPECT_EQ(100, gcodec.plType);
EXPECT_EQ(width, gcodec.width);
EXPECT_EQ(height, gcodec.height);
EXPECT_EQ(std::min(start_bitrate, max_bitrate), gcodec.startBitrate);
EXPECT_EQ(max_bitrate, gcodec.maxBitrate);
EXPECT_EQ(min_bitrate, gcodec.minBitrate);
EXPECT_EQ(fps, gcodec.maxFramerate);
// VP8 specific.
EXPECT_FALSE(gcodec.codecSpecific.VP8.pictureLossIndicationOn);
EXPECT_FALSE(gcodec.codecSpecific.VP8.feedbackModeOn);
EXPECT_EQ(webrtc::kComplexityNormal, gcodec.codecSpecific.VP8.complexity);
EXPECT_EQ(webrtc::kResilienceOff, gcodec.codecSpecific.VP8.resilience);
EXPECT_EQ(max_quantization, gcodec.qpMax);
// Simulcast.
EXPECT_EQ(layers, gcodec.numberOfSimulcastStreams);
if (layers > 0) {
EXPECT_EQ(kSimulcastNumberOfTemporalLayers,
gcodec.codecSpecific.VP8.numberOfTemporalLayers);
} else {
EXPECT_EQ(kNumberOfTemporalLayers,
gcodec.codecSpecific.VP8.numberOfTemporalLayers);
}
for (int i = 0; i < static_cast<int>(layers) - 1; ++i) {
EXPECT_EQ(gcodec.width / (0x01 << (layers - 1 - i)),
gcodec.simulcastStream[i].width);
EXPECT_EQ(gcodec.height / (0x01 << (layers - 1 - i)),
gcodec.simulcastStream[i].height);
EXPECT_EQ(kSimulcastNumberOfTemporalLayers,
gcodec.simulcastStream[i].numberOfTemporalLayers);
EXPECT_EQ(FindSimulcastMaxBitrate(gcodec.simulcastStream[i].width,
gcodec.simulcastStream[i].height,
bitrate_mode),
gcodec.simulcastStream[i].maxBitrate);
EXPECT_EQ(gcodec.qpMax,
gcodec.simulcastStream[i].qpMax);
}
if (layers > 0)
EXPECT_EQ(kMinBandwidthKbps, gcodec.simulcastStream[0].minBitrate);
}
unsigned int FindSimulcastMaxBitrate(
unsigned int width,
unsigned int height,
cricket::SimulcastBitrateMode bitrate_mode) {
for (size_t i = 0; i < ARRAY_SIZE(kSimulcastFormats); ++i) {
if (width >= kSimulcastFormats[i].width &&
height >= kSimulcastFormats[i].height) {
return kSimulcastFormats[i].max_bitrate[bitrate_mode];
}
}
return 0;
}
void SetUp2SimulcastStreams(
cricket::VideoOptions::HighestBitrate high_bitrate_mode,
const cricket::VideoCodec& codec) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
options.video_highest_bitrate.Set(high_bitrate_mode);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2))));
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
}
void SetUp3SimulcastStreams(
cricket::VideoOptions::HighestBitrate high_bitrate_mode,
const cricket::VideoCodec& codec) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
options.video_highest_bitrate.Set(high_bitrate_mode);
EXPECT_TRUE(channel_->SetOptions(options));
// Set max settings of 1280x720x30 to make sure we can have maximumly 3
// simulcast streams.
EXPECT_TRUE(engine_.SetDefaultEncoderConfig(
cricket::VideoEncoderConfig(kVP8Codec720p)));
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs3))));
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
SendI420Frame(kVP8Codec720p.width, kVP8Codec720p.height);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
}
void TestSimulcastAdapter(const cricket::VideoCodec& send_codec,
bool expect_use_adapter) {
// Setup
engine_.SetExternalEncoderFactory(&encoder_factory_);
EXPECT_TRUE(SetupEngine());
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(send_codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(kSsrc)));
// Verify
int channel_num = vie_.GetLastChannel();
EXPECT_EQ(1, vie_.GetNumExternalEncoderRegistered(channel_num));
// If simulcast adapter is used, no external encoder instance will be
// created at this point. Otherwise 1 instance should have been created.
int num_enc_instance = expect_use_adapter ? 0 : 1;
EXPECT_EQ(num_enc_instance, encoder_factory_.GetNumCreatedEncoders());
// Clean up
EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
}
virtual void TearDown() {
delete channel_;
engine_.Terminate();
}
protected:
cricket::FakeWebRtcVideoEngine vie_;
cricket::FakeWebRtcVideoDecoderFactory decoder_factory_;
cricket::FakeWebRtcVideoEncoderFactory encoder_factory_;
rtc::FakeCpuMonitor* cpu_monitor_;
cricket::WebRtcVideoEngine engine_;
cricket::WebRtcVideoMediaChannel* channel_;
cricket::WebRtcVoiceMediaChannel* voice_channel_;
cricket::VideoMediaChannel::Error last_error_;
};
// Test fixtures to test WebRtcVideoEngine with a real
// webrtc::VideoEngine.
class WebRtcVideoEngineSimulcastTest
: public VideoEngineTest<cricket::WebRtcVideoEngine> {
protected:
typedef VideoEngineTest<cricket::WebRtcVideoEngine> Base;
};
class WebRtcVideoMediaChannelSimulcastTest
: public VideoMediaChannelTest<
cricket::WebRtcVideoEngine, cricket::WebRtcVideoMediaChannel> {
protected:
typedef VideoMediaChannelTest<cricket::WebRtcVideoEngine,
cricket::WebRtcVideoMediaChannel> Base;
virtual cricket::VideoCodec DefaultCodec() { return kVP8Codec; }
virtual void SetUp() {
Base::SetUp();
}
virtual void TearDown() {
Base::TearDown();
}
// Tests that simulcast sends rtp packets containing expected number of
// layers and payload type.
void SimulcastSend(const cricket::VideoCodec& codec,
const std::vector<uint32>& ssrcs) {
// Remove stream added in Setup.
EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
// Setup channel for sending and receiving simulcast packets.
cricket::VideoOptions vmo;
vmo.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(vmo));
EXPECT_TRUE(SetOneCodec(codec));
if (ssrcs.size() > 1) {
cricket::StreamParams sp;
cricket::SsrcGroup sg(cricket::kSimSsrcGroupSemantics, ssrcs);
sp.ssrcs = ssrcs;
sp.ssrc_groups.push_back(sg);
sp.cname = "cname";
EXPECT_TRUE(channel_->AddSendStream(sp));
} else {
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(ssrcs[0])));
}
// Re-configure capturer.
channel_->SetCapturer(kSsrc, NULL);
cricket::VideoFormat capture_format(codec.width, codec.height,
cricket::VideoFormat::FpsToInterval(codec.framerate),
cricket::FOURCC_I420);
EXPECT_TRUE(channel_->SetCapturer(ssrcs[0], video_capturer_.get()));
EXPECT_EQ(cricket::CS_RUNNING, video_capturer_->Start(capture_format));
EXPECT_TRUE(SetSend(true));
// Send one frame.
EXPECT_EQ(0, NumRtpPackets());
EXPECT_EQ(0, NumRtpBytes());
EXPECT_EQ(0, NumSentSsrcs());
EXPECT_TRUE(SendFrame());
// Verify received expected simulcast layers.
EXPECT_TRUE_WAIT(NumSentSsrcs() == static_cast<int>(ssrcs.size()),
10 * kTimeout);
// Stop sending before counting the packets, as padding will keep being sent
// which can cause a difference between total number of packets and the
// sum of packets on each ssrc if padding is sent in the summation loop.
EXPECT_TRUE(SetSend(false));
int total_num_packets = 0;
int total_num_bytes = 0;
for (size_t i = 0; i < ssrcs.size(); ++i) {
EXPECT_GE(NumRtpPackets(ssrcs[i]), 1);
EXPECT_GT(NumRtpBytes(ssrcs[i]), NumRtpPackets(ssrcs[i]));
total_num_packets += NumRtpPackets(ssrcs[i]);
total_num_bytes += NumRtpBytes(ssrcs[i]);
}
EXPECT_EQ(total_num_packets, NumRtpPackets());
EXPECT_EQ(total_num_bytes, NumRtpBytes());
// All packets have the given payload type.
for (int i = 0; i < total_num_packets; ++i) {
rtc::scoped_ptr<const rtc::Buffer> p(GetRtpPacket(i));
EXPECT_EQ(codec.id, GetPayloadType(p.get()));
}
}
void TestScreencastSettings() {
// Remove stream added in SetUp.
EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
cricket::VideoOptions options;
options.conference_mode.Set(true);
// Enable noise reduction to ensure that it's being disabled for
// screencasting.
options.video_noise_reduction.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
// Setup a simulcast stream and verify that we have the correct
// settings.
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2))));
cricket::VideoCodec codec(DefaultCodec());
EXPECT_TRUE(SetOneCodec(codec));
channel_->SetCapturer(kSsrc, NULL);
cricket::VideoFormat capture_format(codec.width, codec.height,
cricket::VideoFormat::FpsToInterval(codec.framerate),
cricket::FOURCC_I420);
EXPECT_TRUE(channel_->SetCapturer(kSsrcs2[0], video_capturer_.get()));
EXPECT_EQ(cricket::CS_RUNNING, video_capturer_->Start(capture_format));
EXPECT_TRUE(SetSend(true));
EXPECT_TRUE(SendFrame());
webrtc::VideoCodec video_codec;
int default_channel_id = channel_->GetDefaultChannelId();
EXPECT_EQ(0, channel_->engine()->vie()->codec()->GetSendCodec(
default_channel_id, video_codec));
EXPECT_FALSE(video_codec.codecSpecific.VP8.automaticResizeOn);
EXPECT_TRUE(video_codec.codecSpecific.VP8.denoisingOn);
EXPECT_EQ(webrtc::kRealtimeVideo, video_codec.mode);
EXPECT_EQ(3, video_codec.codecSpecific.VP8.numberOfTemporalLayers);
EXPECT_EQ(2, video_codec.numberOfSimulcastStreams);
EXPECT_NE(0u, video_codec.simulcastStream[0].minBitrate);
EXPECT_NE(0u, video_codec.simulcastStream[0].targetBitrate);
EXPECT_NE(0u, video_codec.simulcastStream[0].maxBitrate);
EXPECT_NE(0u, video_codec.simulcastStream[1].minBitrate);
EXPECT_NE(0u, video_codec.simulcastStream[1].targetBitrate);
EXPECT_NE(0u, video_codec.simulcastStream[1].maxBitrate);
// Register a fake screencast capturer and verify that the video settings
// change as expected.
rtc::scoped_ptr<cricket::FakeVideoCapturer> capturer(
new cricket::FakeVideoCapturer);
capturer->SetScreencast(true);
const std::vector<cricket::VideoFormat>* formats =
capturer->GetSupportedFormats();
capture_format = (*formats)[0];
EXPECT_EQ(cricket::CS_RUNNING, capturer->Start(capture_format));
EXPECT_TRUE(channel_->SetCapturer(kSsrcs2[0], capturer.get()));
EXPECT_TRUE(rtc::Thread::Current()->ProcessMessages(30));
EXPECT_TRUE(capturer->CaptureFrame());
default_channel_id = channel_->GetDefaultChannelId();
EXPECT_EQ(0, channel_->engine()->vie()->codec()->GetSendCodec(
default_channel_id, video_codec));
EXPECT_FALSE(video_codec.codecSpecific.VP8.automaticResizeOn);
EXPECT_FALSE(video_codec.codecSpecific.VP8.denoisingOn);
EXPECT_EQ(webrtc::kScreensharing, video_codec.mode);
const int expected_num_layers = 2;
EXPECT_EQ(expected_num_layers,
video_codec.codecSpecific.VP8.numberOfTemporalLayers);
EXPECT_EQ(2, video_codec.numberOfSimulcastStreams);
EXPECT_EQ(0u, video_codec.simulcastStream[0].minBitrate);
EXPECT_EQ(0u, video_codec.simulcastStream[0].targetBitrate);
EXPECT_EQ(0u, video_codec.simulcastStream[0].maxBitrate);
// Make sure that removing screencast restores the simulcast settings.
EXPECT_TRUE(channel_->SetCapturer(kSsrcs2[0], video_capturer_.get()));
EXPECT_TRUE(WaitAndSendFrame(30));
EXPECT_EQ(0, channel_->engine()->vie()->codec()->GetSendCodec(
default_channel_id, video_codec));
EXPECT_FALSE(video_codec.codecSpecific.VP8.automaticResizeOn);
EXPECT_TRUE(video_codec.codecSpecific.VP8.denoisingOn);
EXPECT_EQ(webrtc::kRealtimeVideo, video_codec.mode);
EXPECT_EQ(3, video_codec.codecSpecific.VP8.numberOfTemporalLayers);
EXPECT_EQ(2, video_codec.numberOfSimulcastStreams);
EXPECT_NE(0u, video_codec.simulcastStream[0].minBitrate);
EXPECT_NE(0u, video_codec.simulcastStream[0].targetBitrate);
EXPECT_NE(0u, video_codec.simulcastStream[0].maxBitrate);
EXPECT_NE(0u, video_codec.simulcastStream[1].minBitrate);
EXPECT_NE(0u, video_codec.simulcastStream[1].targetBitrate);
EXPECT_NE(0u, video_codec.simulcastStream[1].maxBitrate);
}
};
// Test that we apply send codec with simulcast properly.
TEST_F(WebRtcVideoEngineSimulcastTestFake, SetSendCodecsWith1SimulcastStreams) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
// One ssrc simulcast StreamParams should be rejected.
EXPECT_FALSE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs1))));
}
TEST_F(WebRtcVideoEngineSimulcastTestFake, SetSendCodecsWith2SimulcastStreams) {
cricket::VideoCodec codec(kVP8Codec);
SetUp2SimulcastStreams(cricket::VideoOptions::NORMAL, codec);
int channel_num = vie_.GetLastChannel();
VerifyVP8SendCodec(channel_num, codec.width, codec.height, 2,
kSimStream0Bitrate + kSimStream2MaxBitrateBoosted);
}
TEST_F(WebRtcVideoEngineSimulcastTestFake, SetSendCodecsWith3SimulcastStreams) {
cricket::VideoCodec codec(kVP8Codec720p);
SetUp3SimulcastStreams(cricket::VideoOptions::NORMAL, codec);
int channel_num = vie_.GetLastChannel();
VerifyVP8SendCodec(channel_num, codec.width, codec.height, 3,
kSimStream0Bitrate + kSimStream2Bitrate +
kSimStream4Bitrate);
}
TEST_F(WebRtcVideoEngineSimulcastTestFake,
SetSendCodecsWith2SimulcastStreamsHighBitrateMode) {
cricket::VideoCodec codec(kVP8Codec);
SetUp2SimulcastStreams(cricket::VideoOptions::HIGH, codec);
int channel_num = vie_.GetLastChannel();
VerifyVP8SendCodec(channel_num, codec.width, codec.height, 2,
kSimStream0TargetBitrateBoosted +
kSimStream2MaxBitrateBoosted, kMinBandwidthKbps,
kStartBandwidthKbps, 30, 0, cricket::SBM_HIGH);
}
TEST_F(WebRtcVideoEngineSimulcastTestFake,
SetSendCodecsWith3SimulcastStreamsHighBitrateMode) {
cricket::VideoCodec codec(kVP8Codec720p);
SetUp3SimulcastStreams(cricket::VideoOptions::HIGH, codec);
int channel_num = vie_.GetLastChannel();
VerifyVP8SendCodec(channel_num, codec.width, codec.height, 3,
kSimStream0TargetBitrateBoosted +
kSimStream2TargetBitrateBoosted +
kSimStream4MaxBitrateBoosted, kMinBandwidthKbps,
kStartBandwidthKbps, 30, 0, cricket::SBM_HIGH);
}
TEST_F(WebRtcVideoEngineSimulcastTestFake,
SetSendCodecsWith2SimulcastStreamsVeryHighBitrateMode) {
cricket::VideoCodec codec(kVP8Codec);
SetUp2SimulcastStreams(cricket::VideoOptions::VERY_HIGH,
codec);
int channel_num = vie_.GetLastChannel();
VerifyVP8SendCodec(channel_num, codec.width, codec.height, 2,
kSimStream0TargetBitrateXd +
kSimStream2MaxBitrateXd, kMinBandwidthKbps,
kStartBandwidthKbps, 30, 0, cricket::SBM_VERY_HIGH);
}
TEST_F(WebRtcVideoEngineSimulcastTestFake,
SetSendCodecsWith3SimulcastStreamsVeryHighBitrateMode) {
cricket::VideoCodec codec(kVP8Codec720p);
SetUp3SimulcastStreams(cricket::VideoOptions::VERY_HIGH,
codec);
int channel_num = vie_.GetLastChannel();
VerifyVP8SendCodec(channel_num, codec.width, codec.height, 3,
kSimStream0TargetBitrateXd +
kSimStream2TargetBitrateXd +
kSimStream4MaxBitrateXd, kMinBandwidthKbps,
kStartBandwidthKbps, 30, 0, cricket::SBM_VERY_HIGH);
}
// Test that we normalize send codec format size in simulcast.
TEST_F(WebRtcVideoEngineSimulcastTestFake,
SetSendCodecsWithOddSizeInSimulcast) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
int channel_num = vie_.GetLastChannel();
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2))));
// Set send codec and verify we get two simulcast sub-streams with
// normalized size.
cricket::VideoCodec codec(kVP8Codec270p);
codec.width += 0x01;
codec.height += 0x01;
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
codec.width &= ~0x01;
codec.height &= ~0x01;
VerifyVP8SendCodec(channel_num, codec.width, codec.height, 2,
kSimStream0Bitrate + kSimStream1MaxBitrateBoosted);
}
// Test that if we add a stream with RTX SSRC's, SSRC's get set correctly.
TEST_F(WebRtcVideoEngineSimulcastTestFake, TestStreamWithRtx) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
int channel_num = vie_.GetLastChannel();
// Set max settings of 1280x720x30 to make sure we can have maximumly 3
// simulcast streams.
EXPECT_TRUE(engine_.SetDefaultEncoderConfig(
cricket::VideoEncoderConfig(kVP8Codec720p)));
// Verify only the first SSRC is set here.
// The rest are set during SetSendCodecs.
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimWithRtxStreamParams("cname",
MAKE_VECTOR(kSsrcs3),
MAKE_VECTOR(kRtxSsrcs3))));
EXPECT_EQ(1, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(1, vie_.GetNumRtxSsrcs(channel_num));
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(kVP8Codec720p);
cricket::VideoCodec rtx_codec(96, "rtx", 0, 0, 0, 0);
rtx_codec.SetParam("apt", kVP8Codec.id);
codec_list.push_back(rtx_codec);
SendI420Frame(kVP8Codec720p.width, kVP8Codec720p.height);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
// RTX payload type should now be set.
EXPECT_EQ(vie_.GetRtxSendPayloadTypes(channel_num),
MAKE_VECTOR(kPayloadTypes1));
// Verify all SSRCs are set after SetSendCodecs.
EXPECT_EQ(3, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(3, vie_.GetNumRtxSsrcs(channel_num));
EXPECT_EQ(1, vie_.GetSsrc(channel_num, 0));
EXPECT_EQ(2, vie_.GetSsrc(channel_num, 1));
EXPECT_EQ(3, vie_.GetSsrc(channel_num, 2));
EXPECT_EQ(4, vie_.GetRtxSsrc(channel_num, 0));
EXPECT_EQ(5, vie_.GetRtxSsrc(channel_num, 1));
EXPECT_EQ(6, vie_.GetRtxSsrc(channel_num, 2));
uint32 ssrc;
EXPECT_EQ(0, vie_.GetLocalSSRC(channel_num, ssrc));
EXPECT_EQ(1U, ssrc);
}
// Test that if we get too few ssrcs are given in AddSendStream(),
// only supported sub-streams will be added.
TEST_F(WebRtcVideoEngineSimulcastTestFake, TooFewSimulcastSsrcs) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
int channel_num = vie_.GetLastChannel();
// Set max settings of 1280x720x30 to make sure we can have maximumly 3
// simulcast streams.
EXPECT_TRUE(engine_.SetDefaultEncoderConfig(
cricket::VideoEncoderConfig(kVP8Codec720p)));
// Verify only the first SSRC is set here.
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2))));
EXPECT_EQ(1, vie_.GetNumSsrcs(channel_num));
cricket::VideoCodec codec(kVP8Codec720p);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
SendI420Frame(kVP8Codec720p.width, kVP8Codec720p.height);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
// Verify all SSRCs are set after SetSendCodecs.
EXPECT_EQ(2, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(1, vie_.GetSsrc(channel_num, 0));
EXPECT_EQ(2, vie_.GetSsrc(channel_num, 1));
uint32 ssrc;
EXPECT_EQ(0, vie_.GetLocalSSRC(channel_num, ssrc));
EXPECT_EQ(1U, ssrc);
VerifyVP8SendCodec(channel_num, 640, 360, 2,
kSimStream0Bitrate + kSimStream2MaxBitrateBoosted);
}
// Test that even more than enough ssrcs are given in AddSendStream(),
// only supported sub-streams will be added.
TEST_F(WebRtcVideoEngineSimulcastTestFake, MoreThanEnoughSimulcastSscrs) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
int channel_num = vie_.GetLastChannel();
// Set max settings of 1280x720x30 to make sure we can have maximumly 3
// simulcast streams.
EXPECT_TRUE(engine_.SetDefaultEncoderConfig(
cricket::VideoEncoderConfig(kVP8Codec720p)));
// Verify only the first SSRC is set here.
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs4))));
EXPECT_EQ(1, vie_.GetNumSsrcs(channel_num));
cricket::VideoCodec codec(kVP8Codec720p);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
SendI420Frame(kVP8Codec720p.width, kVP8Codec720p.height);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
// Verify all SSRCs are set after SetSendCodecs.
EXPECT_EQ(3, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(1, vie_.GetSsrc(channel_num, 0));
EXPECT_EQ(2, vie_.GetSsrc(channel_num, 1));
EXPECT_EQ(3, vie_.GetSsrc(channel_num, 2));
uint32 ssrc;
EXPECT_EQ(0, vie_.GetLocalSSRC(channel_num, ssrc));
EXPECT_EQ(1U, ssrc);
VerifyVP8SendCodec(channel_num, codec.width, codec.height, 3,
kSimStream0Bitrate + kSimStream2Bitrate + kSimStream4Bitrate);
}
// Test that SetSendStreamFormat works well with simulcast.
TEST_F(WebRtcVideoEngineSimulcastTestFake, SetSendStreamFormatWithSimulcast) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
int channel_num = vie_.GetLastChannel();
// Verify SetSendStreamFormat fail before there is a send stream.
cricket::VideoFormat format = engine_.default_codec_format();
EXPECT_FALSE(channel_->SetSendStreamFormat(1, format));
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2))));
// Capture format HD
cricket::FakeVideoCapturer video_capturer;
const std::vector<cricket::VideoFormat>* formats =
video_capturer.GetSupportedFormats();
cricket::VideoFormat capture_format_hd = (*formats)[0];
EXPECT_EQ(cricket::CS_RUNNING, video_capturer.Start(capture_format_hd));
EXPECT_TRUE(channel_->SetCapturer(kSsrcs2[0], &video_capturer));
cricket::VideoCodec codec(kVP8Codec360p);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
SendI420Frame(&video_capturer, kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
EXPECT_EQ(2, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(1, vie_.GetSsrc(channel_num, 0));
EXPECT_EQ(2, vie_.GetSsrc(channel_num, 1));
VerifyVP8SendCodec(channel_num, codec.width, codec.height, 2,
kSimStream0Bitrate + kSimStream2MaxBitrateBoosted);
// Verify SetSendStreamFormat with the same resolution doesn't
// change the number of simulcast sub-streams.
format.width = codec.width;
format.height = codec.height;
EXPECT_TRUE(channel_->SetSendStreamFormat(1, format));
EXPECT_EQ(2, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(1, vie_.GetSsrc(channel_num, 0));
EXPECT_EQ(2, vie_.GetSsrc(channel_num, 1));
// Capture format HD -> adapt (OnOutputFormatRequest VGA) -> VGA.
EXPECT_TRUE(video_capturer.CaptureFrame());
VerifyVP8SendCodec(channel_num, codec.width, codec.height, 2,
kSimStream0Bitrate + kSimStream2MaxBitrateBoosted);
// Now, ask for a small resolution and verify that we only get one stream.
format.width = codec.width / 2;
format.height = codec.height / 2;
EXPECT_TRUE(channel_->SetSendStreamFormat(1, format));
// Capture format HD -> adapt (OnOutputFormatRequest QVGA) -> QVGA.
EXPECT_TRUE(video_capturer.CaptureFrame());
VerifyVP8SendCodec(channel_num, format.width, format.height, 1,
kSimStream0MaxBitrateBoosted);
// Bump resolution back and verify there are 2 sub-streams again.
format.width = codec.width;
format.height = codec.height;
EXPECT_TRUE(channel_->SetSendStreamFormat(1, format));
EXPECT_EQ(2, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(1, vie_.GetSsrc(channel_num, 0));
EXPECT_EQ(2, vie_.GetSsrc(channel_num, 1));
// Capture format HD -> adapt (OnOutputFormatRequest VGA) -> VGA.
EXPECT_TRUE(video_capturer.CaptureFrame());
VerifyVP8SendCodec(channel_num, format.width, format.height, 2,
kSimStream0Bitrate + kSimStream2MaxBitrateBoosted);
// Verify SetSendStreamFormat can use either ssrc in the simulcast
// ssrc group.
format.width = codec.width / 2;
format.height = codec.height / 2;
EXPECT_TRUE(channel_->SetSendStreamFormat(2, format));
EXPECT_EQ(2, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(1, vie_.GetSsrc(channel_num, 0));
EXPECT_EQ(2, vie_.GetSsrc(channel_num, 1));
// Capture format HD -> adapt (OnOutputFormatRequest QVGA) -> QVGA.
EXPECT_TRUE(video_capturer.CaptureFrame());
VerifyVP8SendCodec(channel_num, format.width, format.height, 1,
kSimStream0MaxBitrateBoosted);
// Verify SetSendStreamFormat with bad ssrc fail.
format.width = codec.width;
format.height = codec.height;
EXPECT_FALSE(channel_->SetSendStreamFormat(3, format));
EXPECT_EQ(2, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(1, vie_.GetSsrc(channel_num, 0));
EXPECT_EQ(2, vie_.GetSsrc(channel_num, 1));
VerifyVP8SendCodec(channel_num, format.width / 2, format.height / 2, 1,
kSimStream0MaxBitrateBoosted);
EXPECT_TRUE(channel_->SetCapturer(kSsrcs2[0], NULL));
}
// Test that simulcast send codec is reset on new video frame size.
TEST_F(WebRtcVideoEngineSimulcastTestFake,
ResetSimulcastSendCodecOnNewFrameSize) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
int channel_num = vie_.GetLastChannel();
// Set send codec.
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2))));
cricket::VideoCodec codec(kVP8Codec);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
EXPECT_TRUE(channel_->SetSend(true));
EXPECT_EQ(1, vie_.GetNumSetSendCodecs());
// Feed in frames with different sizes and verify simulcast send codec
// changes accordingly.
// Send an odd frame. Verify format size get normalized.
SendI420Frame(kVP8Codec.width | 0x01, kVP8Codec.height | 0x01);
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 2,
kSimStream0Bitrate + kSimStream2MaxBitrateBoosted);
EXPECT_EQ(2, vie_.GetNumSetSendCodecs());
// Send a big frame. Verify format size never exceed original send codec
// format size.
SendI420Frame(kVP8Codec.width * 2, kVP8Codec.height * 2);
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 2,
kSimStream0Bitrate + kSimStream2MaxBitrateBoosted);
EXPECT_EQ(2, vie_.GetNumSetSendCodecs());
// Send a small frame. Verify format size is bumped in order to meet
// the minimum simulcast reqirement while keeping the aspect ratio.
SendI420Frame(kVP8Codec.width / 2, kVP8Codec.height / 2);
// Need at least 480x270 to have simulcast.
VerifyVP8SendCodec(channel_num, kVP8Codec.width / 2, kVP8Codec.height / 2, 1,
kSimStream0MaxBitrateBoosted);
EXPECT_EQ(3, vie_.GetNumSetSendCodecs());
// Send a normal frame. Verify format size is back to normal.
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 2,
kSimStream0Bitrate + kSimStream2MaxBitrateBoosted);
EXPECT_EQ(4, vie_.GetNumSetSendCodecs());
// Send an odd frame again.
SendI420Frame(kVP8Codec.width | 0x01, kVP8Codec.height | 0x01);
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 2,
kSimStream0Bitrate + kSimStream2MaxBitrateBoosted);
EXPECT_EQ(4, vie_.GetNumSetSendCodecs());
}
// Test that simulcast send codec is reset on new portait mode video frame.
TEST_F(WebRtcVideoEngineSimulcastTestFake,
ResetSimulcastSendCodecOnNewPortaitFrame) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
int channel_num = vie_.GetLastChannel();
// Set send codec.
EXPECT_TRUE(engine_.SetDefaultEncoderConfig(
cricket::VideoEncoderConfig(kVP8Codec720p)));
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2))));
cricket::VideoCodec codec(kVP8Codec720p);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
EXPECT_TRUE(channel_->SetSend(true));
EXPECT_EQ(1, vie_.GetNumSetSendCodecs());
// Feed in frames with different sizes and verify simulcast send codec
// changes accordingly.
// Send a portait mode frame.
SendI420Frame(kVP8Codec.height, kVP8Codec.width);
VerifyVP8SendCodec(channel_num, kVP8Codec.height, kVP8Codec.width, 2,
kSimStream0Bitrate + kSimStream2MaxBitrateBoosted);
EXPECT_EQ(2, vie_.GetNumSetSendCodecs());
}
TEST_F(WebRtcVideoEngineSimulcastTestFake,
SetBandwidthInConferenceWithSimulcast) {
cricket::VideoCodec ccodec(kVP8Codec720p);
SetUp3SimulcastStreams(cricket::VideoOptions::NORMAL, ccodec);
// A higher value than the sum of max of all layers should add the extra
// bandwidth to the higher layer.
uint32 max_bandwidth = 5000;
EXPECT_TRUE(channel_->SetMaxSendBandwidth(max_bandwidth * 1000));
int channel_num = vie_.GetLastChannel();
webrtc::VideoCodec codec;
codec.width = 0; codec.height = 0;
EXPECT_EQ(0, vie_.GetSendCodec(channel_num, codec));
EXPECT_EQ(max_bandwidth, codec.maxBitrate);
int nr_layers = 3;
uint32 sum_bandwidth = 0;
for (int i = 0; i < nr_layers; ++i) {
if (i == nr_layers - 1) {
EXPECT_EQ(max_bandwidth - sum_bandwidth,
codec.simulcastStream[i].maxBitrate);
} else {
EXPECT_EQ(FindSimulcastMaxBitrate(codec.simulcastStream[i].width,
codec.simulcastStream[i].height,
cricket::SBM_NORMAL),
codec.simulcastStream[i].maxBitrate);
sum_bandwidth += codec.simulcastStream[i].maxBitrate;
}
}
// Test setting max bandwidth below the sum of layer specific max bandwidth.
// Basically, the simulcast max overrides the SetMaxSendBandwidth value.
EXPECT_TRUE(channel_->SetMaxSendBandwidth(1));
VerifyVP8SendCodec(channel_num, codec.width, codec.height, 3,
kSimStream0Bitrate + kSimStream2Bitrate +
kSimStream4Bitrate);
}
// Test that sending screencast frames in conference mode changes
// bitrate.
TEST_F(WebRtcVideoEngineSimulcastTestFake, SetBandwidthScreencastInConference) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
// Set send codec.
cricket::VideoCodec codec(kVP8Codec);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(123)));
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
EXPECT_TRUE(channel_->SetMaxSendBandwidth(1200000));
EXPECT_EQ(2, vie_.GetNumSetSendCodecs());
// Set conference mode and verify that this caps maxBitrate.
webrtc::VideoCodec gcodec;
EXPECT_EQ(0, vie_.GetSendCodec(channel_num, gcodec));
EXPECT_GT(gcodec.maxBitrate, 1000u);
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_TRUE(channel_->SetSend(true));
SendI420ScreencastFrame(kVP8Codec.width, kVP8Codec.height);
EXPECT_EQ(3, vie_.GetNumSetSendCodecs());
EXPECT_EQ(0, vie_.GetSendCodec(channel_num, gcodec));
EXPECT_EQ(1000u, gcodec.maxBitrate);
}
// Test AddSendStream with simulcast rejects bad StreamParams.
TEST_F(WebRtcVideoEngineSimulcastTestFake, AddSendStreamWithBadStreamParams) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
// Verify non-sim StreamParams is rejected.
cricket::StreamParams sp_bad;
std::vector<uint32> ssrcs;
ssrcs.push_back(1234);
ssrcs.push_back(5678);
cricket::SsrcGroup sg("bad", ssrcs);
sp_bad.ssrcs = ssrcs;
sp_bad.ssrc_groups.push_back(sg);
sp_bad.cname = "cname";
EXPECT_FALSE(channel_->AddSendStream(sp_bad));
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2))));
}
// Test AddSendStream with simulcast sets ssrc and cname correctly.
TEST_F(WebRtcVideoEngineSimulcastTestFake, AddSendStreamWithSimulcast) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
int channel_num = vie_.GetLastChannel();
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2))));
unsigned int ssrc = 0;
EXPECT_EQ(1, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(0, vie_.GetLocalSSRC(channel_num, ssrc));
EXPECT_EQ(1U, ssrc);
char rtcp_cname[256];
EXPECT_EQ(0, vie_.GetRTCPCName(channel_num, rtcp_cname));
EXPECT_STREQ("cname", rtcp_cname);
EXPECT_TRUE(channel_->RemoveSendStream(1));
}
// Test RemoveSendStream with simulcast.
TEST_F(WebRtcVideoEngineSimulcastTestFake, RemoveSendStreamWithSimulcast) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
// RemoveSendStream should fail when there is no send stream.
EXPECT_FALSE(channel_->RemoveSendStream(1));
cricket::StreamParams stream =
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2));
EXPECT_TRUE(channel_->AddSendStream(stream));
// RemoveSendStream should fail with bad ssrc.
EXPECT_FALSE(channel_->RemoveSendStream(3));
EXPECT_TRUE(channel_->RemoveSendStream(1));
// RemoveSendStream should work with either ssrc.
EXPECT_TRUE(channel_->AddSendStream(stream));
EXPECT_TRUE(channel_->RemoveSendStream(1));
EXPECT_TRUE(channel_->AddSendStream(stream));
EXPECT_TRUE(channel_->RemoveSendStream(2));
// RemoveSendStream should fail when there is no send stream.
EXPECT_FALSE(channel_->RemoveSendStream(1));
}
// Test AddSendStream after send codec has already been set will reset
// send codec with simulcast settings.
TEST_F(WebRtcVideoEngineSimulcastTestFake,
AddSimulcastStreamAfterSetSendCodec) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
int channel_num = vie_.GetLastChannel();
// Set send codec.
cricket::VideoCodec codec(kVP8Codec);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
VerifyVP8SendCodec(channel_num, codec.width, codec.height);
// Add simulcast send stream and verify send codec has been reset.
// Provide 3 ssrcs here and only 2 layers should be added.
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs3))));
VerifyVP8SendCodec(channel_num, codec.width, codec.height, 2,
kSimStream0Bitrate + kSimStream2MaxBitrateBoosted);
// Verify local SSRCs are now populated correctly.
EXPECT_EQ(2, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(1, vie_.GetSsrc(channel_num, 0));
EXPECT_EQ(2, vie_.GetSsrc(channel_num, 1));
uint32 ssrc;
EXPECT_EQ(0, vie_.GetLocalSSRC(channel_num, ssrc));
EXPECT_EQ(1U, ssrc);
// Remove the stream and reset send codec with a smaller size.
EXPECT_TRUE(channel_->RemoveSendStream(1));
VerifyVP8SendCodec(channel_num, codec.width, codec.height, 2,
kSimStream0Bitrate + kSimStream2MaxBitrateBoosted);
codec_list.clear();
codec.width /= 2;
codec.height /= 2;
codec_list.push_back(codec);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
VerifyVP8SendCodec(channel_num, codec.width, codec.height);
// Add simulcast send stream again and verify simulcast have one stream.
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2))));
VerifyVP8SendCodec(channel_num, codec.width, codec.height, 1,
kSimStream0MaxBitrateBoosted);
// Verify we still have 2 SSRCs.
EXPECT_EQ(2, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(1, vie_.GetSsrc(channel_num, 0));
EXPECT_EQ(2, vie_.GetSsrc(channel_num, 1));
EXPECT_EQ(0, vie_.GetLocalSSRC(channel_num, ssrc));
EXPECT_EQ(1U, ssrc);
}
TEST_F(WebRtcVideoEngineSimulcastTestFake, GetStatsWithMultipleSsrcs) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
// Add simulcast stream.
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2))));
// Set send codec and verify we get two simulcast sub-streams.
cricket::VideoCodec codec(kVP8Codec);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
EXPECT_TRUE(channel_->SetSend(true));
cricket::FakeVideoCapturer video_capturer;
const std::vector<cricket::VideoFormat>* formats =
video_capturer.GetSupportedFormats();
cricket::VideoFormat capture_format_vga = (*formats)[1];
EXPECT_EQ(cricket::CS_RUNNING, video_capturer.Start(capture_format_vga));
EXPECT_TRUE(channel_->SetCapturer(kSsrcs2[0], &video_capturer));
// Only require one cpu sample for testing whether the adapter is hooked up.
cricket::CoordinatedVideoAdapter* video_adapter = NULL;
ASSERT_TRUE(channel_->GetVideoAdapter(0u, &video_adapter));
video_adapter->set_cpu_load_min_samples(1);
cpu_monitor_->SignalUpdate(1, 1, 0.1f, 0.85f);
// Capture format VGA -> adapt (OnCpuLoadUpdate downgrade) -> VGA/2.
EXPECT_TRUE(video_capturer.CaptureFrame());
// Get stats and verify there are 2 ssrcs.
cricket::VideoMediaInfo info;
EXPECT_TRUE(channel_->GetStats(&info));
ASSERT_EQ(1U, info.senders.size());
ASSERT_EQ(2U, info.senders[0].ssrcs().size());
EXPECT_EQ(1U, info.senders[0].ssrcs()[0]);
EXPECT_EQ(2U, info.senders[0].ssrcs()[1]);
// Verify the input/send width/height.
EXPECT_EQ(capture_format_vga.width, info.senders[0].input_frame_width);
EXPECT_EQ(capture_format_vga.height, info.senders[0].input_frame_height);
EXPECT_EQ(capture_format_vga.width * 3 / 4,
info.senders[0].send_frame_width);
EXPECT_EQ(capture_format_vga.height * 3 / 4,
info.senders[0].send_frame_height);
EXPECT_TRUE(channel_->SetCapturer(kSsrcs2[0], NULL));
}
// Test receiving channel(s) local ssrc is set to the same as the first
// simulcast sending ssrc.
TEST_F(WebRtcVideoEngineSimulcastTestFake,
AddSimulcastStreamAfterCreatingRecvChannels) {
EXPECT_TRUE(SetupEngine());
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
int channel_num = vie_.GetLastChannel();
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(10)));
int receive_channel_1 = vie_.GetLastChannel();
EXPECT_TRUE(channel_->AddRecvStream(cricket::StreamParams::CreateLegacy(11)));
int receive_channel_2 = vie_.GetLastChannel();
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2))));
unsigned int ssrc = 0;
EXPECT_EQ(1, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(0, vie_.GetLocalSSRC(channel_num, ssrc));
EXPECT_EQ(1U, ssrc);
EXPECT_EQ(0, vie_.GetLocalSSRC(receive_channel_1, ssrc));
EXPECT_EQ(1U, ssrc);
EXPECT_EQ(1, vie_.GetNumSsrcs(receive_channel_1));
EXPECT_EQ(0, vie_.GetLocalSSRC(receive_channel_2, ssrc));
EXPECT_EQ(1U, ssrc);
EXPECT_EQ(1, vie_.GetNumSsrcs(receive_channel_2));
}
// Test 1:1 call never turn on simulcast.
TEST_F(WebRtcVideoEngineSimulcastTestFake, NoSimulcastWith1on1) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2))));
// Set send codec and verify there is no simulcast sub-streams.
cricket::VideoCodec codec(kVP8Codec);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
VerifyVP8SendCodec(channel_num, codec.width, codec.height);
EXPECT_EQ(1, vie_.GetNumSsrcs(channel_num));
// Set options with OPT_CONFERENCE flag and set send codec again.
// Verify simulcast is used now.
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
VerifyVP8SendCodec(channel_num, codec.width, codec.height, 2,
kSimStream0Bitrate + kSimStream2MaxBitrateBoosted);
EXPECT_EQ(2, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(1, vie_.GetSsrc(channel_num, 0));
EXPECT_EQ(2, vie_.GetSsrc(channel_num, 1));
// Remove OPT_CONFERENCE flag and set send codec again.
// Verify simulcast is off again.
options.conference_mode.Set(false);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
VerifyVP8SendCodec(channel_num, codec.width, codec.height);
// Verify we still have 2 SSRCs.
EXPECT_EQ(2, vie_.GetNumSsrcs(channel_num));
EXPECT_EQ(1, vie_.GetSsrc(channel_num, 0));
EXPECT_EQ(2, vie_.GetSsrc(channel_num, 1));
}
// Test SetOptions with OPT_CONFERENCE flag.
TEST_F(WebRtcVideoEngineSimulcastTestFake, SetOptionsWithConferenceMode) {
EXPECT_TRUE(SetupEngine());
int channel_num = vie_.GetLastChannel();
// Set send codec.
cricket::VideoCodec codec(kVP8Codec);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
// Verify default send codec and bitrate.
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height);
// Set options with OPT_CONFERENCE flag.
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
// Change the max bitrate and verify it has changed.
channel_->SetMaxSendBandwidth(kSimStream2MaxBitrateBoosted * 1000);
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height, 0,
kSimStream2MaxBitrateBoosted);
// Turn off conference mode and verify the max bandwidth changed
// back.
options.conference_mode.Set(false);
EXPECT_TRUE(channel_->SetOptions(options));
VerifyVP8SendCodec(channel_num, kVP8Codec.width, kVP8Codec.height);
// Set send codec again with a smaller size.
codec_list.clear();
codec.width /= 2;
codec.height /= 2;
codec_list.push_back(codec);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
// Set options with OPT_CONFERENCE flag and set the max bitrate again.
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
channel_->SetMaxSendBandwidth(kSimStream0MaxBitrateBoosted * 1000);
// Verify channel now has a new max bitrate.
VerifyVP8SendCodec(channel_num, kVP8Codec.width / 2, kVP8Codec.height / 2, 0,
kSimStream0MaxBitrateBoosted);
}
// Test that two different streams can have different formats.
TEST_F(WebRtcVideoEngineSimulcastTestFake,
MultipleSendStreamsDifferentFormats) {
EXPECT_TRUE(SetupEngine());
for (unsigned int i = 0; i < sizeof(kSsrcs2)/sizeof(kSsrcs2[0]); ++i) {
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(kSsrcs2[i])));
}
const int channel0 = vie_.GetChannelFromLocalSsrc(kSsrcs2[0]);
ASSERT_NE(-1, channel0);
const int channel1 = vie_.GetChannelFromLocalSsrc(kSsrcs2[1]);
ASSERT_NE(-1, channel1);
ASSERT_NE(channel0, channel1);
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(kVP8Codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
cricket::VideoFormat format(kVP8Codec.width / 2, kVP8Codec.height / 2,
cricket::VideoFormat::FpsToInterval(kVP8Codec.framerate / 2),
cricket::FOURCC_I420);
EXPECT_TRUE(channel_->SetSendStreamFormat(kSsrcs2[1], format));
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
VerifyVP8SendCodec(channel0, kVP8Codec.width, kVP8Codec.height, 0,
kMaxBandwidthKbps, kMinBandwidthKbps, kStartBandwidthKbps,
kVP8Codec.framerate);
VerifyVP8SendCodec(channel1, kVP8Codec.width / 2, kVP8Codec.height / 2, 0,
kMaxBandwidthKbps, kMinBandwidthKbps, kStartBandwidthKbps,
kVP8Codec.framerate / 2);
}
TEST_F(WebRtcVideoEngineSimulcastTestFake, TestAdaptToOutputFormat) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs3))));
// Capture format HD
cricket::FakeVideoCapturer video_capturer;
const std::vector<cricket::VideoFormat>* formats =
video_capturer.GetSupportedFormats();
cricket::VideoFormat capture_format_hd = (*formats)[0];
EXPECT_EQ(cricket::CS_RUNNING, video_capturer.Start(capture_format_hd));
EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], &video_capturer));
cricket::VideoCodec send_codec(100, "VP8", 800, 600, 30, 0);
cricket::VideoFormat vga_format(640, 360,
cricket::VideoFormat::FpsToInterval(30), cricket::FOURCC_I420);
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(send_codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_TRUE(channel_->SetSendStreamFormat(kSsrcs3[0], vga_format));
EXPECT_TRUE(channel_->SetSend(true));
// Capture format HD -> adapt (OnOutputFormatRequest VGA) -> VGA.
EXPECT_TRUE(video_capturer.CaptureFrame());
const int channel0 = vie_.GetChannelFromLocalSsrc(kSsrcs3[0]);
ASSERT_NE(-1, channel0);
VerifyVP8SendCodec(channel0, vga_format.width, vga_format.height, 0,
kMaxBandwidthKbps, kMinBandwidthKbps, kStartBandwidthKbps,
30);
EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], NULL));
}
TEST_F(WebRtcVideoEngineSimulcastTestFake, TestAdaptToCpuLoad) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs3))));
// Capture format VGA
cricket::FakeVideoCapturer video_capturer;
const std::vector<cricket::VideoFormat>* formats =
video_capturer.GetSupportedFormats();
cricket::VideoFormat capture_format_vga = (*formats)[1];
// Make OnCpuLoadUpdate trigger downgrade.
cricket::VideoOptions options;
options.adapt_input_to_cpu_usage.Set(true);
options.process_adaptation_threshhold.Set(0.1f);
options.system_low_adaptation_threshhold.Set(0.65f);
options.system_high_adaptation_threshhold.Set(0.85f);
options.cpu_overuse_detection.Set(false);
EXPECT_TRUE(channel_->SetOptions(options));
// Verify toggling cpu overuse detection works.
options.cpu_overuse_detection.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
options.cpu_overuse_detection.Set(false);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_EQ(cricket::CS_RUNNING, video_capturer.Start(capture_format_vga));
EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], &video_capturer));
// Only require one cpu sample for testing whether the adapter is hooked up.
cricket::CoordinatedVideoAdapter* video_adapter = NULL;
ASSERT_TRUE(channel_->GetVideoAdapter(0u, &video_adapter));
video_adapter->set_cpu_load_min_samples(1);
cpu_monitor_->SignalUpdate(1, 1, 0.1f, 0.85f);
cricket::VideoCodec send_codec(100, "VP8", 640, 480, 30, 0);
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(send_codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_TRUE(channel_->SetSend(true));
// Capture format VGA -> adapt (OnCpuLoadUpdate downgrade) -> VGA/2.
EXPECT_TRUE(video_capturer.CaptureFrame());
const int channel0 = vie_.GetChannelFromLocalSsrc(kSsrcs3[0]);
ASSERT_NE(-1, channel0);
VerifyVP8SendCodec(
channel0, 3 * send_codec.width / 4, 3 * send_codec.height / 4, 0,
kMaxBandwidthKbps, kMinBandwidthKbps, kStartBandwidthKbps,
send_codec.framerate);
// Trigger more downgrades and check for multiple unable to adapt signal.
EXPECT_EQ(cricket::VideoMediaChannel::ERROR_NONE, last_error_);
cpu_monitor_->SignalUpdate(1, 1, 0.1f, 0.85f);
cpu_monitor_->SignalUpdate(1, 1, 0.1f, 0.85f);
EXPECT_EQ(cricket::VideoMediaChannel::ERROR_REC_CPU_MAX_CANT_DOWNGRADE,
last_error_);
last_error_ = cricket::VideoMediaChannel::ERROR_NONE;
cpu_monitor_->SignalUpdate(1, 1, 0.1f, 0.85f);
EXPECT_EQ(cricket::VideoMediaChannel::ERROR_REC_CPU_MAX_CANT_DOWNGRADE,
last_error_);
EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], NULL));
}
TEST_F(WebRtcVideoEngineSimulcastTestFake, TestAdaptToCpuLoadDisabled) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs3))));
// Capture format VGA
cricket::FakeVideoCapturer video_capturer;
const std::vector<cricket::VideoFormat>* formats =
video_capturer.GetSupportedFormats();
cricket::VideoFormat capture_format_vga = (*formats)[1];
EXPECT_EQ(cricket::CS_RUNNING, video_capturer.Start(capture_format_vga));
EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], &video_capturer));
// Make OnCpuLoadUpdate trigger downgrade.
cricket::VideoOptions options;
options.adapt_input_to_cpu_usage.Set(false);
options.process_adaptation_threshhold.Set(0.1f);
options.system_low_adaptation_threshhold.Set(0.65f);
options.system_high_adaptation_threshhold.Set(0.85f);
EXPECT_TRUE(channel_->SetOptions(options));
// Only require one cpu sample for testing whether the adapter is hooked up.
cricket::CoordinatedVideoAdapter* video_adapter = NULL;
ASSERT_TRUE(channel_->GetVideoAdapter(0u, &video_adapter));
video_adapter->set_cpu_load_min_samples(1);
cpu_monitor_->SignalUpdate(1, 1, 0.1f, 0.85f);
cricket::VideoCodec send_codec(100, "VP8", 640, 480, 30, 0);
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(send_codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_TRUE(channel_->SetSend(true));
// Capture format VGA -> no adapt -> VGA.
EXPECT_TRUE(video_capturer.CaptureFrame());
const int channel0 = vie_.GetChannelFromLocalSsrc(kSsrcs3[0]);
ASSERT_NE(-1, channel0);
VerifyVP8SendCodec(channel0, capture_format_vga.width,
capture_format_vga.height, 0,
kMaxBandwidthKbps, kMinBandwidthKbps, kStartBandwidthKbps,
send_codec.framerate);
EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], NULL));
}
TEST_F(WebRtcVideoEngineSimulcastTestFake, TestAdaptWithCpuOveruseObserver) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs3))));
// Verify that the CpuOveruseObserver is not set by default.
const int channel0 = vie_.GetChannelFromLocalSsrc(kSsrcs3[0]);
ASSERT_NE(-1, channel0);
webrtc::CpuOveruseObserver* observer = vie_.GetCpuOveruseObserver(channel0);
EXPECT_TRUE(observer == NULL);
// Capture format VGA.
cricket::FakeVideoCapturer video_capturer;
const std::vector<cricket::VideoFormat>* formats =
video_capturer.GetSupportedFormats();
cricket::VideoFormat capture_format_vga = (*formats)[1];
EXPECT_EQ(cricket::CS_RUNNING, video_capturer.Start(capture_format_vga));
EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], &video_capturer));
// Verify that the CpuOveruseObserver is registered and trigger downgrade.
cricket::VideoOptions options;
options.cpu_overuse_detection.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
observer = vie_.GetCpuOveruseObserver(channel0);
ASSERT_TRUE(observer != NULL);
observer->OveruseDetected();
cricket::VideoCodec send_codec(100, "VP8", 640, 480, 30, 0);
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(send_codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_TRUE(channel_->SetSend(true));
// Capture format VGA -> adapt (OnCpuResolutionRequest downgrade) -> VGA/2.
EXPECT_TRUE(video_capturer.CaptureFrame());
VerifyVP8SendCodec(
channel0, 3 * send_codec.width / 4, 3 * send_codec.height / 4, 0,
kMaxBandwidthKbps, kMinBandwidthKbps, kStartBandwidthKbps,
send_codec.framerate);
// Trigger upgrade and verify that we adapt back up to VGA.
observer->NormalUsage();
EXPECT_TRUE(video_capturer.CaptureFrame());
VerifyVP8SendCodec(
channel0, send_codec.width, send_codec.height, 0,
kMaxBandwidthKbps, kMinBandwidthKbps, kStartBandwidthKbps,
send_codec.framerate);
// Verify that the CpuOveruseObserver is deregistered.
EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], NULL));
EXPECT_TRUE(vie_.GetCpuOveruseObserver(channel0) == NULL);
}
TEST_F(WebRtcVideoEngineSimulcastTestFake,
TestAdaptWithCpuOveruseObserverDisabled) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs3))));
// Verify that the CpuOveruseObserver is not set by default.
const int channel0 = vie_.GetChannelFromLocalSsrc(kSsrcs3[0]);
ASSERT_NE(-1, channel0);
webrtc::CpuOveruseObserver* observer = vie_.GetCpuOveruseObserver(channel0);
EXPECT_TRUE(observer == NULL);
// Capture format VGA.
cricket::FakeVideoCapturer video_capturer;
const std::vector<cricket::VideoFormat>* formats =
video_capturer.GetSupportedFormats();
cricket::VideoFormat capture_format_vga = (*formats)[1];
EXPECT_EQ(cricket::CS_RUNNING, video_capturer.Start(capture_format_vga));
EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], &video_capturer));
// Disable cpu overuse detection.
cricket::VideoOptions options;
options.cpu_overuse_detection.Set(false);
EXPECT_TRUE(channel_->SetOptions(options));
cricket::CoordinatedVideoAdapter* video_adapter = NULL;
ASSERT_TRUE(channel_->GetVideoAdapter(0u, &video_adapter));
EXPECT_FALSE(video_adapter->cpu_adaptation());
// Verify that the CpuOveruseObserver is registered and trigger downgrade.
observer = vie_.GetCpuOveruseObserver(channel0);
ASSERT_TRUE(observer != NULL);
observer->OveruseDetected();
cricket::VideoCodec send_codec(100, "VP8", 640, 480, 30, 0);
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(send_codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_TRUE(channel_->SetSend(true));
// Capture format VGA -> no adapt -> VGA.
EXPECT_TRUE(video_capturer.CaptureFrame());
VerifyVP8SendCodec(
channel0, capture_format_vga.width, capture_format_vga.height, 0,
kMaxBandwidthKbps, kMinBandwidthKbps, kStartBandwidthKbps,
send_codec.framerate);
// Verify that the CpuOveruseObserver is deregistered.
EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], NULL));
EXPECT_TRUE(vie_.GetCpuOveruseObserver(channel0) == NULL);
}
TEST_F(WebRtcVideoEngineSimulcastTestFake, GetAdaptStats) {
EXPECT_TRUE(SetupEngine());
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs3))));
// Capture format VGA.
cricket::FakeVideoCapturer video_capturer_vga;
const std::vector<cricket::VideoFormat>* formats =
video_capturer_vga.GetSupportedFormats();
cricket::VideoFormat capture_format_vga = (*formats)[1];
EXPECT_EQ(cricket::CS_RUNNING, video_capturer_vga.Start(capture_format_vga));
EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], &video_capturer_vga));
EXPECT_TRUE(video_capturer_vga.CaptureFrame());
cricket::VideoCodec send_codec(100, "VP8", 640, 480, 30, 0);
std::vector<cricket::VideoCodec> codecs;
codecs.push_back(send_codec);
EXPECT_TRUE(channel_->SetSendCodecs(codecs));
EXPECT_TRUE(channel_->SetSend(true));
// Verify that the CpuOveruseObserver is registered and trigger downgrade.
cricket::VideoOptions options;
options.cpu_overuse_detection.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
const int channel0 = vie_.GetChannelFromLocalSsrc(kSsrcs3[0]);
ASSERT_NE(-1, channel0);
webrtc::CpuOveruseObserver* observer = vie_.GetCpuOveruseObserver(channel0);
ASSERT_TRUE(observer != NULL);
observer->OveruseDetected();
// Capture format VGA -> adapt (OnCpuResolutionRequest downgrade) -> VGA/2.
EXPECT_TRUE(video_capturer_vga.CaptureFrame());
cricket::VideoMediaInfo info;
EXPECT_TRUE(channel_->GetStats(&info));
ASSERT_EQ(1U, info.senders.size());
EXPECT_EQ(1, info.senders[0].adapt_changes);
EXPECT_EQ(cricket::CoordinatedVideoAdapter::ADAPTREASON_CPU,
info.senders[0].adapt_reason);
// Trigger upgrade and verify that we adapt back up to VGA.
observer->NormalUsage();
EXPECT_TRUE(video_capturer_vga.CaptureFrame());
info.Clear();
EXPECT_TRUE(channel_->GetStats(&info));
ASSERT_EQ(1U, info.senders.size());
EXPECT_EQ(2, info.senders[0].adapt_changes);
EXPECT_EQ(cricket::CoordinatedVideoAdapter::ADAPTREASON_NONE,
info.senders[0].adapt_reason);
// No capturer (no adapter). Adapt changes from old adapter should be kept.
EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], NULL));
EXPECT_TRUE(vie_.GetCpuOveruseObserver(channel0) == NULL);
info.Clear();
EXPECT_TRUE(channel_->GetStats(&info));
ASSERT_EQ(1U, info.senders.size());
EXPECT_EQ(2, info.senders[0].adapt_changes);
EXPECT_EQ(cricket::CoordinatedVideoAdapter::ADAPTREASON_NONE,
info.senders[0].adapt_reason);
// Set new capturer, capture format HD.
cricket::FakeVideoCapturer video_capturer_hd;
cricket::VideoFormat capture_format_hd = (*formats)[0];
EXPECT_EQ(cricket::CS_RUNNING, video_capturer_hd.Start(capture_format_hd));
EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], &video_capturer_hd));
EXPECT_TRUE(video_capturer_hd.CaptureFrame());
observer = vie_.GetCpuOveruseObserver(channel0);
ASSERT_TRUE(observer != NULL);
// Trigger overuse, HD -> adapt (OnCpuResolutionRequest downgrade) -> HD/2.
observer->OveruseDetected();
EXPECT_TRUE(video_capturer_hd.CaptureFrame());
info.Clear();
EXPECT_TRUE(channel_->GetStats(&info));
ASSERT_EQ(1U, info.senders.size());
EXPECT_EQ(3, info.senders[0].adapt_changes);
EXPECT_EQ(cricket::CoordinatedVideoAdapter::ADAPTREASON_CPU,
info.senders[0].adapt_reason);
EXPECT_TRUE(channel_->SetCapturer(kSsrcs3[0], NULL));
}
// Test that the codec is not reset for every frame sent in
// non-conference and non-screencast mode.
TEST_F(WebRtcVideoEngineSimulcastTestFake, DontResetCodecOnSendFrame) {
EXPECT_TRUE(SetupEngine());
// Set send codec.
cricket::VideoCodec codec(kVP8Codec);
std::vector<cricket::VideoCodec> codec_list;
codec_list.push_back(codec);
EXPECT_TRUE(channel_->AddSendStream(
cricket::StreamParams::CreateLegacy(123)));
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_TRUE(channel_->SetSendCodecs(codec_list));
EXPECT_TRUE(channel_->SetSend(true));
EXPECT_EQ(1, vie_.GetNumSetSendCodecs());
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_EQ(1, vie_.GetNumSetSendCodecs());
SendI420Frame(kVP8Codec.width, kVP8Codec.height);
EXPECT_EQ(1, vie_.GetNumSetSendCodecs());
}
TEST_F(WebRtcVideoEngineSimulcastTestFake,
UseSimulcastAdapterOnVp8OnlyFactory) {
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecVP8, "VP8");
TestSimulcastAdapter(kVP8Codec, true);
}
TEST_F(WebRtcVideoEngineSimulcastTestFake,
UsesSimulcastAdapterForVp8WithCombinedVP8AndH264Factory) {
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecVP8, "VP8");
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecGeneric,
"H264");
TestSimulcastAdapter(kVP8Codec, true);
}
TEST_F(WebRtcVideoEngineSimulcastTestFake,
DontUseSimulcastAdapterForH264WithCombinedVP8AndH264Factory) {
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecVP8, "VP8");
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecGeneric,
"H264");
static const cricket::VideoCodec kH264Codec(100, "H264", 640, 400, 30, 0);
TestSimulcastAdapter(kH264Codec, false);
}
TEST_F(WebRtcVideoEngineSimulcastTestFake,
DontUseSimulcastAdapterOnNonVp8Factory) {
encoder_factory_.AddSupportedVideoCodecType(webrtc::kVideoCodecGeneric,
"H264");
static const cricket::VideoCodec kH264Codec(100, "H264", 640, 400, 30, 0);
TestSimulcastAdapter(kH264Codec, false);
}
// Flaky on Windows and tsan. https://code.google.com/p/webrtc/issues/detail?id=4135
#if defined(WIN32) || defined(THREAD_SANITIZER)
#define MAYBE_SimulcastSend_1280x800 DISABLED_SimulcastSend_1280x800
#else
#define MAYBE_SimulcastSend_1280x800 SimulcastSend_1280x800
#endif
TEST_F(WebRtcVideoMediaChannelSimulcastTest, MAYBE_SimulcastSend_1280x800) {
cricket::VideoCodec codec = kVP8Codec;
codec.width = 1280;
codec.height = 800;
// TODO(zhurunz): Support 3 layers of simulcast.
SimulcastSend(codec, MAKE_VECTOR(kSsrcs2));
}
// Flaky on Windows and tsan. https://code.google.com/p/webrtc/issues/detail?id=4135
#if defined(WIN32) || defined(THREAD_SANITIZER)
#define MAYBE_SimulcastSend_1280x720 DISABLED_SimulcastSend_1280x720
#else
#define MAYBE_SimulcastSend_1280x720 SimulcastSend_1280x720
#endif
TEST_F(WebRtcVideoMediaChannelSimulcastTest, MAYBE_SimulcastSend_1280x720) {
cricket::VideoCodec codec = kVP8Codec;
codec.width = 1280;
codec.height = 720;
// TODO(zhurunz): Support 3 layers of simulcast.
SimulcastSend(codec, MAKE_VECTOR(kSsrcs2));
}
// Flaky on Windows and tsan. https://code.google.com/p/webrtc/issues/detail?id=4135
#if defined(WIN32) || defined(THREAD_SANITIZER)
#define MAYBE_SimulcastSend_960x540 DISABLED_SimulcastSend_960x540
#else
#define MAYBE_SimulcastSend_960x540 SimulcastSend_960x540
#endif
TEST_F(WebRtcVideoMediaChannelSimulcastTest, MAYBE_SimulcastSend_960x540) {
cricket::VideoCodec codec = kVP8Codec;
codec.width = 960;
codec.height = 540;
// TODO(zhurunz): Support 3 layers of simulcast.
SimulcastSend(codec, MAKE_VECTOR(kSsrcs2));
}
// Flaky on Windows and tsan. https://code.google.com/p/webrtc/issues/detail?id=4135
#if defined(WIN32) || defined(THREAD_SANITIZER)
#define MAYBE_SimulcastSend_960x600 DISABLED_SimulcastSend_960x600
#else
#define MAYBE_SimulcastSend_960x600 SimulcastSend_960x600
#endif
TEST_F(WebRtcVideoMediaChannelSimulcastTest, MAYBE_SimulcastSend_960x600) {
cricket::VideoCodec codec = kVP8Codec;
codec.width = 960;
codec.height = 600;
// TODO(zhurunz): Support 3 layers of simulcast.
SimulcastSend(codec, MAKE_VECTOR(kSsrcs2));
}
// Flaky on Windows and tsan. https://code.google.com/p/webrtc/issues/detail?id=4135
#if defined(WIN32) || defined(THREAD_SANITIZER)
#define MAYBE_SimulcastSend_640x400 DISABLED_SimulcastSend_640x400
#else
#define MAYBE_SimulcastSend_640x400 SimulcastSend_640x400
#endif
TEST_F(WebRtcVideoMediaChannelSimulcastTest, MAYBE_SimulcastSend_640x400) {
cricket::VideoCodec codec = kVP8Codec;
codec.width = 640;
codec.height = 400;
SimulcastSend(codec, MAKE_VECTOR(kSsrcs2));
}
// Flaky on Windows and tsan. https://code.google.com/p/webrtc/issues/detail?id=4135
#if defined(WIN32) || defined(THREAD_SANITIZER)
#define MAYBE_SimulcastSend_640x360 DISABLED_SimulcastSend_640x360
#else
#define MAYBE_SimulcastSend_640x360 SimulcastSend_640x360
#endif
TEST_F(WebRtcVideoMediaChannelSimulcastTest, MAYBE_SimulcastSend_640x360) {
cricket::VideoCodec codec = kVP8Codec;
codec.width = 640;
codec.height = 360;
SimulcastSend(codec, MAKE_VECTOR(kSsrcs2));
}
// Flaky on Windows and tsan. https://code.google.com/p/webrtc/issues/detail?id=4135
#if defined(WIN32) || defined(THREAD_SANITIZER)
#define MAYBE_SimulcastSend_480x300 DISABLED_SimulcastSend_480x300
#else
#define MAYBE_SimulcastSend_480x300 SimulcastSend_480x300
#endif
TEST_F(WebRtcVideoMediaChannelSimulcastTest, MAYBE_SimulcastSend_480x300) {
cricket::VideoCodec codec = kVP8Codec;
codec.width = 480;
codec.height = 300;
SimulcastSend(codec, MAKE_VECTOR(kSsrcs2));
}
TEST_F(WebRtcVideoMediaChannelSimulcastTest, DISABLED_SimulcastSend_480x270) {
cricket::VideoCodec codec = kVP8Codec;
codec.width = 480;
codec.height = 270;
SimulcastSend(codec, MAKE_VECTOR(kSsrcs2));
}
// Flaky on Windows and tsan. https://code.google.com/p/webrtc/issues/detail?id=4135
#if defined(WIN32) || defined(THREAD_SANITIZER)
#define MAYBE_SimulcastSend_320x200 DISABLED_SimulcastSend_320x200
#else
#define MAYBE_SimulcastSend_320x200 SimulcastSend_320x200
#endif
TEST_F(WebRtcVideoMediaChannelSimulcastTest, MAYBE_SimulcastSend_320x200) {
cricket::VideoCodec codec = kVP8Codec;
codec.width = 320;
codec.height = 200;
SimulcastSend(codec, MAKE_VECTOR(kSsrcs1));
}
// Flaky on Windows and tsan. https://code.google.com/p/webrtc/issues/detail?id=4135
#if defined(WIN32) || defined(THREAD_SANITIZER)
#define MAYBE_SimulcastSend_320x180 DISABLED_SimulcastSend_320x180
#else
#define MAYBE_SimulcastSend_320x180 SimulcastSend_320x180
#endif
TEST_F(WebRtcVideoMediaChannelSimulcastTest, MAYBE_SimulcastSend_320x180) {
cricket::VideoCodec codec = kVP8Codec;
codec.width = 320;
codec.height = 180;
SimulcastSend(codec, MAKE_VECTOR(kSsrcs1));
}
// Test reset send codec with simulcast.
// Disabled per b/6773425
TEST_F(WebRtcVideoMediaChannelSimulcastTest, DISABLED_SimulcastResetSendCodec) {
// Remove stream added in Setup.
EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2))));
cricket::VideoCodec codec(DefaultCodec());
EXPECT_TRUE(SetOneCodec(codec));
EXPECT_TRUE(SetSend(true));
int packets = 0;
// Send the first frame with default format size.
EXPECT_TRUE(SendFrame());
EXPECT_TRUE_WAIT(NumRtpPackets() > packets, kTimeout);
DrainOutgoingPackets();
packets = NumRtpPackets();
// Simulate capture frame size changes.
// Verify there is new rtp packet coming out of the encoder.
// Send an odd frame.
EXPECT_TRUE(SendCustomVideoFrame(DefaultCodec().width | 0x01,
DefaultCodec().height | 0x01));
EXPECT_TRUE_WAIT(NumRtpPackets() > packets, kTimeout);
packets = DrainOutgoingPackets();
// Send a small frame in width.
EXPECT_TRUE(SendCustomVideoFrame(DefaultCodec().width / 2,
DefaultCodec().height));
EXPECT_TRUE_WAIT(NumRtpPackets() > packets, kTimeout);
packets = DrainOutgoingPackets();
// Send a small frame in height.
EXPECT_TRUE(SendCustomVideoFrame(DefaultCodec().width,
DefaultCodec().height / 2));
EXPECT_TRUE_WAIT(NumRtpPackets() > packets, kTimeout);
packets = DrainOutgoingPackets();
// Send a big frame in width.
EXPECT_TRUE(SendCustomVideoFrame(DefaultCodec().width * 2,
DefaultCodec().height));
EXPECT_TRUE_WAIT(NumRtpPackets() > packets, kTimeout);
packets = DrainOutgoingPackets();
// Send a big frame in height.
EXPECT_TRUE(SendCustomVideoFrame(DefaultCodec().width,
DefaultCodec().height * 2));
EXPECT_TRUE_WAIT(NumRtpPackets() > packets, kTimeout);
packets = DrainOutgoingPackets();
// Send a normal frame.
EXPECT_TRUE(SendCustomVideoFrame(DefaultCodec().width,
DefaultCodec().height));
EXPECT_TRUE_WAIT(NumRtpPackets() > packets, kTimeout);
packets = DrainOutgoingPackets();
}
// Test simulcast streams are decodeable with expected sizes.
TEST_F(WebRtcVideoMediaChannelSimulcastTest, SimulcastStreams) {
// Remove stream added in Setup.
EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2))));
cricket::VideoCodec codec(DefaultCodec());
EXPECT_TRUE(SetOneCodec(codec));
// Re-configure capturer.
channel_->SetCapturer(kSsrc, NULL);
EXPECT_TRUE(channel_->SetCapturer(kSsrcs2[0], video_capturer_.get()));
cricket::VideoFormat capture_format(codec.width, codec.height,
cricket::VideoFormat::FpsToInterval(codec.framerate),
cricket::FOURCC_I420);
EXPECT_EQ(cricket::CS_RUNNING, video_capturer_->Start(capture_format));
EXPECT_TRUE(SetSend(true));
cricket::FakeVideoRenderer renderer1, renderer2;
EXPECT_TRUE(channel_->AddRecvStream(
cricket::StreamParams::CreateLegacy(kSsrcs2[0])));
EXPECT_TRUE(channel_->AddRecvStream(
cricket::StreamParams::CreateLegacy(kSsrcs2[1])));
EXPECT_TRUE(channel_->SetRenderer(kSsrcs2[0], &renderer1));
EXPECT_TRUE(channel_->SetRenderer(kSsrcs2[1], &renderer2));
EXPECT_TRUE(channel_->SetRender(true));
EXPECT_EQ(0, renderer1.num_rendered_frames());
EXPECT_EQ(0, renderer2.num_rendered_frames());
EXPECT_TRUE(SendFrame());
EXPECT_FRAME_ON_RENDERER_WAIT(renderer1, 1,
DefaultCodec().width / 2, DefaultCodec().height / 2, kTimeout);
EXPECT_FRAME_ON_RENDERER_WAIT(renderer2, 1,
DefaultCodec().width, DefaultCodec().height, kTimeout);
EXPECT_EQ(1, renderer1.num_set_sizes());
EXPECT_EQ(1, renderer2.num_set_sizes());
}
// Simulcast and resolution resizing should be turned off when screencasting
// but not otherwise.
// TODO(dmunene): Fix flaky test with bug 15773660.
TEST_F(WebRtcVideoMediaChannelSimulcastTest, DISABLED_ScreencastRendering) {
// Remove stream added in SetUp.
EXPECT_TRUE(channel_->RemoveSendStream(kSsrc));
cricket::VideoOptions options;
options.conference_mode.Set(true);
EXPECT_TRUE(channel_->SetOptions(options));
// Setup a simulcast stream and verify that frames are rendered on
// both renderers.
EXPECT_TRUE(channel_->AddSendStream(
cricket::CreateSimStreamParams("cname", MAKE_VECTOR(kSsrcs2))));
cricket::VideoCodec codec(DefaultCodec());
EXPECT_TRUE(SetOneCodec(codec));
EXPECT_TRUE(SetSend(true));
cricket::FakeVideoRenderer renderer1, renderer2;
EXPECT_TRUE(channel_->AddRecvStream(
cricket::StreamParams::CreateLegacy(kSsrcs2[0])));
EXPECT_TRUE(channel_->AddRecvStream(
cricket::StreamParams::CreateLegacy(kSsrcs2[1])));
EXPECT_TRUE(channel_->SetRenderer(kSsrcs2[0], &renderer1));
EXPECT_TRUE(channel_->SetRenderer(kSsrcs2[1], &renderer2));
EXPECT_TRUE(channel_->SetRender(true));
EXPECT_EQ(0, renderer1.num_rendered_frames());
EXPECT_EQ(0, renderer2.num_rendered_frames());
// Re-configure capturer.
channel_->SetCapturer(kSsrc, NULL);
EXPECT_TRUE(channel_->SetCapturer(kSsrcs2[0], video_capturer_.get()));
EXPECT_TRUE(channel_->SetCapturer(kSsrcs2[1], video_capturer_.get()));
cricket::VideoFormat capture_format(codec.width, codec.height,
cricket::VideoFormat::FpsToInterval(codec.framerate),
cricket::FOURCC_I420);
EXPECT_EQ(cricket::CS_RUNNING, video_capturer_->Start(capture_format));
EXPECT_TRUE(SendFrame());
EXPECT_FRAME_ON_RENDERER_WAIT(renderer1, 1, codec.width / 2, codec.height / 2,
kTimeout);
EXPECT_FRAME_ON_RENDERER_WAIT(renderer2, 1, codec.width, codec.height,
kTimeout);
// Register a fake screencast capturer and verify that frames are only
// rendered to a single renderer.
rtc::scoped_ptr<cricket::FakeVideoCapturer> capturer(
new cricket::FakeVideoCapturer);
capturer->SetScreencast(true);
const std::vector<cricket::VideoFormat>* formats =
capturer->GetSupportedFormats();
capture_format = (*formats)[0];
EXPECT_EQ(cricket::CS_RUNNING, capturer->Start(capture_format));
// Capture a frame to increment the frame timestamp since the default video
// capturer starts at the same timestamp.
EXPECT_TRUE(capturer->CaptureFrame());
EXPECT_TRUE(channel_->SetCapturer(kSsrcs2[0], capturer.get()));
EXPECT_TRUE(rtc::Thread::Current()->ProcessMessages(30));
EXPECT_TRUE(capturer->CaptureFrame());
EXPECT_FRAME_ON_RENDERER_WAIT(renderer1, 2, capture_format.width,
capture_format.height, kTimeout);
// When screencasting we only encode a single stream (no simulcast), which is
// why we only expect frames to be rendered in one of the renderers.
EXPECT_EQ(1, renderer2.num_rendered_frames());
// Disable screencast and make sure frames are now rendered in both renderers.
EXPECT_TRUE(channel_->SetCapturer(kSsrcs2[0], NULL));
EXPECT_FRAME_ON_RENDERER_WAIT(renderer1, 3, codec.width / 2, codec.height / 2,
kTimeout);
EXPECT_FRAME_ON_RENDERER_WAIT(renderer2, 2, codec.width, codec.height,
kTimeout);
}
// Disable for TSan v2, see
// https://code.google.com/p/webrtc/issues/detail?id=3525 for details.
#if !defined(THREAD_SANITIZER)
// Ensures that the correct settings are applied to the codec when two temporal
// layer screencasting is enabled, and that the correct simulcast settings are
// reapplied when disabling screencasting.
TEST_F(WebRtcVideoMediaChannelSimulcastTest, ConferenceModeScreencastSettings) {
TestScreencastSettings();
}
#endif // if !defined(THREAD_SANITIZER)