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