• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2015 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 "testing/gmock/include/gmock/gmock.h"
12 #include "webrtc/base/scoped_ptr.h"
13 #include "webrtc/modules/audio_coding/neteq/tools/neteq_external_decoder_test.h"
14 #include "webrtc/modules/audio_coding/neteq/tools/rtp_generator.h"
15 
16 namespace webrtc {
17 namespace test {
18 
19 using ::testing::_;
20 using ::testing::SetArgPointee;
21 using ::testing::Return;
22 
23 class MockAudioDecoder final : public AudioDecoder {
24  public:
25   static const int kPacketDuration = 960;  // 48 kHz * 20 ms
26 
MockAudioDecoder(size_t num_channels)27   explicit MockAudioDecoder(size_t num_channels)
28       : num_channels_(num_channels), fec_enabled_(false) {
29   }
~MockAudioDecoder()30   ~MockAudioDecoder() override { Die(); }
31   MOCK_METHOD0(Die, void());
32 
33   MOCK_METHOD0(Reset, void());
34 
PacketDuration(const uint8_t * encoded,size_t encoded_len) const35   int PacketDuration(const uint8_t* encoded,
36                      size_t encoded_len) const override {
37     return kPacketDuration;
38   }
39 
PacketDurationRedundant(const uint8_t * encoded,size_t encoded_len) const40   int PacketDurationRedundant(const uint8_t* encoded,
41                               size_t encoded_len) const override {
42     return kPacketDuration;
43   }
44 
PacketHasFec(const uint8_t * encoded,size_t encoded_len) const45   bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const override {
46     return fec_enabled_;
47   }
48 
Channels() const49   size_t Channels() const override { return num_channels_; }
50 
set_fec_enabled(bool enable_fec)51   void set_fec_enabled(bool enable_fec) { fec_enabled_ = enable_fec; }
52 
fec_enabled() const53   bool fec_enabled() const { return fec_enabled_; }
54 
55  protected:
56   // Override the following methods such that no actual payload is needed.
DecodeInternal(const uint8_t * encoded,size_t encoded_len,int,int16_t * decoded,SpeechType * speech_type)57   int DecodeInternal(const uint8_t* encoded,
58                      size_t encoded_len,
59                      int /*sample_rate_hz*/,
60                      int16_t* decoded,
61                      SpeechType* speech_type) override {
62     *speech_type = kSpeech;
63     memset(decoded, 0, sizeof(int16_t) * kPacketDuration * Channels());
64     return kPacketDuration * Channels();
65   }
66 
DecodeRedundantInternal(const uint8_t * encoded,size_t encoded_len,int sample_rate_hz,int16_t * decoded,SpeechType * speech_type)67   int DecodeRedundantInternal(const uint8_t* encoded,
68                               size_t encoded_len,
69                               int sample_rate_hz,
70                               int16_t* decoded,
71                               SpeechType* speech_type) override {
72     return DecodeInternal(encoded, encoded_len, sample_rate_hz, decoded,
73                           speech_type);
74   }
75 
76  private:
77   const size_t num_channels_;
78   bool fec_enabled_;
79 };
80 
81 class NetEqNetworkStatsTest : public NetEqExternalDecoderTest {
82  public:
83   static const int kPayloadSizeByte = 30;
84   static const int kFrameSizeMs = 20;
85   static const int kMaxOutputSize = 960;  // 10 ms * 48 kHz * 2 channels.
86 
87 enum logic {
88   IGNORE,
89   EQUAL,
90   SMALLER_THAN,
91   LARGER_THAN,
92 };
93 
94 struct NetEqNetworkStatsCheck {
95   logic current_buffer_size_ms;
96   logic preferred_buffer_size_ms;
97   logic jitter_peaks_found;
98   logic packet_loss_rate;
99   logic packet_discard_rate;
100   logic expand_rate;
101   logic speech_expand_rate;
102   logic preemptive_rate;
103   logic accelerate_rate;
104   logic secondary_decoded_rate;
105   logic clockdrift_ppm;
106   logic added_zero_samples;
107   NetEqNetworkStatistics stats_ref;
108 };
109 
NetEqNetworkStatsTest(NetEqDecoder codec,MockAudioDecoder * decoder)110   NetEqNetworkStatsTest(NetEqDecoder codec,
111                         MockAudioDecoder* decoder)
112       : NetEqExternalDecoderTest(codec, decoder),
113         external_decoder_(decoder),
114         samples_per_ms_(CodecSampleRateHz(codec) / 1000),
115         frame_size_samples_(kFrameSizeMs * samples_per_ms_),
116         rtp_generator_(new test::RtpGenerator(samples_per_ms_)),
117         last_lost_time_(0),
118         packet_loss_interval_(0xffffffff) {
119     Init();
120   }
121 
Lost(uint32_t send_time)122   bool Lost(uint32_t send_time) {
123     if (send_time - last_lost_time_ >= packet_loss_interval_) {
124       last_lost_time_ = send_time;
125       return true;
126     }
127     return false;
128   }
129 
SetPacketLossRate(double loss_rate)130   void SetPacketLossRate(double loss_rate) {
131       packet_loss_interval_ = (loss_rate >= 1e-3 ?
132           static_cast<double>(kFrameSizeMs) / loss_rate : 0xffffffff);
133   }
134 
135   // |stats_ref|
136   // expects.x = -1, do not care
137   // expects.x = 0, 'x' in current stats should equal 'x' in |stats_ref|
138   // expects.x = 1, 'x' in current stats should < 'x' in |stats_ref|
139   // expects.x = 2, 'x' in current stats should > 'x' in |stats_ref|
CheckNetworkStatistics(NetEqNetworkStatsCheck expects)140   void CheckNetworkStatistics(NetEqNetworkStatsCheck expects) {
141     NetEqNetworkStatistics stats;
142     neteq()->NetworkStatistics(&stats);
143 
144 #define CHECK_NETEQ_NETWORK_STATS(x)\
145   switch (expects.x) {\
146     case EQUAL:\
147       EXPECT_EQ(stats.x, expects.stats_ref.x);\
148       break;\
149     case SMALLER_THAN:\
150       EXPECT_LT(stats.x, expects.stats_ref.x);\
151       break;\
152     case LARGER_THAN:\
153       EXPECT_GT(stats.x, expects.stats_ref.x);\
154       break;\
155     default:\
156       break;\
157   }
158 
159     CHECK_NETEQ_NETWORK_STATS(current_buffer_size_ms);
160     CHECK_NETEQ_NETWORK_STATS(preferred_buffer_size_ms);
161     CHECK_NETEQ_NETWORK_STATS(jitter_peaks_found);
162     CHECK_NETEQ_NETWORK_STATS(packet_loss_rate);
163     CHECK_NETEQ_NETWORK_STATS(packet_discard_rate);
164     CHECK_NETEQ_NETWORK_STATS(expand_rate);
165     CHECK_NETEQ_NETWORK_STATS(speech_expand_rate);
166     CHECK_NETEQ_NETWORK_STATS(preemptive_rate);
167     CHECK_NETEQ_NETWORK_STATS(accelerate_rate);
168     CHECK_NETEQ_NETWORK_STATS(secondary_decoded_rate);
169     CHECK_NETEQ_NETWORK_STATS(clockdrift_ppm);
170     CHECK_NETEQ_NETWORK_STATS(added_zero_samples);
171 
172 #undef CHECK_NETEQ_NETWORK_STATS
173 
174     // Compare with CurrentDelay, which should be identical.
175     EXPECT_EQ(stats.current_buffer_size_ms, neteq()->CurrentDelayMs());
176   }
177 
RunTest(int num_loops,NetEqNetworkStatsCheck expects)178   void RunTest(int num_loops, NetEqNetworkStatsCheck expects) {
179     NetEqOutputType output_type;
180     uint32_t time_now;
181     uint32_t next_send_time;
182 
183     // Initiate |last_lost_time_|.
184     time_now = next_send_time = last_lost_time_ =
185         rtp_generator_->GetRtpHeader(kPayloadType, frame_size_samples_,
186                                      &rtp_header_);
187     for (int k = 0; k < num_loops; ++k) {
188       // Delay by one frame such that the FEC can come in.
189       while (time_now + kFrameSizeMs >= next_send_time) {
190         next_send_time = rtp_generator_->GetRtpHeader(kPayloadType,
191                                                       frame_size_samples_,
192                                                       &rtp_header_);
193         if (!Lost(next_send_time)) {
194           InsertPacket(rtp_header_, payload_, next_send_time);
195         }
196       }
197       GetOutputAudio(kMaxOutputSize, output_, &output_type);
198       time_now += kOutputLengthMs;
199     }
200     CheckNetworkStatistics(expects);
201     neteq()->FlushBuffers();
202   }
203 
DecodeFecTest()204   void DecodeFecTest() {
205     external_decoder_->set_fec_enabled(false);
206     NetEqNetworkStatsCheck expects = {
207       IGNORE,  // current_buffer_size_ms
208       IGNORE,  // preferred_buffer_size_ms
209       IGNORE,  // jitter_peaks_found
210       EQUAL,  // packet_loss_rate
211       EQUAL,  // packet_discard_rate
212       EQUAL,  // expand_rate
213       EQUAL,  // voice_expand_rate
214       IGNORE,  // preemptive_rate
215       EQUAL,  // accelerate_rate
216       EQUAL,  // decoded_fec_rate
217       IGNORE,  // clockdrift_ppm
218       EQUAL,  // added_zero_samples
219       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
220     };
221     RunTest(50, expects);
222 
223     // Next we introduce packet losses.
224     SetPacketLossRate(0.1);
225     expects.stats_ref.packet_loss_rate = 1337;
226     expects.stats_ref.expand_rate = expects.stats_ref.speech_expand_rate = 1065;
227     RunTest(50, expects);
228 
229     // Next we enable FEC.
230     external_decoder_->set_fec_enabled(true);
231     // If FEC fills in the lost packets, no packet loss will be counted.
232     expects.stats_ref.packet_loss_rate = 0;
233     expects.stats_ref.expand_rate = expects.stats_ref.speech_expand_rate = 0;
234     expects.stats_ref.secondary_decoded_rate = 2006;
235     RunTest(50, expects);
236   }
237 
NoiseExpansionTest()238   void NoiseExpansionTest() {
239     NetEqNetworkStatsCheck expects = {
240       IGNORE,  // current_buffer_size_ms
241       IGNORE,  // preferred_buffer_size_ms
242       IGNORE,  // jitter_peaks_found
243       EQUAL,  // packet_loss_rate
244       EQUAL,  // packet_discard_rate
245       EQUAL,  // expand_rate
246       EQUAL,  // speech_expand_rate
247       IGNORE,  // preemptive_rate
248       EQUAL,  // accelerate_rate
249       EQUAL,  // decoded_fec_rate
250       IGNORE,  // clockdrift_ppm
251       EQUAL,  // added_zero_samples
252       {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
253     };
254     RunTest(50, expects);
255 
256     SetPacketLossRate(1);
257     expects.stats_ref.expand_rate = 16384;
258     expects.stats_ref.speech_expand_rate = 5324;
259     RunTest(10, expects);  // Lost 10 * 20ms in a row.
260   }
261 
262  private:
263   MockAudioDecoder* external_decoder_;
264   const int samples_per_ms_;
265   const size_t frame_size_samples_;
266   rtc::scoped_ptr<test::RtpGenerator> rtp_generator_;
267   WebRtcRTPHeader rtp_header_;
268   uint32_t last_lost_time_;
269   uint32_t packet_loss_interval_;
270   uint8_t payload_[kPayloadSizeByte];
271   int16_t output_[kMaxOutputSize];
272 };
273 
TEST(NetEqNetworkStatsTest,DecodeFec)274 TEST(NetEqNetworkStatsTest, DecodeFec) {
275   MockAudioDecoder decoder(1);
276   NetEqNetworkStatsTest test(NetEqDecoder::kDecoderOpus, &decoder);
277   test.DecodeFecTest();
278   EXPECT_CALL(decoder, Die()).Times(1);
279 }
280 
TEST(NetEqNetworkStatsTest,StereoDecodeFec)281 TEST(NetEqNetworkStatsTest, StereoDecodeFec) {
282   MockAudioDecoder decoder(2);
283   NetEqNetworkStatsTest test(NetEqDecoder::kDecoderOpus, &decoder);
284   test.DecodeFecTest();
285   EXPECT_CALL(decoder, Die()).Times(1);
286 }
287 
TEST(NetEqNetworkStatsTest,NoiseExpansionTest)288 TEST(NetEqNetworkStatsTest, NoiseExpansionTest) {
289   MockAudioDecoder decoder(1);
290   NetEqNetworkStatsTest test(NetEqDecoder::kDecoderOpus, &decoder);
291   test.NoiseExpansionTest();
292   EXPECT_CALL(decoder, Die()).Times(1);
293 }
294 
295 }  // namespace test
296 }  // namespace webrtc
297 
298 
299 
300 
301