| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (c) 2013 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/main/acm2/acm_receiver.h" | |
| 12 | |
| 13 #include <algorithm> // std::min | |
| 14 | |
| 15 #include "testing/gtest/include/gtest/gtest.h" | |
| 16 #include "webrtc/base/scoped_ptr.h" | |
| 17 #include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h" | |
| 18 #include "webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h" | |
| 19 #include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h" | |
| 20 #include "webrtc/modules/audio_coding/neteq/tools/rtp_generator.h" | |
| 21 #include "webrtc/system_wrappers/interface/clock.h" | |
| 22 #include "webrtc/test/test_suite.h" | |
| 23 #include "webrtc/test/testsupport/fileutils.h" | |
| 24 #include "webrtc/test/testsupport/gtest_disable.h" | |
| 25 | |
| 26 namespace webrtc { | |
| 27 | |
| 28 namespace acm2 { | |
| 29 namespace { | |
| 30 | |
| 31 bool CodecsEqual(const CodecInst& codec_a, const CodecInst& codec_b) { | |
| 32 if (strcmp(codec_a.plname, codec_b.plname) != 0 || | |
| 33 codec_a.plfreq != codec_b.plfreq || | |
| 34 codec_a.pltype != codec_b.pltype || | |
| 35 codec_b.channels != codec_a.channels) | |
| 36 return false; | |
| 37 return true; | |
| 38 } | |
| 39 | |
| 40 } // namespace | |
| 41 | |
| 42 class AcmReceiverTest : public AudioPacketizationCallback, | |
| 43 public ::testing::Test { | |
| 44 protected: | |
| 45 AcmReceiverTest() | |
| 46 : timestamp_(0), | |
| 47 packet_sent_(false), | |
| 48 last_packet_send_timestamp_(timestamp_), | |
| 49 last_frame_type_(kEmptyFrame) { | |
| 50 AudioCoding::Config config; | |
| 51 config.transport = this; | |
| 52 acm_.reset(new AudioCodingImpl(config)); | |
| 53 receiver_.reset(new AcmReceiver(config.ToOldConfig())); | |
| 54 } | |
| 55 | |
| 56 ~AcmReceiverTest() {} | |
| 57 | |
| 58 void SetUp() override { | |
| 59 ASSERT_TRUE(receiver_.get() != NULL); | |
| 60 ASSERT_TRUE(acm_.get() != NULL); | |
| 61 for (int n = 0; n < ACMCodecDB::kNumCodecs; n++) { | |
| 62 ASSERT_EQ(0, ACMCodecDB::Codec(n, &codecs_[n])); | |
| 63 } | |
| 64 | |
| 65 rtp_header_.header.sequenceNumber = 0; | |
| 66 rtp_header_.header.timestamp = 0; | |
| 67 rtp_header_.header.markerBit = false; | |
| 68 rtp_header_.header.ssrc = 0x12345678; // Arbitrary. | |
| 69 rtp_header_.header.numCSRCs = 0; | |
| 70 rtp_header_.header.payloadType = 0; | |
| 71 rtp_header_.frameType = kAudioFrameSpeech; | |
| 72 rtp_header_.type.Audio.isCNG = false; | |
| 73 } | |
| 74 | |
| 75 void TearDown() override {} | |
| 76 | |
| 77 void InsertOnePacketOfSilence(int codec_id) { | |
| 78 CodecInst codec; | |
| 79 ACMCodecDB::Codec(codec_id, &codec); | |
| 80 if (timestamp_ == 0) { // This is the first time inserting audio. | |
| 81 ASSERT_TRUE(acm_->RegisterSendCodec(codec_id, codec.pltype)); | |
| 82 } else { | |
| 83 const CodecInst* current_codec = acm_->GetSenderCodecInst(); | |
| 84 ASSERT_TRUE(current_codec); | |
| 85 if (!CodecsEqual(codec, *current_codec)) | |
| 86 ASSERT_TRUE(acm_->RegisterSendCodec(codec_id, codec.pltype)); | |
| 87 } | |
| 88 AudioFrame frame; | |
| 89 // Frame setup according to the codec. | |
| 90 frame.sample_rate_hz_ = codec.plfreq; | |
| 91 frame.samples_per_channel_ = codec.plfreq / 100; // 10 ms. | |
| 92 frame.num_channels_ = codec.channels; | |
| 93 memset(frame.data_, 0, frame.samples_per_channel_ * frame.num_channels_ * | |
| 94 sizeof(int16_t)); | |
| 95 int num_bytes = 0; | |
| 96 packet_sent_ = false; | |
| 97 last_packet_send_timestamp_ = timestamp_; | |
| 98 while (num_bytes == 0) { | |
| 99 frame.timestamp_ = timestamp_; | |
| 100 timestamp_ += frame.samples_per_channel_; | |
| 101 num_bytes = acm_->Add10MsAudio(frame); | |
| 102 ASSERT_GE(num_bytes, 0); | |
| 103 } | |
| 104 ASSERT_TRUE(packet_sent_); // Sanity check. | |
| 105 } | |
| 106 | |
| 107 // Last element of id should be negative. | |
| 108 void AddSetOfCodecs(const int* id) { | |
| 109 int n = 0; | |
| 110 while (id[n] >= 0) { | |
| 111 ASSERT_EQ(0, receiver_->AddCodec(id[n], codecs_[id[n]].pltype, | |
| 112 codecs_[id[n]].channels, | |
| 113 codecs_[id[n]].plfreq, NULL)); | |
| 114 ++n; | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 int32_t SendData(FrameType frame_type, | |
| 119 uint8_t payload_type, | |
| 120 uint32_t timestamp, | |
| 121 const uint8_t* payload_data, | |
| 122 size_t payload_len_bytes, | |
| 123 const RTPFragmentationHeader* fragmentation) override { | |
| 124 if (frame_type == kEmptyFrame) | |
| 125 return 0; | |
| 126 | |
| 127 rtp_header_.header.payloadType = payload_type; | |
| 128 rtp_header_.frameType = frame_type; | |
| 129 if (frame_type == kAudioFrameSpeech) | |
| 130 rtp_header_.type.Audio.isCNG = false; | |
| 131 else | |
| 132 rtp_header_.type.Audio.isCNG = true; | |
| 133 rtp_header_.header.timestamp = timestamp; | |
| 134 | |
| 135 int ret_val = receiver_->InsertPacket(rtp_header_, payload_data, | |
| 136 payload_len_bytes); | |
| 137 if (ret_val < 0) { | |
| 138 assert(false); | |
| 139 return -1; | |
| 140 } | |
| 141 rtp_header_.header.sequenceNumber++; | |
| 142 packet_sent_ = true; | |
| 143 last_frame_type_ = frame_type; | |
| 144 return 0; | |
| 145 } | |
| 146 | |
| 147 rtc::scoped_ptr<AcmReceiver> receiver_; | |
| 148 CodecInst codecs_[ACMCodecDB::kMaxNumCodecs]; | |
| 149 rtc::scoped_ptr<AudioCoding> acm_; | |
| 150 WebRtcRTPHeader rtp_header_; | |
| 151 uint32_t timestamp_; | |
| 152 bool packet_sent_; // Set when SendData is called reset when inserting audio. | |
| 153 uint32_t last_packet_send_timestamp_; | |
| 154 FrameType last_frame_type_; | |
| 155 }; | |
| 156 | |
| 157 TEST_F(AcmReceiverTest, DISABLED_ON_ANDROID(AddCodecGetCodec)) { | |
| 158 // Add codec. | |
| 159 for (int n = 0; n < ACMCodecDB::kNumCodecs; ++n) { | |
| 160 if (n & 0x1) // Just add codecs with odd index. | |
| 161 EXPECT_EQ(0, | |
| 162 receiver_->AddCodec(n, codecs_[n].pltype, codecs_[n].channels, | |
| 163 codecs_[n].plfreq, NULL)); | |
| 164 } | |
| 165 // Get codec and compare. | |
| 166 for (int n = 0; n < ACMCodecDB::kNumCodecs; ++n) { | |
| 167 CodecInst my_codec; | |
| 168 if (n & 0x1) { | |
| 169 // Codecs with odd index should match the reference. | |
| 170 EXPECT_EQ(0, receiver_->DecoderByPayloadType(codecs_[n].pltype, | |
| 171 &my_codec)); | |
| 172 EXPECT_TRUE(CodecsEqual(codecs_[n], my_codec)); | |
| 173 } else { | |
| 174 // Codecs with even index are not registered. | |
| 175 EXPECT_EQ(-1, receiver_->DecoderByPayloadType(codecs_[n].pltype, | |
| 176 &my_codec)); | |
| 177 } | |
| 178 } | |
| 179 } | |
| 180 | |
| 181 TEST_F(AcmReceiverTest, DISABLED_ON_ANDROID(AddCodecChangePayloadType)) { | |
| 182 const int codec_id = ACMCodecDB::kPCMA; | |
| 183 CodecInst ref_codec1; | |
| 184 EXPECT_EQ(0, ACMCodecDB::Codec(codec_id, &ref_codec1)); | |
| 185 CodecInst ref_codec2 = ref_codec1; | |
| 186 ++ref_codec2.pltype; | |
| 187 CodecInst test_codec; | |
| 188 | |
| 189 // Register the same codec with different payload types. | |
| 190 EXPECT_EQ( | |
| 191 0, receiver_->AddCodec(codec_id, ref_codec1.pltype, ref_codec1.channels, | |
| 192 ref_codec1.plfreq, NULL)); | |
| 193 EXPECT_EQ( | |
| 194 0, receiver_->AddCodec(codec_id, ref_codec2.pltype, ref_codec2.channels, | |
| 195 ref_codec2.plfreq, NULL)); | |
| 196 | |
| 197 // Both payload types should exist. | |
| 198 EXPECT_EQ(0, receiver_->DecoderByPayloadType(ref_codec1.pltype, &test_codec)); | |
| 199 EXPECT_EQ(true, CodecsEqual(ref_codec1, test_codec)); | |
| 200 EXPECT_EQ(0, receiver_->DecoderByPayloadType(ref_codec2.pltype, &test_codec)); | |
| 201 EXPECT_EQ(true, CodecsEqual(ref_codec2, test_codec)); | |
| 202 } | |
| 203 | |
| 204 TEST_F(AcmReceiverTest, DISABLED_ON_ANDROID(AddCodecChangeCodecId)) { | |
| 205 const int codec_id1 = ACMCodecDB::kPCMU; | |
| 206 CodecInst ref_codec1; | |
| 207 EXPECT_EQ(0, ACMCodecDB::Codec(codec_id1, &ref_codec1)); | |
| 208 const int codec_id2 = ACMCodecDB::kPCMA; | |
| 209 CodecInst ref_codec2; | |
| 210 EXPECT_EQ(0, ACMCodecDB::Codec(codec_id2, &ref_codec2)); | |
| 211 ref_codec2.pltype = ref_codec1.pltype; | |
| 212 CodecInst test_codec; | |
| 213 | |
| 214 // Register the same payload type with different codec ID. | |
| 215 EXPECT_EQ( | |
| 216 0, receiver_->AddCodec(codec_id1, ref_codec1.pltype, ref_codec1.channels, | |
| 217 ref_codec1.plfreq, NULL)); | |
| 218 EXPECT_EQ( | |
| 219 0, receiver_->AddCodec(codec_id2, ref_codec2.pltype, ref_codec2.channels, | |
| 220 ref_codec2.plfreq, NULL)); | |
| 221 | |
| 222 // Make sure that the last codec is used. | |
| 223 EXPECT_EQ(0, receiver_->DecoderByPayloadType(ref_codec2.pltype, &test_codec)); | |
| 224 EXPECT_EQ(true, CodecsEqual(ref_codec2, test_codec)); | |
| 225 } | |
| 226 | |
| 227 TEST_F(AcmReceiverTest, DISABLED_ON_ANDROID(AddCodecRemoveCodec)) { | |
| 228 CodecInst codec; | |
| 229 const int codec_id = ACMCodecDB::kPCMA; | |
| 230 EXPECT_EQ(0, ACMCodecDB::Codec(codec_id, &codec)); | |
| 231 const int payload_type = codec.pltype; | |
| 232 EXPECT_EQ(0, receiver_->AddCodec(codec_id, codec.pltype, codec.channels, | |
| 233 codec.plfreq, NULL)); | |
| 234 | |
| 235 // Remove non-existing codec should not fail. ACM1 legacy. | |
| 236 EXPECT_EQ(0, receiver_->RemoveCodec(payload_type + 1)); | |
| 237 | |
| 238 // Remove an existing codec. | |
| 239 EXPECT_EQ(0, receiver_->RemoveCodec(payload_type)); | |
| 240 | |
| 241 // Ask for the removed codec, must fail. | |
| 242 EXPECT_EQ(-1, receiver_->DecoderByPayloadType(payload_type, &codec)); | |
| 243 } | |
| 244 | |
| 245 TEST_F(AcmReceiverTest, DISABLED_ON_ANDROID(SampleRate)) { | |
| 246 const int kCodecId[] = { | |
| 247 ACMCodecDB::kISAC, ACMCodecDB::kISACSWB, | |
| 248 -1 // Terminator. | |
| 249 }; | |
| 250 AddSetOfCodecs(kCodecId); | |
| 251 | |
| 252 AudioFrame frame; | |
| 253 const int kOutSampleRateHz = 8000; // Different than codec sample rate. | |
| 254 int n = 0; | |
| 255 while (kCodecId[n] >= 0) { | |
| 256 const int num_10ms_frames = codecs_[kCodecId[n]].pacsize / | |
| 257 (codecs_[kCodecId[n]].plfreq / 100); | |
| 258 InsertOnePacketOfSilence(kCodecId[n]); | |
| 259 for (int k = 0; k < num_10ms_frames; ++k) { | |
| 260 EXPECT_EQ(0, receiver_->GetAudio(kOutSampleRateHz, &frame)); | |
| 261 } | |
| 262 EXPECT_EQ(std::min(32000, codecs_[kCodecId[n]].plfreq), | |
| 263 receiver_->current_sample_rate_hz()); | |
| 264 ++n; | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 TEST_F(AcmReceiverTest, DISABLED_ON_ANDROID(PostdecodingVad)) { | |
| 269 receiver_->EnableVad(); | |
| 270 EXPECT_TRUE(receiver_->vad_enabled()); | |
| 271 | |
| 272 const int id = ACMCodecDB::kPCM16Bwb; | |
| 273 ASSERT_EQ(0, receiver_->AddCodec(id, codecs_[id].pltype, codecs_[id].channels, | |
| 274 codecs_[id].plfreq, NULL)); | |
| 275 const int kNumPackets = 5; | |
| 276 const int num_10ms_frames = codecs_[id].pacsize / (codecs_[id].plfreq / 100); | |
| 277 AudioFrame frame; | |
| 278 for (int n = 0; n < kNumPackets; ++n) { | |
| 279 InsertOnePacketOfSilence(id); | |
| 280 for (int k = 0; k < num_10ms_frames; ++k) | |
| 281 ASSERT_EQ(0, receiver_->GetAudio(codecs_[id].plfreq, &frame)); | |
| 282 } | |
| 283 EXPECT_EQ(AudioFrame::kVadPassive, frame.vad_activity_); | |
| 284 | |
| 285 receiver_->DisableVad(); | |
| 286 EXPECT_FALSE(receiver_->vad_enabled()); | |
| 287 | |
| 288 for (int n = 0; n < kNumPackets; ++n) { | |
| 289 InsertOnePacketOfSilence(id); | |
| 290 for (int k = 0; k < num_10ms_frames; ++k) | |
| 291 ASSERT_EQ(0, receiver_->GetAudio(codecs_[id].plfreq, &frame)); | |
| 292 } | |
| 293 EXPECT_EQ(AudioFrame::kVadUnknown, frame.vad_activity_); | |
| 294 } | |
| 295 | |
| 296 #ifdef WEBRTC_CODEC_ISAC | |
| 297 #define IF_ISAC_FLOAT(x) x | |
| 298 #else | |
| 299 #define IF_ISAC_FLOAT(x) DISABLED_##x | |
| 300 #endif | |
| 301 | |
| 302 TEST_F(AcmReceiverTest, DISABLED_ON_ANDROID(IF_ISAC_FLOAT(LastAudioCodec))) { | |
| 303 const int kCodecId[] = { | |
| 304 ACMCodecDB::kISAC, ACMCodecDB::kPCMA, ACMCodecDB::kISACSWB, | |
| 305 ACMCodecDB::kPCM16Bswb32kHz, | |
| 306 -1 // Terminator. | |
| 307 }; | |
| 308 AddSetOfCodecs(kCodecId); | |
| 309 | |
| 310 const int kCngId[] = { // Not including full-band. | |
| 311 ACMCodecDB::kCNNB, ACMCodecDB::kCNWB, ACMCodecDB::kCNSWB, | |
| 312 -1 // Terminator. | |
| 313 }; | |
| 314 AddSetOfCodecs(kCngId); | |
| 315 | |
| 316 // Register CNG at sender side. | |
| 317 int n = 0; | |
| 318 while (kCngId[n] > 0) { | |
| 319 ASSERT_TRUE(acm_->RegisterSendCodec(kCngId[n], codecs_[kCngId[n]].pltype)); | |
| 320 ++n; | |
| 321 } | |
| 322 | |
| 323 CodecInst codec; | |
| 324 // No audio payload is received. | |
| 325 EXPECT_EQ(-1, receiver_->LastAudioCodec(&codec)); | |
| 326 | |
| 327 // Start with sending DTX. | |
| 328 ASSERT_TRUE(acm_->SetVad(true, true, VADVeryAggr)); | |
| 329 packet_sent_ = false; | |
| 330 InsertOnePacketOfSilence(kCodecId[0]); // Enough to test with one codec. | |
| 331 ASSERT_TRUE(packet_sent_); | |
| 332 EXPECT_EQ(kAudioFrameCN, last_frame_type_); | |
| 333 | |
| 334 // Has received, only, DTX. Last Audio codec is undefined. | |
| 335 EXPECT_EQ(-1, receiver_->LastAudioCodec(&codec)); | |
| 336 EXPECT_EQ(-1, receiver_->last_audio_codec_id()); | |
| 337 | |
| 338 n = 0; | |
| 339 while (kCodecId[n] >= 0) { // Loop over codecs. | |
| 340 // Set DTX off to send audio payload. | |
| 341 acm_->SetVad(false, false, VADAggr); | |
| 342 packet_sent_ = false; | |
| 343 InsertOnePacketOfSilence(kCodecId[n]); | |
| 344 | |
| 345 // Sanity check if Actually an audio payload received, and it should be | |
| 346 // of type "speech." | |
| 347 ASSERT_TRUE(packet_sent_); | |
| 348 ASSERT_EQ(kAudioFrameSpeech, last_frame_type_); | |
| 349 EXPECT_EQ(kCodecId[n], receiver_->last_audio_codec_id()); | |
| 350 | |
| 351 // Set VAD on to send DTX. Then check if the "Last Audio codec" returns | |
| 352 // the expected codec. | |
| 353 acm_->SetVad(true, true, VADAggr); | |
| 354 | |
| 355 // Do as many encoding until a DTX is sent. | |
| 356 while (last_frame_type_ != kAudioFrameCN) { | |
| 357 packet_sent_ = false; | |
| 358 InsertOnePacketOfSilence(kCodecId[n]); | |
| 359 ASSERT_TRUE(packet_sent_); | |
| 360 } | |
| 361 EXPECT_EQ(kCodecId[n], receiver_->last_audio_codec_id()); | |
| 362 EXPECT_EQ(0, receiver_->LastAudioCodec(&codec)); | |
| 363 EXPECT_TRUE(CodecsEqual(codecs_[kCodecId[n]], codec)); | |
| 364 ++n; | |
| 365 } | |
| 366 } | |
| 367 | |
| 368 } // namespace acm2 | |
| 369 | |
| 370 } // namespace webrtc | |
| OLD | NEW |