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