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