Refactor NetEq test event log input.

Remove duplicate implementions and complex inheritance.

Slight change to the event log visualizer NetEq simulations to only
include time after the first packet has been received.

Bug: None
Change-Id: I8a7bd3d4d2b601fc134292554476020f9b3eee92
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/300300
Commit-Queue: Jakob Ivarsson‎ <jakobi@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39773}
This commit is contained in:
Jakob Ivarsson 2023-04-04 21:54:18 +02:00 committed by WebRTC LUCI CQ
parent b8219a1f98
commit 27d70f3133
7 changed files with 177 additions and 546 deletions

View File

@ -850,14 +850,6 @@ rtc_library("neteq_test_tools") {
"//third_party/abseil-cpp/absl/strings",
"//third_party/abseil-cpp/absl/types:optional",
]
if (rtc_enable_protobuf) {
sources += [
"neteq/tools/neteq_event_log_input.cc",
"neteq/tools/neteq_event_log_input.h",
]
deps += [ ":rtc_event_log_source" ]
}
}
rtc_library("neteq_tools") {
@ -893,6 +885,16 @@ rtc_library("neteq_tools") {
"//third_party/abseil-cpp/absl/strings",
"//third_party/abseil-cpp/absl/types:optional",
]
if (rtc_enable_protobuf) {
sources += [
"neteq/tools/neteq_event_log_input.cc",
"neteq/tools/neteq_event_log_input.h",
]
deps += [ "../../logging:rtc_event_log_parser" ]
public_deps = # no-presubmit-check TODO(webrtc:8603)
[ "../../logging:rtc_event_log_proto" ]
}
}
rtc_library("neteq_input_audio_tools") {
@ -912,29 +914,6 @@ rtc_library("neteq_input_audio_tools") {
}
if (rtc_enable_protobuf) {
rtc_library("rtc_event_log_source") {
testonly = true
sources = [
"neteq/tools/rtc_event_log_source.cc",
"neteq/tools/rtc_event_log_source.h",
]
deps = [
":neteq_tools_minimal",
"../../logging:rtc_event_log_parser",
"../../rtc_base:checks",
"../rtp_rtcp",
"../rtp_rtcp:rtp_rtcp_format",
]
absl_deps = [
"//third_party/abseil-cpp/absl/strings",
"//third_party/abseil-cpp/absl/types:optional",
]
public_deps = # no-presubmit-check TODO(webrtc:8603)
[ "../../logging:rtc_event_log_proto" ]
}
# Only used for test purpose. Since we want to use it from chromium
# (see audio_coding_modules_tests_shared below), we cannot guard it
# under rtc_include_tests.

View File

@ -14,64 +14,153 @@
#include <memory>
#include "absl/strings/string_view.h"
#include "modules/audio_coding/neteq/tools/rtc_event_log_source.h"
#include "rtc_base/checks.h"
namespace webrtc {
namespace test {
namespace {
NetEqEventLogInput* NetEqEventLogInput::CreateFromFile(
absl::string_view file_name,
absl::optional<uint32_t> ssrc_filter) {
auto event_log_src =
RtcEventLogSource::CreateFromFile(file_name, ssrc_filter);
if (!event_log_src) {
class NetEqEventLogInput : public NetEqInput {
public:
NetEqEventLogInput(const std::vector<LoggedRtpPacketIncoming>& packet_stream,
const std::vector<LoggedAudioPlayoutEvent>& output_events,
const std::vector<LoggedNetEqSetMinimumDelayEvent>&
neteq_set_minimum_delay_events,
absl::optional<int64_t> end_time_ms)
: packet_stream_(packet_stream),
packet_stream_it_(packet_stream_.begin()),
output_events_(output_events),
output_events_it_(output_events_.begin()),
neteq_set_minimum_delay_events_(neteq_set_minimum_delay_events),
neteq_set_minimum_delay_events_it_(
neteq_set_minimum_delay_events_.begin()),
end_time_ms_(end_time_ms) {
// Ignore all output events before the first packet.
while (output_events_it_ != output_events_.end() &&
output_events_it_->log_time_ms() <
packet_stream_it_->log_time_ms()) {
++output_events_it_;
}
}
absl::optional<int64_t> NextPacketTime() const override {
if (packet_stream_it_ == packet_stream_.end()) {
return absl::nullopt;
}
if (end_time_ms_ && packet_stream_it_->rtp.log_time_ms() > *end_time_ms_) {
return absl::nullopt;
}
return packet_stream_it_->rtp.log_time_ms();
}
absl::optional<int64_t> NextOutputEventTime() const override {
if (output_events_it_ == output_events_.end()) {
return absl::nullopt;
}
if (end_time_ms_ && output_events_it_->log_time_ms() > *end_time_ms_) {
return absl::nullopt;
}
return output_events_it_->log_time_ms();
}
absl::optional<SetMinimumDelayInfo> NextSetMinimumDelayInfo() const override {
if (neteq_set_minimum_delay_events_it_ ==
neteq_set_minimum_delay_events_.end()) {
return absl::nullopt;
}
if (end_time_ms_ &&
neteq_set_minimum_delay_events_it_->log_time_ms() > *end_time_ms_) {
return absl::nullopt;
}
return SetMinimumDelayInfo(
neteq_set_minimum_delay_events_it_->log_time_ms(),
neteq_set_minimum_delay_events_it_->minimum_delay_ms);
}
std::unique_ptr<PacketData> PopPacket() override {
if (packet_stream_it_ == packet_stream_.end()) {
return nullptr;
}
auto packet_data = std::make_unique<PacketData>();
packet_data->header = packet_stream_it_->rtp.header;
packet_data->time_ms = packet_stream_it_->rtp.log_time_ms();
// This is a header-only "dummy" packet. Set the payload to all zeros, with
// length according to the virtual length.
packet_data->payload.SetSize(packet_stream_it_->rtp.total_length -
packet_stream_it_->rtp.header_length);
std::fill_n(packet_data->payload.data(), packet_data->payload.size(), 0);
++packet_stream_it_;
return packet_data;
}
void AdvanceOutputEvent() override {
if (output_events_it_ != output_events_.end()) {
++output_events_it_;
}
}
void AdvanceSetMinimumDelay() override {
if (neteq_set_minimum_delay_events_it_ !=
neteq_set_minimum_delay_events_.end()) {
++neteq_set_minimum_delay_events_it_;
}
}
bool ended() const override { return !NextEventTime(); }
absl::optional<RTPHeader> NextHeader() const override {
if (packet_stream_it_ == packet_stream_.end()) {
return absl::nullopt;
}
return packet_stream_it_->rtp.header;
}
private:
const std::vector<LoggedRtpPacketIncoming> packet_stream_;
std::vector<LoggedRtpPacketIncoming>::const_iterator packet_stream_it_;
const std::vector<LoggedAudioPlayoutEvent> output_events_;
std::vector<LoggedAudioPlayoutEvent>::const_iterator output_events_it_;
const std::vector<LoggedNetEqSetMinimumDelayEvent>
neteq_set_minimum_delay_events_;
std::vector<LoggedNetEqSetMinimumDelayEvent>::const_iterator
neteq_set_minimum_delay_events_it_;
const absl::optional<int64_t> end_time_ms_;
};
} // namespace
std::unique_ptr<NetEqInput> CreateNetEqEventLogInput(
const ParsedRtcEventLog& parsed_log,
absl::optional<uint32_t> ssrc) {
if (parsed_log.incoming_audio_ssrcs().empty()) {
return nullptr;
}
return new NetEqEventLogInput(std::move(event_log_src));
}
NetEqEventLogInput* NetEqEventLogInput::CreateFromString(
absl::string_view file_contents,
absl::optional<uint32_t> ssrc_filter) {
auto event_log_src =
RtcEventLogSource::CreateFromString(file_contents, ssrc_filter);
if (!event_log_src) {
// Pick the first SSRC if none was provided.
ssrc = ssrc.value_or(*parsed_log.incoming_audio_ssrcs().begin());
auto streams = parsed_log.incoming_rtp_packets_by_ssrc();
auto stream =
std::find_if(streams.begin(), streams.end(),
[ssrc](auto stream) { return stream.ssrc == ssrc; });
if (stream == streams.end()) {
return nullptr;
}
return new NetEqEventLogInput(std::move(event_log_src));
}
absl::optional<int64_t> NetEqEventLogInput::NextOutputEventTime() const {
return next_output_event_ms_;
}
absl::optional<NetEqInput::SetMinimumDelayInfo>
NetEqEventLogInput::NextSetMinimumDelayInfo() const {
return next_minimum_delay_event_info_;
}
void NetEqEventLogInput::AdvanceOutputEvent() {
next_output_event_ms_ = source_->NextAudioOutputEventMs();
if (*next_output_event_ms_ == std::numeric_limits<int64_t>::max()) {
next_output_event_ms_ = absl::nullopt;
auto output_events_it = parsed_log.audio_playout_events().find(*ssrc);
if (output_events_it == parsed_log.audio_playout_events().end()) {
return nullptr;
}
}
void NetEqEventLogInput::AdvanceSetMinimumDelay() {
next_minimum_delay_event_info_ = source_->NextSetMinimumDelayEvent();
}
PacketSource* NetEqEventLogInput::source() {
return source_.get();
}
NetEqEventLogInput::NetEqEventLogInput(
std::unique_ptr<RtcEventLogSource> source)
: source_(std::move(source)) {
LoadNextPacket();
AdvanceOutputEvent();
AdvanceSetMinimumDelay();
std::vector<LoggedNetEqSetMinimumDelayEvent> neteq_set_minimum_delay_events;
auto neteq_set_minimum_delay_events_it =
parsed_log.neteq_set_minimum_delay_events().find(*ssrc);
if (neteq_set_minimum_delay_events_it !=
parsed_log.neteq_set_minimum_delay_events().end()) {
neteq_set_minimum_delay_events = neteq_set_minimum_delay_events_it->second;
}
int64_t end_time_ms = parsed_log.first_log_segment().stop_time_ms();
return std::make_unique<NetEqEventLogInput>(
stream->incoming_packets, output_events_it->second,
neteq_set_minimum_delay_events, end_time_ms);
}
} // namespace test

View File

@ -11,43 +11,17 @@
#ifndef MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_EVENT_LOG_INPUT_H_
#define MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_EVENT_LOG_INPUT_H_
#include <map>
#include <memory>
#include <string>
#include "absl/strings/string_view.h"
#include "modules/audio_coding/neteq/tools/neteq_packet_source_input.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "absl/types/optional.h"
#include "logging/rtc_event_log/rtc_event_log_parser.h"
#include "modules/audio_coding/neteq/tools/neteq_input.h"
namespace webrtc {
namespace test {
class RtcEventLogSource;
// Implementation of NetEqPacketSourceInput to be used with an
// RtcEventLogSource.
class NetEqEventLogInput final : public NetEqPacketSourceInput {
public:
static NetEqEventLogInput* CreateFromFile(
absl::string_view file_name,
absl::optional<uint32_t> ssrc_filter);
static NetEqEventLogInput* CreateFromString(
absl::string_view file_contents,
absl::optional<uint32_t> ssrc_filter);
absl::optional<int64_t> NextOutputEventTime() const override;
absl::optional<SetMinimumDelayInfo> NextSetMinimumDelayInfo() const override;
void AdvanceOutputEvent() override;
void AdvanceSetMinimumDelay() override;
protected:
PacketSource* source() override;
private:
NetEqEventLogInput(std::unique_ptr<RtcEventLogSource> source);
std::unique_ptr<RtcEventLogSource> source_;
absl::optional<SetMinimumDelayInfo> next_minimum_delay_event_info_;
};
std::unique_ptr<NetEqInput> CreateNetEqEventLogInput(
const ParsedRtcEventLog& parsed_log,
absl::optional<uint32_t> ssrc);
} // namespace test
} // namespace webrtc

View File

@ -112,8 +112,14 @@ std::unique_ptr<NetEqTest> NetEqTestFactory::InitializeTestFromString(
absl::string_view input_string,
NetEqFactory* factory,
const Config& config) {
std::unique_ptr<NetEqInput> input(
NetEqEventLogInput::CreateFromString(input_string, config.ssrc_filter));
ParsedRtcEventLog parsed_log;
auto status = parsed_log.ParseString(input_string);
if (!status.ok()) {
std::cerr << "Failed to parse event log: " << status.message() << std::endl;
return nullptr;
}
std::unique_ptr<NetEqInput> input =
CreateNetEqEventLogInput(parsed_log, config.ssrc_filter);
if (!input) {
std::cerr << "Error: Cannot parse input string" << std::endl;
return nullptr;
@ -139,8 +145,14 @@ std::unique_ptr<NetEqTest> NetEqTestFactory::InitializeTestFromFile(
input.reset(new NetEqRtpDumpInput(input_file_name, rtp_ext_map,
config.ssrc_filter));
} else {
input.reset(NetEqEventLogInput::CreateFromFile(input_file_name,
config.ssrc_filter));
ParsedRtcEventLog parsed_log;
auto status = parsed_log.ParseFile(input_file_name);
if (!status.ok()) {
std::cerr << "Failed to parse event log: " << status.message()
<< std::endl;
return nullptr;
}
input = CreateNetEqEventLogInput(parsed_log, config.ssrc_filter);
}
std::cout << "Input file: " << input_file_name << std::endl;

View File

@ -1,198 +0,0 @@
/*
* Copyright (c) 2015 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 "modules/audio_coding/neteq/tools/rtc_event_log_source.h"
#include <string.h>
#include <iostream>
#include <limits>
#include <memory>
#include <set>
#include <utility>
#include "absl/strings/string_view.h"
#include "logging/rtc_event_log/rtc_event_processor.h"
#include "modules/audio_coding/neteq/tools/neteq_input.h"
#include "modules/audio_coding/neteq/tools/packet.h"
#include "rtc_base/checks.h"
namespace webrtc {
namespace test {
namespace {
bool ShouldSkipStream(ParsedRtcEventLog::MediaType media_type,
uint32_t ssrc,
absl::optional<uint32_t> ssrc_filter) {
if (media_type != ParsedRtcEventLog::MediaType::AUDIO)
return true;
if (ssrc_filter.has_value() && ssrc != *ssrc_filter)
return true;
return false;
}
} // namespace
std::unique_ptr<RtcEventLogSource> RtcEventLogSource::CreateFromFile(
absl::string_view file_name,
absl::optional<uint32_t> ssrc_filter) {
auto source = std::unique_ptr<RtcEventLogSource>(new RtcEventLogSource());
ParsedRtcEventLog parsed_log;
auto status = parsed_log.ParseFile(file_name);
if (!status.ok()) {
std::cerr << "Failed to parse event log: " << status.message() << std::endl;
std::cerr << "Skipping log." << std::endl;
return nullptr;
}
if (!source->Initialize(parsed_log, ssrc_filter)) {
std::cerr << "Failed to initialize source from event log, skipping."
<< std::endl;
return nullptr;
}
return source;
}
std::unique_ptr<RtcEventLogSource> RtcEventLogSource::CreateFromString(
absl::string_view file_contents,
absl::optional<uint32_t> ssrc_filter) {
auto source = std::unique_ptr<RtcEventLogSource>(new RtcEventLogSource());
ParsedRtcEventLog parsed_log;
auto status = parsed_log.ParseString(file_contents);
if (!status.ok()) {
std::cerr << "Failed to parse event log: " << status.message() << std::endl;
std::cerr << "Skipping log." << std::endl;
return nullptr;
}
if (!source->Initialize(parsed_log, ssrc_filter)) {
std::cerr << "Failed to initialize source from event log, skipping."
<< std::endl;
return nullptr;
}
return source;
}
RtcEventLogSource::~RtcEventLogSource() {}
std::unique_ptr<Packet> RtcEventLogSource::NextPacket() {
if (rtp_packet_index_ >= rtp_packets_.size())
return nullptr;
std::unique_ptr<Packet> packet = std::move(rtp_packets_[rtp_packet_index_++]);
return packet;
}
int64_t RtcEventLogSource::NextAudioOutputEventMs() {
if (audio_output_index_ >= audio_outputs_.size())
return std::numeric_limits<int64_t>::max();
int64_t output_time_ms = audio_outputs_[audio_output_index_++];
return output_time_ms;
}
absl::optional<NetEqInput::SetMinimumDelayInfo>
RtcEventLogSource::NextSetMinimumDelayEvent() {
if (minimum_delay_index_ >= minimum_delay_.size()) {
return absl::nullopt;
}
return minimum_delay_[minimum_delay_index_++];
}
RtcEventLogSource::RtcEventLogSource() : PacketSource() {}
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()
: parsed_log.stop_log_events().front().log_time_us();
std::set<uint32_t> packet_ssrcs;
auto handle_rtp_packet =
[this, first_log_end_time_us,
&packet_ssrcs](const webrtc::LoggedRtpPacketIncoming& incoming) {
if (!filter_.test(incoming.rtp.header.payloadType) &&
incoming.log_time_us() < first_log_end_time_us) {
rtp_packets_.emplace_back(std::make_unique<Packet>(
incoming.rtp.header, incoming.rtp.total_length,
incoming.rtp.total_length - incoming.rtp.header_length,
static_cast<double>(incoming.log_time_ms())));
packet_ssrcs.insert(rtp_packets_.back()->header().ssrc);
}
};
std::set<uint32_t> ignored_ssrcs;
auto handle_audio_playout =
[this, first_log_end_time_us, &packet_ssrcs,
&ignored_ssrcs](const webrtc::LoggedAudioPlayoutEvent& audio_playout) {
if (audio_playout.log_time_us() < first_log_end_time_us) {
if (packet_ssrcs.count(audio_playout.ssrc) > 0) {
audio_outputs_.emplace_back(audio_playout.log_time_ms());
} else {
ignored_ssrcs.insert(audio_playout.ssrc);
}
}
};
auto handle_neteq_set_minimum_delay =
[this, first_log_end_time_us, &packet_ssrcs](
const webrtc::LoggedNetEqSetMinimumDelayEvent minimum_delay_event) {
if (minimum_delay_event.log_time_us() < first_log_end_time_us) {
if (packet_ssrcs.count(minimum_delay_event.remote_ssrc) > 0) {
minimum_delay_.emplace_back(minimum_delay_event.log_time_ms(),
minimum_delay_event.minimum_delay_ms);
}
}
};
// This wouldn't be needed if we knew that there was at most one audio stream.
webrtc::RtcEventProcessor event_processor;
for (const auto& rtp_packets : parsed_log.incoming_rtp_packets_by_ssrc()) {
ParsedRtcEventLog::MediaType media_type =
parsed_log.GetMediaType(rtp_packets.ssrc, webrtc::kIncomingPacket);
if (ShouldSkipStream(media_type, rtp_packets.ssrc, ssrc_filter)) {
continue;
}
event_processor.AddEvents(rtp_packets.incoming_packets, handle_rtp_packet);
// If no SSRC filter has been set, use the first SSRC only. The simulator
// does not work properly with interleaved packets from multiple SSRCs.
if (!ssrc_filter.has_value()) {
ssrc_filter = rtp_packets.ssrc;
}
}
for (const auto& audio_playouts : parsed_log.audio_playout_events()) {
if (ssrc_filter.has_value() && audio_playouts.first != *ssrc_filter)
continue;
event_processor.AddEvents(audio_playouts.second, handle_audio_playout);
}
for (const auto& neteq_set_minimum_delay_event :
parsed_log.neteq_set_minimum_delay_events()) {
if (ssrc_filter.has_value() &&
neteq_set_minimum_delay_event.first != *ssrc_filter) {
continue;
}
event_processor.AddEvents(neteq_set_minimum_delay_event.second,
handle_neteq_set_minimum_delay);
}
// Fills in rtp_packets_ and audio_outputs_.
event_processor.ProcessEventsInOrder();
for (const auto& ssrc : ignored_ssrcs) {
std::cout << "Ignoring GetAudio events from SSRC 0x" << std::hex << ssrc
<< " because no packets were found with a matching SSRC."
<< std::endl;
}
return true;
}
} // namespace test
} // namespace webrtc

View File

@ -1,77 +0,0 @@
/*
* Copyright (c) 2015 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 MODULES_AUDIO_CODING_NETEQ_TOOLS_RTC_EVENT_LOG_SOURCE_H_
#define MODULES_AUDIO_CODING_NETEQ_TOOLS_RTC_EVENT_LOG_SOURCE_H_
#include <memory>
#include <string>
#include <vector>
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "logging/rtc_event_log/rtc_event_log_parser.h"
#include "modules/audio_coding/neteq/tools/neteq_input.h"
#include "modules/audio_coding/neteq/tools/packet_source.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
namespace webrtc {
class RtpHeaderParser;
namespace test {
class Packet;
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 std::unique_ptr<RtcEventLogSource> CreateFromFile(
absl::string_view 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(
absl::string_view file_contents,
absl::optional<uint32_t> ssrc_filter);
virtual ~RtcEventLogSource();
RtcEventLogSource(const RtcEventLogSource&) = delete;
RtcEventLogSource& operator=(const RtcEventLogSource&) = delete;
std::unique_ptr<Packet> NextPacket() override;
// Returns the timestamp of the next audio output event, in milliseconds. The
// maximum value of int64_t is returned if there are no more audio output
// events available.
int64_t NextAudioOutputEventMs();
// Returns the next NetEq set minimum delay event if available.
absl::optional<NetEqInput::SetMinimumDelayInfo> NextSetMinimumDelayEvent();
private:
RtcEventLogSource();
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;
std::vector<int64_t> audio_outputs_;
size_t audio_output_index_ = 0;
std::vector<NetEqInput::SetMinimumDelayInfo> minimum_delay_;
size_t minimum_delay_index_ = 0;
};
} // namespace test
} // namespace webrtc
#endif // MODULES_AUDIO_CODING_NETEQ_TOOLS_RTC_EVENT_LOG_SOURCE_H_

View File

@ -18,6 +18,7 @@
#include "modules/audio_coding/neteq/tools/audio_sink.h"
#include "modules/audio_coding/neteq/tools/fake_decode_from_file.h"
#include "modules/audio_coding/neteq/tools/neteq_delay_analyzer.h"
#include "modules/audio_coding/neteq/tools/neteq_event_log_input.h"
#include "modules/audio_coding/neteq/tools/neteq_replacement_input.h"
#include "modules/audio_coding/neteq/tools/neteq_test.h"
#include "modules/audio_coding/neteq/tools/resample_input_audio_file.h"
@ -176,114 +177,6 @@ void CreateAudioEncoderNumChannelsGraph(const ParsedRtcEventLog& parsed_log,
plot->SetTitle("Reported audio encoder number of channels");
}
class NetEqStreamInput : public test::NetEqInput {
public:
// Does not take any ownership, and all pointers must refer to valid objects
// that outlive the one constructed.
NetEqStreamInput(const std::vector<LoggedRtpPacketIncoming>* packet_stream,
const std::vector<LoggedAudioPlayoutEvent>* output_events,
const std::vector<LoggedNetEqSetMinimumDelayEvent>*
neteq_set_minimum_delay_events,
absl::optional<int64_t> end_time_ms)
: packet_stream_(*packet_stream),
packet_stream_it_(packet_stream_.begin()),
output_events_it_(output_events->begin()),
output_events_end_(output_events->end()),
neteq_set_minimum_delay_events_it_(
neteq_set_minimum_delay_events->begin()),
neteq_set_minimum_delay_events_end_(
neteq_set_minimum_delay_events->end()),
end_time_ms_(end_time_ms) {
RTC_DCHECK(packet_stream);
RTC_DCHECK(output_events);
}
absl::optional<int64_t> NextPacketTime() const override {
if (packet_stream_it_ == packet_stream_.end()) {
return absl::nullopt;
}
if (end_time_ms_ && packet_stream_it_->rtp.log_time_ms() > *end_time_ms_) {
return absl::nullopt;
}
return packet_stream_it_->rtp.log_time_ms();
}
absl::optional<int64_t> NextOutputEventTime() const override {
if (output_events_it_ == output_events_end_) {
return absl::nullopt;
}
if (end_time_ms_ && output_events_it_->log_time_ms() > *end_time_ms_) {
return absl::nullopt;
}
return output_events_it_->log_time_ms();
}
absl::optional<SetMinimumDelayInfo> NextSetMinimumDelayInfo() const override {
if (neteq_set_minimum_delay_events_it_ ==
neteq_set_minimum_delay_events_end_) {
return absl::nullopt;
}
if (end_time_ms_ &&
neteq_set_minimum_delay_events_it_->log_time_ms() > *end_time_ms_) {
return absl::nullopt;
}
return SetMinimumDelayInfo(
neteq_set_minimum_delay_events_it_->log_time_ms(),
neteq_set_minimum_delay_events_it_->minimum_delay_ms);
}
std::unique_ptr<PacketData> PopPacket() override {
if (packet_stream_it_ == packet_stream_.end()) {
return std::unique_ptr<PacketData>();
}
std::unique_ptr<PacketData> packet_data(new PacketData());
packet_data->header = packet_stream_it_->rtp.header;
packet_data->time_ms = packet_stream_it_->rtp.log_time_ms();
// This is a header-only "dummy" packet. Set the payload to all zeros, with
// length according to the virtual length.
packet_data->payload.SetSize(packet_stream_it_->rtp.total_length -
packet_stream_it_->rtp.header_length);
std::fill_n(packet_data->payload.data(), packet_data->payload.size(), 0);
++packet_stream_it_;
return packet_data;
}
void AdvanceOutputEvent() override {
if (output_events_it_ != output_events_end_) {
++output_events_it_;
}
}
void AdvanceSetMinimumDelay() override {
if (neteq_set_minimum_delay_events_it_ !=
neteq_set_minimum_delay_events_end_) {
++neteq_set_minimum_delay_events_it_;
}
}
bool ended() const override { return !NextEventTime(); }
absl::optional<RTPHeader> NextHeader() const override {
if (packet_stream_it_ == packet_stream_.end()) {
return absl::nullopt;
}
return packet_stream_it_->rtp.header;
}
private:
const std::vector<LoggedRtpPacketIncoming>& packet_stream_;
std::vector<LoggedRtpPacketIncoming>::const_iterator packet_stream_it_;
std::vector<LoggedAudioPlayoutEvent>::const_iterator output_events_it_;
const std::vector<LoggedAudioPlayoutEvent>::const_iterator output_events_end_;
std::vector<LoggedNetEqSetMinimumDelayEvent>::const_iterator
neteq_set_minimum_delay_events_it_;
const std::vector<LoggedNetEqSetMinimumDelayEvent>::const_iterator
neteq_set_minimum_delay_events_end_;
const absl::optional<int64_t> end_time_ms_;
};
namespace {
// Factory to create a "replacement decoder" that produces the decoded audio
@ -323,16 +216,12 @@ class ReplacementAudioDecoderFactory : public AudioDecoderFactory {
// the test and returns the NetEqDelayAnalyzer object that was used to
// instrument the test.
std::unique_ptr<test::NetEqStatsGetter> CreateNetEqTestAndRun(
const std::vector<LoggedRtpPacketIncoming>* packet_stream,
const std::vector<LoggedAudioPlayoutEvent>* output_events,
const std::vector<LoggedNetEqSetMinimumDelayEvent>*
neteq_set_minimum_delay_events,
absl::optional<int64_t> end_time_ms,
ParsedRtcEventLog parsed_log,
uint32_t ssrc,
const std::string& replacement_file_name,
int file_sample_rate_hz) {
std::unique_ptr<test::NetEqInput> input(
new NetEqStreamInput(packet_stream, output_events,
neteq_set_minimum_delay_events, end_time_ms));
std::unique_ptr<test::NetEqInput> input =
test::CreateNetEqEventLogInput(parsed_log, ssrc);
constexpr int kReplacementPt = 127;
std::set<uint8_t> cn_types;
@ -373,47 +262,10 @@ NetEqStatsGetterMap SimulateNetEq(const ParsedRtcEventLog& parsed_log,
const std::string& replacement_file_name,
int file_sample_rate_hz) {
NetEqStatsGetterMap neteq_stats;
for (const auto& stream : parsed_log.incoming_rtp_packets_by_ssrc()) {
const uint32_t ssrc = stream.ssrc;
if (!IsAudioSsrc(parsed_log, kIncomingPacket, ssrc))
continue;
const std::vector<LoggedRtpPacketIncoming>* audio_packets =
&stream.incoming_packets;
if (audio_packets == nullptr) {
// No incoming audio stream found.
continue;
}
RTC_DCHECK(neteq_stats.find(ssrc) == neteq_stats.end());
std::map<uint32_t, std::vector<LoggedAudioPlayoutEvent>>::const_iterator
output_events_it = parsed_log.audio_playout_events().find(ssrc);
if (output_events_it == parsed_log.audio_playout_events().end()) {
// Could not find output events with SSRC matching the input audio stream.
// Using the first available stream of output events.
output_events_it = parsed_log.audio_playout_events().cbegin();
}
const auto neteq_set_minimum_delay_events_it =
parsed_log.neteq_set_minimum_delay_events().find(ssrc);
std::vector<LoggedNetEqSetMinimumDelayEvent>
empty_neteq_set_minimum_delay_event;
const std::vector<LoggedNetEqSetMinimumDelayEvent>&
neteq_set_minimum_delay_events =
neteq_set_minimum_delay_events_it ==
parsed_log.neteq_set_minimum_delay_events().cend()
? empty_neteq_set_minimum_delay_event
: neteq_set_minimum_delay_events_it->second;
int64_t end_time_ms = parsed_log.first_log_segment().stop_time_ms();
neteq_stats[ssrc] =
CreateNetEqTestAndRun(audio_packets, &output_events_it->second,
&neteq_set_minimum_delay_events, end_time_ms,
replacement_file_name, file_sample_rate_hz);
for (uint32_t ssrc : parsed_log.incoming_audio_ssrcs()) {
neteq_stats[ssrc] = CreateNetEqTestAndRun(
parsed_log, ssrc, replacement_file_name, file_sample_rate_hz);
}
return neteq_stats;
}