ide/isa: convert to qdev.
[qemu] / audio / paaudio.c
1 /* public domain */
2 #include "qemu-common.h"
3 #include "audio.h"
4
5 #include <pulse/simple.h>
6 #include <pulse/error.h>
7
8 #define AUDIO_CAP "pulseaudio"
9 #include "audio_int.h"
10 #include "audio_pt_int.h"
11
12 typedef struct {
13     HWVoiceOut hw;
14     int done;
15     int live;
16     int decr;
17     int rpos;
18     pa_simple *s;
19     void *pcm_buf;
20     struct audio_pt pt;
21 } PAVoiceOut;
22
23 typedef struct {
24     HWVoiceIn hw;
25     int done;
26     int dead;
27     int incr;
28     int wpos;
29     pa_simple *s;
30     void *pcm_buf;
31     struct audio_pt pt;
32 } PAVoiceIn;
33
34 static struct {
35     int samples;
36     int divisor;
37     char *server;
38     char *sink;
39     char *source;
40 } conf = {
41     .samples = 1024,
42     .divisor = 2,
43 };
44
45 static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
46 {
47     va_list ap;
48
49     va_start (ap, fmt);
50     AUD_vlog (AUDIO_CAP, fmt, ap);
51     va_end (ap);
52
53     AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err));
54 }
55
56 static void *qpa_thread_out (void *arg)
57 {
58     PAVoiceOut *pa = arg;
59     HWVoiceOut *hw = &pa->hw;
60     int threshold;
61
62     threshold = conf.divisor ? hw->samples / conf.divisor : 0;
63
64     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
65         return NULL;
66     }
67
68     for (;;) {
69         int decr, to_mix, rpos;
70
71         for (;;) {
72             if (pa->done) {
73                 goto exit;
74             }
75
76             if (pa->live > threshold) {
77                 break;
78             }
79
80             if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
81                 goto exit;
82             }
83         }
84
85         decr = to_mix = pa->live;
86         rpos = hw->rpos;
87
88         if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
89             return NULL;
90         }
91
92         while (to_mix) {
93             int error;
94             int chunk = audio_MIN (to_mix, hw->samples - rpos);
95             struct st_sample *src = hw->mix_buf + rpos;
96
97             hw->clip (pa->pcm_buf, src, chunk);
98
99             if (pa_simple_write (pa->s, pa->pcm_buf,
100                                  chunk << hw->info.shift, &error) < 0) {
101                 qpa_logerr (error, "pa_simple_write failed\n");
102                 return NULL;
103             }
104
105             rpos = (rpos + chunk) % hw->samples;
106             to_mix -= chunk;
107         }
108
109         if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
110             return NULL;
111         }
112
113         pa->rpos = rpos;
114         pa->live -= decr;
115         pa->decr += decr;
116     }
117
118  exit:
119     audio_pt_unlock (&pa->pt, AUDIO_FUNC);
120     return NULL;
121 }
122
123 static int qpa_run_out (HWVoiceOut *hw)
124 {
125     int live, decr;
126     PAVoiceOut *pa = (PAVoiceOut *) hw;
127
128     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
129         return 0;
130     }
131
132     live = audio_pcm_hw_get_live_out (hw);
133     decr = audio_MIN (live, pa->decr);
134     pa->decr -= decr;
135     pa->live = live - decr;
136     hw->rpos = pa->rpos;
137     if (pa->live > 0) {
138         audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
139     }
140     else {
141         audio_pt_unlock (&pa->pt, AUDIO_FUNC);
142     }
143     return decr;
144 }
145
146 static int qpa_write (SWVoiceOut *sw, void *buf, int len)
147 {
148     return audio_pcm_sw_write (sw, buf, len);
149 }
150
151 /* capture */
152 static void *qpa_thread_in (void *arg)
153 {
154     PAVoiceIn *pa = arg;
155     HWVoiceIn *hw = &pa->hw;
156     int threshold;
157
158     threshold = conf.divisor ? hw->samples / conf.divisor : 0;
159
160     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
161         return NULL;
162     }
163
164     for (;;) {
165         int incr, to_grab, wpos;
166
167         for (;;) {
168             if (pa->done) {
169                 goto exit;
170             }
171
172             if (pa->dead > threshold) {
173                 break;
174             }
175
176             if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
177                 goto exit;
178             }
179         }
180
181         incr = to_grab = pa->dead;
182         wpos = hw->wpos;
183
184         if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
185             return NULL;
186         }
187
188         while (to_grab) {
189             int error;
190             int chunk = audio_MIN (to_grab, hw->samples - wpos);
191             void *buf = advance (pa->pcm_buf, wpos);
192
193             if (pa_simple_read (pa->s, buf,
194                                 chunk << hw->info.shift, &error) < 0) {
195                 qpa_logerr (error, "pa_simple_read failed\n");
196                 return NULL;
197             }
198
199             hw->conv (hw->conv_buf + wpos, buf, chunk, &nominal_volume);
200             wpos = (wpos + chunk) % hw->samples;
201             to_grab -= chunk;
202         }
203
204         if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
205             return NULL;
206         }
207
208         pa->wpos = wpos;
209         pa->dead -= incr;
210         pa->incr += incr;
211     }
212
213  exit:
214     audio_pt_unlock (&pa->pt, AUDIO_FUNC);
215     return NULL;
216 }
217
218 static int qpa_run_in (HWVoiceIn *hw)
219 {
220     int live, incr, dead;
221     PAVoiceIn *pa = (PAVoiceIn *) hw;
222
223     if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
224         return 0;
225     }
226
227     live = audio_pcm_hw_get_live_in (hw);
228     dead = hw->samples - live;
229     incr = audio_MIN (dead, pa->incr);
230     pa->incr -= incr;
231     pa->dead = dead - incr;
232     hw->wpos = pa->wpos;
233     if (pa->dead > 0) {
234         audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
235     }
236     else {
237         audio_pt_unlock (&pa->pt, AUDIO_FUNC);
238     }
239     return incr;
240 }
241
242 static int qpa_read (SWVoiceIn *sw, void *buf, int len)
243 {
244     return audio_pcm_sw_read (sw, buf, len);
245 }
246
247 static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)
248 {
249     int format;
250
251     switch (afmt) {
252     case AUD_FMT_S8:
253     case AUD_FMT_U8:
254         format = PA_SAMPLE_U8;
255         break;
256     case AUD_FMT_S16:
257     case AUD_FMT_U16:
258         format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
259         break;
260     case AUD_FMT_S32:
261     case AUD_FMT_U32:
262         format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
263         break;
264     default:
265         dolog ("Internal logic error: Bad audio format %d\n", afmt);
266         format = PA_SAMPLE_U8;
267         break;
268     }
269     return format;
270 }
271
272 static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
273 {
274     switch (fmt) {
275     case PA_SAMPLE_U8:
276         return AUD_FMT_U8;
277     case PA_SAMPLE_S16BE:
278         *endianness = 1;
279         return AUD_FMT_S16;
280     case PA_SAMPLE_S16LE:
281         *endianness = 0;
282         return AUD_FMT_S16;
283     case PA_SAMPLE_S32BE:
284         *endianness = 1;
285         return AUD_FMT_S32;
286     case PA_SAMPLE_S32LE:
287         *endianness = 0;
288         return AUD_FMT_S32;
289     default:
290         dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
291         return AUD_FMT_U8;
292     }
293 }
294
295 static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
296 {
297     int error;
298     static pa_sample_spec ss;
299     struct audsettings obt_as = *as;
300     PAVoiceOut *pa = (PAVoiceOut *) hw;
301
302     ss.format = audfmt_to_pa (as->fmt, as->endianness);
303     ss.channels = as->nchannels;
304     ss.rate = as->freq;
305
306     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
307
308     pa->s = pa_simple_new (
309         conf.server,
310         "qemu",
311         PA_STREAM_PLAYBACK,
312         conf.sink,
313         "pcm.playback",
314         &ss,
315         NULL,                   /* channel map */
316         NULL,                   /* buffering attributes */
317         &error
318         );
319     if (!pa->s) {
320         qpa_logerr (error, "pa_simple_new for playback failed\n");
321         goto fail1;
322     }
323
324     audio_pcm_init_info (&hw->info, &obt_as);
325     hw->samples = conf.samples;
326     pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
327     if (!pa->pcm_buf) {
328         dolog ("Could not allocate buffer (%d bytes)\n",
329                hw->samples << hw->info.shift);
330         goto fail2;
331     }
332
333     if (audio_pt_init (&pa->pt, qpa_thread_out, hw, AUDIO_CAP, AUDIO_FUNC)) {
334         goto fail3;
335     }
336
337     return 0;
338
339  fail3:
340     qemu_free (pa->pcm_buf);
341     pa->pcm_buf = NULL;
342  fail2:
343     pa_simple_free (pa->s);
344     pa->s = NULL;
345  fail1:
346     return -1;
347 }
348
349 static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
350 {
351     int error;
352     static pa_sample_spec ss;
353     struct audsettings obt_as = *as;
354     PAVoiceIn *pa = (PAVoiceIn *) hw;
355
356     ss.format = audfmt_to_pa (as->fmt, as->endianness);
357     ss.channels = as->nchannels;
358     ss.rate = as->freq;
359
360     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
361
362     pa->s = pa_simple_new (
363         conf.server,
364         "qemu",
365         PA_STREAM_RECORD,
366         conf.source,
367         "pcm.capture",
368         &ss,
369         NULL,                   /* channel map */
370         NULL,                   /* buffering attributes */
371         &error
372         );
373     if (!pa->s) {
374         qpa_logerr (error, "pa_simple_new for capture failed\n");
375         goto fail1;
376     }
377
378     audio_pcm_init_info (&hw->info, &obt_as);
379     hw->samples = conf.samples;
380     pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
381     if (!pa->pcm_buf) {
382         dolog ("Could not allocate buffer (%d bytes)\n",
383                hw->samples << hw->info.shift);
384         goto fail2;
385     }
386
387     if (audio_pt_init (&pa->pt, qpa_thread_in, hw, AUDIO_CAP, AUDIO_FUNC)) {
388         goto fail3;
389     }
390
391     return 0;
392
393  fail3:
394     qemu_free (pa->pcm_buf);
395     pa->pcm_buf = NULL;
396  fail2:
397     pa_simple_free (pa->s);
398     pa->s = NULL;
399  fail1:
400     return -1;
401 }
402
403 static void qpa_fini_out (HWVoiceOut *hw)
404 {
405     void *ret;
406     PAVoiceOut *pa = (PAVoiceOut *) hw;
407
408     audio_pt_lock (&pa->pt, AUDIO_FUNC);
409     pa->done = 1;
410     audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
411     audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
412
413     if (pa->s) {
414         pa_simple_free (pa->s);
415         pa->s = NULL;
416     }
417
418     audio_pt_fini (&pa->pt, AUDIO_FUNC);
419     qemu_free (pa->pcm_buf);
420     pa->pcm_buf = NULL;
421 }
422
423 static void qpa_fini_in (HWVoiceIn *hw)
424 {
425     void *ret;
426     PAVoiceIn *pa = (PAVoiceIn *) hw;
427
428     audio_pt_lock (&pa->pt, AUDIO_FUNC);
429     pa->done = 1;
430     audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
431     audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
432
433     if (pa->s) {
434         pa_simple_free (pa->s);
435         pa->s = NULL;
436     }
437
438     audio_pt_fini (&pa->pt, AUDIO_FUNC);
439     qemu_free (pa->pcm_buf);
440     pa->pcm_buf = NULL;
441 }
442
443 static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
444 {
445     (void) hw;
446     (void) cmd;
447     return 0;
448 }
449
450 static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
451 {
452     (void) hw;
453     (void) cmd;
454     return 0;
455 }
456
457 /* common */
458 static void *qpa_audio_init (void)
459 {
460     return &conf;
461 }
462
463 static void qpa_audio_fini (void *opaque)
464 {
465     (void) opaque;
466 }
467
468 struct audio_option qpa_options[] = {
469     {
470         .name  = "SAMPLES",
471         .tag   = AUD_OPT_INT,
472         .valp  = &conf.samples,
473         .descr = "buffer size in samples"
474     },
475     {
476         .name  = "DIVISOR",
477         .tag   = AUD_OPT_INT,
478         .valp  = &conf.divisor,
479         .descr = "threshold divisor"
480     },
481     {
482         .name  = "SERVER",
483         .tag   = AUD_OPT_STR,
484         .valp  = &conf.server,
485         .descr = "server address"
486     },
487     {
488         .name  = "SINK",
489         .tag   = AUD_OPT_STR,
490         .valp  = &conf.sink,
491         .descr = "sink device name"
492     },
493     {
494         .name  = "SOURCE",
495         .tag   = AUD_OPT_STR,
496         .valp  = &conf.source,
497         .descr = "source device name"
498     },
499     { /* End of list */ }
500 };
501
502 static struct audio_pcm_ops qpa_pcm_ops = {
503     .init_out = qpa_init_out,
504     .fini_out = qpa_fini_out,
505     .run_out  = qpa_run_out,
506     .write    = qpa_write,
507     .ctl_out  = qpa_ctl_out,
508
509     .init_in  = qpa_init_in,
510     .fini_in  = qpa_fini_in,
511     .run_in   = qpa_run_in,
512     .read     = qpa_read,
513     .ctl_in   = qpa_ctl_in
514 };
515
516 struct audio_driver pa_audio_driver = {
517     .name           = "pa",
518     .descr          = "http://www.pulseaudio.org/",
519     .options        = qpa_options,
520     .init           = qpa_audio_init,
521     .fini           = qpa_audio_fini,
522     .pcm_ops        = &qpa_pcm_ops,
523     .can_be_default = 0,
524     .max_voices_out = INT_MAX,
525     .max_voices_in  = INT_MAX,
526     .voice_size_out = sizeof (PAVoiceOut),
527     .voice_size_in  = sizeof (PAVoiceIn)
528 };