• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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