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 "testing/gtest/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 virtual int32_t SendData(
39 FrameType frameType, uint8_t payload_type,
40 uint32_t timestamp, const uint8_t* payload_data,
41 uint16_t payload_size,
42 const RTPFragmentationHeader* fragmentation) OVERRIDE;
44 void Perform(bool start_in_sync, int num_channels_input);
46 void InitializeSender(int frame_size_primary_samples,
47 int num_channels_primary, int sampling_rate);
49 void PopulateCodecInstances(int frame_size_primary_ms,
50 int num_channels_primary, int sampling_rate);
52 void Validate(bool start_in_sync, int tolerance);
53 bool EqualTimestamp(int stream, int position);
54 int EqualPayloadLength(int stream, int position);
55 bool EqualPayloadData(int stream, int position);
57 static const int kMaxNumStoredPayloads = 2;
65 scoped_ptr<AudioCodingModule> acm_dual_stream_;
66 scoped_ptr<AudioCodingModule> acm_ref_primary_;
67 scoped_ptr<AudioCodingModule> acm_ref_secondary_;
69 CodecInst primary_encoder_;
70 CodecInst secondary_encoder_;
72 CodecInst red_encoder_;
74 int payload_ref_is_stored_[kMaxNumStreams][kMaxNumStoredPayloads];
75 int payload_dual_is_stored_[kMaxNumStreams][kMaxNumStoredPayloads];
77 uint32_t timestamp_ref_[kMaxNumStreams][kMaxNumStoredPayloads];
78 uint32_t timestamp_dual_[kMaxNumStreams][kMaxNumStoredPayloads];
80 int payload_len_ref_[kMaxNumStreams][kMaxNumStoredPayloads];
81 int payload_len_dual_[kMaxNumStreams][kMaxNumStoredPayloads];
83 uint8_t payload_data_ref_[kMaxNumStreams][MAX_PAYLOAD_SIZE_BYTE
84 * kMaxNumStoredPayloads];
85 uint8_t payload_data_dual_[kMaxNumStreams][MAX_PAYLOAD_SIZE_BYTE
86 * kMaxNumStoredPayloads];
87 int num_received_payloads_dual_[kMaxNumStreams];
88 int num_received_payloads_ref_[kMaxNumStreams];
90 int num_compared_payloads_[kMaxNumStreams];
91 uint32_t last_timestamp_[kMaxNumStreams];
92 bool received_payload_[kMaxNumStreams];
95 DualStreamTest::DualStreamTest()
96 : acm_dual_stream_(AudioCodingModule::Create(0)),
97 acm_ref_primary_(AudioCodingModule::Create(1)),
98 acm_ref_secondary_(AudioCodingModule::Create(2)),
99 payload_ref_is_stored_(),
100 payload_dual_is_stored_(),
102 num_received_payloads_dual_(),
103 num_received_payloads_ref_(),
104 num_compared_payloads_(),
106 received_payload_() {}
108 DualStreamTest::~DualStreamTest() {}
110 void DualStreamTest::PopulateCodecInstances(int frame_size_primary_ms,
111 int num_channels_primary,
115 // Invalid values. To check later on if the codec are found in the database.
116 primary_encoder_.pltype = -1;
117 secondary_encoder_.pltype = -1;
118 red_encoder_.pltype = -1;
120 for (int n = 0; n < AudioCodingModule::NumberOfCodecs(); n++) {
121 AudioCodingModule::Codec(n, &my_codec);
122 if (strcmp(my_codec.plname, "ISAC") == 0
123 && my_codec.plfreq == sampling_rate) {
124 my_codec.rate = 32000;
125 my_codec.pacsize = 30 * sampling_rate / 1000;
126 memcpy(&secondary_encoder_, &my_codec, sizeof(my_codec));
127 } else if (strcmp(my_codec.plname, "L16") == 0
128 && my_codec.channels == num_channels_primary
129 && my_codec.plfreq == sampling_rate) {
130 my_codec.pacsize = frame_size_primary_ms * sampling_rate / 1000;
131 memcpy(&primary_encoder_, &my_codec, sizeof(my_codec));
132 } else if (strcmp(my_codec.plname, "red") == 0) {
133 memcpy(&red_encoder_, &my_codec, sizeof(my_codec));
137 ASSERT_GE(primary_encoder_.pltype, 0);
138 ASSERT_GE(secondary_encoder_.pltype, 0);
139 ASSERT_GE(red_encoder_.pltype, 0);
142 void DualStreamTest::InitializeSender(int frame_size_primary_samples,
143 int num_channels_primary,
145 ASSERT_TRUE(acm_dual_stream_.get() != NULL);
146 ASSERT_TRUE(acm_ref_primary_.get() != NULL);
147 ASSERT_TRUE(acm_ref_secondary_.get() != NULL);
149 ASSERT_EQ(0, acm_dual_stream_->InitializeSender());
150 ASSERT_EQ(0, acm_ref_primary_->InitializeSender());
151 ASSERT_EQ(0, acm_ref_secondary_->InitializeSender());
153 PopulateCodecInstances(frame_size_primary_samples, num_channels_primary,
156 ASSERT_EQ(0, acm_ref_primary_->RegisterSendCodec(primary_encoder_));
157 ASSERT_EQ(0, acm_ref_secondary_->RegisterSendCodec(secondary_encoder_));
158 ASSERT_EQ(0, acm_dual_stream_->RegisterSendCodec(primary_encoder_));
160 acm_dual_stream_->RegisterSecondarySendCodec(secondary_encoder_));
162 ASSERT_EQ(0, acm_ref_primary_->RegisterTransportCallback(this));
163 ASSERT_EQ(0, acm_ref_secondary_->RegisterTransportCallback(this));
164 ASSERT_EQ(0, acm_dual_stream_->RegisterTransportCallback(this));
167 void DualStreamTest::Perform(bool start_in_sync, int num_channels_input) {
169 std::string file_name = test::ResourcePath(
170 (num_channels_input == 1) ?
171 "audio_coding/testfile32kHz" : "audio_coding/teststereo32kHz",
173 pcm_file.Open(file_name, 32000, "rb");
174 pcm_file.ReadStereo(num_channels_input == 2);
175 AudioFrame audio_frame;
178 if (num_channels_input == 2 && primary_encoder_.channels == 2
179 && secondary_encoder_.channels == 1) {
183 if (!start_in_sync) {
184 pcm_file.Read10MsData(audio_frame);
185 // Unregister secondary codec and feed only the primary
186 acm_dual_stream_->UnregisterSecondarySendCodec();
187 EXPECT_EQ(0, acm_dual_stream_->Add10MsData(audio_frame));
188 EXPECT_EQ(0, acm_ref_primary_->Add10MsData(audio_frame));
190 acm_dual_stream_->RegisterSecondarySendCodec(secondary_encoder_));
193 const int kNumFramesToProcess = 100;
195 while (!pcm_file.EndOfFile() && frame_cntr < kNumFramesToProcess) {
196 pcm_file.Read10MsData(audio_frame);
198 EXPECT_EQ(0, acm_dual_stream_->Add10MsData(audio_frame));
199 EXPECT_EQ(0, acm_ref_primary_->Add10MsData(audio_frame));
200 EXPECT_EQ(0, acm_ref_secondary_->Add10MsData(audio_frame));
202 EXPECT_GE(acm_dual_stream_->Process(), 0);
203 EXPECT_GE(acm_ref_primary_->Process(), 0);
204 EXPECT_GE(acm_ref_secondary_->Process(), 0);
206 if (start_in_sync || frame_cntr > 7) {
207 // If we haven't started in sync the first few audio frames might
208 // slightly differ due to the difference in the state of the resamplers
209 // of dual-ACM and reference-ACM.
210 Validate(start_in_sync, tolerance);
212 // SendData stores the payloads, if we are not comparing we have to free
213 // the space by resetting these flags.
214 memset(payload_ref_is_stored_, 0, sizeof(payload_ref_is_stored_));
215 memset(payload_dual_is_stored_, 0, sizeof(payload_dual_is_stored_));
220 // Make sure that number of received payloads match. In case of secondary
221 // encoder, the dual-stream might deliver one lesser payload. The reason is
222 // that some secondary payloads are stored to be sent with a payload generated
223 // later and the input file may end before the "next" payload .
224 EXPECT_EQ(num_received_payloads_ref_[kPrimary],
225 num_received_payloads_dual_[kPrimary]);
227 num_received_payloads_ref_[kSecondary]
228 == num_received_payloads_dual_[kSecondary]
229 || num_received_payloads_ref_[kSecondary]
230 == (num_received_payloads_dual_[kSecondary] + 1));
232 // Make sure all received payloads are compared.
234 EXPECT_EQ(num_received_payloads_dual_[kPrimary],
235 num_compared_payloads_[kPrimary]);
236 EXPECT_EQ(num_received_payloads_dual_[kSecondary],
237 num_compared_payloads_[kSecondary]);
239 // In asynchronous test we don't compare couple of first frames, so we
240 // should account for them in our counting.
241 EXPECT_GE(num_compared_payloads_[kPrimary],
242 num_received_payloads_dual_[kPrimary] - 4);
243 EXPECT_GE(num_compared_payloads_[kSecondary],
244 num_received_payloads_dual_[kSecondary] - 4);
248 bool DualStreamTest::EqualTimestamp(int stream_index, int position) {
249 if (timestamp_dual_[stream_index][position]
250 != timestamp_ref_[stream_index][position]) {
256 int DualStreamTest::EqualPayloadLength(int stream_index, int position) {
258 payload_len_dual_[stream_index][position]
259 - payload_len_ref_[stream_index][position]);
262 bool DualStreamTest::EqualPayloadData(int stream_index, int position) {
264 payload_len_dual_[stream_index][position]
265 == payload_len_ref_[stream_index][position]);
266 int offset = position * MAX_PAYLOAD_SIZE_BYTE;
267 for (int n = 0; n < payload_len_dual_[stream_index][position]; n++) {
268 if (payload_data_dual_[stream_index][offset + n]
269 != payload_data_ref_[stream_index][offset + n]) {
276 void DualStreamTest::Validate(bool start_in_sync, int tolerance) {
277 for (int stream_index = 0; stream_index < kMaxNumStreams; stream_index++) {
278 int my_tolerance = stream_index == kPrimary ? 0 : tolerance;
279 for (int position = 0; position < kMaxNumStoredPayloads; position++) {
280 if (payload_ref_is_stored_[stream_index][position] == 1
281 && payload_dual_is_stored_[stream_index][position] == 1) {
282 // Check timestamps only if codecs started in sync or it is primary.
283 if (start_in_sync || stream_index == 0)
284 EXPECT_TRUE(EqualTimestamp(stream_index, position));
285 EXPECT_LE(EqualPayloadLength(stream_index, position), my_tolerance);
286 if (my_tolerance == 0)
287 EXPECT_TRUE(EqualPayloadData(stream_index, position));
288 num_compared_payloads_[stream_index]++;
289 payload_ref_is_stored_[stream_index][position] = 0;
290 payload_dual_is_stored_[stream_index][position] = 0;
296 int32_t DualStreamTest::SendData(FrameType frameType, uint8_t payload_type,
298 const uint8_t* payload_data,
299 uint16_t payload_size,
300 const RTPFragmentationHeader* fragmentation) {
304 if (payload_type == red_encoder_.pltype) {
305 if (fragmentation == NULL) {
309 // As the oldest payloads are in the higher indices of fragmentation,
310 // to be able to check the increment of timestamps are correct we loop
312 for (int n = fragmentation->fragmentationVectorSize - 1; n >= 0; --n) {
313 if (fragmentation->fragmentationPlType[n] == primary_encoder_.pltype) {
314 // Received primary payload from dual stream.
315 stream_index = kPrimary;
316 } else if (fragmentation->fragmentationPlType[n]
317 == secondary_encoder_.pltype) {
318 // Received secondary payload from dual stream.
319 stream_index = kSecondary;
324 num_received_payloads_dual_[stream_index]++;
325 if (payload_dual_is_stored_[stream_index][0] == 0) {
327 } else if (payload_dual_is_stored_[stream_index][1] == 0) {
333 timestamp_dual_[stream_index][position] = timestamp
334 - fragmentation->fragmentationTimeDiff[n];
335 payload_len_dual_[stream_index][position] = fragmentation
336 ->fragmentationLength[n];
338 &payload_data_dual_[stream_index][position * MAX_PAYLOAD_SIZE_BYTE],
339 &payload_data[fragmentation->fragmentationOffset[n]],
340 fragmentation->fragmentationLength[n]);
341 payload_dual_is_stored_[stream_index][position] = 1;
342 // Check if timestamps are incremented correctly.
343 if (received_payload_[stream_index]) {
344 int t = timestamp_dual_[stream_index][position]
345 - last_timestamp_[stream_index];
346 if ((stream_index == kPrimary) && (t != primary_encoder_.pacsize)) {
350 if ((stream_index == kSecondary) && (t != secondary_encoder_.pacsize)) {
355 received_payload_[stream_index] = true;
357 last_timestamp_[stream_index] = timestamp_dual_[stream_index][position];
360 if (fragmentation != NULL) {
364 if (payload_type == primary_encoder_.pltype) {
365 stream_index = kPrimary;
366 } else if (payload_type == secondary_encoder_.pltype) {
367 stream_index = kSecondary;
372 num_received_payloads_ref_[stream_index]++;
373 if (payload_ref_is_stored_[stream_index][0] == 0) {
375 } else if (payload_ref_is_stored_[stream_index][1] == 0) {
381 timestamp_ref_[stream_index][position] = timestamp;
382 payload_len_ref_[stream_index][position] = payload_size;
383 memcpy(&payload_data_ref_[stream_index][position * MAX_PAYLOAD_SIZE_BYTE],
384 payload_data, payload_size);
385 payload_ref_is_stored_[stream_index][position] = 1;
390 // Mono input, mono primary WB 20 ms frame.
391 TEST_F(DualStreamTest,
392 DISABLED_ON_ANDROID(BitExactSyncMonoInputMonoPrimaryWb20Ms)) {
393 InitializeSender(20, 1, 16000);
397 // Mono input, stereo primary WB 20 ms frame.
398 TEST_F(DualStreamTest,
399 DISABLED_ON_ANDROID(BitExactSyncMonoInput_StereoPrimaryWb20Ms)) {
400 InitializeSender(20, 2, 16000);
404 // Mono input, mono primary SWB 20 ms frame.
405 TEST_F(DualStreamTest,
406 DISABLED_ON_ANDROID(BitExactSyncMonoInputMonoPrimarySwb20Ms)) {
407 InitializeSender(20, 1, 32000);
411 // Mono input, stereo primary SWB 20 ms frame.
412 TEST_F(DualStreamTest,
413 DISABLED_ON_ANDROID(BitExactSyncMonoInputStereoPrimarySwb20Ms)) {
414 InitializeSender(20, 2, 32000);
418 // Mono input, mono primary WB 40 ms frame.
419 TEST_F(DualStreamTest,
420 DISABLED_ON_ANDROID(BitExactSyncMonoInputMonoPrimaryWb40Ms)) {
421 InitializeSender(40, 1, 16000);
425 // Mono input, stereo primary WB 40 ms frame
426 TEST_F(DualStreamTest,
427 DISABLED_ON_ANDROID(BitExactSyncMonoInputStereoPrimaryWb40Ms)) {
428 InitializeSender(40, 2, 16000);
432 // Stereo input, mono primary WB 20 ms frame.
433 TEST_F(DualStreamTest,
434 DISABLED_ON_ANDROID(BitExactSyncStereoInputMonoPrimaryWb20Ms)) {
435 InitializeSender(20, 1, 16000);
439 // Stereo input, stereo primary WB 20 ms frame.
440 TEST_F(DualStreamTest,
441 DISABLED_ON_ANDROID(BitExactSyncStereoInputStereoPrimaryWb20Ms)) {
442 InitializeSender(20, 2, 16000);
446 // Stereo input, mono primary SWB 20 ms frame.
447 TEST_F(DualStreamTest,
448 DISABLED_ON_ANDROID(BitExactSyncStereoInputMonoPrimarySwb20Ms)) {
449 InitializeSender(20, 1, 32000);
453 // Stereo input, stereo primary SWB 20 ms frame.
454 TEST_F(DualStreamTest,
455 DISABLED_ON_ANDROID(BitExactSyncStereoInputStereoPrimarySwb20Ms)) {
456 InitializeSender(20, 2, 32000);
460 // Stereo input, mono primary WB 40 ms frame.
461 TEST_F(DualStreamTest,
462 DISABLED_ON_ANDROID(BitExactSyncStereoInputMonoPrimaryWb40Ms)) {
463 InitializeSender(40, 1, 16000);
467 // Stereo input, stereo primary WB 40 ms frame.
468 TEST_F(DualStreamTest,
469 DISABLED_ON_ANDROID(BitExactSyncStereoInputStereoPrimaryWb40Ms)) {
470 InitializeSender(40, 2, 16000);
474 // Asynchronous test, ACM is fed with data then secondary coder is registered.
475 // Mono input, mono primary WB 20 ms frame.
476 TEST_F(DualStreamTest,
477 DISABLED_ON_ANDROID(BitExactAsyncMonoInputMonoPrimaryWb20Ms)) {
478 InitializeSender(20, 1, 16000);
482 // Mono input, mono primary WB 20 ms frame.
483 TEST_F(DualStreamTest,
484 DISABLED_ON_ANDROID(BitExactAsyncMonoInputMonoPrimaryWb40Ms)) {
485 InitializeSender(40, 1, 16000);
489 TEST_F(DualStreamTest, DISABLED_ON_ANDROID(Api)) {
490 PopulateCodecInstances(20, 1, 16000);
492 ASSERT_EQ(0, acm_dual_stream_->InitializeSender());
493 ASSERT_EQ(-1, acm_dual_stream_->SecondarySendCodec(&my_codec));
495 // Not allowed to register secondary codec if primary is not registered yet.
497 acm_dual_stream_->RegisterSecondarySendCodec(secondary_encoder_));
498 ASSERT_EQ(-1, acm_dual_stream_->SecondarySendCodec(&my_codec));
500 ASSERT_EQ(0, acm_dual_stream_->RegisterSendCodec(primary_encoder_));
502 ASSERT_EQ(0, acm_dual_stream_->SetVAD(true, true, VADNormal));
504 // Make sure vad is activated.
508 EXPECT_EQ(0, acm_dual_stream_->VAD(&vad_status, &dtx_status, &vad_mode));
509 EXPECT_TRUE(vad_status);
510 EXPECT_TRUE(dtx_status);
511 EXPECT_EQ(VADNormal, vad_mode);
514 acm_dual_stream_->RegisterSecondarySendCodec(secondary_encoder_));
516 ASSERT_EQ(0, acm_dual_stream_->SecondarySendCodec(&my_codec));
517 ASSERT_EQ(0, memcmp(&my_codec, &secondary_encoder_, sizeof(my_codec)));
519 // Test if VAD get disabled after registering secondary codec.
520 EXPECT_EQ(0, acm_dual_stream_->VAD(&vad_status, &dtx_status, &vad_mode));
521 EXPECT_FALSE(vad_status);
522 EXPECT_FALSE(dtx_status);
524 // Activating VAD should fail.
525 ASSERT_EQ(-1, acm_dual_stream_->SetVAD(true, true, VADNormal));
527 // Unregister secondary encoder and it should be possible to activate VAD.
528 acm_dual_stream_->UnregisterSecondarySendCodec();
530 ASSERT_EQ(-1, acm_dual_stream_->SecondarySendCodec(&my_codec));
532 ASSERT_EQ(0, acm_dual_stream_->SetVAD(true, true, VADVeryAggr));
533 // Make sure VAD is activated.
534 EXPECT_EQ(0, acm_dual_stream_->VAD(&vad_status, &dtx_status, &vad_mode));
535 EXPECT_TRUE(vad_status);
536 EXPECT_TRUE(dtx_status);
537 EXPECT_EQ(VADVeryAggr, vad_mode);
540 } // namespace webrtc