• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
11 #include "modules/audio_coding/neteq/tools/neteq_test.h"
12 
13 #include <iomanip>
14 #include <iostream>
15 
16 #include "modules/audio_coding/neteq/default_neteq_factory.h"
17 #include "modules/rtp_rtcp/source/byte_io.h"
18 #include "system_wrappers/include/clock.h"
19 
20 namespace webrtc {
21 namespace test {
22 namespace {
23 
ActionToOperations(absl::optional<NetEqSimulator::Action> a)24 absl::optional<NetEq::Operation> ActionToOperations(
25     absl::optional<NetEqSimulator::Action> a) {
26   if (!a) {
27     return absl::nullopt;
28   }
29   switch (*a) {
30     case NetEqSimulator::Action::kAccelerate:
31       return absl::make_optional(NetEq::Operation::kAccelerate);
32     case NetEqSimulator::Action::kExpand:
33       return absl::make_optional(NetEq::Operation::kExpand);
34     case NetEqSimulator::Action::kNormal:
35       return absl::make_optional(NetEq::Operation::kNormal);
36     case NetEqSimulator::Action::kPreemptiveExpand:
37       return absl::make_optional(NetEq::Operation::kPreemptiveExpand);
38   }
39 }
40 
CreateNetEq(const NetEq::Config & config,Clock * clock,const rtc::scoped_refptr<AudioDecoderFactory> & decoder_factory)41 std::unique_ptr<NetEq> CreateNetEq(
42     const NetEq::Config& config,
43     Clock* clock,
44     const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) {
45   return DefaultNetEqFactory().CreateNetEq(config, decoder_factory, clock);
46 }
47 
48 }  // namespace
49 
OnInsertPacketError(const NetEqInput::PacketData & packet)50 void DefaultNetEqTestErrorCallback::OnInsertPacketError(
51     const NetEqInput::PacketData& packet) {
52   std::cerr << "InsertPacket returned an error." << std::endl;
53   std::cerr << "Packet data: " << packet.ToString() << std::endl;
54   FATAL();
55 }
56 
OnGetAudioError()57 void DefaultNetEqTestErrorCallback::OnGetAudioError() {
58   std::cerr << "GetAudio returned an error." << std::endl;
59   FATAL();
60 }
61 
NetEqTest(const NetEq::Config & config,rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,const DecoderMap & codecs,std::unique_ptr<std::ofstream> text_log,NetEqFactory * neteq_factory,std::unique_ptr<NetEqInput> input,std::unique_ptr<AudioSink> output,Callbacks callbacks)62 NetEqTest::NetEqTest(const NetEq::Config& config,
63                      rtc::scoped_refptr<AudioDecoderFactory> decoder_factory,
64                      const DecoderMap& codecs,
65                      std::unique_ptr<std::ofstream> text_log,
66                      NetEqFactory* neteq_factory,
67                      std::unique_ptr<NetEqInput> input,
68                      std::unique_ptr<AudioSink> output,
69                      Callbacks callbacks)
70     : clock_(0),
71       neteq_(neteq_factory
72                  ? neteq_factory->CreateNetEq(config, decoder_factory, &clock_)
73                  : CreateNetEq(config, &clock_, decoder_factory)),
74       input_(std::move(input)),
75       output_(std::move(output)),
76       callbacks_(callbacks),
77       sample_rate_hz_(config.sample_rate_hz),
78       text_log_(std::move(text_log)) {
79   RTC_CHECK(!config.enable_muted_state)
80       << "The code does not handle enable_muted_state";
81   RegisterDecoders(codecs);
82 }
83 
84 NetEqTest::~NetEqTest() = default;
85 
Run()86 int64_t NetEqTest::Run() {
87   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) {
94     callbacks_.simulation_ended_callback->SimulationEnded(simulation_time,
95                                                           neteq_.get());
96   }
97   return simulation_time;
98 }
99 
RunToNextGetAudio()100 NetEqTest::SimulationStepResult NetEqTest::RunToNextGetAudio() {
101   SimulationStepResult result;
102   const int64_t start_time_ms = *input_->NextEventTime();
103   int64_t time_now_ms = start_time_ms;
104   current_state_.packet_iat_ms.clear();
105 
106   while (!input_->ended()) {
107     // Advance time to next event.
108     RTC_DCHECK(input_->NextEventTime());
109     clock_.AdvanceTimeMilliseconds(*input_->NextEventTime() - time_now_ms);
110     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);
115       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,
120             rtc::ArrayView<const uint8_t>(packet_data->payload));
121         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);
130       }
131       if (last_packet_time_ms_) {
132         current_state_.packet_iat_ms.push_back(time_now_ms -
133                                                *last_packet_time_ms_);
134       }
135       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
152                    << ", seq_no: " << packet_data->header.sequenceNumber
153                    << ", 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       }
162       last_packet_time_ms_ = absl::make_optional<int>(time_now_ms);
163       last_packet_timestamp_ =
164           absl::make_optional<uint32_t>(packet_data->header.timestamp);
165     }
166 
167     // Check if it is time to get output audio.
168     if (input_->NextOutputEventTime() &&
169         time_now_ms >= *input_->NextOutputEventTime()) {
170       if (callbacks_.get_audio_callback) {
171         callbacks_.get_audio_callback->BeforeGetAudio(neteq_.get());
172       }
173       AudioFrame out_frame;
174       bool muted;
175       int error = neteq_->GetAudio(&out_frame, &muted,
176                                    ActionToOperations(next_action_));
177       next_action_ = absl::nullopt;
178       RTC_CHECK(!muted) << "The code does not handle enable_muted_state";
179       if (error != NetEq::kOK) {
180         if (callbacks_.error_callback) {
181           callbacks_.error_callback->OnGetAudioError();
182         }
183       } else {
184         sample_rate_hz_ = out_frame.sample_rate_hz_;
185       }
186       if (callbacks_.get_audio_callback) {
187         callbacks_.get_audio_callback->AfterGetAudio(time_now_ms, out_frame,
188                                                      muted, neteq_.get());
189       }
190 
191       if (output_) {
192         RTC_CHECK(output_->WriteArray(
193             out_frame.data(),
194             out_frame.samples_per_channel_ * out_frame.num_channels_));
195       }
196 
197       input_->AdvanceOutputEvent();
198       result.simulation_step_ms =
199           input_->NextEventTime().value_or(time_now_ms) - start_time_ms;
200       const auto operations_state = neteq_->GetOperationsAndState();
201       current_state_.current_delay_ms = operations_state.current_buffer_size_ms;
202       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;
208       // 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       }
233       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 =
240             (lifetime_stats.concealed_samples -
241              lifetime_stats.silent_concealed_samples) >
242             (prev_lifetime_stats_.concealed_samples -
243              prev_lifetime_stats_.silent_concealed_samples);
244         *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;
268       const bool no_more_packets_to_decode =
269           !input_->NextPacketTime() && !operations_state.next_packet_available;
270       result.is_simulation_finished =
271           no_more_packets_to_decode || input_->ended();
272       prev_ops_state_ = operations_state;
273       return result;
274     }
275   }
276   result.simulation_step_ms =
277       input_->NextEventTime().value_or(time_now_ms) - start_time_ms;
278   result.is_simulation_finished = true;
279   return result;
280 }
281 
SetNextAction(NetEqTest::Action next_operation)282 void NetEqTest::SetNextAction(NetEqTest::Action next_operation) {
283   next_action_ = absl::optional<Action>(next_operation);
284 }
285 
GetNetEqState()286 NetEqTest::NetEqState NetEqTest::GetNetEqState() {
287   return current_state_;
288 }
289 
SimulationStats()290 NetEqNetworkStatistics NetEqTest::SimulationStats() {
291   NetEqNetworkStatistics stats;
292   RTC_CHECK_EQ(neteq_->NetworkStatistics(&stats), 0);
293   return stats;
294 }
295 
LifetimeStats() const296 NetEqLifetimeStatistics NetEqTest::LifetimeStats() const {
297   return neteq_->GetLifetimeStatistics();
298 }
299 
StandardDecoderMap()300 NetEqTest::DecoderMap NetEqTest::StandardDecoderMap() {
301   DecoderMap codecs = {
302     {0, SdpAudioFormat("pcmu", 8000, 1)},
303     {8, SdpAudioFormat("pcma", 8000, 1)},
304 #ifdef WEBRTC_CODEC_ILBC
305     {102, SdpAudioFormat("ilbc", 8000, 1)},
306 #endif
307     {103, SdpAudioFormat("isac", 16000, 1)},
308 #if !defined(WEBRTC_ANDROID)
309     {104, SdpAudioFormat("isac", 32000, 1)},
310 #endif
311 #ifdef WEBRTC_CODEC_OPUS
312     {111, SdpAudioFormat("opus", 48000, 2)},
313 #endif
314     {93, SdpAudioFormat("l16", 8000, 1)},
315     {94, SdpAudioFormat("l16", 16000, 1)},
316     {95, SdpAudioFormat("l16", 32000, 1)},
317     {96, SdpAudioFormat("l16", 48000, 1)},
318     {9, SdpAudioFormat("g722", 8000, 1)},
319     {106, SdpAudioFormat("telephone-event", 8000, 1)},
320     {114, SdpAudioFormat("telephone-event", 16000, 1)},
321     {115, SdpAudioFormat("telephone-event", 32000, 1)},
322     {116, SdpAudioFormat("telephone-event", 48000, 1)},
323     {117, SdpAudioFormat("red", 8000, 1)},
324     {13, SdpAudioFormat("cn", 8000, 1)},
325     {98, SdpAudioFormat("cn", 16000, 1)},
326     {99, SdpAudioFormat("cn", 32000, 1)},
327     {100, SdpAudioFormat("cn", 48000, 1)}
328   };
329   return codecs;
330 }
331 
RegisterDecoders(const DecoderMap & codecs)332 void NetEqTest::RegisterDecoders(const DecoderMap& codecs) {
333   for (const auto& c : codecs) {
334     RTC_CHECK(neteq_->RegisterPayloadType(c.first, c.second))
335         << "Cannot register " << c.second.name << " to payload type "
336         << c.first;
337   }
338 }
339 
340 }  // namespace test
341 }  // namespace webrtc
342