Unifying the handling of the events in NetEqInput.

Bug: webrtc:14763
Change-Id: I9615a9ce41c9b577c4ebd4cdcc9885bfbc5dac48
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/293040
Reviewed-by: Sam Zackrisson <saza@webrtc.org>
Commit-Queue: Jesus de Vicente Pena <devicentepena@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Reviewed-by: Jakob Ivarsson‎ <jakobi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#39706}
This commit is contained in:
Jesús de Vicente Peña 2023-03-28 16:59:09 +02:00 committed by WebRTC LUCI CQ
parent 58b049373e
commit d93b7b91e0
22 changed files with 484 additions and 492 deletions

View File

@ -119,34 +119,26 @@ class LossyInput : public NetEqInput {
burst_length_(burst_length), burst_length_(burst_length),
input_(std::move(input)) {} input_(std::move(input)) {}
absl::optional<int64_t> NextPacketTime() const override { absl::optional<int64_t> NextEventTime() const {
return input_->NextPacketTime(); return input_->NextEventTime();
} }
absl::optional<int64_t> NextOutputEventTime() const override { std::unique_ptr<Event> PopEvent() override {
return input_->NextOutputEventTime(); std::unique_ptr<Event> event = input_->PopEvent();
} if (event == nullptr || event->type() != Event::Type::kPacketData) {
return event;
absl::optional<SetMinimumDelayInfo> NextSetMinimumDelayInfo() const override {
return input_->NextSetMinimumDelayInfo();
}
std::unique_ptr<PacketData> PopPacket() override {
if (loss_cadence_ != 0 && (++count_ % loss_cadence_) == 0) {
// Pop `burst_length_` packets to create the loss.
auto packet_to_return = input_->PopPacket();
for (int i = 0; i < burst_length_; i++) {
input_->PopPacket();
}
return packet_to_return;
} }
return input_->PopPacket(); if (loss_cadence_ != 0 && remaining_losses_ == 0 &&
} (++count_ % loss_cadence_) == 0) {
// Pop `burst_length_` packets to create the loss.
void AdvanceOutputEvent() override { return input_->AdvanceOutputEvent(); } remaining_losses_ = burst_length_;
} else {
void AdvanceSetMinimumDelay() override { if (remaining_losses_ != 0) {
return input_->AdvanceSetMinimumDelay(); remaining_losses_--;
return PopEvent();
}
}
return event;
} }
bool ended() const override { return input_->ended(); } bool ended() const override { return input_->ended(); }
@ -158,6 +150,7 @@ class LossyInput : public NetEqInput {
private: private:
const int loss_cadence_; const int loss_cadence_;
const int burst_length_; const int burst_length_;
int remaining_losses_ = 0;
int count_ = 0; int count_ = 0;
const std::unique_ptr<NetEqInput> input_; const std::unique_ptr<NetEqInput> input_;
}; };

View File

@ -988,9 +988,9 @@ TEST(NetEqNoTimeStretchingMode, RunTest) {
{5, kRtpExtensionTransportSequenceNumber}, {5, kRtpExtensionTransportSequenceNumber},
{7, kRtpExtensionVideoContentType}, {7, kRtpExtensionVideoContentType},
{8, kRtpExtensionVideoTiming}}; {8, kRtpExtensionVideoTiming}};
std::unique_ptr<NetEqInput> input(new NetEqRtpDumpInput( std::unique_ptr<NetEqInput> input = std::make_unique<NetEqPacketSourceInput>(
webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp"), webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp"),
rtp_ext_map, absl::nullopt /*No SSRC filter*/)); rtp_ext_map, absl::nullopt /*No SSRC filter*/);
std::unique_ptr<TimeLimitedNetEqInput> input_time_limit( std::unique_ptr<TimeLimitedNetEqInput> input_time_limit(
new TimeLimitedNetEqInput(std::move(input), 20000)); new TimeLimitedNetEqInput(std::move(input), 20000));
std::unique_ptr<AudioSink> output(new VoidAudioSink); std::unique_ptr<AudioSink> output(new VoidAudioSink);

View File

@ -24,36 +24,19 @@ EncodeNetEqInput::EncodeNetEqInput(std::unique_ptr<Generator> generator,
: generator_(std::move(generator)), : generator_(std::move(generator)),
encoder_(std::move(encoder)), encoder_(std::move(encoder)),
input_duration_ms_(input_duration_ms) { input_duration_ms_(input_duration_ms) {
CreatePacket(); event_ = GetNextEvent();
} }
EncodeNetEqInput::~EncodeNetEqInput() = default; EncodeNetEqInput::~EncodeNetEqInput() = default;
absl::optional<int64_t> EncodeNetEqInput::NextPacketTime() const { std::unique_ptr<NetEqInput::Event> EncodeNetEqInput::PopEvent() {
RTC_DCHECK(packet_data_); std::unique_ptr<NetEqInput::Event> event_to_return = std::move(event_);
return static_cast<int64_t>(packet_data_->time_ms); event_ = GetNextEvent();
} return event_to_return;
absl::optional<int64_t> EncodeNetEqInput::NextOutputEventTime() const {
return next_output_event_ms_;
}
std::unique_ptr<NetEqInput::PacketData> EncodeNetEqInput::PopPacket() {
RTC_DCHECK(packet_data_);
// Grab the packet to return...
std::unique_ptr<PacketData> packet_to_return = std::move(packet_data_);
// ... and line up the next packet for future use.
CreatePacket();
return packet_to_return;
}
void EncodeNetEqInput::AdvanceOutputEvent() {
next_output_event_ms_ += kOutputPeriodMs;
} }
bool EncodeNetEqInput::ended() const { bool EncodeNetEqInput::ended() const {
return next_output_event_ms_ > input_duration_ms_; return next_output_event_ms_ > input_duration_ms_ + kOutputPeriodMs;
} }
absl::optional<RTPHeader> EncodeNetEqInput::NextHeader() const { absl::optional<RTPHeader> EncodeNetEqInput::NextHeader() const {
@ -61,9 +44,23 @@ absl::optional<RTPHeader> EncodeNetEqInput::NextHeader() const {
return packet_data_->header; return packet_data_->header;
} }
std::unique_ptr<NetEqInput::Event> EncodeNetEqInput::GetNextEvent() {
std::unique_ptr<NetEqInput::Event> event;
if (packet_data_ == nullptr) {
CreatePacket();
}
if (next_output_event_ms_ < packet_data_->timestamp_ms_) {
event = std::make_unique<GetAudio>(next_output_event_ms_);
next_output_event_ms_ += kOutputPeriodMs;
return event;
}
event = std::move(packet_data_);
CreatePacket();
return event;
}
void EncodeNetEqInput::CreatePacket() { void EncodeNetEqInput::CreatePacket() {
// Create a new PacketData object. // Create a new PacketData object.
RTC_DCHECK(!packet_data_);
packet_data_.reset(new NetEqInput::PacketData); packet_data_.reset(new NetEqInput::PacketData);
RTC_DCHECK_EQ(packet_data_->payload.size(), 0); RTC_DCHECK_EQ(packet_data_->payload.size(), 0);
@ -86,7 +83,7 @@ void EncodeNetEqInput::CreatePacket() {
packet_data_->header.timestamp = info.encoded_timestamp; packet_data_->header.timestamp = info.encoded_timestamp;
packet_data_->header.payloadType = info.payload_type; packet_data_->header.payloadType = info.payload_type;
packet_data_->header.sequenceNumber = sequence_number_++; packet_data_->header.sequenceNumber = sequence_number_++;
packet_data_->time_ms = next_packet_time_ms_; packet_data_->timestamp_ms_ = next_packet_time_ms_;
next_packet_time_ms_ += num_blocks * kOutputPeriodMs; next_packet_time_ms_ += num_blocks * kOutputPeriodMs;
} }

View File

@ -37,28 +37,24 @@ class EncodeNetEqInput : public NetEqInput {
int64_t input_duration_ms); int64_t input_duration_ms);
~EncodeNetEqInput() override; ~EncodeNetEqInput() override;
absl::optional<int64_t> NextPacketTime() const override; std::unique_ptr<Event> PopEvent() override;
absl::optional<int64_t> NextOutputEventTime() const override;
absl::optional<SetMinimumDelayInfo> NextSetMinimumDelayInfo() const override {
return absl::nullopt;
}
std::unique_ptr<PacketData> PopPacket() override;
void AdvanceOutputEvent() override;
void AdvanceSetMinimumDelay() override {}
bool ended() const override; bool ended() const override;
absl::optional<RTPHeader> NextHeader() const override; absl::optional<RTPHeader> NextHeader() const override;
absl::optional<int64_t> NextEventTime() const override {
if (event_) {
return event_->timestamp_ms();
}
return absl::nullopt;
}
private: private:
static constexpr int64_t kOutputPeriodMs = 10; static constexpr int64_t kOutputPeriodMs = 10;
void CreatePacket(); void CreatePacket();
std::unique_ptr<Event> GetNextEvent();
std::unique_ptr<Generator> generator_; std::unique_ptr<Generator> generator_;
std::unique_ptr<AudioEncoder> encoder_; std::unique_ptr<AudioEncoder> encoder_;
@ -68,6 +64,7 @@ class EncodeNetEqInput : public NetEqInput {
int64_t next_packet_time_ms_ = 0; int64_t next_packet_time_ms_ = 0;
int64_t next_output_event_ms_ = 0; int64_t next_output_event_ms_ = 0;
const int64_t input_duration_ms_; const int64_t input_duration_ms_;
std::unique_ptr<Event> event_;
}; };
} // namespace test } // namespace test

