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