blob: 6815a989028caa688224c435b269ed963393bc3f [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/*
2 * QEMU ESD audio driver
3 *
David 'Digit' Turner5ad9feb2009-08-21 03:05:29 +02004 * Copyright (c) 2008-2009 The Android Open Source Project
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08005 * Copyright (c) 2006 Frederick Reeve (brushed up by malc)
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080025#include <esd.h>
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -070026#include "qemu-common.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080027#include "audio.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080028
29#define AUDIO_CAP "esd"
30#include "audio_int.h"
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +010031#include "audio_pt_int.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080032
David 'Digit' Turnere1e03df2013-12-15 00:42:21 +010033#include "android/qemu-debug.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080034
35#define DEBUG 1
36
37#if DEBUG
38# include <stdio.h>
39# define D(...) VERBOSE_PRINT(audio,__VA_ARGS__)
40# define D_ACTIVE VERBOSE_CHECK(audio)
41# define O(...) VERBOSE_PRINT(audioout,__VA_ARGS__)
42# define I(...) VERBOSE_PRINT(audioin,__VA_ARGS__)
43#else
44# define D(...) ((void)0)
45# define D_ACTIVE 0
46# define O(...) ((void)0)
47# define I(...) ((void)0)
48#endif
49
50#define STRINGIFY_(x) #x
51#define STRINGIFY(x) STRINGIFY_(x)
52
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +010053#include <dlfcn.h>
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080054/* link dynamically to the libesd.so */
55
56#define DYNLINK_FUNCTIONS \
57 DYNLINK_FUNC(int,esd_play_stream,(esd_format_t,int,const char*,const char*)) \
58 DYNLINK_FUNC(int,esd_record_stream,(esd_format_t,int,const char*,const char*)) \
59 DYNLINK_FUNC(int,esd_open_sound,( const char *host )) \
60 DYNLINK_FUNC(int,esd_close,(int)) \
61
62#define DYNLINK_FUNCTIONS_INIT \
63 esd_dynlink_init
64
David 'Digit' Turner1634ff52013-12-14 23:31:41 +010065#include "android/dynlink.h"
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080066
67static void* esd_lib;
68
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +010069
70typedef struct {
71 HWVoiceOut hw;
72 int done;
73 int live;
74 int decr;
75 int rpos;
76 void *pcm_buf;
77 int fd;
78 struct audio_pt pt;
79} ESDVoiceOut;
80
81typedef struct {
82 HWVoiceIn hw;
83 int done;
84 int dead;
85 int incr;
86 int wpos;
87 void *pcm_buf;
88 int fd;
89 struct audio_pt pt;
90} ESDVoiceIn;
91
92static struct {
93 int samples;
94 int divisor;
95 char *dac_host;
96 char *adc_host;
97} conf = {
98 .samples = 1024,
99 .divisor = 2,
100};
101
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800102static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
103{
104 va_list ap;
105
106 va_start (ap, fmt);
107 AUD_vlog (AUDIO_CAP, fmt, ap);
108 va_end (ap);
109
110 AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
111}
112
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100113/* playback */
114static void *qesd_thread_out (void *arg)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800115{
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100116 ESDVoiceOut *esd = arg;
117 HWVoiceOut *hw = &esd->hw;
118 int threshold;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800119
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100120 threshold = conf.divisor ? hw->samples / conf.divisor : 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800121
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100122 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
123 return NULL;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800124 }
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100125
126 for (;;) {
127 int decr, to_mix, rpos;
128
129 for (;;) {
130 if (esd->done) {
131 goto exit;
132 }
133
134 if (esd->live > threshold) {
135 break;
136 }
137
138 if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
139 goto exit;
140 }
141 }
142
143 decr = to_mix = esd->live;
144 rpos = hw->rpos;
145
146 if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
147 return NULL;
148 }
149
150 while (to_mix) {
151 ssize_t written;
152 int chunk = audio_MIN (to_mix, hw->samples - rpos);
153 struct st_sample *src = hw->mix_buf + rpos;
154
155 hw->clip (esd->pcm_buf, src, chunk);
156
157 again:
158 written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);
159 if (written == -1) {
160 if (errno == EINTR || errno == EAGAIN) {
161 goto again;
162 }
163 qesd_logerr (errno, "write failed\n");
164 return NULL;
165 }
166
167 if (written != chunk << hw->info.shift) {
168 int wsamples = written >> hw->info.shift;
169 int wbytes = wsamples << hw->info.shift;
170 if (wbytes != written) {
171 dolog ("warning: Misaligned write %d (requested %zd), "
172 "alignment %d\n",
173 wbytes, written, hw->info.align + 1);
174 }
175 to_mix -= wsamples;
176 rpos = (rpos + wsamples) % hw->samples;
177 break;
178 }
179
180 rpos = (rpos + chunk) % hw->samples;
181 to_mix -= chunk;
182 }
183
184 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
185 return NULL;
186 }
187
188 esd->rpos = rpos;
189 esd->live -= decr;
190 esd->decr += decr;
191 }
192
193 exit:
194 audio_pt_unlock (&esd->pt, AUDIO_FUNC);
195 return NULL;
196}
197
198static int qesd_run_out (HWVoiceOut *hw, int live)
199{
200 int decr;
201 ESDVoiceOut *esd = (ESDVoiceOut *) hw;
202
203 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
204 return 0;
205 }
206
207 decr = audio_MIN (live, esd->decr);
208 esd->decr -= decr;
209 esd->live = live - decr;
210 hw->rpos = esd->rpos;
211 if (esd->live > 0) {
212 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
213 }
214 else {
215 audio_pt_unlock (&esd->pt, AUDIO_FUNC);
216 }
217 return decr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800218}
219
220static int qesd_write (SWVoiceOut *sw, void *buf, int len)
221{
222 return audio_pcm_sw_write (sw, buf, len);
223}
224
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700225static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800226{
227 ESDVoiceOut *esd = (ESDVoiceOut *) hw;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700228 struct audsettings obt_as = *as;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800229 int esdfmt = ESD_STREAM | ESD_PLAY;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800230
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800231 esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
232 switch (as->fmt) {
233 case AUD_FMT_S8:
234 case AUD_FMT_U8:
235 esdfmt |= ESD_BITS8;
236 obt_as.fmt = AUD_FMT_U8;
237 break;
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100238
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800239 case AUD_FMT_S32:
240 case AUD_FMT_U32:
241 dolog ("Will use 16 instead of 32 bit samples\n");
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100242
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800243 case AUD_FMT_S16:
244 case AUD_FMT_U16:
245 deffmt:
246 esdfmt |= ESD_BITS16;
247 obt_as.fmt = AUD_FMT_S16;
248 break;
249
250 default:
251 dolog ("Internal logic error: Bad audio format %d\n", as->fmt);
252 goto deffmt;
253
254 }
255 obt_as.endianness = AUDIO_HOST_ENDIANNESS;
256
257 audio_pcm_init_info (&hw->info, &obt_as);
258
259 hw->samples = conf.samples;
260 esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
261 if (!esd->pcm_buf) {
262 dolog ("Could not allocate buffer (%d bytes)\n",
263 hw->samples << hw->info.shift);
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100264 return -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800265 }
266
267 esd->fd = FF(esd_play_stream) (esdfmt, as->freq, conf.dac_host, NULL);
268 if (esd->fd < 0) {
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100269 qesd_logerr (errno, "esd_play_stream failed\n");
270 goto fail1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800271 }
272
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100273 if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
274 goto fail2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800275 }
276
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100277 return 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800278
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800279 fail2:
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100280 if (close (esd->fd)) {
281 qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
282 AUDIO_FUNC, esd->fd);
283 }
284 esd->fd = -1;
285
286 fail1:
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100287 g_free (esd->pcm_buf);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800288 esd->pcm_buf = NULL;
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100289 return -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800290}
291
292static void qesd_fini_out (HWVoiceOut *hw)
293{
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100294 void *ret;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800295 ESDVoiceOut *esd = (ESDVoiceOut *) hw;
296
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100297 audio_pt_lock (&esd->pt, AUDIO_FUNC);
298 esd->done = 1;
299 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
300 audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
301
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800302 if (esd->fd >= 0) {
303 if (close (esd->fd)) {
304 qesd_logerr (errno, "failed to close esd socket\n");
305 }
306 esd->fd = -1;
307 }
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100308
309 audio_pt_fini (&esd->pt, AUDIO_FUNC);
310
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100311 g_free (esd->pcm_buf);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800312 esd->pcm_buf = NULL;
313}
314
315static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
316{
317 (void) hw;
318 (void) cmd;
319 return 0;
320}
321
322/* capture */
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100323static void *qesd_thread_in (void *arg)
324{
325 ESDVoiceIn *esd = arg;
326 HWVoiceIn *hw = &esd->hw;
327 int threshold;
328
329 threshold = conf.divisor ? hw->samples / conf.divisor : 0;
330
331 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
332 return NULL;
333 }
334
335 for (;;) {
336 int incr, to_grab, wpos;
337
338 for (;;) {
339 if (esd->done) {
340 goto exit;
341 }
342
343 if (esd->dead > threshold) {
344 break;
345 }
346
347 if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
348 goto exit;
349 }
350 }
351
352 incr = to_grab = esd->dead;
353 wpos = hw->wpos;
354
355 if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
356 return NULL;
357 }
358
359 while (to_grab) {
360 ssize_t nread;
361 int chunk = audio_MIN (to_grab, hw->samples - wpos);
362 void *buf = advance (esd->pcm_buf, wpos);
363
364 again:
365 nread = read (esd->fd, buf, chunk << hw->info.shift);
366 if (nread == -1) {
367 if (errno == EINTR || errno == EAGAIN) {
368 goto again;
369 }
370 qesd_logerr (errno, "read failed\n");
371 return NULL;
372 }
373
374 if (nread != chunk << hw->info.shift) {
375 int rsamples = nread >> hw->info.shift;
376 int rbytes = rsamples << hw->info.shift;
377 if (rbytes != nread) {
378 dolog ("warning: Misaligned write %d (requested %zd), "
379 "alignment %d\n",
380 rbytes, nread, hw->info.align + 1);
381 }
382 to_grab -= rsamples;
383 wpos = (wpos + rsamples) % hw->samples;
384 break;
385 }
386
387 hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift,
388 &nominal_volume);
389 wpos = (wpos + chunk) % hw->samples;
390 to_grab -= chunk;
391 }
392
393 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
394 return NULL;
395 }
396
397 esd->wpos = wpos;
398 esd->dead -= incr;
399 esd->incr += incr;
400 }
401
402 exit:
403 audio_pt_unlock (&esd->pt, AUDIO_FUNC);
404 return NULL;
405}
406
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800407static int qesd_run_in (HWVoiceIn *hw)
408{
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100409 int live, incr, dead;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800410 ESDVoiceIn *esd = (ESDVoiceIn *) hw;
411
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100412 if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
413 return 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800414 }
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100415
416 live = audio_pcm_hw_get_live_in (hw);
417 dead = hw->samples - live;
418 incr = audio_MIN (dead, esd->incr);
419 esd->incr -= incr;
420 esd->dead = dead - incr;
421 hw->wpos = esd->wpos;
422 if (esd->dead > 0) {
423 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
424 }
425 else {
426 audio_pt_unlock (&esd->pt, AUDIO_FUNC);
427 }
428 return incr;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800429}
430
431static int qesd_read (SWVoiceIn *sw, void *buf, int len)
432{
433 return audio_pcm_sw_read (sw, buf, len);
434}
435
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700436static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800437{
438 ESDVoiceIn *esd = (ESDVoiceIn *) hw;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700439 struct audsettings obt_as = *as;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800440 int esdfmt = ESD_STREAM | ESD_RECORD;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800441
442 esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
443 switch (as->fmt) {
444 case AUD_FMT_S8:
445 case AUD_FMT_U8:
446 esdfmt |= ESD_BITS8;
447 obt_as.fmt = AUD_FMT_U8;
448 break;
449
450 case AUD_FMT_S16:
451 case AUD_FMT_U16:
452 esdfmt |= ESD_BITS16;
453 obt_as.fmt = AUD_FMT_S16;
454 break;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700455
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800456 case AUD_FMT_S32:
457 case AUD_FMT_U32:
458 dolog ("Will use 16 instead of 32 bit samples\n");
459 esdfmt |= ESD_BITS16;
460 obt_as.fmt = AUD_FMT_S16;
461 break;
462 }
463 obt_as.endianness = AUDIO_HOST_ENDIANNESS;
464
465 audio_pcm_init_info (&hw->info, &obt_as);
466
467 hw->samples = conf.samples;
468 esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
469 if (!esd->pcm_buf) {
470 dolog ("Could not allocate buffer (%d bytes)\n",
471 hw->samples << hw->info.shift);
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100472 return -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800473 }
474
475 esd->fd = FF(esd_record_stream) (esdfmt, as->freq, conf.adc_host, NULL);
476 if (esd->fd < 0) {
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100477 qesd_logerr (errno, "esd_record_stream failed\n");
478 goto fail1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800479 }
480
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100481 if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
482 goto fail2;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800483 }
484
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100485 return 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800486
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800487 fail2:
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100488 if (close (esd->fd)) {
489 qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
490 AUDIO_FUNC, esd->fd);
491 }
492 esd->fd = -1;
493
494 fail1:
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100495 g_free (esd->pcm_buf);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800496 esd->pcm_buf = NULL;
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100497 return -1;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800498}
499
500static void qesd_fini_in (HWVoiceIn *hw)
501{
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100502 void *ret;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800503 ESDVoiceIn *esd = (ESDVoiceIn *) hw;
504
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100505 audio_pt_lock (&esd->pt, AUDIO_FUNC);
506 esd->done = 1;
507 audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
508 audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
509
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800510 if (esd->fd >= 0) {
511 if (close (esd->fd)) {
512 qesd_logerr (errno, "failed to close esd socket\n");
513 }
514 esd->fd = -1;
515 }
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100516
517 audio_pt_fini (&esd->pt, AUDIO_FUNC);
518
David 'Digit' Turneraa8236d2014-01-10 17:02:29 +0100519 g_free (esd->pcm_buf);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800520 esd->pcm_buf = NULL;
521}
522
523static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
524{
525 (void) hw;
526 (void) cmd;
527 return 0;
528}
529
530/* common */
531static void *qesd_audio_init (void)
532{
533 void* result = NULL;
534
535 D("%s: entering", __FUNCTION__);
536
537 if (esd_lib == NULL) {
538 int fd;
539
540 esd_lib = dlopen( "libesd.so", RTLD_NOW );
541 if (esd_lib == NULL)
542 esd_lib = dlopen( "libesd.so.0", RTLD_NOW );
543
544 if (esd_lib == NULL) {
545 D("could not find libesd on this system");
546 goto Exit;
547 }
548
549 if (esd_dynlink_init(esd_lib) < 0)
550 goto Fail;
551
552 fd = FF(esd_open_sound)(conf.dac_host);
553 if (fd < 0) {
554 D("%s: could not open direct sound server connection, trying localhost",
555 __FUNCTION__);
556 fd = FF(esd_open_sound)("localhost");
557 if (fd < 0) {
558 D("%s: could not open localhost sound server connection", __FUNCTION__);
559 goto Fail;
560 }
561 }
562
563 D("%s: EsounD server connection succeeded", __FUNCTION__);
564 /* FF(esd_close)(fd); */
565 }
566 result = &conf;
567 goto Exit;
568
569Fail:
570 D("%s: failed to open library", __FUNCTION__);
571 dlclose(esd_lib);
572 esd_lib = NULL;
573
574Exit:
575 return result;
576}
577
578static void qesd_audio_fini (void *opaque)
579{
580 (void) opaque;
581 if (esd_lib != NULL) {
582 dlclose(esd_lib);
583 esd_lib = NULL;
584 }
585 ldebug ("esd_fini");
586}
587
588struct audio_option qesd_options[] = {
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100589 {
590 .name = "SAMPLES",
591 .tag = AUD_OPT_INT,
592 .valp = &conf.samples,
593 .descr = "buffer size in samples"
594 },
595 {
596 .name = "DIVISOR",
597 .tag = AUD_OPT_INT,
598 .valp = &conf.divisor,
599 .descr = "threshold divisor"
600 },
601 {
602 .name = "DAC_HOST",
603 .tag = AUD_OPT_STR,
604 .valp = &conf.dac_host,
605 .descr = "playback host"
606 },
607 {
608 .name = "ADC_HOST",
609 .tag = AUD_OPT_STR,
610 .valp = &conf.adc_host,
611 .descr = "capture host"
612 },
613 { /* End of list */ }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800614};
615
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700616static struct audio_pcm_ops qesd_pcm_ops = {
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100617 .init_out = qesd_init_out,
618 .fini_out = qesd_fini_out,
619 .run_out = qesd_run_out,
620 .write = qesd_write,
621 .ctl_out = qesd_ctl_out,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800622
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100623 .init_in = qesd_init_in,
624 .fini_in = qesd_fini_in,
625 .run_in = qesd_run_in,
626 .read = qesd_read,
627 .ctl_in = qesd_ctl_in,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800628};
629
630struct audio_driver esd_audio_driver = {
David 'Digit' Turner5d0e37b2011-01-02 12:58:51 +0100631 .name = "esd",
632 .descr = "http://en.wikipedia.org/wiki/Esound",
633 .options = qesd_options,
634 .init = qesd_audio_init,
635 .fini = qesd_audio_fini,
636 .pcm_ops = &qesd_pcm_ops,
637 .can_be_default = 0,
638 .max_voices_out = INT_MAX,
639 .max_voices_in = INT_MAX,
640 .voice_size_out = sizeof (ESDVoiceOut),
641 .voice_size_in = sizeof (ESDVoiceIn)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800642};