1/*
2 *  Copyright (c) 2012 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 "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"
21
22namespace webrtc {
23
24class DualStreamTest : public AudioPacketizationCallback,
25                       public ::testing::Test {
26 protected:
27  DualStreamTest();
28  ~DualStreamTest();
29
30  void RunTest(int frame_size_primary_samples,
31               int num_channels_primary,
32               int sampling_rate,
33               bool start_in_sync,
34               int num_channels_input);
35
36  void ApiTest();
37
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;
43
44  void Perform(bool start_in_sync, int num_channels_input);
45
46  void InitializeSender(int frame_size_primary_samples,
47                        int num_channels_primary, int sampling_rate);
48
49  void PopulateCodecInstances(int frame_size_primary_ms,
50                              int num_channels_primary, int sampling_rate);
51
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);
56
57  static const int kMaxNumStoredPayloads = 2;
58
59  enum {
60    kPrimary = 0,
61    kSecondary,
62    kMaxNumStreams
63  };
64
65  scoped_ptr<AudioCodingModule> acm_dual_stream_;
66  scoped_ptr<AudioCodingModule> acm_ref_primary_;
67  scoped_ptr<AudioCodingModule> acm_ref_secondary_;
68
69  CodecInst primary_encoder_;
70  CodecInst secondary_encoder_;
71
72  CodecInst red_encoder_;
73
74  int payload_ref_is_stored_[kMaxNumStreams][kMaxNumStoredPayloads];
75  int payload_dual_is_stored_[kMaxNumStreams][kMaxNumStoredPayloads];
76
77  uint32_t timestamp_ref_[kMaxNumStreams][kMaxNumStoredPayloads];
78  uint32_t timestamp_dual_[kMaxNumStreams][kMaxNumStoredPayloads];
79
80  int payload_len_ref_[kMaxNumStreams][kMaxNumStoredPayloads];
81  int payload_len_dual_[kMaxNumStreams][kMaxNumStoredPayloads];
82
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];
89
90  int num_compared_payloads_[kMaxNumStreams];
91  uint32_t last_timestamp_[kMaxNumStreams];
92  bool received_payload_[kMaxNumStreams];
93};
94
95DualStreamTest::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_(),
101      timestamp_ref_(),
102      num_received_payloads_dual_(),
103      num_received_payloads_ref_(),
104      num_compared_payloads_(),
105      last_timestamp_(),
106      received_payload_() {}
107
108DualStreamTest::~DualStreamTest() {}
109
110void DualStreamTest::PopulateCodecInstances(int frame_size_primary_ms,
111                                            int num_channels_primary,
112                                            int sampling_rate) {
113  CodecInst my_codec;
114
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;
119
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));
134    }
135  }
136
137  ASSERT_GE(primary_encoder_.pltype, 0);
138  ASSERT_GE(secondary_encoder_.pltype, 0);
139  ASSERT_GE(red_encoder_.pltype, 0);
140}
141
142void DualStreamTest::InitializeSender(int frame_size_primary_samples,
143                                      int num_channels_primary,
144                                      int sampling_rate) {
145  ASSERT_TRUE(acm_dual_stream_.get() != NULL);
146  ASSERT_TRUE(acm_ref_primary_.get() != NULL);
147  ASSERT_TRUE(acm_ref_secondary_.get() != NULL);
148
149  ASSERT_EQ(0, acm_dual_stream_->InitializeSender());
150  ASSERT_EQ(0, acm_ref_primary_->InitializeSender());
151  ASSERT_EQ(0, acm_ref_secondary_->InitializeSender());
152
153  PopulateCodecInstances(frame_size_primary_samples, num_channels_primary,
154                         sampling_rate);
155
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_));
159  ASSERT_EQ(0,
160            acm_dual_stream_->RegisterSecondarySendCodec(secondary_encoder_));
161
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));
165}
166
167void DualStreamTest::Perform(bool start_in_sync, int num_channels_input) {
168  PCMFile pcm_file;
169  std::string file_name = test::ResourcePath(
170      (num_channels_input == 1) ?
171          "audio_coding/testfile32kHz" : "audio_coding/teststereo32kHz",
172      "pcm");
173  pcm_file.Open(file_name, 32000, "rb");
174  pcm_file.ReadStereo(num_channels_input == 2);
175  AudioFrame audio_frame;
176
177  int tolerance = 0;
178  if (num_channels_input == 2 && primary_encoder_.channels == 2
179      && secondary_encoder_.channels == 1) {
180    tolerance = 12;
181  }
182
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));
189    ASSERT_EQ(0,
190              acm_dual_stream_->RegisterSecondarySendCodec(secondary_encoder_));
191  }
192
193  const int kNumFramesToProcess = 100;
194  int frame_cntr = 0;
195  while (!pcm_file.EndOfFile() && frame_cntr < kNumFramesToProcess) {
196    pcm_file.Read10MsData(audio_frame);
197    frame_cntr++;
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));
201
202    EXPECT_GE(acm_dual_stream_->Process(), 0);
203    EXPECT_GE(acm_ref_primary_->Process(), 0);
204    EXPECT_GE(acm_ref_secondary_->Process(), 0);
205
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);
211    } else {
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_));
216    }
217  }
218  pcm_file.Close();
219
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]);
226  EXPECT_TRUE(
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));
231
232  // Make sure all received payloads are compared.
233  if (start_in_sync) {
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]);
238  } else {
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);
245  }
246}
247
248bool DualStreamTest::EqualTimestamp(int stream_index, int position) {
249  if (timestamp_dual_[stream_index][position]
250      != timestamp_ref_[stream_index][position]) {
251    return false;
252  }
253  return true;
254}
255
256int DualStreamTest::EqualPayloadLength(int stream_index, int position) {
257  return abs(
258      payload_len_dual_[stream_index][position]
259          - payload_len_ref_[stream_index][position]);
260}
261
262bool DualStreamTest::EqualPayloadData(int stream_index, int position) {
263  assert(
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]) {
270      return false;
271    }
272  }
273  return true;
274}
275
276void 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;
291      }
292    }
293  }
294}
295
296int32_t DualStreamTest::SendData(FrameType frameType, uint8_t payload_type,
297                                 uint32_t timestamp,
298                                 const uint8_t* payload_data,
299                                 uint16_t payload_size,
300                                 const RTPFragmentationHeader* fragmentation) {
301  int position;
302  int stream_index;
303
304  if (payload_type == red_encoder_.pltype) {
305    if (fragmentation == NULL) {
306      assert(false);
307      return -1;
308    }
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
311    // backward.
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;
320      } else {
321        assert(false);
322        return -1;
323      }
324      num_received_payloads_dual_[stream_index]++;
325      if (payload_dual_is_stored_[stream_index][0] == 0) {
326        position = 0;
327      } else if (payload_dual_is_stored_[stream_index][1] == 0) {
328        position = 1;
329      } else {
330        assert(false);
331        return -1;
332      }
333      timestamp_dual_[stream_index][position] = timestamp
334          - fragmentation->fragmentationTimeDiff[n];
335      payload_len_dual_[stream_index][position] = fragmentation
336          ->fragmentationLength[n];
337      memcpy(
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)) {
347          assert(false);
348          return -1;
349        }
350        if ((stream_index == kSecondary) && (t != secondary_encoder_.pacsize)) {
351          assert(false);
352          return -1;
353        }
354      } else {
355        received_payload_[stream_index] = true;
356      }
357      last_timestamp_[stream_index] = timestamp_dual_[stream_index][position];
358    }
359  } else {
360    if (fragmentation != NULL) {
361      assert(false);
362      return -1;
363    }
364    if (payload_type == primary_encoder_.pltype) {
365      stream_index = kPrimary;
366    } else if (payload_type == secondary_encoder_.pltype) {
367      stream_index = kSecondary;
368    } else {
369      assert(false);
370      return -1;
371    }
372    num_received_payloads_ref_[stream_index]++;
373    if (payload_ref_is_stored_[stream_index][0] == 0) {
374      position = 0;
375    } else if (payload_ref_is_stored_[stream_index][1] == 0) {
376      position = 1;
377    } else {
378      assert(false);
379      return -1;
380    }
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;
386  }
387  return 0;
388}
389
390// Mono input, mono primary WB 20 ms frame.
391TEST_F(DualStreamTest,
392       DISABLED_ON_ANDROID(BitExactSyncMonoInputMonoPrimaryWb20Ms)) {
393  InitializeSender(20, 1, 16000);
394  Perform(true, 1);
395}
396
397// Mono input, stereo primary WB 20 ms frame.
398TEST_F(DualStreamTest,
399       DISABLED_ON_ANDROID(BitExactSyncMonoInput_StereoPrimaryWb20Ms)) {
400  InitializeSender(20, 2, 16000);
401  Perform(true, 1);
402}
403
404// Mono input, mono primary SWB 20 ms frame.
405TEST_F(DualStreamTest,
406       DISABLED_ON_ANDROID(BitExactSyncMonoInputMonoPrimarySwb20Ms)) {
407  InitializeSender(20, 1, 32000);
408  Perform(true, 1);
409}
410
411// Mono input, stereo primary SWB 20 ms frame.
412TEST_F(DualStreamTest,
413       DISABLED_ON_ANDROID(BitExactSyncMonoInputStereoPrimarySwb20Ms)) {
414  InitializeSender(20, 2, 32000);
415  Perform(true, 1);
416}
417
418// Mono input, mono primary WB 40 ms frame.
419TEST_F(DualStreamTest,
420       DISABLED_ON_ANDROID(BitExactSyncMonoInputMonoPrimaryWb40Ms)) {
421  InitializeSender(40, 1, 16000);
422  Perform(true, 1);
423}
424
425// Mono input, stereo primary WB 40 ms frame
426TEST_F(DualStreamTest,
427       DISABLED_ON_ANDROID(BitExactSyncMonoInputStereoPrimaryWb40Ms)) {
428  InitializeSender(40, 2, 16000);
429  Perform(true, 1);
430}
431
432// Stereo input, mono primary WB 20 ms frame.
433TEST_F(DualStreamTest,
434       DISABLED_ON_ANDROID(BitExactSyncStereoInputMonoPrimaryWb20Ms)) {
435  InitializeSender(20, 1, 16000);
436  Perform(true, 2);
437}
438
439// Stereo input, stereo primary WB 20 ms frame.
440TEST_F(DualStreamTest,
441       DISABLED_ON_ANDROID(BitExactSyncStereoInputStereoPrimaryWb20Ms)) {
442  InitializeSender(20, 2, 16000);
443  Perform(true, 2);
444}
445
446// Stereo input, mono primary SWB 20 ms frame.
447TEST_F(DualStreamTest,
448       DISABLED_ON_ANDROID(BitExactSyncStereoInputMonoPrimarySwb20Ms)) {
449  InitializeSender(20, 1, 32000);
450  Perform(true, 2);
451}
452
453// Stereo input, stereo primary SWB 20 ms frame.
454TEST_F(DualStreamTest,
455       DISABLED_ON_ANDROID(BitExactSyncStereoInputStereoPrimarySwb20Ms)) {
456  InitializeSender(20, 2, 32000);
457  Perform(true, 2);
458}
459
460// Stereo input, mono primary WB 40 ms frame.
461TEST_F(DualStreamTest,
462       DISABLED_ON_ANDROID(BitExactSyncStereoInputMonoPrimaryWb40Ms)) {
463  InitializeSender(40, 1, 16000);
464  Perform(true, 2);
465}
466
467// Stereo input, stereo primary WB 40 ms frame.
468TEST_F(DualStreamTest,
469       DISABLED_ON_ANDROID(BitExactSyncStereoInputStereoPrimaryWb40Ms)) {
470  InitializeSender(40, 2, 16000);
471  Perform(true, 2);
472}
473
474// Asynchronous test, ACM is fed with data then secondary coder is registered.
475// Mono input, mono primary WB 20 ms frame.
476TEST_F(DualStreamTest,
477       DISABLED_ON_ANDROID(BitExactAsyncMonoInputMonoPrimaryWb20Ms)) {
478  InitializeSender(20, 1, 16000);
479  Perform(false, 1);
480}
481
482// Mono input, mono primary WB 20 ms frame.
483TEST_F(DualStreamTest,
484       DISABLED_ON_ANDROID(BitExactAsyncMonoInputMonoPrimaryWb40Ms)) {
485  InitializeSender(40, 1, 16000);
486  Perform(false, 1);
487}
488
489TEST_F(DualStreamTest, DISABLED_ON_ANDROID(Api)) {
490  PopulateCodecInstances(20, 1, 16000);
491  CodecInst my_codec;
492  ASSERT_EQ(0, acm_dual_stream_->InitializeSender());
493  ASSERT_EQ(-1, acm_dual_stream_->SecondarySendCodec(&my_codec));
494
495  // Not allowed to register secondary codec if primary is not registered yet.
496  ASSERT_EQ(-1,
497      acm_dual_stream_->RegisterSecondarySendCodec(secondary_encoder_));
498  ASSERT_EQ(-1, acm_dual_stream_->SecondarySendCodec(&my_codec));
499
500  ASSERT_EQ(0, acm_dual_stream_->RegisterSendCodec(primary_encoder_));
501
502  ASSERT_EQ(0, acm_dual_stream_->SetVAD(true, true, VADNormal));
503
504  // Make sure vad is activated.
505  bool vad_status;
506  bool dtx_status;
507  ACMVADMode vad_mode;
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);
512
513  ASSERT_EQ(0,
514      acm_dual_stream_->RegisterSecondarySendCodec(secondary_encoder_));
515
516  ASSERT_EQ(0, acm_dual_stream_->SecondarySendCodec(&my_codec));
517  ASSERT_EQ(0, memcmp(&my_codec, &secondary_encoder_, sizeof(my_codec)));
518
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);
523
524  // Activating VAD should fail.
525  ASSERT_EQ(-1, acm_dual_stream_->SetVAD(true, true, VADNormal));
526
527  // Unregister secondary encoder and it should be possible to activate VAD.
528  acm_dual_stream_->UnregisterSecondarySendCodec();
529  // Should fail.
530  ASSERT_EQ(-1, acm_dual_stream_->SecondarySendCodec(&my_codec));
531
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);
538}
539
540}  // namespace webrtc
541