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 "modules/audio_coding/codecs/red/audio_encoder_copy_red.h"
12 
13 #include <memory>
14 #include <vector>
15 
16 #include "rtc_base/checks.h"
17 #include "rtc_base/numerics/safe_conversions.h"
18 #include "test/gtest.h"
19 #include "test/mock_audio_encoder.h"
20 #include "test/testsupport/rtc_expect_death.h"
21 
22 using ::testing::_;
23 using ::testing::Eq;
24 using ::testing::InSequence;
25 using ::testing::Invoke;
26 using ::testing::MockFunction;
27 using ::testing::Not;
28 using ::testing::Optional;
29 using ::testing::Return;
30 using ::testing::SetArgPointee;
31 
32 namespace webrtc {
33 
34 namespace {
35 static const size_t kMaxNumSamples = 48 * 10 * 2;  // 10 ms @ 48 kHz stereo.
36 }
37 
38 class AudioEncoderCopyRedTest : public ::testing::Test {
39  protected:
AudioEncoderCopyRedTest()40   AudioEncoderCopyRedTest()
41       : mock_encoder_(new MockAudioEncoder),
42         timestamp_(4711),
43         sample_rate_hz_(16000),
44         num_audio_samples_10ms(sample_rate_hz_ / 100),
45         red_payload_type_(200) {
46     AudioEncoderCopyRed::Config config;
47     config.payload_type = red_payload_type_;
48     config.speech_encoder = std::unique_ptr<AudioEncoder>(mock_encoder_);
49     red_.reset(new AudioEncoderCopyRed(std::move(config)));
50     memset(audio_, 0, sizeof(audio_));
51     EXPECT_CALL(*mock_encoder_, NumChannels()).WillRepeatedly(Return(1U));
52     EXPECT_CALL(*mock_encoder_, SampleRateHz())
53         .WillRepeatedly(Return(sample_rate_hz_));
54   }
55 
TearDown()56   void TearDown() override { red_.reset(); }
57 
Encode()58   void Encode() {
59     ASSERT_TRUE(red_.get() != NULL);
60     encoded_.Clear();
61     encoded_info_ = red_->Encode(
62         timestamp_,
63         rtc::ArrayView<const int16_t>(audio_, num_audio_samples_10ms),
64         &encoded_);
65     timestamp_ += rtc::checked_cast<uint32_t>(num_audio_samples_10ms);
66   }
67 
68   MockAudioEncoder* mock_encoder_;
69   std::unique_ptr<AudioEncoderCopyRed> red_;
70   uint32_t timestamp_;
71   int16_t audio_[kMaxNumSamples];
72   const int sample_rate_hz_;
73   size_t num_audio_samples_10ms;
74   rtc::Buffer encoded_;
75   AudioEncoder::EncodedInfo encoded_info_;
76   const int red_payload_type_;
77 };
78 
TEST_F(AudioEncoderCopyRedTest,CreateAndDestroy)79 TEST_F(AudioEncoderCopyRedTest, CreateAndDestroy) {}
80 
TEST_F(AudioEncoderCopyRedTest,CheckSampleRatePropagation)81 TEST_F(AudioEncoderCopyRedTest, CheckSampleRatePropagation) {
82   EXPECT_CALL(*mock_encoder_, SampleRateHz()).WillOnce(Return(17));
83   EXPECT_EQ(17, red_->SampleRateHz());
84 }
85 
TEST_F(AudioEncoderCopyRedTest,CheckNumChannelsPropagation)86 TEST_F(AudioEncoderCopyRedTest, CheckNumChannelsPropagation) {
87   EXPECT_CALL(*mock_encoder_, NumChannels()).WillOnce(Return(17U));
88   EXPECT_EQ(17U, red_->NumChannels());
89 }
90 
TEST_F(AudioEncoderCopyRedTest,CheckFrameSizePropagation)91 TEST_F(AudioEncoderCopyRedTest, CheckFrameSizePropagation) {
92   EXPECT_CALL(*mock_encoder_, Num10MsFramesInNextPacket())
93       .WillOnce(Return(17U));
94   EXPECT_EQ(17U, red_->Num10MsFramesInNextPacket());
95 }
96 
TEST_F(AudioEncoderCopyRedTest,CheckMaxFrameSizePropagation)97 TEST_F(AudioEncoderCopyRedTest, CheckMaxFrameSizePropagation) {
98   EXPECT_CALL(*mock_encoder_, Max10MsFramesInAPacket()).WillOnce(Return(17U));
99   EXPECT_EQ(17U, red_->Max10MsFramesInAPacket());
100 }
101 
TEST_F(AudioEncoderCopyRedTest,CheckTargetAudioBitratePropagation)102 TEST_F(AudioEncoderCopyRedTest, CheckTargetAudioBitratePropagation) {
103   EXPECT_CALL(*mock_encoder_,
104               OnReceivedUplinkBandwidth(4711, absl::optional<int64_t>()));
105   red_->OnReceivedUplinkBandwidth(4711, absl::nullopt);
106 }
107 
TEST_F(AudioEncoderCopyRedTest,CheckPacketLossFractionPropagation)108 TEST_F(AudioEncoderCopyRedTest, CheckPacketLossFractionPropagation) {
109   EXPECT_CALL(*mock_encoder_, OnReceivedUplinkPacketLossFraction(0.5));
110   red_->OnReceivedUplinkPacketLossFraction(0.5);
111 }
112 
TEST_F(AudioEncoderCopyRedTest,CheckGetFrameLengthRangePropagation)113 TEST_F(AudioEncoderCopyRedTest, CheckGetFrameLengthRangePropagation) {
114   auto expected_range =
115       std::make_pair(TimeDelta::Millis(20), TimeDelta::Millis(20));
116   EXPECT_CALL(*mock_encoder_, GetFrameLengthRange())
117       .WillRepeatedly(Return(absl::make_optional(expected_range)));
118   EXPECT_THAT(red_->GetFrameLengthRange(), Optional(Eq(expected_range)));
119 }
120 
121 // Checks that the an Encode() call is immediately propagated to the speech
122 // encoder.
TEST_F(AudioEncoderCopyRedTest,CheckImmediateEncode)123 TEST_F(AudioEncoderCopyRedTest, CheckImmediateEncode) {
124   // Interleaving the EXPECT_CALL sequence with expectations on the MockFunction
125   // check ensures that exactly one call to EncodeImpl happens in each
126   // Encode call.
127   InSequence s;
128   MockFunction<void(int check_point_id)> check;
129   for (int i = 1; i <= 6; ++i) {
130     EXPECT_CALL(*mock_encoder_, EncodeImpl(_, _, _))
131         .WillRepeatedly(Return(AudioEncoder::EncodedInfo()));
132     EXPECT_CALL(check, Call(i));
133     Encode();
134     check.Call(i);
135   }
136 }
137 
138 // Checks that no output is produced if the underlying codec doesn't emit any
139 // new data, even if the RED codec is loaded with a secondary encoding.
TEST_F(AudioEncoderCopyRedTest,CheckNoOutput)140 TEST_F(AudioEncoderCopyRedTest, CheckNoOutput) {
141   static const size_t kEncodedSize = 17;
142   {
143     InSequence s;
144     EXPECT_CALL(*mock_encoder_, EncodeImpl(_, _, _))
145         .WillOnce(Invoke(MockAudioEncoder::FakeEncoding(kEncodedSize)))
146         .WillOnce(Invoke(MockAudioEncoder::FakeEncoding(0)))
147         .WillOnce(Invoke(MockAudioEncoder::FakeEncoding(kEncodedSize)));
148   }
149 
150   // Start with one Encode() call that will produce output.
151   Encode();
152   // First call is a special case, since it does not include a secondary
153   // payload.
154   EXPECT_EQ(1u, encoded_info_.redundant.size());
155   EXPECT_EQ(kEncodedSize, encoded_info_.encoded_bytes);
156 
157   // Next call to the speech encoder will not produce any output.
158   Encode();
159   EXPECT_EQ(0u, encoded_info_.encoded_bytes);
160 
161   // Final call to the speech encoder will produce output.
162   Encode();
163   EXPECT_EQ(2 * kEncodedSize, encoded_info_.encoded_bytes);
164   ASSERT_EQ(2u, encoded_info_.redundant.size());
165 }
166 
167 // Checks that the correct payload sizes are populated into the redundancy
168 // information.
TEST_F(AudioEncoderCopyRedTest,CheckPayloadSizes)169 TEST_F(AudioEncoderCopyRedTest, CheckPayloadSizes) {
170   // Let the mock encoder return payload sizes 1, 2, 3, ..., 10 for the sequence
171   // of calls.
172   static const int kNumPackets = 10;
173   InSequence s;
174   for (int encode_size = 1; encode_size <= kNumPackets; ++encode_size) {
175     EXPECT_CALL(*mock_encoder_, EncodeImpl(_, _, _))
176         .WillOnce(Invoke(MockAudioEncoder::FakeEncoding(encode_size)));
177   }
178 
179   // First call is a special case, since it does not include a secondary
180   // payload.
181   Encode();
182   EXPECT_EQ(1u, encoded_info_.redundant.size());
183   EXPECT_EQ(1u, encoded_info_.encoded_bytes);
184 
185   for (size_t i = 2; i <= kNumPackets; ++i) {
186     Encode();
187     ASSERT_EQ(2u, encoded_info_.redundant.size());
188     EXPECT_EQ(i, encoded_info_.redundant[0].encoded_bytes);
189     EXPECT_EQ(i - 1, encoded_info_.redundant[1].encoded_bytes);
190     EXPECT_EQ(i + i - 1, encoded_info_.encoded_bytes);
191   }
192 }
193 
194 // Checks that the correct timestamps are returned.
TEST_F(AudioEncoderCopyRedTest,CheckTimestamps)195 TEST_F(AudioEncoderCopyRedTest, CheckTimestamps) {
196   uint32_t primary_timestamp = timestamp_;
197   AudioEncoder::EncodedInfo info;
198   info.encoded_bytes = 17;
199   info.encoded_timestamp = timestamp_;
200 
201   EXPECT_CALL(*mock_encoder_, EncodeImpl(_, _, _))
202       .WillOnce(Invoke(MockAudioEncoder::FakeEncoding(info)));
203 
204   // First call is a special case, since it does not include a secondary
205   // payload.
206   Encode();
207   EXPECT_EQ(primary_timestamp, encoded_info_.encoded_timestamp);
208 
209   uint32_t secondary_timestamp = primary_timestamp;
210   primary_timestamp = timestamp_;
211   info.encoded_timestamp = timestamp_;
212   EXPECT_CALL(*mock_encoder_, EncodeImpl(_, _, _))
213       .WillOnce(Invoke(MockAudioEncoder::FakeEncoding(info)));
214 
215   Encode();
216   ASSERT_EQ(2u, encoded_info_.redundant.size());
217   EXPECT_EQ(primary_timestamp, encoded_info_.redundant[0].encoded_timestamp);
218   EXPECT_EQ(secondary_timestamp, encoded_info_.redundant[1].encoded_timestamp);
219   EXPECT_EQ(primary_timestamp, encoded_info_.encoded_timestamp);
220 }
221 
222 // Checks that the primary and secondary payloads are written correctly.
TEST_F(AudioEncoderCopyRedTest,CheckPayloads)223 TEST_F(AudioEncoderCopyRedTest, CheckPayloads) {
224   // Let the mock encoder write payloads with increasing values. The first
225   // payload will have values 0, 1, 2, ..., kPayloadLenBytes - 1.
226   static const size_t kPayloadLenBytes = 5;
227   uint8_t payload[kPayloadLenBytes];
228   for (uint8_t i = 0; i < kPayloadLenBytes; ++i) {
229     payload[i] = i;
230   }
231   EXPECT_CALL(*mock_encoder_, EncodeImpl(_, _, _))
232       .WillRepeatedly(Invoke(MockAudioEncoder::CopyEncoding(payload)));
233 
234   // First call is a special case, since it does not include a secondary
235   // payload.
236   Encode();
237   EXPECT_EQ(kPayloadLenBytes, encoded_info_.encoded_bytes);
238   for (size_t i = 0; i < kPayloadLenBytes; ++i) {
239     EXPECT_EQ(i, encoded_.data()[i]);
240   }
241 
242   for (int j = 0; j < 5; ++j) {
243     // Increment all values of the payload by 10.
244     for (size_t i = 0; i < kPayloadLenBytes; ++i)
245       payload[i] += 10;
246 
247     Encode();
248     ASSERT_EQ(2u, encoded_info_.redundant.size());
249     EXPECT_EQ(kPayloadLenBytes, encoded_info_.redundant[0].encoded_bytes);
250     EXPECT_EQ(kPayloadLenBytes, encoded_info_.redundant[1].encoded_bytes);
251     for (size_t i = 0; i < kPayloadLenBytes; ++i) {
252       // Check primary payload.
253       EXPECT_EQ((j + 1) * 10 + i, encoded_.data()[i]);
254       // Check secondary payload.
255       EXPECT_EQ(j * 10 + i, encoded_.data()[i + kPayloadLenBytes]);
256     }
257   }
258 }
259 
260 // Checks correct propagation of payload type.
261 // Checks that the correct timestamps are returned.
TEST_F(AudioEncoderCopyRedTest,CheckPayloadType)262 TEST_F(AudioEncoderCopyRedTest, CheckPayloadType) {
263   const int primary_payload_type = red_payload_type_ + 1;
264   AudioEncoder::EncodedInfo info;
265   info.encoded_bytes = 17;
266   info.payload_type = primary_payload_type;
267   EXPECT_CALL(*mock_encoder_, EncodeImpl(_, _, _))
268       .WillOnce(Invoke(MockAudioEncoder::FakeEncoding(info)));
269 
270   // First call is a special case, since it does not include a secondary
271   // payload.
272   Encode();
273   ASSERT_EQ(1u, encoded_info_.redundant.size());
274   EXPECT_EQ(primary_payload_type, encoded_info_.redundant[0].payload_type);
275   EXPECT_EQ(red_payload_type_, encoded_info_.payload_type);
276 
277   const int secondary_payload_type = red_payload_type_ + 2;
278   info.payload_type = secondary_payload_type;
279   EXPECT_CALL(*mock_encoder_, EncodeImpl(_, _, _))
280       .WillOnce(Invoke(MockAudioEncoder::FakeEncoding(info)));
281 
282   Encode();
283   ASSERT_EQ(2u, encoded_info_.redundant.size());
284   EXPECT_EQ(secondary_payload_type, encoded_info_.redundant[0].payload_type);
285   EXPECT_EQ(primary_payload_type, encoded_info_.redundant[1].payload_type);
286   EXPECT_EQ(red_payload_type_, encoded_info_.payload_type);
287 }
288 
289 #if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
290 
291 // This test fixture tests various error conditions that makes the
292 // AudioEncoderCng die via CHECKs.
293 class AudioEncoderCopyRedDeathTest : public AudioEncoderCopyRedTest {
294  protected:
AudioEncoderCopyRedDeathTest()295   AudioEncoderCopyRedDeathTest() : AudioEncoderCopyRedTest() {}
296 };
297 
TEST_F(AudioEncoderCopyRedDeathTest,WrongFrameSize)298 TEST_F(AudioEncoderCopyRedDeathTest, WrongFrameSize) {
299   num_audio_samples_10ms *= 2;  // 20 ms frame.
300   RTC_EXPECT_DEATH(Encode(), "");
301   num_audio_samples_10ms = 0;  // Zero samples.
302   RTC_EXPECT_DEATH(Encode(), "");
303 }
304 
TEST_F(AudioEncoderCopyRedDeathTest,NullSpeechEncoder)305 TEST_F(AudioEncoderCopyRedDeathTest, NullSpeechEncoder) {
306   AudioEncoderCopyRed* red = NULL;
307   AudioEncoderCopyRed::Config config;
308   config.speech_encoder = NULL;
309   RTC_EXPECT_DEATH(red = new AudioEncoderCopyRed(std::move(config)),
310                    "Speech encoder not provided.");
311   // The delete operation is needed to avoid leak reports from memcheck.
312   delete red;
313 }
314 
315 #endif  // GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
316 
317 }  // namespace webrtc
318