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:
parent
2a596549ca
commit
413ee9a010
@ -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",
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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_);
|
||||
}
|
||||
|
||||
@ -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_;
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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") {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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) {}
|
||||
|
||||
|
||||
144
webrtc/test/single_threaded_task_queue.cc
Normal file
144
webrtc/test/single_threaded_task_queue.cc
Normal 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
|
||||
97
webrtc/test/single_threaded_task_queue.h
Normal file
97
webrtc/test/single_threaded_task_queue.h
Normal 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_
|
||||
364
webrtc/test/single_threaded_task_queue_unittest.cc
Normal file
364
webrtc/test/single_threaded_task_queue_unittest.cc
Normal 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
@ -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) {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user