1 /* Copyright 2019 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
6 #include <gtest/gtest.h>
7
8 extern "C" {
9 #include "cras_audio_format.h"
10 #include "cras_hfp_alsa_iodev.h"
11 #include "cras_hfp_slc.h"
12 #include "cras_iodev.h"
13 }
14
15 struct hfp_alsa_io {
16 struct cras_iodev base;
17 struct cras_bt_device* device;
18 struct hfp_slc_handle* slc;
19 struct cras_iodev* aio;
20 };
21
22 static struct cras_iodev fake_sco_out, fake_sco_in;
23 static struct cras_bt_device* fake_device;
24 static struct hfp_slc_handle* fake_slc;
25
26 static size_t cras_bt_device_append_iodev_called;
27 static size_t cras_bt_device_rm_iodev_called;
28 static size_t cras_iodev_add_node_called;
29 static size_t cras_iodev_rm_node_called;
30 static size_t cras_iodev_set_active_node_called;
31 static size_t cras_iodev_free_format_called;
32 static size_t cras_iodev_free_resources_called;
33 static size_t cras_iodev_set_format_called;
34 static size_t hfp_set_call_status_called;
35 static size_t hfp_event_speaker_gain_called;
36
37 #define _FAKE_CALL1(name) \
38 static size_t fake_##name##_called; \
39 static int fake_##name(void* a) { \
40 fake_##name##_called++; \
41 return 0; \
42 }
43 #define _FAKE_CALL2(name) \
44 static size_t fake_##name##_called; \
45 static int fake_##name(void* a, void* b) { \
46 fake_##name##_called++; \
47 return 0; \
48 }
49 #define _FAKE_CALL3(name) \
50 static size_t fake_##name##_called; \
51 static int fake_##name(void* a, void* b, void* c) { \
52 fake_##name##_called++; \
53 return 0; \
54 }
55
56 _FAKE_CALL1(open_dev);
57 _FAKE_CALL1(update_supported_formats);
58 _FAKE_CALL1(configure_dev);
59 _FAKE_CALL1(close_dev);
60 _FAKE_CALL2(frames_queued);
61 _FAKE_CALL1(delay_frames);
62 _FAKE_CALL3(get_buffer);
63 _FAKE_CALL2(put_buffer);
64 _FAKE_CALL1(flush_buffer);
65 _FAKE_CALL3(update_active_node);
66 _FAKE_CALL1(start);
67 _FAKE_CALL2(no_stream);
68 _FAKE_CALL1(is_free_running);
69
ResetStubData()70 static void ResetStubData() {
71 cras_bt_device_append_iodev_called = 0;
72 cras_bt_device_rm_iodev_called = 0;
73 cras_iodev_add_node_called = 0;
74 cras_iodev_rm_node_called = 0;
75 cras_iodev_set_active_node_called = 0;
76 cras_iodev_free_format_called = 0;
77 cras_iodev_free_resources_called = 0;
78 cras_iodev_set_format_called = 0;
79 hfp_set_call_status_called = 0;
80 hfp_event_speaker_gain_called = 0;
81
82 fake_sco_out.open_dev = fake_sco_in.open_dev =
83 (int (*)(struct cras_iodev*))fake_open_dev;
84 fake_open_dev_called = 0;
85
86 fake_sco_out.update_supported_formats = fake_sco_in.update_supported_formats =
87 (int (*)(struct cras_iodev*))fake_update_supported_formats;
88 fake_update_supported_formats_called = 0;
89
90 fake_sco_out.configure_dev = fake_sco_in.configure_dev =
91 (int (*)(struct cras_iodev*))fake_configure_dev;
92 fake_configure_dev_called = 0;
93
94 fake_sco_out.close_dev = fake_sco_in.close_dev =
95 (int (*)(struct cras_iodev*))fake_close_dev;
96 fake_close_dev_called = 0;
97
98 fake_sco_out.frames_queued = fake_sco_in.frames_queued =
99 (int (*)(const struct cras_iodev*, struct timespec*))fake_frames_queued;
100 fake_frames_queued_called = 0;
101
102 fake_sco_out.delay_frames = fake_sco_in.delay_frames =
103 (int (*)(const struct cras_iodev*))fake_delay_frames;
104 fake_delay_frames_called = 0;
105
106 fake_sco_out.get_buffer = fake_sco_in.get_buffer = (int (*)(
107 struct cras_iodev*, struct cras_audio_area**, unsigned*))fake_get_buffer;
108 fake_get_buffer_called = 0;
109
110 fake_sco_out.put_buffer = fake_sco_in.put_buffer =
111 (int (*)(struct cras_iodev*, unsigned))fake_put_buffer;
112 fake_put_buffer_called = 0;
113
114 fake_sco_out.flush_buffer = fake_sco_in.flush_buffer =
115 (int (*)(struct cras_iodev*))fake_flush_buffer;
116 fake_flush_buffer_called = 0;
117
118 fake_sco_out.update_active_node = fake_sco_in.update_active_node =
119 (void (*)(struct cras_iodev*, unsigned, unsigned))fake_update_active_node;
120 fake_update_active_node_called = 0;
121
122 fake_sco_out.start = fake_sco_in.start =
123 (int (*)(const struct cras_iodev*))fake_start;
124 fake_start_called = 0;
125
126 fake_sco_out.no_stream = fake_sco_in.no_stream =
127 (int (*)(struct cras_iodev*, int))fake_no_stream;
128 fake_no_stream_called = 0;
129
130 fake_sco_out.is_free_running = fake_sco_in.is_free_running =
131 (int (*)(const struct cras_iodev*))fake_is_free_running;
132 fake_is_free_running_called = 0;
133 }
134
135 namespace {
136
137 class HfpAlsaIodev : public testing::Test {
138 protected:
SetUp()139 virtual void SetUp() { ResetStubData(); }
140
TearDown()141 virtual void TearDown() {}
142 };
143
TEST_F(HfpAlsaIodev,CreateHfpAlsaOutputIodev)144 TEST_F(HfpAlsaIodev, CreateHfpAlsaOutputIodev) {
145 struct cras_iodev* iodev;
146 struct hfp_alsa_io* hfp_alsa_io;
147
148 fake_sco_out.direction = CRAS_STREAM_OUTPUT;
149 iodev = hfp_alsa_iodev_create(&fake_sco_out, fake_device, fake_slc,
150 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
151 hfp_alsa_io = (struct hfp_alsa_io*)iodev;
152
153 EXPECT_EQ(CRAS_STREAM_OUTPUT, iodev->direction);
154 EXPECT_EQ(1, cras_bt_device_append_iodev_called);
155 EXPECT_EQ(1, cras_iodev_add_node_called);
156 EXPECT_EQ(1, cras_iodev_set_active_node_called);
157 EXPECT_EQ(&fake_sco_out, hfp_alsa_io->aio);
158
159 hfp_alsa_iodev_destroy(iodev);
160
161 EXPECT_EQ(1, cras_bt_device_rm_iodev_called);
162 EXPECT_EQ(1, cras_iodev_rm_node_called);
163 EXPECT_EQ(1, cras_iodev_free_resources_called);
164 }
165
TEST_F(HfpAlsaIodev,CreateHfpAlsaInputIodev)166 TEST_F(HfpAlsaIodev, CreateHfpAlsaInputIodev) {
167 struct cras_iodev* iodev;
168 struct hfp_alsa_io* hfp_alsa_io;
169
170 fake_sco_in.direction = CRAS_STREAM_INPUT;
171 iodev = hfp_alsa_iodev_create(&fake_sco_in, fake_device, fake_slc,
172 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
173 hfp_alsa_io = (struct hfp_alsa_io*)iodev;
174
175 EXPECT_EQ(CRAS_STREAM_INPUT, iodev->direction);
176 EXPECT_EQ(1, cras_bt_device_append_iodev_called);
177 EXPECT_EQ(1, cras_iodev_add_node_called);
178 EXPECT_EQ(1, cras_iodev_set_active_node_called);
179 EXPECT_EQ(&fake_sco_in, hfp_alsa_io->aio);
180 /* Input device does not use software gain. */
181 EXPECT_EQ(0, iodev->software_volume_needed);
182
183 hfp_alsa_iodev_destroy(iodev);
184
185 EXPECT_EQ(1, cras_bt_device_rm_iodev_called);
186 EXPECT_EQ(1, cras_iodev_rm_node_called);
187 EXPECT_EQ(1, cras_iodev_free_resources_called);
188 }
189
TEST_F(HfpAlsaIodev,OpenDev)190 TEST_F(HfpAlsaIodev, OpenDev) {
191 struct cras_iodev* iodev;
192
193 fake_sco_out.direction = CRAS_STREAM_OUTPUT;
194 iodev = hfp_alsa_iodev_create(&fake_sco_out, fake_device, fake_slc,
195 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
196 iodev->open_dev(iodev);
197
198 EXPECT_EQ(1, fake_open_dev_called);
199
200 hfp_alsa_iodev_destroy(iodev);
201 }
202
TEST_F(HfpAlsaIodev,UpdateSupportedFormat)203 TEST_F(HfpAlsaIodev, UpdateSupportedFormat) {
204 struct cras_iodev* iodev;
205 size_t supported_rates[] = {8000, 0};
206 size_t supported_channel_counts[] = {1, 0};
207 snd_pcm_format_t supported_formats[] = {SND_PCM_FORMAT_S16_LE,
208 (snd_pcm_format_t)0};
209
210 fake_sco_out.supported_rates = supported_rates;
211 fake_sco_out.supported_channel_counts = supported_channel_counts;
212 fake_sco_out.supported_formats = supported_formats;
213
214 fake_sco_out.direction = CRAS_STREAM_OUTPUT;
215 iodev = hfp_alsa_iodev_create(&fake_sco_out, fake_device, fake_slc,
216 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
217 iodev->update_supported_formats(iodev);
218
219 EXPECT_EQ(1, fake_update_supported_formats_called);
220 for (size_t i = 0; i < 2; ++i) {
221 EXPECT_EQ(supported_rates[i], iodev->supported_rates[i]);
222 EXPECT_EQ(supported_channel_counts[i], iodev->supported_channel_counts[i]);
223 EXPECT_EQ(supported_formats[i], iodev->supported_formats[i]);
224 }
225
226 hfp_alsa_iodev_destroy(iodev);
227 }
228
TEST_F(HfpAlsaIodev,ConfigureDev)229 TEST_F(HfpAlsaIodev, ConfigureDev) {
230 struct cras_iodev* iodev;
231 size_t buf_size = 8192;
232
233 fake_sco_out.direction = CRAS_STREAM_OUTPUT;
234 fake_sco_out.buffer_size = buf_size;
235 iodev = hfp_alsa_iodev_create(&fake_sco_out, fake_device, fake_slc,
236 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
237 iodev->configure_dev(iodev);
238
239 EXPECT_EQ(1, fake_configure_dev_called);
240 EXPECT_EQ(1, hfp_set_call_status_called);
241 EXPECT_EQ(buf_size, iodev->buffer_size);
242
243 hfp_alsa_iodev_destroy(iodev);
244 }
245
TEST_F(HfpAlsaIodev,CloseDev)246 TEST_F(HfpAlsaIodev, CloseDev) {
247 struct cras_iodev* iodev;
248
249 fake_sco_out.direction = CRAS_STREAM_OUTPUT;
250 iodev = hfp_alsa_iodev_create(&fake_sco_out, fake_device, fake_slc,
251 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
252 iodev->close_dev(iodev);
253
254 EXPECT_EQ(1, cras_iodev_free_format_called);
255 EXPECT_EQ(1, fake_close_dev_called);
256
257 hfp_alsa_iodev_destroy(iodev);
258 }
259
TEST_F(HfpAlsaIodev,FramesQueued)260 TEST_F(HfpAlsaIodev, FramesQueued) {
261 struct cras_iodev* iodev;
262
263 fake_sco_out.direction = CRAS_STREAM_OUTPUT;
264 iodev = hfp_alsa_iodev_create(&fake_sco_out, fake_device, fake_slc,
265 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
266 iodev->frames_queued(iodev, (struct timespec*)NULL);
267
268 EXPECT_EQ(1, fake_frames_queued_called);
269
270 hfp_alsa_iodev_destroy(iodev);
271 }
272
TEST_F(HfpAlsaIodev,DelayFrames)273 TEST_F(HfpAlsaIodev, DelayFrames) {
274 struct cras_iodev* iodev;
275
276 fake_sco_out.direction = CRAS_STREAM_OUTPUT;
277 iodev = hfp_alsa_iodev_create(&fake_sco_out, fake_device, fake_slc,
278 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
279 iodev->delay_frames(iodev);
280
281 EXPECT_EQ(1, fake_delay_frames_called);
282
283 hfp_alsa_iodev_destroy(iodev);
284 }
285
TEST_F(HfpAlsaIodev,GetBuffer)286 TEST_F(HfpAlsaIodev, GetBuffer) {
287 struct cras_iodev* iodev;
288
289 fake_sco_out.direction = CRAS_STREAM_OUTPUT;
290 iodev = hfp_alsa_iodev_create(&fake_sco_out, fake_device, fake_slc,
291 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
292 iodev->get_buffer(iodev, (struct cras_audio_area**)NULL, (unsigned*)NULL);
293
294 EXPECT_EQ(1, fake_get_buffer_called);
295
296 hfp_alsa_iodev_destroy(iodev);
297 }
298
TEST_F(HfpAlsaIodev,PutBuffer)299 TEST_F(HfpAlsaIodev, PutBuffer) {
300 struct cras_iodev* iodev;
301
302 fake_sco_out.direction = CRAS_STREAM_OUTPUT;
303 iodev = hfp_alsa_iodev_create(&fake_sco_out, fake_device, fake_slc,
304 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
305 iodev->put_buffer(iodev, 0xdeadbeef);
306
307 EXPECT_EQ(1, fake_put_buffer_called);
308
309 hfp_alsa_iodev_destroy(iodev);
310 }
311
TEST_F(HfpAlsaIodev,FlushBuffer)312 TEST_F(HfpAlsaIodev, FlushBuffer) {
313 struct cras_iodev* iodev;
314
315 fake_sco_out.direction = CRAS_STREAM_OUTPUT;
316 iodev = hfp_alsa_iodev_create(&fake_sco_out, fake_device, fake_slc,
317 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
318 iodev->flush_buffer(iodev);
319
320 EXPECT_EQ(1, fake_flush_buffer_called);
321
322 hfp_alsa_iodev_destroy(iodev);
323 }
324
TEST_F(HfpAlsaIodev,UpdateActiveNode)325 TEST_F(HfpAlsaIodev, UpdateActiveNode) {
326 struct cras_iodev* iodev;
327
328 fake_sco_out.direction = CRAS_STREAM_OUTPUT;
329 iodev = hfp_alsa_iodev_create(&fake_sco_out, fake_device, fake_slc,
330 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
331 iodev->update_active_node(iodev, 0xdeadbeef, 0xdeadbeef);
332
333 EXPECT_EQ(1, fake_update_active_node_called);
334
335 hfp_alsa_iodev_destroy(iodev);
336 }
337
TEST_F(HfpAlsaIodev,Start)338 TEST_F(HfpAlsaIodev, Start) {
339 struct cras_iodev* iodev;
340
341 fake_sco_out.direction = CRAS_STREAM_OUTPUT;
342 iodev = hfp_alsa_iodev_create(&fake_sco_out, fake_device, fake_slc,
343 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
344 iodev->start(iodev);
345
346 EXPECT_EQ(1, fake_start_called);
347
348 hfp_alsa_iodev_destroy(iodev);
349 }
350
TEST_F(HfpAlsaIodev,SetVolume)351 TEST_F(HfpAlsaIodev, SetVolume) {
352 struct cras_iodev* iodev;
353
354 fake_sco_out.direction = CRAS_STREAM_OUTPUT;
355 iodev = hfp_alsa_iodev_create(&fake_sco_out, fake_device, fake_slc,
356 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
357 iodev->set_volume(iodev);
358
359 EXPECT_EQ(1, hfp_event_speaker_gain_called);
360
361 hfp_alsa_iodev_destroy(iodev);
362 }
363
TEST_F(HfpAlsaIodev,NoStream)364 TEST_F(HfpAlsaIodev, NoStream) {
365 struct cras_iodev* iodev;
366
367 fake_sco_out.direction = CRAS_STREAM_OUTPUT;
368 iodev = hfp_alsa_iodev_create(&fake_sco_out, fake_device, fake_slc,
369 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
370 iodev->min_cb_level = 0xab;
371 iodev->max_cb_level = 0xcd;
372
373 iodev->no_stream(iodev, 1);
374
375 EXPECT_EQ(0xab, fake_sco_out.min_cb_level);
376 EXPECT_EQ(0xcd, fake_sco_out.max_cb_level);
377 EXPECT_EQ(1, fake_no_stream_called);
378
379 hfp_alsa_iodev_destroy(iodev);
380 }
381
TEST_F(HfpAlsaIodev,IsFreeRunning)382 TEST_F(HfpAlsaIodev, IsFreeRunning) {
383 struct cras_iodev* iodev;
384
385 fake_sco_out.direction = CRAS_STREAM_OUTPUT;
386 iodev = hfp_alsa_iodev_create(&fake_sco_out, fake_device, fake_slc,
387 CRAS_BT_DEVICE_PROFILE_HFP_AUDIOGATEWAY);
388 iodev->is_free_running(iodev);
389
390 EXPECT_EQ(1, fake_is_free_running_called);
391
392 hfp_alsa_iodev_destroy(iodev);
393 }
394
395 } // namespace
396
397 extern "C" {
398
cras_iodev_set_format(struct cras_iodev * iodev,const struct cras_audio_format * fmt)399 int cras_iodev_set_format(struct cras_iodev* iodev,
400 const struct cras_audio_format* fmt) {
401 cras_iodev_set_format_called++;
402 return 0;
403 }
404
cras_iodev_free_format(struct cras_iodev * iodev)405 void cras_iodev_free_format(struct cras_iodev* iodev) {
406 cras_iodev_free_format_called++;
407 }
408
cras_iodev_add_node(struct cras_iodev * iodev,struct cras_ionode * node)409 void cras_iodev_add_node(struct cras_iodev* iodev, struct cras_ionode* node) {
410 cras_iodev_add_node_called++;
411 iodev->nodes = node;
412 }
413
cras_iodev_rm_node(struct cras_iodev * iodev,struct cras_ionode * node)414 void cras_iodev_rm_node(struct cras_iodev* iodev, struct cras_ionode* node) {
415 cras_iodev_rm_node_called++;
416 iodev->nodes = NULL;
417 }
418
cras_iodev_set_active_node(struct cras_iodev * iodev,struct cras_ionode * node)419 void cras_iodev_set_active_node(struct cras_iodev* iodev,
420 struct cras_ionode* node) {
421 cras_iodev_set_active_node_called++;
422 iodev->active_node = node;
423 }
424
cras_system_get_volume()425 size_t cras_system_get_volume() {
426 return 0;
427 }
428
cras_bt_device_name(const struct cras_bt_device * device)429 const char* cras_bt_device_name(const struct cras_bt_device* device) {
430 return "fake-device-name";
431 }
432
cras_bt_device_address(const struct cras_bt_device * device)433 const char* cras_bt_device_address(const struct cras_bt_device* device) {
434 return "1A:2B:3C:4D:5E:6F";
435 }
436
cras_bt_device_append_iodev(struct cras_bt_device * device,struct cras_iodev * iodev,enum cras_bt_device_profile profile)437 void cras_bt_device_append_iodev(struct cras_bt_device* device,
438 struct cras_iodev* iodev,
439 enum cras_bt_device_profile profile) {
440 cras_bt_device_append_iodev_called++;
441 }
442
cras_bt_device_rm_iodev(struct cras_bt_device * device,struct cras_iodev * iodev)443 void cras_bt_device_rm_iodev(struct cras_bt_device* device,
444 struct cras_iodev* iodev) {
445 cras_bt_device_rm_iodev_called++;
446 }
447
cras_bt_device_object_path(const struct cras_bt_device * device)448 const char* cras_bt_device_object_path(const struct cras_bt_device* device) {
449 return "/fake/object/path";
450 }
451
cras_iodev_free_resources(struct cras_iodev * iodev)452 void cras_iodev_free_resources(struct cras_iodev* iodev) {
453 cras_iodev_free_resources_called++;
454 }
455
hfp_set_call_status(struct hfp_slc_handle * handle,int call)456 int hfp_set_call_status(struct hfp_slc_handle* handle, int call) {
457 hfp_set_call_status_called++;
458 return 0;
459 }
460
hfp_event_speaker_gain(struct hfp_slc_handle * handle,int gain)461 int hfp_event_speaker_gain(struct hfp_slc_handle* handle, int gain) {
462 hfp_event_speaker_gain_called++;
463 return 0;
464 }
465
cras_bt_device_get_sco(struct cras_bt_device * device,int codec)466 int cras_bt_device_get_sco(struct cras_bt_device* device, int codec) {
467 return 0;
468 }
469
cras_bt_device_put_sco(struct cras_bt_device * device)470 void cras_bt_device_put_sco(struct cras_bt_device* device) {}
471
hfp_slc_get_selected_codec(struct hfp_slc_handle * handle)472 int hfp_slc_get_selected_codec(struct hfp_slc_handle* handle) {
473 return HFP_CODEC_ID_CVSD;
474 }
475
476 } // extern "C"
477
main(int argc,char ** argv)478 int main(int argc, char** argv) {
479 ::testing::InitGoogleTest(&argc, argv);
480 return RUN_ALL_TESTS();
481 }
482