Home | History | Annotate | Download | only in acm2
      1 /*
      2  *  Copyright (c) 2015 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/base/arraysize.h"
     13 #include "webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h"
     14 #include "webrtc/modules/audio_coding/acm2/rent_a_codec.h"
     15 
     16 namespace webrtc {
     17 namespace acm2 {
     18 
     19 using ::testing::Return;
     20 
     21 namespace {
     22 const int kDataLengthSamples = 80;
     23 const int kPacketSizeSamples = 2 * kDataLengthSamples;
     24 const int16_t kZeroData[kDataLengthSamples] = {0};
     25 const CodecInst kDefaultCodecInst = {0, "pcmu", 8000, kPacketSizeSamples,
     26                                      1, 64000};
     27 const int kCngPt = 13;
     28 }  // namespace
     29 
     30 class RentACodecTestF : public ::testing::Test {
     31  protected:
     32   void CreateCodec() {
     33     speech_encoder_ = rent_a_codec_.RentEncoder(kDefaultCodecInst);
     34     ASSERT_TRUE(speech_encoder_);
     35     RentACodec::StackParameters param;
     36     param.use_cng = true;
     37     param.speech_encoder = speech_encoder_;
     38     encoder_ = rent_a_codec_.RentEncoderStack(&param);
     39   }
     40 
     41   void EncodeAndVerify(size_t expected_out_length,
     42                        uint32_t expected_timestamp,
     43                        int expected_payload_type,
     44                        int expected_send_even_if_empty) {
     45     uint8_t out[kPacketSizeSamples];
     46     AudioEncoder::EncodedInfo encoded_info;
     47     encoded_info =
     48         encoder_->Encode(timestamp_, kZeroData, kPacketSizeSamples, out);
     49     timestamp_ += kDataLengthSamples;
     50     EXPECT_TRUE(encoded_info.redundant.empty());
     51     EXPECT_EQ(expected_out_length, encoded_info.encoded_bytes);
     52     EXPECT_EQ(expected_timestamp, encoded_info.encoded_timestamp);
     53     if (expected_payload_type >= 0)
     54       EXPECT_EQ(expected_payload_type, encoded_info.payload_type);
     55     if (expected_send_even_if_empty >= 0)
     56       EXPECT_EQ(static_cast<bool>(expected_send_even_if_empty),
     57                 encoded_info.send_even_if_empty);
     58   }
     59 
     60   RentACodec rent_a_codec_;
     61   AudioEncoder* speech_encoder_ = nullptr;
     62   AudioEncoder* encoder_ = nullptr;
     63   uint32_t timestamp_ = 0;
     64 };
     65 
     66 // This test verifies that CNG frames are delivered as expected. Since the frame
     67 // size is set to 20 ms, we expect the first encode call to produce no output
     68 // (which is signaled as 0 bytes output of type kNoEncoding). The next encode
     69 // call should produce one SID frame of 9 bytes. The third call should not
     70 // result in any output (just like the first one). The fourth and final encode
     71 // call should produce an "empty frame", which is like no output, but with
     72 // AudioEncoder::EncodedInfo::send_even_if_empty set to true. (The reason to
     73 // produce an empty frame is to drive sending of DTMF packets in the RTP/RTCP
     74 // module.)
     75 TEST_F(RentACodecTestF, VerifyCngFrames) {
     76   CreateCodec();
     77   uint32_t expected_timestamp = timestamp_;
     78   // Verify no frame.
     79   {
     80     SCOPED_TRACE("First encoding");
     81     EncodeAndVerify(0, expected_timestamp, -1, -1);
     82   }
     83 
     84   // Verify SID frame delivered.
     85   {
     86     SCOPED_TRACE("Second encoding");
     87     EncodeAndVerify(9, expected_timestamp, kCngPt, 1);
     88   }
     89 
     90   // Verify no frame.
     91   {
     92     SCOPED_TRACE("Third encoding");
     93     EncodeAndVerify(0, expected_timestamp, -1, -1);
     94   }
     95 
     96   // Verify NoEncoding.
     97   expected_timestamp += 2 * kDataLengthSamples;
     98   {
     99     SCOPED_TRACE("Fourth encoding");
    100     EncodeAndVerify(0, expected_timestamp, kCngPt, 1);
    101   }
    102 }
    103 
    104 TEST(RentACodecTest, ExternalEncoder) {
    105   const int kSampleRateHz = 8000;
    106   MockAudioEncoder external_encoder;
    107   EXPECT_CALL(external_encoder, SampleRateHz())
    108       .WillRepeatedly(Return(kSampleRateHz));
    109   EXPECT_CALL(external_encoder, NumChannels()).WillRepeatedly(Return(1));
    110   EXPECT_CALL(external_encoder, SetFec(false)).WillRepeatedly(Return(true));
    111 
    112   RentACodec rac;
    113   RentACodec::StackParameters param;
    114   param.speech_encoder = &external_encoder;
    115   EXPECT_EQ(&external_encoder, rac.RentEncoderStack(&param));
    116   const int kPacketSizeSamples = kSampleRateHz / 100;
    117   int16_t audio[kPacketSizeSamples] = {0};
    118   uint8_t encoded[kPacketSizeSamples];
    119   AudioEncoder::EncodedInfo info;
    120 
    121   {
    122     ::testing::InSequence s;
    123     info.encoded_timestamp = 0;
    124     EXPECT_CALL(external_encoder,
    125                 EncodeInternal(0, rtc::ArrayView<const int16_t>(audio),
    126                                arraysize(encoded), encoded))
    127         .WillOnce(Return(info));
    128     EXPECT_CALL(external_encoder, Mark("A"));
    129     EXPECT_CALL(external_encoder, Mark("B"));
    130     info.encoded_timestamp = 2;
    131     EXPECT_CALL(external_encoder,
    132                 EncodeInternal(2, rtc::ArrayView<const int16_t>(audio),
    133                                arraysize(encoded), encoded))
    134         .WillOnce(Return(info));
    135     EXPECT_CALL(external_encoder, Die());
    136   }
    137 
    138   info = rac.GetEncoderStack()->Encode(0, audio, arraysize(encoded), encoded);
    139   EXPECT_EQ(0u, info.encoded_timestamp);
    140   external_encoder.Mark("A");
    141 
    142   // Change to internal encoder.
    143   CodecInst codec_inst = kDefaultCodecInst;
    144   codec_inst.pacsize = kPacketSizeSamples;
    145   param.speech_encoder = rac.RentEncoder(codec_inst);
    146   ASSERT_TRUE(param.speech_encoder);
    147   EXPECT_EQ(param.speech_encoder, rac.RentEncoderStack(&param));
    148 
    149   // Don't expect any more calls to the external encoder.
    150   info = rac.GetEncoderStack()->Encode(1, audio, arraysize(encoded), encoded);
    151   external_encoder.Mark("B");
    152 
    153   // Change back to external encoder again.
    154   param.speech_encoder = &external_encoder;
    155   EXPECT_EQ(&external_encoder, rac.RentEncoderStack(&param));
    156   info = rac.GetEncoderStack()->Encode(2, audio, arraysize(encoded), encoded);
    157   EXPECT_EQ(2u, info.encoded_timestamp);
    158 }
    159 
    160 // Verify that the speech encoder's Reset method is called when CNG or RED
    161 // (or both) are switched on, but not when they're switched off.
    162 void TestCngAndRedResetSpeechEncoder(bool use_cng, bool use_red) {
    163   MockAudioEncoder speech_encoder;
    164   EXPECT_CALL(speech_encoder, NumChannels()).WillRepeatedly(Return(1));
    165   EXPECT_CALL(speech_encoder, Max10MsFramesInAPacket())
    166       .WillRepeatedly(Return(2));
    167   EXPECT_CALL(speech_encoder, SampleRateHz()).WillRepeatedly(Return(8000));
    168   EXPECT_CALL(speech_encoder, SetFec(false)).WillRepeatedly(Return(true));
    169   {
    170     ::testing::InSequence s;
    171     EXPECT_CALL(speech_encoder, Mark("disabled"));
    172     EXPECT_CALL(speech_encoder, Mark("enabled"));
    173     if (use_cng || use_red)
    174       EXPECT_CALL(speech_encoder, Reset());
    175     EXPECT_CALL(speech_encoder, Die());
    176   }
    177 
    178   RentACodec::StackParameters param1, param2;
    179   param1.speech_encoder = &speech_encoder;
    180   param2.speech_encoder = &speech_encoder;
    181   param2.use_cng = use_cng;
    182   param2.use_red = use_red;
    183   speech_encoder.Mark("disabled");
    184   RentACodec rac;
    185   rac.RentEncoderStack(&param1);
    186   speech_encoder.Mark("enabled");
    187   rac.RentEncoderStack(&param2);
    188 }
    189 
    190 TEST(RentACodecTest, CngResetsSpeechEncoder) {
    191   TestCngAndRedResetSpeechEncoder(true, false);
    192 }
    193 
    194 TEST(RentACodecTest, RedResetsSpeechEncoder) {
    195   TestCngAndRedResetSpeechEncoder(false, true);
    196 }
    197 
    198 TEST(RentACodecTest, CngAndRedResetsSpeechEncoder) {
    199   TestCngAndRedResetSpeechEncoder(true, true);
    200 }
    201 
    202 TEST(RentACodecTest, NoCngAndRedNoSpeechEncoderReset) {
    203   TestCngAndRedResetSpeechEncoder(false, false);
    204 }
    205 
    206 TEST(RentACodecTest, RentEncoderError) {
    207   const CodecInst codec_inst = {
    208       0, "Robert'); DROP TABLE Students;", 8000, 160, 1, 64000};
    209   RentACodec rent_a_codec;
    210   EXPECT_FALSE(rent_a_codec.RentEncoder(codec_inst));
    211 }
    212 
    213 #if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
    214 TEST(RentACodecTest, RentEncoderStackWithoutSpeechEncoder) {
    215   RentACodec::StackParameters sp;
    216   EXPECT_EQ(nullptr, sp.speech_encoder);
    217   EXPECT_DEATH(RentACodec().RentEncoderStack(&sp), "");
    218 }
    219 #endif
    220 
    221 }  // namespace acm2
    222 }  // namespace webrtc
    223