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 <string.h>
12#include <vector>
13
14#include "testing/gtest/include/gtest/gtest.h"
15#include "webrtc/base/checks.h"
16#include "webrtc/base/md5digest.h"
17#include "webrtc/base/thread_annotations.h"
18#include "webrtc/modules/audio_coding/main/acm2/acm_receive_test.h"
19#include "webrtc/modules/audio_coding/main/acm2/acm_send_test.h"
20#include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
21#include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h"
22#include "webrtc/modules/audio_coding/neteq/tools/audio_checksum.h"
23#include "webrtc/modules/audio_coding/neteq/tools/audio_loop.h"
24#include "webrtc/modules/audio_coding/neteq/tools/input_audio_file.h"
25#include "webrtc/modules/audio_coding/neteq/tools/output_audio_file.h"
26#include "webrtc/modules/audio_coding/neteq/tools/packet.h"
27#include "webrtc/modules/audio_coding/neteq/tools/rtp_file_source.h"
28#include "webrtc/modules/interface/module_common_types.h"
29#include "webrtc/system_wrappers/interface/clock.h"
30#include "webrtc/system_wrappers/interface/compile_assert.h"
31#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
32#include "webrtc/system_wrappers/interface/event_wrapper.h"
33#include "webrtc/system_wrappers/interface/scoped_ptr.h"
34#include "webrtc/system_wrappers/interface/sleep.h"
35#include "webrtc/system_wrappers/interface/thread_wrapper.h"
36#include "webrtc/test/testsupport/fileutils.h"
37#include "webrtc/test/testsupport/gtest_disable.h"
38
39namespace webrtc {
40
41const int kSampleRateHz = 16000;
42const int kNumSamples10ms = kSampleRateHz / 100;
43const int kFrameSizeMs = 10;  // Multiple of 10.
44const int kFrameSizeSamples = kFrameSizeMs / 10 * kNumSamples10ms;
45const int kPayloadSizeBytes = kFrameSizeSamples * sizeof(int16_t);
46const uint8_t kPayloadType = 111;
47
48class RtpUtility {
49 public:
50  RtpUtility(int samples_per_packet, uint8_t payload_type)
51      : samples_per_packet_(samples_per_packet), payload_type_(payload_type) {}
52
53  virtual ~RtpUtility() {}
54
55  void Populate(WebRtcRTPHeader* rtp_header) {
56    rtp_header->header.sequenceNumber = 0xABCD;
57    rtp_header->header.timestamp = 0xABCDEF01;
58    rtp_header->header.payloadType = payload_type_;
59    rtp_header->header.markerBit = false;
60    rtp_header->header.ssrc = 0x1234;
61    rtp_header->header.numCSRCs = 0;
62    rtp_header->frameType = kAudioFrameSpeech;
63
64    rtp_header->header.payload_type_frequency = kSampleRateHz;
65    rtp_header->type.Audio.channel = 1;
66    rtp_header->type.Audio.isCNG = false;
67  }
68
69  void Forward(WebRtcRTPHeader* rtp_header) {
70    ++rtp_header->header.sequenceNumber;
71    rtp_header->header.timestamp += samples_per_packet_;
72  }
73
74 private:
75  int samples_per_packet_;
76  uint8_t payload_type_;
77};
78
79class PacketizationCallbackStub : public AudioPacketizationCallback {
80 public:
81  PacketizationCallbackStub()
82      : num_calls_(0),
83        crit_sect_(CriticalSectionWrapper::CreateCriticalSection()) {}
84
85  virtual int32_t SendData(
86      FrameType frame_type,
87      uint8_t payload_type,
88      uint32_t timestamp,
89      const uint8_t* payload_data,
90      uint16_t payload_len_bytes,
91      const RTPFragmentationHeader* fragmentation) OVERRIDE {
92    CriticalSectionScoped lock(crit_sect_.get());
93    ++num_calls_;
94    last_payload_vec_.assign(payload_data, payload_data + payload_len_bytes);
95    return 0;
96  }
97
98  int num_calls() const {
99    CriticalSectionScoped lock(crit_sect_.get());
100    return num_calls_;
101  }
102
103  int last_payload_len_bytes() const {
104    CriticalSectionScoped lock(crit_sect_.get());
105    return last_payload_vec_.size();
106  }
107
108  void SwapBuffers(std::vector<uint8_t>* payload) {
109    CriticalSectionScoped lock(crit_sect_.get());
110    last_payload_vec_.swap(*payload);
111  }
112
113 private:
114  int num_calls_ GUARDED_BY(crit_sect_);
115  std::vector<uint8_t> last_payload_vec_ GUARDED_BY(crit_sect_);
116  const scoped_ptr<CriticalSectionWrapper> crit_sect_;
117};
118
119class AudioCodingModuleTest : public ::testing::Test {
120 protected:
121  AudioCodingModuleTest()
122      : rtp_utility_(new RtpUtility(kFrameSizeSamples, kPayloadType)) {
123    config_.transport = &packet_cb_;
124  }
125
126  ~AudioCodingModuleTest() {}
127
128  void TearDown() OVERRIDE {}
129
130  void SetUp() OVERRIDE {
131    rtp_utility_->Populate(&rtp_header_);
132
133    input_frame_.sample_rate_hz_ = kSampleRateHz;
134    input_frame_.num_channels_ = 1;
135    input_frame_.samples_per_channel_ = kSampleRateHz * 10 / 1000;  // 10 ms.
136    COMPILE_ASSERT(kSampleRateHz * 10 / 1000 <= AudioFrame::kMaxDataSizeSamples,
137                   audio_frame_too_small);
138    memset(input_frame_.data_,
139           0,
140           input_frame_.samples_per_channel_ * sizeof(input_frame_.data_[0]));
141  }
142
143  void CreateAcm() {
144    acm_.reset(AudioCoding::Create(config_));
145    ASSERT_TRUE(acm_.get() != NULL);
146    RegisterCodec();
147  }
148
149  virtual void RegisterCodec() {
150    // Register L16 codec in ACM.
151    int codec_type = acm2::ACMCodecDB::kNone;
152    switch (kSampleRateHz) {
153      case 8000:
154        codec_type = acm2::ACMCodecDB::kPCM16B;
155        break;
156      case 16000:
157        codec_type = acm2::ACMCodecDB::kPCM16Bwb;
158        break;
159      case 32000:
160        codec_type = acm2::ACMCodecDB::kPCM16Bswb32kHz;
161        break;
162      default:
163        FATAL() << "Sample rate not supported in this test.";
164    }
165    ASSERT_TRUE(acm_->RegisterSendCodec(codec_type, kPayloadType));
166    ASSERT_TRUE(acm_->RegisterReceiveCodec(codec_type, kPayloadType));
167  }
168
169  virtual void InsertPacketAndPullAudio() {
170    InsertPacket();
171    PullAudio();
172  }
173
174  virtual void InsertPacket() {
175    const uint8_t kPayload[kPayloadSizeBytes] = {0};
176    ASSERT_TRUE(acm_->InsertPacket(kPayload, kPayloadSizeBytes, rtp_header_));
177    rtp_utility_->Forward(&rtp_header_);
178  }
179
180  virtual void PullAudio() {
181    AudioFrame audio_frame;
182    ASSERT_TRUE(acm_->Get10MsAudio(&audio_frame));
183  }
184
185  virtual void InsertAudio() {
186    int encoded_bytes = acm_->Add10MsAudio(input_frame_);
187    ASSERT_GE(encoded_bytes, 0);
188    input_frame_.timestamp_ += kNumSamples10ms;
189  }
190
191  AudioCoding::Config config_;
192  scoped_ptr<RtpUtility> rtp_utility_;
193  scoped_ptr<AudioCoding> acm_;
194  PacketizationCallbackStub packet_cb_;
195  WebRtcRTPHeader rtp_header_;
196  AudioFrame input_frame_;
197};
198
199// Check if the statistics are initialized correctly. Before any call to ACM
200// all fields have to be zero.
201TEST_F(AudioCodingModuleTest, DISABLED_ON_ANDROID(InitializedToZero)) {
202  CreateAcm();
203  AudioDecodingCallStats stats;
204  acm_->GetDecodingCallStatistics(&stats);
205  EXPECT_EQ(0, stats.calls_to_neteq);
206  EXPECT_EQ(0, stats.calls_to_silence_generator);
207  EXPECT_EQ(0, stats.decoded_normal);
208  EXPECT_EQ(0, stats.decoded_cng);
209  EXPECT_EQ(0, stats.decoded_plc);
210  EXPECT_EQ(0, stats.decoded_plc_cng);
211}
212
213// Apply an initial playout delay. Calls to AudioCodingModule::PlayoutData10ms()
214// should result in generating silence, check the associated field.
215TEST_F(AudioCodingModuleTest, DISABLED_ON_ANDROID(SilenceGeneratorCalled)) {
216  const int kInitialDelay = 100;
217  config_.initial_playout_delay_ms = kInitialDelay;
218  CreateAcm();
219  AudioDecodingCallStats stats;
220
221  int num_calls = 0;
222  for (int time_ms = 0; time_ms < kInitialDelay;
223       time_ms += kFrameSizeMs, ++num_calls) {
224    InsertPacketAndPullAudio();
225  }
226  acm_->GetDecodingCallStatistics(&stats);
227  EXPECT_EQ(0, stats.calls_to_neteq);
228  EXPECT_EQ(num_calls, stats.calls_to_silence_generator);
229  EXPECT_EQ(0, stats.decoded_normal);
230  EXPECT_EQ(0, stats.decoded_cng);
231  EXPECT_EQ(0, stats.decoded_plc);
232  EXPECT_EQ(0, stats.decoded_plc_cng);
233}
234
235// Insert some packets and pull audio. Check statistics are valid. Then,
236// simulate packet loss and check if PLC and PLC-to-CNG statistics are
237// correctly updated.
238TEST_F(AudioCodingModuleTest, DISABLED_ON_ANDROID(NetEqCalls)) {
239  CreateAcm();
240  AudioDecodingCallStats stats;
241  const int kNumNormalCalls = 10;
242
243  for (int num_calls = 0; num_calls < kNumNormalCalls; ++num_calls) {
244    InsertPacketAndPullAudio();
245  }
246  acm_->GetDecodingCallStatistics(&stats);
247  EXPECT_EQ(kNumNormalCalls, stats.calls_to_neteq);
248  EXPECT_EQ(0, stats.calls_to_silence_generator);
249  EXPECT_EQ(kNumNormalCalls, stats.decoded_normal);
250  EXPECT_EQ(0, stats.decoded_cng);
251  EXPECT_EQ(0, stats.decoded_plc);
252  EXPECT_EQ(0, stats.decoded_plc_cng);
253
254  const int kNumPlc = 3;
255  const int kNumPlcCng = 5;
256
257  // Simulate packet-loss. NetEq first performs PLC then PLC fades to CNG.
258  for (int n = 0; n < kNumPlc + kNumPlcCng; ++n) {
259    PullAudio();
260  }
261  acm_->GetDecodingCallStatistics(&stats);
262  EXPECT_EQ(kNumNormalCalls + kNumPlc + kNumPlcCng, stats.calls_to_neteq);
263  EXPECT_EQ(0, stats.calls_to_silence_generator);
264  EXPECT_EQ(kNumNormalCalls, stats.decoded_normal);
265  EXPECT_EQ(0, stats.decoded_cng);
266  EXPECT_EQ(kNumPlc, stats.decoded_plc);
267  EXPECT_EQ(kNumPlcCng, stats.decoded_plc_cng);
268}
269
270TEST_F(AudioCodingModuleTest, VerifyOutputFrame) {
271  CreateAcm();
272  AudioFrame audio_frame;
273  const int kSampleRateHz = 32000;
274  EXPECT_TRUE(acm_->Get10MsAudio(&audio_frame));
275  EXPECT_EQ(0u, audio_frame.timestamp_);
276  EXPECT_GT(audio_frame.num_channels_, 0);
277  EXPECT_EQ(kSampleRateHz / 100, audio_frame.samples_per_channel_);
278  EXPECT_EQ(kSampleRateHz, audio_frame.sample_rate_hz_);
279}
280
281// A multi-threaded test for ACM. This base class is using the PCM16b 16 kHz
282// codec, while the derive class AcmIsacMtTest is using iSAC.
283class AudioCodingModuleMtTest : public AudioCodingModuleTest {
284 protected:
285  static const int kNumPackets = 500;
286  static const int kNumPullCalls = 500;
287
288  AudioCodingModuleMtTest()
289      : AudioCodingModuleTest(),
290        send_thread_(ThreadWrapper::CreateThread(CbSendThread,
291                                                 this,
292                                                 kRealtimePriority,
293                                                 "send")),
294        insert_packet_thread_(ThreadWrapper::CreateThread(CbInsertPacketThread,
295                                                          this,
296                                                          kRealtimePriority,
297                                                          "insert_packet")),
298        pull_audio_thread_(ThreadWrapper::CreateThread(CbPullAudioThread,
299                                                       this,
300                                                       kRealtimePriority,
301                                                       "pull_audio")),
302        test_complete_(EventWrapper::Create()),
303        send_count_(0),
304        insert_packet_count_(0),
305        pull_audio_count_(0),
306        crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
307        next_insert_packet_time_ms_(0),
308        fake_clock_(new SimulatedClock(0)) {
309    config_.clock = fake_clock_.get();
310  }
311
312  virtual void SetUp() OVERRIDE {
313    AudioCodingModuleTest::SetUp();
314    CreateAcm();
315    StartThreads();
316  }
317
318  void StartThreads() {
319    unsigned int thread_id = 0;
320    ASSERT_TRUE(send_thread_->Start(thread_id));
321    ASSERT_TRUE(insert_packet_thread_->Start(thread_id));
322    ASSERT_TRUE(pull_audio_thread_->Start(thread_id));
323  }
324
325  virtual void TearDown() OVERRIDE {
326    AudioCodingModuleTest::TearDown();
327    pull_audio_thread_->Stop();
328    send_thread_->Stop();
329    insert_packet_thread_->Stop();
330  }
331
332  EventTypeWrapper RunTest() {
333    return test_complete_->Wait(10 * 60 * 1000);  // 10 minutes' timeout.
334  }
335
336  virtual bool TestDone() {
337    if (packet_cb_.num_calls() > kNumPackets) {
338      CriticalSectionScoped lock(crit_sect_.get());
339      if (pull_audio_count_ > kNumPullCalls) {
340        // Both conditions for completion are met. End the test.
341        return true;
342      }
343    }
344    return false;
345  }
346
347  static bool CbSendThread(void* context) {
348    return reinterpret_cast<AudioCodingModuleMtTest*>(context)->CbSendImpl();
349  }
350
351  // The send thread doesn't have to care about the current simulated time,
352  // since only the AcmReceiver is using the clock.
353  bool CbSendImpl() {
354    SleepMs(1);
355    if (HasFatalFailure()) {
356      // End the test early if a fatal failure (ASSERT_*) has occurred.
357      test_complete_->Set();
358    }
359    ++send_count_;
360    InsertAudio();
361    if (TestDone()) {
362      test_complete_->Set();
363    }
364    return true;
365  }
366
367  static bool CbInsertPacketThread(void* context) {
368    return reinterpret_cast<AudioCodingModuleMtTest*>(context)
369        ->CbInsertPacketImpl();
370  }
371
372  bool CbInsertPacketImpl() {
373    SleepMs(1);
374    {
375      CriticalSectionScoped lock(crit_sect_.get());
376      if (fake_clock_->TimeInMilliseconds() < next_insert_packet_time_ms_) {
377        return true;
378      }
379      next_insert_packet_time_ms_ += 10;
380    }
381    // Now we're not holding the crit sect when calling ACM.
382    ++insert_packet_count_;
383    InsertPacket();
384    return true;
385  }
386
387  static bool CbPullAudioThread(void* context) {
388    return reinterpret_cast<AudioCodingModuleMtTest*>(context)
389        ->CbPullAudioImpl();
390  }
391
392  bool CbPullAudioImpl() {
393    SleepMs(1);
394    {
395      CriticalSectionScoped lock(crit_sect_.get());
396      // Don't let the insert thread fall behind.
397      if (next_insert_packet_time_ms_ < fake_clock_->TimeInMilliseconds()) {
398        return true;
399      }
400      ++pull_audio_count_;
401    }
402    // Now we're not holding the crit sect when calling ACM.
403    PullAudio();
404    fake_clock_->AdvanceTimeMilliseconds(10);
405    return true;
406  }
407
408  scoped_ptr<ThreadWrapper> send_thread_;
409  scoped_ptr<ThreadWrapper> insert_packet_thread_;
410  scoped_ptr<ThreadWrapper> pull_audio_thread_;
411  const scoped_ptr<EventWrapper> test_complete_;
412  int send_count_;
413  int insert_packet_count_;
414  int pull_audio_count_ GUARDED_BY(crit_sect_);
415  const scoped_ptr<CriticalSectionWrapper> crit_sect_;
416  int64_t next_insert_packet_time_ms_ GUARDED_BY(crit_sect_);
417  scoped_ptr<SimulatedClock> fake_clock_;
418};
419
420TEST_F(AudioCodingModuleMtTest, DoTest) {
421  EXPECT_EQ(kEventSignaled, RunTest());
422}
423
424// This is a multi-threaded ACM test using iSAC. The test encodes audio
425// from a PCM file. The most recent encoded frame is used as input to the
426// receiving part. Depending on timing, it may happen that the same RTP packet
427// is inserted into the receiver multiple times, but this is a valid use-case,
428// and simplifies the test code a lot.
429class AcmIsacMtTest : public AudioCodingModuleMtTest {
430 protected:
431  static const int kNumPackets = 500;
432  static const int kNumPullCalls = 500;
433
434  AcmIsacMtTest()
435      : AudioCodingModuleMtTest(),
436        last_packet_number_(0) {}
437
438  ~AcmIsacMtTest() {}
439
440  virtual void SetUp() OVERRIDE {
441    AudioCodingModuleTest::SetUp();
442    CreateAcm();
443
444    // Set up input audio source to read from specified file, loop after 5
445    // seconds, and deliver blocks of 10 ms.
446    const std::string input_file_name =
447        webrtc::test::ResourcePath("audio_coding/speech_mono_16kHz", "pcm");
448    audio_loop_.Init(input_file_name, 5 * kSampleRateHz, kNumSamples10ms);
449
450    // Generate one packet to have something to insert.
451    int loop_counter = 0;
452    while (packet_cb_.last_payload_len_bytes() == 0) {
453      InsertAudio();
454      ASSERT_LT(loop_counter++, 10);
455    }
456    // Set |last_packet_number_| to one less that |num_calls| so that the packet
457    // will be fetched in the next InsertPacket() call.
458    last_packet_number_ = packet_cb_.num_calls() - 1;
459
460    StartThreads();
461  }
462
463  virtual void RegisterCodec() OVERRIDE {
464    COMPILE_ASSERT(kSampleRateHz == 16000, test_designed_for_isac_16khz);
465
466    // Register iSAC codec in ACM, effectively unregistering the PCM16B codec
467    // registered in AudioCodingModuleTest::SetUp();
468    ASSERT_TRUE(acm_->RegisterSendCodec(acm2::ACMCodecDB::kISAC, kPayloadType));
469    ASSERT_TRUE(
470        acm_->RegisterReceiveCodec(acm2::ACMCodecDB::kISAC, kPayloadType));
471  }
472
473  virtual void InsertPacket() OVERRIDE {
474    int num_calls = packet_cb_.num_calls();  // Store locally for thread safety.
475    if (num_calls > last_packet_number_) {
476      // Get the new payload out from the callback handler.
477      // Note that since we swap buffers here instead of directly inserting
478      // a pointer to the data in |packet_cb_|, we avoid locking the callback
479      // for the duration of the IncomingPacket() call.
480      packet_cb_.SwapBuffers(&last_payload_vec_);
481      ASSERT_GT(last_payload_vec_.size(), 0u);
482      rtp_utility_->Forward(&rtp_header_);
483      last_packet_number_ = num_calls;
484    }
485    ASSERT_GT(last_payload_vec_.size(), 0u);
486    ASSERT_TRUE(acm_->InsertPacket(
487        &last_payload_vec_[0], last_payload_vec_.size(), rtp_header_));
488  }
489
490  virtual void InsertAudio() OVERRIDE {
491    memcpy(input_frame_.data_, audio_loop_.GetNextBlock(), kNumSamples10ms);
492    AudioCodingModuleTest::InsertAudio();
493  }
494
495  // This method is the same as AudioCodingModuleMtTest::TestDone(), but here
496  // it is using the constants defined in this class (i.e., shorter test run).
497  virtual bool TestDone() OVERRIDE {
498    if (packet_cb_.num_calls() > kNumPackets) {
499      CriticalSectionScoped lock(crit_sect_.get());
500      if (pull_audio_count_ > kNumPullCalls) {
501        // Both conditions for completion are met. End the test.
502        return true;
503      }
504    }
505    return false;
506  }
507
508  int last_packet_number_;
509  std::vector<uint8_t> last_payload_vec_;
510  test::AudioLoop audio_loop_;
511};
512
513TEST_F(AcmIsacMtTest, DoTest) {
514  EXPECT_EQ(kEventSignaled, RunTest());
515}
516
517class AcmReceiverBitExactness : public ::testing::Test {
518 public:
519  static std::string PlatformChecksum(std::string win64,
520                                      std::string android,
521                                      std::string others) {
522#if defined(_WIN32) && defined(WEBRTC_ARCH_64_BITS)
523    return win64;
524#elif defined(WEBRTC_ANDROID)
525    return android;
526#else
527    return others;
528#endif
529  }
530
531 protected:
532  void Run(int output_freq_hz, const std::string& checksum_ref) {
533    const std::string input_file_name =
534        webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp");
535    scoped_ptr<test::RtpFileSource> packet_source(
536        test::RtpFileSource::Create(input_file_name));
537#ifdef WEBRTC_ANDROID
538    // Filter out iLBC and iSAC-swb since they are not supported on Android.
539    packet_source->FilterOutPayloadType(102);  // iLBC.
540    packet_source->FilterOutPayloadType(104);  // iSAC-swb.
541#endif
542
543    test::AudioChecksum checksum;
544    const std::string output_file_name =
545        webrtc::test::OutputPath() +
546        ::testing::UnitTest::GetInstance()
547            ->current_test_info()
548            ->test_case_name() +
549        "_" + ::testing::UnitTest::GetInstance()->current_test_info()->name() +
550        "_output.pcm";
551    test::OutputAudioFile output_file(output_file_name);
552    test::AudioSinkFork output(&checksum, &output_file);
553
554    test::AcmReceiveTest test(packet_source.get(), &output, output_freq_hz,
555                              test::AcmReceiveTest::kArbitraryChannels);
556    ASSERT_NO_FATAL_FAILURE(test.RegisterNetEqTestCodecs());
557    test.Run();
558
559    std::string checksum_string = checksum.Finish();
560    EXPECT_EQ(checksum_ref, checksum_string);
561  }
562};
563
564TEST_F(AcmReceiverBitExactness, 8kHzOutput) {
565  Run(8000,
566      PlatformChecksum("bd6f8d9602cd82444ea2539e674df747",
567                       "6ac89c7145072c26bfeba602cd661afb",
568                       "8a8440f5511eb729221b9aac25cda3a0"));
569}
570
571TEST_F(AcmReceiverBitExactness, 16kHzOutput) {
572  Run(16000,
573      PlatformChecksum("a39bc6ee0c4eb15f3ad2f43cebcc571d",
574                       "3e888eb04f57db2c6ef952fe64f17fe6",
575                       "7be583092c5adbcb0f6cd66eca20ea63"));
576}
577
578TEST_F(AcmReceiverBitExactness, 32kHzOutput) {
579  Run(32000,
580      PlatformChecksum("80964572aaa2dc92f9e34896dd3802b3",
581                       "aeca37e963310f5b6552b7edea23c2f1",
582                       "3a84188abe9fca25fedd6034760f3e22"));
583}
584
585TEST_F(AcmReceiverBitExactness, 48kHzOutput) {
586  Run(48000,
587      PlatformChecksum("8aacde91f390e0d5a9c2ed571a25fd37",
588                       "76b9e99e0a3998aa28355e7a2bd836f7",
589                       "89b4b19bdb4de40f1d88302ef8cb9f9b"));
590}
591
592// This test verifies bit exactness for the send-side of ACM. The test setup is
593// a chain of three different test classes:
594//
595// test::AcmSendTest -> AcmSenderBitExactness -> test::AcmReceiveTest
596//
597// The receiver side is driving the test by requesting new packets from
598// AcmSenderBitExactness::NextPacket(). This method, in turn, asks for the
599// packet from test::AcmSendTest::NextPacket, which inserts audio from the
600// input file until one packet is produced. (The input file loops indefinitely.)
601// Before passing the packet to the receiver, this test class verifies the
602// packet header and updates a payload checksum with the new payload. The
603// decoded output from the receiver is also verified with a (separate) checksum.
604class AcmSenderBitExactness : public ::testing::Test,
605                              public test::PacketSource {
606 protected:
607  static const int kTestDurationMs = 1000;
608
609  AcmSenderBitExactness()
610      : frame_size_rtp_timestamps_(0),
611        packet_count_(0),
612        payload_type_(0),
613        last_sequence_number_(0),
614        last_timestamp_(0) {}
615
616  // Sets up the test::AcmSendTest object. Returns true on success, otherwise
617  // false.
618  bool SetUpSender() {
619    const std::string input_file_name =
620        webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
621    // Note that |audio_source_| will loop forever. The test duration is set
622    // explicitly by |kTestDurationMs|.
623    audio_source_.reset(new test::InputAudioFile(input_file_name));
624    static const int kSourceRateHz = 32000;
625    send_test_.reset(new test::AcmSendTest(
626        audio_source_.get(), kSourceRateHz, kTestDurationMs));
627    return send_test_.get() != NULL;
628  }
629
630  // Registers a send codec in the test::AcmSendTest object. Returns true on
631  // success, false on failure.
632  bool RegisterSendCodec(int codec_type,
633                         int channels,
634                         int payload_type,
635                         int frame_size_samples,
636                         int frame_size_rtp_timestamps) {
637    payload_type_ = payload_type;
638    frame_size_rtp_timestamps_ = frame_size_rtp_timestamps;
639    return send_test_->RegisterCodec(
640        codec_type, channels, payload_type, frame_size_samples);
641  }
642
643  // Runs the test. SetUpSender() and RegisterSendCodec() must have been called
644  // before calling this method.
645  void Run(const std::string& audio_checksum_ref,
646           const std::string& payload_checksum_ref,
647           int expected_packets,
648           test::AcmReceiveTest::NumOutputChannels expected_channels) {
649    // Set up the receiver used to decode the packets and verify the decoded
650    // output.
651    test::AudioChecksum audio_checksum;
652    const std::string output_file_name =
653        webrtc::test::OutputPath() +
654        ::testing::UnitTest::GetInstance()
655            ->current_test_info()
656            ->test_case_name() +
657        "_" +
658        ::testing::UnitTest::GetInstance()->current_test_info()->name() +
659        "_output.pcm";
660    test::OutputAudioFile output_file(output_file_name);
661    // Have the output audio sent both to file and to the checksum calculator.
662    test::AudioSinkFork output(&audio_checksum, &output_file);
663    const int kOutputFreqHz = 8000;
664    test::AcmReceiveTest receive_test(
665        this, &output, kOutputFreqHz, expected_channels);
666    ASSERT_NO_FATAL_FAILURE(receive_test.RegisterDefaultCodecs());
667
668    // This is where the actual test is executed.
669    receive_test.Run();
670
671    // Extract and verify the audio checksum.
672    std::string checksum_string = audio_checksum.Finish();
673    EXPECT_EQ(audio_checksum_ref, checksum_string);
674
675    // Extract and verify the payload checksum.
676    char checksum_result[rtc::Md5Digest::kSize];
677    payload_checksum_.Finish(checksum_result, rtc::Md5Digest::kSize);
678    checksum_string = rtc::hex_encode(checksum_result, rtc::Md5Digest::kSize);
679    EXPECT_EQ(payload_checksum_ref, checksum_string);
680
681    // Verify number of packets produced.
682    EXPECT_EQ(expected_packets, packet_count_);
683  }
684
685  // Returns a pointer to the next packet. Returns NULL if the source is
686  // depleted (i.e., the test duration is exceeded), or if an error occurred.
687  // Inherited from test::PacketSource.
688  virtual test::Packet* NextPacket() OVERRIDE {
689    // Get the next packet from AcmSendTest. Ownership of |packet| is
690    // transferred to this method.
691    test::Packet* packet = send_test_->NextPacket();
692    if (!packet)
693      return NULL;
694
695    VerifyPacket(packet);
696    // TODO(henrik.lundin) Save the packet to file as well.
697
698    // Pass it on to the caller. The caller becomes the owner of |packet|.
699    return packet;
700  }
701
702  // Verifies the packet.
703  void VerifyPacket(const test::Packet* packet) {
704    EXPECT_TRUE(packet->valid_header());
705    // (We can check the header fields even if valid_header() is false.)
706    EXPECT_EQ(payload_type_, packet->header().payloadType);
707    if (packet_count_ > 0) {
708      // This is not the first packet.
709      uint16_t sequence_number_diff =
710          packet->header().sequenceNumber - last_sequence_number_;
711      EXPECT_EQ(1, sequence_number_diff);
712      uint32_t timestamp_diff = packet->header().timestamp - last_timestamp_;
713      EXPECT_EQ(frame_size_rtp_timestamps_, timestamp_diff);
714    }
715    ++packet_count_;
716    last_sequence_number_ = packet->header().sequenceNumber;
717    last_timestamp_ = packet->header().timestamp;
718    // Update the checksum.
719    payload_checksum_.Update(packet->payload(), packet->payload_length_bytes());
720  }
721
722  void SetUpTest(int codec_type,
723                 int channels,
724                 int payload_type,
725                 int codec_frame_size_samples,
726                 int codec_frame_size_rtp_timestamps) {
727    ASSERT_TRUE(SetUpSender());
728    ASSERT_TRUE(RegisterSendCodec(codec_type,
729                                  channels,
730                                  payload_type,
731                                  codec_frame_size_samples,
732                                  codec_frame_size_rtp_timestamps));
733  }
734
735  scoped_ptr<test::AcmSendTest> send_test_;
736  scoped_ptr<test::InputAudioFile> audio_source_;
737  uint32_t frame_size_rtp_timestamps_;
738  int packet_count_;
739  uint8_t payload_type_;
740  uint16_t last_sequence_number_;
741  uint32_t last_timestamp_;
742  rtc::Md5Digest payload_checksum_;
743};
744
745TEST_F(AcmSenderBitExactness, IsacWb30ms) {
746  ASSERT_NO_FATAL_FAILURE(SetUpTest(acm2::ACMCodecDB::kISAC, 1, 103, 480, 480));
747  Run(AcmReceiverBitExactness::PlatformChecksum(
748          "c7e5bdadfa2871df95639fcc297cf23d",
749          "0499ca260390769b3172136faad925b9",
750          "0b58f9eeee43d5891f5f6c75e77984a3"),
751      AcmReceiverBitExactness::PlatformChecksum(
752          "d42cb5195463da26c8129bbfe73a22e6",
753          "83de248aea9c3c2bd680b6952401b4ca",
754          "3c79f16f34218271f3dca4e2b1dfe1bb"),
755      33,
756      test::AcmReceiveTest::kMonoOutput);
757}
758
759TEST_F(AcmSenderBitExactness, IsacWb60ms) {
760  ASSERT_NO_FATAL_FAILURE(SetUpTest(acm2::ACMCodecDB::kISAC, 1, 103, 960, 960));
761  Run(AcmReceiverBitExactness::PlatformChecksum(
762          "14d63c5f08127d280e722e3191b73bdd",
763          "8da003e16c5371af2dc2be79a50f9076",
764          "1ad29139a04782a33daad8c2b9b35875"),
765      AcmReceiverBitExactness::PlatformChecksum(
766          "ebe04a819d3a9d83a83a17f271e1139a",
767          "97aeef98553b5a4b5a68f8b716e8eaf0",
768          "9e0a0ab743ad987b55b8e14802769c56"),
769      16,
770      test::AcmReceiveTest::kMonoOutput);
771}
772
773TEST_F(AcmSenderBitExactness, DISABLED_ON_ANDROID(IsacSwb30ms)) {
774  ASSERT_NO_FATAL_FAILURE(
775      SetUpTest(acm2::ACMCodecDB::kISACSWB, 1, 104, 960, 960));
776  Run(AcmReceiverBitExactness::PlatformChecksum(
777          "98d960600eb4ddb3fcbe11f5057ddfd7",
778          "",
779          "2f6dfe142f735f1d96f6bd86d2526f42"),
780      AcmReceiverBitExactness::PlatformChecksum(
781          "cc9d2d86a71d6f99f97680a5c27e2762",
782          "",
783          "7b214fc3a5e33d68bf30e77969371f31"),
784      33,
785      test::AcmReceiveTest::kMonoOutput);
786}
787
788TEST_F(AcmSenderBitExactness, Pcm16_8000khz_10ms) {
789  ASSERT_NO_FATAL_FAILURE(SetUpTest(acm2::ACMCodecDB::kPCM16B, 1, 107, 80, 80));
790  Run("de4a98e1406f8b798d99cd0704e862e2",
791      "c1edd36339ce0326cc4550041ad719a0",
792      100,
793      test::AcmReceiveTest::kMonoOutput);
794}
795
796TEST_F(AcmSenderBitExactness, Pcm16_16000khz_10ms) {
797  ASSERT_NO_FATAL_FAILURE(
798      SetUpTest(acm2::ACMCodecDB::kPCM16Bwb, 1, 108, 160, 160));
799  Run("ae646d7b68384a1269cc080dd4501916",
800      "ad786526383178b08d80d6eee06e9bad",
801      100,
802      test::AcmReceiveTest::kMonoOutput);
803}
804
805TEST_F(AcmSenderBitExactness, Pcm16_32000khz_10ms) {
806  ASSERT_NO_FATAL_FAILURE(
807      SetUpTest(acm2::ACMCodecDB::kPCM16Bswb32kHz, 1, 109, 320, 320));
808  Run("7fe325e8fbaf755e3c5df0b11a4774fb",
809      "5ef82ea885e922263606c6fdbc49f651",
810      100,
811      test::AcmReceiveTest::kMonoOutput);
812}
813
814TEST_F(AcmSenderBitExactness, Pcm16_stereo_8000khz_10ms) {
815  ASSERT_NO_FATAL_FAILURE(
816      SetUpTest(acm2::ACMCodecDB::kPCM16B_2ch, 2, 111, 80, 80));
817  Run("fb263b74e7ac3de915474d77e4744ceb",
818      "62ce5adb0d4965d0a52ec98ae7f98974",
819      100,
820      test::AcmReceiveTest::kStereoOutput);
821}
822
823TEST_F(AcmSenderBitExactness, Pcm16_stereo_16000khz_10ms) {
824  ASSERT_NO_FATAL_FAILURE(
825      SetUpTest(acm2::ACMCodecDB::kPCM16Bwb_2ch, 2, 112, 160, 160));
826  Run("d09e9239553649d7ac93e19d304281fd",
827      "41ca8edac4b8c71cd54fd9f25ec14870",
828      100,
829      test::AcmReceiveTest::kStereoOutput);
830}
831
832TEST_F(AcmSenderBitExactness, Pcm16_stereo_32000khz_10ms) {
833  ASSERT_NO_FATAL_FAILURE(
834      SetUpTest(acm2::ACMCodecDB::kPCM16Bswb32kHz_2ch, 2, 113, 320, 320));
835  Run("5f025d4f390982cc26b3d92fe02e3044",
836      "50e58502fb04421bf5b857dda4c96879",
837      100,
838      test::AcmReceiveTest::kStereoOutput);
839}
840
841TEST_F(AcmSenderBitExactness, Pcmu_20ms) {
842  ASSERT_NO_FATAL_FAILURE(SetUpTest(acm2::ACMCodecDB::kPCMU, 1, 0, 160, 160));
843  Run("81a9d4c0bb72e9becc43aef124c981e9",
844      "8f9b8750bd80fe26b6cbf6659b89f0f9",
845      50,
846      test::AcmReceiveTest::kMonoOutput);
847}
848
849TEST_F(AcmSenderBitExactness, Pcma_20ms) {
850  ASSERT_NO_FATAL_FAILURE(SetUpTest(acm2::ACMCodecDB::kPCMA, 1, 8, 160, 160));
851  Run("39611f798969053925a49dc06d08de29",
852      "6ad745e55aa48981bfc790d0eeef2dd1",
853      50,
854      test::AcmReceiveTest::kMonoOutput);
855}
856
857TEST_F(AcmSenderBitExactness, Pcmu_stereo_20ms) {
858  ASSERT_NO_FATAL_FAILURE(
859      SetUpTest(acm2::ACMCodecDB::kPCMU_2ch, 2, 110, 160, 160));
860  Run("437bec032fdc5cbaa0d5175430af7b18",
861      "60b6f25e8d1e74cb679cfe756dd9bca5",
862      50,
863      test::AcmReceiveTest::kStereoOutput);
864}
865
866TEST_F(AcmSenderBitExactness, Pcma_stereo_20ms) {
867  ASSERT_NO_FATAL_FAILURE(
868      SetUpTest(acm2::ACMCodecDB::kPCMA_2ch, 2, 118, 160, 160));
869  Run("a5c6d83c5b7cedbeff734238220a4b0c",
870      "92b282c83efd20e7eeef52ba40842cf7",
871      50,
872      test::AcmReceiveTest::kStereoOutput);
873}
874
875TEST_F(AcmSenderBitExactness, DISABLED_ON_ANDROID(Ilbc_30ms)) {
876  ASSERT_NO_FATAL_FAILURE(SetUpTest(acm2::ACMCodecDB::kILBC, 1, 102, 240, 240));
877  Run(AcmReceiverBitExactness::PlatformChecksum(
878          "7b6ec10910debd9af08011d3ed5249f7",
879          "android_audio",
880          "7b6ec10910debd9af08011d3ed5249f7"),
881      AcmReceiverBitExactness::PlatformChecksum(
882          "cfae2e9f6aba96e145f2bcdd5050ce78",
883          "android_payload",
884          "cfae2e9f6aba96e145f2bcdd5050ce78"),
885      33,
886      test::AcmReceiveTest::kMonoOutput);
887}
888
889TEST_F(AcmSenderBitExactness, DISABLED_ON_ANDROID(G722_20ms)) {
890  ASSERT_NO_FATAL_FAILURE(SetUpTest(acm2::ACMCodecDB::kG722, 1, 9, 320, 160));
891  Run(AcmReceiverBitExactness::PlatformChecksum(
892          "7d759436f2533582950d148b5161a36c",
893          "android_audio",
894          "7d759436f2533582950d148b5161a36c"),
895      AcmReceiverBitExactness::PlatformChecksum(
896          "fc68a87e1380614e658087cb35d5ca10",
897          "android_payload",
898          "fc68a87e1380614e658087cb35d5ca10"),
899      50,
900      test::AcmReceiveTest::kMonoOutput);
901}
902
903TEST_F(AcmSenderBitExactness, DISABLED_ON_ANDROID(G722_stereo_20ms)) {
904  ASSERT_NO_FATAL_FAILURE(
905      SetUpTest(acm2::ACMCodecDB::kG722_2ch, 2, 119, 320, 160));
906  Run(AcmReceiverBitExactness::PlatformChecksum(
907          "7190ee718ab3d80eca181e5f7140c210",
908          "android_audio",
909          "7190ee718ab3d80eca181e5f7140c210"),
910      AcmReceiverBitExactness::PlatformChecksum(
911          "66516152eeaa1e650ad94ff85f668dac",
912          "android_payload",
913          "66516152eeaa1e650ad94ff85f668dac"),
914      50,
915      test::AcmReceiveTest::kStereoOutput);
916}
917
918TEST_F(AcmSenderBitExactness, Opus_stereo_20ms) {
919  ASSERT_NO_FATAL_FAILURE(SetUpTest(acm2::ACMCodecDB::kOpus, 2, 120, 960, 960));
920  Run(AcmReceiverBitExactness::PlatformChecksum(
921          "855041f2490b887302bce9d544731849",
922          "1e1a0fce893fef2d66886a7f09e2ebce",
923          "855041f2490b887302bce9d544731849"),
924      AcmReceiverBitExactness::PlatformChecksum(
925          "d781cce1ab986b618d0da87226cdde30",
926          "1a1fe04dd12e755949987c8d729fb3e0",
927          "d781cce1ab986b618d0da87226cdde30"),
928      50,
929      test::AcmReceiveTest::kStereoOutput);
930}
931
932}  // namespace webrtc
933