Use SingleThreadedTaskQueue in DirectTransport

DirectTransport has so far used its own thread, which led to a different threading-model for in the unit-tests than is used in actual WebRTC. Because of that, some critical-sections that weren't truly necessary in WebRTC could not be replaced with thread-checks, because those checks failed in unit-tests.

This CL introduces SingleThreadedTaskQueue - a TaskQueue which guarantees to run all of its tasks on the same thread (rtc::TaskQueue doesn't guarantee that on Mac) - and uses that for DirectTransport. CLs based on top of this will uncomment thread-checks which had to be commented out before, and remove unnecessary critical-sections.

Future work would probably replace the thread-checkers by more sophisticated serialized-access checks, allowing us to move from the SingleThreadedTaskQueue to a normal TaskQueue.

Related implementation notes:
* This CL has made DirectTransport::StopSending() superfluous, and so it was deleted.

BUG=webrtc:8113, webrtc:7405, webrtc:8056, webrtc:8116

Review-Url: https://codereview.webrtc.org/2998923002
Cr-Commit-Position: refs/heads/master@{#19445}
This commit is contained in:
eladalon 2017-08-22 04:02:52 -07:00 committed by Commit Bot
parent 2a596549ca
commit 413ee9a010
24 changed files with 2273 additions and 1194 deletions

View File

@ -156,6 +156,7 @@ if (rtc_include_tests) {
"../system_wrappers",
"../test:fake_audio_device",
"../test:field_trial",
"../test:single_threaded_task_queue",
"../test:test_common",
"../test:test_main",
"//testing/gmock",

View File

@ -48,15 +48,18 @@ void AudioBweTest::OnFakeAudioDevicesCreated(
send_audio_device_ = send_audio_device;
}
test::PacketTransport* AudioBweTest::CreateSendTransport(Call* sender_call) {
test::PacketTransport* AudioBweTest::CreateSendTransport(
SingleThreadedTaskQueueForTesting* task_queue,
Call* sender_call) {
return new test::PacketTransport(
sender_call, this, test::PacketTransport::kSender,
task_queue, sender_call, this, test::PacketTransport::kSender,
test::CallTest::payload_type_map_, GetNetworkPipeConfig());
}
test::PacketTransport* AudioBweTest::CreateReceiveTransport() {
test::PacketTransport* AudioBweTest::CreateReceiveTransport(
SingleThreadedTaskQueueForTesting* task_queue) {
return new test::PacketTransport(
nullptr, this, test::PacketTransport::kReceiver,
task_queue, nullptr, this, test::PacketTransport::kReceiver,
test::CallTest::payload_type_map_, GetNetworkPipeConfig());
}

View File

@ -15,6 +15,7 @@
#include "webrtc/test/call_test.h"
#include "webrtc/test/fake_audio_device.h"
#include "webrtc/test/single_threaded_task_queue.h"
namespace webrtc {
namespace test {
@ -38,8 +39,11 @@ class AudioBweTest : public test::EndToEndTest {
test::FakeAudioDevice* send_audio_device,
test::FakeAudioDevice* recv_audio_device) override;
test::PacketTransport* CreateSendTransport(Call* sender_call) override;
test::PacketTransport* CreateReceiveTransport() override;
test::PacketTransport* CreateSendTransport(
SingleThreadedTaskQueueForTesting* task_queue,
Call* sender_call) override;
test::PacketTransport* CreateReceiveTransport(
SingleThreadedTaskQueueForTesting* task_queue) override;
void PerformTest() override;

View File

@ -86,15 +86,17 @@ FakeNetworkPipe::Config AudioQualityTest::GetNetworkPipeConfig() {
}
test::PacketTransport* AudioQualityTest::CreateSendTransport(
SingleThreadedTaskQueueForTesting* task_queue,
Call* sender_call) {
return new test::PacketTransport(
sender_call, this, test::PacketTransport::kSender,
task_queue, sender_call, this, test::PacketTransport::kSender,
test::CallTest::payload_type_map_, GetNetworkPipeConfig());
}
test::PacketTransport* AudioQualityTest::CreateReceiveTransport() {
test::PacketTransport* AudioQualityTest::CreateReceiveTransport(
SingleThreadedTaskQueueForTesting* task_queue) {
return new test::PacketTransport(
nullptr, this, test::PacketTransport::kReceiver,
task_queue, nullptr, this, test::PacketTransport::kReceiver,
test::CallTest::payload_type_map_, GetNetworkPipeConfig());
}

View File

@ -41,8 +41,11 @@ class AudioQualityTest : public test::EndToEndTest {
test::FakeAudioDevice* send_audio_device,
test::FakeAudioDevice* recv_audio_device) override;
test::PacketTransport* CreateSendTransport(Call* sender_call) override;
test::PacketTransport* CreateReceiveTransport() override;
test::PacketTransport* CreateSendTransport(
SingleThreadedTaskQueueForTesting* task_queue,
Call* sender_call) override;
test::PacketTransport* CreateReceiveTransport(
SingleThreadedTaskQueueForTesting* task_queue) override;
void ModifyAudioConfigs(
AudioSendStream::Config* send_config,

View File

@ -102,51 +102,55 @@ class BitrateEstimatorTest : public test::CallTest {
virtual ~BitrateEstimatorTest() { EXPECT_TRUE(streams_.empty()); }
virtual void SetUp() {
Call::Config config(event_log_.get());
receiver_call_.reset(Call::Create(config));
sender_call_.reset(Call::Create(config));
task_queue_.SendTask([this]() {
Call::Config config(event_log_.get());
receiver_call_.reset(Call::Create(config));
sender_call_.reset(Call::Create(config));
send_transport_.reset(
new test::DirectTransport(sender_call_.get(), payload_type_map_));
send_transport_->SetReceiver(receiver_call_->Receiver());
receive_transport_.reset(
new test::DirectTransport(receiver_call_.get(), payload_type_map_));
receive_transport_->SetReceiver(sender_call_->Receiver());
send_transport_.reset(new test::DirectTransport(
&task_queue_, sender_call_.get(), payload_type_map_));
send_transport_->SetReceiver(receiver_call_->Receiver());
receive_transport_.reset(new test::DirectTransport(
&task_queue_, receiver_call_.get(), payload_type_map_));
receive_transport_->SetReceiver(sender_call_->Receiver());
video_send_config_ = VideoSendStream::Config(send_transport_.get());
video_send_config_.rtp.ssrcs.push_back(kVideoSendSsrcs[0]);
// Encoders will be set separately per stream.
video_send_config_.encoder_settings.encoder = nullptr;
video_send_config_.encoder_settings.payload_name = "FAKE";
video_send_config_.encoder_settings.payload_type =
kFakeVideoSendPayloadType;
test::FillEncoderConfiguration(1, &video_encoder_config_);
video_send_config_ = VideoSendStream::Config(send_transport_.get());
video_send_config_.rtp.ssrcs.push_back(kVideoSendSsrcs[0]);
// Encoders will be set separately per stream.
video_send_config_.encoder_settings.encoder = nullptr;
video_send_config_.encoder_settings.payload_name = "FAKE";
video_send_config_.encoder_settings.payload_type =
kFakeVideoSendPayloadType;
test::FillEncoderConfiguration(1, &video_encoder_config_);
receive_config_ = VideoReceiveStream::Config(receive_transport_.get());
// receive_config_.decoders will be set by every stream separately.
receive_config_.rtp.remote_ssrc = video_send_config_.rtp.ssrcs[0];
receive_config_.rtp.local_ssrc = kReceiverLocalVideoSsrc;
receive_config_.rtp.remb = true;
receive_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId));
receive_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTimeUri, kASTExtensionId));
receive_config_ = VideoReceiveStream::Config(receive_transport_.get());
// receive_config_.decoders will be set by every stream separately.
receive_config_.rtp.remote_ssrc = video_send_config_.rtp.ssrcs[0];
receive_config_.rtp.local_ssrc = kReceiverLocalVideoSsrc;
receive_config_.rtp.remb = true;
receive_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId));
receive_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTimeUri, kASTExtensionId));
});
}
virtual void TearDown() {
std::for_each(streams_.begin(), streams_.end(),
std::mem_fun(&Stream::StopSending));
task_queue_.SendTask([this]() {
std::for_each(streams_.begin(), streams_.end(),
std::mem_fun(&Stream::StopSending));
send_transport_->StopSending();
receive_transport_->StopSending();
while (!streams_.empty()) {
delete streams_.back();
streams_.pop_back();
}
while (!streams_.empty()) {
delete streams_.back();
streams_.pop_back();
}
send_transport_.reset();
receive_transport_.reset();
receiver_call_.reset();
sender_call_.reset();
receiver_call_.reset();
sender_call_.reset();
});
}
protected:
@ -241,66 +245,80 @@ static const char* kSingleStreamLog =
"RemoteBitrateEstimatorSingleStream: Instantiating.";
TEST_F(BitrateEstimatorTest, InstantiatesTOFPerDefaultForVideo) {
video_send_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId));
receiver_log_.PushExpectedLogLine(kSingleStreamLog);
receiver_log_.PushExpectedLogLine(kSingleStreamLog);
streams_.push_back(new Stream(this));
task_queue_.SendTask([this]() {
video_send_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId));
receiver_log_.PushExpectedLogLine(kSingleStreamLog);
receiver_log_.PushExpectedLogLine(kSingleStreamLog);
streams_.push_back(new Stream(this));
});
EXPECT_TRUE(receiver_log_.Wait());
}
TEST_F(BitrateEstimatorTest, ImmediatelySwitchToASTForVideo) {
video_send_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTimeUri, kASTExtensionId));
receiver_log_.PushExpectedLogLine(kSingleStreamLog);
receiver_log_.PushExpectedLogLine(kSingleStreamLog);
receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE.");
receiver_log_.PushExpectedLogLine(kAbsSendTimeLog);
streams_.push_back(new Stream(this));
task_queue_.SendTask([this]() {
video_send_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kAbsSendTimeUri, kASTExtensionId));
receiver_log_.PushExpectedLogLine(kSingleStreamLog);
receiver_log_.PushExpectedLogLine(kSingleStreamLog);
receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE.");
receiver_log_.PushExpectedLogLine(kAbsSendTimeLog);
streams_.push_back(new Stream(this));
});
EXPECT_TRUE(receiver_log_.Wait());
}
TEST_F(BitrateEstimatorTest, SwitchesToASTForVideo) {
video_send_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId));
receiver_log_.PushExpectedLogLine(kSingleStreamLog);
receiver_log_.PushExpectedLogLine(kSingleStreamLog);
streams_.push_back(new Stream(this));
task_queue_.SendTask([this]() {
video_send_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId));
receiver_log_.PushExpectedLogLine(kSingleStreamLog);
receiver_log_.PushExpectedLogLine(kSingleStreamLog);
streams_.push_back(new Stream(this));
});
EXPECT_TRUE(receiver_log_.Wait());
video_send_config_.rtp.extensions[0] =
RtpExtension(RtpExtension::kAbsSendTimeUri, kASTExtensionId);
receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE.");
receiver_log_.PushExpectedLogLine(kAbsSendTimeLog);
streams_.push_back(new Stream(this));
task_queue_.SendTask([this]() {
video_send_config_.rtp.extensions[0] =
RtpExtension(RtpExtension::kAbsSendTimeUri, kASTExtensionId);
receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE.");
receiver_log_.PushExpectedLogLine(kAbsSendTimeLog);
streams_.push_back(new Stream(this));
});
EXPECT_TRUE(receiver_log_.Wait());
}
// This test is flaky. See webrtc:5790.
TEST_F(BitrateEstimatorTest, DISABLED_SwitchesToASTThenBackToTOFForVideo) {
video_send_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId));
receiver_log_.PushExpectedLogLine(kSingleStreamLog);
receiver_log_.PushExpectedLogLine(kAbsSendTimeLog);
receiver_log_.PushExpectedLogLine(kSingleStreamLog);
streams_.push_back(new Stream(this));
task_queue_.SendTask([this]() {
video_send_config_.rtp.extensions.push_back(
RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId));
receiver_log_.PushExpectedLogLine(kSingleStreamLog);
receiver_log_.PushExpectedLogLine(kAbsSendTimeLog);
receiver_log_.PushExpectedLogLine(kSingleStreamLog);
streams_.push_back(new Stream(this));
});
EXPECT_TRUE(receiver_log_.Wait());
video_send_config_.rtp.extensions[0] =
RtpExtension(RtpExtension::kAbsSendTimeUri, kASTExtensionId);
receiver_log_.PushExpectedLogLine(kAbsSendTimeLog);
receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE.");
streams_.push_back(new Stream(this));
task_queue_.SendTask([this]() {
video_send_config_.rtp.extensions[0] =
RtpExtension(RtpExtension::kAbsSendTimeUri, kASTExtensionId);
receiver_log_.PushExpectedLogLine(kAbsSendTimeLog);
receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE.");
streams_.push_back(new Stream(this));
});
EXPECT_TRUE(receiver_log_.Wait());
video_send_config_.rtp.extensions[0] =
RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId);
receiver_log_.PushExpectedLogLine(kAbsSendTimeLog);
receiver_log_.PushExpectedLogLine(
"WrappingBitrateEstimator: Switching to transmission time offset RBE.");
streams_.push_back(new Stream(this));
streams_[0]->StopSending();
streams_[1]->StopSending();
task_queue_.SendTask([this]() {
video_send_config_.rtp.extensions[0] =
RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId);
receiver_log_.PushExpectedLogLine(kAbsSendTimeLog);
receiver_log_.PushExpectedLogLine(
"WrappingBitrateEstimator: Switching to transmission time offset RBE.");
streams_.push_back(new Stream(this));
streams_[0]->StopSending();
streams_[1]->StopSending();
});
EXPECT_TRUE(receiver_log_.Wait());
}
} // namespace webrtc

View File

