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