blob: a3c3ffa32b971be52cc18aa829930f9b4e11e135 [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
Oleh Prypinf7f753b2018-12-17 15:02:25 +000016#include "api/audio_codecs/builtin_audio_decoder_factory.h"
Ivo Creusen2db46b02018-12-14 16:49:12 +010017#include "modules/rtp_rtcp/source/byte_io.h"
henrik.lundine8a77e32016-06-22 06:34:03 -070018
19namespace webrtc {
20namespace test {
Ivo Creusen55de08e2018-09-03 11:49:27 +020021namespace {
22
23absl::optional<Operations> ActionToOperations(
24 absl::optional<NetEqSimulator::Action> a) {
25 if (!a) {
26 return absl::nullopt;
27 }
28 switch (*a) {
29 case NetEqSimulator::Action::kAccelerate:
30 return absl::make_optional(kAccelerate);
31 case NetEqSimulator::Action::kExpand:
32 return absl::make_optional(kExpand);
33 case NetEqSimulator::Action::kNormal:
34 return absl::make_optional(kNormal);
35 case NetEqSimulator::Action::kPreemptiveExpand:
36 return absl::make_optional(kPreemptiveExpand);
37 }
38}
39
40} // namespace
henrik.lundine8a77e32016-06-22 06:34:03 -070041
42void DefaultNetEqTestErrorCallback::OnInsertPacketError(
henrik.lundine8a77e32016-06-22 06:34:03 -070043 const NetEqInput::PacketData& packet) {
Henrik Lundinc417d9e2017-06-14 12:29:03 +020044 std::cerr << "InsertPacket returned an error." << std::endl;
henrik.lundin7a38fd22017-04-28 01:35:53 -070045 std::cerr << "Packet data: " << packet.ToString() << std::endl;
henrik.lundine8a77e32016-06-22 06:34:03 -070046 FATAL();
47}
48
Henrik Lundinc417d9e2017-06-14 12:29:03 +020049void DefaultNetEqTestErrorCallback::OnGetAudioError() {
50 std::cerr << "GetAudio returned an error." << std::endl;
henrik.lundine8a77e32016-06-22 06:34:03 -070051 FATAL();
52}
53
54NetEqTest::NetEqTest(const NetEq::Config& config,
55 const DecoderMap& codecs,
56 const ExtDecoderMap& ext_codecs,
Ivo Creusen2db46b02018-12-14 16:49:12 +010057 std::unique_ptr<std::ofstream> text_log,
henrik.lundine8a77e32016-06-22 06:34:03 -070058 std::unique_ptr<NetEqInput> input,
59 std::unique_ptr<AudioSink> output,
henrik.lundin02739d92017-05-04 06:09:06 -070060 Callbacks callbacks)
Oleh Prypinf7f753b2018-12-17 15:02:25 +000061 : neteq_(NetEq::Create(config, CreateBuiltinAudioDecoderFactory())),
henrik.lundine8a77e32016-06-22 06:34:03 -070062 input_(std::move(input)),
63 output_(std::move(output)),
henrik.lundin02739d92017-05-04 06:09:06 -070064 callbacks_(callbacks),
Ivo Creusen2db46b02018-12-14 16:49:12 +010065 sample_rate_hz_(config.sample_rate_hz),
66 text_log_(std::move(text_log)) {
henrik.lundine8a77e32016-06-22 06:34:03 -070067 RTC_CHECK(!config.enable_muted_state)
68 << "The code does not handle enable_muted_state";
69 RegisterDecoders(codecs);
70 RegisterExternalDecoders(ext_codecs);
71}
72
Mirko Bonadei682aac52018-07-20 13:59:20 +020073NetEqTest::~NetEqTest() = default;
74
henrik.lundine8a77e32016-06-22 06:34:03 -070075int64_t NetEqTest::Run() {
Ivo Creusen55de08e2018-09-03 11:49:27 +020076 int64_t simulation_time = 0;
77 SimulationStepResult step_result;
78 do {
79 step_result = RunToNextGetAudio();
80 simulation_time += step_result.simulation_step_ms;
81 } while (!step_result.is_simulation_finished);
82 if (callbacks_.simulation_ended_callback) {
83 callbacks_.simulation_ended_callback->SimulationEnded(simulation_time);
84 }
85 return simulation_time;
86}
87
88NetEqTest::SimulationStepResult NetEqTest::RunToNextGetAudio() {
89 SimulationStepResult result;
henrik.lundine8a77e32016-06-22 06:34:03 -070090 const int64_t start_time_ms = *input_->NextEventTime();
91 int64_t time_now_ms = start_time_ms;
Ivo Creusen4384f532018-09-07 17:19:56 +020092 current_state_.packet_iat_ms.clear();
henrik.lundine8a77e32016-06-22 06:34:03 -070093
94 while (!input_->ended()) {
95 // Advance time to next event.
96 RTC_DCHECK(input_->NextEventTime());
97 time_now_ms = *input_->NextEventTime();
98 // Check if it is time to insert packet.
99 if (input_->NextPacketTime() && time_now_ms >= *input_->NextPacketTime()) {
100 std::unique_ptr<NetEqInput::PacketData> packet_data = input_->PopPacket();
101 RTC_CHECK(packet_data);
Minyue Li1a800182018-09-12 12:52:48 +0200102 const size_t payload_data_length =
103 packet_data->payload.size() - packet_data->header.paddingLength;
104 if (payload_data_length != 0) {
105 int error = neteq_->InsertPacket(
106 packet_data->header,
107 rtc::ArrayView<const uint8_t>(packet_data->payload),
108 static_cast<uint32_t>(packet_data->time_ms * sample_rate_hz_ /
109 1000));
110 if (error != NetEq::kOK && callbacks_.error_callback) {
111 callbacks_.error_callback->OnInsertPacketError(*packet_data);
112 }
113 if (callbacks_.post_insert_packet) {
114 callbacks_.post_insert_packet->AfterInsertPacket(*packet_data,
115 neteq_.get());
116 }
117 } else {
118 neteq_->InsertEmptyPacket(packet_data->header);
henrik.lundine8a77e32016-06-22 06:34:03 -0700119 }
Ivo Creusen4384f532018-09-07 17:19:56 +0200120 if (last_packet_time_ms_) {
121 current_state_.packet_iat_ms.push_back(time_now_ms -
122 *last_packet_time_ms_);
123 }
Ivo Creusen2db46b02018-12-14 16:49:12 +0100124 if (text_log_) {
125 const auto ops_state = neteq_->GetOperationsAndState();
126 const auto delta_wallclock =
127 last_packet_time_ms_ ? (time_now_ms - *last_packet_time_ms_) : -1;
128 const auto delta_timestamp =
129 last_packet_timestamp_
130 ? (static_cast<int64_t>(packet_data->header.timestamp) -
131 *last_packet_timestamp_) *
132 1000 / sample_rate_hz_
133 : -1;
134 const auto packet_size_bytes =
135 packet_data->payload.size() == 12
136 ? ByteReader<uint32_t>::ReadLittleEndian(
137 &packet_data->payload[8])
138 : -1;
139 *text_log_ << "Packet - wallclock: " << std::setw(5) << time_now_ms
140 << ", delta wc: " << std::setw(4) << delta_wallclock
141 << ", timestamp: " << std::setw(10)
142 << packet_data->header.timestamp
143 << ", delta ts: " << std::setw(4) << delta_timestamp
144 << ", size: " << std::setw(5) << packet_size_bytes
145 << ", frame size: " << std::setw(3)
146 << ops_state.current_frame_size_ms
147 << ", buffer size: " << std::setw(4)
148 << ops_state.current_buffer_size_ms << std::endl;
149 }
Ivo Creusen4384f532018-09-07 17:19:56 +0200150 last_packet_time_ms_ = absl::make_optional<int>(time_now_ms);
Ivo Creusen2db46b02018-12-14 16:49:12 +0100151 last_packet_timestamp_ =
152 absl::make_optional<uint32_t>(packet_data->header.timestamp);
henrik.lundine8a77e32016-06-22 06:34:03 -0700153 }
154
155 // Check if it is time to get output audio.
156 if (input_->NextOutputEventTime() &&
157 time_now_ms >= *input_->NextOutputEventTime()) {
henrik.lundin02739d92017-05-04 06:09:06 -0700158 if (callbacks_.get_audio_callback) {
159 callbacks_.get_audio_callback->BeforeGetAudio(neteq_.get());
160 }
henrik.lundine8a77e32016-06-22 06:34:03 -0700161 AudioFrame out_frame;
162 bool muted;
Ivo Creusen55de08e2018-09-03 11:49:27 +0200163 int error = neteq_->GetAudio(&out_frame, &muted,
164 ActionToOperations(next_action_));
165 next_action_ = absl::nullopt;
henrik.lundine8a77e32016-06-22 06:34:03 -0700166 RTC_CHECK(!muted) << "The code does not handle enable_muted_state";
167 if (error != NetEq::kOK) {
henrik.lundin02739d92017-05-04 06:09:06 -0700168 if (callbacks_.error_callback) {
Henrik Lundinc417d9e2017-06-14 12:29:03 +0200169 callbacks_.error_callback->OnGetAudioError();
henrik.lundine8a77e32016-06-22 06:34:03 -0700170 }
171 } else {
172 sample_rate_hz_ = out_frame.sample_rate_hz_;
173 }
henrik.lundin02739d92017-05-04 06:09:06 -0700174 if (callbacks_.get_audio_callback) {
175 callbacks_.get_audio_callback->AfterGetAudio(time_now_ms, out_frame,
176 muted, neteq_.get());
177 }
henrik.lundine8a77e32016-06-22 06:34:03 -0700178
179 if (output_) {
180 RTC_CHECK(output_->WriteArray(
yujo36b1a5f2017-06-12 12:45:32 -0700181 out_frame.data(),
henrik.lundine8a77e32016-06-22 06:34:03 -0700182 out_frame.samples_per_channel_ * out_frame.num_channels_));
183 }
184
185 input_->AdvanceOutputEvent();
Henrik Lundin9be77452018-09-10 12:53:27 +0200186 result.simulation_step_ms =
187 input_->NextEventTime().value_or(time_now_ms) - start_time_ms;
Ivo Creusend1c2f782018-09-13 14:39:55 +0200188 const auto operations_state = neteq_->GetOperationsAndState();
189 current_state_.current_delay_ms = operations_state.current_buffer_size_ms;
Ivo Creusendc6d5532018-09-27 11:43:42 +0200190 current_state_.packet_size_ms = operations_state.current_frame_size_ms;
191 current_state_.next_packet_available =
192 operations_state.next_packet_available;
193 current_state_.packet_buffer_flushed =
194 operations_state.packet_buffer_flushes >
195 prev_ops_state_.packet_buffer_flushes;
Ivo Creusend1c2f782018-09-13 14:39:55 +0200196 // TODO(ivoc): Add more accurate reporting by tracking the origin of
197 // samples in the sync buffer.
198 result.action_times_ms[Action::kExpand] = 0;
199 result.action_times_ms[Action::kAccelerate] = 0;
200 result.action_times_ms[Action::kPreemptiveExpand] = 0;
201 result.action_times_ms[Action::kNormal] = 0;
202
203 if (out_frame.speech_type_ == AudioFrame::SpeechType::kPLC ||
204 out_frame.speech_type_ == AudioFrame::SpeechType::kPLCCNG) {
205 // Consider the whole frame to be the result of expansion.
206 result.action_times_ms[Action::kExpand] = 10;
207 } else if (operations_state.accelerate_samples -
208 prev_ops_state_.accelerate_samples >
209 0) {
210 // Consider the whole frame to be the result of acceleration.
211 result.action_times_ms[Action::kAccelerate] = 10;
212 } else if (operations_state.preemptive_samples -
213 prev_ops_state_.preemptive_samples >
214 0) {
215 // Consider the whole frame to be the result of preemptive expansion.
216 result.action_times_ms[Action::kPreemptiveExpand] = 10;
217 } else {
218 // Consider the whole frame to be the result of normal playout.
219 result.action_times_ms[Action::kNormal] = 10;
220 }
Ivo Creusen2db46b02018-12-14 16:49:12 +0100221 auto lifetime_stats = LifetimeStats();
222 if (text_log_) {
223 const bool plc =
224 (out_frame.speech_type_ == AudioFrame::SpeechType::kPLC) ||
225 (out_frame.speech_type_ == AudioFrame::SpeechType::kPLCCNG);
226 const bool cng = out_frame.speech_type_ == AudioFrame::SpeechType::kCNG;
227 const bool voice_concealed =
228 lifetime_stats.voice_concealed_samples >
229 prev_lifetime_stats_.voice_concealed_samples;
230 *text_log_ << "GetAudio - wallclock: " << std::setw(5) << time_now_ms
231 << ", delta wc: " << std::setw(4)
232 << (input_->NextEventTime().value_or(time_now_ms) -
233 start_time_ms)
234 << ", CNG: " << cng << ", PLC: " << plc
235 << ", voice concealed: " << voice_concealed
236 << ", buffer size: " << std::setw(4)
237 << current_state_.current_delay_ms << std::endl;
238 if (operations_state.discarded_primary_packets >
239 prev_ops_state_.discarded_primary_packets) {
240 *text_log_ << "Discarded "
241 << (operations_state.discarded_primary_packets -
242 prev_ops_state_.discarded_primary_packets)
243 << " primary packets." << std::endl;
244 }
245 if (operations_state.packet_buffer_flushes >
246 prev_ops_state_.packet_buffer_flushes) {
247 *text_log_ << "Flushed packet buffer "
248 << (operations_state.packet_buffer_flushes -
249 prev_ops_state_.packet_buffer_flushes)
250 << " times." << std::endl;
251 }
252 }
253 prev_lifetime_stats_ = lifetime_stats;
Ivo Creusen55de08e2018-09-03 11:49:27 +0200254 result.is_simulation_finished = input_->ended();
Ivo Creusend1c2f782018-09-13 14:39:55 +0200255 prev_ops_state_ = operations_state;
Ivo Creusen55de08e2018-09-03 11:49:27 +0200256 return result;
henrik.lundine8a77e32016-06-22 06:34:03 -0700257 }
258 }
Henrik Lundin9be77452018-09-10 12:53:27 +0200259 result.simulation_step_ms =
260 input_->NextEventTime().value_or(time_now_ms) - start_time_ms;
Ivo Creusen55de08e2018-09-03 11:49:27 +0200261 result.is_simulation_finished = true;
262 return result;
263}
264
265void NetEqTest::SetNextAction(NetEqTest::Action next_operation) {
266 next_action_ = absl::optional<Action>(next_operation);
267}
268
269NetEqTest::NetEqState NetEqTest::GetNetEqState() {
Ivo Creusen4384f532018-09-07 17:19:56 +0200270 return current_state_;
henrik.lundine8a77e32016-06-22 06:34:03 -0700271}
272
273NetEqNetworkStatistics NetEqTest::SimulationStats() {
274 NetEqNetworkStatistics stats;
275 RTC_CHECK_EQ(neteq_->NetworkStatistics(&stats), 0);
276 return stats;
277}
278
Alex Narest7ff6ca52018-02-07 18:46:33 +0100279NetEqLifetimeStatistics NetEqTest::LifetimeStats() const {
280 return neteq_->GetLifetimeStatistics();
281}
282
Henrik Lundin7687ad52018-07-02 10:14:46 +0200283NetEqTest::DecoderMap NetEqTest::StandardDecoderMap() {
284 DecoderMap codecs = {
285 {0, std::make_pair(NetEqDecoder::kDecoderPCMu, "pcmu")},
286 {8, std::make_pair(NetEqDecoder::kDecoderPCMa, "pcma")},
287#ifdef WEBRTC_CODEC_ILBC
288 {102, std::make_pair(NetEqDecoder::kDecoderILBC, "ilbc")},
289#endif
290 {103, std::make_pair(NetEqDecoder::kDecoderISAC, "isac")},
291#if !defined(WEBRTC_ANDROID)
292 {104, std::make_pair(NetEqDecoder::kDecoderISACswb, "isac-swb")},
293#endif
294#ifdef WEBRTC_CODEC_OPUS
295 {111, std::make_pair(NetEqDecoder::kDecoderOpus, "opus")},
296#endif
297 {93, std::make_pair(NetEqDecoder::kDecoderPCM16B, "pcm16-nb")},
298 {94, std::make_pair(NetEqDecoder::kDecoderPCM16Bwb, "pcm16-wb")},
299 {95, std::make_pair(NetEqDecoder::kDecoderPCM16Bswb32kHz, "pcm16-swb32")},
300 {96, std::make_pair(NetEqDecoder::kDecoderPCM16Bswb48kHz, "pcm16-swb48")},
301 {9, std::make_pair(NetEqDecoder::kDecoderG722, "g722")},
302 {106, std::make_pair(NetEqDecoder::kDecoderAVT, "avt")},
303 {114, std::make_pair(NetEqDecoder::kDecoderAVT16kHz, "avt-16")},
304 {115, std::make_pair(NetEqDecoder::kDecoderAVT32kHz, "avt-32")},
305 {116, std::make_pair(NetEqDecoder::kDecoderAVT48kHz, "avt-48")},
306 {117, std::make_pair(NetEqDecoder::kDecoderRED, "red")},
307 {13, std::make_pair(NetEqDecoder::kDecoderCNGnb, "cng-nb")},
308 {98, std::make_pair(NetEqDecoder::kDecoderCNGwb, "cng-wb")},
309 {99, std::make_pair(NetEqDecoder::kDecoderCNGswb32kHz, "cng-swb32")},
310 {100, std::make_pair(NetEqDecoder::kDecoderCNGswb48kHz, "cng-swb48")}
311 };
312 return codecs;
313}
314
henrik.lundine8a77e32016-06-22 06:34:03 -0700315void NetEqTest::RegisterDecoders(const DecoderMap& codecs) {
316 for (const auto& c : codecs) {
317 RTC_CHECK_EQ(
318 neteq_->RegisterPayloadType(c.second.first, c.second.second, c.first),
319 NetEq::kOK)
320 << "Cannot register " << c.second.second << " to payload type "
321 << c.first;
322 }
323}
324
325void NetEqTest::RegisterExternalDecoders(const ExtDecoderMap& codecs) {
326 for (const auto& c : codecs) {
327 RTC_CHECK_EQ(
328 neteq_->RegisterExternalDecoder(c.second.decoder, c.second.codec,
329 c.second.codec_name, c.first),
330 NetEq::kOK)
331 << "Cannot register " << c.second.codec_name << " to payload type "
332 << c.first;
333 }
334}
335
336} // namespace test
337} // namespace webrtc