blob: 22f5ad693126ce695acf95a56e2c93204a5c864e [file] [log] [blame]
henrik.lundine8a77e32016-06-22 06:34:03 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_coding/neteq/tools/neteq_test.h"
henrik.lundine8a77e32016-06-22 06:34:03 -070012
Ivo Creusen2db46b02018-12-14 16:49:12 +010013#include <iomanip>
henrik.lundine8a77e32016-06-22 06:34:03 -070014#include <iostream>
15
Ivo Creusen39cf3c72019-11-28 14:07:14 +010016#include "modules/audio_coding/neteq/default_neteq_factory.h"
Ivo Creusen2db46b02018-12-14 16:49:12 +010017#include "modules/rtp_rtcp/source/byte_io.h"
Alessio Bazzica8f319a32019-07-24 16:47:02 +000018#include "system_wrappers/include/clock.h"
henrik.lundine8a77e32016-06-22 06:34:03 -070019
20namespace webrtc {
21namespace test {
Ivo Creusen55de08e2018-09-03 11:49:27 +020022namespace {
23
Ivo Creusen3ce44a32019-10-31 14:38:11 +010024absl::optional<NetEq::Operation> ActionToOperations(
Ivo Creusen55de08e2018-09-03 11:49:27 +020025 absl::optional<NetEqSimulator::Action> a) {
26 if (!a) {
27 return absl::nullopt;
28 }
29 switch (*a) {
30 case NetEqSimulator::Action::kAccelerate:
Ivo Creusen3ce44a32019-10-31 14:38:11 +010031 return absl::make_optional(NetEq::Operation::kAccelerate);
Ivo Creusen55de08e2018-09-03 11:49:27 +020032 case NetEqSimulator::Action::kExpand:
Ivo Creusen3ce44a32019-10-31 14:38:11 +010033 return absl::make_optional(NetEq::Operation::kExpand);
Ivo Creusen55de08e2018-09-03 11:49:27 +020034 case NetEqSimulator::Action::kNormal:
Ivo Creusen3ce44a32019-10-31 14:38:11 +010035 return absl::make_optional(NetEq::Operation::kNormal);
Ivo Creusen55de08e2018-09-03 11:49:27 +020036 case NetEqSimulator::Action::kPreemptiveExpand:
Ivo Creusen3ce44a32019-10-31 14:38:11 +010037 return absl::make_optional(NetEq::Operation::kPreemptiveExpand);
Ivo Creusen55de08e2018-09-03 11:49:27 +020038 }
39}
40
Ivo Creusen3ce44a32019-10-31 14:38:11 +010041std::unique_ptr<NetEq> CreateNetEq(
42 const NetEq::Config& config,
43 Clock* clock,
44 const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) {
Ivo Creusen39cf3c72019-11-28 14:07:14 +010045 return DefaultNetEqFactory().CreateNetEq(config, decoder_factory, clock);
Ivo Creusen3ce44a32019-10-31 14:38:11 +010046}
47
Ivo Creusen55de08e2018-09-03 11:49:27 +020048} // namespace
henrik.lundine8a77e32016-06-22 06:34:03 -070049
50void DefaultNetEqTestErrorCallback::OnInsertPacketError(
henrik.lundine8a77e32016-06-22 06:34:03 -070051 const NetEqInput::PacketData& packet) {
Henrik Lundinc417d9e2017-06-14 12:29:03 +020052 std::cerr << "InsertPacket returned an error." << std::endl;
henrik.lundin7a38fd22017-04-28 01:35:53 -070053 std::cerr << "Packet data: " << packet.ToString() << std::endl;
Mirko Bonadei01719fb2020-11-17 14:50:54 +010054 RTC_FATAL();
henrik.lundine8a77e32016-06-22 06:34:03 -070055}
56
Henrik Lundinc417d9e2017-06-14 12:29:03 +020057void DefaultNetEqTestErrorCallback::OnGetAudioError() {
58 std::cerr << "GetAudio returned an error." << std::endl;
Mirko Bonadei01719fb2020-11-17 14:50:54 +010059 RTC_FATAL();
henrik.lundine8a77e32016-06-22 06:34:03 -070060}
61
62NetEqTest::NetEqTest(const NetEq::Config& config,
Niels Möller3f651d82018-12-19 15:06:17 +010063 rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
henrik.lundine8a77e32016-06-22 06:34:03 -070064 const DecoderMap& codecs,
Ivo Creusen2db46b02018-12-14 16:49:12 +010065 std::unique_ptr<std::ofstream> text_log,
Ivo Creusencee751a2020-01-16 17:17:09 +010066 NetEqFactory* neteq_factory,
henrik.lundine8a77e32016-06-22 06:34:03 -070067 std::unique_ptr<NetEqInput> input,
68 std::unique_ptr<AudioSink> output,
henrik.lundin02739d92017-05-04 06:09:06 -070069 Callbacks callbacks)
Alessio Bazzica8f319a32019-07-24 16:47:02 +000070 : clock_(0),
Ivo Creusencee751a2020-01-16 17:17:09 +010071 neteq_(neteq_factory
72 ? neteq_factory->CreateNetEq(config, decoder_factory, &clock_)
73 : CreateNetEq(config, &clock_, decoder_factory)),
henrik.lundine8a77e32016-06-22 06:34:03 -070074 input_(std::move(input)),
75 output_(std::move(output)),
henrik.lundin02739d92017-05-04 06:09:06 -070076 callbacks_(callbacks),
Ivo Creusen2db46b02018-12-14 16:49:12 +010077 sample_rate_hz_(config.sample_rate_hz),
78 text_log_(std::move(text_log)) {
henrik.lundine8a77e32016-06-22 06:34:03 -070079 RTC_CHECK(!config.enable_muted_state)
80 << "The code does not handle enable_muted_state";
81 RegisterDecoders(codecs);
henrik.lundine8a77e32016-06-22 06:34:03 -070082}
83
Mirko Bonadei682aac52018-07-20 13:59:20 +020084NetEqTest::~NetEqTest() = default;
85
henrik.lundine8a77e32016-06-22 06:34:03 -070086int64_t NetEqTest::Run() {
Ivo Creusen55de08e2018-09-03 11:49:27 +020087 int64_t simulation_time = 0;
88 SimulationStepResult step_result;
89 do {
90 step_result = RunToNextGetAudio();
91 simulation_time += step_result.simulation_step_ms;
92 } while (!step_result.is_simulation_finished);
93 if (callbacks_.simulation_ended_callback) {
Henrik Lundinc49e9c22020-05-25 11:26:15 +020094 callbacks_.simulation_ended_callback->SimulationEnded(simulation_time,
95 neteq_.get());
Ivo Creusen55de08e2018-09-03 11:49:27 +020096 }
97 return simulation_time;
98}
99
100NetEqTest::SimulationStepResult NetEqTest::RunToNextGetAudio() {
101 SimulationStepResult result;
henrik.lundine8a77e32016-06-22 06:34:03 -0700102 const int64_t start_time_ms = *input_->NextEventTime();
103 int64_t time_now_ms = start_time_ms;
Ivo Creusen4384f532018-09-07 17:19:56 +0200104 current_state_.packet_iat_ms.clear();
henrik.lundine8a77e32016-06-22 06:34:03 -0700105
106 while (!input_->ended()) {
107 // Advance time to next event.
108 RTC_DCHECK(input_->NextEventTime());
Alessio Bazzica8f319a32019-07-24 16:47:02 +0000109 clock_.AdvanceTimeMilliseconds(*input_->NextEventTime() - time_now_ms);
henrik.lundine8a77e32016-06-22 06:34:03 -0700110 time_now_ms = *input_->NextEventTime();
111 // Check if it is time to insert packet.
112 if (input_->NextPacketTime() && time_now_ms >= *input_->NextPacketTime()) {
113 std::unique_ptr<NetEqInput::PacketData> packet_data = input_->PopPacket();
114 RTC_CHECK(packet_data);
Minyue Li1a800182018-09-12 12:52:48 +0200115 const size_t payload_data_length =
116 packet_data->payload.size() - packet_data->header.paddingLength;
117 if (payload_data_length != 0) {
118 int error = neteq_->InsertPacket(
119 packet_data->header,
Karl Wiberg45eb1352019-10-10 14:23:00 +0200120 rtc::ArrayView<const uint8_t>(packet_data->payload));
Minyue Li1a800182018-09-12 12:52:48 +0200121 if (error != NetEq::kOK && callbacks_.error_callback) {
122 callbacks_.error_callback->OnInsertPacketError(*packet_data);
123 }
124 if (callbacks_.post_insert_packet) {
125 callbacks_.post_insert_packet->AfterInsertPacket(*packet_data,
126 neteq_.get());
127 }
128 } else {
129 neteq_->InsertEmptyPacket(packet_data->header);
henrik.lundine8a77e32016-06-22 06:34:03 -0700130 }
Ivo Creusen4384f532018-09-07 17:19:56 +0200131 if (last_packet_time_ms_) {
132 current_state_.packet_iat_ms.push_back(time_now_ms -
133 *last_packet_time_ms_);
134 }
Ivo Creusen2db46b02018-12-14 16:49:12 +0100135 if (text_log_) {
136 const auto ops_state = neteq_->GetOperationsAndState();
137 const auto delta_wallclock =
138 last_packet_time_ms_ ? (time_now_ms - *last_packet_time_ms_) : -1;
139 const auto delta_timestamp =
140 last_packet_timestamp_
141 ? (static_cast<int64_t>(packet_data->header.timestamp) -
142 *last_packet_timestamp_) *
143 1000 / sample_rate_hz_
144 : -1;
145 const auto packet_size_bytes =
146 packet_data->payload.size() == 12
147 ? ByteReader<uint32_t>::ReadLittleEndian(
148 &packet_data->payload[8])
149 : -1;
150 *text_log_ << "Packet - wallclock: " << std::setw(5) << time_now_ms
151 << ", delta wc: " << std::setw(4) << delta_wallclock
Jakob Ivarssone98954c2019-02-06 15:37:50 +0100152 << ", seq_no: " << packet_data->header.sequenceNumber
Ivo Creusen2db46b02018-12-14 16:49:12 +0100153 << ", timestamp: " << std::setw(10)
154 << packet_data->header.timestamp
155 << ", delta ts: " << std::setw(4) << delta_timestamp
156 << ", size: " << std::setw(5) << packet_size_bytes
157 << ", frame size: " << std::setw(3)
158 << ops_state.current_frame_size_ms
159 << ", buffer size: " << std::setw(4)
160 << ops_state.current_buffer_size_ms << std::endl;
161 }
Ivo Creusen4384f532018-09-07 17:19:56 +0200162 last_packet_time_ms_ = absl::make_optional<int>(time_now_ms);
Ivo Creusen2db46b02018-12-14 16:49:12 +0100163 last_packet_timestamp_ =
164 absl::make_optional<uint32_t>(packet_data->header.timestamp);
henrik.lundine8a77e32016-06-22 06:34:03 -0700165 }
166
167 // Check if it is time to get output audio.
168 if (input_->NextOutputEventTime() &&
169 time_now_ms >= *input_->NextOutputEventTime()) {
henrik.lundin02739d92017-05-04 06:09:06 -0700170 if (callbacks_.get_audio_callback) {
171 callbacks_.get_audio_callback->BeforeGetAudio(neteq_.get());
172 }
henrik.lundine8a77e32016-06-22 06:34:03 -0700173 AudioFrame out_frame;
174 bool muted;
Tommi3cc68ec2021-06-09 19:30:41 +0200175 int error = neteq_->GetAudio(&out_frame, &muted, nullptr,
Ivo Creusen55de08e2018-09-03 11:49:27 +0200176 ActionToOperations(next_action_));
177 next_action_ = absl::nullopt;
henrik.lundine8a77e32016-06-22 06:34:03 -0700178 RTC_CHECK(!muted) << "The code does not handle enable_muted_state";
179 if (error != NetEq::kOK) {
henrik.lundin02739d92017-05-04 06:09:06 -0700180 if (callbacks_.error_callback) {
Henrik Lundinc417d9e2017-06-14 12:29:03 +0200181 callbacks_.error_callback->OnGetAudioError();
henrik.lundine8a77e32016-06-22 06:34:03 -0700182 }
183 } else {
184 sample_rate_hz_ = out_frame.sample_rate_hz_;
185 }
henrik.lundin02739d92017-05-04 06:09:06 -0700186 if (callbacks_.get_audio_callback) {
187 callbacks_.get_audio_callback->AfterGetAudio(time_now_ms, out_frame,
188 muted, neteq_.get());
189 }
henrik.lundine8a77e32016-06-22 06:34:03 -0700190
191 if (output_) {
192 RTC_CHECK(output_->WriteArray(
yujo36b1a5f2017-06-12 12:45:32 -0700193 out_frame.data(),
henrik.lundine8a77e32016-06-22 06:34:03 -0700194 out_frame.samples_per_channel_ * out_frame.num_channels_));
195 }
196
197 input_->AdvanceOutputEvent();
Henrik Lundin9be77452018-09-10 12:53:27 +0200198 result.simulation_step_ms =
199 input_->NextEventTime().value_or(time_now_ms) - start_time_ms;
Ivo Creusend1c2f782018-09-13 14:39:55 +0200200 const auto operations_state = neteq_->GetOperationsAndState();
201 current_state_.current_delay_ms = operations_state.current_buffer_size_ms;
Ivo Creusendc6d5532018-09-27 11:43:42 +0200202 current_state_.packet_size_ms = operations_state.current_frame_size_ms;
203 current_state_.next_packet_available =
204 operations_state.next_packet_available;
205 current_state_.packet_buffer_flushed =
206 operations_state.packet_buffer_flushes >
207 prev_ops_state_.packet_buffer_flushes;
Ivo Creusend1c2f782018-09-13 14:39:55 +0200208 // TODO(ivoc): Add more accurate reporting by tracking the origin of
209 // samples in the sync buffer.
210 result.action_times_ms[Action::kExpand] = 0;
211 result.action_times_ms[Action::kAccelerate] = 0;
212 result.action_times_ms[Action::kPreemptiveExpand] = 0;
213 result.action_times_ms[Action::kNormal] = 0;
214
215 if (out_frame.speech_type_ == AudioFrame::SpeechType::kPLC ||
216 out_frame.speech_type_ == AudioFrame::SpeechType::kPLCCNG) {
217 // Consider the whole frame to be the result of expansion.
218 result.action_times_ms[Action::kExpand] = 10;
219 } else if (operations_state.accelerate_samples -
220 prev_ops_state_.accelerate_samples >
221 0) {
222 // Consider the whole frame to be the result of acceleration.
223 result.action_times_ms[Action::kAccelerate] = 10;
224 } else if (operations_state.preemptive_samples -
225 prev_ops_state_.preemptive_samples >
226 0) {
227 // Consider the whole frame to be the result of preemptive expansion.
228 result.action_times_ms[Action::kPreemptiveExpand] = 10;
229 } else {
230 // Consider the whole frame to be the result of normal playout.
231 result.action_times_ms[Action::kNormal] = 10;
232 }
Ivo Creusen2db46b02018-12-14 16:49:12 +0100233 auto lifetime_stats = LifetimeStats();
234 if (text_log_) {
235 const bool plc =
236 (out_frame.speech_type_ == AudioFrame::SpeechType::kPLC) ||
237 (out_frame.speech_type_ == AudioFrame::SpeechType::kPLCCNG);
238 const bool cng = out_frame.speech_type_ == AudioFrame::SpeechType::kCNG;
239 const bool voice_concealed =
Ivo Creusenbf4a2212019-04-24 14:06:24 +0200240 (lifetime_stats.concealed_samples -
241 lifetime_stats.silent_concealed_samples) >
242 (prev_lifetime_stats_.concealed_samples -
243 prev_lifetime_stats_.silent_concealed_samples);
Ivo Creusen2db46b02018-12-14 16:49:12 +0100244 *text_log_ << "GetAudio - wallclock: " << std::setw(5) << time_now_ms
245 << ", delta wc: " << std::setw(4)
246 << (input_->NextEventTime().value_or(time_now_ms) -
247 start_time_ms)
248 << ", CNG: " << cng << ", PLC: " << plc
249 << ", voice concealed: " << voice_concealed
250 << ", buffer size: " << std::setw(4)
251 << current_state_.current_delay_ms << std::endl;
252 if (operations_state.discarded_primary_packets >
253 prev_ops_state_.discarded_primary_packets) {
254 *text_log_ << "Discarded "
255 << (operations_state.discarded_primary_packets -
256 prev_ops_state_.discarded_primary_packets)
257 << " primary packets." << std::endl;
258 }
259 if (operations_state.packet_buffer_flushes >
260 prev_ops_state_.packet_buffer_flushes) {
261 *text_log_ << "Flushed packet buffer "
262 << (operations_state.packet_buffer_flushes -
263 prev_ops_state_.packet_buffer_flushes)
264 << " times." << std::endl;
265 }
266 }
267 prev_lifetime_stats_ = lifetime_stats;
Jakob Ivarsson9ce451a2019-05-22 16:41:22 +0200268 const bool no_more_packets_to_decode =
269 !input_->NextPacketTime() && !operations_state.next_packet_available;
Ivo Creusen876a3dc2020-08-18 17:08:18 +0200270 // End the simulation if the gap is too large. This indicates an issue
271 // with the event log file.
272 const bool simulation_step_too_large = result.simulation_step_ms > 1000;
Ivo Creusenb9b74562020-10-26 17:49:25 +0100273 if (simulation_step_too_large) {
274 // If we don't reset the step time, the large gap will be included in
275 // the simulation time, which can be a large distortion.
276 result.simulation_step_ms = 10;
277 }
Ivo Creusen876a3dc2020-08-18 17:08:18 +0200278 result.is_simulation_finished = simulation_step_too_large ||
279 no_more_packets_to_decode ||
280 input_->ended();
Ivo Creusend1c2f782018-09-13 14:39:55 +0200281 prev_ops_state_ = operations_state;
Ivo Creusen55de08e2018-09-03 11:49:27 +0200282 return result;
henrik.lundine8a77e32016-06-22 06:34:03 -0700283 }
284 }
Henrik Lundin9be77452018-09-10 12:53:27 +0200285 result.simulation_step_ms =
286 input_->NextEventTime().value_or(time_now_ms) - start_time_ms;
Ivo Creusen55de08e2018-09-03 11:49:27 +0200287 result.is_simulation_finished = true;
288 return result;
289}
290
291void NetEqTest::SetNextAction(NetEqTest::Action next_operation) {
292 next_action_ = absl::optional<Action>(next_operation);
293}
294
295NetEqTest::NetEqState NetEqTest::GetNetEqState() {
Ivo Creusen4384f532018-09-07 17:19:56 +0200296 return current_state_;
henrik.lundine8a77e32016-06-22 06:34:03 -0700297}
298
299NetEqNetworkStatistics NetEqTest::SimulationStats() {
300 NetEqNetworkStatistics stats;
301 RTC_CHECK_EQ(neteq_->NetworkStatistics(&stats), 0);
302 return stats;
303}
304
Alex Narest7ff6ca52018-02-07 18:46:33 +0100305NetEqLifetimeStatistics NetEqTest::LifetimeStats() const {
306 return neteq_->GetLifetimeStatistics();
307}
308
Henrik Lundin7687ad52018-07-02 10:14:46 +0200309NetEqTest::DecoderMap NetEqTest::StandardDecoderMap() {
310 DecoderMap codecs = {
Niels Möller05543682019-01-10 16:55:06 +0100311 {0, SdpAudioFormat("pcmu", 8000, 1)},
312 {8, SdpAudioFormat("pcma", 8000, 1)},
Henrik Lundin7687ad52018-07-02 10:14:46 +0200313#ifdef WEBRTC_CODEC_ILBC
Niels Möller05543682019-01-10 16:55:06 +0100314 {102, SdpAudioFormat("ilbc", 8000, 1)},
Henrik Lundin7687ad52018-07-02 10:14:46 +0200315#endif
Niels Möller05543682019-01-10 16:55:06 +0100316 {103, SdpAudioFormat("isac", 16000, 1)},
Henrik Lundin7687ad52018-07-02 10:14:46 +0200317#if !defined(WEBRTC_ANDROID)
Niels Möller05543682019-01-10 16:55:06 +0100318 {104, SdpAudioFormat("isac", 32000, 1)},
Henrik Lundin7687ad52018-07-02 10:14:46 +0200319#endif
320#ifdef WEBRTC_CODEC_OPUS
Niels Möller05543682019-01-10 16:55:06 +0100321 {111, SdpAudioFormat("opus", 48000, 2)},
Henrik Lundin7687ad52018-07-02 10:14:46 +0200322#endif
Niels Möller05543682019-01-10 16:55:06 +0100323 {93, SdpAudioFormat("l16", 8000, 1)},
324 {94, SdpAudioFormat("l16", 16000, 1)},
325 {95, SdpAudioFormat("l16", 32000, 1)},
326 {96, SdpAudioFormat("l16", 48000, 1)},
327 {9, SdpAudioFormat("g722", 8000, 1)},
328 {106, SdpAudioFormat("telephone-event", 8000, 1)},
329 {114, SdpAudioFormat("telephone-event", 16000, 1)},
330 {115, SdpAudioFormat("telephone-event", 32000, 1)},
331 {116, SdpAudioFormat("telephone-event", 48000, 1)},
332 {117, SdpAudioFormat("red", 8000, 1)},
333 {13, SdpAudioFormat("cn", 8000, 1)},
334 {98, SdpAudioFormat("cn", 16000, 1)},
335 {99, SdpAudioFormat("cn", 32000, 1)},
336 {100, SdpAudioFormat("cn", 48000, 1)}
Henrik Lundin7687ad52018-07-02 10:14:46 +0200337 };
338 return codecs;
339}
340
henrik.lundine8a77e32016-06-22 06:34:03 -0700341void NetEqTest::RegisterDecoders(const DecoderMap& codecs) {
342 for (const auto& c : codecs) {
Niels Möller05543682019-01-10 16:55:06 +0100343 RTC_CHECK(neteq_->RegisterPayloadType(c.first, c.second))
344 << "Cannot register " << c.second.name << " to payload type "
henrik.lundine8a77e32016-06-22 06:34:03 -0700345 << c.first;
346 }
347}
348
henrik.lundine8a77e32016-06-22 06:34:03 -0700349} // namespace test
350} // namespace webrtc