1/* 2 * Copyright (c) 2014 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 "webrtc/modules/audio_coding/neteq/tools/neteq_performance_test.h" 12 13#include "webrtc/modules/audio_coding/codecs/pcm16b/pcm16b.h" 14#include "webrtc/modules/audio_coding/neteq/include/neteq.h" 15#include "webrtc/modules/audio_coding/neteq/tools/audio_loop.h" 16#include "webrtc/modules/audio_coding/neteq/tools/rtp_generator.h" 17#include "webrtc/system_wrappers/include/clock.h" 18#include "webrtc/test/testsupport/fileutils.h" 19#include "webrtc/typedefs.h" 20 21using webrtc::NetEq; 22using webrtc::test::AudioLoop; 23using webrtc::test::RtpGenerator; 24using webrtc::WebRtcRTPHeader; 25 26namespace webrtc { 27namespace test { 28 29int64_t NetEqPerformanceTest::Run(int runtime_ms, 30 int lossrate, 31 double drift_factor) { 32 const std::string kInputFileName = 33 webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"); 34 const int kSampRateHz = 32000; 35 const webrtc::NetEqDecoder kDecoderType = 36 webrtc::NetEqDecoder::kDecoderPCM16Bswb32kHz; 37 const std::string kDecoderName = "pcm16-swb32"; 38 const int kPayloadType = 95; 39 40 // Initialize NetEq instance. 41 NetEq::Config config; 42 config.sample_rate_hz = kSampRateHz; 43 NetEq* neteq = NetEq::Create(config); 44 // Register decoder in |neteq|. 45 if (neteq->RegisterPayloadType(kDecoderType, kDecoderName, kPayloadType) != 0) 46 return -1; 47 48 // Set up AudioLoop object. 49 AudioLoop audio_loop; 50 const size_t kMaxLoopLengthSamples = kSampRateHz * 10; // 10 second loop. 51 const size_t kInputBlockSizeSamples = 60 * kSampRateHz / 1000; // 60 ms. 52 if (!audio_loop.Init(kInputFileName, kMaxLoopLengthSamples, 53 kInputBlockSizeSamples)) 54 return -1; 55 56 int32_t time_now_ms = 0; 57 58 // Get first input packet. 59 WebRtcRTPHeader rtp_header; 60 RtpGenerator rtp_gen(kSampRateHz / 1000); 61 // Start with positive drift first half of simulation. 62 rtp_gen.set_drift_factor(drift_factor); 63 bool drift_flipped = false; 64 int32_t packet_input_time_ms = 65 rtp_gen.GetRtpHeader(kPayloadType, kInputBlockSizeSamples, &rtp_header); 66 auto input_samples = audio_loop.GetNextBlock(); 67 if (input_samples.empty()) 68 exit(1); 69 uint8_t input_payload[kInputBlockSizeSamples * sizeof(int16_t)]; 70 size_t payload_len = WebRtcPcm16b_Encode(input_samples.data(), 71 input_samples.size(), input_payload); 72 RTC_CHECK_EQ(sizeof(input_payload), payload_len); 73 74 // Main loop. 75 webrtc::Clock* clock = webrtc::Clock::GetRealTimeClock(); 76 int64_t start_time_ms = clock->TimeInMilliseconds(); 77 while (time_now_ms < runtime_ms) { 78 while (packet_input_time_ms <= time_now_ms) { 79 // Drop every N packets, where N = FLAGS_lossrate. 80 bool lost = false; 81 if (lossrate > 0) { 82 lost = ((rtp_header.header.sequenceNumber - 1) % lossrate) == 0; 83 } 84 if (!lost) { 85 // Insert packet. 86 int error = 87 neteq->InsertPacket(rtp_header, input_payload, 88 packet_input_time_ms * kSampRateHz / 1000); 89 if (error != NetEq::kOK) 90 return -1; 91 } 92 93 // Get next packet. 94 packet_input_time_ms = rtp_gen.GetRtpHeader(kPayloadType, 95 kInputBlockSizeSamples, 96 &rtp_header); 97 input_samples = audio_loop.GetNextBlock(); 98 if (input_samples.empty()) 99 return -1; 100 payload_len = WebRtcPcm16b_Encode(input_samples.data(), 101 input_samples.size(), input_payload); 102 assert(payload_len == kInputBlockSizeSamples * sizeof(int16_t)); 103 } 104 105 // Get output audio, but don't do anything with it. 106 static const int kMaxChannels = 1; 107 static const size_t kMaxSamplesPerMs = 48000 / 1000; 108 static const int kOutputBlockSizeMs = 10; 109 static const size_t kOutDataLen = 110 kOutputBlockSizeMs * kMaxSamplesPerMs * kMaxChannels; 111 int16_t out_data[kOutDataLen]; 112 size_t num_channels; 113 size_t samples_per_channel; 114 int error = neteq->GetAudio(kOutDataLen, out_data, &samples_per_channel, 115 &num_channels, NULL); 116 if (error != NetEq::kOK) 117 return -1; 118 119 assert(samples_per_channel == static_cast<size_t>(kSampRateHz * 10 / 1000)); 120 121 time_now_ms += kOutputBlockSizeMs; 122 if (time_now_ms >= runtime_ms / 2 && !drift_flipped) { 123 // Apply negative drift second half of simulation. 124 rtp_gen.set_drift_factor(-drift_factor); 125 drift_flipped = true; 126 } 127 } 128 int64_t end_time_ms = clock->TimeInMilliseconds(); 129 delete neteq; 130 return end_time_ms - start_time_ms; 131} 132 133} // namespace test 134} // namespace webrtc 135