View File

@ -27,37 +27,27 @@ InitialPacketInserterNetEqInput::InitialPacketInserterNetEqInput(
packets_to_insert_(number_of_initial_packets), packets_to_insert_(number_of_initial_packets),
sample_rate_hz_(sample_rate_hz) {} sample_rate_hz_(sample_rate_hz) {}
absl::optional<int64_t> InitialPacketInserterNetEqInput::NextPacketTime() absl::optional<int64_t> InitialPacketInserterNetEqInput::NextEventTime() const {
const { return source_->NextEventTime();
return source_->NextPacketTime();
} }
absl::optional<int64_t> InitialPacketInserterNetEqInput::NextOutputEventTime() std::unique_ptr<NetEqInput::Event> InitialPacketInserterNetEqInput::PopEvent() {
const { std::unique_ptr<NetEqInput::Event> event;
return source_->NextOutputEventTime();
}
absl::optional<NetEqInput::SetMinimumDelayInfo>
InitialPacketInserterNetEqInput::NextSetMinimumDelayInfo() const {
return source_->NextSetMinimumDelayInfo();
}
std::unique_ptr<InitialPacketInserterNetEqInput::PacketData>
InitialPacketInserterNetEqInput::PopPacket() {
if (!first_packet_) { if (!first_packet_) {
first_packet_ = source_->PopPacket(); event = source_->PopEvent();
if (!first_packet_) { if (event == nullptr || event->type() != Event::Type::kPacketData) {
// The source has no packets, so we should not insert any dummy packets. return event;
packets_to_insert_ = 0;
} }
first_packet_ = std::move(event);
} }
if (packets_to_insert_ > 0) { if (packets_to_insert_ > 0) {
RTC_CHECK(first_packet_); RTC_CHECK(first_packet_);
auto dummy_packet = std::unique_ptr<PacketData>(new PacketData()); std::unique_ptr<PacketData> dummy_packet = std::make_unique<PacketData>();
dummy_packet->header = first_packet_->header; PacketData& first_packet = static_cast<PacketData&>(*first_packet_);
dummy_packet->payload = rtc::Buffer(first_packet_->payload.data(), dummy_packet->header = first_packet.header;
first_packet_->payload.size()); dummy_packet->payload =
dummy_packet->time_ms = first_packet_->time_ms; rtc::Buffer(first_packet.payload.data(), first_packet.payload.size());
dummy_packet->timestamp_ms_ = first_packet.timestamp_ms_;
dummy_packet->header.sequenceNumber -= packets_to_insert_; dummy_packet->header.sequenceNumber -= packets_to_insert_;
// This assumes 20ms per packet. // This assumes 20ms per packet.
dummy_packet->header.timestamp -= dummy_packet->header.timestamp -=
@ -65,15 +55,7 @@ InitialPacketInserterNetEqInput::PopPacket() {
packets_to_insert_--; packets_to_insert_--;
return dummy_packet; return dummy_packet;
} }
return source_->PopPacket(); return source_->PopEvent();
}
void InitialPacketInserterNetEqInput::AdvanceSetMinimumDelay() {
source_->AdvanceSetMinimumDelay();
}
void InitialPacketInserterNetEqInput::AdvanceOutputEvent() {
source_->AdvanceOutputEvent();
} }
bool InitialPacketInserterNetEqInput::ended() const { bool InitialPacketInserterNetEqInput::ended() const {

View File

@ -27,20 +27,16 @@ class InitialPacketInserterNetEqInput final : public NetEqInput {
InitialPacketInserterNetEqInput(std::unique_ptr<NetEqInput> source, InitialPacketInserterNetEqInput(std::unique_ptr<NetEqInput> source,
int number_of_initial_packets, int number_of_initial_packets,
int sample_rate_hz); int sample_rate_hz);
absl::optional<int64_t> NextPacketTime() const override; std::unique_ptr<Event> PopEvent() override;
absl::optional<int64_t> NextOutputEventTime() const override;
absl::optional<SetMinimumDelayInfo> NextSetMinimumDelayInfo() const override;
std::unique_ptr<PacketData> PopPacket() override;
void AdvanceOutputEvent() override;
void AdvanceSetMinimumDelay() override;
bool ended() const override; bool ended() const override;
absl::optional<RTPHeader> NextHeader() const override; absl::optional<RTPHeader> NextHeader() const override;
absl::optional<int64_t> NextEventTime() const override;
private: private:
const std::unique_ptr<NetEqInput> source_; const std::unique_ptr<NetEqInput> source_;
int packets_to_insert_; int packets_to_insert_;
const int sample_rate_hz_; const int sample_rate_hz_;
std::unique_ptr<PacketData> first_packet_; std::unique_ptr<Event> first_packet_;
}; };
} // namespace test } // namespace test

View File

@ -87,8 +87,8 @@ void PrintDelays(const NetEqDelayAnalyzer::Delays& delays,
void NetEqDelayAnalyzer::AfterInsertPacket( void NetEqDelayAnalyzer::AfterInsertPacket(
const test::NetEqInput::PacketData& packet, const test::NetEqInput::PacketData& packet,
NetEq* neteq) { NetEq* neteq) {
data_.insert( data_.insert(std::make_pair(packet.header.timestamp,
std::make_pair(packet.header.timestamp, TimingData(packet.time_ms))); TimingData(packet.timestamp_ms())));
ssrcs_.insert(packet.header.ssrc); ssrcs_.insert(packet.header.ssrc);
payload_types_.insert(packet.header.payloadType); payload_types_.insert(packet.header.payloadType);
} }

View File

@ -42,36 +42,88 @@ NetEqEventLogInput* NetEqEventLogInput::CreateFromString(
return new NetEqEventLogInput(std::move(event_log_src)); return new NetEqEventLogInput(std::move(event_log_src));
} }
absl::optional<int64_t> NetEqEventLogInput::NextOutputEventTime() const { std::unique_ptr<NetEqInput::Event> NetEqEventLogInput::PopEvent() {
return next_output_event_ms_; std::unique_ptr<NetEqInput::Event> event_to_return = std::move(event_);
event_ = GetNextEvent();
return event_to_return;
} }
absl::optional<NetEqInput::SetMinimumDelayInfo> absl::optional<RTPHeader> NetEqEventLogInput::NextHeader() const {
NetEqEventLogInput::NextSetMinimumDelayInfo() const { return packet_ ? absl::optional<RTPHeader>(packet_->header()) : absl::nullopt;
return next_minimum_delay_event_info_;
} }
void NetEqEventLogInput::AdvanceOutputEvent() { absl::optional<int64_t> NetEqEventLogInput::NextOutputEventTime() {
next_output_event_ms_ = source_->NextAudioOutputEventMs(); absl::optional<int64_t> next_output_event_ms;
if (*next_output_event_ms_ == std::numeric_limits<int64_t>::max()) { next_output_event_ms = source_->NextAudioOutputEventMs();
next_output_event_ms_ = absl::nullopt; if (*next_output_event_ms == std::numeric_limits<int64_t>::max()) {
next_output_event_ms = absl::nullopt;
} }
return next_output_event_ms;
} }
void NetEqEventLogInput::AdvanceSetMinimumDelay() { std::unique_ptr<NetEqInput::Event> NetEqEventLogInput::CreatePacketEvent() {
next_minimum_delay_event_info_ = source_->NextSetMinimumDelayEvent(); std::unique_ptr<PacketData> packet_data = std::make_unique<PacketData>();
packet_data->header = packet_->header();
if (packet_->payload_length_bytes() == 0 &&
packet_->virtual_payload_length_bytes() > 0) {
// 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_->virtual_payload_length_bytes());
std::fill_n(packet_data->payload.data(), packet_data->payload.size(), 0);
} else {
packet_data->payload.SetData(packet_->payload(),
packet_->payload_length_bytes());
}
packet_data->timestamp_ms_ = packet_->time_ms();
packet_ = source_->NextPacket();
return packet_data;
} }
PacketSource* NetEqEventLogInput::source() { std::unique_ptr<NetEqInput::Event> NetEqEventLogInput::CreateOutputEvent() {
return source_.get(); std::unique_ptr<NetEqInput::Event> event =
std::make_unique<NetEqInput::GetAudio>(next_output_event_ms_.value());
next_output_event_ms_ = NextOutputEventTime();
return event;
}
std::unique_ptr<NetEqInput::Event>
NetEqEventLogInput::CreateSetMinimumDelayEvent() {
std::unique_ptr<NetEqInput::Event> event =
std::make_unique<NetEqInput::SetMinimumDelay>(
next_minimum_delay_event_.value());
next_minimum_delay_event_ = source_->NextSetMinimumDelayEvent();
return event;
}
std::unique_ptr<NetEqInput::Event> NetEqEventLogInput::GetNextEvent() {
std::unique_ptr<NetEqInput::Event> event;
int64_t packet_time_ms = packet_ ? static_cast<int64_t>(packet_->time_ms())
: std::numeric_limits<int64_t>::max();
int64_t output_time_ms = next_output_event_ms_.has_value()
? next_output_event_ms_.value()
: std::numeric_limits<int64_t>::max();
int64_t minimum_delay_ms = next_minimum_delay_event_.has_value()
? next_minimum_delay_event_->timestamp_ms()
: std::numeric_limits<int64_t>::max();
if (packet_ && packet_time_ms <= minimum_delay_ms &&
packet_time_ms <= output_time_ms) {
event = CreatePacketEvent();
} else if (next_minimum_delay_event_.has_value() &&
minimum_delay_ms <= output_time_ms) {
event = CreateSetMinimumDelayEvent();
} else if (next_output_event_ms_.has_value()) {
event = CreateOutputEvent();
}
return event;
} }
NetEqEventLogInput::NetEqEventLogInput( NetEqEventLogInput::NetEqEventLogInput(
std::unique_ptr<RtcEventLogSource> source) std::unique_ptr<RtcEventLogSource> source)
: source_(std::move(source)) { : source_(std::move(source)) {
LoadNextPacket(); packet_ = source_->NextPacket();
AdvanceOutputEvent(); next_minimum_delay_event_ = source_->NextSetMinimumDelayEvent();
AdvanceSetMinimumDelay(); next_output_event_ms_ = NextOutputEventTime();
event_ = GetNextEvent();
} }
} // namespace test } // namespace test

View File

@ -24,9 +24,8 @@ namespace test {
class RtcEventLogSource; class RtcEventLogSource;
// Implementation of NetEqPacketSourceInput to be used with an // Implementation of a NetEqInput from an RtcEventLogSource.
// RtcEventLogSource. class NetEqEventLogInput final : public NetEqInput {
class NetEqEventLogInput final : public NetEqPacketSourceInput {
public: public:
static NetEqEventLogInput* CreateFromFile( static NetEqEventLogInput* CreateFromFile(
absl::string_view file_name, absl::string_view file_name,
@ -35,18 +34,31 @@ class NetEqEventLogInput final : public NetEqPacketSourceInput {
absl::string_view file_contents, absl::string_view file_contents,
absl::optional<uint32_t> ssrc_filter); absl::optional<uint32_t> ssrc_filter);
absl::optional<int64_t> NextOutputEventTime() const override; absl::optional<int64_t> NextEventTime() const override {
absl::optional<SetMinimumDelayInfo> NextSetMinimumDelayInfo() const override; if (event_) {
void AdvanceOutputEvent() override; return event_->timestamp_ms();
void AdvanceSetMinimumDelay() override; }
return absl::nullopt;
protected: }
PacketSource* source() override; std::unique_ptr<Event> PopEvent() override;
absl::optional<RTPHeader> NextHeader() const override;
bool ended() const override {
return !next_output_event_ms_ || packet_ == nullptr;
}
private: private:
NetEqEventLogInput(std::unique_ptr<RtcEventLogSource> source); NetEqEventLogInput(std::unique_ptr<RtcEventLogSource> source);
std::unique_ptr<Event> GetNextEvent();
std::unique_ptr<Event> CreatePacketEvent();
std::unique_ptr<Event> CreateOutputEvent();
std::unique_ptr<Event> CreateSetMinimumDelayEvent();
absl::optional<int64_t> NextOutputEventTime();
std::unique_ptr<RtcEventLogSource> source_; std::unique_ptr<RtcEventLogSource> source_;
absl::optional<SetMinimumDelayInfo> next_minimum_delay_event_info_; std::unique_ptr<Packet> packet_;
absl::optional<int64_t> next_output_event_ms_;
absl::optional<SetMinimumDelay> next_minimum_delay_event_;
std::unique_ptr<Event> event_;
}; };
} // namespace test } // namespace test

View File

@ -22,7 +22,7 @@ std::string NetEqInput::PacketData::ToString() const {
rtc::StringBuilder ss; rtc::StringBuilder ss;
ss << "{" ss << "{"
"time_ms: " "time_ms: "
<< static_cast<int64_t>(time_ms) << static_cast<int64_t>(timestamp_ms_)
<< ", " << ", "
"header: {" "header: {"
"pt: " "pt: "
@ -50,46 +50,24 @@ TimeLimitedNetEqInput::TimeLimitedNetEqInput(std::unique_ptr<NetEqInput> input,
TimeLimitedNetEqInput::~TimeLimitedNetEqInput() = default; TimeLimitedNetEqInput::~TimeLimitedNetEqInput() = default;
absl::optional<int64_t> TimeLimitedNetEqInput::NextPacketTime() const { std::unique_ptr<NetEqInput::Event> TimeLimitedNetEqInput::PopEvent() {
return ended_ ? absl::nullopt : input_->NextPacketTime(); std::unique_ptr<Event> event;
}
absl::optional<int64_t> TimeLimitedNetEqInput::NextOutputEventTime() const {
return ended_ ? absl::nullopt : input_->NextOutputEventTime();
}
absl::optional<NetEqInput::SetMinimumDelayInfo>
TimeLimitedNetEqInput::NextSetMinimumDelayInfo() const {
return ended_ ? absl::nullopt : input_->NextSetMinimumDelayInfo();
}
std::unique_ptr<NetEqInput::PacketData> TimeLimitedNetEqInput::PopPacket() {
if (ended_) { if (ended_) {
return std::unique_ptr<PacketData>(); return event;
} }
auto packet = input_->PopPacket(); event = input_->PopEvent();
MaybeSetEnded(); MaybeSetEnded();
return packet; return event;
}
void TimeLimitedNetEqInput::AdvanceOutputEvent() {
if (!ended_) {
input_->AdvanceOutputEvent();
MaybeSetEnded();
}
}
void TimeLimitedNetEqInput::AdvanceSetMinimumDelay() {
if (!ended_) {
input_->AdvanceSetMinimumDelay();
MaybeSetEnded();
}
} }
bool TimeLimitedNetEqInput::ended() const { bool TimeLimitedNetEqInput::ended() const {
return ended_ || input_->ended(); return ended_ || input_->ended();
} }
absl::optional<int64_t> TimeLimitedNetEqInput::NextEventTime() const {
return input_->NextEventTime();
}
absl::optional<RTPHeader> TimeLimitedNetEqInput::NextHeader() const { absl::optional<RTPHeader> TimeLimitedNetEqInput::NextHeader() const {
return ended_ ? absl::nullopt : input_->NextHeader(); return ended_ ? absl::nullopt : input_->NextHeader();
} }

View File

@ -26,74 +26,53 @@ namespace test {
// Interface class for input to the NetEqTest class. // Interface class for input to the NetEqTest class.
class NetEqInput { class NetEqInput {
public: public:
struct PacketData { class Event {
PacketData(); public:
~PacketData(); enum class Type { kPacketData, kGetAudio, kSetMinimumDelay };
std::string ToString() const; virtual Type type() = 0;
virtual int64_t timestamp_ms() const = 0;
RTPHeader header; virtual ~Event() = default;
rtc::Buffer payload;
int64_t time_ms;
}; };
struct SetMinimumDelayInfo { class PacketData : public Event {
SetMinimumDelayInfo(int64_t timestamp_ms_in, int delay_ms_in) public:
: timestamp_ms(timestamp_ms_in), delay_ms(delay_ms_in) {} PacketData();
int64_t timestamp_ms; ~PacketData();
int delay_ms; Type type() override { return Type::kPacketData; }
int64_t timestamp_ms() const override { return timestamp_ms_; }
std::string ToString() const;
RTPHeader header;
rtc::Buffer payload;
int64_t timestamp_ms_;
};
class SetMinimumDelay : public Event {
public:
SetMinimumDelay(int64_t timestamp_ms_in, int delay_ms_in)
: timestamp_ms_(timestamp_ms_in), delay_ms_(delay_ms_in) {}
Type type() override { return Type::kSetMinimumDelay; }
int64_t timestamp_ms() const override { return timestamp_ms_; }
int delay_ms() { return delay_ms_; }
private:
int64_t timestamp_ms_;
int delay_ms_;
};
class GetAudio : public Event {
public:
explicit GetAudio(int64_t timestamp_ms_in)
: timestamp_ms_(timestamp_ms_in) {}
Type type() override { return Type::kGetAudio; }
int64_t timestamp_ms() const override { return timestamp_ms_; }
private:
int64_t timestamp_ms_;
}; };
virtual ~NetEqInput() = default; virtual ~NetEqInput() = default;
// Returns at what time (in ms) NetEq::InsertPacket should be called next, or virtual std::unique_ptr<Event> PopEvent() = 0;
// empty if the source is out of packets.
virtual absl::optional<int64_t> NextPacketTime() const = 0;
// Returns at what time (in ms) NetEq::GetAudio should be called next, or
// empty if no more output events are available.
virtual absl::optional<int64_t> NextOutputEventTime() const = 0;
// Returns the information related to the next NetEq set minimum delay event
// if available.
virtual absl::optional<SetMinimumDelayInfo> NextSetMinimumDelayInfo()
const = 0;
// Returns the time (in ms) for the next event (packet, output or set minimum
// delay event) or empty if there are no more events.
absl::optional<int64_t> NextEventTime() const {
absl::optional<int64_t> next_event_time = NextPacketTime();
const auto next_output_time = NextOutputEventTime();
// Return the minimum of non-empty `a` and `b`, or empty if both are empty.
if (next_output_time) {
next_event_time = next_event_time ? std::min(next_event_time.value(),
next_output_time.value())
: next_output_time;
}
const auto next_neteq_minimum_delay = NextSetMinimumDelayInfo();
if (next_neteq_minimum_delay) {
next_event_time =
next_event_time
? std::min(next_event_time.value(),
next_neteq_minimum_delay.value().timestamp_ms)
: next_neteq_minimum_delay.value().timestamp_ms;
}
return next_event_time;
}
// Returns the next packet to be inserted into NetEq. The packet following the
// returned one is pre-fetched in the NetEqInput object, such that future
// calls to NextPacketTime() or NextHeader() will return information from that
// packet.
virtual std::unique_ptr<PacketData> PopPacket() = 0;
// Move to the next output event. This will make NextOutputEventTime() return
// a new value (potentially the same if several output events share the same
// time).
virtual void AdvanceOutputEvent() = 0;
// Move to the next NetEq set minimum delay. This will make
// `NextSetMinimumDelayInfo` return a new value.
virtual void AdvanceSetMinimumDelay() = 0;
// Returns true if the source has come to an end. An implementation must // Returns true if the source has come to an end. An implementation must
// eventually return true from this method, or the test will end up in an // eventually return true from this method, or the test will end up in an
@ -103,6 +82,10 @@ class NetEqInput {
// Returns the RTP header for the next packet, i.e., the packet that will be // Returns the RTP header for the next packet, i.e., the packet that will be
// delivered next by PopPacket(). // delivered next by PopPacket().
virtual absl::optional<RTPHeader> NextHeader() const = 0; virtual absl::optional<RTPHeader> NextHeader() const = 0;
// Returns the time (in ms) for the next event, or empty if both are out of
// events.
virtual absl::optional<int64_t> NextEventTime() const = 0;
}; };
// Wrapper class to impose a time limit on a NetEqInput object, typically // Wrapper class to impose a time limit on a NetEqInput object, typically
@ -112,12 +95,8 @@ class TimeLimitedNetEqInput : public NetEqInput {
public: public:
TimeLimitedNetEqInput(std::unique_ptr<NetEqInput> input, int64_t duration_ms); TimeLimitedNetEqInput(std::unique_ptr<NetEqInput> input, int64_t duration_ms);
~TimeLimitedNetEqInput() override; ~TimeLimitedNetEqInput() override;
absl::optional<int64_t> NextPacketTime() const override; absl::optional<int64_t> NextEventTime() const override;
absl::optional<int64_t> NextOutputEventTime() const override; std::unique_ptr<Event> PopEvent() override;
absl::optional<SetMinimumDelayInfo> NextSetMinimumDelayInfo() const override;
std::unique_ptr<PacketData> PopPacket() override;
void AdvanceOutputEvent() override;
void AdvanceSetMinimumDelay() override;
bool ended() const override; bool ended() const override;
absl::optional<RTPHeader> NextHeader() const override; absl::optional<RTPHeader> NextHeader() const override;

View File

@ -20,27 +20,45 @@
namespace webrtc { namespace webrtc {
namespace test { namespace test {
NetEqPacketSourceInput::NetEqPacketSourceInput() : next_output_event_ms_(0) {} NetEqPacketSourceInput::NetEqPacketSourceInput(
absl::string_view file_name,
const NetEqPacketSourceInput::RtpHeaderExtensionMap& hdr_ext_map,
absl::optional<uint32_t> ssrc_filter)
: next_output_event_ms_(0) {
std::unique_ptr<RtpFileSource> source(
RtpFileSource::Create(file_name, ssrc_filter));
for (const auto& ext_pair : hdr_ext_map) {
source->RegisterRtpHeaderExtension(ext_pair.second, ext_pair.first);
}
packet_source_ = std::move(source);
packet_ = packet_source_->NextPacket();
event_ = GetNextEvent();
}
absl::optional<int64_t> NetEqPacketSourceInput::NextPacketTime() const { std::unique_ptr<NetEqInput::Event> NetEqPacketSourceInput::PopEvent() {
return packet_ std::unique_ptr<Event> event_to_return = std::move(event_);
? absl::optional<int64_t>(static_cast<int64_t>(packet_->time_ms())) event_ = GetNextEvent();
: absl::nullopt; return event_to_return;
} }
absl::optional<RTPHeader> NetEqPacketSourceInput::NextHeader() const { absl::optional<RTPHeader> NetEqPacketSourceInput::NextHeader() const {
return packet_ ? absl::optional<RTPHeader>(packet_->header()) : absl::nullopt; if (packet_) {
} return packet_->header();
void NetEqPacketSourceInput::LoadNextPacket() {
packet_ = source()->NextPacket();
}
std::unique_ptr<NetEqInput::PacketData> NetEqPacketSourceInput::PopPacket() {
if (!packet_) {
return std::unique_ptr<PacketData>();
} }
std::unique_ptr<PacketData> packet_data(new PacketData); return absl::nullopt;
}
std::unique_ptr<NetEqInput::Event> NetEqPacketSourceInput::GetNextEvent() {
if (!packet_) {
return nullptr;
}
if (packet_->time_ms() > next_output_event_ms_) {
std::unique_ptr<NetEqInput::GetAudio> event =
std::make_unique<NetEqInput::GetAudio>(next_output_event_ms_);
next_output_event_ms_ += kOutputPeriodMs;
return event;
}
std::unique_ptr<PacketData> packet_data = std::make_unique<PacketData>();
packet_data->header = packet_->header(); packet_data->header = packet_->header();
if (packet_->payload_length_bytes() == 0 && if (packet_->payload_length_bytes() == 0 &&
packet_->virtual_payload_length_bytes() > 0) { packet_->virtual_payload_length_bytes() > 0) {
@ -52,39 +70,10 @@ std::unique_ptr<NetEqInput::PacketData> NetEqPacketSourceInput::PopPacket() {
packet_data->payload.SetData(packet_->payload(), packet_data->payload.SetData(packet_->payload(),
packet_->payload_length_bytes()); packet_->payload_length_bytes());
} }
packet_data->time_ms = packet_->time_ms(); packet_data->timestamp_ms_ = packet_->time_ms();
packet_ = packet_source_->NextPacket();
LoadNextPacket();
return packet_data; return packet_data;
} }
NetEqRtpDumpInput::NetEqRtpDumpInput(absl::string_view file_name,
const RtpHeaderExtensionMap& hdr_ext_map,
absl::optional<uint32_t> ssrc_filter)
: source_(RtpFileSource::Create(file_name, ssrc_filter)) {
for (const auto& ext_pair : hdr_ext_map) {
source_->RegisterRtpHeaderExtension(ext_pair.second, ext_pair.first);
}
LoadNextPacket();
}
absl::optional<int64_t> NetEqRtpDumpInput::NextOutputEventTime() const {
return next_output_event_ms_;
}
void NetEqRtpDumpInput::AdvanceOutputEvent() {
if (next_output_event_ms_) {
*next_output_event_ms_ += kOutputPeriodMs;
}
if (!NextPacketTime()) {
next_output_event_ms_ = absl::nullopt;
}
}
PacketSource* NetEqRtpDumpInput::source() {
return source_.get();
}
} // namespace test } // namespace test
} // namespace webrtc } // namespace webrtc

View File

@ -30,43 +30,29 @@ class NetEqPacketSourceInput : public NetEqInput {
public: public:
using RtpHeaderExtensionMap = std::map<int, webrtc::RTPExtensionType>; using RtpHeaderExtensionMap = std::map<int, webrtc::RTPExtensionType>;
NetEqPacketSourceInput(); NetEqPacketSourceInput(
absl::optional<int64_t> NextPacketTime() const override; absl::string_view file_name,
std::unique_ptr<PacketData> PopPacket() override; const NetEqPacketSourceInput::RtpHeaderExtensionMap& hdr_ext_map,
absl::optional<RTPHeader> NextHeader() const override; absl::optional<uint32_t> ssrc_filter);
bool ended() const override { return !next_output_event_ms_; }
protected: absl::optional<int64_t> NextEventTime() const override {
virtual PacketSource* source() = 0; if (event_) {
void LoadNextPacket(); return event_->timestamp_ms();
}
absl::optional<int64_t> next_output_event_ms_;
private:
std::unique_ptr<Packet> packet_;
};
// Implementation of NetEqPacketSourceInput to be used with an RtpFileSource.
class NetEqRtpDumpInput final : public NetEqPacketSourceInput {
public:
NetEqRtpDumpInput(absl::string_view file_name,
const RtpHeaderExtensionMap& hdr_ext_map,
absl::optional<uint32_t> ssrc_filter);
absl::optional<int64_t> NextOutputEventTime() const override;
absl::optional<SetMinimumDelayInfo> NextSetMinimumDelayInfo() const override {
return absl::nullopt; return absl::nullopt;
} }
void AdvanceOutputEvent() override; std::unique_ptr<Event> PopEvent() override;
void AdvanceSetMinimumDelay() override {} absl::optional<RTPHeader> NextHeader() const override;
bool ended() const override { return event_ == nullptr; }
protected:
PacketSource* source() override;
private: private:
static constexpr int64_t kOutputPeriodMs = 10; static constexpr int64_t kOutputPeriodMs = 10;
std::unique_ptr<Event> GetNextEvent();
std::unique_ptr<RtpFileSource> source_; std::unique_ptr<Packet> packet_;
std::unique_ptr<PacketSource> packet_source_;
int64_t next_output_event_ms_;
std::unique_ptr<Event> event_;
}; };
} // namespace test } // namespace test

View File

@ -26,46 +26,25 @@ NetEqReplacementInput::NetEqReplacementInput(
comfort_noise_types_(comfort_noise_types), comfort_noise_types_(comfort_noise_types),
forbidden_types_(forbidden_types) { forbidden_types_(forbidden_types) {
RTC_CHECK(source_); RTC_CHECK(source_);
packet_ = source_->PopPacket(); event_ = source_->PopEvent();
ReplacePacket(); ReplaceIfPacketEvent();
} }
absl::optional<int64_t> NetEqReplacementInput::NextPacketTime() const { std::unique_ptr<NetEqInput::Event> NetEqReplacementInput::PopEvent() {
return packet_ std::unique_ptr<NetEqInput::Event> event_to_return = std::move(event_);
? absl::optional<int64_t>(static_cast<int64_t>(packet_->time_ms))
: absl::nullopt;
}
absl::optional<int64_t> NetEqReplacementInput::NextOutputEventTime() const {
return source_->NextOutputEventTime();
}
absl::optional<NetEqInput::SetMinimumDelayInfo>
NetEqReplacementInput::NextSetMinimumDelayInfo() const {
return source_->NextSetMinimumDelayInfo();
}
std::unique_ptr<NetEqInput::PacketData> NetEqReplacementInput::PopPacket() {
std::unique_ptr<PacketData> to_return = std::move(packet_);
while (true) { while (true) {
packet_ = source_->PopPacket(); event_ = source_->PopEvent();
if (!packet_) if (event_ == nullptr || event_->type() != Event::Type::kPacketData) {
break; break;
if (packet_->payload.size() > packet_->header.paddingLength) { }
PacketData& packet = static_cast<PacketData&>(*event_);
if (packet.payload.size() > packet.header.paddingLength) {
// Not padding only. Good to go. Skip this packet otherwise. // Not padding only. Good to go. Skip this packet otherwise.
break; break;
} }
} }
ReplacePacket(); ReplaceIfPacketEvent();
return to_return; return event_to_return;
}
void NetEqReplacementInput::AdvanceOutputEvent() {
source_->AdvanceOutputEvent();
}
void NetEqReplacementInput::AdvanceSetMinimumDelay() {
source_->AdvanceSetMinimumDelay();
} }
bool NetEqReplacementInput::ended() const { bool NetEqReplacementInput::ended() const {
@ -76,36 +55,38 @@ absl::optional<RTPHeader> NetEqReplacementInput::NextHeader() const {
return source_->NextHeader(); return source_->NextHeader();
} }
void NetEqReplacementInput::ReplacePacket() { void NetEqReplacementInput::ReplaceIfPacketEvent() {
if (!source_->NextPacketTime()) { if (event_ == nullptr || event_->type() != Event::Type::kPacketData) {
// End of input. Cannot do proper replacement on the very last packet, so we
// delete it instead.
packet_.reset();
return; return;
} }
RTC_DCHECK(packet_); PacketData& packet = static_cast<PacketData&>(*event_);
RTC_CHECK_EQ(forbidden_types_.count(packet_->header.payloadType), 0) RTC_CHECK_EQ(forbidden_types_.count(packet.header.payloadType), 0)
<< "Payload type " << static_cast<int>(packet_->header.payloadType) << "Payload type " << static_cast<int>(packet.header.payloadType)
<< " is forbidden."; << " is forbidden.";
// Check if this packet is comfort noise. // Check if this packet is comfort noise.
if (comfort_noise_types_.count(packet_->header.payloadType) != 0) { if (comfort_noise_types_.count(packet.header.payloadType) != 0) {
// If CNG, simply insert a zero-energy one-byte payload. // If CNG, simply insert a zero-energy one-byte payload.
uint8_t cng_payload[1] = {127}; // Max attenuation of CNG. uint8_t cng_payload[1] = {127}; // Max attenuation of CNG.
packet_->payload.SetData(cng_payload); packet.payload.SetData(cng_payload);
return; return;
} }
absl::optional<RTPHeader> next_hdr = source_->NextHeader(); absl::optional<RTPHeader> next_hdr = source_->NextHeader();
if (!next_hdr) {
// End of input. Cannot do proper replacement on the very last packet, so we
// delete it instead.
event_ = nullptr;
return;
}
RTC_DCHECK(next_hdr); RTC_DCHECK(next_hdr);
uint8_t payload[12]; uint8_t payload[12];
RTC_DCHECK_LE(last_frame_size_timestamps_, 120 * 48); RTC_DCHECK_LE(last_frame_size_timestamps_, 120 * 48);
uint32_t input_frame_size_timestamps = last_frame_size_timestamps_; uint32_t input_frame_size_timestamps = last_frame_size_timestamps_;
const uint32_t timestamp_diff = const uint32_t timestamp_diff = next_hdr->timestamp - packet.header.timestamp;
next_hdr->timestamp - packet_->header.timestamp; if (next_hdr->sequenceNumber == packet.header.sequenceNumber + 1 &&
if (next_hdr->sequenceNumber == packet_->header.sequenceNumber + 1 &&
timestamp_diff <= 120 * 48) { timestamp_diff <= 120 * 48) {
// Packets are in order and the timestamp diff is less than 5760 samples. // Packets are in order and the timestamp diff is less than 5760 samples.
// Accept the timestamp diff as a valid frame size. // Accept the timestamp diff as a valid frame size.
@ -113,11 +94,11 @@ void NetEqReplacementInput::ReplacePacket() {
last_frame_size_timestamps_ = input_frame_size_timestamps; last_frame_size_timestamps_ = input_frame_size_timestamps;
} }
RTC_DCHECK_LE(input_frame_size_timestamps, 120 * 48); RTC_DCHECK_LE(input_frame_size_timestamps, 120 * 48);
FakeDecodeFromFile::PrepareEncoded(packet_->header.timestamp, FakeDecodeFromFile::PrepareEncoded(packet.header.timestamp,
input_frame_size_timestamps, input_frame_size_timestamps,
packet_->payload.size(), payload); packet.payload.size(), payload);
packet_->payload.SetData(payload); packet.payload.SetData(payload);
packet_->header.payloadType = replacement_payload_type_; packet.header.payloadType = replacement_payload_type_;
return; return;
} }

View File

@ -28,23 +28,24 @@ class NetEqReplacementInput : public NetEqInput {
const std::set<uint8_t>& comfort_noise_types, const std::set<uint8_t>& comfort_noise_types,
const std::set<uint8_t>& forbidden_types); const std::set<uint8_t>& forbidden_types);
absl::optional<int64_t> NextPacketTime() const override; absl::optional<int64_t> NextEventTime() const override {
absl::optional<int64_t> NextOutputEventTime() const override; if (event_) {
absl::optional<SetMinimumDelayInfo> NextSetMinimumDelayInfo() const override; return event_->timestamp_ms();
std::unique_ptr<PacketData> PopPacket() override; }
void AdvanceOutputEvent() override; return absl::nullopt;
void AdvanceSetMinimumDelay() override; }
std::unique_ptr<Event> PopEvent() override;
bool ended() const override; bool ended() const override;
absl::optional<RTPHeader> NextHeader() const override; absl::optional<RTPHeader> NextHeader() const override;
private: private:
void ReplacePacket(); void ReplaceIfPacketEvent();
std::unique_ptr<NetEqInput> source_; std::unique_ptr<NetEqInput> source_;
const uint8_t replacement_payload_type_; const uint8_t replacement_payload_type_;
const std::set<uint8_t> comfort_noise_types_; const std::set<uint8_t> comfort_noise_types_;
const std::set<uint8_t> forbidden_types_; const std::set<uint8_t> forbidden_types_;
std::unique_ptr<PacketData> packet_; // The next packet to deliver. std::unique_ptr<Event> event_; // The next event to deliver.
uint32_t last_frame_size_timestamps_ = 960; // Initial guess: 20 ms @ 48 kHz. uint32_t last_frame_size_timestamps_ = 960; // Initial guess: 20 ms @ 48 kHz.
}; };

View File

@ -107,25 +107,27 @@ NetEqTest::SimulationStepResult NetEqTest::RunToNextGetAudio() {
RTC_DCHECK(input_->NextEventTime()); RTC_DCHECK(input_->NextEventTime());
clock_.AdvanceTimeMilliseconds(*input_->NextEventTime() - time_now_ms); clock_.AdvanceTimeMilliseconds(*input_->NextEventTime() - time_now_ms);
time_now_ms = *input_->NextEventTime(); time_now_ms = *input_->NextEventTime();
std::unique_ptr<NetEqInput::Event> event = input_->PopEvent();
// Check if it is time to insert packet. // Check if it is time to insert packet.
if (input_->NextPacketTime() && time_now_ms >= *input_->NextPacketTime()) { RTC_CHECK(event);
std::unique_ptr<NetEqInput::PacketData> packet_data = input_->PopPacket(); if (event->type() == NetEqInput::Event::Type::kPacketData) {
RTC_CHECK(packet_data); NetEqInput::PacketData& packet_data =
static_cast<NetEqInput::PacketData&>(*event);
const size_t payload_data_length = const size_t payload_data_length =
packet_data->payload.size() - packet_data->header.paddingLength; packet_data.payload.size() - packet_data.header.paddingLength;
if (payload_data_length != 0) { if (payload_data_length != 0) {
int error = neteq_->InsertPacket( int error = neteq_->InsertPacket(
packet_data->header, packet_data.header,
rtc::ArrayView<const uint8_t>(packet_data->payload)); rtc::ArrayView<const uint8_t>(packet_data.payload));
if (error != NetEq::kOK && callbacks_.error_callback) { if (error != NetEq::kOK && callbacks_.error_callback) {
callbacks_.error_callback->OnInsertPacketError(*packet_data); callbacks_.error_callback->OnInsertPacketError(packet_data);
} }
if (callbacks_.post_insert_packet) { if (callbacks_.post_insert_packet) {
callbacks_.post_insert_packet->AfterInsertPacket(*packet_data, callbacks_.post_insert_packet->AfterInsertPacket(packet_data,
neteq_.get()); neteq_.get());
} }
} else { } else {
neteq_->InsertEmptyPacket(packet_data->header); neteq_->InsertEmptyPacket(packet_data.header);
} }
if (last_packet_time_ms_) { if (last_packet_time_ms_) {
current_state_.packet_iat_ms.push_back(time_now_ms - current_state_.packet_iat_ms.push_back(time_now_ms -
@ -137,20 +139,20 @@ NetEqTest::SimulationStepResult NetEqTest::RunToNextGetAudio() {
last_packet_time_ms_ ? (time_now_ms - *last_packet_time_ms_) : -1; last_packet_time_ms_ ? (time_now_ms - *last_packet_time_ms_) : -1;
const auto delta_timestamp = const auto delta_timestamp =
last_packet_timestamp_ last_packet_timestamp_
? (static_cast<int64_t>(packet_data->header.timestamp) - ? (static_cast<int64_t>(packet_data.header.timestamp) -
*last_packet_timestamp_) * *last_packet_timestamp_) *
1000 / sample_rate_hz_ 1000 / sample_rate_hz_
: -1; : -1;
const auto packet_size_bytes = const auto packet_size_bytes =
packet_data->payload.size() == 12 packet_data.payload.size() == 12
? ByteReader<uint32_t>::ReadLittleEndian( ? ByteReader<uint32_t>::ReadLittleEndian(
&packet_data->payload[8]) &packet_data.payload[8])
: -1; : -1;
*text_log_ << "Packet - wallclock: " << std::setw(5) << time_now_ms *text_log_ << "Packet - wallclock: " << std::setw(5) << time_now_ms
<< ", delta wc: " << std::setw(4) << delta_wallclock << ", delta wc: " << std::setw(4) << delta_wallclock
<< ", seq_no: " << packet_data->header.sequenceNumber << ", seq_no: " << packet_data.header.sequenceNumber
<< ", timestamp: " << std::setw(10) << ", timestamp: " << std::setw(10)
<< packet_data->header.timestamp << packet_data.header.timestamp
<< ", delta ts: " << std::setw(4) << delta_timestamp << ", delta ts: " << std::setw(4) << delta_timestamp
<< ", size: " << std::setw(5) << packet_size_bytes << ", size: " << std::setw(5) << packet_size_bytes
<< ", frame size: " << std::setw(3) << ", frame size: " << std::setw(3)
@ -160,19 +162,16 @@ NetEqTest::SimulationStepResult NetEqTest::RunToNextGetAudio() {
} }
last_packet_time_ms_ = absl::make_optional<int>(time_now_ms); last_packet_time_ms_ = absl::make_optional<int>(time_now_ms);
last_packet_timestamp_ = last_packet_timestamp_ =
absl::make_optional<uint32_t>(packet_data->header.timestamp); absl::make_optional<uint32_t>(packet_data.header.timestamp);
} }
if (input_->NextSetMinimumDelayInfo().has_value() && if (event->type() == NetEqInput::Event::Type::kSetMinimumDelay) {
time_now_ms >= input_->NextSetMinimumDelayInfo().value().timestamp_ms) {
neteq_->SetBaseMinimumDelayMs( neteq_->SetBaseMinimumDelayMs(
input_->NextSetMinimumDelayInfo().value().delay_ms); static_cast<NetEqInput::SetMinimumDelay&>(*event).delay_ms());
input_->AdvanceSetMinimumDelay();
} }
// Check if it is time to get output audio. // Check if it is time to get output audio.
if (input_->NextOutputEventTime() && if (event->type() == NetEqInput::Event::Type::kGetAudio) {
time_now_ms >= *input_->NextOutputEventTime()) {
if (callbacks_.get_audio_callback) { if (callbacks_.get_audio_callback) {
callbacks_.get_audio_callback->BeforeGetAudio(neteq_.get()); callbacks_.get_audio_callback->BeforeGetAudio(neteq_.get());
} }
@ -200,7 +199,6 @@ NetEqTest::SimulationStepResult NetEqTest::RunToNextGetAudio() {
out_frame.samples_per_channel_ * out_frame.num_channels_)); out_frame.samples_per_channel_ * out_frame.num_channels_));
} }
input_->AdvanceOutputEvent();
result.simulation_step_ms = result.simulation_step_ms =
input_->NextEventTime().value_or(time_now_ms) - start_time_ms; input_->NextEventTime().value_or(time_now_ms) - start_time_ms;
const auto operations_state = neteq_->GetOperationsAndState(); const auto operations_state = neteq_->GetOperationsAndState();
@ -271,8 +269,8 @@ NetEqTest::SimulationStepResult NetEqTest::RunToNextGetAudio() {
} }
} }
prev_lifetime_stats_ = lifetime_stats; prev_lifetime_stats_ = lifetime_stats;
const bool no_more_packets_to_decode = const bool no_more_events =
!input_->NextPacketTime() && !operations_state.next_packet_available; !input_->NextEventTime() && !operations_state.next_packet_available;
// End the simulation if the gap is too large. This indicates an issue // End the simulation if the gap is too large. This indicates an issue
// with the event log file. // with the event log file.
const bool simulation_step_too_large = result.simulation_step_ms > 1000; const bool simulation_step_too_large = result.simulation_step_ms > 1000;
@ -281,9 +279,8 @@ NetEqTest::SimulationStepResult NetEqTest::RunToNextGetAudio() {
// the simulation time, which can be a large distortion. // the simulation time, which can be a large distortion.
result.simulation_step_ms = 10; result.simulation_step_ms = 10;
} }
result.is_simulation_finished = simulation_step_too_large || result.is_simulation_finished =
no_more_packets_to_decode || simulation_step_too_large || no_more_events || input_->ended();
input_->ended();
prev_ops_state_ = operations_state; prev_ops_state_ = operations_state;
return result; return result;
} }

View File

@ -136,8 +136,8 @@ std::unique_ptr<NetEqTest> NetEqTestFactory::InitializeTestFromFile(
std::unique_ptr<NetEqInput> input; std::unique_ptr<NetEqInput> input;
if (RtpFileSource::ValidRtpDump(input_file_name) || if (RtpFileSource::ValidRtpDump(input_file_name) ||
RtpFileSource::ValidPcap(input_file_name)) { RtpFileSource::ValidPcap(input_file_name)) {
input.reset(new NetEqRtpDumpInput(input_file_name, rtp_ext_map, input = std::make_unique<NetEqPacketSourceInput>(
config.ssrc_filter)); input_file_name, rtp_ext_map, config.ssrc_filter);
} else { } else {
input.reset(NetEqEventLogInput::CreateFromFile(input_file_name, input.reset(NetEqEventLogInput::CreateFromFile(input_file_name,
config.ssrc_filter)); config.ssrc_filter));
@ -169,21 +169,17 @@ std::unique_ptr<NetEqTest> NetEqTestFactory::InitializeTest(
if (config.skip_get_audio_events > 0) { if (config.skip_get_audio_events > 0) {
std::cout << "Skipping " << config.skip_get_audio_events std::cout << "Skipping " << config.skip_get_audio_events
<< " get_audio events" << std::endl; << " get_audio events" << std::endl;
if (!input->NextPacketTime() || !input->NextOutputEventTime()) { if (!input->NextEventTime()) {
std::cerr << "No events found" << std::endl; std::cerr << "No events found" << std::endl;
return nullptr; return nullptr;
} }
for (int i = 0; i < config.skip_get_audio_events; i++) { for (int i = 0; i < config.skip_get_audio_events; i++) {
input->AdvanceOutputEvent(); std::unique_ptr<NetEqInput::Event> event = input->PopEvent();
if (!input->NextOutputEventTime()) { while (event && event->type() != NetEqInput::Event::Type::kGetAudio) {
std::cerr << "Not enough get_audio events found" << std::endl; event = input->PopEvent();
return nullptr;
} }
} if (event == nullptr) {
while (*input->NextPacketTime() < *input->NextOutputEventTime()) { std::cerr << "Not enough events found" << std::endl;
input->PopPacket();
if (!input->NextPacketTime()) {
std::cerr << "Not enough incoming packets found" << std::endl;
return nullptr; return nullptr;
} }
} }
@ -212,7 +208,10 @@ std::unique_ptr<NetEqTest> NetEqTestFactory::InitializeTest(
// types and SSRCs. // types and SSRCs.
discarded_pt_and_ssrc.emplace(first_rtp_header->payloadType, discarded_pt_and_ssrc.emplace(first_rtp_header->payloadType,
first_rtp_header->ssrc); first_rtp_header->ssrc);
input->PopPacket(); std::unique_ptr<NetEqInput::Event> event = input->PopEvent();
while (event && event->type() != NetEqInput::Event::Type::kPacketData) {
event = input->PopEvent();
}
} }
if (!discarded_pt_and_ssrc.empty()) { if (!discarded_pt_and_ssrc.empty()) {
std::cout << "Discarded initial packets with the following payload types " std::cout << "Discarded initial packets with the following payload types "

View File

@ -95,7 +95,7 @@ int64_t RtcEventLogSource::NextAudioOutputEventMs() {
return output_time_ms; return output_time_ms;
} }
absl::optional<NetEqInput::SetMinimumDelayInfo> absl::optional<NetEqInput::SetMinimumDelay>
RtcEventLogSource::NextSetMinimumDelayEvent() { RtcEventLogSource::NextSetMinimumDelayEvent() {
if (minimum_delay_index_ >= minimum_delay_.size()) { if (minimum_delay_index_ >= minimum_delay_.size()) {
return absl::nullopt; return absl::nullopt;

View File

@ -55,7 +55,7 @@ class RtcEventLogSource : public PacketSource {
int64_t NextAudioOutputEventMs(); int64_t NextAudioOutputEventMs();
// Returns the next NetEq set minimum delay event if available. // Returns the next NetEq set minimum delay event if available.
absl::optional<NetEqInput::SetMinimumDelayInfo> NextSetMinimumDelayEvent(); absl::optional<NetEqInput::SetMinimumDelay> NextSetMinimumDelayEvent();
private: private:
RtcEventLogSource(); RtcEventLogSource();
@ -67,7 +67,7 @@ class RtcEventLogSource : public PacketSource {
size_t rtp_packet_index_ = 0; size_t rtp_packet_index_ = 0;
std::vector<int64_t> audio_outputs_; std::vector<int64_t> audio_outputs_;
size_t audio_output_index_ = 0; size_t audio_output_index_ = 0;
std::vector<NetEqInput::SetMinimumDelayInfo> minimum_delay_; std::vector<NetEqInput::SetMinimumDelay> minimum_delay_;
size_t minimum_delay_index_ = 0; size_t minimum_delay_index_ = 0;
}; };

View File

@ -196,9 +196,52 @@ class NetEqStreamInput : public test::NetEqInput {
end_time_ms_(end_time_ms) { end_time_ms_(end_time_ms) {
RTC_DCHECK(packet_stream); RTC_DCHECK(packet_stream);
RTC_DCHECK(output_events); RTC_DCHECK(output_events);
event_ = GetNextEvent();
} }
absl::optional<int64_t> NextPacketTime() const override { absl::optional<int64_t> NextEventTime() const override {
if (event_) {
return event_->timestamp_ms();
}
return absl::nullopt;
}
std::unique_ptr<Event> PopEvent() override {
std::unique_ptr<Event> return_event = std::move(event_);
event_ = GetNextEvent();
return return_event;
}
std::unique_ptr<Event> GetNextEvent() {
absl::optional<int64_t> next_time;
absl::optional<int64_t> next_packet_time = NextPacketTime();
absl::optional<int64_t> next_output_time = NextOutputEventTime();
absl::optional<int64_t> next_set_minimum_delay_time =
NextSetMinimumDelayTime();
for (auto time :
{next_packet_time, next_output_time, next_set_minimum_delay_time}) {
if (time) {
if (next_time) {
next_time = time.value() < next_time.value() ? time : next_time;
} else {
next_time = time;
}
}
}
if (next_packet_time && next_packet_time.value() == next_time.value()) {
return PopPacket();
}
if (next_output_time && next_output_time.value() == next_time.value()) {
return PopGetAudio();
}
if (next_set_minimum_delay_time &&
next_set_minimum_delay_time.value() == next_time.value()) {
return PopNetEqSetMinimumDelay();
}
return nullptr;
}
absl::optional<int64_t> NextPacketTime() const {
if (packet_stream_it_ == packet_stream_.end()) { if (packet_stream_it_ == packet_stream_.end()) {
return absl::nullopt; return absl::nullopt;
} }
@ -208,7 +251,7 @@ class NetEqStreamInput : public test::NetEqInput {
return packet_stream_it_->rtp.log_time_ms(); return packet_stream_it_->rtp.log_time_ms();
} }
absl::optional<int64_t> NextOutputEventTime() const override { absl::optional<int64_t> NextOutputEventTime() const {
if (output_events_it_ == output_events_end_) { if (output_events_it_ == output_events_end_) {
return absl::nullopt; return absl::nullopt;
} }
@ -218,7 +261,7 @@ class NetEqStreamInput : public test::NetEqInput {
return output_events_it_->log_time_ms(); return output_events_it_->log_time_ms();
} }
absl::optional<SetMinimumDelayInfo> NextSetMinimumDelayInfo() const override { absl::optional<int64_t> NextSetMinimumDelayTime() const {
if (neteq_set_minimum_delay_events_it_ == if (neteq_set_minimum_delay_events_it_ ==
neteq_set_minimum_delay_events_end_) { neteq_set_minimum_delay_events_end_) {
return absl::nullopt; return absl::nullopt;
@ -227,18 +270,16 @@ class NetEqStreamInput : public test::NetEqInput {
neteq_set_minimum_delay_events_it_->log_time_ms() > *end_time_ms_) { neteq_set_minimum_delay_events_it_->log_time_ms() > *end_time_ms_) {
return absl::nullopt; return absl::nullopt;
} }
return SetMinimumDelayInfo( return neteq_set_minimum_delay_events_it_->log_time_ms();
neteq_set_minimum_delay_events_it_->log_time_ms(),
neteq_set_minimum_delay_events_it_->minimum_delay_ms);
} }
std::unique_ptr<PacketData> PopPacket() override { std::unique_ptr<PacketData> PopPacket() {
if (packet_stream_it_ == packet_stream_.end()) { if (packet_stream_it_ == packet_stream_.end()) {
return std::unique_ptr<PacketData>(); return std::unique_ptr<PacketData>();
} }
std::unique_ptr<PacketData> packet_data(new PacketData()); std::unique_ptr<PacketData> packet_data(new PacketData());
packet_data->header = packet_stream_it_->rtp.header; packet_data->header = packet_stream_it_->rtp.header;
packet_data->time_ms = packet_stream_it_->rtp.log_time_ms(); packet_data->timestamp_ms_ = packet_stream_it_->rtp.log_time_ms();
// This is a header-only "dummy" packet. Set the payload to all zeros, with // This is a header-only "dummy" packet. Set the payload to all zeros, with
// length according to the virtual length. // length according to the virtual length.
@ -250,17 +291,26 @@ class NetEqStreamInput : public test::NetEqInput {
return packet_data; return packet_data;
} }
void AdvanceOutputEvent() override { std::unique_ptr<GetAudio> PopGetAudio() {
std::unique_ptr<GetAudio> get_audio;
if (output_events_it_ != output_events_end_) { if (output_events_it_ != output_events_end_) {
get_audio = std::make_unique<GetAudio>(output_events_it_->log_time_ms());
++output_events_it_; ++output_events_it_;
} }
return get_audio;
} }
void AdvanceSetMinimumDelay() override { std::unique_ptr<SetMinimumDelay> PopNetEqSetMinimumDelay() {
std::unique_ptr<SetMinimumDelay> net_eq_set_minimum_delay;
if (neteq_set_minimum_delay_events_it_ != if (neteq_set_minimum_delay_events_it_ !=
neteq_set_minimum_delay_events_end_) { neteq_set_minimum_delay_events_end_) {
net_eq_set_minimum_delay = std::make_unique<SetMinimumDelay>(
neteq_set_minimum_delay_events_it_->log_time_ms(),
neteq_set_minimum_delay_events_it_->minimum_delay_ms);
++neteq_set_minimum_delay_events_it_; ++neteq_set_minimum_delay_events_it_;
} }
return net_eq_set_minimum_delay;
} }
bool ended() const override { return !NextEventTime(); } bool ended() const override { return !NextEventTime(); }
@ -282,6 +332,7 @@ class NetEqStreamInput : public test::NetEqInput {
const std::vector<LoggedNetEqSetMinimumDelayEvent>::const_iterator const std::vector<LoggedNetEqSetMinimumDelayEvent>::const_iterator
neteq_set_minimum_delay_events_end_; neteq_set_minimum_delay_events_end_;
const absl::optional<int64_t> end_time_ms_; const absl::optional<int64_t> end_time_ms_;
std::unique_ptr<Event> event_;
}; };
namespace { namespace {

View File

@ -64,71 +64,65 @@ class FuzzRtpInput : public NetEqInput {
new SineGenerator(config.sample_rate_hz)); new SineGenerator(config.sample_rate_hz));
input_.reset(new EncodeNetEqInput(std::move(generator), std::move(encoder), input_.reset(new EncodeNetEqInput(std::move(generator), std::move(encoder),
std::numeric_limits<int64_t>::max())); std::numeric_limits<int64_t>::max()));
packet_ = input_->PopPacket(); // We pop the first event so we have information about the timing of such
FuzzHeader(); // first event.
MaybeFuzzPayload(); event_ = input_->PopEvent();
if (event_ && event_->type() == Event::Type::kPacketData) {
FuzzPacket(static_cast<PacketData*>(event_.get()));
}
} }
absl::optional<int64_t> NextPacketTime() const override { std::unique_ptr<Event> PopEvent() override {
return packet_->time_ms; std::unique_ptr<Event> event_to_return = std::move(event_);
} event_ = input_->PopEvent();
if (event_ && event_->type() == Event::Type::kPacketData) {
absl::optional<int64_t> NextOutputEventTime() const override { FuzzPacket(static_cast<PacketData*>(event_.get()));
return input_->NextOutputEventTime(); }
} return event_to_return;
absl::optional<SetMinimumDelayInfo> NextSetMinimumDelayInfo() const override {
return input_->NextSetMinimumDelayInfo();
}
std::unique_ptr<PacketData> PopPacket() override {
RTC_DCHECK(packet_);
std::unique_ptr<PacketData> packet_to_return = std::move(packet_);
packet_ = input_->PopPacket();
FuzzHeader();
MaybeFuzzPayload();
return packet_to_return;
}
void AdvanceOutputEvent() override { return input_->AdvanceOutputEvent(); }
void AdvanceSetMinimumDelay() override {
return input_->AdvanceSetMinimumDelay();
} }
bool ended() const override { return ended_; } bool ended() const override { return ended_; }
absl::optional<RTPHeader> NextHeader() const override { absl::optional<RTPHeader> NextHeader() const override {
RTC_DCHECK(packet_); RTC_DCHECK(event_ && event_->type() == Event::Type::kPacketData);
return packet_->header; return static_cast<PacketData&>(*event_).header;
}
absl::optional<int64_t> NextEventTime() const override {
if (event_) {
return event_->timestamp_ms();
}
return absl::nullopt;
} }
private: private:
void FuzzHeader() { void FuzzPacket(PacketData* packet_data) {
FuzzHeader(packet_data->header);
MaybeFuzzPayload(packet_data->payload);
}
void FuzzHeader(RTPHeader& header) {
constexpr size_t kNumBytesToFuzz = 11; constexpr size_t kNumBytesToFuzz = 11;
if (data_ix_ + kNumBytesToFuzz > data_.size()) { if (data_ix_ + kNumBytesToFuzz > data_.size()) {
ended_ = true; ended_ = true;
return; return;
} }
RTC_DCHECK(packet_);
const size_t start_ix = data_ix_; const size_t start_ix = data_ix_;
packet_->header.payloadType = header.payloadType =
ByteReader<uint8_t>::ReadLittleEndian(&data_[data_ix_]); ByteReader<uint8_t>::ReadLittleEndian(&data_[data_ix_]);
packet_->header.payloadType &= 0x7F; header.payloadType &= 0x7F;
data_ix_ += sizeof(uint8_t); data_ix_ += sizeof(uint8_t);
packet_->header.sequenceNumber = header.sequenceNumber =
ByteReader<uint16_t>::ReadLittleEndian(&data_[data_ix_]); ByteReader<uint16_t>::ReadLittleEndian(&data_[data_ix_]);
data_ix_ += sizeof(uint16_t); data_ix_ += sizeof(uint16_t);
packet_->header.timestamp = header.timestamp = ByteReader<uint32_t>::ReadLittleEndian(&data_[data_ix_]);
ByteReader<uint32_t>::ReadLittleEndian(&data_[data_ix_]);
data_ix_ += sizeof(uint32_t); data_ix_ += sizeof(uint32_t);
packet_->header.ssrc = header.ssrc = ByteReader<uint32_t>::ReadLittleEndian(&data_[data_ix_]);
ByteReader<uint32_t>::ReadLittleEndian(&data_[data_ix_]);
data_ix_ += sizeof(uint32_t); data_ix_ += sizeof(uint32_t);
RTC_CHECK_EQ(data_ix_ - start_ix, kNumBytesToFuzz); RTC_CHECK_EQ(data_ix_ - start_ix, kNumBytesToFuzz);
} }
void MaybeFuzzPayload() { void MaybeFuzzPayload(rtc::Buffer& payload) {
// Read one byte of fuzz data to determine how many payload bytes to fuzz. // Read one byte of fuzz data to determine how many payload bytes to fuzz.
if (data_ix_ + 1 > data_.size()) { if (data_ix_ + 1 > data_.size()) {
ended_ = true; ended_ = true;
@ -138,7 +132,7 @@ class FuzzRtpInput : public NetEqInput {
// Restrict number of bytes to fuzz to 16; a reasonably low number enough to // Restrict number of bytes to fuzz to 16; a reasonably low number enough to
// cover a few RED headers. Also don't write outside the payload length. // cover a few RED headers. Also don't write outside the payload length.
bytes_to_fuzz = std::min(bytes_to_fuzz % 16, packet_->payload.size()); bytes_to_fuzz = std::min(bytes_to_fuzz % 16, payload.size());
if (bytes_to_fuzz == 0) if (bytes_to_fuzz == 0)
return; return;
@ -148,7 +142,7 @@ class FuzzRtpInput : public NetEqInput {
return; return;
} }
std::memcpy(packet_->payload.data(), &data_[data_ix_], bytes_to_fuzz); std::memcpy(payload.data(), &data_[data_ix_], bytes_to_fuzz);
data_ix_ += bytes_to_fuzz; data_ix_ += bytes_to_fuzz;
} }
@ -156,7 +150,7 @@ class FuzzRtpInput : public NetEqInput {
rtc::ArrayView<const uint8_t> data_; rtc::ArrayView<const uint8_t> data_;
size_t data_ix_ = 0; size_t data_ix_ = 0;
std::unique_ptr<EncodeNetEqInput> input_; std::unique_ptr<EncodeNetEqInput> input_;
std::unique_ptr<PacketData> packet_; std::unique_ptr<Event> event_;
}; };
} // namespace } // namespace

View File

@ -80,8 +80,10 @@ class FuzzSignalInput : public NetEqInput {
new SineAndNoiseGenerator(config.sample_rate_hz, fuzz_data)); new SineAndNoiseGenerator(config.sample_rate_hz, fuzz_data));
input_.reset(new EncodeNetEqInput(std::move(generator), std::move(encoder), input_.reset(new EncodeNetEqInput(std::move(generator), std::move(encoder),
std::numeric_limits<int64_t>::max())); std::numeric_limits<int64_t>::max()));
packet_ = input_->PopPacket(); // We pop the first event so we have information about the timing of such
// first event.
PopPacket();
PopEvent();
// Select an output event period. This is how long time we wait between each // Select an output event period. This is how long time we wait between each
// call to NetEq::GetAudio. 10 ms is nominal, 9 and 11 ms will both lead to // call to NetEq::GetAudio. 10 ms is nominal, 9 and 11 ms will both lead to
// clock drift (in different directions). // clock drift (in different directions).
@ -89,32 +91,45 @@ class FuzzSignalInput : public NetEqInput {
output_event_period_ms_ = fuzz_data_.SelectOneOf(output_event_periods); output_event_period_ms_ = fuzz_data_.SelectOneOf(output_event_periods);
} }
absl::optional<int64_t> NextPacketTime() const override { std::unique_ptr<Event> PopEvent() override {
return packet_->time_ms; std::unique_ptr<Event> event_to_return = std::move(event_);
if (packet_ && packet_->timestamp_ms() <= next_output_event_ms_) {
event_ = PopPacket();
} else {
event_ = std::make_unique<GetAudio>(next_output_event_ms_);
next_output_event_ms_ += output_event_period_ms_;
}
return event_to_return;
} }
absl::optional<int64_t> NextOutputEventTime() const override { absl::optional<int64_t> NextEventTime() const override {
return next_output_event_ms_; if (event_) {
return event_->timestamp_ms();
}
return absl::nullopt;
} }
absl::optional<SetMinimumDelayInfo> NextSetMinimumDelayInfo() const override { std::unique_ptr<Event> PopPacket() {
return input_->NextSetMinimumDelayInfo(); std::unique_ptr<Event> packet_to_return = std::move(packet_);
} int64_t packet_to_return_time_ms =
packet_to_return ? packet_to_return->timestamp_ms() : 0;
std::unique_ptr<PacketData> PopPacket() override { PacketData* packet_data = nullptr;
RTC_DCHECK(packet_);
std::unique_ptr<PacketData> packet_to_return = std::move(packet_);
do { do {
packet_ = input_->PopPacket(); std::unique_ptr<Event> event = input_->PopEvent();
while (event && event->type() != Event::Type::kPacketData) {
event = input_->PopEvent();
}
packet_data = static_cast<PacketData*>(event.get());
// If the next value from the fuzzer input is 0, the packet is discarded // If the next value from the fuzzer input is 0, the packet is discarded
// and the next one is pulled from the source. // and the next one is pulled from the source.
} while (fuzz_data_.CanReadBytes(1) && fuzz_data_.Read<uint8_t>() == 0); } while (fuzz_data_.CanReadBytes(1) && fuzz_data_.Read<uint8_t>() == 0);
if (fuzz_data_.CanReadBytes(1)) { if (fuzz_data_.CanReadBytes(1) && packet_data) {
// Generate jitter by setting an offset for the arrival time. // Generate jitter by setting an offset for the arrival time.
const int8_t arrival_time_offset_ms = fuzz_data_.Read<int8_t>(); const int8_t arrival_time_offset_ms = fuzz_data_.Read<int8_t>();
// The arrival time can not be before the previous packets. // The arrival time can not be before the previous packets.
packet_->time_ms = std::max(packet_to_return->time_ms, packet_data->timestamp_ms_ =
packet_->time_ms + arrival_time_offset_ms); std::max(packet_to_return_time_ms,
packet_data->timestamp_ms_ + arrival_time_offset_ms);
} else { } else {
// Mark that we are at the end of the test. However, the current packet is // Mark that we are at the end of the test. However, the current packet is
// still valid (but it may not have been fuzzed as expected). // still valid (but it may not have been fuzzed as expected).
@ -123,28 +138,21 @@ class FuzzSignalInput : public NetEqInput {
return packet_to_return; return packet_to_return;
} }
void AdvanceOutputEvent() override {
next_output_event_ms_ += output_event_period_ms_;
}
void AdvanceSetMinimumDelay() override {
return input_->AdvanceSetMinimumDelay();
}
bool ended() const override { return ended_; } bool ended() const override { return ended_; }
absl::optional<RTPHeader> NextHeader() const override { absl::optional<RTPHeader> NextHeader() const override {
RTC_DCHECK(packet_); RTC_DCHECK(packet_);
return packet_->header; return static_cast<PacketData&>(*packet_).header;
} }
private: private:
bool ended_ = false; bool ended_ = false;
FuzzDataHelper& fuzz_data_; FuzzDataHelper& fuzz_data_;
std::unique_ptr<EncodeNetEqInput> input_; std::unique_ptr<EncodeNetEqInput> input_;
std::unique_ptr<PacketData> packet_; std::unique_ptr<Event> packet_;
int64_t next_output_event_ms_ = 0; int64_t next_output_event_ms_ = 0;
int64_t output_event_period_ms_ = 10; int64_t output_event_period_ms_;
std::unique_ptr<Event> event_;
}; };
template <class T> template <class T>