Allow passing an event log as string to NetEqSimulator.
Previously only reading from the filesystem was supported, this CL allows parsing an event log from a string. Bug: webrtc:10337 Change-Id: Iadde3319eb8fb4175625f510201fac9c01c80ed9 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/127296 Commit-Queue: Ivo Creusen <ivoc@webrtc.org> Reviewed-by: Minyue Li <minyue@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Cr-Commit-Position: refs/heads/master@{#27202}
This commit is contained in:
@ -421,6 +421,7 @@ if (rtc_include_tests) {
|
||||
"../rtc_base:checks",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
"//third_party/abseil-cpp/absl/memory",
|
||||
"//third_party/abseil-cpp/absl/strings",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,7 +50,30 @@ std::unique_ptr<NetEqSimulator> NetEqSimulatorFactory::CreateSimulator(
|
||||
config.replacement_audio_file = FLAG_replacement_audio_file;
|
||||
config.max_nr_packets_in_buffer = FLAG_max_nr_packets_in_buffer;
|
||||
config.output_audio_filename = output_audio_filename;
|
||||
return factory_->InitializeTest(argv[1], config);
|
||||
return factory_->InitializeTestFromFile(argv[1], config);
|
||||
}
|
||||
|
||||
std::unique_ptr<NetEqSimulator> NetEqSimulatorFactory::CreateSimulatorFromFile(
|
||||
absl::string_view event_log_filename,
|
||||
absl::string_view replacement_audio_filename,
|
||||
Config simulation_config) {
|
||||
NetEqTestFactory::Config config;
|
||||
config.replacement_audio_file = std::string(replacement_audio_filename);
|
||||
config.max_nr_packets_in_buffer = simulation_config.max_nr_packets_in_buffer;
|
||||
return factory_->InitializeTestFromFile(std::string(event_log_filename),
|
||||
config);
|
||||
}
|
||||
|
||||
std::unique_ptr<NetEqSimulator>
|
||||
NetEqSimulatorFactory::CreateSimulatorFromString(
|
||||
absl::string_view event_log_file_contents,
|
||||
absl::string_view replacement_audio_filename,
|
||||
Config simulation_config) {
|
||||
NetEqTestFactory::Config config;
|
||||
config.replacement_audio_file = std::string(replacement_audio_filename);
|
||||
config.max_nr_packets_in_buffer = simulation_config.max_nr_packets_in_buffer;
|
||||
return factory_->InitializeTestFromString(
|
||||
std::string(event_log_file_contents), config);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
|
||||
@ -12,7 +12,9 @@
|
||||
#define API_TEST_NETEQ_SIMULATOR_FACTORY_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "api/test/neteq_simulator.h"
|
||||
|
||||
namespace webrtc {
|
||||
@ -24,8 +26,20 @@ class NetEqSimulatorFactory {
|
||||
public:
|
||||
NetEqSimulatorFactory();
|
||||
~NetEqSimulatorFactory();
|
||||
struct Config {
|
||||
int max_nr_packets_in_buffer = 0;
|
||||
};
|
||||
// This function takes the same arguments as the neteq_rtpplay utility.
|
||||
std::unique_ptr<NetEqSimulator> CreateSimulator(int argc, char* argv[]);
|
||||
std::unique_ptr<NetEqSimulator> CreateSimulatorFromFile(
|
||||
absl::string_view event_log_filename,
|
||||
absl::string_view replacement_audio_filename,
|
||||
Config simulation_config);
|
||||
// The same as above, but pass the file contents as a string.
|
||||
std::unique_ptr<NetEqSimulator> CreateSimulatorFromString(
|
||||
absl::string_view event_log_file_contents,
|
||||
absl::string_view replacement_audio_file,
|
||||
Config simulation_config);
|
||||
|
||||
private:
|
||||
std::unique_ptr<NetEqTestFactory> factory_;
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "modules/audio_coding/neteq/tools/neteq_event_log_input.h"
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
||||
#include "modules/audio_coding/neteq/tools/rtc_event_log_source.h"
|
||||
#include "rtc_base/checks.h"
|
||||
@ -18,11 +19,18 @@
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
NetEqEventLogInput::NetEqEventLogInput(const std::string& file_name,
|
||||
absl::optional<uint32_t> ssrc_filter)
|
||||
: source_(RtcEventLogSource::Create(file_name, ssrc_filter)) {
|
||||
LoadNextPacket();
|
||||
AdvanceOutputEvent();
|
||||
NetEqEventLogInput* NetEqEventLogInput::CreateFromFile(
|
||||
const std::string& file_name,
|
||||
absl::optional<uint32_t> ssrc_filter) {
|
||||
return new NetEqEventLogInput(
|
||||
RtcEventLogSource::CreateFromFile(file_name, ssrc_filter));
|
||||
}
|
||||
|
||||
NetEqEventLogInput* NetEqEventLogInput::CreateFromString(
|
||||
const std::string& file_contents,
|
||||
absl::optional<uint32_t> ssrc_filter) {
|
||||
return new NetEqEventLogInput(
|
||||
RtcEventLogSource::CreateFromString(file_contents, ssrc_filter));
|
||||
}
|
||||
|
||||
absl::optional<int64_t> NetEqEventLogInput::NextOutputEventTime() const {
|
||||
@ -40,5 +48,12 @@ PacketSource* NetEqEventLogInput::source() {
|
||||
return source_.get();
|
||||
}
|
||||
|
||||
NetEqEventLogInput::NetEqEventLogInput(
|
||||
std::unique_ptr<RtcEventLogSource> source)
|
||||
: source_(std::move(source)) {
|
||||
LoadNextPacket();
|
||||
AdvanceOutputEvent();
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
||||
@ -27,8 +27,12 @@ class RtcEventLogSource;
|
||||
// RtcEventLogSource.
|
||||
class NetEqEventLogInput final : public NetEqPacketSourceInput {
|
||||
public:
|
||||
NetEqEventLogInput(const std::string& file_name,
|
||||
absl::optional<uint32_t> ssrc_filter);
|
||||
static NetEqEventLogInput* CreateFromFile(
|
||||
const std::string& file_name,
|
||||
absl::optional<uint32_t> ssrc_filter);
|
||||
static NetEqEventLogInput* CreateFromString(
|
||||
const std::string& file_contents,
|
||||
absl::optional<uint32_t> ssrc_filter);
|
||||
|
||||
absl::optional<int64_t> NextOutputEventTime() const override;
|
||||
void AdvanceOutputEvent() override;
|
||||
@ -37,6 +41,7 @@ class NetEqEventLogInput final : public NetEqPacketSourceInput {
|
||||
PacketSource* source() override;
|
||||
|
||||
private:
|
||||
NetEqEventLogInput(std::unique_ptr<RtcEventLogSource> source);
|
||||
std::unique_ptr<RtcEventLogSource> source_;
|
||||
};
|
||||
|
||||
|
||||
@ -377,8 +377,8 @@ int main(int argc, char* argv[]) {
|
||||
config.ssrc_filter = absl::make_optional(ssrc);
|
||||
}
|
||||
|
||||
std::unique_ptr<webrtc::test::NetEqTest> test = factory.InitializeTest(
|
||||
/*input_filename=*/argv[1], config);
|
||||
std::unique_ptr<webrtc::test::NetEqTest> test =
|
||||
factory.InitializeTestFromFile(/*input_filename=*/argv[1], config);
|
||||
test->Run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -108,8 +108,17 @@ NetEqTestFactory::Config::Config() = default;
|
||||
NetEqTestFactory::Config::Config(const Config& other) = default;
|
||||
NetEqTestFactory::Config::~Config() = default;
|
||||
|
||||
std::unique_ptr<NetEqTest> NetEqTestFactory::InitializeTest(
|
||||
std::string input_file_name,
|
||||
std::unique_ptr<NetEqTest> NetEqTestFactory::InitializeTestFromString(
|
||||
const std::string& input_string,
|
||||
const Config& config) {
|
||||
std::unique_ptr<NetEqInput> input(
|
||||
NetEqEventLogInput::CreateFromString(input_string, config.ssrc_filter));
|
||||
RTC_CHECK(input) << "Cannot parse input string";
|
||||
return InitializeTest(std::move(input), config);
|
||||
}
|
||||
|
||||
std::unique_ptr<NetEqTest> NetEqTestFactory::InitializeTestFromFile(
|
||||
const std::string& input_file_name,
|
||||
const Config& config) {
|
||||
// Gather RTP header extensions in a map.
|
||||
NetEqPacketSourceInput::RtpHeaderExtensionMap rtp_ext_map = {
|
||||
@ -125,12 +134,19 @@ std::unique_ptr<NetEqTest> NetEqTestFactory::InitializeTest(
|
||||
input.reset(new NetEqRtpDumpInput(input_file_name, rtp_ext_map,
|
||||
config.ssrc_filter));
|
||||
} else {
|
||||
input.reset(new NetEqEventLogInput(input_file_name, config.ssrc_filter));
|
||||
input.reset(NetEqEventLogInput::CreateFromFile(input_file_name,
|
||||
config.ssrc_filter));
|
||||
}
|
||||
|
||||
std::cout << "Input file: " << input_file_name << std::endl;
|
||||
RTC_CHECK(input) << "Cannot open input file";
|
||||
RTC_CHECK(!input->ended()) << "Input file is empty";
|
||||
return InitializeTest(std::move(input), config);
|
||||
}
|
||||
|
||||
std::unique_ptr<NetEqTest> NetEqTestFactory::InitializeTest(
|
||||
std::unique_ptr<NetEqInput> input,
|
||||
const Config& config) {
|
||||
RTC_CHECK(!input->ended()) << "Input is empty";
|
||||
|
||||
// Check the sample rate.
|
||||
absl::optional<int> sample_rate_hz;
|
||||
|
||||
@ -133,10 +133,16 @@ class NetEqTestFactory {
|
||||
absl::optional<std::string> output_audio_filename;
|
||||
};
|
||||
|
||||
std::unique_ptr<NetEqTest> InitializeTest(std::string input_filename,
|
||||
const Config& config);
|
||||
std::unique_ptr<NetEqTest> InitializeTestFromFile(
|
||||
const std::string& input_filename,
|
||||
const Config& config);
|
||||
std::unique_ptr<NetEqTest> InitializeTestFromString(
|
||||
const std::string& input_string,
|
||||
const Config& config);
|
||||
|
||||
private:
|
||||
std::unique_ptr<NetEqTest> InitializeTest(std::unique_ptr<NetEqInput> input,
|
||||
const Config& config);
|
||||
std::unique_ptr<SsrcSwitchDetector> ssrc_switch_detector_;
|
||||
std::unique_ptr<NetEqStatsPlotter> stats_plotter_;
|
||||
};
|
||||
|
||||
@ -36,11 +36,23 @@ bool ShouldSkipStream(ParsedRtcEventLog::MediaType media_type,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
RtcEventLogSource* RtcEventLogSource::Create(
|
||||
std::unique_ptr<RtcEventLogSource> RtcEventLogSource::CreateFromFile(
|
||||
const std::string& file_name,
|
||||
absl::optional<uint32_t> ssrc_filter) {
|
||||
RtcEventLogSource* source = new RtcEventLogSource();
|
||||
RTC_CHECK(source->OpenFile(file_name, ssrc_filter));
|
||||
auto source = std::unique_ptr<RtcEventLogSource>(new RtcEventLogSource());
|
||||
ParsedRtcEventLog parsed_log;
|
||||
RTC_CHECK(parsed_log.ParseFile(file_name));
|
||||
RTC_CHECK(source->Initialize(parsed_log, ssrc_filter));
|
||||
return source;
|
||||
}
|
||||
|
||||
std::unique_ptr<RtcEventLogSource> RtcEventLogSource::CreateFromString(
|
||||
const std::string& file_contents,
|
||||
absl::optional<uint32_t> ssrc_filter) {
|
||||
auto source = std::unique_ptr<RtcEventLogSource>(new RtcEventLogSource());
|
||||
ParsedRtcEventLog parsed_log;
|
||||
RTC_CHECK(parsed_log.ParseString(file_contents));
|
||||
RTC_CHECK(source->Initialize(parsed_log, ssrc_filter));
|
||||
return source;
|
||||
}
|
||||
|
||||
@ -64,12 +76,8 @@ int64_t RtcEventLogSource::NextAudioOutputEventMs() {
|
||||
|
||||
RtcEventLogSource::RtcEventLogSource() : PacketSource() {}
|
||||
|
||||
bool RtcEventLogSource::OpenFile(const std::string& file_name,
|
||||
absl::optional<uint32_t> ssrc_filter) {
|
||||
ParsedRtcEventLog parsed_log;
|
||||
if (!parsed_log.ParseFile(file_name))
|
||||
return false;
|
||||
|
||||
bool RtcEventLogSource::Initialize(const ParsedRtcEventLog& parsed_log,
|
||||
absl::optional<uint32_t> ssrc_filter) {
|
||||
const auto first_log_end_time_us =
|
||||
parsed_log.stop_log_events().empty()
|
||||
? std::numeric_limits<int64_t>::max()
|
||||
|
||||
@ -33,8 +33,13 @@ class RtcEventLogSource : public PacketSource {
|
||||
public:
|
||||
// Creates an RtcEventLogSource reading from |file_name|. If the file cannot
|
||||
// be opened, or has the wrong format, NULL will be returned.
|
||||
static RtcEventLogSource* Create(const std::string& file_name,
|
||||
absl::optional<uint32_t> ssrc_filter);
|
||||
static std::unique_ptr<RtcEventLogSource> CreateFromFile(
|
||||
const std::string& file_name,
|
||||
absl::optional<uint32_t> ssrc_filter);
|
||||
// Same as above, but uses a string with the file contents.
|
||||
static std::unique_ptr<RtcEventLogSource> CreateFromString(
|
||||
const std::string& file_contents,
|
||||
absl::optional<uint32_t> ssrc_filter);
|
||||
|
||||
virtual ~RtcEventLogSource();
|
||||
|
||||
@ -48,8 +53,8 @@ class RtcEventLogSource : public PacketSource {
|
||||
private:
|
||||
RtcEventLogSource();
|
||||
|
||||
bool OpenFile(const std::string& file_name,
|
||||
absl::optional<uint32_t> ssrc_filter);
|
||||
bool Initialize(const ParsedRtcEventLog& parsed_log,
|
||||
absl::optional<uint32_t> ssrc_filter);
|
||||
|
||||
std::vector<std::unique_ptr<Packet>> rtp_packets_;
|
||||
size_t rtp_packet_index_ = 0;
|
||||
|
||||
Reference in New Issue
Block a user