2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
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.
11 #include "gtest/gtest.h"
12 #include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h"
13 #include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
14 #include "webrtc/modules/audio_coding/main/test/PCMFile.h"
15 #include "webrtc/modules/audio_coding/main/test/utility.h"
16 #include "webrtc/modules/interface/module_common_types.h"
17 #include "webrtc/system_wrappers/interface/scoped_ptr.h"
18 #include "webrtc/typedefs.h"
19 #include "webrtc/test/testsupport/fileutils.h"
20 #include "webrtc/test/testsupport/gtest_disable.h"
24 class DualStreamTest : public AudioPacketizationCallback,
25 public ::testing::Test {
30 void RunTest(int frame_size_primary_samples,
31 int num_channels_primary,
34 int num_channels_input);
38 int32_t SendData(FrameType frameType, uint8_t payload_type,
39 uint32_t timestamp, const uint8_t* payload_data,
40 uint16_t payload_size,
41 const RTPFragmentationHeader* fragmentation);
43 void Perform(bool start_in_sync, int num_channels_input);
45 void InitializeSender(int frame_size_primary_samples,
46 int num_channels_primary, int sampling_rate);
48 void PopulateCodecInstances(int frame_size_primary_ms,
49 int num_channels_primary, int sampling_rate);
51 void Validate(bool start_in_sync, int tolerance);
52 bool EqualTimestamp(int stream, int position);
53 int EqualPayloadLength(int stream, int position);
54 bool EqualPayloadData(int stream, int position);
56 static const int kMaxNumStoredPayloads = 2;
64 scoped_ptr<AudioCodingModule> acm_dual_stream_;
65 scoped_ptr<AudioCodingModule> acm_ref_primary_;
66 scoped_ptr<AudioCodingModule> acm_ref_secondary_;
68 CodecInst primary_encoder_;
69 CodecInst secondary_encoder_;
71 CodecInst red_encoder_;
73 int payload_ref_is_stored_[kMaxNumStreams][kMaxNumStoredPayloads];
74 int payload_dual_is_stored_[kMaxNumStreams][kMaxNumStoredPayloads];
76 uint32_t timestamp_ref_[kMaxNumStreams][kMaxNumStoredPayloads];
77 uint32_t timestamp_dual_[kMaxNumStreams][kMaxNumStoredPayloads];
79 int payload_len_ref_[kMaxNumStreams][kMaxNumStoredPayloads];
80 int payload_len_dual_[kMaxNumStreams][kMaxNumStoredPayloads];
82 uint8_t payload_data_ref_[kMaxNumStreams][MAX_PAYLOAD_SIZE_BYTE
83 * kMaxNumStoredPayloads];
84 uint8_t payload_data_dual_[kMaxNumStreams][MAX_PAYLOAD_SIZE_BYTE
85 * kMaxNumStoredPayloads];
86 int num_received_payloads_dual_[kMaxNumStreams];
87 int num_received_payloads_ref_[kMaxNumStreams];
89 int num_compared_payloads_[kMaxNumStreams];
90 uint32_t last_timestamp_[kMaxNumStreams];
91 bool received_payload_[kMaxNumStreams];
94 DualStreamTest::DualStreamTest()
95 : acm_dual_stream_(AudioCodingModule::Create(0)),
96 acm_ref_primary_(AudioCodingModule::Create(1)),
97 acm_ref_secondary_(AudioCodingModule::Create(2)),
98 payload_ref_is_stored_(),
99 payload_dual_is_stored_(),
101 num_received_payloads_dual_(),
102 num_received_payloads_ref_(),
103 num_compared_payloads_(),
105 received_payload_() {}
107 DualStreamTest::~DualStreamTest() {}
109 void DualStreamTest::PopulateCodecInstances(int frame_size_primary_ms,
110 int num_channels_primary,
114 // Invalid values. To check later on if the codec are found in the database.
115 primary_encoder_.pltype = -1;
116 secondary_encoder_.pltype = -1;
117 red_encoder_.pltype = -1;
119 for (int n = 0; n < AudioCodingModule::NumberOfCodecs(); n++) {
120 AudioCodingModule::Codec(n, &my_codec);
121 if (strcmp(my_codec.plname, "ISAC") == 0
122 && my_codec.plfreq == sampling_rate) {
123 my_codec.rate = 32000;
124 my_codec.pacsize = 30 * sampling_rate / 1000;
125 memcpy(&secondary_encoder_, &my_codec, sizeof(my_codec));
126 } else if (strcmp(my_codec.plname, "L16") == 0
127 && my_codec.channels == num_channels_primary
128 && my_codec.plfreq == sampling_rate) {
129 my_codec.pacsize = frame_size_primary_ms * sampling_rate / 1000;
130 memcpy(&primary_encoder_, &my_codec, sizeof(my_codec));
131 } else if (strcmp(my_codec.plname, "red") == 0) {
132 memcpy(&red_encoder_, &my_codec, sizeof(my_codec));
136 ASSERT_GE(primary_encoder_.pltype, 0);
137 ASSERT_GE(secondary_encoder_.pltype, 0);
138 ASSERT_GE(red_encoder_.pltype, 0);
141 void DualStreamTest::InitializeSender(int frame_size_primary_samples,
142 int num_channels_primary,
144 ASSERT_TRUE(acm_dual_stream_.get() != NULL);
145 ASSERT_TRUE(acm_ref_primary_.get() != NULL);
146 ASSERT_TRUE(acm_ref_secondary_.get() != NULL);
148 ASSERT_EQ(0, acm_dual_stream_->InitializeSender());
149 ASSERT_EQ(0, acm_ref_primary_->InitializeSender());
150 ASSERT_EQ(0, acm_ref_secondary_->InitializeSender());
152 PopulateCodecInstances(frame_size_primary_samples, num_channels_primary,
155 ASSERT_EQ(0, acm_ref_primary_->RegisterSendCodec(primary_encoder_));
156 ASSERT_EQ(0, acm_ref_secondary_->RegisterSendCodec(secondary_encoder_));
157 ASSERT_EQ(0, acm_dual_stream_->RegisterSendCodec(primary_encoder_));
159 acm_dual_stream_->RegisterSecondarySendCodec(secondary_encoder_));
161 ASSERT_EQ(0, acm_ref_primary_->RegisterTransportCallback(this));
162 ASSERT_EQ(0, acm_ref_secondary_->RegisterTransportCallback(this));
163 ASSERT_EQ(0, acm_dual_stream_->RegisterTransportCallback(this));
166 void DualStreamTest::Perform(bool start_in_sync, int num_channels_input) {
168 std::string file_name = test::ResourcePath(
169 (num_channels_input == 1) ?
170 "audio_coding/testfile32kHz" : "audio_coding/teststereo32kHz",
172 pcm_file.Open(file_name, 32000, "rb");
173 pcm_file.ReadStereo(num_channels_input == 2);
174 AudioFrame audio_frame;
177 if (num_channels_input == 2 && primary_encoder_.channels == 2
178 && secondary_encoder_.channels == 1) {
182 if (!start_in_sync) {
183 pcm_file.Read10MsData(audio_frame);
184 // Unregister secondary codec and feed only the primary
185 acm_dual_stream_->UnregisterSecondarySendCodec();
186 EXPECT_EQ(0, acm_dual_stream_->Add10MsData(audio_frame));
187 EXPECT_EQ(0, acm_ref_primary_->Add10MsData(audio_frame));
189 acm_dual_stream_->RegisterSecondarySendCodec(secondary_encoder_));
192 const int kNumFramesToProcess = 100;
194 while (!pcm_file.EndOfFile() && frame_cntr < kNumFramesToProcess) {
195 pcm_file.Read10MsData(audio_frame);
197 EXPECT_EQ(0, acm_dual_stream_->Add10MsData(audio_frame));
198 EXPECT_EQ(0, acm_ref_primary_->Add10MsData(audio_frame));
199 EXPECT_EQ(0, acm_ref_secondary_->Add10MsData(audio_frame));
201 EXPECT_GE(acm_dual_stream_->Process(), 0);
202 EXPECT_GE(acm_ref_primary_->Process(), 0);
203 EXPECT_GE(acm_ref_secondary_->Process(), 0);
205 if (start_in_sync || frame_cntr > 7) {
206 // If we haven't started in sync the first few audio frames might
207 // slightly differ due to the difference in the state of the resamplers
208 // of dual-ACM and reference-ACM.
209 Validate(start_in_sync, tolerance);
211 // SendData stores the payloads, if we are not comparing we have to free
212 // the space by resetting these flags.
213 memset(payload_ref_is_stored_, 0, sizeof(payload_ref_is_stored_));
214 memset(payload_dual_is_stored_, 0, sizeof(payload_dual_is_stored_));
219 // Make sure that number of received payloads match. In case of secondary
220 // encoder, the dual-stream might deliver one lesser payload. The reason is
221 // that some secondary payloads are stored to be sent with a payload generated
222 // later and the input file may end before the "next" payload .
223 EXPECT_EQ(num_received_payloads_ref_[kPrimary],
224 num_received_payloads_dual_[kPrimary]);
226 num_received_payloads_ref_[kSecondary]
227 == num_received_payloads_dual_[kSecondary]
228 || num_received_payloads_ref_[kSecondary]
229 == (num_received_payloads_dual_[kSecondary] + 1));
231 // Make sure all received payloads are compared.
233 EXPECT_EQ(num_received_payloads_dual_[kPrimary],
234 num_compared_payloads_[kPrimary]);
235 EXPECT_EQ(num_received_payloads_dual_[kSecondary],
236 num_compared_payloads_[kSecondary]);
238 // In asynchronous test we don't compare couple of first frames, so we
239 // should account for them in our counting.
240 EXPECT_GE(num_compared_payloads_[kPrimary],
241 num_received_payloads_dual_[kPrimary] - 4);
242 EXPECT_GE(num_compared_payloads_[kSecondary],
243 num_received_payloads_dual_[kSecondary] - 4);
247 bool DualStreamTest::EqualTimestamp(int stream_index, int position) {
248 if (timestamp_dual_[stream_index][position]
249 != timestamp_ref_[stream_index][position]) {
255 int DualStreamTest::EqualPayloadLength(int stream_index, int position) {
257 payload_len_dual_[stream_index][position]
258 - payload_len_ref_[stream_index][position]);
261 bool DualStreamTest::EqualPayloadData(int stream_index, int position) {
263 payload_len_dual_[stream_index][position]
264 == payload_len_ref_[stream_index][position]);
265 int offset = position * MAX_PAYLOAD_SIZE_BYTE;
266 for (int n = 0; n < payload_len_dual_[stream_index][position]; n++) {
267 if (payload_data_dual_[stream_index][offset + n]
268 != payload_data_ref_[stream_index][offset + n]) {
275 void DualStreamTest::Validate(bool start_in_sync, int tolerance) {
276 for (int stream_index = 0; stream_index < kMaxNumStreams; stream_index++) {
277 int my_tolerance = stream_index == kPrimary ? 0 : tolerance;
278 for (int position = 0; position < kMaxNumStoredPayloads; position++) {
279 if (payload_ref_is_stored_[stream_index][position] == 1
280 && payload_dual_is_stored_[stream_index][position] == 1) {
281 // Check timestamps only if codecs started in sync or it is primary.
282 if (start_in_sync || stream_index == 0)
283 EXPECT_TRUE(EqualTimestamp(stream_index, position));
284 EXPECT_LE(EqualPayloadLength(stream_index, position), my_tolerance);
285 if (my_tolerance == 0)
286 EXPECT_TRUE(EqualPayloadData(stream_index, position));
287 num_compared_payloads_[stream_index]++;
288 payload_ref_is_stored_[stream_index][position] = 0;
289 payload_dual_is_stored_[stream_index][position] = 0;
295 int32_t DualStreamTest::SendData(FrameType frameType, uint8_t payload_type,
297 const uint8_t* payload_data,
298 uint16_t payload_size,
299 const RTPFragmentationHeader* fragmentation) {
303 if (payload_type == red_encoder_.pltype) {
304 if (fragmentation == NULL) {
308 // As the oldest payloads are in the higher indices of fragmentation,
309 // to be able to check the increment of timestamps are correct we loop
311 for (int n = fragmentation->fragmentationVectorSize - 1; n >= 0; --n) {
312 if (fragmentation->fragmentationPlType[n] == primary_encoder_.pltype) {
313 // Received primary payload from dual stream.
314 stream_index = kPrimary;
315 } else if (fragmentation->fragmentationPlType[n]
316 == secondary_encoder_.pltype) {
317 // Received secondary payload from dual stream.
318 stream_index = kSecondary;
323 num_received_payloads_dual_[stream_index]++;
324 if (payload_dual_is_stored_[stream_index][0] == 0) {
326 } else if (payload_dual_is_stored_[stream_index][1] == 0) {
332 timestamp_dual_[stream_index][position] = timestamp
333 - fragmentation->fragmentationTimeDiff[n];
334 payload_len_dual_[stream_index][position] = fragmentation
335 ->fragmentationLength[n];
337 &payload_data_dual_[stream_index][position * MAX_PAYLOAD_SIZE_BYTE],
338 &payload_data[fragmentation->fragmentationOffset[n]],
339 fragmentation->fragmentationLength[n]);
340 payload_dual_is_stored_[stream_index][position] = 1;
341 // Check if timestamps are incremented correctly.
342 if (received_payload_[stream_index]) {
343 int t = timestamp_dual_[stream_index][position]
344 - last_timestamp_[stream_index];
345 if ((stream_index == kPrimary) && (t != primary_encoder_.pacsize)) {
349 if ((stream_index == kSecondary) && (t != secondary_encoder_.pacsize)) {
354 received_payload_[stream_index] = true;
356 last_timestamp_[stream_index] = timestamp_dual_[stream_index][position];
359 if (fragmentation != NULL) {
363 if (payload_type == primary_encoder_.pltype) {
364 stream_index = kPrimary;
365 } else if (payload_type == secondary_encoder_.pltype) {
366 stream_index = kSecondary;
371 num_received_payloads_ref_[stream_index]++;
372 if (payload_ref_is_stored_[stream_index][0] == 0) {
374 } else if (payload_ref_is_stored_[stream_index][1] == 0) {
380 timestamp_ref_[stream_index][position] = timestamp;
381 payload_len_ref_[stream_index][position] = payload_size;
382 memcpy(&payload_data_ref_[stream_index][position * MAX_PAYLOAD_SIZE_BYTE],
383 payload_data, payload_size);
384 payload_ref_is_stored_[stream_index][position] = 1;
389 // Mono input, mono primary WB 20 ms frame.
390 TEST_F(DualStreamTest,
391 DISABLED_ON_ANDROID(BitExactSyncMonoInputMonoPrimaryWb20Ms)) {
392 InitializeSender(20, 1, 16000);
396 // Mono input, stereo primary WB 20 ms frame.
397 TEST_F(DualStreamTest,
398 DISABLED_ON_ANDROID(BitExactSyncMonoInput_StereoPrimaryWb20Ms)) {
399 InitializeSender(20, 2, 16000);
403 // Mono input, mono primary SWB 20 ms frame.
404 TEST_F(DualStreamTest,
405 DISABLED_ON_ANDROID(BitExactSyncMonoInputMonoPrimarySwb20Ms)) {
406 InitializeSender(20, 1, 32000);
410 // Mono input, stereo primary SWB 20 ms frame.
411 TEST_F(DualStreamTest,
412 DISABLED_ON_ANDROID(BitExactSyncMonoInputStereoPrimarySwb20Ms)) {
413 InitializeSender(20, 2, 32000);
417 // Mono input, mono primary WB 40 ms frame.
418 TEST_F(DualStreamTest,
419 DISABLED_ON_ANDROID(BitExactSyncMonoInputMonoPrimaryWb40Ms)) {
420 InitializeSender(40, 1, 16000);
424 // Mono input, stereo primary WB 40 ms frame
425 TEST_F(DualStreamTest,
426 DISABLED_ON_ANDROID(BitExactSyncMonoInputStereoPrimaryWb40Ms)) {
427 InitializeSender(40, 2, 16000);
431 // Stereo input, mono primary WB 20 ms frame.
432 TEST_F(DualStreamTest,
433 DISABLED_ON_ANDROID(BitExactSyncStereoInputMonoPrimaryWb20Ms)) {
434 InitializeSender(20, 1, 16000);
438 // Stereo input, stereo primary WB 20 ms frame.
439 TEST_F(DualStreamTest,
440 DISABLED_ON_ANDROID(BitExactSyncStereoInputStereoPrimaryWb20Ms)) {
441 InitializeSender(20, 2, 16000);
445 // Stereo input, mono primary SWB 20 ms frame.
446 TEST_F(DualStreamTest,
447 DISABLED_ON_ANDROID(BitExactSyncStereoInputMonoPrimarySwb20Ms)) {
448 InitializeSender(20, 1, 32000);
452 // Stereo input, stereo primary SWB 20 ms frame.
453 TEST_F(DualStreamTest,
454 DISABLED_ON_ANDROID(BitExactSyncStereoInputStereoPrimarySwb20Ms)) {
455 InitializeSender(20, 2, 32000);
459 // Stereo input, mono primary WB 40 ms frame.
460 TEST_F(DualStreamTest,
461 DISABLED_ON_ANDROID(BitExactSyncStereoInputMonoPrimaryWb40Ms)) {
462 InitializeSender(40, 1, 16000);
466 // Stereo input, stereo primary WB 40 ms frame.
467 TEST_F(DualStreamTest,
468 DISABLED_ON_ANDROID(BitExactSyncStereoInputStereoPrimaryWb40Ms)) {
469 InitializeSender(40, 2, 16000);
473 // Asynchronous test, ACM is fed with data then secondary coder is registered.
474 // Mono input, mono primary WB 20 ms frame.
475 TEST_F(DualStreamTest,
476 DISABLED_ON_ANDROID(BitExactAsyncMonoInputMonoPrimaryWb20Ms)) {
477 InitializeSender(20, 1, 16000);
481 // Mono input, mono primary WB 20 ms frame.
482 TEST_F(DualStreamTest,
483 DISABLED_ON_ANDROID(BitExactAsyncMonoInputMonoPrimaryWb40Ms)) {
484 InitializeSender(40, 1, 16000);
488 TEST_F(DualStreamTest, DISABLED_ON_ANDROID(Api)) {
489 PopulateCodecInstances(20, 1, 16000);
491 ASSERT_EQ(0, acm_dual_stream_->InitializeSender());
492 ASSERT_EQ(-1, acm_dual_stream_->SecondarySendCodec(&my_codec));
494 // Not allowed to register secondary codec if primary is not registered yet.
496 acm_dual_stream_->RegisterSecondarySendCodec(secondary_encoder_));
497 ASSERT_EQ(-1, acm_dual_stream_->SecondarySendCodec(&my_codec));
499 ASSERT_EQ(0, acm_dual_stream_->RegisterSendCodec(primary_encoder_));
501 ASSERT_EQ(0, acm_dual_stream_->SetVAD(true, true, VADNormal));
503 // Make sure vad is activated.
507 EXPECT_EQ(0, acm_dual_stream_->VAD(&vad_status, &dtx_status, &vad_mode));
508 EXPECT_TRUE(vad_status);
509 EXPECT_TRUE(dtx_status);
510 EXPECT_EQ(VADNormal, vad_mode);
513 acm_dual_stream_->RegisterSecondarySendCodec(secondary_encoder_));
515 ASSERT_EQ(0, acm_dual_stream_->SecondarySendCodec(&my_codec));
516 ASSERT_EQ(0, memcmp(&my_codec, &secondary_encoder_, sizeof(my_codec)));
518 // Test if VAD get disabled after registering secondary codec.
519 EXPECT_EQ(0, acm_dual_stream_->VAD(&vad_status, &dtx_status, &vad_mode));
520 EXPECT_FALSE(vad_status);
521 EXPECT_FALSE(dtx_status);
523 // Activating VAD should fail.
524 ASSERT_EQ(-1, acm_dual_stream_->SetVAD(true, true, VADNormal));
526 // Unregister secondary encoder and it should be possible to activate VAD.
527 acm_dual_stream_->UnregisterSecondarySendCodec();
529 ASSERT_EQ(-1, acm_dual_stream_->SecondarySendCodec(&my_codec));
531 ASSERT_EQ(0, acm_dual_stream_->SetVAD(true, true, VADVeryAggr));
532 // Make sure VAD is activated.
533 EXPECT_EQ(0, acm_dual_stream_->VAD(&vad_status, &dtx_status, &vad_mode));
534 EXPECT_TRUE(vad_status);
535 EXPECT_TRUE(dtx_status);
536 EXPECT_EQ(VADVeryAggr, vad_mode);
539 } // namespace webrtc