| /* | 
 |  *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 |  | 
 | #include "webrtc/modules/audio_coding/neteq/tools/neteq_test.h" | 
 |  | 
 | #include <iostream> | 
 |  | 
 | #include "webrtc/api/audio_codecs/builtin_audio_decoder_factory.h" | 
 |  | 
 | namespace webrtc { | 
 | namespace test { | 
 |  | 
 | void DefaultNetEqTestErrorCallback::OnInsertPacketError( | 
 |     int error_code, | 
 |     const NetEqInput::PacketData& packet) { | 
 |   if (error_code == NetEq::kUnknownRtpPayloadType) { | 
 |     std::cerr << "RTP Payload type " | 
 |               << static_cast<int>(packet.header.header.payloadType) | 
 |               << " is unknown." << std::endl; | 
 |   } else { | 
 |     std::cerr << "InsertPacket returned error code " << error_code << std::endl; | 
 |     std::cerr << "Header data:" << std::endl; | 
 |     std::cerr << "  PT = " << static_cast<int>(packet.header.header.payloadType) | 
 |               << std::endl; | 
 |     std::cerr << "  SN = " << packet.header.header.sequenceNumber << std::endl; | 
 |     std::cerr << "  TS = " << packet.header.header.timestamp << std::endl; | 
 |   } | 
 |   FATAL(); | 
 | } | 
 |  | 
 | void DefaultNetEqTestErrorCallback::OnGetAudioError(int error_code) { | 
 |   std::cerr << "GetAudio returned error code " << error_code << std::endl; | 
 |   FATAL(); | 
 | } | 
 |  | 
 | NetEqTest::NetEqTest(const NetEq::Config& config, | 
 |                      const DecoderMap& codecs, | 
 |                      const ExtDecoderMap& ext_codecs, | 
 |                      std::unique_ptr<NetEqInput> input, | 
 |                      std::unique_ptr<AudioSink> output, | 
 |                      NetEqTestErrorCallback* error_callback) | 
 |     : neteq_(NetEq::Create(config, CreateBuiltinAudioDecoderFactory())), | 
 |       input_(std::move(input)), | 
 |       output_(std::move(output)), | 
 |       error_callback_(error_callback), | 
 |       sample_rate_hz_(config.sample_rate_hz) { | 
 |   RTC_CHECK(!config.enable_muted_state) | 
 |       << "The code does not handle enable_muted_state"; | 
 |   RegisterDecoders(codecs); | 
 |   RegisterExternalDecoders(ext_codecs); | 
 | } | 
 |  | 
 | int64_t NetEqTest::Run() { | 
 |   const int64_t start_time_ms = *input_->NextEventTime(); | 
 |   int64_t time_now_ms = start_time_ms; | 
 |  | 
 |   while (!input_->ended()) { | 
 |     // Advance time to next event. | 
 |     RTC_DCHECK(input_->NextEventTime()); | 
 |     time_now_ms = *input_->NextEventTime(); | 
 |     // Check if it is time to insert packet. | 
 |     if (input_->NextPacketTime() && time_now_ms >= *input_->NextPacketTime()) { | 
 |       std::unique_ptr<NetEqInput::PacketData> packet_data = input_->PopPacket(); | 
 |       RTC_CHECK(packet_data); | 
 |       int error = neteq_->InsertPacket( | 
 |           packet_data->header, | 
 |           rtc::ArrayView<const uint8_t>(packet_data->payload), | 
 |           static_cast<uint32_t>(packet_data->time_ms * sample_rate_hz_ / 1000)); | 
 |       if (error != NetEq::kOK && error_callback_) { | 
 |         error_callback_->OnInsertPacketError(neteq_->LastError(), *packet_data); | 
 |       } | 
 |     } | 
 |  | 
 |     // Check if it is time to get output audio. | 
 |     if (input_->NextOutputEventTime() && | 
 |         time_now_ms >= *input_->NextOutputEventTime()) { | 
 |       AudioFrame out_frame; | 
 |       bool muted; | 
 |       int error = neteq_->GetAudio(&out_frame, &muted); | 
 |       RTC_CHECK(!muted) << "The code does not handle enable_muted_state"; | 
 |       if (error != NetEq::kOK) { | 
 |         if (error_callback_) { | 
 |           error_callback_->OnGetAudioError(neteq_->LastError()); | 
 |         } | 
 |       } else { | 
 |         sample_rate_hz_ = out_frame.sample_rate_hz_; | 
 |       } | 
 |  | 
 |       if (output_) { | 
 |         RTC_CHECK(output_->WriteArray( | 
 |             out_frame.data_, | 
 |             out_frame.samples_per_channel_ * out_frame.num_channels_)); | 
 |       } | 
 |  | 
 |       input_->AdvanceOutputEvent(); | 
 |     } | 
 |   } | 
 |   return time_now_ms - start_time_ms; | 
 | } | 
 |  | 
 | NetEqNetworkStatistics NetEqTest::SimulationStats() { | 
 |   NetEqNetworkStatistics stats; | 
 |   RTC_CHECK_EQ(neteq_->NetworkStatistics(&stats), 0); | 
 |   return stats; | 
 | } | 
 |  | 
 | void NetEqTest::RegisterDecoders(const DecoderMap& codecs) { | 
 |   for (const auto& c : codecs) { | 
 |     RTC_CHECK_EQ( | 
 |         neteq_->RegisterPayloadType(c.second.first, c.second.second, c.first), | 
 |         NetEq::kOK) | 
 |         << "Cannot register " << c.second.second << " to payload type " | 
 |         << c.first; | 
 |   } | 
 | } | 
 |  | 
 | void NetEqTest::RegisterExternalDecoders(const ExtDecoderMap& codecs) { | 
 |   for (const auto& c : codecs) { | 
 |     RTC_CHECK_EQ( | 
 |         neteq_->RegisterExternalDecoder(c.second.decoder, c.second.codec, | 
 |                                         c.second.codec_name, c.first), | 
 |         NetEq::kOK) | 
 |         << "Cannot register " << c.second.codec_name << " to payload type " | 
 |         << c.first; | 
 |   } | 
 | } | 
 |  | 
 | }  // namespace test | 
 | }  // namespace webrtc |