1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <stdio.h>
6 #include <gtest/gtest.h>
7 
8 extern "C" {
9 #include "cras_apm_list.h"
10 #include "cras_audio_area.h"
11 #include "cras_dsp_pipeline.h"
12 #include "cras_iodev.h"
13 #include "cras_iodev_list.h"
14 #include "cras_types.h"
15 #include "float_buffer.h"
16 #include "webrtc_apm.h"
17 }
18 
19 namespace {
20 
21 static void *stream_ptr = reinterpret_cast<void *>(0x123);
22 static void *dev_ptr = reinterpret_cast<void *>(0x345);
23 static void *dev_ptr2 = reinterpret_cast<void *>(0x678);
24 static struct cras_apm_list *list;
25 static struct cras_audio_area fake_audio_area;
26 static unsigned int dsp_util_interleave_frames;
27 static unsigned int webrtc_apm_process_stream_f_called;
28 static unsigned int webrtc_apm_process_reverse_stream_f_called;
29 static device_enabled_callback_t device_enabled_callback_val;
30 static struct ext_dsp_module *ext_dsp_module_value;
31 static struct cras_iodev fake_iodev;
32 
33 
TEST(ApmList,ApmListCreate)34 TEST(ApmList, ApmListCreate) {
35   list = cras_apm_list_create(stream_ptr, 0);
36   EXPECT_EQ((void *)NULL, list);
37 
38   list = cras_apm_list_create(stream_ptr, APM_ECHO_CANCELLATION);
39   EXPECT_NE((void *)NULL, list);
40   EXPECT_EQ(APM_ECHO_CANCELLATION, cras_apm_list_get_effects(list));
41 
42   cras_apm_list_destroy(list);
43 }
44 
TEST(ApmList,AddRemoveApm)45 TEST(ApmList, AddRemoveApm) {
46   struct cras_audio_format fmt;
47 
48   fmt.num_channels = 2;
49   fmt.frame_rate = 48000;
50   fmt.format = SND_PCM_FORMAT_S16_LE;
51 
52   list = cras_apm_list_create(stream_ptr, APM_ECHO_CANCELLATION);
53   EXPECT_NE((void *)NULL, list);
54 
55   EXPECT_NE((void *)NULL, cras_apm_list_add(list, dev_ptr, &fmt));
56   EXPECT_EQ((void *)NULL, cras_apm_list_get(list, dev_ptr2));
57 
58   EXPECT_NE((void *)NULL, cras_apm_list_add(list, dev_ptr2, &fmt));
59   EXPECT_NE((void *)NULL, cras_apm_list_get(list, dev_ptr));
60 
61   cras_apm_list_remove(list, dev_ptr);
62   EXPECT_EQ((void *)NULL, cras_apm_list_get(list, dev_ptr));
63   EXPECT_NE((void *)NULL, cras_apm_list_get(list, dev_ptr2));
64 
65   cras_apm_list_remove(list, dev_ptr2);
66   EXPECT_EQ((void *)NULL, cras_apm_list_get(list, dev_ptr2));
67 
68   cras_apm_list_destroy(list);
69 }
70 
TEST(ApmList,ApmProcessForwardBuffer)71 TEST(ApmList, ApmProcessForwardBuffer) {
72   struct cras_apm *apm;
73   struct cras_audio_format fmt;
74   struct cras_audio_area *area;
75   struct float_buffer *buf;
76 
77   fmt.num_channels = 2;
78   fmt.frame_rate = 48000;
79   fmt.format = SND_PCM_FORMAT_S16_LE;
80 
81   list = cras_apm_list_create(stream_ptr, APM_ECHO_CANCELLATION);
82   EXPECT_NE((void *)NULL, list);
83 
84   apm = cras_apm_list_add(list, dev_ptr, &fmt);
85 
86   buf = float_buffer_create(500, 2);
87   float_buffer_written(buf, 300);
88   webrtc_apm_process_stream_f_called = 0;
89   cras_apm_list_process(apm, buf, 0);
90   EXPECT_EQ(0, webrtc_apm_process_stream_f_called);
91 
92   area = cras_apm_list_get_processed(apm);
93   EXPECT_EQ(0, area->frames);
94 
95   float_buffer_reset(buf);
96   float_buffer_written(buf, 200);
97   cras_apm_list_process(apm, buf, 0);
98   area = cras_apm_list_get_processed(apm);
99   EXPECT_EQ(1, webrtc_apm_process_stream_f_called);
100   EXPECT_EQ(480, dsp_util_interleave_frames);
101   EXPECT_EQ(480, area->frames);
102 
103   /* Put some processed frames. Another apm_list process will not call
104    * into webrtc_apm because the processed buffer is not yet empty.
105    */
106   cras_apm_list_put_processed(apm, 200);
107   float_buffer_reset(buf);
108   float_buffer_written(buf, 500);
109   cras_apm_list_process(apm, buf, 0);
110   EXPECT_EQ(1, webrtc_apm_process_stream_f_called);
111 
112   /* Put another 280 processed frames, so it's now ready for webrtc_apm
113    * to process another chunk of 480 frames (10ms) data.
114    */
115   cras_apm_list_put_processed(apm, 280);
116   cras_apm_list_process(apm, buf, 0);
117   EXPECT_EQ(2, webrtc_apm_process_stream_f_called);
118 
119   float_buffer_destroy(&buf);
120   cras_apm_list_destroy(list);
121 }
122 
TEST(ApmList,ApmProcessReverseData)123 TEST(ApmList, ApmProcessReverseData) {
124   struct cras_apm *apm;
125   struct cras_audio_format fmt;
126   struct float_buffer *buf;
127   float *const *rp;
128   unsigned int nread;
129   struct cras_iodev fake_iodev;
130 
131   fmt.num_channels = 2;
132   fmt.frame_rate = 48000;
133   fmt.format = SND_PCM_FORMAT_S16_LE;
134 
135   fake_iodev.direction = CRAS_STREAM_OUTPUT;
136   device_enabled_callback_val = NULL;
137   ext_dsp_module_value = NULL;
138   webrtc_apm_process_reverse_stream_f_called = 0;
139 
140   cras_apm_list_init("");
141   EXPECT_NE((void *)NULL, device_enabled_callback_val);
142 
143   device_enabled_callback_val(&fake_iodev, NULL);
144   EXPECT_NE((void *)NULL, ext_dsp_module_value);
145   EXPECT_NE((void *)NULL, ext_dsp_module_value->ports);
146 
147   buf = float_buffer_create(500, 2);
148   float_buffer_written(buf, 500);
149   nread = 500;
150   rp = float_buffer_read_pointer(buf, 0, &nread);
151 
152   for (int i = 0; i < buf->num_channels; i++)
153     ext_dsp_module_value->ports[i] = rp[i];
154 
155   ext_dsp_module_value->configure(ext_dsp_module_value,
156                                   800, 2, 48000);
157   ext_dsp_module_value->run(ext_dsp_module_value, 500);
158   EXPECT_EQ(0, webrtc_apm_process_reverse_stream_f_called);
159 
160   list = cras_apm_list_create(stream_ptr, APM_ECHO_CANCELLATION);
161   EXPECT_NE((void *)NULL, list);
162 
163   apm = cras_apm_list_add(list, dev_ptr, &fmt);
164 
165   ext_dsp_module_value->run(ext_dsp_module_value, 250);
166   EXPECT_EQ(0, webrtc_apm_process_reverse_stream_f_called);
167 
168   ext_dsp_module_value->run(ext_dsp_module_value, 250);
169   EXPECT_EQ(1, webrtc_apm_process_reverse_stream_f_called);
170 
171   float_buffer_destroy(&buf);
172   cras_apm_list_deinit();
173 }
174 
175 extern "C" {
cras_iodev_list_set_device_enabled_callback(device_enabled_callback_t enabled_cb,device_disabled_callback_t disabled_cb,void * cb_data)176 int cras_iodev_list_set_device_enabled_callback(
177 		device_enabled_callback_t enabled_cb,
178 		device_disabled_callback_t disabled_cb,
179 		void *cb_data)
180 {
181   device_enabled_callback_val = enabled_cb;
182   return 0;
183 }
cras_iodev_list_get_first_enabled_iodev(enum CRAS_STREAM_DIRECTION direction)184 struct cras_iodev *cras_iodev_list_get_first_enabled_iodev(
185 	enum CRAS_STREAM_DIRECTION direction)
186 {
187   return &fake_iodev;
188 }
cras_iodev_set_ext_dsp_module(struct cras_iodev * iodev,struct ext_dsp_module * ext)189 void cras_iodev_set_ext_dsp_module(struct cras_iodev *iodev,
190 				   struct ext_dsp_module *ext)
191 {
192   ext_dsp_module_value = ext;
193 }
cras_audio_area_create(int num_channels)194 struct cras_audio_area *cras_audio_area_create(int num_channels)
195 {
196   return &fake_audio_area;
197 }
198 
cras_audio_area_destroy(struct cras_audio_area * area)199 void cras_audio_area_destroy(struct cras_audio_area *area)
200 {
201 }
cras_audio_area_config_channels(struct cras_audio_area * area,const struct cras_audio_format * fmt)202 void cras_audio_area_config_channels(struct cras_audio_area *area,
203 				     const struct cras_audio_format *fmt)
204 {
205 }
cras_audio_area_config_buf_pointers(struct cras_audio_area * area,const struct cras_audio_format * fmt,uint8_t * base_buffer)206 void cras_audio_area_config_buf_pointers(struct cras_audio_area *area,
207 					 const struct cras_audio_format *fmt,
208 					 uint8_t *base_buffer)
209 {
210 }
dsp_util_interleave(float * const * input,int16_t * output,int channels,snd_pcm_format_t format,int frames)211 void dsp_util_interleave(float *const *input, int16_t *output, int channels,
212 			 snd_pcm_format_t format, int frames)
213 {
214   dsp_util_interleave_frames = frames;
215 }
aec_config_get(const char * device_config_dir)216 struct aec_config *aec_config_get(const char *device_config_dir)
217 {
218   return NULL;
219 }
aec_config_dump(struct aec_config * config)220 void aec_config_dump(struct aec_config *config)
221 {
222 }
apm_config_get(const char * device_config_dir)223 struct apm_config *apm_config_get(const char *device_config_dir)
224 {
225   return NULL;
226 }
apm_config_dump(struct apm_config * config)227 void apm_config_dump(struct apm_config *config)
228 {
229 }
webrtc_apm_create(unsigned int num_channels,unsigned int frame_rate,struct aec_config * aec_config,struct apm_config * apm_config)230 webrtc_apm webrtc_apm_create(unsigned int num_channels,
231 			     unsigned int frame_rate,
232 			     struct aec_config *aec_config,
233                              struct apm_config *apm_config)
234 {
235   return reinterpret_cast<webrtc_apm>(0x11);
236 }
webrtc_apm_destroy(webrtc_apm apm)237 void webrtc_apm_destroy(webrtc_apm apm)
238 {
239   return;
240 }
webrtc_apm_process_stream_f(webrtc_apm ptr,int num_channels,int rate,float * const * data)241 int webrtc_apm_process_stream_f(webrtc_apm ptr,
242 				int num_channels,
243 				int rate,
244 				float *const *data)
245 {
246   webrtc_apm_process_stream_f_called++;
247   return 0;
248 }
249 
webrtc_apm_process_reverse_stream_f(webrtc_apm ptr,int num_channels,int rate,float * const * data)250 int webrtc_apm_process_reverse_stream_f(
251 		webrtc_apm ptr,
252 		int num_channels, int rate,
253 		float *const *data)
254 {
255   webrtc_apm_process_reverse_stream_f_called++;
256   return 0;
257 }
webrtc_apm_aec_dump(webrtc_apm ptr,void ** work_queue,int start,FILE * handle)258 int webrtc_apm_aec_dump(webrtc_apm ptr, void** work_queue,
259                         int start, FILE *handle)
260 {
261   return 0;
262 }
263 
264 } // extern "C"
265 } // namespace
266 
267 
main(int argc,char ** argv)268 int main(int argc, char **argv) {
269   ::testing::InitGoogleTest(&argc, argv);
270   return RUN_ALL_TESTS();
271 }
272