configure: change "found" to "find"
[qemu] / audio / esdaudio.c
1 /*
2  * QEMU ESD audio driver
3  *
4  * Copyright (c) 2006 Frederick Reeve (brushed up by malc)
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include <esd.h>
25 #include "qemu-common.h"
26 #include "audio.h"
27 #include <signal.h>
28
29 #define AUDIO_CAP "esd"
30 #include "audio_int.h"
31 #include "audio_pt_int.h"
32
33 typedef struct {
34     HWVoiceOut hw;
35     int done;
36     int live;
37     int decr;
38     int rpos;
39     void *pcm_buf;
40     int fd;
41     struct audio_pt pt;
42 } ESDVoiceOut;
43
44 typedef struct {
45     HWVoiceIn hw;
46     int done;
47     int dead;
48     int incr;
49     int wpos;
50     void *pcm_buf;
51     int fd;
52     struct audio_pt pt;
53 } ESDVoiceIn;
54
55 static struct {
56     int samples;
57     int divisor;
58     char *dac_host;
59     char *adc_host;
60 } conf = {
61     .samples = 1024,
62     .divisor = 2,
63 };
64
65 static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
66 {
67     va_list ap;
68
69     va_start (ap, fmt);
70     AUD_vlog (AUDIO_CAP, fmt, ap);
71     va_end (ap);
72
73     AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
74 }
75
76 /* playback */
77 static void *qesd_thread_out (void *arg)
78 {
79     ESDVoiceOut *esd = arg;
80     HWVoiceOut *hw = &esd->hw;
81     int threshold;
82
83     threshold = conf.divisor ? hw->samples / conf.divisor : 0;
84
85     if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
86         return NULL;
87     }
88
89     for (;;) {
90         int decr, to_mix, rpos;
91
92         for (;;) {
93             if (esd->done) {
94                 goto exit;
95             }
96
97             if (esd->live > threshold) {
98                 break;
99             }
100
101             if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
102                 goto exit;
103             }
104         }
105
106         decr = to_mix = esd->live;
107         rpos = hw->rpos;
108
109         if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
110             return NULL;
111         }
112
113         while (to_mix) {
114             ssize_t written;
115             int chunk = audio_MIN (to_mix, hw->samples - rpos);
116             struct st_sample *src = hw->mix_buf + rpos;
117
118             hw->clip (esd->pcm_buf, src, chunk);
119
120         again:
121             written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);
122             if (written == -1) {
123                 if (errno == EINTR || errno == EAGAIN) {
124                     goto again;
125                 }
126                 qesd_logerr (errno, "write failed\n");
127                 return NULL;
128             }
129
130             if (written != chunk << hw->info.shift) {
131                 int wsamples = written >> hw->info.shift;
132                 int wbytes = wsamples << hw->info.shift;
133                 if (wbytes != written) {
134                     dolog ("warning: Misaligned write %d (requested %zd), "
135                            "alignment %d\n",
136                            wbytes, written, hw->info.align + 1);
137                 }
138                 to_mix -= wsamples;
139                 rpos = (rpos + wsamples) % hw->samples;
140                 break;
141             }
142
143             rpos = (rpos + chunk) % hw->samples;
144             to_mix -= chunk;
145         }
146
147         if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
148             return NULL;
149         }
150
151         esd->rpos = rpos;
152         esd->live -= decr;
153         esd->decr += decr;
154     }
155
156  exit:
157     audio_pt_unlock (&esd->pt, AUDIO_FUNC);
158     return NULL;
159 }
160
161 static int qesd_run_out (HWVoiceOut *hw)
162 {
163     int live, decr;
164     ESDVoiceOut *esd = (ESDVoiceOut *) hw;
165
166     if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
167         return 0;
168     }
169
170     live = audio_pcm_hw_get_live_out (hw);
171     decr = audio_MIN (live, esd->decr);
172     esd->decr -= decr;
173     esd->live = live - decr;
174     hw->rpos = esd->rpos;
175     if (esd->live > 0) {
176         audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
177     }
178     else {
179         audio_pt_unlock (&esd->pt, AUDIO_FUNC);
180     }
181     return decr;
182 }
183
184 static int qesd_write (SWVoiceOut *sw, void *buf, int len)
185 {
186     return audio_pcm_sw_write (sw, buf, len);
187 }
188
189 static int qesd_init_out (HWVoiceOut *hw, struct audsettings *as)
190 {
191     ESDVoiceOut *esd = (ESDVoiceOut *) hw;
192     struct audsettings obt_as = *as;
193     int esdfmt = ESD_STREAM | ESD_PLAY;
194     int err;
195     sigset_t set, old_set;
196
197     sigfillset (&set);
198
199     esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
200     switch (as->fmt) {
201     case AUD_FMT_S8:
202     case AUD_FMT_U8:
203         esdfmt |= ESD_BITS8;
204         obt_as.fmt = AUD_FMT_U8;
205         break;
206
207     case AUD_FMT_S32:
208     case AUD_FMT_U32:
209         dolog ("Will use 16 instead of 32 bit samples\n");
210
211     case AUD_FMT_S16:
212     case AUD_FMT_U16:
213     deffmt:
214         esdfmt |= ESD_BITS16;
215         obt_as.fmt = AUD_FMT_S16;
216         break;
217
218     default:
219         dolog ("Internal logic error: Bad audio format %d\n", as->fmt);
220         goto deffmt;
221
222     }
223     obt_as.endianness = AUDIO_HOST_ENDIANNESS;
224
225     audio_pcm_init_info (&hw->info, &obt_as);
226
227     hw->samples = conf.samples;
228     esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
229     if (!esd->pcm_buf) {
230         dolog ("Could not allocate buffer (%d bytes)\n",
231                hw->samples << hw->info.shift);
232         return -1;
233     }
234
235     esd->fd = -1;
236     err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
237     if (err) {
238         qesd_logerr (err, "pthread_sigmask failed\n");
239         goto fail1;
240     }
241
242     esd->fd = esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL);
243     if (esd->fd < 0) {
244         qesd_logerr (errno, "esd_play_stream failed\n");
245         goto fail2;
246     }
247
248     if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
249         goto fail3;
250     }
251
252     err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
253     if (err) {
254         qesd_logerr (err, "pthread_sigmask(restore) failed\n");
255     }
256
257     return 0;
258
259  fail3:
260     if (close (esd->fd)) {
261         qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
262                      AUDIO_FUNC, esd->fd);
263     }
264     esd->fd = -1;
265
266  fail2:
267     err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
268     if (err) {
269         qesd_logerr (err, "pthread_sigmask(restore) failed\n");
270     }
271
272  fail1:
273     qemu_free (esd->pcm_buf);
274     esd->pcm_buf = NULL;
275     return -1;
276 }
277
278 static void qesd_fini_out (HWVoiceOut *hw)
279 {
280     void *ret;
281     ESDVoiceOut *esd = (ESDVoiceOut *) hw;
282
283     audio_pt_lock (&esd->pt, AUDIO_FUNC);
284     esd->done = 1;
285     audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
286     audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
287
288     if (esd->fd >= 0) {
289         if (close (esd->fd)) {
290             qesd_logerr (errno, "failed to close esd socket\n");
291         }
292         esd->fd = -1;
293     }
294
295     audio_pt_fini (&esd->pt, AUDIO_FUNC);
296
297     qemu_free (esd->pcm_buf);
298     esd->pcm_buf = NULL;
299 }
300
301 static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
302 {
303     (void) hw;
304     (void) cmd;
305     return 0;
306 }
307
308 /* capture */
309 static void *qesd_thread_in (void *arg)
310 {
311     ESDVoiceIn *esd = arg;
312     HWVoiceIn *hw = &esd->hw;
313     int threshold;
314
315     threshold = conf.divisor ? hw->samples / conf.divisor : 0;
316
317     if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
318         return NULL;
319     }
320
321     for (;;) {
322         int incr, to_grab, wpos;
323
324         for (;;) {
325             if (esd->done) {
326                 goto exit;
327             }
328
329             if (esd->dead > threshold) {
330                 break;
331             }
332
333             if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
334                 goto exit;
335             }
336         }
337
338         incr = to_grab = esd->dead;
339         wpos = hw->wpos;
340
341         if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
342             return NULL;
343         }
344
345         while (to_grab) {
346             ssize_t nread;
347             int chunk = audio_MIN (to_grab, hw->samples - wpos);
348             void *buf = advance (esd->pcm_buf, wpos);
349
350         again:
351             nread = read (esd->fd, buf, chunk << hw->info.shift);
352             if (nread == -1) {
353                 if (errno == EINTR || errno == EAGAIN) {
354                     goto again;
355                 }
356                 qesd_logerr (errno, "read failed\n");
357                 return NULL;
358             }
359
360             if (nread != chunk << hw->info.shift) {
361                 int rsamples = nread >> hw->info.shift;
362                 int rbytes = rsamples << hw->info.shift;
363                 if (rbytes != nread) {
364                     dolog ("warning: Misaligned write %d (requested %zd), "
365                            "alignment %d\n",
366                            rbytes, nread, hw->info.align + 1);
367                 }
368                 to_grab -= rsamples;
369                 wpos = (wpos + rsamples) % hw->samples;
370                 break;
371             }
372
373             hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift,
374                       &nominal_volume);
375             wpos = (wpos + chunk) % hw->samples;
376             to_grab -= chunk;
377         }
378
379         if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
380             return NULL;
381         }
382
383         esd->wpos = wpos;
384         esd->dead -= incr;
385         esd->incr += incr;
386     }
387
388  exit:
389     audio_pt_unlock (&esd->pt, AUDIO_FUNC);
390     return NULL;
391 }
392
393 static int qesd_run_in (HWVoiceIn *hw)
394 {
395     int live, incr, dead;
396     ESDVoiceIn *esd = (ESDVoiceIn *) hw;
397
398     if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
399         return 0;
400     }
401
402     live = audio_pcm_hw_get_live_in (hw);
403     dead = hw->samples - live;
404     incr = audio_MIN (dead, esd->incr);
405     esd->incr -= incr;
406     esd->dead = dead - incr;
407     hw->wpos = esd->wpos;
408     if (esd->dead > 0) {
409         audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
410     }
411     else {
412         audio_pt_unlock (&esd->pt, AUDIO_FUNC);
413     }
414     return incr;
415 }
416
417 static int qesd_read (SWVoiceIn *sw, void *buf, int len)
418 {
419     return audio_pcm_sw_read (sw, buf, len);
420 }
421
422 static int qesd_init_in (HWVoiceIn *hw, struct audsettings *as)
423 {
424     ESDVoiceIn *esd = (ESDVoiceIn *) hw;
425     struct audsettings obt_as = *as;
426     int esdfmt = ESD_STREAM | ESD_RECORD;
427     int err;
428     sigset_t set, old_set;
429
430     sigfillset (&set);
431
432     esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
433     switch (as->fmt) {
434     case AUD_FMT_S8:
435     case AUD_FMT_U8:
436         esdfmt |= ESD_BITS8;
437         obt_as.fmt = AUD_FMT_U8;
438         break;
439
440     case AUD_FMT_S16:
441     case AUD_FMT_U16:
442         esdfmt |= ESD_BITS16;
443         obt_as.fmt = AUD_FMT_S16;
444         break;
445
446     case AUD_FMT_S32:
447     case AUD_FMT_U32:
448         dolog ("Will use 16 instead of 32 bit samples\n");
449         esdfmt |= ESD_BITS16;
450         obt_as.fmt = AUD_FMT_S16;
451         break;
452     }
453     obt_as.endianness = AUDIO_HOST_ENDIANNESS;
454
455     audio_pcm_init_info (&hw->info, &obt_as);
456
457     hw->samples = conf.samples;
458     esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
459     if (!esd->pcm_buf) {
460         dolog ("Could not allocate buffer (%d bytes)\n",
461                hw->samples << hw->info.shift);
462         return -1;
463     }
464
465     esd->fd = -1;
466
467     err = pthread_sigmask (SIG_BLOCK, &set, &old_set);
468     if (err) {
469         qesd_logerr (err, "pthread_sigmask failed\n");
470         goto fail1;
471     }
472
473     esd->fd = esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL);
474     if (esd->fd < 0) {
475         qesd_logerr (errno, "esd_record_stream failed\n");
476         goto fail2;
477     }
478
479     if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
480         goto fail3;
481     }
482
483     err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
484     if (err) {
485         qesd_logerr (err, "pthread_sigmask(restore) failed\n");
486     }
487
488     return 0;
489
490  fail3:
491     if (close (esd->fd)) {
492         qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
493                      AUDIO_FUNC, esd->fd);
494     }
495     esd->fd = -1;
496
497  fail2:
498     err = pthread_sigmask (SIG_SETMASK, &old_set, NULL);
499     if (err) {
500         qesd_logerr (err, "pthread_sigmask(restore) failed\n");
501     }
502
503  fail1:
504     qemu_free (esd->pcm_buf);
505     esd->pcm_buf = NULL;
506     return -1;
507 }
508
509 static void qesd_fini_in (HWVoiceIn *hw)
510 {
511     void *ret;
512     ESDVoiceIn *esd = (ESDVoiceIn *) hw;
513
514     audio_pt_lock (&esd->pt, AUDIO_FUNC);
515     esd->done = 1;
516     audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
517     audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
518
519     if (esd->fd >= 0) {
520         if (close (esd->fd)) {
521             qesd_logerr (errno, "failed to close esd socket\n");
522         }
523         esd->fd = -1;
524     }
525
526     audio_pt_fini (&esd->pt, AUDIO_FUNC);
527
528     qemu_free (esd->pcm_buf);
529     esd->pcm_buf = NULL;
530 }
531
532 static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
533 {
534     (void) hw;
535     (void) cmd;
536     return 0;
537 }
538
539 /* common */
540 static void *qesd_audio_init (void)
541 {
542     return &conf;
543 }
544
545 static void qesd_audio_fini (void *opaque)
546 {
547     (void) opaque;
548     ldebug ("esd_fini");
549 }
550
551 struct audio_option qesd_options[] = {
552     {
553         .name  = "SAMPLES",
554         .tag   = AUD_OPT_INT,
555         .valp  = &conf.samples,
556         .descr = "buffer size in samples"
557     },
558     {
559         .name  = "DIVISOR",
560         .tag   = AUD_OPT_INT,
561         .valp  = &conf.divisor,
562         .descr = "threshold divisor"
563     },
564     {
565         .name  = "DAC_HOST",
566         .tag   = AUD_OPT_STR,
567         .valp  = &conf.dac_host,
568         .descr = "playback host"
569     },
570     {
571         .name  = "ADC_HOST",
572         .tag   = AUD_OPT_STR,
573         .valp  = &conf.adc_host,
574         .descr = "capture host"
575     },
576     { /* End of list */ }
577 };
578
579 static struct audio_pcm_ops qesd_pcm_ops = {
580     .init_out = qesd_init_out,
581     .fini_out = qesd_fini_out,
582     .run_out  = qesd_run_out,
583     .write    = qesd_write,
584     .ctl_out  = qesd_ctl_out,
585
586     .init_in  = qesd_init_in,
587     .fini_in  = qesd_fini_in,
588     .run_in   = qesd_run_in,
589     .read     = qesd_read,
590     .ctl_in   = qesd_ctl_in,
591 };
592
593 struct audio_driver esd_audio_driver = {
594     .name           = "esd",
595     .descr          = "http://en.wikipedia.org/wiki/Esound",
596     .options        = qesd_options,
597     .init           = qesd_audio_init,
598     .fini           = qesd_audio_fini,
599     .pcm_ops        = &qesd_pcm_ops,
600     .can_be_default = 0,
601     .max_voices_out = INT_MAX,
602     .max_voices_in  = INT_MAX,
603     .voice_size_out = sizeof (ESDVoiceOut),
604     .voice_size_in  = sizeof (ESDVoiceIn)
605 };