• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
CreateCodec()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 
EncodeAndVerify(size_t expected_out_length,uint32_t expected_timestamp,int expected_payload_type,int expected_send_even_if_empty)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.)
TEST_F(RentACodecTestF,VerifyCngFrames)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 
TEST(RentACodecTest,ExternalEncoder)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.
TestCngAndRedResetSpeechEncoder(bool use_cng,bool use_red)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 
TEST(RentACodecTest,CngResetsSpeechEncoder)190 TEST(RentACodecTest, CngResetsSpeechEncoder) {
191   TestCngAndRedResetSpeechEncoder(true, false);
192 }
193 
TEST(RentACodecTest,RedResetsSpeechEncoder)194 TEST(RentACodecTest, RedResetsSpeechEncoder) {
195   TestCngAndRedResetSpeechEncoder(false, true);
196 }
197 
TEST(RentACodecTest,CngAndRedResetsSpeechEncoder)198 TEST(RentACodecTest, CngAndRedResetsSpeechEncoder) {
199   TestCngAndRedResetSpeechEncoder(true, true);
200 }
201 
TEST(RentACodecTest,NoCngAndRedNoSpeechEncoderReset)202 TEST(RentACodecTest, NoCngAndRedNoSpeechEncoderReset) {
203   TestCngAndRedResetSpeechEncoder(false, false);
204 }
205 
TEST(RentACodecTest,RentEncoderError)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)
TEST(RentACodecTest,RentEncoderStackWithoutSpeechEncoder)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