1 /*
2 * QEMU ESD audio driver
3 *
4 * Copyright (c) 2008-2009 The Android Open Source Project
5 * 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 */
25 #include <esd.h>
26 #include "qemu-common.h"
27 #include "audio.h"
28 #include <signal.h>
29
30 #define AUDIO_CAP "esd"
31 #include "audio_int.h"
32 #include <dlfcn.h>
33
34 #include "qemu_debug.h"
35
36 #define DEBUG 1
37
38 #if DEBUG
39 # include <stdio.h>
40 # define D(...) VERBOSE_PRINT(audio,__VA_ARGS__)
41 # define D_ACTIVE VERBOSE_CHECK(audio)
42 # define O(...) VERBOSE_PRINT(audioout,__VA_ARGS__)
43 # define I(...) VERBOSE_PRINT(audioin,__VA_ARGS__)
44 #else
45 # define D(...) ((void)0)
46 # define D_ACTIVE 0
47 # define O(...) ((void)0)
48 # define I(...) ((void)0)
49 #endif
50
51 #define STRINGIFY_(x) #x
52 #define STRINGIFY(x) STRINGIFY_(x)
53
54 typedef struct {
55 HWVoiceOut hw;
56 int done;
57 int live;
58 int decr;
59 int rpos;
60 void *pcm_buf;
61 int fd;
62 } ESDVoiceOut;
63
64 typedef struct {
65 HWVoiceIn hw;
66 int done;
67 int dead;
68 int incr;
69 int wpos;
70 void *pcm_buf;
71 int fd;
72 } ESDVoiceIn;
73
74 static struct {
75 int samples;
76 int divisor;
77 char *dac_host;
78 char *adc_host;
79 } conf = {
80 1024,
81 2,
82 NULL,
83 NULL
84 };
85
86 /* link dynamically to the libesd.so */
87
88 #define DYNLINK_FUNCTIONS \
89 DYNLINK_FUNC(int,esd_play_stream,(esd_format_t,int,const char*,const char*)) \
90 DYNLINK_FUNC(int,esd_record_stream,(esd_format_t,int,const char*,const char*)) \
91 DYNLINK_FUNC(int,esd_open_sound,( const char *host )) \
92 DYNLINK_FUNC(int,esd_close,(int)) \
93
94 #define DYNLINK_FUNCTIONS_INIT \
95 esd_dynlink_init
96
97 #include "dynlink.h"
98
99 static void* esd_lib;
100
qesd_logerr(int err,const char * fmt,...)101 static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
102 {
103 va_list ap;
104
105 va_start (ap, fmt);
106 AUD_vlog (AUDIO_CAP, fmt, ap);
107 va_end (ap);
108
109 AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
110 }
111
qesd_run_out(HWVoiceOut * hw)112 static int qesd_run_out (HWVoiceOut *hw)
113 {
114 ESDVoiceOut *esd = (ESDVoiceOut *) hw;
115 int liveSamples, totalSamples;
116 int rpos, nwrite, writeSamples, writeBytes;
117
118 liveSamples = audio_pcm_hw_get_live_out (hw);
119 rpos = hw->rpos;
120 totalSamples = 0;
121
122 while (liveSamples > 0) {
123 int chunkSamples = audio_MIN (liveSamples, hw->samples - rpos);
124 int chunkBytes = chunkSamples << hw->info.shift;
125 struct st_sample *src = hw->mix_buf + rpos;
126
127 hw->clip (esd->pcm_buf, src, chunkSamples);
128
129 AGAIN:
130 nwrite = write (esd->fd, esd->pcm_buf, chunkBytes);
131 if (nwrite == -1) {
132 if (errno == EINTR)
133 goto AGAIN;
134 if (errno == EAGAIN || errno == EWOULDBLOCK)
135 break;
136 qesd_logerr (errno, "write failed: %s\n", strerror(errno));
137 O("EsounD output thread write error: %s", strerror(errno));
138 break;
139 }
140 if (nwrite == 0)
141 break;
142
143 writeSamples = nwrite >> hw->info.shift;
144 writeBytes = writeSamples << hw->info.shift;
145 if (writeBytes != nwrite) {
146 dolog ("warning: Misaligned write %d (requested %d), "
147 "alignment %d\n",
148 nwrite, writeBytes, hw->info.align + 1);
149 }
150 rpos = (rpos + writeSamples) % hw->samples;
151 totalSamples += writeSamples;
152 liveSamples -= writeSamples;
153 }
154 hw->rpos = rpos;
155 return totalSamples;
156 }
157
qesd_write(SWVoiceOut * sw,void * buf,int len)158 static int qesd_write (SWVoiceOut *sw, void *buf, int len)
159 {
160 return audio_pcm_sw_write (sw, buf, len);
161 }
162
qesd_init_out(HWVoiceOut * hw,struct audsettings * as)163 static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
164 {
165 ESDVoiceOut *esd = (ESDVoiceOut *) hw;
166 struct audsettings obt_as = *as;
167 int esdfmt = ESD_STREAM | ESD_PLAY;
168 int result = -1;
169
170 /* shut down verbose debug spew */
171 if (!D_ACTIVE)
172 stdio_disable();
173
174 O("initializing EsoundD audio output");
175 esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
176 switch (as->fmt) {
177 case AUD_FMT_S8:
178 case AUD_FMT_U8:
179 esdfmt |= ESD_BITS8;
180 obt_as.fmt = AUD_FMT_U8;
181 break;
182 #if 0
183 case AUD_FMT_S32:
184 case AUD_FMT_U32:
185 dolog ("Will use 16 instead of 32 bit samples\n");
186 #endif
187 case AUD_FMT_S16:
188 case AUD_FMT_U16:
189 deffmt:
190 esdfmt |= ESD_BITS16;
191 obt_as.fmt = AUD_FMT_S16;
192 break;
193
194 default:
195 dolog ("Internal logic error: Bad audio format %d\n", as->fmt);
196 goto deffmt;
197
198 }
199 obt_as.endianness = AUDIO_HOST_ENDIANNESS;
200
201 audio_pcm_init_info (&hw->info, &obt_as);
202
203 hw->samples = conf.samples;
204 esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
205 if (!esd->pcm_buf) {
206 dolog ("Could not allocate buffer (%d bytes)\n",
207 hw->samples << hw->info.shift);
208 goto exit;
209 }
210
211 esd->fd = FF(esd_play_stream) (esdfmt, as->freq, conf.dac_host, NULL);
212 if (esd->fd < 0) {
213 if (conf.dac_host == NULL) {
214 esd->fd = FF(esd_play_stream) (esdfmt, as->freq, "localhost", NULL);
215 }
216 if (esd->fd < 0) {
217 qesd_logerr (errno, "esd_play_stream failed\n");
218 goto fail2;
219 }
220 }
221
222 {
223 int flags;
224 flags = fcntl(esd->fd, F_GETFL);
225 fcntl(esd->fd, F_SETFL, flags | O_NONBLOCK);
226 }
227
228 result = 0; /* success */
229 goto exit;
230
231 fail2:
232 qemu_free (esd->pcm_buf);
233 esd->pcm_buf = NULL;
234
235 exit:
236 if (!D_ACTIVE)
237 stdio_enable();
238
239 return result;
240 }
241
qesd_fini_out(HWVoiceOut * hw)242 static void qesd_fini_out (HWVoiceOut *hw)
243 {
244 ESDVoiceOut *esd = (ESDVoiceOut *) hw;
245
246 if (esd->fd >= 0) {
247 if (close (esd->fd)) {
248 qesd_logerr (errno, "failed to close esd socket\n");
249 }
250 esd->fd = -1;
251 }
252 qemu_free (esd->pcm_buf);
253 esd->pcm_buf = NULL;
254 }
255
qesd_ctl_out(HWVoiceOut * hw,int cmd,...)256 static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
257 {
258 (void) hw;
259 (void) cmd;
260 return 0;
261 }
262
263 /* capture */
qesd_run_in(HWVoiceIn * hw)264 static int qesd_run_in (HWVoiceIn *hw)
265 {
266 int wpos, liveSamples, totalSamples;
267 int grabSamples;
268 ESDVoiceIn *esd = (ESDVoiceIn *) hw;
269
270 wpos = hw->wpos;
271 liveSamples = audio_pcm_hw_get_live_in (hw);
272 grabSamples = hw->samples - liveSamples;
273 totalSamples = 0;
274
275 while (grabSamples > 0) {
276 ssize_t nread;
277 int chunkSamples = audio_MIN (grabSamples, hw->samples - wpos);
278 int chunkBytes = chunkSamples << hw->info.shift;
279 int readSamples, readBytes;
280 void* buf = advance (esd->pcm_buf, wpos);
281
282 AGAIN:
283 nread = read (esd->fd, buf, chunkBytes);
284 if (nread == -1) {
285 if (errno == EINTR)
286 goto AGAIN;
287 if (errno == EAGAIN || errno == EWOULDBLOCK)
288 break;
289
290 qesd_logerr (errno, "read failed: %s\n", strerror(errno));
291 break;
292 }
293 if (nread == 0)
294 break;
295
296 readSamples = nread >> hw->info.shift;
297 readBytes = readSamples << hw->info.shift;
298
299 if (readBytes != nread) {
300 dolog ("warning: Misaligned read %d (requested %d), "
301 "alignment %d\n",
302 nread, readBytes, hw->info.align + 1);
303 }
304
305 hw->conv (hw->conv_buf + wpos, buf, readSamples,
306 &nominal_volume);
307
308 wpos = (wpos + readSamples) % hw->samples;
309 grabSamples -= readSamples;
310 totalSamples += readSamples;
311 }
312 hw->wpos = wpos;
313 return totalSamples;
314 }
315
qesd_read(SWVoiceIn * sw,void * buf,int len)316 static int qesd_read (SWVoiceIn *sw, void *buf, int len)
317 {
318 return audio_pcm_sw_read (sw, buf, len);
319 }
320
qesd_init_in(HWVoiceIn * hw,struct audsettings * as)321 static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
322 {
323 ESDVoiceIn *esd = (ESDVoiceIn *) hw;
324 struct audsettings obt_as = *as;
325 int esdfmt = ESD_STREAM | ESD_RECORD;
326 int result = -1;
327
328 /* shut down verbose debug spew */
329 if (!D_ACTIVE)
330 stdio_disable();
331
332 esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
333 switch (as->fmt) {
334 case AUD_FMT_S8:
335 case AUD_FMT_U8:
336 esdfmt |= ESD_BITS8;
337 obt_as.fmt = AUD_FMT_U8;
338 break;
339
340 case AUD_FMT_S16:
341 case AUD_FMT_U16:
342 esdfmt |= ESD_BITS16;
343 obt_as.fmt = AUD_FMT_S16;
344 break;
345
346 case AUD_FMT_S32:
347 case AUD_FMT_U32:
348 dolog ("Will use 16 instead of 32 bit samples\n");
349 esdfmt |= ESD_BITS16;
350 obt_as.fmt = AUD_FMT_S16;
351 break;
352 }
353 obt_as.endianness = AUDIO_HOST_ENDIANNESS;
354
355 audio_pcm_init_info (&hw->info, &obt_as);
356
357 hw->samples = conf.samples;
358 esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
359 if (!esd->pcm_buf) {
360 dolog ("Could not allocate buffer (%d bytes)\n",
361 hw->samples << hw->info.shift);
362 goto exit;
363 }
364
365 esd->fd = FF(esd_record_stream) (esdfmt, as->freq, conf.adc_host, NULL);
366 if (esd->fd < 0) {
367 if (conf.adc_host == NULL) {
368 esd->fd = FF(esd_record_stream) (esdfmt, as->freq, "localhost", NULL);
369 }
370 if (esd->fd < 0) {
371 qesd_logerr (errno, "esd_record_stream failed\n");
372 goto fail2;
373 }
374 }
375
376 {
377 int flags;
378 flags = fcntl(esd->fd, F_GETFL);
379 fcntl(esd->fd, F_SETFL, flags | O_NONBLOCK);
380 }
381
382 result = 0; /* success */
383 goto exit;
384
385 fail2:
386 qemu_free (esd->pcm_buf);
387 esd->pcm_buf = NULL;
388
389 exit:
390 if (!D_ACTIVE)
391 stdio_enable();
392
393 return result;
394 }
395
qesd_fini_in(HWVoiceIn * hw)396 static void qesd_fini_in (HWVoiceIn *hw)
397 {
398 ESDVoiceIn *esd = (ESDVoiceIn *) hw;
399
400 if (esd->fd >= 0) {
401 if (close (esd->fd)) {
402 qesd_logerr (errno, "failed to close esd socket\n");
403 }
404 esd->fd = -1;
405 }
406 qemu_free (esd->pcm_buf);
407 esd->pcm_buf = NULL;
408 }
409
qesd_ctl_in(HWVoiceIn * hw,int cmd,...)410 static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
411 {
412 (void) hw;
413 (void) cmd;
414 return 0;
415 }
416
417 /* common */
qesd_audio_init(void)418 static void *qesd_audio_init (void)
419 {
420 void* result = NULL;
421
422 D("%s: entering", __FUNCTION__);
423
424 if (esd_lib == NULL) {
425 int fd;
426
427 esd_lib = dlopen( "libesd.so", RTLD_NOW );
428 if (esd_lib == NULL)
429 esd_lib = dlopen( "libesd.so.0", RTLD_NOW );
430
431 if (esd_lib == NULL) {
432 D("could not find libesd on this system");
433 goto Exit;
434 }
435
436 if (esd_dynlink_init(esd_lib) < 0)
437 goto Fail;
438
439 fd = FF(esd_open_sound)(conf.dac_host);
440 if (fd < 0) {
441 D("%s: could not open direct sound server connection, trying localhost",
442 __FUNCTION__);
443 fd = FF(esd_open_sound)("localhost");
444 if (fd < 0) {
445 D("%s: could not open localhost sound server connection", __FUNCTION__);
446 goto Fail;
447 }
448 }
449
450 D("%s: EsounD server connection succeeded", __FUNCTION__);
451 /* FF(esd_close)(fd); */
452 }
453 result = &conf;
454 goto Exit;
455
456 Fail:
457 D("%s: failed to open library", __FUNCTION__);
458 dlclose(esd_lib);
459 esd_lib = NULL;
460
461 Exit:
462 return result;
463 }
464
qesd_audio_fini(void * opaque)465 static void qesd_audio_fini (void *opaque)
466 {
467 (void) opaque;
468 if (esd_lib != NULL) {
469 dlclose(esd_lib);
470 esd_lib = NULL;
471 }
472 ldebug ("esd_fini");
473 }
474
475 struct audio_option qesd_options[] = {
476 {"SAMPLES", AUD_OPT_INT, &conf.samples,
477 "buffer size in samples", NULL, 0},
478
479 {"DIVISOR", AUD_OPT_INT, &conf.divisor,
480 "threshold divisor", NULL, 0},
481
482 {"DAC_HOST", AUD_OPT_STR, &conf.dac_host,
483 "playback host", NULL, 0},
484
485 {"ADC_HOST", AUD_OPT_STR, &conf.adc_host,
486 "capture host", NULL, 0},
487
488 {NULL, 0, NULL, NULL, NULL, 0}
489 };
490
491 static struct audio_pcm_ops qesd_pcm_ops = {
492 qesd_init_out,
493 qesd_fini_out,
494 qesd_run_out,
495 qesd_write,
496 qesd_ctl_out,
497
498 qesd_init_in,
499 qesd_fini_in,
500 qesd_run_in,
501 qesd_read,
502 qesd_ctl_in,
503 };
504
505 struct audio_driver esd_audio_driver = {
506 INIT_FIELD (name = ) "esd",
507 INIT_FIELD (descr = )
508 "EsounD audio (en.wikipedia.org/wiki/Esound)",
509 INIT_FIELD (options = ) qesd_options,
510 INIT_FIELD (init = ) qesd_audio_init,
511 INIT_FIELD (fini = ) qesd_audio_fini,
512 INIT_FIELD (pcm_ops = ) &qesd_pcm_ops,
513 INIT_FIELD (can_be_default = ) 1,
514 INIT_FIELD (max_voices_out = ) INT_MAX,
515 INIT_FIELD (max_voices_in = ) 1,
516 INIT_FIELD (voice_size_out = ) sizeof (ESDVoiceOut),
517 INIT_FIELD (voice_size_in = ) sizeof (ESDVoiceIn)
518 };
519