• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 
Run(int runtime_ms,int lossrate,double drift_factor)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 =
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