Home | History | Annotate | Download | only in acm2
      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/modules/audio_coding/main/interface/audio_coding_module.h"
     17 #include "webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.h"
     18 #include "webrtc/modules/audio_coding/main/acm2/acm_codec_database.h"
     19 #include "webrtc/modules/audio_coding/neteq/tools/rtp_generator.h"
     20 #include "webrtc/system_wrappers/interface/clock.h"
     21 #include "webrtc/system_wrappers/interface/scoped_ptr.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_(kFrameEmpty) {
     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   virtual 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   virtual void TearDown() OVERRIDE {
     76   }
     77 
     78   void InsertOnePacketOfSilence(int codec_id) {
     79     CodecInst codec;
     80     ACMCodecDB::Codec(codec_id, &codec);
     81     if (timestamp_ == 0) {  // This is the first time inserting audio.
     82       ASSERT_TRUE(acm_->RegisterSendCodec(codec_id, codec.pltype));
     83     } else {
     84       const CodecInst* current_codec = acm_->GetSenderCodecInst();
     85       ASSERT_TRUE(current_codec);
     86       if (!CodecsEqual(codec, *current_codec))
     87         ASSERT_TRUE(acm_->RegisterSendCodec(codec_id, codec.pltype));
     88     }
     89     AudioFrame frame;
     90     // Frame setup according to the codec.
     91     frame.sample_rate_hz_ = codec.plfreq;
     92     frame.samples_per_channel_ = codec.plfreq / 100;  // 10 ms.
     93     frame.num_channels_ = codec.channels;
     94     memset(frame.data_, 0, frame.samples_per_channel_ * frame.num_channels_ *
     95            sizeof(int16_t));
     96     int num_bytes = 0;
     97     packet_sent_ = false;
     98     last_packet_send_timestamp_ = timestamp_;
     99     while (num_bytes == 0) {
    100       frame.timestamp_ = timestamp_;
    101       timestamp_ += frame.samples_per_channel_;
    102       num_bytes = acm_->Add10MsAudio(frame);
    103       ASSERT_GE(num_bytes, 0);
    104     }
    105     ASSERT_TRUE(packet_sent_);  // Sanity check.
    106   }
    107 
    108   // Last element of id should be negative.
    109   void AddSetOfCodecs(const int* id) {
    110     int n = 0;
    111     while (id[n] >= 0) {
    112       ASSERT_EQ(0, receiver_->AddCodec(id[n], codecs_[id[n]].pltype,
    113                                        codecs_[id[n]].channels, NULL));
    114       ++n;
    115     }
    116   }
    117 
    118   virtual int SendData(
    119       FrameType frame_type,
    120       uint8_t payload_type,
    121       uint32_t timestamp,
    122       const uint8_t* payload_data,
    123       uint16_t payload_len_bytes,
    124       const RTPFragmentationHeader* fragmentation) OVERRIDE {
    125     if (frame_type == kFrameEmpty)
    126       return 0;
    127 
    128     rtp_header_.header.payloadType = payload_type;
    129     rtp_header_.frameType = frame_type;
    130     if (frame_type == kAudioFrameSpeech)
    131       rtp_header_.type.Audio.isCNG = false;
    132     else
    133       rtp_header_.type.Audio.isCNG = true;
    134     rtp_header_.header.timestamp = timestamp;
    135 
    136     int ret_val = receiver_->InsertPacket(rtp_header_, payload_data,
    137                                           payload_len_bytes);
    138     if (ret_val < 0) {
    139       assert(false);
    140       return -1;
    141     }
    142     rtp_header_.header.sequenceNumber++;
    143     packet_sent_ = true;
    144     last_frame_type_ = frame_type;
    145     return 0;
    146   }
    147 
    148   scoped_ptr<AcmReceiver> receiver_;
    149   CodecInst codecs_[ACMCodecDB::kMaxNumCodecs];
    150   scoped_ptr<AudioCoding> acm_;
    151   WebRtcRTPHeader rtp_header_;
    152   uint32_t timestamp_;
    153   bool packet_sent_;  // Set when SendData is called reset when inserting audio.
    154   uint32_t last_packet_send_timestamp_;
    155   FrameType last_frame_type_;
    156 };
    157 
    158 TEST_F(AcmReceiverTest, DISABLED_ON_ANDROID(AddCodecGetCodec)) {
    159   // Add codec.
    160   for (int n = 0; n < ACMCodecDB::kNumCodecs; ++n) {
    161     if (n & 0x1)  // Just add codecs with odd index.
    162       EXPECT_EQ(0, receiver_->AddCodec(n, codecs_[n].pltype,
    163                                        codecs_[n].channels, 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   CodecInst ref_codec;
    183   const int codec_id = ACMCodecDB::kPCMA;
    184   EXPECT_EQ(0, ACMCodecDB::Codec(codec_id, &ref_codec));
    185   const int payload_type = ref_codec.pltype;
    186   EXPECT_EQ(0, receiver_->AddCodec(codec_id, ref_codec.pltype,
    187                                    ref_codec.channels, NULL));
    188   CodecInst test_codec;
    189   EXPECT_EQ(0, receiver_->DecoderByPayloadType(payload_type, &test_codec));
    190   EXPECT_EQ(true, CodecsEqual(ref_codec, test_codec));
    191 
    192   // Re-register the same codec with different payload.
    193   ref_codec.pltype = payload_type + 1;
    194   EXPECT_EQ(0, receiver_->AddCodec(codec_id, ref_codec.pltype,
    195                                    ref_codec.channels, NULL));
    196 
    197   // Payload type |payload_type| should not exist.
    198   EXPECT_EQ(-1, receiver_->DecoderByPayloadType(payload_type, &test_codec));
    199 
    200   // Payload type |payload_type + 1| should exist.
    201   EXPECT_EQ(0, receiver_->DecoderByPayloadType(payload_type + 1, &test_codec));
    202   EXPECT_TRUE(CodecsEqual(test_codec, ref_codec));
    203 }
    204 
    205 TEST_F(AcmReceiverTest, DISABLED_ON_ANDROID(AddCodecRemoveCodec)) {
    206   CodecInst codec;
    207   const int codec_id = ACMCodecDB::kPCMA;
    208   EXPECT_EQ(0, ACMCodecDB::Codec(codec_id, &codec));
    209   const int payload_type = codec.pltype;
    210   EXPECT_EQ(0, receiver_->AddCodec(codec_id, codec.pltype,
    211                                    codec.channels, NULL));
    212 
    213   // Remove non-existing codec should not fail. ACM1 legacy.
    214   EXPECT_EQ(0, receiver_->RemoveCodec(payload_type + 1));
    215 
    216   // Remove an existing codec.
    217   EXPECT_EQ(0, receiver_->RemoveCodec(payload_type));
    218 
    219   // Ask for the removed codec, must fail.
    220   EXPECT_EQ(-1, receiver_->DecoderByPayloadType(payload_type, &codec));
    221 }
    222 
    223 TEST_F(AcmReceiverTest, DISABLED_ON_ANDROID(SampleRate)) {
    224   const int kCodecId[] = {
    225       ACMCodecDB::kISAC, ACMCodecDB::kISACSWB, ACMCodecDB::kISACFB,
    226       -1  // Terminator.
    227   };
    228   AddSetOfCodecs(kCodecId);
    229 
    230   AudioFrame frame;
    231   const int kOutSampleRateHz = 8000;  // Different than codec sample rate.
    232   int n = 0;
    233   while (kCodecId[n] >= 0) {
    234     const int num_10ms_frames = codecs_[kCodecId[n]].pacsize /
    235         (codecs_[kCodecId[n]].plfreq / 100);
    236     InsertOnePacketOfSilence(kCodecId[n]);
    237     for (int k = 0; k < num_10ms_frames; ++k) {
    238       EXPECT_EQ(0, receiver_->GetAudio(kOutSampleRateHz, &frame));
    239     }
    240     EXPECT_EQ(std::min(32000, codecs_[kCodecId[n]].plfreq),
    241               receiver_->current_sample_rate_hz());
    242     ++n;
    243   }
    244 }
    245 
    246 // Verify that the playout mode is set correctly.
    247 TEST_F(AcmReceiverTest, DISABLED_ON_ANDROID(PlayoutMode)) {
    248   receiver_->SetPlayoutMode(voice);
    249   EXPECT_EQ(voice, receiver_->PlayoutMode());
    250 
    251   receiver_->SetPlayoutMode(streaming);
    252   EXPECT_EQ(streaming, receiver_->PlayoutMode());
    253 
    254   receiver_->SetPlayoutMode(fax);
    255   EXPECT_EQ(fax, receiver_->PlayoutMode());
    256 
    257   receiver_->SetPlayoutMode(off);
    258   EXPECT_EQ(off, receiver_->PlayoutMode());
    259 }
    260 
    261 TEST_F(AcmReceiverTest, DISABLED_ON_ANDROID(PostdecodingVad)) {
    262   receiver_->EnableVad();
    263   EXPECT_TRUE(receiver_->vad_enabled());
    264 
    265   const int id = ACMCodecDB::kPCM16Bwb;
    266   ASSERT_EQ(0, receiver_->AddCodec(id, codecs_[id].pltype, codecs_[id].channels,
    267                                    NULL));
    268   const int kNumPackets = 5;
    269   const int num_10ms_frames = codecs_[id].pacsize / (codecs_[id].plfreq / 100);
    270   AudioFrame frame;
    271   for (int n = 0; n < kNumPackets; ++n) {
    272     InsertOnePacketOfSilence(id);
    273     for (int k = 0; k < num_10ms_frames; ++k)
    274       ASSERT_EQ(0, receiver_->GetAudio(codecs_[id].plfreq, &frame));
    275   }
    276   EXPECT_EQ(AudioFrame::kVadPassive, frame.vad_activity_);
    277 
    278   receiver_->DisableVad();
    279   EXPECT_FALSE(receiver_->vad_enabled());
    280 
    281   for (int n = 0; n < kNumPackets; ++n) {
    282     InsertOnePacketOfSilence(id);
    283     for (int k = 0; k < num_10ms_frames; ++k)
    284       ASSERT_EQ(0, receiver_->GetAudio(codecs_[id].plfreq, &frame));
    285   }
    286   EXPECT_EQ(AudioFrame::kVadUnknown, frame.vad_activity_);
    287 }
    288 
    289 TEST_F(AcmReceiverTest, DISABLED_ON_ANDROID(LastAudioCodec)) {
    290   const int kCodecId[] = {
    291       ACMCodecDB::kISAC, ACMCodecDB::kPCMA, ACMCodecDB::kISACSWB,
    292       ACMCodecDB::kPCM16Bswb32kHz, ACMCodecDB::kG722_1C_48,
    293       -1  // Terminator.
    294   };
    295   AddSetOfCodecs(kCodecId);
    296 
    297   const int kCngId[] = {  // Not including full-band.
    298       ACMCodecDB::kCNNB, ACMCodecDB::kCNWB, ACMCodecDB::kCNSWB,
    299       -1  // Terminator.
    300   };
    301   AddSetOfCodecs(kCngId);
    302 
    303   // Register CNG at sender side.
    304   int n = 0;
    305   while (kCngId[n] > 0) {
    306     ASSERT_TRUE(acm_->RegisterSendCodec(kCngId[n], codecs_[kCngId[n]].pltype));
    307     ++n;
    308   }
    309 
    310   CodecInst codec;
    311   // No audio payload is received.
    312   EXPECT_EQ(-1, receiver_->LastAudioCodec(&codec));
    313 
    314   // Start with sending DTX.
    315   ASSERT_TRUE(acm_->SetVad(true, true, VADVeryAggr));
    316   packet_sent_ = false;
    317   InsertOnePacketOfSilence(kCodecId[0]);  // Enough to test with one codec.
    318   ASSERT_TRUE(packet_sent_);
    319   EXPECT_EQ(kAudioFrameCN, last_frame_type_);
    320 
    321   // Has received, only, DTX. Last Audio codec is undefined.
    322   EXPECT_EQ(-1, receiver_->LastAudioCodec(&codec));
    323   EXPECT_EQ(-1, receiver_->last_audio_codec_id());
    324   EXPECT_EQ(-1, receiver_->last_audio_payload_type());
    325 
    326   n = 0;
    327   while (kCodecId[n] >= 0) {  // Loop over codecs.
    328     // Set DTX off to send audio payload.
    329     acm_->SetVad(false, false, VADAggr);
    330     packet_sent_ = false;
    331     InsertOnePacketOfSilence(kCodecId[n]);
    332 
    333     // Sanity check if Actually an audio payload received, and it should be
    334     // of type "speech."
    335     ASSERT_TRUE(packet_sent_);
    336     ASSERT_EQ(kAudioFrameSpeech, last_frame_type_);
    337     EXPECT_EQ(kCodecId[n], receiver_->last_audio_codec_id());
    338 
    339     // Set VAD on to send DTX. Then check if the "Last Audio codec" returns
    340     // the expected codec.
    341     acm_->SetVad(true, true, VADAggr);
    342 
    343     // Do as many encoding until a DTX is sent.
    344     while (last_frame_type_ != kAudioFrameCN) {
    345       packet_sent_ = false;
    346       InsertOnePacketOfSilence(kCodecId[n]);
    347       ASSERT_TRUE(packet_sent_);
    348     }
    349     EXPECT_EQ(kCodecId[n], receiver_->last_audio_codec_id());
    350     EXPECT_EQ(codecs_[kCodecId[n]].pltype,
    351               receiver_->last_audio_payload_type());
    352     EXPECT_EQ(0, receiver_->LastAudioCodec(&codec));
    353     EXPECT_TRUE(CodecsEqual(codecs_[kCodecId[n]], codec));
    354     ++n;
    355   }
    356 }
    357 
    358 }  // namespace acm2
    359 
    360 }  // namespace webrtc
    361