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