@ -21,7 +21,7 @@
#include "webrtc/modules/audio_mixer/audio_mixer_impl.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
#include "webrtc/rtc_base/checks.h"
#include "webrtc/rtc_base/constructormagic.h"
#include "webrtc/rtc_base/ptr_util.h"
#include "webrtc/rtc_base/thread_annotations.h"
#include "webrtc/system_wrappers/include/metrics_default.h"
#include "webrtc/test/call_test.h"
@ -35,6 +35,7 @@
#include "webrtc/test/frame_generator_capturer.h"
#include "webrtc/test/gtest.h"
#include "webrtc/test/rtp_rtcp_observer.h"
#include "webrtc/test/single_threaded_task_queue.h"
#include "webrtc/test/testsupport/fileutils.h"
#include "webrtc/test/testsupport/perf_test.h"
#include "webrtc/video/transport_adapter.h"
@ -143,146 +144,167 @@ void CallPerfTest::TestAudioVideoSync(FecMode fec,
const uint32_t kAudioSendSsrc = 1234;
const uint32_t kAudioRecvSsrc = 5678;
metrics::Reset();
rtc::scoped_refptr<AudioProcessing> audio_processing =
AudioProcessing::Create();
VoiceEngine* voice_engine = VoiceEngine::Create();
VoEBase* voe_base = VoEBase::GetInterface(voice_engine);
FakeAudioDevice fake_audio_device(
FakeAudioDevice::CreatePulsedNoiseCapturer(256, 48000),
FakeAudioDevice::CreateDiscardRenderer(48000), audio_rtp_speed);
EXPECT_EQ(0, voe_base->Init(&fake_audio_device, audio_processing.get(),
decoder_factory_));
VoEBase::ChannelConfig config;
config.enable_voice_pacing = true;
int send_channel_id = voe_base->CreateChannel(config);
int recv_channel_id = voe_base->CreateChannel();
AudioState::Config send_audio_state_config;
send_audio_state_config.voice_engine = voice_engine;
send_audio_state_config.audio_mixer = AudioMixerImpl::Create();
send_audio_state_config.audio_processing = audio_processing;
Call::Config sender_config(event_log_.get());
sender_config.audio_state = AudioState::Create(send_audio_state_config);
Call::Config receiver_config(event_log_.get());
receiver_config.audio_state = sender_config.audio_state;
CreateCalls(sender_config, receiver_config);
VideoRtcpAndSyncObserver observer(Clock::GetRealTimeClock());
int send_channel_id;
int recv_channel_id;
FakeNetworkPipe::Config audio_net_config;
audio_net_config.queue_delay_ms = 500;
audio_net_config.loss_percent = 5;
rtc::scoped_refptr<AudioProcessing> audio_processing;
VoiceEngine* voice_engine;
VoEBase* voe_base;
std::unique_ptr<FakeAudioDevice> fake_audio_device;
VideoRtcpAndSyncObserver observer(Clock::GetRealTimeClock());
std::map<uint8_t, MediaType> audio_pt_map;
std::map<uint8_t, MediaType> video_pt_map;
std::copy_if(std::begin(payload_type_map_), std::end(payload_type_map_),
std::inserter(audio_pt_map, audio_pt_map.end()),
[](const std::pair<const uint8_t, MediaType>& pair) {
return pair.second == MediaType::AUDIO;
});
std::copy_if(std::begin(payload_type_map_), std::end(payload_type_map_),
std::inserter(video_pt_map, video_pt_map.end()),
[](const std::pair<const uint8_t, MediaType>& pair) {
return pair.second == MediaType::VIDEO;
});
test::PacketTransport audio_send_transport(sender_call_.get(), &observer,
test::PacketTransport::kSender,
audio_pt_map, audio_net_config);
audio_send_transport.SetReceiver(receiver_call_->Receiver());
test::PacketTransport video_send_transport(
sender_call_.get(), &observer, test::PacketTransport::kSender,
video_pt_map, FakeNetworkPipe::Config());
video_send_transport.SetReceiver(receiver_call_->Receiver());
test::PacketTransport receive_transport(
receiver_call_.get(), &observer, test::PacketTransport::kReceiver,
payload_type_map_, FakeNetworkPipe::Config());
receive_transport.SetReceiver(sender_call_->Receiver());
CreateSendConfig(1, 0, 0, &video_send_transport);
CreateMatchingReceiveConfigs(&receive_transport);
AudioSendStream::Config audio_send_config(&audio_send_transport);
audio_send_config.voe_channel_id = send_channel_id;
audio_send_config.rtp.ssrc = kAudioSendSsrc;
audio_send_config.send_codec_spec =
rtc::Optional<AudioSendStream::Config::SendCodecSpec>(
{kAudioSendPayloadType, {"ISAC", 16000, 1}});
audio_send_config.encoder_factory = CreateBuiltinAudioEncoderFactory();
AudioSendStream* audio_send_stream =
sender_call_->CreateAudioSendStream(audio_send_config);
video_send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
if (fec == FecMode::kOn) {
video_send_config_.rtp.ulpfec.red_payload_type = kRedPayloadType;
video_send_config_.rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType;
video_receive_configs_[0].rtp.ulpfec.red_payload_type = kRedPayloadType;
video_receive_configs_[0].rtp.ulpfec.ulpfec_payload_type =
kUlpfecPayloadType;
}
video_receive_configs_[0].rtp.nack.rtp_history_ms = 1000;
video_receive_configs_[0].renderer = &observer;
video_receive_configs_[0].sync_group = kSyncGroup;
AudioReceiveStream::Config audio_recv_config;
audio_recv_config.rtp.remote_ssrc = kAudioSendSsrc;
audio_recv_config.rtp.local_ssrc = kAudioRecvSsrc;
audio_recv_config.voe_channel_id = recv_channel_id;
audio_recv_config.sync_group = kSyncGroup;
audio_recv_config.decoder_factory = decoder_factory_;
audio_recv_config.decoder_map = {{kAudioSendPayloadType, {"ISAC", 16000, 1}}};
std::unique_ptr<test::PacketTransport> audio_send_transport;
std::unique_ptr<test::PacketTransport> video_send_transport;
std::unique_ptr<test::PacketTransport> receive_transport;
AudioSendStream* audio_send_stream;
AudioReceiveStream* audio_receive_stream;
std::unique_ptr<DriftingClock> drifting_clock;
if (create_first == CreateOrder::kAudioFirst) {
audio_receive_stream =
receiver_call_->CreateAudioReceiveStream(audio_recv_config);
CreateVideoStreams();
} else {
CreateVideoStreams();
audio_receive_stream =
receiver_call_->CreateAudioReceiveStream(audio_recv_config);
}
EXPECT_EQ(1u, video_receive_streams_.size());
observer.set_receive_stream(video_receive_streams_[0]);
DriftingClock drifting_clock(clock_, video_ntp_speed);
CreateFrameGeneratorCapturerWithDrift(&drifting_clock, video_rtp_speed,
kDefaultFramerate, kDefaultWidth,
kDefaultHeight);
task_queue_.SendTask([&]() {
metrics::Reset();
audio_processing = AudioProcessing::Create();
voice_engine = VoiceEngine::Create();
voe_base = VoEBase::GetInterface(voice_engine);
fake_audio_device = rtc::MakeUnique<FakeAudioDevice>(
FakeAudioDevice::CreatePulsedNoiseCapturer(256, 48000),
FakeAudioDevice::CreateDiscardRenderer(48000), audio_rtp_speed);
EXPECT_EQ(0, voe_base->Init(fake_audio_device.get(), audio_processing.get(),
decoder_factory_));
VoEBase::ChannelConfig config;
config.enable_voice_pacing = true;
send_channel_id = voe_base->CreateChannel(config);
recv_channel_id = voe_base->CreateChannel();
Start();
AudioState::Config send_audio_state_config;
send_audio_state_config.voice_engine = voice_engine;
send_audio_state_config.audio_mixer = AudioMixerImpl::Create();
send_audio_state_config.audio_processing = audio_processing;
Call::Config sender_config(event_log_.get());
audio_send_stream->Start();
audio_receive_stream->Start();
sender_config.audio_state = AudioState::Create(send_audio_state_config);
Call::Config receiver_config(event_log_.get());
receiver_config.audio_state = sender_config.audio_state;
CreateCalls(sender_config, receiver_config);
std::copy_if(std::begin(payload_type_map_), std::end(payload_type_map_),
std::inserter(audio_pt_map, audio_pt_map.end()),
[](const std::pair<const uint8_t, MediaType>& pair) {
return pair.second == MediaType::AUDIO;
});
std::copy_if(std::begin(payload_type_map_), std::end(payload_type_map_),
std::inserter(video_pt_map, video_pt_map.end()),
[](const std::pair<const uint8_t, MediaType>& pair) {
return pair.second == MediaType::VIDEO;
});
audio_send_transport = rtc::MakeUnique<test::PacketTransport>(
&task_queue_, sender_call_.get(), &observer,
test::PacketTransport::kSender, audio_pt_map, audio_net_config);
audio_send_transport->SetReceiver(receiver_call_->Receiver());
video_send_transport = rtc::MakeUnique<test::PacketTransport>(
&task_queue_, sender_call_.get(), &observer,
test::PacketTransport::kSender, video_pt_map,
FakeNetworkPipe::Config());
video_send_transport->SetReceiver(receiver_call_->Receiver());
receive_transport = rtc::MakeUnique<test::PacketTransport>(
&task_queue_, receiver_call_.get(), &observer,
test::PacketTransport::kReceiver, payload_type_map_,
FakeNetworkPipe::Config());
receive_transport->SetReceiver(sender_call_->Receiver());
CreateSendConfig(1, 0, 0, video_send_transport.get());
CreateMatchingReceiveConfigs(receive_transport.get());
AudioSendStream::Config audio_send_config(audio_send_transport.get());
audio_send_config.voe_channel_id = send_channel_id;
audio_send_config.rtp.ssrc = kAudioSendSsrc;
audio_send_config.send_codec_spec =
rtc::Optional<AudioSendStream::Config::SendCodecSpec>(
{kAudioSendPayloadType, {"ISAC", 16000, 1}});
audio_send_config.encoder_factory = CreateBuiltinAudioEncoderFactory();
audio_send_stream = sender_call_->CreateAudioSendStream(audio_send_config);
video_send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
if (fec == FecMode::kOn) {
video_send_config_.rtp.ulpfec.red_payload_type = kRedPayloadType;
video_send_config_.rtp.ulpfec.ulpfec_payload_type = kUlpfecPayloadType;
video_receive_configs_[0].rtp.ulpfec.red_payload_type = kRedPayloadType;
video_receive_configs_[0].rtp.ulpfec.ulpfec_payload_type =
kUlpfecPayloadType;
}
video_receive_configs_[0].rtp.nack.rtp_history_ms = 1000;
video_receive_configs_[0].renderer = &observer;
video_receive_configs_[0].sync_group = kSyncGroup;
AudioReceiveStream::Config audio_recv_config;
audio_recv_config.rtp.remote_ssrc = kAudioSendSsrc;
audio_recv_config.rtp.local_ssrc = kAudioRecvSsrc;
audio_recv_config.voe_channel_id = recv_channel_id;
audio_recv_config.sync_group = kSyncGroup;
audio_recv_config.decoder_factory = decoder_factory_;
audio_recv_config.decoder_map = {
{kAudioSendPayloadType, {"ISAC", 16000, 1}}};
if (create_first == CreateOrder::kAudioFirst) {
audio_receive_stream =
receiver_call_->CreateAudioReceiveStream(audio_recv_config);
CreateVideoStreams();
} else {
CreateVideoStreams();
audio_receive_stream =
receiver_call_->CreateAudioReceiveStream(audio_recv_config);
}
EXPECT_EQ(1u, video_receive_streams_.size());
observer.set_receive_stream(video_receive_streams_[0]);
drifting_clock = rtc::MakeUnique<DriftingClock>(clock_, video_ntp_speed);
CreateFrameGeneratorCapturerWithDrift(drifting_clock.get(), video_rtp_speed,
kDefaultFramerate, kDefaultWidth,
kDefaultHeight);
Start();
audio_send_stream->Start();
audio_receive_stream->Start();
});
EXPECT_TRUE(observer.Wait())
<< "Timed out while waiting for audio and video to be synchronized.";
audio_send_stream->Stop();
audio_receive_stream->Stop();
task_queue_.SendTask([&]() {
audio_send_stream->Stop();
audio_receive_stream->Stop();
Stop();
video_send_transport.StopSending();
audio_send_transport.StopSending();
receive_transport.StopSending();
Stop();
DestroyStreams();
DestroyStreams();
sender_call_->DestroyAudioSendStream(audio_send_stream);
receiver_call_->DestroyAudioReceiveStream(audio_receive_stream);
video_send_transport.reset();
audio_send_transport.reset();
receive_transport.reset();
voe_base->DeleteChannel(send_channel_id);
voe_base->DeleteChannel(recv_channel_id);
voe_base->Release();
sender_call_->DestroyAudioSendStream(audio_send_stream);
receiver_call_->DestroyAudioReceiveStream(audio_receive_stream);
DestroyCalls();
voe_base->DeleteChannel(send_channel_id);
voe_base->DeleteChannel(recv_channel_id);
voe_base->Release();
VoiceEngine::Delete(voice_engine);
DestroyCalls();
VoiceEngine::Delete(voice_engine);
fake_audio_device.reset();
});
observer.PrintResults();
@ -335,14 +357,17 @@ void CallPerfTest::TestCaptureNtpTime(const FakeNetworkPipe::Config& net_config,
rtp_start_timestamp_(0) {}
private:
test::PacketTransport* CreateSendTransport(Call* sender_call) override {
return new test::PacketTransport(sender_call, this,
test::PacketTransport* CreateSendTransport(
test::SingleThreadedTaskQueueForTesting* task_queue,
Call* sender_call) override {
return new test::PacketTransport(task_queue, sender_call, this,
test::PacketTransport::kSender,
payload_type_map_, net_config_);
}
test::PacketTransport* CreateReceiveTransport() override {
return new test::PacketTransport(nullptr, this,
test::PacketTransport* CreateReceiveTransport(
test::SingleThreadedTaskQueueForTesting* task_queue) override {
return new test::PacketTransport(task_queue, nullptr, this,
test::PacketTransport::kReceiver,
payload_type_map_, net_config_);
}

View File

@ -90,9 +90,11 @@ void RampUpTester::OnVideoStreamsCreated(
send_stream_ = send_stream;
}
test::PacketTransport* RampUpTester::CreateSendTransport(Call* sender_call) {
test::PacketTransport* RampUpTester::CreateSendTransport(
test::SingleThreadedTaskQueueForTesting* task_queue,
Call* sender_call) {
send_transport_ = new test::PacketTransport(
sender_call, this, test::PacketTransport::kSender,
task_queue, sender_call, this, test::PacketTransport::kSender,
test::CallTest::payload_type_map_, forward_transport_config_);
return send_transport_;
}

View File

@ -84,7 +84,9 @@ class RampUpTester : public test::EndToEndTest {
void OnVideoStreamsCreated(
VideoSendStream* send_stream,
const std::vector<VideoReceiveStream*>& receive_streams) override;
test::PacketTransport* CreateSendTransport(Call* sender_call) override;
test::PacketTransport* CreateSendTransport(
test::SingleThreadedTaskQueueForTesting* task_queue,
Call* sender_call) override;
void ModifyVideoConfigs(
VideoSendStream::Config* send_config,
std::vector<VideoReceiveStream::Config>* receive_configs,

View File

@ -287,6 +287,7 @@ if (!build_with_chromium) {
"frame_generator_unittest.cc",
"rtp_file_reader_unittest.cc",
"rtp_file_writer_unittest.cc",
"single_threaded_task_queue_unittest.cc",
"testsupport/always_passing_unittest.cc",
"testsupport/metrics/video_metrics_unittest.cc",
"testsupport/packet_reader_unittest.cc",
@ -401,8 +402,23 @@ rtc_source_set("direct_transport") {
"../call",
"../modules/rtp_rtcp",
"../rtc_base:rtc_base_approved",
"../rtc_base:sequenced_task_checker",
"../system_wrappers",
]
public_deps = [
":single_threaded_task_queue",
]
}
rtc_source_set("single_threaded_task_queue") {
testonly = true
sources = [
"single_threaded_task_queue.cc",
"single_threaded_task_queue.h",
]
deps = [
"../rtc_base:rtc_base_approved",
]
}
rtc_source_set("fake_audio_device") {

View File

@ -18,8 +18,11 @@
#include "webrtc/config.h"
#include "webrtc/modules/audio_mixer/audio_mixer_impl.h"
#include "webrtc/rtc_base/checks.h"
#include "webrtc/rtc_base/event.h"
#include "webrtc/rtc_base/ptr_util.h"
#include "webrtc/test/testsupport/fileutils.h"
#include "webrtc/voice_engine/include/voe_base.h"
namespace webrtc {
namespace test {
@ -41,112 +44,124 @@ CallTest::CallTest()
num_flexfec_streams_(0),
decoder_factory_(CreateBuiltinAudioDecoderFactory()),
encoder_factory_(CreateBuiltinAudioEncoderFactory()),
task_queue_("CallTestTaskQueue"),
fake_send_audio_device_(nullptr),
fake_recv_audio_device_(nullptr) {}
CallTest::~CallTest() {
task_queue_.SendTask([this]() {
fake_send_audio_device_.reset();
fake_recv_audio_device_.reset();
frame_generator_capturer_.reset();
});
}
void CallTest::RunBaseTest(BaseTest* test) {
num_video_streams_ = test->GetNumVideoStreams();
num_audio_streams_ = test->GetNumAudioStreams();
num_flexfec_streams_ = test->GetNumFlexfecStreams();
RTC_DCHECK(num_video_streams_ > 0 || num_audio_streams_ > 0);
Call::Config send_config(test->GetSenderCallConfig());
if (num_audio_streams_ > 0) {
CreateFakeAudioDevices(test->CreateCapturer(), test->CreateRenderer());
test->OnFakeAudioDevicesCreated(fake_send_audio_device_.get(),
fake_recv_audio_device_.get());
apm_send_ = AudioProcessing::Create();
apm_recv_ = AudioProcessing::Create();
CreateVoiceEngines();
AudioState::Config audio_state_config;
audio_state_config.voice_engine = voe_send_.voice_engine;
audio_state_config.audio_mixer = AudioMixerImpl::Create();
audio_state_config.audio_processing = apm_send_;
send_config.audio_state = AudioState::Create(audio_state_config);
}
CreateSenderCall(send_config);
if (sender_call_transport_controller_ != nullptr) {
test->OnRtpTransportControllerSendCreated(
sender_call_transport_controller_);
}
if (test->ShouldCreateReceivers()) {
Call::Config recv_config(test->GetReceiverCallConfig());
task_queue_.SendTask([this, test]() {
num_video_streams_ = test->GetNumVideoStreams();
num_audio_streams_ = test->GetNumAudioStreams();
num_flexfec_streams_ = test->GetNumFlexfecStreams();
RTC_DCHECK(num_video_streams_ > 0 || num_audio_streams_ > 0);
Call::Config send_config(test->GetSenderCallConfig());
if (num_audio_streams_ > 0) {
CreateFakeAudioDevices(test->CreateCapturer(), test->CreateRenderer());
test->OnFakeAudioDevicesCreated(fake_send_audio_device_.get(),
fake_recv_audio_device_.get());
apm_send_ = AudioProcessing::Create();
apm_recv_ = AudioProcessing::Create();
CreateVoiceEngines();
AudioState::Config audio_state_config;
audio_state_config.voice_engine = voe_recv_.voice_engine;
audio_state_config.voice_engine = voe_send_.voice_engine;
audio_state_config.audio_mixer = AudioMixerImpl::Create();
audio_state_config.audio_processing = apm_recv_;
recv_config.audio_state = AudioState::Create(audio_state_config);
audio_state_config.audio_processing = apm_send_;
send_config.audio_state = AudioState::Create(audio_state_config);
}
CreateReceiverCall(recv_config);
}
test->OnCallsCreated(sender_call_.get(), receiver_call_.get());
receive_transport_.reset(test->CreateReceiveTransport());
send_transport_.reset(test->CreateSendTransport(sender_call_.get()));
CreateSenderCall(send_config);
if (sender_call_transport_controller_ != nullptr) {
test->OnRtpTransportControllerSendCreated(
sender_call_transport_controller_);
}
if (test->ShouldCreateReceivers()) {
Call::Config recv_config(test->GetReceiverCallConfig());
if (num_audio_streams_ > 0) {
AudioState::Config audio_state_config;
audio_state_config.voice_engine = voe_recv_.voice_engine;
audio_state_config.audio_mixer = AudioMixerImpl::Create();
audio_state_config.audio_processing = apm_recv_;
recv_config.audio_state = AudioState::Create(audio_state_config);
}
CreateReceiverCall(recv_config);
}
test->OnCallsCreated(sender_call_.get(), receiver_call_.get());
receive_transport_.reset(test->CreateReceiveTransport(&task_queue_));
send_transport_.reset(
test->CreateSendTransport(&task_queue_, sender_call_.get()));
if (test->ShouldCreateReceivers()) {
send_transport_->SetReceiver(receiver_call_->Receiver());
receive_transport_->SetReceiver(sender_call_->Receiver());
if (num_video_streams_ > 0)
receiver_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
if (num_audio_streams_ > 0)
receiver_call_->SignalChannelNetworkState(MediaType::AUDIO, kNetworkUp);
} else {
// Sender-only call delivers to itself.
send_transport_->SetReceiver(sender_call_->Receiver());
receive_transport_->SetReceiver(nullptr);
}
if (test->ShouldCreateReceivers()) {
send_transport_->SetReceiver(receiver_call_->Receiver());
receive_transport_->SetReceiver(sender_call_->Receiver());
if (num_video_streams_ > 0)
receiver_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
if (num_audio_streams_ > 0)
receiver_call_->SignalChannelNetworkState(MediaType::AUDIO, kNetworkUp);
} else {
// Sender-only call delivers to itself.
send_transport_->SetReceiver(sender_call_->Receiver());
receive_transport_->SetReceiver(nullptr);
}
CreateSendConfig(num_video_streams_, num_audio_streams_, num_flexfec_streams_,
send_transport_.get());
if (test->ShouldCreateReceivers()) {
CreateMatchingReceiveConfigs(receive_transport_.get());
}
if (num_video_streams_ > 0) {
test->ModifyVideoConfigs(&video_send_config_, &video_receive_configs_,
&video_encoder_config_);
}
if (num_audio_streams_ > 0) {
test->ModifyAudioConfigs(&audio_send_config_, &audio_receive_configs_);
}
if (num_flexfec_streams_ > 0) {
test->ModifyFlexfecConfigs(&flexfec_receive_configs_);
}
CreateSendConfig(num_video_streams_, num_audio_streams_,
num_flexfec_streams_, send_transport_.get());
if (test->ShouldCreateReceivers()) {
CreateMatchingReceiveConfigs(receive_transport_.get());
}
if (num_video_streams_ > 0) {
test->ModifyVideoConfigs(&video_send_config_, &video_receive_configs_,
&video_encoder_config_);
}
if (num_audio_streams_ > 0) {
test->ModifyAudioConfigs(&audio_send_config_, &audio_receive_configs_);
}
if (num_flexfec_streams_ > 0) {
test->ModifyFlexfecConfigs(&flexfec_receive_configs_);
}
if (num_flexfec_streams_ > 0) {
CreateFlexfecStreams();
test->OnFlexfecStreamsCreated(flexfec_receive_streams_);
}
if (num_video_streams_ > 0) {
CreateVideoStreams();
test->OnVideoStreamsCreated(video_send_stream_, video_receive_streams_);
}
if (num_audio_streams_ > 0) {
CreateAudioStreams();
test->OnAudioStreamsCreated(audio_send_stream_, audio_receive_streams_);
}
if (num_flexfec_streams_ > 0) {
CreateFlexfecStreams();
test->OnFlexfecStreamsCreated(flexfec_receive_streams_);
}
if (num_video_streams_ > 0) {
CreateVideoStreams();
test->OnVideoStreamsCreated(video_send_stream_, video_receive_streams_);
}
if (num_audio_streams_ > 0) {
CreateAudioStreams();
test->OnAudioStreamsCreated(audio_send_stream_, audio_receive_streams_);
}
if (num_video_streams_ > 0) {
int width = kDefaultWidth;
int height = kDefaultHeight;
int frame_rate = kDefaultFramerate;
test->ModifyVideoCaptureStartResolution(&width, &height, &frame_rate);
CreateFrameGeneratorCapturer(frame_rate, width, height);
test->OnFrameGeneratorCapturerCreated(frame_generator_capturer_.get());
}
if (num_video_streams_ > 0) {
int width = kDefaultWidth;
int height = kDefaultHeight;
int frame_rate = kDefaultFramerate;
test->ModifyVideoCaptureStartResolution(&width, &height, &frame_rate);
CreateFrameGeneratorCapturer(frame_rate, width, height);
test->OnFrameGeneratorCapturerCreated(frame_generator_capturer_.get());
}
Start();
});
Start();
test->PerformTest();
send_transport_->StopSending();
receive_transport_->StopSending();
Stop();
DestroyStreams();
DestroyCalls();
if (num_audio_streams_ > 0)
DestroyVoiceEngines();
task_queue_.SendTask([this]() {
Stop();
DestroyStreams();
send_transport_.reset();
receive_transport_.reset();
DestroyCalls();
if (num_audio_streams_ > 0)
DestroyVoiceEngines();
});
test->OnTestFinished();
}
@ -517,16 +532,19 @@ void BaseTest::OnRtpTransportControllerSendCreated(
void BaseTest::OnCallsCreated(Call* sender_call, Call* receiver_call) {
}
test::PacketTransport* BaseTest::CreateSendTransport(Call* sender_call) {
return new PacketTransport(sender_call, this, test::PacketTransport::kSender,
CallTest::payload_type_map_,
FakeNetworkPipe::Config());
test::PacketTransport* BaseTest::CreateSendTransport(
SingleThreadedTaskQueueForTesting* task_queue,
Call* sender_call) {
return new PacketTransport(
task_queue, sender_call, this, test::PacketTransport::kSender,
CallTest::payload_type_map_, FakeNetworkPipe::Config());
}
test::PacketTransport* BaseTest::CreateReceiveTransport() {
return new PacketTransport(nullptr, this, test::PacketTransport::kReceiver,
CallTest::payload_type_map_,
FakeNetworkPipe::Config());
test::PacketTransport* BaseTest::CreateReceiveTransport(
SingleThreadedTaskQueueForTesting* task_queue) {
return new PacketTransport(
task_queue, nullptr, this, test::PacketTransport::kReceiver,
CallTest::payload_type_map_, FakeNetworkPipe::Config());
}
size_t BaseTest::GetNumVideoStreams() const {

View File

@ -23,6 +23,7 @@
#include "webrtc/test/fake_videorenderer.h"
#include "webrtc/test/frame_generator_capturer.h"
#include "webrtc/test/rtp_rtcp_observer.h"
#include "webrtc/test/single_threaded_task_queue.h"
namespace webrtc {
@ -136,6 +137,8 @@ class CallTest : public ::testing::Test {
rtc::scoped_refptr<AudioEncoderFactory> encoder_factory_;
test::FakeVideoRenderer fake_renderer_;
SingleThreadedTaskQueueForTesting task_queue_;
private:
// TODO(holmer): Remove once VoiceEngine is fully refactored to the new API.
// These methods are used to set up legacy voice engines and channels which is
@ -188,8 +191,11 @@ class BaseTest : public RtpRtcpObserver {
RtpTransportControllerSend* controller);
virtual void OnCallsCreated(Call* sender_call, Call* receiver_call);
virtual test::PacketTransport* CreateSendTransport(Call* sender_call);
virtual test::PacketTransport* CreateReceiveTransport();
virtual test::PacketTransport* CreateSendTransport(
SingleThreadedTaskQueueForTesting* task_queue,
Call* sender_call);
virtual test::PacketTransport* CreateReceiveTransport(
SingleThreadedTaskQueueForTesting* task_queue);
virtual void ModifyVideoConfigs(
VideoSendStream::Config* send_config,

View File

@ -10,7 +10,9 @@
#include "webrtc/test/direct_transport.h"
#include "webrtc/call/call.h"
#include "webrtc/rtc_base/ptr_util.h"
#include "webrtc/system_wrappers/include/clock.h"
#include "webrtc/test/single_threaded_task_queue.h"
namespace webrtc {
namespace test {
@ -32,36 +34,71 @@ DirectTransport::DirectTransport(
DirectTransport::DirectTransport(const FakeNetworkPipe::Config& config,
Call* send_call,
std::unique_ptr<Demuxer> demuxer)
: DirectTransport(nullptr, config, send_call, std::move(demuxer)) {}
DirectTransport::DirectTransport(
SingleThreadedTaskQueueForTesting* task_queue,
Call* send_call,
const std::map<uint8_t, MediaType>& payload_type_map)
: DirectTransport(task_queue,
FakeNetworkPipe::Config(),
send_call,
payload_type_map) {
}
DirectTransport::DirectTransport(
SingleThreadedTaskQueueForTesting* task_queue,
const FakeNetworkPipe::Config& config,
Call* send_call,
const std::map<uint8_t, MediaType>& payload_type_map)
: DirectTransport(
task_queue,
config,
send_call,
std::unique_ptr<Demuxer>(new DemuxerImpl(payload_type_map))) {
}
DirectTransport::DirectTransport(SingleThreadedTaskQueueForTesting* task_queue,
const FakeNetworkPipe::Config& config,
Call* send_call,
std::unique_ptr<Demuxer> demuxer)
: send_call_(send_call),
packet_event_(false, false),
thread_(NetworkProcess, this, "NetworkProcess"),
clock_(Clock::GetRealTimeClock()),
shutting_down_(false),
task_queue_(task_queue),
fake_network_(clock_, config, std::move(demuxer)) {
thread_.Start();
// TODO(eladalon): When the deprecated ctors are removed, this check
// can be restored. https://bugs.chromium.org/p/webrtc/issues/detail?id=8125
// RTC_DCHECK(task_queue);
if (!task_queue) {
deprecated_task_queue_ =
rtc::MakeUnique<SingleThreadedTaskQueueForTesting>("deprecated_queue");
task_queue_ = deprecated_task_queue_.get();
}
if (send_call_) {
send_call_->SignalChannelNetworkState(MediaType::AUDIO, kNetworkUp);
send_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
}
SendPackets();
}
DirectTransport::~DirectTransport() { StopSending(); }
DirectTransport::~DirectTransport() {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
// Constructor updates |next_scheduled_task_|, so it's guaranteed to
// be initialized.
task_queue_->CancelTask(next_scheduled_task_);
}
void DirectTransport::SetConfig(const FakeNetworkPipe::Config& config) {
fake_network_.SetConfig(config);
}
void DirectTransport::StopSending() {
{
rtc::CritScope crit(&lock_);
shutting_down_ = true;
}
packet_event_.Set();
thread_.Stop();
task_queue_->CancelTask(next_scheduled_task_);
}
void DirectTransport::SetReceiver(PacketReceiver* receiver) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
fake_network_.SetReceiver(receiver);
}
@ -74,13 +111,11 @@ bool DirectTransport::SendRtp(const uint8_t* data,
send_call_->OnSentPacket(sent_packet);
}
fake_network_.SendPacket(data, length);
packet_event_.Set();
return true;
}
bool DirectTransport::SendRtcp(const uint8_t* data, size_t length) {
fake_network_.SendPacket(data, length);
packet_event_.Set();
return true;
}
@ -104,18 +139,15 @@ void DirectTransport::ForceDemuxer::DeliverPacket(
packet->data_length(), packet_time);
}
bool DirectTransport::NetworkProcess(void* transport) {
return static_cast<DirectTransport*>(transport)->SendPackets();
}
void DirectTransport::SendPackets() {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
bool DirectTransport::SendPackets() {
fake_network_.Process();
int64_t wait_time_ms = fake_network_.TimeUntilNextProcess();
if (wait_time_ms > 0) {
packet_event_.Wait(static_cast<int>(wait_time_ms));
}
rtc::CritScope crit(&lock_);
return shutting_down_ ? false : true;
int64_t delay_ms = fake_network_.TimeUntilNextProcess();
next_scheduled_task_ = task_queue_->PostDelayedTask([this]() {
SendPackets();
}, delay_ms);
}
} // namespace test
} // namespace webrtc

View File

@ -12,14 +12,13 @@
#include <assert.h>
#include <deque>
#include <memory>
#include "webrtc/api/call/transport.h"
#include "webrtc/call/call.h"
#include "webrtc/rtc_base/criticalsection.h"
#include "webrtc/rtc_base/event.h"
#include "webrtc/rtc_base/platform_thread.h"
#include "webrtc/rtc_base/sequenced_task_checker.h"
#include "webrtc/test/fake_network_pipe.h"
#include "webrtc/test/single_threaded_task_queue.h"
namespace webrtc {
@ -30,14 +29,17 @@ namespace test {
class DirectTransport : public Transport {
public:
DirectTransport(Call* send_call,
const std::map<uint8_t, MediaType>& payload_type_map);
DirectTransport(const FakeNetworkPipe::Config& config,
Call* send_call,
const std::map<uint8_t, MediaType>& payload_type_map);
DirectTransport(const FakeNetworkPipe::Config& config,
Call* send_call,
std::unique_ptr<Demuxer> demuxer);
RTC_DEPRECATED DirectTransport(
Call* send_call,
const std::map<uint8_t, MediaType>& payload_type_map);
RTC_DEPRECATED DirectTransport(
const FakeNetworkPipe::Config& config,
Call* send_call,
const std::map<uint8_t, MediaType>& payload_type_map);
RTC_DEPRECATED DirectTransport(
const FakeNetworkPipe::Config& config,
Call* send_call,
std::unique_ptr<Demuxer> demuxer);
// This deprecated variant always uses MediaType::VIDEO.
RTC_DEPRECATED explicit DirectTransport(Call* send_call)
@ -46,11 +48,26 @@ class DirectTransport : public Transport {
send_call,
std::unique_ptr<Demuxer>(new ForceDemuxer(MediaType::VIDEO))) {}
DirectTransport(SingleThreadedTaskQueueForTesting* task_queue,
Call* send_call,
const std::map<uint8_t, MediaType>& payload_type_map);
DirectTransport(SingleThreadedTaskQueueForTesting* task_queue,
const FakeNetworkPipe::Config& config,
Call* send_call,
const std::map<uint8_t, MediaType>& payload_type_map);
DirectTransport(SingleThreadedTaskQueueForTesting* task_queue,
const FakeNetworkPipe::Config& config,
Call* send_call,
std::unique_ptr<Demuxer> demuxer);
~DirectTransport() override;
void SetConfig(const FakeNetworkPipe::Config& config);
virtual void StopSending();
RTC_DEPRECATED void StopSending();
// TODO(holmer): Look into moving this to the constructor.
virtual void SetReceiver(PacketReceiver* receiver);
@ -77,18 +94,25 @@ class DirectTransport : public Transport {
RTC_DISALLOW_COPY_AND_ASSIGN(ForceDemuxer);
};
static bool NetworkProcess(void* transport);
bool SendPackets();
void SendPackets();
rtc::CriticalSection lock_;
Call* const send_call_;
rtc::Event packet_event_;
rtc::PlatformThread thread_;
Clock* const clock_;
bool shutting_down_;
// TODO(eladalon): Make |task_queue_| const.
// https://bugs.chromium.org/p/webrtc/issues/detail?id=8125
SingleThreadedTaskQueueForTesting* task_queue_;
SingleThreadedTaskQueueForTesting::TaskId next_scheduled_task_;
FakeNetworkPipe fake_network_;
rtc::SequencedTaskChecker sequence_checker_;
// TODO(eladalon): https://bugs.chromium.org/p/webrtc/issues/detail?id=8125
// Deprecated versions of the ctor don't get the task queue passed in from
// outside. We'll create one locally for them. This is deprecated, and will
// be removed as soon as the need for those ctors is removed.
std::unique_ptr<SingleThreadedTaskQueueForTesting> deprecated_task_queue_;
};
} // namespace test
} // namespace webrtc

View File

@ -21,6 +21,7 @@ namespace webrtc {
namespace test {
LayerFilteringTransport::LayerFilteringTransport(
SingleThreadedTaskQueueForTesting* task_queue,
const FakeNetworkPipe::Config& config,
Call* send_call,
uint8_t vp8_video_payload_type,
@ -28,7 +29,7 @@ LayerFilteringTransport::LayerFilteringTransport(
int selected_tl,
int selected_sl,
const std::map<uint8_t, MediaType>& payload_type_map)
: test::DirectTransport(config, send_call, payload_type_map),
: DirectTransport(task_queue, config, send_call, payload_type_map),
vp8_video_payload_type_(vp8_video_payload_type),
vp9_video_payload_type_(vp9_video_payload_type),
selected_tl_(selected_tl),

View File

@ -13,6 +13,7 @@
#include "webrtc/call/call.h"
#include "webrtc/test/direct_transport.h"
#include "webrtc/test/fake_network_pipe.h"
#include "webrtc/test/single_threaded_task_queue.h"
#include <map>
@ -22,7 +23,8 @@ namespace test {
class LayerFilteringTransport : public test::DirectTransport {
public:
LayerFilteringTransport(const FakeNetworkPipe::Config& config,
LayerFilteringTransport(SingleThreadedTaskQueueForTesting* task_queue,
const FakeNetworkPipe::Config& config,
Call* send_call,
uint8_t vp8_video_payload_type,
uint8_t vp9_video_payload_type,

View File

@ -32,6 +32,7 @@ namespace webrtc {
namespace test {
class PacketTransport;
class SingleThreadedTaskQueueForTesting;
class RtpRtcpObserver {
public:
@ -91,12 +92,16 @@ class PacketTransport : public test::DirectTransport {
public:
enum TransportType { kReceiver, kSender };
PacketTransport(Call* send_call,
PacketTransport(SingleThreadedTaskQueueForTesting* task_queue,
Call* send_call,
RtpRtcpObserver* observer,
TransportType transport_type,
const std::map<uint8_t, MediaType>& payload_type_map,
const FakeNetworkPipe::Config& configuration)
: test::DirectTransport(configuration, send_call, payload_type_map),
: test::DirectTransport(task_queue,
configuration,
send_call,
payload_type_map),
observer_(observer),
transport_type_(transport_type) {}

View File

@ -0,0 +1,144 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/test/single_threaded_task_queue.h"
#include <utility>
#include "webrtc/rtc_base/checks.h"
#include "webrtc/rtc_base/ptr_util.h"
#include "webrtc/rtc_base/safe_conversions.h"
#include "webrtc/rtc_base/timeutils.h"
namespace webrtc {
namespace test {
SingleThreadedTaskQueueForTesting::QueuedTask::QueuedTask(
SingleThreadedTaskQueueForTesting::TaskId task_id,
int64_t earliest_execution_time,
SingleThreadedTaskQueueForTesting::Task task)
: task_id(task_id),
earliest_execution_time(earliest_execution_time),
task(task) {}
SingleThreadedTaskQueueForTesting::QueuedTask::~QueuedTask() = default;
SingleThreadedTaskQueueForTesting::SingleThreadedTaskQueueForTesting(
const char* name)
: thread_(Run, this, name),
running_(true),
next_task_id_(0),
wake_up_(false, false) {
thread_.Start();
}
SingleThreadedTaskQueueForTesting::~SingleThreadedTaskQueueForTesting() {
RTC_DCHECK_RUN_ON(&owner_thread_checker_);
{
rtc::CritScope lock(&cs_);
running_ = false;
}
wake_up_.Set();
thread_.Stop();
}
SingleThreadedTaskQueueForTesting::TaskId
SingleThreadedTaskQueueForTesting::PostTask(Task task) {
return PostDelayedTask(task, 0);
}
SingleThreadedTaskQueueForTesting::TaskId
SingleThreadedTaskQueueForTesting::PostDelayedTask(Task task,
int64_t delay_ms) {
int64_t earliest_exec_time = rtc::TimeAfter(delay_ms);
rtc::CritScope lock(&cs_);
TaskId id = next_task_id_++;
// Insert after any other tasks with an earlier-or-equal target time.
auto it = tasks_.begin();
for (; it != tasks_.end(); it++) {
if (earliest_exec_time < (*it)->earliest_execution_time) {
break;
}
}
tasks_.insert(it, rtc::MakeUnique<QueuedTask>(id, earliest_exec_time, task));
// This class is optimized for simplicty, not for performance. This will wake
// the thread up even if the next task in the queue is only scheduled for
// quite some time from now. In that case, the thread will just send itself
// back to sleep.
wake_up_.Set();
return id;
}
void SingleThreadedTaskQueueForTesting::SendTask(Task task) {
rtc::Event done(true, false);
PostTask([&task, &done]() {
task();
done.Set();
});
done.Wait(rtc::Event::kForever);
}
bool SingleThreadedTaskQueueForTesting::CancelTask(TaskId task_id) {
rtc::CritScope lock(&cs_);
for (auto it = tasks_.begin(); it != tasks_.end(); it++) {
if ((*it)->task_id == task_id) {
tasks_.erase(it);
return true;
}
}
return false;
}
void SingleThreadedTaskQueueForTesting::Run(void* obj) {
static_cast<SingleThreadedTaskQueueForTesting*>(obj)->RunLoop();
}
void SingleThreadedTaskQueueForTesting::RunLoop() {
while (true) {
std::unique_ptr<QueuedTask> queued_task;
// An empty queue would lead to sleeping until the queue becoems non-empty.
// A queue where the earliest task is shceduled for later than now, will
// lead to sleeping until the time of the next scheduled task (or until
// more tasks are scheduled).
int wait_time = rtc::Event::kForever;
{
rtc::CritScope lock(&cs_);
if (!running_) {
return;
}
if (!tasks_.empty()) {
int64_t remaining_delay_ms = rtc::TimeDiff(
tasks_.front()->earliest_execution_time, rtc::TimeMillis());
if (remaining_delay_ms <= 0) {
queued_task = std::move(tasks_.front());
tasks_.pop_front();
} else {
wait_time = rtc::saturated_cast<int>(remaining_delay_ms);
}
}
}
if (queued_task) {
queued_task->task();
} else {
wake_up_.Wait(wait_time);
}
}
}
} // namespace test
} // namespace webrtc

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_TEST_SINGLE_THREADED_TASK_QUEUE_H_
#define WEBRTC_TEST_SINGLE_THREADED_TASK_QUEUE_H_
#include <functional>
#include <list>
#include <memory>
#include "webrtc/rtc_base/criticalsection.h"
#include "webrtc/rtc_base/event.h"
#include "webrtc/rtc_base/platform_thread.h"
#include "webrtc/rtc_base/thread_checker.h"
namespace webrtc {
namespace test {
// This class gives capabilities similar to rtc::TaskQueue, but ensures
// everything happens on the same thread. This is intended to make the
// threading model of unit-tests (specifically end-to-end tests) more closely
// resemble that of real WebRTC, thereby allowing us to replace some critical
// sections by thread-checkers.
// This task is NOT tuned for performance, but rather for simplicity.
class SingleThreadedTaskQueueForTesting {
public:
using Task = std::function<void()>;
using TaskId = size_t;
explicit SingleThreadedTaskQueueForTesting(const char* name);
~SingleThreadedTaskQueueForTesting();
// Sends one task to the task-queue, and returns a handle by which the
// task can be cancelled.
// This mimics the behavior of TaskQueue, but only for lambdas, rather than
// for both lambdas and QueuedTask objects.
TaskId PostTask(Task task);
// Same as PostTask(), but ensures that the task will not begin execution
// less than |delay_ms| milliseconds after being posted; an upper bound
// is not provided.
TaskId PostDelayedTask(Task task, int64_t delay_ms);
// Send one task to the queue. The function does not return until the task
// has finished executing. No support for canceling the task.
void SendTask(Task task);
// Given an identifier to the task, attempts to eject it from the queue.
// Returns true if the task was found and cancelled. Failure possible
// only for invalid task IDs, or for tasks which have already been executed.
bool CancelTask(TaskId task_id);
private:
struct QueuedTask {
QueuedTask(TaskId task_id, int64_t earliest_execution_time, Task task);
~QueuedTask();
TaskId task_id;
int64_t earliest_execution_time;
Task task;
};
static void Run(void* obj);
void RunLoop();
rtc::CriticalSection cs_;
std::list<std::unique_ptr<QueuedTask>> tasks_ GUARDED_BY(cs_);
rtc::ThreadChecker owner_thread_checker_;
rtc::PlatformThread thread_;
bool running_ GUARDED_BY(cs_);
TaskId next_task_id_;
// The task-queue will sleep when not executing a task. Wake up occurs when:
// * Upon destruction, to make sure that the |thead_| terminates, so that it
// may be joined. [Event will be set.]
// * New task added. Because we optimize for simplicity rahter than for
// performance (this class is a testing facility only), waking up occurs
// when we get a new task even if it is scheduled with a delay. The RunLoop
// is in charge of sending itself back to sleep if the next task is only
// to be executed at a later time. [Event will be set.]
// * When the next task in the queue is a delayed-task, and the time for
// its execution has come. [Event will time-out.]
rtc::Event wake_up_;
};
} // namespace test
} // namespace webrtc
#endif // WEBRTC_TEST_SINGLE_THREADED_TASK_QUEUE_H_

View File

@ -0,0 +1,364 @@
/*
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/test/single_threaded_task_queue.h"
#include <atomic>
#include <memory>
#include <vector>
#include "webrtc/rtc_base/event.h"
#include "webrtc/rtc_base/ptr_util.h"
#include "webrtc/test/gtest.h"
namespace webrtc {
namespace test {
namespace {
using TaskId = SingleThreadedTaskQueueForTesting::TaskId;
// Test should not rely on the object under test not being faulty. If the task
// queue ever blocks forever, we want the tests to fail, rather than hang.
constexpr int kMaxWaitTimeMs = 10000;
TEST(SingleThreadedTaskQueueForTestingTest, SanityConstructionDestruction) {
SingleThreadedTaskQueueForTesting task_queue("task_queue");
}
TEST(SingleThreadedTaskQueueForTestingTest, ExecutesPostedTasks) {
SingleThreadedTaskQueueForTesting task_queue("task_queue");
std::atomic<bool> executed(false);
rtc::Event done(true, false);
task_queue.PostTask([&executed, &done]() {
executed.store(true);
done.Set();
});
ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
EXPECT_TRUE(executed.load());
}
TEST(SingleThreadedTaskQueueForTestingTest,
PostMultipleTasksFromSameExternalThread) {
SingleThreadedTaskQueueForTesting task_queue("task_queue");
constexpr size_t kCount = 3;
std::atomic<bool> executed[kCount];
for (std::atomic<bool>& exec : executed) {
exec.store(false);
}
std::vector<std::unique_ptr<rtc::Event>> done_events;
for (size_t i = 0; i < kCount; i++) {
done_events.emplace_back(rtc::MakeUnique<rtc::Event>(false, false));
}
// To avoid the tasks which comprise the actual test from running before they
// have all be posted, which could result in only one task ever being in the
// queue at any given time, post one waiting task that would block the
// task-queue, and unblock only after all tasks have been posted.
rtc::Event rendezvous(true, false);
task_queue.PostTask([&rendezvous]() {
ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs));
});
// Post the tasks which comprise the test.
for (size_t i = 0; i < kCount; i++) {
task_queue.PostTask([&executed, &done_events, i]() { // |i| by value.
executed[i].store(true);
done_events[i]->Set();
});
}
rendezvous.Set(); // Release the task-queue.
// Wait until the task queue has executed all the tasks.
for (size_t i = 0; i < kCount; i++) {
ASSERT_TRUE(done_events[i]->Wait(kMaxWaitTimeMs));
}
for (size_t i = 0; i < kCount; i++) {
EXPECT_TRUE(executed[i].load());
}
}
TEST(SingleThreadedTaskQueueForTestingTest, PostToTaskQueueFromOwnThread) {
SingleThreadedTaskQueueForTesting task_queue("task_queue");
std::atomic<bool> executed(false);
rtc::Event done(true, false);
auto internally_posted_task = [&executed, &done]() {
executed.store(true);
done.Set();
};
auto externally_posted_task = [&task_queue, &internally_posted_task]() {
task_queue.PostTask(internally_posted_task);
};
task_queue.PostTask(externally_posted_task);
ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
EXPECT_TRUE(executed.load());
}
TEST(SingleThreadedTaskQueueForTestingTest, TasksExecutedInSequence) {
SingleThreadedTaskQueueForTesting task_queue("task_queue");
// The first task would perform:
// accumulator = 10 * accumulator + i
// Where |i| is 1, 2 and 3 for the 1st, 2nd and 3rd tasks, respectively.
// The result would be 123 if and only iff the tasks were executed in order.
size_t accumulator = 0;
size_t expected_value = 0; // Updates to the correct value.
// Prevent the chain from being set in motion before we've had time to
// schedule it all, lest the queue only contain one task at a time.
rtc::Event rendezvous(true, false);
task_queue.PostTask([&rendezvous]() {
ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs));
});
for (size_t i = 0; i < 3; i++) {
task_queue.PostTask([&accumulator, i]() { // |i| passed by value.
accumulator = 10 * accumulator + i;
});
expected_value = 10 * expected_value + i;
}
// The test will wait for the task-queue to finish.
rtc::Event done(true, false);
task_queue.PostTask([&done]() {
done.Set();
});
rendezvous.Set(); // Set the chain in motion.
ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
EXPECT_EQ(accumulator, expected_value);
}
TEST(SingleThreadedTaskQueueForTestingTest, ExecutesPostedDelayedTask) {
SingleThreadedTaskQueueForTesting task_queue("task_queue");
std::atomic<bool> executed(false);
rtc::Event done(true, false);
constexpr int64_t delay_ms = 20;
static_assert(delay_ms < kMaxWaitTimeMs / 2, "Delay too long for tests.");
task_queue.PostDelayedTask([&executed, &done]() {
executed.store(true);
done.Set();
}, delay_ms);
ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
EXPECT_TRUE(executed.load());
}
TEST(SingleThreadedTaskQueueForTestingTest, DoesNotExecuteDelayedTaskTooSoon) {
SingleThreadedTaskQueueForTesting task_queue("task_queue");
std::atomic<bool> executed(false);
constexpr int64_t delay_ms = 2000;
static_assert(delay_ms < kMaxWaitTimeMs / 2, "Delay too long for tests.");
task_queue.PostDelayedTask([&executed]() {
executed.store(true);
}, delay_ms);
// Wait less than is enough, make sure the task was not yet executed.
rtc::Event not_done(true, false);
ASSERT_FALSE(not_done.Wait(delay_ms / 2));
EXPECT_FALSE(executed.load());
}
TEST(SingleThreadedTaskQueueForTestingTest,
TaskWithLesserDelayPostedAfterFirstDelayedTaskExectuedBeforeFirst) {
SingleThreadedTaskQueueForTesting task_queue("task_queue");
std::atomic<bool> earlier_executed(false);
constexpr int64_t earlier_delay_ms = 500;
std::atomic<bool> later_executed(false);
constexpr int64_t later_delay_ms = 1000;
static_assert(earlier_delay_ms + later_delay_ms < kMaxWaitTimeMs / 2,
"Delay too long for tests.");
rtc::Event done(true, false);
auto earlier_task = [&earlier_executed, &later_executed]() {
EXPECT_FALSE(later_executed.load());
earlier_executed.store(true);
};
auto later_task = [&earlier_executed, &later_executed, &done]() {
EXPECT_TRUE(earlier_executed.load());
later_executed.store(true);
done.Set();
};
task_queue.PostDelayedTask(later_task, later_delay_ms);
task_queue.PostDelayedTask(earlier_task, earlier_delay_ms);
ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
ASSERT_TRUE(earlier_executed);
ASSERT_TRUE(later_executed);
}
TEST(SingleThreadedTaskQueueForTestingTest,
TaskWithGreaterDelayPostedAfterFirstDelayedTaskExectuedAfterFirst) {
SingleThreadedTaskQueueForTesting task_queue("task_queue");
std::atomic<bool> earlier_executed(false);
constexpr int64_t earlier_delay_ms = 500;
std::atomic<bool> later_executed(false);
constexpr int64_t later_delay_ms = 1000;
static_assert(earlier_delay_ms + later_delay_ms < kMaxWaitTimeMs / 2,
"Delay too long for tests.");
rtc::Event done(true, false);
auto earlier_task = [&earlier_executed, &later_executed]() {
EXPECT_FALSE(later_executed.load());
earlier_executed.store(true);
};
auto later_task = [&earlier_executed, &later_executed, &done]() {
EXPECT_TRUE(earlier_executed.load());
later_executed.store(true);
done.Set();
};
task_queue.PostDelayedTask(earlier_task, earlier_delay_ms);
task_queue.PostDelayedTask(later_task, later_delay_ms);
ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
ASSERT_TRUE(earlier_executed);
ASSERT_TRUE(later_executed);
}
TEST(SingleThreadedTaskQueueForTestingTest, ExternalThreadCancelsTask) {
SingleThreadedTaskQueueForTesting task_queue("task_queue");
rtc::Event done(true, false);
// Prevent the to-be-cancelled task from being executed before we've had
// time to cancel it.
rtc::Event rendezvous(true, false);
task_queue.PostTask([&rendezvous]() {
ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs));
});
TaskId cancelled_task_id = task_queue.PostTask([]() {
EXPECT_TRUE(false);
});
task_queue.PostTask([&done]() {
done.Set();
});
task_queue.CancelTask(cancelled_task_id);
// Set the tasks in motion; the cancelled task does not run (otherwise the
// test would fail). The last task ends the test, showing that the queue
// progressed beyond the cancelled task.
rendezvous.Set();
ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
}
// In this test, we'll set off a chain where the first task cancels the second
// task, then a third task runs (showing that we really cancelled the task,
// rather than just halted the task-queue).
TEST(SingleThreadedTaskQueueForTestingTest, InternalThreadCancelsTask) {
SingleThreadedTaskQueueForTesting task_queue("task_queue");
rtc::Event done(true, false);
// Prevent the chain from being set-off before we've set everything up.
rtc::Event rendezvous(true, false);
task_queue.PostTask([&rendezvous]() {
ASSERT_TRUE(rendezvous.Wait(kMaxWaitTimeMs));
});
// This is the canceller-task. It takes cancelled_task_id by reference,
// because the ID will only become known after the cancelled task is
// scheduled.
TaskId cancelled_task_id;
auto canceller_task = [&task_queue, &cancelled_task_id]() {
task_queue.CancelTask(cancelled_task_id);
};
task_queue.PostTask(canceller_task);
// This task will be cancelled by the task before it.
auto cancelled_task = []() {
EXPECT_TRUE(false);
};
cancelled_task_id = task_queue.PostTask(cancelled_task);
// When this task runs, it will allow the test to be finished.
auto completion_marker_task = [&done]() {
done.Set();
};
task_queue.PostTask(completion_marker_task);
rendezvous.Set(); // Set the chain in motion.
ASSERT_TRUE(done.Wait(kMaxWaitTimeMs));
}
TEST(SingleThreadedTaskQueueForTestingTest, SendTask) {
SingleThreadedTaskQueueForTesting task_queue("task_queue");
std::atomic<bool> executed(false);
task_queue.SendTask([&executed]() {
// Intentionally delay, so that if SendTask didn't block, the sender thread
// would have time to read |executed|.
rtc::Event delay(true, false);
ASSERT_FALSE(delay.Wait(1000));
executed.store(true);
});
EXPECT_TRUE(executed);
}
TEST(SingleThreadedTaskQueueForTestingTest,
DestructTaskQueueWhileTasksPending) {
auto task_queue =
rtc::MakeUnique<SingleThreadedTaskQueueForTesting>("task_queue");
std::atomic<size_t> counter(0);
constexpr size_t tasks = 10;
for (size_t i = 0; i < tasks; i++) {
task_queue->PostTask([&counter]() {
std::atomic_fetch_add(&counter, static_cast<size_t>(1));
rtc::Event delay(true, false);
ASSERT_FALSE(delay.Wait(500));
});
}
task_queue.reset();
EXPECT_LT(counter, tasks);
}
} // namespace
} // namespace test
} // namespace webrtc

File diff suppressed because it is too large Load Diff

View File

@ -139,6 +139,14 @@ class PictureIdTest : public test::CallTest {
virtual ~PictureIdTest() {
EXPECT_EQ(nullptr, video_send_stream_);
EXPECT_TRUE(video_receive_streams_.empty());
task_queue_.SendTask([this]() {
Stop();
DestroyStreams();
send_transport_.reset();
receive_transport_.reset();
DestroyCalls();
});
}
void SetupEncoder(VideoEncoder* encoder);
@ -196,28 +204,34 @@ class VideoStreamFactory
};
void PictureIdTest::SetupEncoder(VideoEncoder* encoder) {
Call::Config config(event_log_.get());
CreateCalls(config, config);
task_queue_.SendTask([this, &encoder]() {
Call::Config config(event_log_.get());
CreateCalls(config, config);
send_transport_.reset(new test::PacketTransport(
sender_call_.get(), &observer, test::PacketTransport::kSender,
payload_type_map_, FakeNetworkPipe::Config()));
send_transport_.reset(new test::PacketTransport(
&task_queue_, sender_call_.get(), &observer,
test::PacketTransport::kSender, payload_type_map_,
FakeNetworkPipe::Config()));
CreateSendConfig(kNumSsrcs, 0, 0, send_transport_.get());
video_send_config_.encoder_settings.encoder = encoder;
video_send_config_.encoder_settings.payload_name = "VP8";
video_encoder_config_.video_stream_factory =
new rtc::RefCountedObject<VideoStreamFactory>();
video_encoder_config_.number_of_streams = 1;
CreateSendConfig(kNumSsrcs, 0, 0, send_transport_.get());
video_send_config_.encoder_settings.encoder = encoder;
video_send_config_.encoder_settings.payload_name = "VP8";
video_encoder_config_.video_stream_factory =
new rtc::RefCountedObject<VideoStreamFactory>();
video_encoder_config_.number_of_streams = 1;
});
}
void PictureIdTest::TestPictureIdContinuousAfterReconfigure(
const std::vector<int>& ssrc_counts) {
CreateVideoStreams();
CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
task_queue_.SendTask([this]() {
CreateVideoStreams();
CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
// Initial test with a single stream.
Start();
});
// Initial test with a single stream.
Start();
EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
// Reconfigure VideoEncoder and test picture id increase.
@ -228,21 +242,31 @@ void PictureIdTest::TestPictureIdContinuousAfterReconfigure(
observer.SetExpectedSsrcs(ssrc_count);
observer.ResetObservedSsrcs();
// Make sure the picture_id sequence is continuous on reinit and recreate.
video_send_stream_->ReconfigureVideoEncoder(video_encoder_config_.Copy());
task_queue_.SendTask([this]() {
video_send_stream_->ReconfigureVideoEncoder(video_encoder_config_.Copy());
});
EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
}
Stop();
DestroyStreams();
task_queue_.SendTask([this]() {
Stop();
DestroyStreams();
send_transport_.reset();
receive_transport_.reset();
DestroyCalls();
});
}
void PictureIdTest::TestPictureIdIncreaseAfterRecreateStreams(
const std::vector<int>& ssrc_counts) {
CreateVideoStreams();
CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
task_queue_.SendTask([this]() {
CreateVideoStreams();
CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
// Initial test with a single stream.
Start();
});
// Initial test with a single stream.
Start();
EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
// Recreate VideoSendStream and test picture id increase.
@ -250,24 +274,31 @@ void PictureIdTest::TestPictureIdIncreaseAfterRecreateStreams(
// with it, therefore it is expected that some frames might be lost.
observer.SetMaxExpectedPictureIdGap(kMaxFramesLost);
for (int ssrc_count : ssrc_counts) {
video_encoder_config_.number_of_streams = ssrc_count;
task_queue_.SendTask([this, &ssrc_count]() {
video_encoder_config_.number_of_streams = ssrc_count;
frame_generator_capturer_->Stop();
sender_call_->DestroyVideoSendStream(video_send_stream_);
frame_generator_capturer_->Stop();
sender_call_->DestroyVideoSendStream(video_send_stream_);
observer.SetExpectedSsrcs(ssrc_count);
observer.ResetObservedSsrcs();
observer.SetExpectedSsrcs(ssrc_count);
observer.ResetObservedSsrcs();
video_send_stream_ = sender_call_->CreateVideoSendStream(
video_send_config_.Copy(), video_encoder_config_.Copy());
video_send_stream_->Start();
CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
frame_generator_capturer_->Start();
});
video_send_stream_ = sender_call_->CreateVideoSendStream(
video_send_config_.Copy(), video_encoder_config_.Copy());
video_send_stream_->Start();
CreateFrameGeneratorCapturer(kFrameRate, kFrameMaxWidth, kFrameMaxHeight);
frame_generator_capturer_->Start();
EXPECT_TRUE(observer.Wait()) << "Timed out waiting for packets.";
}
Stop();
DestroyStreams();
task_queue_.SendTask([this]() {
Stop();
DestroyStreams();
send_transport_.reset();
receive_transport_.reset();
});
}
TEST_F(PictureIdTest, PictureIdContinuousAfterReconfigureVp8) {

View File

@ -37,6 +37,7 @@
#include "webrtc/rtc_base/memory_usage.h"
#include "webrtc/rtc_base/optional.h"
#include "webrtc/rtc_base/platform_file.h"
#include "webrtc/rtc_base/ptr_util.h"
#include "webrtc/rtc_base/timeutils.h"
#include "webrtc/system_wrappers/include/cpu_info.h"
#include "webrtc/system_wrappers/include/field_trial.h"
@ -1651,6 +1652,10 @@ void VideoQualityTest::DestroyThumbnailStreams() {
sender_call_->DestroyVideoReceiveStream(thumbnail_receive_stream);
thumbnail_send_streams_.clear();
thumbnail_receive_streams_.clear();
for (std::unique_ptr<test::VideoCapturer>& video_caputurer :
thumbnail_capturers_) {
video_caputurer.reset();
}
}
void VideoQualityTest::SetupScreenshareOrSVC() {
@ -1769,6 +1774,11 @@ void VideoQualityTest::CreateCapturer() {
}
void VideoQualityTest::RunWithAnalyzer(const Params& params) {
std::unique_ptr<test::LayerFilteringTransport> send_transport;
std::unique_ptr<test::DirectTransport> recv_transport;
FILE* graph_data_output_file = nullptr;
std::unique_ptr<VideoAnalyzer> analyzer;
params_ = params;
RTC_CHECK(!params_.audio.enabled);
@ -1776,7 +1786,6 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) {
// differentiate between the analyzer and the renderer case.
CheckParams();
FILE* graph_data_output_file = nullptr;
if (!params_.analyzer.graph_data_output_filename.empty()) {
graph_data_output_file =
fopen(params_.analyzer.graph_data_output_filename.c_str(), "w");
@ -1794,22 +1803,26 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) {
Call::Config call_config(event_log_.get());
call_config.bitrate_config = params.call.call_bitrate_config;
CreateCalls(call_config, call_config);
test::LayerFilteringTransport send_transport(
params_.pipe, sender_call_.get(), kPayloadTypeVP8, kPayloadTypeVP9,
params_.video.selected_tl, params_.ss.selected_sl, payload_type_map_);
task_queue_.SendTask([this, &call_config, &send_transport,
&recv_transport]() {
CreateCalls(call_config, call_config);
test::DirectTransport recv_transport(params_.pipe, receiver_call_.get(),
payload_type_map_);
send_transport = rtc::MakeUnique<test::LayerFilteringTransport>(
&task_queue_, params_.pipe, sender_call_.get(), kPayloadTypeVP8,
kPayloadTypeVP9, params_.video.selected_tl, params_.ss.selected_sl,
payload_type_map_);
recv_transport = rtc::MakeUnique<test::DirectTransport>(
&task_queue_, params_.pipe, receiver_call_.get(), payload_type_map_);
});
std::string graph_title = params_.analyzer.graph_title;
if (graph_title.empty())
graph_title = VideoQualityTest::GenerateGraphTitle();
bool is_quick_test_enabled = field_trial::IsEnabled("WebRTC-QuickPerfTest");
VideoAnalyzer analyzer(
&send_transport, params_.analyzer.test_label,
analyzer = rtc::MakeUnique<VideoAnalyzer>(
send_transport.get(), params_.analyzer.test_label,
params_.analyzer.avg_psnr_threshold, params_.analyzer.avg_ssim_threshold,
is_quick_test_enabled
? kFramesSentInQuickTest
@ -1820,82 +1833,91 @@ void VideoQualityTest::RunWithAnalyzer(const Params& params) {
static_cast<size_t>(params_.ss.selected_stream), params.ss.selected_sl,
params_.video.selected_tl, is_quick_test_enabled, clock_,
params_.logging.rtp_dump_name);
analyzer.SetCall(sender_call_.get());
analyzer.SetReceiver(receiver_call_->Receiver());
send_transport.SetReceiver(&analyzer);
recv_transport.SetReceiver(sender_call_->Receiver());
SetupVideo(&analyzer, &recv_transport);
SetupThumbnails(&analyzer, &recv_transport);
video_receive_configs_[params_.ss.selected_stream].renderer = &analyzer;
video_send_config_.pre_encode_callback = analyzer.pre_encode_proxy();
RTC_DCHECK(!video_send_config_.post_encode_callback);
video_send_config_.post_encode_callback = analyzer.encode_timing_proxy();
task_queue_.SendTask([&]() {
analyzer->SetCall(sender_call_.get());
analyzer->SetReceiver(receiver_call_->Receiver());
send_transport->SetReceiver(analyzer.get());
recv_transport->SetReceiver(sender_call_->Receiver());
SetupScreenshareOrSVC();
SetupVideo(analyzer.get(), recv_transport.get());
SetupThumbnails(analyzer.get(), recv_transport.get());
video_receive_configs_[params_.ss.selected_stream].renderer =
analyzer.get();
video_send_config_.pre_encode_callback = analyzer->pre_encode_proxy();
RTC_DCHECK(!video_send_config_.post_encode_callback);
video_send_config_.post_encode_callback = analyzer->encode_timing_proxy();
CreateFlexfecStreams();
CreateVideoStreams();
analyzer.SetSendStream(video_send_stream_);
if (video_receive_streams_.size() == 1)
analyzer.SetReceiveStream(video_receive_streams_[0]);
SetupScreenshareOrSVC();
video_send_stream_->SetSource(analyzer.OutputInterface(),
degradation_preference_);
CreateFlexfecStreams();
CreateVideoStreams();
analyzer->SetSendStream(video_send_stream_);
if (video_receive_streams_.size() == 1)
analyzer->SetReceiveStream(video_receive_streams_[0]);
SetupThumbnailCapturers(params_.call.num_thumbnails);
for (size_t i = 0; i < thumbnail_send_streams_.size(); ++i) {
thumbnail_send_streams_[i]->SetSource(thumbnail_capturers_[i].get(),
degradation_preference_);
}
video_send_stream_->SetSource(analyzer->OutputInterface(),
degradation_preference_);
CreateCapturer();
SetupThumbnailCapturers(params_.call.num_thumbnails);
for (size_t i = 0; i < thumbnail_send_streams_.size(); ++i) {
thumbnail_send_streams_[i]->SetSource(thumbnail_capturers_[i].get(),
degradation_preference_);
}
analyzer.SetSource(video_capturer_.get(), params_.ss.infer_streams);
CreateCapturer();
StartEncodedFrameLogs(video_send_stream_);
StartEncodedFrameLogs(video_receive_streams_[params_.ss.selected_stream]);
video_send_stream_->Start();
for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_)
thumbnail_send_stream->Start();
for (VideoReceiveStream* receive_stream : video_receive_streams_)
receive_stream->Start();
for (VideoReceiveStream* thumbnail_receive_stream :
thumbnail_receive_streams_)
thumbnail_receive_stream->Start();
analyzer->SetSource(video_capturer_.get(), params_.ss.infer_streams);
analyzer.StartMeasuringCpuProcessTime();
StartEncodedFrameLogs(video_send_stream_);
StartEncodedFrameLogs(video_receive_streams_[params_.ss.selected_stream]);
video_send_stream_->Start();
for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_)
thumbnail_send_stream->Start();
for (VideoReceiveStream* receive_stream : video_receive_streams_)
receive_stream->Start();
for (VideoReceiveStream* thumbnail_receive_stream :
thumbnail_receive_streams_)
thumbnail_receive_stream->Start();
video_capturer_->Start();
for (std::unique_ptr<test::VideoCapturer>& video_caputurer :
thumbnail_capturers_) {
video_caputurer->Start();
}
analyzer->StartMeasuringCpuProcessTime();
analyzer.Wait();
video_capturer_->Start();
for (std::unique_ptr<test::VideoCapturer>& video_caputurer :
thumbnail_capturers_) {
video_caputurer->Start();
}
});
send_transport.StopSending();
recv_transport.StopSending();
analyzer->Wait();
for (std::unique_ptr<test::VideoCapturer>& video_caputurer :
thumbnail_capturers_)
video_caputurer->Stop();
video_capturer_->Stop();
for (VideoReceiveStream* thumbnail_receive_stream :
thumbnail_receive_streams_)
thumbnail_receive_stream->Stop();
for (VideoReceiveStream* receive_stream : video_receive_streams_)
receive_stream->Stop();
for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_)
thumbnail_send_stream->Stop();
video_send_stream_->Stop();
task_queue_.SendTask([&]() {
for (std::unique_ptr<test::VideoCapturer>& video_caputurer :
thumbnail_capturers_)
video_caputurer->Stop();
video_capturer_->Stop();
for (VideoReceiveStream* thumbnail_receive_stream :
thumbnail_receive_streams_)
thumbnail_receive_stream->Stop();
for (VideoReceiveStream* receive_stream : video_receive_streams_)
receive_stream->Stop();
for (VideoSendStream* thumbnail_send_stream : thumbnail_send_streams_)
thumbnail_send_stream->Stop();
video_send_stream_->Stop();
DestroyStreams();
DestroyThumbnailStreams();
DestroyStreams();
DestroyThumbnailStreams();
event_log_->StopLogging();
if (graph_data_output_file)
fclose(graph_data_output_file);
event_log_->StopLogging();
if (graph_data_output_file)
fclose(graph_data_output_file);
video_capturer_.reset();
send_transport.reset();
recv_transport.reset();
DestroyCalls();
});
}
void VideoQualityTest::SetupAudio(int send_channel_id,
@ -1942,162 +1964,177 @@ void VideoQualityTest::SetupAudio(int send_channel_id,
}
void VideoQualityTest::RunWithRenderers(const Params& params) {
params_ = params;
CheckParams();
// TODO(ivica): Remove bitrate_config and use the default Call::Config(), to
// match the full stack tests.
Call::Config call_config(event_log_.get());
call_config.bitrate_config = params_.call.call_bitrate_config;
std::unique_ptr<test::LayerFilteringTransport> send_transport;
std::unique_ptr<test::DirectTransport> recv_transport;
::VoiceEngineState voe;
rtc::scoped_refptr<webrtc::AudioProcessing> audio_processing(
webrtc::AudioProcessing::Create());
if (params_.audio.enabled) {
CreateVoiceEngine(&voe, audio_processing.get(), decoder_factory_);
AudioState::Config audio_state_config;
audio_state_config.voice_engine = voe.voice_engine;
audio_state_config.audio_mixer = AudioMixerImpl::Create();
audio_state_config.audio_processing = audio_processing;
call_config.audio_state = AudioState::Create(audio_state_config);
}
CreateCalls(call_config, call_config);
// TODO(minyue): consider if this is a good transport even for audio only
// calls.
test::LayerFilteringTransport send_transport(
params.pipe, sender_call_.get(), kPayloadTypeVP8, kPayloadTypeVP9,
params.video.selected_tl, params_.ss.selected_sl, payload_type_map_);
test::DirectTransport recv_transport(params_.pipe, receiver_call_.get(),
payload_type_map_);
// TODO(ivica): Use two calls to be able to merge with RunWithAnalyzer or at
// least share as much code as possible. That way this test would also match
// the full stack tests better.
send_transport.SetReceiver(receiver_call_->Receiver());
recv_transport.SetReceiver(sender_call_->Receiver());
std::unique_ptr<test::VideoRenderer> local_preview;
std::vector<std::unique_ptr<test::VideoRenderer>> loopback_renderers_;
if (params_.video.enabled) {
// Create video renderers.
local_preview.reset(test::VideoRenderer::Create(
"Local Preview", params_.video.width, params_.video.height));
const size_t selected_stream_id = params_.ss.selected_stream;
const size_t num_streams = params_.ss.streams.size();
if (selected_stream_id == num_streams) {
for (size_t stream_id = 0; stream_id < num_streams; ++stream_id) {
std::ostringstream oss;
oss << "Loopback Video - Stream #" << static_cast<int>(stream_id);
loopback_renderers_.emplace_back(test::VideoRenderer::Create(
oss.str().c_str(), params_.ss.streams[stream_id].width,
params_.ss.streams[stream_id].height));
}
} else {
loopback_renderers_.emplace_back(test::VideoRenderer::Create(
"Loopback Video", params_.ss.streams[selected_stream_id].width,
params_.ss.streams[selected_stream_id].height));
}
SetupVideo(&send_transport, &recv_transport);
video_send_config_.pre_encode_callback = local_preview.get();
if (selected_stream_id == num_streams) {
for (size_t stream_id = 0; stream_id < num_streams; ++stream_id) {
video_receive_configs_[stream_id].renderer =
loopback_renderers_[stream_id].get();
if (params_.audio.enabled && params_.audio.sync_video)
video_receive_configs_[stream_id].sync_group = kSyncGroup;
}
} else {
video_receive_configs_[selected_stream_id].renderer =
loopback_renderers_.back().get();
if (params_.audio.enabled && params_.audio.sync_video)
video_receive_configs_[selected_stream_id].sync_group = kSyncGroup;
}
if (params_.screenshare.enabled)
SetupScreenshareOrSVC();
CreateFlexfecStreams();
CreateVideoStreams();
CreateCapturer();
video_send_stream_->SetSource(video_capturer_.get(),
degradation_preference_);
}
std::vector<std::unique_ptr<test::VideoRenderer>> loopback_renderers;
AudioReceiveStream* audio_receive_stream = nullptr;
if (params_.audio.enabled) {
SetupAudio(voe.send_channel_id, voe.receive_channel_id, &send_transport,
&audio_receive_stream);
}
for (VideoReceiveStream* receive_stream : video_receive_streams_)
StartEncodedFrameLogs(receive_stream);
StartEncodedFrameLogs(video_send_stream_);
task_queue_.SendTask([&]() {
params_ = params;
CheckParams();
// Start sending and receiving video.
if (params_.video.enabled) {
for (VideoReceiveStream* video_receive_stream : video_receive_streams_)
video_receive_stream->Start();
// TODO(ivica): Remove bitrate_config and use the default Call::Config(), to
// match the full stack tests.
Call::Config call_config(event_log_.get());
call_config.bitrate_config = params_.call.call_bitrate_config;
video_send_stream_->Start();
video_capturer_->Start();
}
rtc::scoped_refptr<webrtc::AudioProcessing> audio_processing(
webrtc::AudioProcessing::Create());
if (params_.audio.enabled) {
// Start receiving audio.
audio_receive_stream->Start();
EXPECT_EQ(0, voe.base->StartPlayout(voe.receive_channel_id));
if (params_.audio.enabled) {
CreateVoiceEngine(&voe, audio_processing.get(), decoder_factory_);
AudioState::Config audio_state_config;
audio_state_config.voice_engine = voe.voice_engine;
audio_state_config.audio_mixer = AudioMixerImpl::Create();
audio_state_config.audio_processing = audio_processing;
call_config.audio_state = AudioState::Create(audio_state_config);
}
// Start sending audio.
audio_send_stream_->Start();
EXPECT_EQ(0, voe.base->StartSend(voe.send_channel_id));
}
CreateCalls(call_config, call_config);
// TODO(minyue): consider if this is a good transport even for audio only
// calls.
send_transport = rtc::MakeUnique<test::LayerFilteringTransport>(
&task_queue_, params.pipe, sender_call_.get(), kPayloadTypeVP8,
kPayloadTypeVP9, params.video.selected_tl, params_.ss.selected_sl,
payload_type_map_);
recv_transport = rtc::MakeUnique<test::DirectTransport>(
&task_queue_, params_.pipe, receiver_call_.get(), payload_type_map_);
// TODO(ivica): Use two calls to be able to merge with RunWithAnalyzer or at
// least share as much code as possible. That way this test would also match
// the full stack tests better.
send_transport->SetReceiver(receiver_call_->Receiver());
recv_transport->SetReceiver(sender_call_->Receiver());
if (params_.video.enabled) {
// Create video renderers.
local_preview.reset(test::VideoRenderer::Create(
"Local Preview", params_.video.width, params_.video.height));
const size_t selected_stream_id = params_.ss.selected_stream;
const size_t num_streams = params_.ss.streams.size();
if (selected_stream_id == num_streams) {
for (size_t stream_id = 0; stream_id < num_streams; ++stream_id) {
std::ostringstream oss;
oss << "Loopback Video - Stream #" << static_cast<int>(stream_id);
loopback_renderers.emplace_back(test::VideoRenderer::Create(
oss.str().c_str(), params_.ss.streams[stream_id].width,
params_.ss.streams[stream_id].height));
}
} else {
loopback_renderers.emplace_back(test::VideoRenderer::Create(
"Loopback Video", params_.ss.streams[selected_stream_id].width,
params_.ss.streams[selected_stream_id].height));
}
SetupVideo(send_transport.get(), recv_transport.get());
video_send_config_.pre_encode_callback = local_preview.get();
if (selected_stream_id == num_streams) {
for (size_t stream_id = 0; stream_id < num_streams; ++stream_id) {
video_receive_configs_[stream_id].renderer =
loopback_renderers[stream_id].get();
if (params_.audio.enabled && params_.audio.sync_video)
video_receive_configs_[stream_id].sync_group = kSyncGroup;
}
} else {
video_receive_configs_[selected_stream_id].renderer =
loopback_renderers.back().get();
if (params_.audio.enabled && params_.audio.sync_video)
video_receive_configs_[selected_stream_id].sync_group = kSyncGroup;
}
if (params_.screenshare.enabled)
SetupScreenshareOrSVC();
CreateFlexfecStreams();
CreateVideoStreams();
CreateCapturer();
video_send_stream_->SetSource(video_capturer_.get(),
degradation_preference_);
}
if (params_.audio.enabled) {
SetupAudio(voe.send_channel_id, voe.receive_channel_id,
send_transport.get(), &audio_receive_stream);
}
for (VideoReceiveStream* receive_stream : video_receive_streams_)
StartEncodedFrameLogs(receive_stream);
StartEncodedFrameLogs(video_send_stream_);
// Start sending and receiving video.
if (params_.video.enabled) {
for (VideoReceiveStream* video_receive_stream : video_receive_streams_)
video_receive_stream->Start();
video_send_stream_->Start();
video_capturer_->Start();
}
if (params_.audio.enabled) {
// Start receiving audio.
audio_receive_stream->Start();
EXPECT_EQ(0, voe.base->StartPlayout(voe.receive_channel_id));
// Start sending audio.
audio_send_stream_->Start();
EXPECT_EQ(0, voe.base->StartSend(voe.send_channel_id));
}
});
test::PressEnterToContinue();
if (params_.audio.enabled) {
// Stop sending audio.
EXPECT_EQ(0, voe.base->StopSend(voe.send_channel_id));
audio_send_stream_->Stop();
task_queue_.SendTask([&]() {
if (params_.audio.enabled) {
// Stop sending audio.
EXPECT_EQ(0, voe.base->StopSend(voe.send_channel_id));
audio_send_stream_->Stop();
// Stop receiving audio.
EXPECT_EQ(0, voe.base->StopPlayout(voe.receive_channel_id));
audio_receive_stream->Stop();
sender_call_->DestroyAudioSendStream(audio_send_stream_);
receiver_call_->DestroyAudioReceiveStream(audio_receive_stream);
}
// Stop receiving audio.
EXPECT_EQ(0, voe.base->StopPlayout(voe.receive_channel_id));
audio_receive_stream->Stop();
sender_call_->DestroyAudioSendStream(audio_send_stream_);
receiver_call_->DestroyAudioReceiveStream(audio_receive_stream);
}
// Stop receiving and sending video.
if (params_.video.enabled) {
video_capturer_->Stop();
video_send_stream_->Stop();
for (FlexfecReceiveStream* flexfec_receive_stream :
flexfec_receive_streams_) {
for (VideoReceiveStream* video_receive_stream : video_receive_streams_) {
video_receive_stream->RemoveSecondarySink(flexfec_receive_stream);
// Stop receiving and sending video.
if (params_.video.enabled) {
video_capturer_->Stop();
video_send_stream_->Stop();
for (FlexfecReceiveStream* flexfec_receive_stream :
flexfec_receive_streams_) {
for (VideoReceiveStream* video_receive_stream :
video_receive_streams_) {
video_receive_stream->RemoveSecondarySink(flexfec_receive_stream);
}
receiver_call_->DestroyFlexfecReceiveStream(flexfec_receive_stream);
}
receiver_call_->DestroyFlexfecReceiveStream(flexfec_receive_stream);
for (VideoReceiveStream* receive_stream : video_receive_streams_) {
receive_stream->Stop();
receiver_call_->DestroyVideoReceiveStream(receive_stream);
}
sender_call_->DestroyVideoSendStream(video_send_stream_);
}
for (VideoReceiveStream* receive_stream : video_receive_streams_) {
receive_stream->Stop();
receiver_call_->DestroyVideoReceiveStream(receive_stream);
}
sender_call_->DestroyVideoSendStream(video_send_stream_);
}
send_transport.StopSending();
recv_transport.StopSending();
video_capturer_.reset();
send_transport.reset();
recv_transport.reset();
if (params_.audio.enabled)
DestroyVoiceEngine(&voe);
if (params_.audio.enabled)
DestroyVoiceEngine(&voe);
local_preview.reset();
loopback_renderers.clear();
DestroyCalls();
});
}
void VideoQualityTest::StartEncodedFrameLogs(VideoSendStream* stream) {

View File

@ -67,25 +67,31 @@ class VideoSendStreamTest : public test::CallTest {
};
TEST_F(VideoSendStreamTest, CanStartStartedStream) {
CreateSenderCall(Call::Config(event_log_.get()));
task_queue_.SendTask([this]() {
CreateSenderCall(Call::Config(event_log_.get()));
test::NullTransport transport;
CreateSendConfig(1, 0, 0, &transport);
CreateVideoStreams();
video_send_stream_->Start();
video_send_stream_->Start();
DestroyStreams();
test::NullTransport transport;
CreateSendConfig(1, 0, 0, &transport);
CreateVideoStreams();
video_send_stream_->Start();
video_send_stream_->Start();
DestroyStreams();
DestroyCalls();
});
}
TEST_F(VideoSendStreamTest, CanStopStoppedStream) {
CreateSenderCall(Call::Config(event_log_.get()));
task_queue_.SendTask([this]() {
CreateSenderCall(Call::Config(event_log_.get()));
test::NullTransport transport;
CreateSendConfig(1, 0, 0, &transport);
CreateVideoStreams();
video_send_stream_->Stop();
video_send_stream_->Stop();
DestroyStreams();
test::NullTransport transport;
CreateSendConfig(1, 0, 0, &transport);
CreateVideoStreams();
video_send_stream_->Stop();
video_send_stream_->Stop();
DestroyStreams();
DestroyCalls();
});
}
TEST_F(VideoSendStreamTest, SupportsCName) {
@ -480,7 +486,9 @@ class UlpfecObserver : public test::EndToEndTest {
return SEND_PACKET;
}
test::PacketTransport* CreateSendTransport(Call* sender_call) override {
test::PacketTransport* CreateSendTransport(
test::SingleThreadedTaskQueueForTesting* task_queue,
Call* sender_call) override {
// At low RTT (< kLowRttNackMs) -> NACK only, no FEC.
// Configure some network delay.
const int kNetworkDelayMs = 100;
@ -488,7 +496,7 @@ class UlpfecObserver : public test::EndToEndTest {
config.loss_percent = 5;
config.queue_delay_ms = kNetworkDelayMs;
return new test::PacketTransport(
sender_call, this, test::PacketTransport::kSender,
task_queue, sender_call, this, test::PacketTransport::kSender,
VideoSendStreamTest::payload_type_map_, config);
}
@ -636,7 +644,9 @@ class FlexfecObserver : public test::EndToEndTest {
return SEND_PACKET;
}
test::PacketTransport* CreateSendTransport(Call* sender_call) override {
test::PacketTransport* CreateSendTransport(
test::SingleThreadedTaskQueueForTesting* task_queue,
Call* sender_call) override {
// At low RTT (< kLowRttNackMs) -> NACK only, no FEC.
// Therefore we need some network delay.
const int kNetworkDelayMs = 100;
@ -644,7 +654,7 @@ class FlexfecObserver : public test::EndToEndTest {
config.loss_percent = 5;
config.queue_delay_ms = kNetworkDelayMs;
return new test::PacketTransport(
sender_call, this, test::PacketTransport::kSender,
task_queue, sender_call, this, test::PacketTransport::kSender,
VideoSendStreamTest::payload_type_map_, config);
}
@ -1337,13 +1347,15 @@ TEST_F(VideoSendStreamTest, PaddingIsPrimarilyRetransmissions) {
return SEND_PACKET;
}
test::PacketTransport* CreateSendTransport(Call* sender_call) override {
test::PacketTransport* CreateSendTransport(
test::SingleThreadedTaskQueueForTesting* task_queue,
Call* sender_call) override {
const int kNetworkDelayMs = 50;
FakeNetworkPipe::Config config;
config.loss_percent = 10;
config.link_capacity_kbps = kCapacityKbps;
config.queue_delay_ms = kNetworkDelayMs;
return new test::PacketTransport(sender_call, this,
return new test::PacketTransport(task_queue, sender_call, this,
test::PacketTransport::kSender,
payload_type_map_, config);
}
@ -1476,8 +1488,11 @@ TEST_F(VideoSendStreamTest, ChangingNetworkRoute) {
static const uint8_t kExtensionId = test::kTransportSequenceNumberExtensionId;
class ChangingNetworkRouteTest : public test::EndToEndTest {
public:
ChangingNetworkRouteTest()
: EndToEndTest(test::CallTest::kDefaultTimeoutMs), call_(nullptr) {
explicit ChangingNetworkRouteTest(
test::SingleThreadedTaskQueueForTesting* task_queue)
: EndToEndTest(test::CallTest::kDefaultTimeoutMs),
task_queue_(task_queue),
call_(nullptr) {
EXPECT_TRUE(parser_->RegisterRtpHeaderExtension(
kRtpExtensionTransportSequenceNumber, kExtensionId));
}
@ -1518,26 +1533,33 @@ TEST_F(VideoSendStreamTest, ChangingNetworkRoute) {
void PerformTest() override {
rtc::NetworkRoute new_route(true, 10, 20, -1);
call_->OnNetworkRouteChanged("transport", new_route);
Call::Config::BitrateConfig bitrate_config;
bitrate_config.start_bitrate_bps = kStartBitrateBps;
call_->SetBitrateConfig(bitrate_config);
task_queue_->SendTask([this, &new_route, &bitrate_config]() {
call_->OnNetworkRouteChanged("transport", new_route);
bitrate_config.start_bitrate_bps = kStartBitrateBps;
call_->SetBitrateConfig(bitrate_config);
});
EXPECT_TRUE(Wait())
<< "Timed out while waiting for start bitrate to be exceeded.";
bitrate_config.start_bitrate_bps = -1;
bitrate_config.max_bitrate_bps = kNewMaxBitrateBps;
call_->SetBitrateConfig(bitrate_config);
// TODO(holmer): We should set the last sent packet id here and verify
// that we correctly ignore any packet loss reported prior to that id.
++new_route.local_network_id;
call_->OnNetworkRouteChanged("transport", new_route);
EXPECT_GE(call_->GetStats().send_bandwidth_bps, kStartBitrateBps);
task_queue_->SendTask([this, &new_route, &bitrate_config]() {
bitrate_config.start_bitrate_bps = -1;
bitrate_config.max_bitrate_bps = kNewMaxBitrateBps;
call_->SetBitrateConfig(bitrate_config);
// TODO(holmer): We should set the last sent packet id here and verify
// that we correctly ignore any packet loss reported prior to that id.
++new_route.local_network_id;
call_->OnNetworkRouteChanged("transport", new_route);
EXPECT_GE(call_->GetStats().send_bandwidth_bps, kStartBitrateBps);
});
}
private:
test::SingleThreadedTaskQueueForTesting* const task_queue_;
Call* call_;
} test;
} test(&task_queue_);
RunBaseTest(&test);
}
@ -1545,8 +1567,10 @@ TEST_F(VideoSendStreamTest, ChangingNetworkRoute) {
TEST_F(VideoSendStreamTest, ChangingTransportOverhead) {
class ChangingTransportOverheadTest : public test::EndToEndTest {
public:
ChangingTransportOverheadTest()
explicit ChangingTransportOverheadTest(
test::SingleThreadedTaskQueueForTesting* task_queue)
: EndToEndTest(test::CallTest::kDefaultTimeoutMs),
task_queue_(task_queue),
call_(nullptr),
packets_sent_(0),
transport_overhead_(0) {}
@ -1572,27 +1596,36 @@ TEST_F(VideoSendStreamTest, ChangingTransportOverhead) {
}
void PerformTest() override {
transport_overhead_ = 100;
call_->OnTransportOverheadChanged(webrtc::MediaType::VIDEO,
transport_overhead_);
task_queue_->SendTask([this]() {
transport_overhead_ = 100;
call_->OnTransportOverheadChanged(webrtc::MediaType::VIDEO,
transport_overhead_);
});
EXPECT_TRUE(Wait());
{
rtc::CritScope cs(&lock_);
packets_sent_ = 0;
}
transport_overhead_ = 500;
call_->OnTransportOverheadChanged(webrtc::MediaType::VIDEO,
transport_overhead_);
task_queue_->SendTask([this]() {
transport_overhead_ = 500;
call_->OnTransportOverheadChanged(webrtc::MediaType::VIDEO,
transport_overhead_);
});
EXPECT_TRUE(Wait());
}
private:
test::SingleThreadedTaskQueueForTesting* const task_queue_;
Call* call_;
rtc::CriticalSection lock_;
int packets_sent_ GUARDED_BY(lock_);
int transport_overhead_;
const size_t kMaxRtpPacketSize = 1000;
} test;
} test(&task_queue_);
RunBaseTest(&test);
}
@ -1716,16 +1749,18 @@ TEST_F(VideoSendStreamTest, RespectsMinTransmitBitrateAfterContentSwitch) {
// Function for removing and recreating the send stream with a new config.
auto reset_fun = [this](const VideoSendStream::Config& send_stream_config,
const VideoEncoderConfig& encoder_config) {
Stop();
sender_call_->DestroyVideoSendStream(video_send_stream_);
video_send_config_ = send_stream_config.Copy();
video_encoder_config_ = encoder_config.Copy();
video_send_stream_ = sender_call_->CreateVideoSendStream(
video_send_config_.Copy(), video_encoder_config_.Copy());
video_send_stream_->SetSource(
frame_generator_capturer_.get(),
VideoSendStream::DegradationPreference::kMaintainResolution);
Start();
task_queue_.SendTask([this, &send_stream_config, &encoder_config]() {
Stop();
sender_call_->DestroyVideoSendStream(video_send_stream_);
video_send_config_ = send_stream_config.Copy();
video_encoder_config_ = encoder_config.Copy();
video_send_stream_ = sender_call_->CreateVideoSendStream(
video_send_config_.Copy(), video_encoder_config_.Copy());
video_send_stream_->SetSource(
frame_generator_capturer_.get(),
VideoSendStream::DegradationPreference::kMaintainResolution);
Start();
});
};
MaxPaddingSetTest<decltype(reset_fun)> test(true, &reset_fun);
RunBaseTest(&test);
@ -1791,21 +1826,32 @@ TEST_F(VideoSendStreamTest,
int last_initialized_frame_height_ GUARDED_BY(&crit_);
};
CreateSenderCall(Call::Config(event_log_.get()));
test::NullTransport transport;
CreateSendConfig(1, 0, 0, &transport);
EncoderObserver encoder;
video_send_config_.encoder_settings.encoder = &encoder;
CreateVideoStreams();
CreateFrameGeneratorCapturer(kDefaultFramerate, kDefaultWidth,
kDefaultHeight);
frame_generator_capturer_->Start();
task_queue_.SendTask([this, &transport, &encoder]() {
CreateSenderCall(Call::Config(event_log_.get()));
CreateSendConfig(1, 0, 0, &transport);
video_send_config_.encoder_settings.encoder = &encoder;
CreateVideoStreams();
CreateFrameGeneratorCapturer(kDefaultFramerate, kDefaultWidth,
kDefaultHeight);
frame_generator_capturer_->Start();
});
encoder.WaitForResolution(kDefaultWidth, kDefaultHeight);
frame_generator_capturer_->ChangeResolution(kDefaultWidth * 2,
kDefaultHeight * 2);
task_queue_.SendTask([this]() {
frame_generator_capturer_->ChangeResolution(kDefaultWidth * 2,
kDefaultHeight * 2);
});
encoder.WaitForResolution(kDefaultWidth * 2, kDefaultHeight * 2);
DestroyStreams();
task_queue_.SendTask([this]() {
DestroyStreams();
DestroyCalls();
});
}
TEST_F(VideoSendStreamTest, CanReconfigureToUseStartBitrateAbovePreviousMax) {
@ -1937,31 +1983,42 @@ TEST_F(VideoSendStreamTest, VideoSendStreamStopSetEncoderRateToZero) {
rtc::Optional<int> bitrate_kbps_ GUARDED_BY(crit_);
};
CreateSenderCall(Call::Config(event_log_.get()));
test::NullTransport transport;
CreateSendConfig(1, 0, 0, &transport);
sender_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
StartStopBitrateObserver encoder;
video_send_config_.encoder_settings.encoder = &encoder;
video_send_config_.encoder_settings.internal_source = true;
CreateVideoStreams();
task_queue_.SendTask([this, &transport, &encoder]() {
CreateSenderCall(Call::Config(event_log_.get()));
CreateSendConfig(1, 0, 0, &transport);
sender_call_->SignalChannelNetworkState(MediaType::VIDEO, kNetworkUp);
video_send_config_.encoder_settings.encoder = &encoder;
video_send_config_.encoder_settings.internal_source = true;
CreateVideoStreams();
});
EXPECT_TRUE(encoder.WaitForEncoderInit());
video_send_stream_->Start();
task_queue_.SendTask([this]() {
video_send_stream_->Start();
});
EXPECT_TRUE(encoder.WaitBitrateChanged(true));
video_send_stream_->Stop();
task_queue_.SendTask([this]() {
video_send_stream_->Stop();
});
EXPECT_TRUE(encoder.WaitBitrateChanged(false));
video_send_stream_->Start();
task_queue_.SendTask([this]() {
video_send_stream_->Start();
});
EXPECT_TRUE(encoder.WaitBitrateChanged(true));
DestroyStreams();
task_queue_.SendTask([this]() {
DestroyStreams();
DestroyCalls();
});
}
TEST_F(VideoSendStreamTest, CapturesTextureAndVideoFrames) {
@ -1992,49 +2049,55 @@ TEST_F(VideoSendStreamTest, CapturesTextureAndVideoFrames) {
rtc::Event output_frame_event_;
};
// Initialize send stream.
CreateSenderCall(Call::Config(event_log_.get()));
test::NullTransport transport;
CreateSendConfig(1, 0, 0, &transport);
FrameObserver observer;
video_send_config_.pre_encode_callback = &observer;
CreateVideoStreams();
// Prepare five input frames. Send ordinary VideoFrame and texture frames
// alternatively.
std::vector<VideoFrame> input_frames;
int width = 168;
int height = 132;
input_frames.push_back(test::FakeNativeBuffer::CreateFrame(
width, height, 1, 1, kVideoRotation_0));
input_frames.push_back(test::FakeNativeBuffer::CreateFrame(
width, height, 2, 2, kVideoRotation_0));
input_frames.push_back(CreateVideoFrame(width, height, 3));
input_frames.push_back(CreateVideoFrame(width, height, 4));
input_frames.push_back(test::FakeNativeBuffer::CreateFrame(
width, height, 5, 5, kVideoRotation_0));
task_queue_.SendTask([this, &transport, &observer, &input_frames]() {
// Initialize send stream.
CreateSenderCall(Call::Config(event_log_.get()));
video_send_stream_->Start();
test::FrameForwarder forwarder;
video_send_stream_->SetSource(
&forwarder, VideoSendStream::DegradationPreference::kMaintainFramerate);
for (size_t i = 0; i < input_frames.size(); i++) {
forwarder.IncomingCapturedFrame(input_frames[i]);
// Wait until the output frame is received before sending the next input
// frame. Or the previous input frame may be replaced without delivering.
observer.WaitOutputFrame();
}
video_send_stream_->Stop();
video_send_stream_->SetSource(
nullptr, VideoSendStream::DegradationPreference::kMaintainFramerate);
CreateSendConfig(1, 0, 0, &transport);
video_send_config_.pre_encode_callback = &observer;
CreateVideoStreams();
// Prepare five input frames. Send ordinary VideoFrame and texture frames
// alternatively.
int width = 168;
int height = 132;
input_frames.push_back(test::FakeNativeBuffer::CreateFrame(
width, height, 1, 1, kVideoRotation_0));
input_frames.push_back(test::FakeNativeBuffer::CreateFrame(
width, height, 2, 2, kVideoRotation_0));
input_frames.push_back(CreateVideoFrame(width, height, 3));
input_frames.push_back(CreateVideoFrame(width, height, 4));
input_frames.push_back(test::FakeNativeBuffer::CreateFrame(
width, height, 5, 5, kVideoRotation_0));
video_send_stream_->Start();
test::FrameForwarder forwarder;
video_send_stream_->SetSource(
&forwarder, VideoSendStream::DegradationPreference::kMaintainFramerate);
for (size_t i = 0; i < input_frames.size(); i++) {
forwarder.IncomingCapturedFrame(input_frames[i]);
// Wait until the output frame is received before sending the next input
// frame. Or the previous input frame may be replaced without delivering.
observer.WaitOutputFrame();
}
video_send_stream_->Stop();
video_send_stream_->SetSource(
nullptr, VideoSendStream::DegradationPreference::kMaintainFramerate);
});
// Test if the input and output frames are the same. render_time_ms and
// timestamp are not compared because capturer sets those values.
ExpectEqualFramesVector(input_frames, observer.output_frames());
DestroyStreams();
task_queue_.SendTask([this]() {
DestroyStreams();
DestroyCalls();
});
}
void ExpectEqualFramesVector(const std::vector<VideoFrame>& frames1,
@ -2060,8 +2123,10 @@ VideoFrame CreateVideoFrame(int width, int height, uint8_t data) {
TEST_F(VideoSendStreamTest, EncoderIsProperlyInitializedAndDestroyed) {
class EncoderStateObserver : public test::SendTest, public VideoEncoder {
public:
EncoderStateObserver()
explicit EncoderStateObserver(
test::SingleThreadedTaskQueueForTesting* task_queue)
: SendTest(kDefaultTimeoutMs),
task_queue_(task_queue),
stream_(nullptr),
initialized_(false),
callback_registered_(false),
@ -2148,18 +2213,23 @@ TEST_F(VideoSendStreamTest, EncoderIsProperlyInitializedAndDestroyed) {
void PerformTest() override {
EXPECT_TRUE(Wait()) << "Timed out while waiting for Encode.";
EXPECT_EQ(0u, num_releases());
stream_->ReconfigureVideoEncoder(std::move(encoder_config_));
EXPECT_EQ(0u, num_releases());
stream_->Stop();
// Encoder should not be released before destroying the VideoSendStream.
EXPECT_FALSE(IsReleased());
EXPECT_TRUE(IsReadyForEncode());
stream_->Start();
task_queue_->SendTask([this]() {
EXPECT_EQ(0u, num_releases());
stream_->ReconfigureVideoEncoder(std::move(encoder_config_));
EXPECT_EQ(0u, num_releases());
stream_->Stop();
// Encoder should not be released before destroying the VideoSendStream.
EXPECT_FALSE(IsReleased());
EXPECT_TRUE(IsReadyForEncode());
stream_->Start();
});
// Sanity check, make sure we still encode frames with this encoder.
EXPECT_TRUE(Wait()) << "Timed out while waiting for Encode.";
}
test::SingleThreadedTaskQueueForTesting* const task_queue_;
rtc::CriticalSection crit_;
VideoSendStream* stream_;
bool initialized_ GUARDED_BY(crit_);
@ -2167,7 +2237,7 @@ TEST_F(VideoSendStreamTest, EncoderIsProperlyInitializedAndDestroyed) {
size_t num_releases_ GUARDED_BY(crit_);
bool released_ GUARDED_BY(crit_);
VideoEncoderConfig encoder_config_;
} test_encoder;
} test_encoder(&task_queue_);
RunBaseTest(&test_encoder);
@ -2553,9 +2623,11 @@ TEST_F(VideoSendStreamTest, ReconfigureBitratesSetsEncoderBitratesCorrectly) {
class EncoderBitrateThresholdObserver : public test::SendTest,
public test::FakeEncoder {
public:
EncoderBitrateThresholdObserver()
explicit EncoderBitrateThresholdObserver(
test::SingleThreadedTaskQueueForTesting* task_queue)
: SendTest(kDefaultTimeoutMs),
FakeEncoder(Clock::GetRealTimeClock()),
task_queue_(task_queue),
init_encode_event_(false, false),
bitrate_changed_event_(false, false),
target_bitrate_(0),
@ -2680,7 +2752,9 @@ TEST_F(VideoSendStreamTest, ReconfigureBitratesSetsEncoderBitratesCorrectly) {
Call::Config::BitrateConfig bitrate_config;
bitrate_config.start_bitrate_bps = kIncreasedStartBitrateKbps * 1000;
bitrate_config.max_bitrate_bps = kIncreasedMaxBitrateKbps * 1000;
call_->SetBitrateConfig(bitrate_config);
task_queue_->SendTask([this, &bitrate_config]() {
call_->SetBitrateConfig(bitrate_config);
});
// Encoder rate is capped by EncoderConfig max_bitrate_bps.
WaitForSetRates(kMaxBitrateKbps);
encoder_config_.max_bitrate_bps = kLowerMaxBitrateKbps * 1000;
@ -2702,6 +2776,7 @@ TEST_F(VideoSendStreamTest, ReconfigureBitratesSetsEncoderBitratesCorrectly) {
WaitForSetRates(kIncreasedStartBitrateKbps);
}
test::SingleThreadedTaskQueueForTesting* const task_queue_;
rtc::Event init_encode_event_;
rtc::Event bitrate_changed_event_;
rtc::CriticalSection crit_;
@ -2711,7 +2786,7 @@ TEST_F(VideoSendStreamTest, ReconfigureBitratesSetsEncoderBitratesCorrectly) {
webrtc::Call* call_;
webrtc::VideoSendStream* send_stream_;
webrtc::VideoEncoderConfig encoder_config_;
} test;
} test(&task_queue_);
RunBaseTest(&test);
}
@ -3302,9 +3377,11 @@ TEST_F(VideoSendStreamTest, RemoveOverheadFromBandwidth) {
class RemoveOverheadFromBandwidthTest : public test::EndToEndTest,
public test::FakeEncoder {
public:
RemoveOverheadFromBandwidthTest()
explicit RemoveOverheadFromBandwidthTest(
test::SingleThreadedTaskQueueForTesting* task_queue)
: EndToEndTest(test::CallTest::kDefaultTimeoutMs),
FakeEncoder(Clock::GetRealTimeClock()),
task_queue_(task_queue),
call_(nullptr),
max_bitrate_bps_(0),
first_packet_sent_(false),
@ -3349,8 +3426,10 @@ TEST_F(VideoSendStreamTest, RemoveOverheadFromBandwidth) {
bitrate_config.start_bitrate_bps = kStartBitrateBps;
bitrate_config.max_bitrate_bps = kMaxBitrateBps;
bitrate_config.min_bitrate_bps = kMinBitrateBps;
call_->SetBitrateConfig(bitrate_config);
call_->OnTransportOverheadChanged(webrtc::MediaType::VIDEO, 40);
task_queue_->SendTask([this, &bitrate_config]() {
call_->SetBitrateConfig(bitrate_config);
call_->OnTransportOverheadChanged(webrtc::MediaType::VIDEO, 40);
});
// At a bitrate of 60kbps with a packet size of 1200B video and an
// overhead of 40B per packet video produces 2240bps overhead.
@ -3363,13 +3442,13 @@ TEST_F(VideoSendStreamTest, RemoveOverheadFromBandwidth) {
}
private:
test::SingleThreadedTaskQueueForTesting* const task_queue_;
Call* call_;
rtc::CriticalSection crit_;
uint32_t max_bitrate_bps_ GUARDED_BY(&crit_);
bool first_packet_sent_ GUARDED_BY(&crit_);
rtc::Event bitrate_changed_event_;
} test;
} test(&task_queue_);
RunBaseTest(&test);
}