• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 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 #include <stdio.h>
6 #include <stdint.h>
7 #include <gtest/gtest.h>
8 
9 extern "C" {
10 
11 #include "a2dp-codecs.h"
12 #include "cras_audio_area.h"
13 #include "audio_thread.h"
14 #include "audio_thread_log.h"
15 #include "cras_bt_transport.h"
16 #include "cras_iodev.h"
17 
18 #include "cras_a2dp_iodev.h"
19 }
20 
21 #define FAKE_OBJECT_PATH "/fake/obj/path"
22 
23 #define MAX_A2DP_ENCODE_CALLS 8
24 #define MAX_A2DP_WRITE_CALLS 4
25 
26 static struct cras_bt_transport *fake_transport;
27 static cras_audio_format format;
28 static size_t cras_bt_device_append_iodev_called;
29 static size_t cras_bt_device_rm_iodev_called;
30 static size_t cras_iodev_add_node_called;
31 static size_t cras_iodev_rm_node_called;
32 static size_t cras_iodev_set_active_node_called;
33 static size_t cras_bt_transport_acquire_called;
34 static size_t cras_bt_transport_configuration_called;
35 static size_t cras_bt_transport_release_called;
36 static size_t init_a2dp_called;
37 static int init_a2dp_return_val;
38 static size_t destroy_a2dp_called;
39 static size_t drain_a2dp_called;
40 static size_t a2dp_block_size_called;
41 static size_t a2dp_queued_frames_val;
42 static size_t cras_iodev_free_format_called;
43 static size_t cras_iodev_free_resources_called;
44 static int pcm_buf_size_val[MAX_A2DP_ENCODE_CALLS];
45 static unsigned int a2dp_encode_processed_bytes_val[MAX_A2DP_ENCODE_CALLS];
46 static unsigned int a2dp_encode_index;
47 static int a2dp_write_return_val[MAX_A2DP_WRITE_CALLS];
48 static unsigned int a2dp_write_index;
49 static cras_audio_area *dummy_audio_area;
50 static thread_callback write_callback;
51 static void *write_callback_data;
52 static const char *fake_device_name = "fake device name";
53 static const char *cras_bt_device_name_ret;
54 static unsigned int cras_bt_transport_write_mtu_ret;
55 
ResetStubData()56 void ResetStubData() {
57   cras_bt_device_append_iodev_called = 0;
58   cras_bt_device_rm_iodev_called = 0;
59   cras_iodev_add_node_called = 0;
60   cras_iodev_rm_node_called = 0;
61   cras_iodev_set_active_node_called = 0;
62   cras_bt_transport_acquire_called = 0;
63   cras_bt_transport_configuration_called = 0;
64   cras_bt_transport_release_called = 0;
65   init_a2dp_called = 0;
66   init_a2dp_return_val = 0;
67   destroy_a2dp_called = 0;
68   drain_a2dp_called = 0;
69   a2dp_block_size_called = 0;
70   a2dp_queued_frames_val = 0;
71   cras_iodev_free_format_called = 0;
72   cras_iodev_free_resources_called = 0;
73   memset(a2dp_encode_processed_bytes_val, 0,
74          sizeof(a2dp_encode_processed_bytes_val));
75   a2dp_encode_index = 0;
76   a2dp_write_index = 0;
77   cras_bt_transport_write_mtu_ret = 800;
78 
79   fake_transport = reinterpret_cast<struct cras_bt_transport *>(0x123);
80 
81   if (!dummy_audio_area) {
82     dummy_audio_area = (cras_audio_area*)calloc(1,
83         sizeof(*dummy_audio_area) + sizeof(cras_channel_area) * 2);
84   }
85 
86   write_callback = NULL;
87 }
88 
iodev_set_format(struct cras_iodev * iodev,struct cras_audio_format * fmt)89 int iodev_set_format(struct cras_iodev *iodev,
90                      struct cras_audio_format *fmt)
91 {
92   fmt->format = SND_PCM_FORMAT_S16_LE;
93   fmt->num_channels = 2;
94   fmt->frame_rate = 44100;
95   iodev->format = fmt;
96   return 0;
97 }
98 
99 namespace {
100 
101 static struct timespec time_now;
102 
TEST(A2dpIoInit,InitializeA2dpIodev)103 TEST(A2dpIoInit, InitializeA2dpIodev) {
104   struct cras_iodev *iodev;
105 
106   atlog = (audio_thread_event_log *)calloc(1, sizeof(audio_thread_event_log));
107 
108   ResetStubData();
109 
110   cras_bt_device_name_ret = NULL;
111   iodev = a2dp_iodev_create(fake_transport);
112 
113   ASSERT_NE(iodev, (void *)NULL);
114   ASSERT_EQ(iodev->direction, CRAS_STREAM_OUTPUT);
115   ASSERT_EQ(1, cras_bt_transport_configuration_called);
116   ASSERT_EQ(1, init_a2dp_called);
117   ASSERT_EQ(1, cras_bt_device_append_iodev_called);
118   ASSERT_EQ(1, cras_iodev_add_node_called);
119   ASSERT_EQ(1, cras_iodev_set_active_node_called);
120 
121   /* Assert iodev name matches the object path when bt device doesn't
122    * have its readable name populated. */
123   ASSERT_STREQ(FAKE_OBJECT_PATH, iodev->info.name);
124 
125   a2dp_iodev_destroy(iodev);
126 
127   ASSERT_EQ(1, cras_bt_device_rm_iodev_called);
128   ASSERT_EQ(1, cras_iodev_rm_node_called);
129   ASSERT_EQ(1, destroy_a2dp_called);
130   ASSERT_EQ(1, cras_iodev_free_resources_called);
131 
132   cras_bt_device_name_ret = fake_device_name;
133   /* Assert iodev name matches the bt device's name */
134   iodev = a2dp_iodev_create(fake_transport);
135   ASSERT_STREQ(fake_device_name, iodev->info.name);
136 
137   a2dp_iodev_destroy(iodev);
138 }
139 
TEST(A2dpIoInit,InitializeFail)140 TEST(A2dpIoInit, InitializeFail) {
141   struct cras_iodev *iodev;
142 
143   ResetStubData();
144 
145   init_a2dp_return_val = -1;
146   iodev = a2dp_iodev_create(fake_transport);
147 
148   ASSERT_EQ(iodev, (void *)NULL);
149   ASSERT_EQ(1, cras_bt_transport_configuration_called);
150   ASSERT_EQ(1, init_a2dp_called);
151   ASSERT_EQ(0, cras_bt_device_append_iodev_called);
152   ASSERT_EQ(0, cras_iodev_add_node_called);
153   ASSERT_EQ(0, cras_iodev_set_active_node_called);
154   ASSERT_EQ(0, cras_iodev_rm_node_called);
155 }
156 
TEST(A2dpIoInit,OpenIodev)157 TEST(A2dpIoInit, OpenIodev) {
158   struct cras_iodev *iodev;
159 
160   ResetStubData();
161   iodev = a2dp_iodev_create(fake_transport);
162 
163   iodev_set_format(iodev, &format);
164   iodev->open_dev(iodev);
165 
166   ASSERT_EQ(1, cras_bt_transport_acquire_called);
167 
168   iodev->close_dev(iodev);
169   ASSERT_EQ(1, cras_bt_transport_release_called);
170   ASSERT_EQ(1, drain_a2dp_called);
171   ASSERT_EQ(1, cras_iodev_free_format_called);
172 
173   a2dp_iodev_destroy(iodev);
174 }
175 
TEST(A2dpIoInit,GetPutBuffer)176 TEST(A2dpIoInit, GetPutBuffer) {
177   struct cras_iodev *iodev;
178   struct cras_audio_area *area1, *area2, *area3;
179   uint8_t *area1_buf;
180   unsigned frames;
181 
182   ResetStubData();
183   iodev = a2dp_iodev_create(fake_transport);
184 
185   iodev_set_format(iodev, &format);
186   iodev->open_dev(iodev);
187   ASSERT_NE(write_callback, (void *)NULL);
188 
189   frames = 256;
190   iodev->get_buffer(iodev, &area1, &frames);
191   ASSERT_EQ(256, frames);
192   ASSERT_EQ(256, area1->frames);
193   area1_buf = area1->channels[0].buf;
194 
195   /* Test 100 frames(400 bytes) put and all processed. */
196   a2dp_encode_processed_bytes_val[0] = 4096 * 4;
197   a2dp_encode_processed_bytes_val[1] = 400;
198   a2dp_write_index = 0;
199   a2dp_write_return_val[0] = -EAGAIN;
200   a2dp_write_return_val[1] = 400;
201   iodev->put_buffer(iodev, 100);
202   write_callback(write_callback_data);
203   // Start with 4k frames.
204   EXPECT_EQ(4096, pcm_buf_size_val[0]);
205   EXPECT_EQ(400, pcm_buf_size_val[1]);
206 
207   iodev->get_buffer(iodev, &area2, &frames);
208   ASSERT_EQ(256, frames);
209   ASSERT_EQ(256, area2->frames);
210 
211   /* Assert buf2 points to the same position as buf1 */
212   ASSERT_EQ(400, area2->channels[0].buf - area1_buf);
213 
214   /* Test 100 frames(400 bytes) put, only 360 bytes processed,
215    * 40 bytes left in pcm buffer.
216    */
217   a2dp_encode_index = 0;
218   a2dp_encode_processed_bytes_val[0] = 360;
219   a2dp_encode_processed_bytes_val[1] = 0;
220   a2dp_write_index = 0;
221   a2dp_write_return_val[0] = 360;
222   a2dp_write_return_val[1] = 0;
223   iodev->put_buffer(iodev, 100);
224   write_callback(write_callback_data);
225   EXPECT_EQ(400, pcm_buf_size_val[0]);
226   ASSERT_EQ(40, pcm_buf_size_val[1]);
227 
228   iodev->get_buffer(iodev, &area3, &frames);
229 
230   /* Existing buffer not completed processed, assert new buffer starts from
231    * current write pointer.
232    */
233   ASSERT_EQ(256, frames);
234   EXPECT_EQ(800, area3->channels[0].buf - area1_buf);
235 
236   a2dp_iodev_destroy(iodev);
237 }
238 
TEST(A2dpIoInif,FramesQueued)239 TEST(A2dpIoInif, FramesQueued) {
240   struct cras_iodev *iodev;
241   struct cras_audio_area *area;
242   struct timespec tstamp;
243   unsigned frames;
244 
245   ResetStubData();
246   iodev = a2dp_iodev_create(fake_transport);
247 
248   iodev_set_format(iodev, &format);
249   time_now.tv_sec = 0;
250   time_now.tv_nsec = 0;
251   iodev->open_dev(iodev);
252   ASSERT_NE(write_callback, (void *)NULL);
253 
254   frames = 256;
255   iodev->get_buffer(iodev, &area, &frames);
256   ASSERT_EQ(256, frames);
257   ASSERT_EQ(256, area->frames);
258 
259   /* Put 100 frames, proccessed 400 bytes to a2dp buffer.
260    * Assume 200 bytes written out, queued 50 frames in a2dp buffer.
261    */
262   a2dp_encode_processed_bytes_val[0] = 400;
263   a2dp_encode_processed_bytes_val[1] = 0;
264   a2dp_write_return_val[0] = 200;
265   a2dp_write_return_val[1] = -EAGAIN;
266   a2dp_queued_frames_val = 50;
267   time_now.tv_sec = 0;
268   time_now.tv_nsec = 1000000;
269   iodev->put_buffer(iodev, 300);
270   write_callback(write_callback_data);
271   EXPECT_EQ(350, iodev->frames_queued(iodev, &tstamp));
272   EXPECT_EQ(tstamp.tv_sec, time_now.tv_sec);
273   EXPECT_EQ(tstamp.tv_nsec, time_now.tv_nsec);
274 
275   /* After writing another 200 frames, check for correct buffer level. */
276   time_now.tv_sec = 0;
277   time_now.tv_nsec = 2000000;
278   a2dp_encode_index = 0;
279   a2dp_write_index = 0;
280   a2dp_encode_processed_bytes_val[0] = 800;
281   write_callback(write_callback_data);
282   /* 1000000 nsec has passed, estimated queued frames adjusted by 44 */
283   EXPECT_EQ(256, iodev->frames_queued(iodev, &tstamp));
284   EXPECT_EQ(1200, pcm_buf_size_val[0]);
285   EXPECT_EQ(400, pcm_buf_size_val[1]);
286   EXPECT_EQ(tstamp.tv_sec, time_now.tv_sec);
287   EXPECT_EQ(tstamp.tv_nsec, time_now.tv_nsec);
288 
289   /* Queued frames and new put buffer are all written */
290   a2dp_encode_processed_bytes_val[0] = 400;
291   a2dp_encode_processed_bytes_val[1] = 0;
292   a2dp_encode_index = 0;
293   a2dp_write_return_val[0] = 400;
294   a2dp_write_return_val[1] = -EAGAIN;
295   a2dp_write_index = 0;
296 
297   /* Add wnother 200 samples, get back to the original level. */
298   time_now.tv_sec = 0;
299   time_now.tv_nsec = 50000000;
300   a2dp_encode_processed_bytes_val[0] = 600;
301   iodev->put_buffer(iodev, 200);
302   EXPECT_EQ(1200, pcm_buf_size_val[0]);
303   EXPECT_EQ(200, iodev->frames_queued(iodev, &tstamp));
304   EXPECT_EQ(tstamp.tv_sec, time_now.tv_sec);
305   EXPECT_EQ(tstamp.tv_nsec, time_now.tv_nsec);
306 }
307 
TEST(A2dpIo,FlushAtLowBufferLevel)308 TEST(A2dpIo, FlushAtLowBufferLevel) {
309   struct cras_iodev *iodev;
310   struct cras_audio_area *area;
311   struct timespec tstamp;
312   unsigned frames;
313 
314   ResetStubData();
315   iodev = a2dp_iodev_create(fake_transport);
316 
317   iodev_set_format(iodev, &format);
318   time_now.tv_sec = 0;
319   time_now.tv_nsec = 0;
320   iodev->open_dev(iodev);
321   ASSERT_NE(write_callback, (void *)NULL);
322 
323   ASSERT_EQ(iodev->min_buffer_level, 400);
324 
325   frames = 700;
326   iodev->get_buffer(iodev, &area, &frames);
327   ASSERT_EQ(700, frames);
328   ASSERT_EQ(700, area->frames);
329 
330   /* Fake 111 frames in pre-fill*/
331   a2dp_encode_processed_bytes_val[0] = 111;
332   a2dp_write_return_val[0] = -EAGAIN;
333 
334   /* First call to a2dp_encode() processed 800 bytes. */
335   a2dp_encode_processed_bytes_val[1] = 800;
336   a2dp_encode_processed_bytes_val[2] = 0;
337   a2dp_write_return_val[1] = 200;
338 
339   /* put_buffer shouldn't trigger the 2nd call to a2dp_encode() because
340    * buffer is low. Fake some data to make sure this test case will fail
341    * when a2dp_encode() called twice.
342    */
343   a2dp_encode_processed_bytes_val[3] = 800;
344   a2dp_encode_processed_bytes_val[4] = 0;
345   a2dp_write_return_val[2] = -EAGAIN;
346 
347   time_now.tv_nsec = 10000000;
348   iodev->put_buffer(iodev, 700);
349 
350   time_now.tv_nsec = 20000000;
351   EXPECT_EQ(500, iodev->frames_queued(iodev, &tstamp));
352   EXPECT_EQ(tstamp.tv_sec, time_now.tv_sec);
353   EXPECT_EQ(tstamp.tv_nsec, time_now.tv_nsec);
354 }
355 
356 } // namespace
357 
main(int argc,char ** argv)358 int main(int argc, char **argv) {
359   ::testing::InitGoogleTest(&argc, argv);
360   return RUN_ALL_TESTS();
361 }
362 
363 extern "C" {
364 
cras_bt_transport_configuration(const struct cras_bt_transport * transport,void * configuration,int len)365 int cras_bt_transport_configuration(const struct cras_bt_transport *transport,
366                                     void *configuration, int len)
367 {
368   cras_bt_transport_configuration_called++;
369   return 0;
370 }
371 
cras_bt_transport_acquire(struct cras_bt_transport * transport)372 int cras_bt_transport_acquire(struct cras_bt_transport *transport)
373 {
374   cras_bt_transport_acquire_called++;
375   return 0;
376 }
377 
cras_bt_transport_release(struct cras_bt_transport * transport,unsigned int blocking)378 int cras_bt_transport_release(struct cras_bt_transport *transport,
379     unsigned int blocking)
380 {
381   cras_bt_transport_release_called++;
382   return 0;
383 }
384 
cras_bt_transport_fd(const struct cras_bt_transport * transport)385 int cras_bt_transport_fd(const struct cras_bt_transport *transport)
386 {
387   return 0;
388 }
389 
cras_bt_transport_object_path(const struct cras_bt_transport * transport)390 const char *cras_bt_transport_object_path(
391 		const struct cras_bt_transport *transport)
392 {
393   return FAKE_OBJECT_PATH;
394 }
395 
cras_bt_transport_write_mtu(const struct cras_bt_transport * transport)396 uint16_t cras_bt_transport_write_mtu(const struct cras_bt_transport *transport)
397 {
398   return cras_bt_transport_write_mtu_ret;
399 }
400 
cras_bt_transport_set_volume(struct cras_bt_transport * transport,uint16_t volume)401 int cras_bt_transport_set_volume(struct cras_bt_transport *transport,
402     uint16_t volume)
403 {
404   return 0;
405 }
406 
cras_iodev_free_format(struct cras_iodev * iodev)407 void cras_iodev_free_format(struct cras_iodev *iodev)
408 {
409   cras_iodev_free_format_called++;
410 }
411 
cras_iodev_free_resources(struct cras_iodev * iodev)412 void cras_iodev_free_resources(struct cras_iodev *iodev)
413 {
414   cras_iodev_free_resources_called++;
415 }
416 
417 // Cras iodev
cras_iodev_add_node(struct cras_iodev * iodev,struct cras_ionode * node)418 void cras_iodev_add_node(struct cras_iodev *iodev, struct cras_ionode *node)
419 {
420   cras_iodev_add_node_called++;
421   iodev->nodes = node;
422 }
423 
cras_iodev_rm_node(struct cras_iodev * iodev,struct cras_ionode * node)424 void cras_iodev_rm_node(struct cras_iodev *iodev, struct cras_ionode *node)
425 {
426   cras_iodev_rm_node_called++;
427   iodev->nodes = NULL;
428 }
429 
cras_iodev_set_active_node(struct cras_iodev * iodev,struct cras_ionode * node)430 void cras_iodev_set_active_node(struct cras_iodev *iodev,
431 				struct cras_ionode *node)
432 {
433   cras_iodev_set_active_node_called++;
434   iodev->active_node = node;
435 }
436 
437 // From cras_bt_transport
cras_bt_transport_device(const struct cras_bt_transport * transport)438 struct cras_bt_device *cras_bt_transport_device(
439 	const struct cras_bt_transport *transport)
440 {
441   return reinterpret_cast<struct cras_bt_device *>(0x456);;
442 }
443 
cras_bt_transport_profile(const struct cras_bt_transport * transport)444 enum cras_bt_device_profile cras_bt_transport_profile(
445   const struct cras_bt_transport *transport)
446 {
447   return CRAS_BT_DEVICE_PROFILE_A2DP_SOURCE;
448 }
449 
450 // From cras_bt_device
cras_bt_device_name(const struct cras_bt_device * device)451 const char *cras_bt_device_name(const struct cras_bt_device *device)
452 {
453   return cras_bt_device_name_ret;
454 }
455 
cras_bt_device_object_path(const struct cras_bt_device * device)456 const char *cras_bt_device_object_path(const struct cras_bt_device *device) {
457   return "/org/bluez/hci0/dev_1A_2B_3C_4D_5E_6F";
458 }
459 
cras_bt_device_append_iodev(struct cras_bt_device * device,struct cras_iodev * iodev,enum cras_bt_device_profile profile)460 void cras_bt_device_append_iodev(struct cras_bt_device *device,
461                                  struct cras_iodev *iodev,
462                                  enum cras_bt_device_profile profile)
463 {
464   cras_bt_device_append_iodev_called++;
465 }
466 
cras_bt_device_rm_iodev(struct cras_bt_device * device,struct cras_iodev * iodev)467 void cras_bt_device_rm_iodev(struct cras_bt_device *device,
468                              struct cras_iodev *iodev)
469 {
470   cras_bt_device_rm_iodev_called++;
471 }
472 
cras_bt_device_get_use_hardware_volume(struct cras_bt_device * device)473 int cras_bt_device_get_use_hardware_volume(struct cras_bt_device *device)
474 {
475   return 0;
476 }
477 
cras_bt_device_cancel_suspend(struct cras_bt_device * device)478 int cras_bt_device_cancel_suspend(struct cras_bt_device *device)
479 {
480   return 0;
481 }
482 
cras_bt_device_schedule_suspend(struct cras_bt_device * device,unsigned int msec)483 int cras_bt_device_schedule_suspend(struct cras_bt_device *device,
484                                     unsigned int msec)
485 {
486   return 0;
487 }
488 
init_a2dp(struct a2dp_info * a2dp,a2dp_sbc_t * sbc)489 int init_a2dp(struct a2dp_info *a2dp, a2dp_sbc_t *sbc)
490 {
491   init_a2dp_called++;
492   return init_a2dp_return_val;
493 }
494 
destroy_a2dp(struct a2dp_info * a2dp)495 void destroy_a2dp(struct a2dp_info *a2dp)
496 {
497   destroy_a2dp_called++;
498 }
499 
a2dp_codesize(struct a2dp_info * a2dp)500 int a2dp_codesize(struct a2dp_info *a2dp)
501 {
502   return 512;
503 }
504 
a2dp_block_size(struct a2dp_info * a2dp,int encoded_bytes)505 int a2dp_block_size(struct a2dp_info *a2dp, int encoded_bytes)
506 {
507   a2dp_block_size_called++;
508 
509   // Assumes a2dp block size is 1:1 before/after encode.
510   return encoded_bytes;
511 }
512 
a2dp_queued_frames(struct a2dp_info * a2dp)513 int a2dp_queued_frames(struct a2dp_info *a2dp)
514 {
515   return a2dp_queued_frames_val;
516 }
517 
a2dp_drain(struct a2dp_info * a2dp)518 void a2dp_drain(struct a2dp_info *a2dp)
519 {
520   drain_a2dp_called++;
521 }
522 
a2dp_encode(struct a2dp_info * a2dp,const void * pcm_buf,int pcm_buf_size,int format_bytes,size_t link_mtu)523 int a2dp_encode(struct a2dp_info *a2dp, const void *pcm_buf, int pcm_buf_size,
524                 int format_bytes, size_t link_mtu) {
525   unsigned int processed;
526 
527   if (a2dp_encode_index == MAX_A2DP_ENCODE_CALLS)
528     return 0;
529   processed = a2dp_encode_processed_bytes_val[a2dp_encode_index];
530   pcm_buf_size_val[a2dp_encode_index] = pcm_buf_size;
531   a2dp_encode_index++;
532   return processed;
533 }
534 
a2dp_write(struct a2dp_info * a2dp,int stream_fd,size_t link_mtu)535 int a2dp_write(struct a2dp_info *a2dp, int stream_fd, size_t link_mtu) {
536   return a2dp_write_return_val[a2dp_write_index++];;
537 }
538 
clock_gettime(clockid_t clk_id,struct timespec * tp)539 int clock_gettime(clockid_t clk_id, struct timespec *tp) {
540   *tp = time_now;
541   return 0;
542 }
543 
cras_iodev_init_audio_area(struct cras_iodev * iodev,int num_channels)544 void cras_iodev_init_audio_area(struct cras_iodev *iodev,
545                                 int num_channels) {
546   iodev->area = dummy_audio_area;
547 }
548 
cras_iodev_free_audio_area(struct cras_iodev * iodev)549 void cras_iodev_free_audio_area(struct cras_iodev *iodev) {
550 }
551 
cras_audio_area_config_buf_pointers(struct cras_audio_area * area,const struct cras_audio_format * fmt,uint8_t * base_buffer)552 void cras_audio_area_config_buf_pointers(struct cras_audio_area *area,
553 					 const struct cras_audio_format *fmt,
554 					 uint8_t *base_buffer)
555 {
556   dummy_audio_area->channels[0].buf = base_buffer;
557 }
558 
cras_iodev_list_get_audio_thread()559 struct audio_thread *cras_iodev_list_get_audio_thread()
560 {
561   return NULL;
562 }
563 // From audio_thread
564 struct audio_thread_event_log *atlog;
565 
audio_thread_add_write_callback(int fd,thread_callback cb,void * data)566 void audio_thread_add_write_callback(int fd, thread_callback cb, void *data) {
567   write_callback = cb;
568   write_callback_data = data;
569 }
570 
audio_thread_rm_callback_sync(struct audio_thread * thread,int fd)571 int audio_thread_rm_callback_sync(struct audio_thread *thread, int fd) {
572   return 0;
573 }
574 
audio_thread_enable_callback(int fd,int enabled)575 void audio_thread_enable_callback(int fd, int enabled) {
576 }
577 
578 }
579