1 /* Copyright 2013 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 #include <stdint.h>
8 #include <time.h>
9
10 extern "C" {
11 #include "cras_hfp_info.c"
12 #include "sbc_codec_stub.h"
13 }
14 static struct hfp_info* info;
15 static struct cras_iodev dev;
16 static cras_audio_format format;
17
18 static int cras_msbc_plc_create_called;
19 static int cras_msbc_plc_handle_good_frames_called;
20 static int cras_msbc_plc_handle_bad_frames_called;
21
22 static thread_callback thread_cb;
23 static void* cb_data;
24 static timespec ts;
25
ResetStubData()26 void ResetStubData() {
27 sbc_codec_stub_reset();
28 cras_msbc_plc_create_called = 0;
29
30 format.format = SND_PCM_FORMAT_S16_LE;
31 format.num_channels = 1;
32 format.frame_rate = 8000;
33 dev.format = &format;
34 }
35
36 namespace {
37
TEST(HfpInfo,AddRmDev)38 TEST(HfpInfo, AddRmDev) {
39 ResetStubData();
40
41 info = hfp_info_create(HFP_CODEC_ID_CVSD);
42 ASSERT_NE(info, (void*)NULL);
43 dev.direction = CRAS_STREAM_OUTPUT;
44
45 /* Test add dev */
46 ASSERT_EQ(0, hfp_info_add_iodev(info, dev.direction, dev.format));
47 ASSERT_TRUE(hfp_info_has_iodev(info));
48
49 /* Test remove dev */
50 ASSERT_EQ(0, hfp_info_rm_iodev(info, dev.direction));
51 ASSERT_FALSE(hfp_info_has_iodev(info));
52
53 hfp_info_destroy(info);
54 }
55
TEST(HfpInfo,AddRmDevInvalid)56 TEST(HfpInfo, AddRmDevInvalid) {
57 ResetStubData();
58
59 info = hfp_info_create(HFP_CODEC_ID_CVSD);
60 ASSERT_NE(info, (void*)NULL);
61
62 dev.direction = CRAS_STREAM_OUTPUT;
63
64 /* Remove an iodev which doesn't exist */
65 ASSERT_NE(0, hfp_info_rm_iodev(info, dev.direction));
66
67 /* Adding an iodev twice returns error code */
68 ASSERT_EQ(0, hfp_info_add_iodev(info, dev.direction, dev.format));
69 ASSERT_NE(0, hfp_info_add_iodev(info, dev.direction, dev.format));
70
71 hfp_info_destroy(info);
72 }
73
TEST(HfpInfo,AcquirePlaybackBuffer)74 TEST(HfpInfo, AcquirePlaybackBuffer) {
75 unsigned buffer_frames, buffer_frames2, queued;
76 uint8_t* samples;
77
78 ResetStubData();
79
80 info = hfp_info_create(HFP_CODEC_ID_CVSD);
81 ASSERT_NE(info, (void*)NULL);
82
83 hfp_info_start(1, 48, info);
84 dev.direction = CRAS_STREAM_OUTPUT;
85 ASSERT_EQ(0, hfp_info_add_iodev(info, dev.direction, dev.format));
86
87 buffer_frames = 500;
88 hfp_buf_acquire(info, dev.direction, &samples, &buffer_frames);
89 ASSERT_EQ(500, buffer_frames);
90
91 hfp_buf_release(info, dev.direction, 500);
92 ASSERT_EQ(500, hfp_buf_queued(info, dev.direction));
93
94 /* Assert the amount of frames of available buffer + queued buf is
95 * greater than or equal to the buffer size, 2 bytes per frame
96 */
97 queued = hfp_buf_queued(info, dev.direction);
98 buffer_frames = 500;
99 hfp_buf_acquire(info, dev.direction, &samples, &buffer_frames);
100 ASSERT_GE(info->playback_buf->used_size / 2, buffer_frames + queued);
101
102 /* Consume all queued data from read buffer */
103 buf_increment_read(info->playback_buf, queued * 2);
104
105 queued = hfp_buf_queued(info, dev.direction);
106 ASSERT_EQ(0, queued);
107
108 /* Assert consecutive acquire buffer will acquire full used size of buffer */
109 buffer_frames = 500;
110 hfp_buf_acquire(info, dev.direction, &samples, &buffer_frames);
111 hfp_buf_release(info, dev.direction, buffer_frames);
112
113 buffer_frames2 = 500;
114 hfp_buf_acquire(info, dev.direction, &samples, &buffer_frames2);
115 hfp_buf_release(info, dev.direction, buffer_frames2);
116
117 ASSERT_GE(info->playback_buf->used_size / 2, buffer_frames + buffer_frames2);
118
119 hfp_info_destroy(info);
120 }
121
TEST(HfpInfo,AcquireCaptureBuffer)122 TEST(HfpInfo, AcquireCaptureBuffer) {
123 unsigned buffer_frames, buffer_frames2;
124 uint8_t* samples;
125
126 ResetStubData();
127
128 info = hfp_info_create(HFP_CODEC_ID_CVSD);
129 ASSERT_NE(info, (void*)NULL);
130
131 hfp_info_start(1, 48, info);
132 dev.direction = CRAS_STREAM_INPUT;
133 ASSERT_EQ(0, hfp_info_add_iodev(info, dev.direction, dev.format));
134
135 /* Put fake data 100 bytes(50 frames) in capture buf for test */
136 buf_increment_write(info->capture_buf, 100);
137
138 /* Assert successfully acquire and release 100 bytes of data */
139 buffer_frames = 50;
140 hfp_buf_acquire(info, dev.direction, &samples, &buffer_frames);
141 ASSERT_EQ(50, buffer_frames);
142
143 hfp_buf_release(info, dev.direction, buffer_frames);
144 ASSERT_EQ(0, hfp_buf_queued(info, dev.direction));
145
146 /* Push fake data to capture buffer */
147 buf_increment_write(info->capture_buf, info->capture_buf->used_size - 100);
148 buf_increment_write(info->capture_buf, 100);
149
150 /* Assert consecutive acquire call will consume the whole buffer */
151 buffer_frames = 1000;
152 hfp_buf_acquire(info, dev.direction, &samples, &buffer_frames);
153 hfp_buf_release(info, dev.direction, buffer_frames);
154 ASSERT_GE(1000, buffer_frames);
155
156 buffer_frames2 = 1000;
157 hfp_buf_acquire(info, dev.direction, &samples, &buffer_frames2);
158 hfp_buf_release(info, dev.direction, buffer_frames2);
159
160 ASSERT_GE(info->capture_buf->used_size / 2, buffer_frames + buffer_frames2);
161
162 hfp_info_destroy(info);
163 }
164
TEST(HfpInfo,HfpReadWriteFD)165 TEST(HfpInfo, HfpReadWriteFD) {
166 int rc;
167 int sock[2];
168 uint8_t sample[480];
169 uint8_t* buf;
170 unsigned buffer_count;
171
172 ResetStubData();
173
174 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sock));
175
176 info = hfp_info_create(HFP_CODEC_ID_CVSD);
177 ASSERT_NE(info, (void*)NULL);
178
179 dev.direction = CRAS_STREAM_INPUT;
180 hfp_info_start(sock[1], 48, info);
181 ASSERT_EQ(0, hfp_info_add_iodev(info, dev.direction, dev.format));
182
183 /* Mock the sco fd and send some fake data */
184 send(sock[0], sample, 48, 0);
185
186 rc = hfp_read(info);
187 ASSERT_EQ(48, rc);
188
189 rc = hfp_buf_queued(info, dev.direction);
190 ASSERT_EQ(48 / 2, rc);
191
192 /* Fill the write buffer*/
193 buffer_count = info->capture_buf->used_size;
194 buf = buf_write_pointer_size(info->capture_buf, &buffer_count);
195 buf_increment_write(info->capture_buf, buffer_count);
196 ASSERT_NE((void*)NULL, buf);
197
198 rc = hfp_read(info);
199 ASSERT_EQ(0, rc);
200
201 ASSERT_EQ(0, hfp_info_rm_iodev(info, dev.direction));
202 dev.direction = CRAS_STREAM_OUTPUT;
203 ASSERT_EQ(0, hfp_info_add_iodev(info, dev.direction, dev.format));
204
205 /* Initial buffer is empty */
206 rc = hfp_write(info);
207 ASSERT_EQ(0, rc);
208
209 buffer_count = 1024;
210 buf = buf_write_pointer_size(info->playback_buf, &buffer_count);
211 buf_increment_write(info->playback_buf, buffer_count);
212
213 rc = hfp_write(info);
214 ASSERT_EQ(48, rc);
215
216 rc = recv(sock[0], sample, 48, 0);
217 ASSERT_EQ(48, rc);
218
219 hfp_info_destroy(info);
220 }
221
TEST(HfpInfo,StartHfpInfo)222 TEST(HfpInfo, StartHfpInfo) {
223 int sock[2];
224
225 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sock));
226
227 info = hfp_info_create(HFP_CODEC_ID_CVSD);
228 ASSERT_NE(info, (void*)NULL);
229
230 hfp_info_start(sock[0], 48, info);
231 ASSERT_EQ(1, hfp_info_running(info));
232 ASSERT_EQ(cb_data, (void*)info);
233
234 hfp_info_stop(info);
235 ASSERT_EQ(0, hfp_info_running(info));
236 ASSERT_EQ(NULL, cb_data);
237
238 hfp_info_destroy(info);
239 }
240
TEST(HfpInfo,StartHfpInfoAndRead)241 TEST(HfpInfo, StartHfpInfoAndRead) {
242 int rc;
243 int sock[2];
244 uint8_t sample[480];
245
246 ResetStubData();
247
248 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sock));
249
250 info = hfp_info_create(HFP_CODEC_ID_CVSD);
251 ASSERT_NE(info, (void*)NULL);
252
253 /* Start and send two chunk of fake data */
254 hfp_info_start(sock[1], 48, info);
255 send(sock[0], sample, 48, 0);
256 send(sock[0], sample, 48, 0);
257
258 /* Trigger thread callback */
259 thread_cb((struct hfp_info*)cb_data);
260
261 dev.direction = CRAS_STREAM_INPUT;
262 ASSERT_EQ(0, hfp_info_add_iodev(info, dev.direction, dev.format));
263
264 /* Expect no data read, since no idev present at previous thread callback */
265 rc = hfp_buf_queued(info, dev.direction);
266 ASSERT_EQ(0, rc);
267
268 /* Trigger thread callback after idev added. */
269 ts.tv_sec = 0;
270 ts.tv_nsec = 5000000;
271 thread_cb((struct hfp_info*)cb_data);
272
273 rc = hfp_buf_queued(info, dev.direction);
274 ASSERT_EQ(48 / 2, rc);
275
276 /* Assert wait time is unchanged. */
277 ASSERT_EQ(0, ts.tv_sec);
278 ASSERT_EQ(5000000, ts.tv_nsec);
279
280 hfp_info_stop(info);
281 ASSERT_EQ(0, hfp_info_running(info));
282
283 hfp_info_destroy(info);
284 }
285
TEST(HfpInfo,StartHfpInfoAndWrite)286 TEST(HfpInfo, StartHfpInfoAndWrite) {
287 int rc;
288 int sock[2];
289 uint8_t sample[480];
290
291 ResetStubData();
292
293 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sock));
294
295 info = hfp_info_create(HFP_CODEC_ID_CVSD);
296 ASSERT_NE(info, (void*)NULL);
297
298 hfp_info_start(sock[1], 48, info);
299 send(sock[0], sample, 48, 0);
300 send(sock[0], sample, 48, 0);
301
302 /* Trigger thread callback */
303 thread_cb((struct hfp_info*)cb_data);
304
305 /* Without odev in presence, zero packet should be sent. */
306 rc = recv(sock[0], sample, 48, 0);
307 ASSERT_EQ(48, rc);
308
309 dev.direction = CRAS_STREAM_OUTPUT;
310 ASSERT_EQ(0, hfp_info_add_iodev(info, dev.direction, dev.format));
311
312 /* Assert queued samples unchanged before output device added */
313 ASSERT_EQ(0, hfp_buf_queued(info, dev.direction));
314
315 /* Put some fake data and trigger thread callback again */
316 buf_increment_write(info->playback_buf, 1008);
317 thread_cb((struct hfp_info*)cb_data);
318
319 /* Assert some samples written */
320 rc = recv(sock[0], sample, 48, 0);
321 ASSERT_EQ(48, rc);
322 ASSERT_EQ(480, hfp_buf_queued(info, dev.direction));
323
324 hfp_info_stop(info);
325 hfp_info_destroy(info);
326 }
327
send_mSBC_packet(int fd,unsigned seq,int broken_pkt)328 void send_mSBC_packet(int fd, unsigned seq, int broken_pkt) {
329 /* These three bytes are h2 header, frame count and mSBC sync word.
330 * The second octet of H2 header is composed by 4 bits fixed 0x8 and 4 bits
331 * sequence number 0000, 0011, 1100, 1111.
332 */
333 uint8_t headers[4][3] = {{0x01, 0x08, 0xAD},
334 {0x01, 0x38, 0xAD},
335 {0x01, 0xc8, 0xAD},
336 {0x01, 0xf8, 0xAD}};
337 /* These three bytes are HCI SCO Data packet header, we only care the
338 * Packet_Status_Flag bits, which are the bit 4 to 5 in the second octet.
339 */
340 uint8_t sco_header[] = {0x01, 0x01, 0x3c};
341 uint8_t zero_frame[] = {
342 0xad, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, 0x00, 0x77, 0x6d, 0xb6, 0xdd,
343 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d, 0xb6,
344 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77, 0x6d,
345 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6d, 0xdd, 0xb6, 0xdb, 0x77,
346 0x6d, 0xb6, 0xdd, 0xdb, 0x6d, 0xb7, 0x76, 0xdb, 0x6c};
347 if (broken_pkt)
348 sco_header[1] = 0x11;
349
350 send(fd, sco_header, 3, 0);
351 send(fd, headers[seq % 4], 3, 0);
352 send(fd, zero_frame, 57, 0);
353 }
354
TEST(HfpInfo,StartHfpInfoAndReadMsbc)355 TEST(HfpInfo, StartHfpInfoAndReadMsbc) {
356 int sock[2];
357 int pkt_count = 0;
358 int rc;
359 uint8_t sample[480];
360 ResetStubData();
361
362 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sock));
363
364 set_sbc_codec_decoded_out(MSBC_CODE_SIZE);
365
366 info = hfp_info_create(HFP_CODEC_ID_MSBC);
367 ASSERT_NE(info, (void*)NULL);
368 ASSERT_EQ(2, get_msbc_codec_create_called());
369 ASSERT_EQ(1, cras_msbc_plc_create_called);
370
371 /* Start and send an mSBC packets with all zero samples */
372 hfp_info_start(sock[1], 63, info);
373 send_mSBC_packet(sock[0], pkt_count++, 0);
374
375 /* Trigger thread callback */
376 thread_cb((struct hfp_info*)cb_data);
377
378 /* Expect one empty mSBC packet is send, because no odev in presence. */
379 rc = recv(sock[0], sample, MSBC_PKT_SIZE, 0);
380 ASSERT_EQ(MSBC_PKT_SIZE, rc);
381
382 dev.direction = CRAS_STREAM_INPUT;
383 ASSERT_EQ(0, hfp_info_add_iodev(info, dev.direction, dev.format));
384
385 /* Expect no data read, since no idev present at previous thread callback */
386 ASSERT_EQ(0, hfp_buf_queued(info, dev.direction));
387
388 send_mSBC_packet(sock[0], pkt_count, 0);
389
390 /* Trigger thread callback after idev added. */
391 thread_cb((struct hfp_info*)cb_data);
392 rc = recv(sock[0], sample, MSBC_PKT_SIZE, 0);
393 ASSERT_EQ(MSBC_PKT_SIZE, rc);
394
395 ASSERT_EQ(pkt_count * MSBC_CODE_SIZE / 2,
396 hfp_buf_queued(info, dev.direction));
397 ASSERT_EQ(2, cras_msbc_plc_handle_good_frames_called);
398 pkt_count++;
399 /* When the third packet is lost, we should call the handle_bad_packet and
400 * still have right size of samples queued
401 */
402 pkt_count++;
403 send_mSBC_packet(sock[0], pkt_count, 0);
404 thread_cb((struct hfp_info*)cb_data);
405 rc = recv(sock[0], sample, MSBC_PKT_SIZE, 0);
406 ASSERT_EQ(MSBC_PKT_SIZE, rc);
407
408 /* Packet 1, 2, 4 are all good frames */
409 ASSERT_EQ(3, cras_msbc_plc_handle_good_frames_called);
410 ASSERT_EQ(1, cras_msbc_plc_handle_bad_frames_called);
411 ASSERT_EQ(pkt_count * MSBC_CODE_SIZE / 2,
412 hfp_buf_queued(info, dev.direction));
413 pkt_count++;
414 /* If the erroneous data reporting marks the packet as broken, we should
415 * also call the handle_bad_packet and have the right size of samples queued.
416 */
417 send_mSBC_packet(sock[0], pkt_count, 1);
418
419 set_sbc_codec_decoded_fail(1);
420
421 thread_cb((struct hfp_info*)cb_data);
422 rc = recv(sock[0], sample, MSBC_PKT_SIZE, 0);
423 ASSERT_EQ(MSBC_PKT_SIZE, rc);
424
425 ASSERT_EQ(3, cras_msbc_plc_handle_good_frames_called);
426 ASSERT_EQ(2, cras_msbc_plc_handle_bad_frames_called);
427 ASSERT_EQ(pkt_count * MSBC_CODE_SIZE / 2,
428 hfp_buf_queued(info, dev.direction));
429 pkt_count++;
430 /* If we can't decode the packet, we should also call the handle_bad_packet
431 * and have the right size of samples queued
432 */
433 send_mSBC_packet(sock[0], pkt_count, 0);
434
435 set_sbc_codec_decoded_fail(1);
436
437 thread_cb((struct hfp_info*)cb_data);
438 rc = recv(sock[0], sample, MSBC_PKT_SIZE, 0);
439 ASSERT_EQ(MSBC_PKT_SIZE, rc);
440
441 ASSERT_EQ(3, cras_msbc_plc_handle_good_frames_called);
442 ASSERT_EQ(3, cras_msbc_plc_handle_bad_frames_called);
443 ASSERT_EQ(pkt_count * MSBC_CODE_SIZE / 2,
444 hfp_buf_queued(info, dev.direction));
445
446 hfp_info_stop(info);
447 ASSERT_EQ(0, hfp_info_running(info));
448
449 hfp_info_destroy(info);
450 }
451
TEST(HfpInfo,StartHfpInfoAndWriteMsbc)452 TEST(HfpInfo, StartHfpInfoAndWriteMsbc) {
453 int rc;
454 int sock[2];
455 uint8_t sample[480];
456
457 ResetStubData();
458
459 set_sbc_codec_encoded_out(57);
460 ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sock));
461
462 info = hfp_info_create(HFP_CODEC_ID_MSBC);
463 ASSERT_NE(info, (void*)NULL);
464
465 hfp_info_start(sock[1], 63, info);
466 send(sock[0], sample, 63, 0);
467
468 /* Trigger thread callback */
469 thread_cb((struct hfp_info*)cb_data);
470
471 dev.direction = CRAS_STREAM_OUTPUT;
472 ASSERT_EQ(0, hfp_info_add_iodev(info, dev.direction, dev.format));
473
474 /* Assert queued samples unchanged before output device added */
475 ASSERT_EQ(0, hfp_buf_queued(info, dev.direction));
476
477 /* Put some fake data and trigger thread callback again */
478 send(sock[0], sample, 63, 0);
479 buf_increment_write(info->playback_buf, 240);
480 thread_cb((struct hfp_info*)cb_data);
481
482 /* Assert some samples written */
483 rc = recv(sock[0], sample, 60, 0);
484 ASSERT_EQ(60, rc);
485 ASSERT_EQ(0, hfp_buf_queued(info, dev.direction));
486
487 hfp_info_stop(info);
488 hfp_info_destroy(info);
489 }
490
491 } // namespace
492
493 extern "C" {
494
cras_iodev_list_get_audio_thread()495 struct audio_thread* cras_iodev_list_get_audio_thread() {
496 return NULL;
497 }
498
audio_thread_add_callback(int fd,thread_callback cb,void * data)499 void audio_thread_add_callback(int fd, thread_callback cb, void* data) {
500 thread_cb = cb;
501 cb_data = data;
502 return;
503 }
504
audio_thread_rm_callback_sync(struct audio_thread * thread,int fd)505 int audio_thread_rm_callback_sync(struct audio_thread* thread, int fd) {
506 thread_cb = NULL;
507 cb_data = NULL;
508 return 0;
509 }
510
audio_thread_rm_callback(int fd)511 void audio_thread_rm_callback(int fd) {}
512
cras_msbc_plc_create()513 struct cras_msbc_plc* cras_msbc_plc_create() {
514 cras_msbc_plc_create_called++;
515 return NULL;
516 }
517
cras_msbc_plc_destroy(struct cras_msbc_plc * plc)518 void cras_msbc_plc_destroy(struct cras_msbc_plc* plc) {}
519
cras_msbc_plc_handle_bad_frames(struct cras_msbc_plc * plc,struct cras_audio_codec * codec,uint8_t * output)520 int cras_msbc_plc_handle_bad_frames(struct cras_msbc_plc* plc,
521 struct cras_audio_codec* codec,
522 uint8_t* output) {
523 cras_msbc_plc_handle_bad_frames_called++;
524 return MSBC_CODE_SIZE;
525 }
526
cras_msbc_plc_handle_good_frames(struct cras_msbc_plc * plc,const uint8_t * input,uint8_t * output)527 int cras_msbc_plc_handle_good_frames(struct cras_msbc_plc* plc,
528 const uint8_t* input,
529 uint8_t* output) {
530 cras_msbc_plc_handle_good_frames_called++;
531 return MSBC_CODE_SIZE;
532 }
533 }
534
main(int argc,char ** argv)535 int main(int argc, char** argv) {
536 ::testing::InitGoogleTest(&argc, argv);
537 return RUN_ALL_TESTS();
538 }
539