xref: /openbmc/qemu/audio/paaudio.c (revision 37677d7d)
1 /* public domain */
2 
3 #include "qemu/osdep.h"
4 #include "qemu/module.h"
5 #include "audio.h"
6 #include "qapi/opts-visitor.h"
7 
8 #include <pulse/pulseaudio.h>
9 
10 #define AUDIO_CAP "pulseaudio"
11 #include "audio_int.h"
12 #include "audio_pt_int.h"
13 
14 typedef struct {
15     Audiodev *dev;
16     pa_threaded_mainloop *mainloop;
17     pa_context *context;
18 } paaudio;
19 
20 typedef struct {
21     HWVoiceOut hw;
22     int done;
23     int live;
24     int decr;
25     int rpos;
26     pa_stream *stream;
27     void *pcm_buf;
28     struct audio_pt pt;
29     paaudio *g;
30     int samples;
31 } PAVoiceOut;
32 
33 typedef struct {
34     HWVoiceIn hw;
35     int done;
36     int dead;
37     int incr;
38     int wpos;
39     pa_stream *stream;
40     void *pcm_buf;
41     struct audio_pt pt;
42     const void *read_data;
43     size_t read_index, read_length;
44     paaudio *g;
45     int samples;
46 } PAVoiceIn;
47 
48 static void qpa_audio_fini(void *opaque);
49 
50 static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
51 {
52     va_list ap;
53 
54     va_start (ap, fmt);
55     AUD_vlog (AUDIO_CAP, fmt, ap);
56     va_end (ap);
57 
58     AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err));
59 }
60 
61 #ifndef PA_CONTEXT_IS_GOOD
62 static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x)
63 {
64     return
65         x == PA_CONTEXT_CONNECTING ||
66         x == PA_CONTEXT_AUTHORIZING ||
67         x == PA_CONTEXT_SETTING_NAME ||
68         x == PA_CONTEXT_READY;
69 }
70 #endif
71 
72 #ifndef PA_STREAM_IS_GOOD
73 static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
74 {
75     return
76         x == PA_STREAM_CREATING ||
77         x == PA_STREAM_READY;
78 }
79 #endif
80 
81 #define CHECK_SUCCESS_GOTO(c, rerror, expression, label)        \
82     do {                                                        \
83         if (!(expression)) {                                    \
84             if (rerror) {                                       \
85                 *(rerror) = pa_context_errno ((c)->context);    \
86             }                                                   \
87             goto label;                                         \
88         }                                                       \
89     } while (0)
90 
91 #define CHECK_DEAD_GOTO(c, stream, rerror, label)                       \
92     do {                                                                \
93         if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \
94             !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \
95             if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \
96                 ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \
97                 if (rerror) {                                           \
98                     *(rerror) = pa_context_errno ((c)->context);        \
99                 }                                                       \
100             } else {                                                    \
101                 if (rerror) {                                           \
102                     *(rerror) = PA_ERR_BADSTATE;                        \
103                 }                                                       \
104             }                                                           \
105             goto label;                                                 \
106         }                                                               \
107     } while (0)
108 
109 static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror)
110 {
111     paaudio *g = p->g;
112 
113     pa_threaded_mainloop_lock (g->mainloop);
114 
115     CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
116 
117     while (length > 0) {
118         size_t l;
119 
120         while (!p->read_data) {
121             int r;
122 
123             r = pa_stream_peek (p->stream, &p->read_data, &p->read_length);
124             CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
125 
126             if (!p->read_data) {
127                 pa_threaded_mainloop_wait (g->mainloop);
128                 CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
129             } else {
130                 p->read_index = 0;
131             }
132         }
133 
134         l = p->read_length < length ? p->read_length : length;
135         memcpy (data, (const uint8_t *) p->read_data+p->read_index, l);
136 
137         data = (uint8_t *) data + l;
138         length -= l;
139 
140         p->read_index += l;
141         p->read_length -= l;
142 
143         if (!p->read_length) {
144             int r;
145 
146             r = pa_stream_drop (p->stream);
147             p->read_data = NULL;
148             p->read_length = 0;
149             p->read_index = 0;
150 
151             CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
152         }
153     }
154 
155     pa_threaded_mainloop_unlock (g->mainloop);
156     return 0;
157 
158 unlock_and_fail:
159     pa_threaded_mainloop_unlock (g->mainloop);
160     return -1;
161 }
162 
163 static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror)
164 {
165     paaudio *g = p->g;
166 
167     pa_threaded_mainloop_lock (g->mainloop);
168 
169     CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
170 
171     while (length > 0) {
172         size_t l;
173         int r;
174 
175         while (!(l = pa_stream_writable_size (p->stream))) {
176             pa_threaded_mainloop_wait (g->mainloop);
177             CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
178         }
179 
180         CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail);
181 
182         if (l > length) {
183             l = length;
184         }
185 
186         r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
187         CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail);
188 
189         data = (const uint8_t *) data + l;
190         length -= l;
191     }
192 
193     pa_threaded_mainloop_unlock (g->mainloop);
194     return 0;
195 
196 unlock_and_fail:
197     pa_threaded_mainloop_unlock (g->mainloop);
198     return -1;
199 }
200 
201 static void *qpa_thread_out (void *arg)
202 {
203     PAVoiceOut *pa = arg;
204     HWVoiceOut *hw = &pa->hw;
205 
206     if (audio_pt_lock(&pa->pt, __func__)) {
207         return NULL;
208     }
209 
210     for (;;) {
211         int decr, to_mix, rpos;
212 
213         for (;;) {
214             if (pa->done) {
215                 goto exit;
216             }
217 
218             if (pa->live > 0) {
219                 break;
220             }
221 
222             if (audio_pt_wait(&pa->pt, __func__)) {
223                 goto exit;
224             }
225         }
226 
227         decr = to_mix = audio_MIN(pa->live, pa->samples >> 5);
228         rpos = pa->rpos;
229 
230         if (audio_pt_unlock(&pa->pt, __func__)) {
231             return NULL;
232         }
233 
234         while (to_mix) {
235             int error;
236             int chunk = audio_MIN (to_mix, hw->samples - rpos);
237             struct st_sample *src = hw->mix_buf + rpos;
238 
239             hw->clip (pa->pcm_buf, src, chunk);
240 
241             if (qpa_simple_write (pa, pa->pcm_buf,
242                                   chunk << hw->info.shift, &error) < 0) {
243                 qpa_logerr (error, "pa_simple_write failed\n");
244                 return NULL;
245             }
246 
247             rpos = (rpos + chunk) % hw->samples;
248             to_mix -= chunk;
249         }
250 
251         if (audio_pt_lock(&pa->pt, __func__)) {
252             return NULL;
253         }
254 
255         pa->rpos = rpos;
256         pa->live -= decr;
257         pa->decr += decr;
258     }
259 
260  exit:
261     audio_pt_unlock(&pa->pt, __func__);
262     return NULL;
263 }
264 
265 static int qpa_run_out (HWVoiceOut *hw, int live)
266 {
267     int decr;
268     PAVoiceOut *pa = (PAVoiceOut *) hw;
269 
270     if (audio_pt_lock(&pa->pt, __func__)) {
271         return 0;
272     }
273 
274     decr = audio_MIN (live, pa->decr);
275     pa->decr -= decr;
276     pa->live = live - decr;
277     hw->rpos = pa->rpos;
278     if (pa->live > 0) {
279         audio_pt_unlock_and_signal(&pa->pt, __func__);
280     }
281     else {
282         audio_pt_unlock(&pa->pt, __func__);
283     }
284     return decr;
285 }
286 
287 static int qpa_write (SWVoiceOut *sw, void *buf, int len)
288 {
289     return audio_pcm_sw_write (sw, buf, len);
290 }
291 
292 /* capture */
293 static void *qpa_thread_in (void *arg)
294 {
295     PAVoiceIn *pa = arg;
296     HWVoiceIn *hw = &pa->hw;
297 
298     if (audio_pt_lock(&pa->pt, __func__)) {
299         return NULL;
300     }
301 
302     for (;;) {
303         int incr, to_grab, wpos;
304 
305         for (;;) {
306             if (pa->done) {
307                 goto exit;
308             }
309 
310             if (pa->dead > 0) {
311                 break;
312             }
313 
314             if (audio_pt_wait(&pa->pt, __func__)) {
315                 goto exit;
316             }
317         }
318 
319         incr = to_grab = audio_MIN(pa->dead, pa->samples >> 5);
320         wpos = pa->wpos;
321 
322         if (audio_pt_unlock(&pa->pt, __func__)) {
323             return NULL;
324         }
325 
326         while (to_grab) {
327             int error;
328             int chunk = audio_MIN (to_grab, hw->samples - wpos);
329             void *buf = advance (pa->pcm_buf, wpos);
330 
331             if (qpa_simple_read (pa, buf,
332                                  chunk << hw->info.shift, &error) < 0) {
333                 qpa_logerr (error, "pa_simple_read failed\n");
334                 return NULL;
335             }
336 
337             hw->conv (hw->conv_buf + wpos, buf, chunk);
338             wpos = (wpos + chunk) % hw->samples;
339             to_grab -= chunk;
340         }
341 
342         if (audio_pt_lock(&pa->pt, __func__)) {
343             return NULL;
344         }
345 
346         pa->wpos = wpos;
347         pa->dead -= incr;
348         pa->incr += incr;
349     }
350 
351  exit:
352     audio_pt_unlock(&pa->pt, __func__);
353     return NULL;
354 }
355 
356 static int qpa_run_in (HWVoiceIn *hw)
357 {
358     int live, incr, dead;
359     PAVoiceIn *pa = (PAVoiceIn *) hw;
360 
361     if (audio_pt_lock(&pa->pt, __func__)) {
362         return 0;
363     }
364 
365     live = audio_pcm_hw_get_live_in (hw);
366     dead = hw->samples - live;
367     incr = audio_MIN (dead, pa->incr);
368     pa->incr -= incr;
369     pa->dead = dead - incr;
370     hw->wpos = pa->wpos;
371     if (pa->dead > 0) {
372         audio_pt_unlock_and_signal(&pa->pt, __func__);
373     }
374     else {
375         audio_pt_unlock(&pa->pt, __func__);
376     }
377     return incr;
378 }
379 
380 static int qpa_read (SWVoiceIn *sw, void *buf, int len)
381 {
382     return audio_pcm_sw_read (sw, buf, len);
383 }
384 
385 static pa_sample_format_t audfmt_to_pa (AudioFormat afmt, int endianness)
386 {
387     int format;
388 
389     switch (afmt) {
390     case AUDIO_FORMAT_S8:
391     case AUDIO_FORMAT_U8:
392         format = PA_SAMPLE_U8;
393         break;
394     case AUDIO_FORMAT_S16:
395     case AUDIO_FORMAT_U16:
396         format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
397         break;
398     case AUDIO_FORMAT_S32:
399     case AUDIO_FORMAT_U32:
400         format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
401         break;
402     default:
403         dolog ("Internal logic error: Bad audio format %d\n", afmt);
404         format = PA_SAMPLE_U8;
405         break;
406     }
407     return format;
408 }
409 
410 static AudioFormat pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
411 {
412     switch (fmt) {
413     case PA_SAMPLE_U8:
414         return AUDIO_FORMAT_U8;
415     case PA_SAMPLE_S16BE:
416         *endianness = 1;
417         return AUDIO_FORMAT_S16;
418     case PA_SAMPLE_S16LE:
419         *endianness = 0;
420         return AUDIO_FORMAT_S16;
421     case PA_SAMPLE_S32BE:
422         *endianness = 1;
423         return AUDIO_FORMAT_S32;
424     case PA_SAMPLE_S32LE:
425         *endianness = 0;
426         return AUDIO_FORMAT_S32;
427     default:
428         dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
429         return AUDIO_FORMAT_U8;
430     }
431 }
432 
433 static void context_state_cb (pa_context *c, void *userdata)
434 {
435     paaudio *g = userdata;
436 
437     switch (pa_context_get_state(c)) {
438     case PA_CONTEXT_READY:
439     case PA_CONTEXT_TERMINATED:
440     case PA_CONTEXT_FAILED:
441         pa_threaded_mainloop_signal (g->mainloop, 0);
442         break;
443 
444     case PA_CONTEXT_UNCONNECTED:
445     case PA_CONTEXT_CONNECTING:
446     case PA_CONTEXT_AUTHORIZING:
447     case PA_CONTEXT_SETTING_NAME:
448         break;
449     }
450 }
451 
452 static void stream_state_cb (pa_stream *s, void * userdata)
453 {
454     paaudio *g = userdata;
455 
456     switch (pa_stream_get_state (s)) {
457 
458     case PA_STREAM_READY:
459     case PA_STREAM_FAILED:
460     case PA_STREAM_TERMINATED:
461         pa_threaded_mainloop_signal (g->mainloop, 0);
462         break;
463 
464     case PA_STREAM_UNCONNECTED:
465     case PA_STREAM_CREATING:
466         break;
467     }
468 }
469 
470 static void stream_request_cb (pa_stream *s, size_t length, void *userdata)
471 {
472     paaudio *g = userdata;
473 
474     pa_threaded_mainloop_signal (g->mainloop, 0);
475 }
476 
477 static pa_stream *qpa_simple_new (
478         paaudio *g,
479         const char *name,
480         pa_stream_direction_t dir,
481         const char *dev,
482         const pa_sample_spec *ss,
483         const pa_channel_map *map,
484         const pa_buffer_attr *attr,
485         int *rerror)
486 {
487     int r;
488     pa_stream *stream;
489 
490     pa_threaded_mainloop_lock (g->mainloop);
491 
492     stream = pa_stream_new (g->context, name, ss, map);
493     if (!stream) {
494         goto fail;
495     }
496 
497     pa_stream_set_state_callback (stream, stream_state_cb, g);
498     pa_stream_set_read_callback (stream, stream_request_cb, g);
499     pa_stream_set_write_callback (stream, stream_request_cb, g);
500 
501     if (dir == PA_STREAM_PLAYBACK) {
502         r = pa_stream_connect_playback (stream, dev, attr,
503                                         PA_STREAM_INTERPOLATE_TIMING
504 #ifdef PA_STREAM_ADJUST_LATENCY
505                                         |PA_STREAM_ADJUST_LATENCY
506 #endif
507                                         |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
508     } else {
509         r = pa_stream_connect_record (stream, dev, attr,
510                                       PA_STREAM_INTERPOLATE_TIMING
511 #ifdef PA_STREAM_ADJUST_LATENCY
512                                       |PA_STREAM_ADJUST_LATENCY
513 #endif
514                                       |PA_STREAM_AUTO_TIMING_UPDATE);
515     }
516 
517     if (r < 0) {
518       goto fail;
519     }
520 
521     pa_threaded_mainloop_unlock (g->mainloop);
522 
523     return stream;
524 
525 fail:
526     pa_threaded_mainloop_unlock (g->mainloop);
527 
528     if (stream) {
529         pa_stream_unref (stream);
530     }
531 
532     *rerror = pa_context_errno (g->context);
533 
534     return NULL;
535 }
536 
537 static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
538                         void *drv_opaque)
539 {
540     int error;
541     pa_sample_spec ss;
542     pa_buffer_attr ba;
543     struct audsettings obt_as = *as;
544     PAVoiceOut *pa = (PAVoiceOut *) hw;
545     paaudio *g = pa->g = drv_opaque;
546     AudiodevPaOptions *popts = &g->dev->u.pa;
547     AudiodevPaPerDirectionOptions *ppdo = popts->out;
548 
549     ss.format = audfmt_to_pa (as->fmt, as->endianness);
550     ss.channels = as->nchannels;
551     ss.rate = as->freq;
552 
553     ba.tlength = pa_usec_to_bytes(ppdo->latency, &ss);
554     ba.minreq = -1;
555     ba.maxlength = -1;
556     ba.prebuf = -1;
557 
558     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
559 
560     pa->stream = qpa_simple_new (
561         g,
562         "qemu",
563         PA_STREAM_PLAYBACK,
564         ppdo->has_name ? ppdo->name : NULL,
565         &ss,
566         NULL,                   /* channel map */
567         &ba,                    /* buffering attributes */
568         &error
569         );
570     if (!pa->stream) {
571         qpa_logerr (error, "pa_simple_new for playback failed\n");
572         goto fail1;
573     }
574 
575     audio_pcm_init_info (&hw->info, &obt_as);
576     hw->samples = pa->samples = audio_buffer_samples(
577         qapi_AudiodevPaPerDirectionOptions_base(ppdo),
578         &obt_as, ppdo->buffer_length);
579     pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
580     pa->rpos = hw->rpos;
581     if (!pa->pcm_buf) {
582         dolog ("Could not allocate buffer (%d bytes)\n",
583                hw->samples << hw->info.shift);
584         goto fail2;
585     }
586 
587     if (audio_pt_init(&pa->pt, qpa_thread_out, hw, AUDIO_CAP, __func__)) {
588         goto fail3;
589     }
590 
591     return 0;
592 
593  fail3:
594     g_free (pa->pcm_buf);
595     pa->pcm_buf = NULL;
596  fail2:
597     if (pa->stream) {
598         pa_stream_unref (pa->stream);
599         pa->stream = NULL;
600     }
601  fail1:
602     return -1;
603 }
604 
605 static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
606 {
607     int error;
608     pa_sample_spec ss;
609     pa_buffer_attr ba;
610     struct audsettings obt_as = *as;
611     PAVoiceIn *pa = (PAVoiceIn *) hw;
612     paaudio *g = pa->g = drv_opaque;
613     AudiodevPaOptions *popts = &g->dev->u.pa;
614     AudiodevPaPerDirectionOptions *ppdo = popts->in;
615 
616     ss.format = audfmt_to_pa (as->fmt, as->endianness);
617     ss.channels = as->nchannels;
618     ss.rate = as->freq;
619 
620     ba.fragsize = pa_usec_to_bytes(ppdo->latency, &ss);
621     ba.maxlength = -1;
622     ba.minreq = -1;
623     ba.prebuf = -1;
624 
625     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
626 
627     pa->stream = qpa_simple_new (
628         g,
629         "qemu",
630         PA_STREAM_RECORD,
631         ppdo->has_name ? ppdo->name : NULL,
632         &ss,
633         NULL,                   /* channel map */
634         &ba,                    /* buffering attributes */
635         &error
636         );
637     if (!pa->stream) {
638         qpa_logerr (error, "pa_simple_new for capture failed\n");
639         goto fail1;
640     }
641 
642     audio_pcm_init_info (&hw->info, &obt_as);
643     hw->samples = pa->samples = audio_buffer_samples(
644         qapi_AudiodevPaPerDirectionOptions_base(ppdo),
645         &obt_as, ppdo->buffer_length);
646     pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
647     pa->wpos = hw->wpos;
648     if (!pa->pcm_buf) {
649         dolog ("Could not allocate buffer (%d bytes)\n",
650                hw->samples << hw->info.shift);
651         goto fail2;
652     }
653 
654     if (audio_pt_init(&pa->pt, qpa_thread_in, hw, AUDIO_CAP, __func__)) {
655         goto fail3;
656     }
657 
658     return 0;
659 
660  fail3:
661     g_free (pa->pcm_buf);
662     pa->pcm_buf = NULL;
663  fail2:
664     if (pa->stream) {
665         pa_stream_unref (pa->stream);
666         pa->stream = NULL;
667     }
668  fail1:
669     return -1;
670 }
671 
672 static void qpa_fini_out (HWVoiceOut *hw)
673 {
674     void *ret;
675     PAVoiceOut *pa = (PAVoiceOut *) hw;
676 
677     audio_pt_lock(&pa->pt, __func__);
678     pa->done = 1;
679     audio_pt_unlock_and_signal(&pa->pt, __func__);
680     audio_pt_join(&pa->pt, &ret, __func__);
681 
682     if (pa->stream) {
683         pa_stream_unref (pa->stream);
684         pa->stream = NULL;
685     }
686 
687     audio_pt_fini(&pa->pt, __func__);
688     g_free (pa->pcm_buf);
689     pa->pcm_buf = NULL;
690 }
691 
692 static void qpa_fini_in (HWVoiceIn *hw)
693 {
694     void *ret;
695     PAVoiceIn *pa = (PAVoiceIn *) hw;
696 
697     audio_pt_lock(&pa->pt, __func__);
698     pa->done = 1;
699     audio_pt_unlock_and_signal(&pa->pt, __func__);
700     audio_pt_join(&pa->pt, &ret, __func__);
701 
702     if (pa->stream) {
703         pa_stream_unref (pa->stream);
704         pa->stream = NULL;
705     }
706 
707     audio_pt_fini(&pa->pt, __func__);
708     g_free (pa->pcm_buf);
709     pa->pcm_buf = NULL;
710 }
711 
712 static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
713 {
714     PAVoiceOut *pa = (PAVoiceOut *) hw;
715     pa_operation *op;
716     pa_cvolume v;
717     paaudio *g = pa->g;
718 
719 #ifdef PA_CHECK_VERSION    /* macro is present in 0.9.16+ */
720     pa_cvolume_init (&v);  /* function is present in 0.9.13+ */
721 #endif
722 
723     switch (cmd) {
724     case VOICE_VOLUME:
725         {
726             SWVoiceOut *sw;
727             va_list ap;
728 
729             va_start (ap, cmd);
730             sw = va_arg (ap, SWVoiceOut *);
731             va_end (ap);
732 
733             v.channels = 2;
734             v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
735             v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
736 
737             pa_threaded_mainloop_lock (g->mainloop);
738 
739             op = pa_context_set_sink_input_volume (g->context,
740                 pa_stream_get_index (pa->stream),
741                 &v, NULL, NULL);
742             if (!op)
743                 qpa_logerr (pa_context_errno (g->context),
744                             "set_sink_input_volume() failed\n");
745             else
746                 pa_operation_unref (op);
747 
748             op = pa_context_set_sink_input_mute (g->context,
749                 pa_stream_get_index (pa->stream),
750                sw->vol.mute, NULL, NULL);
751             if (!op) {
752                 qpa_logerr (pa_context_errno (g->context),
753                             "set_sink_input_mute() failed\n");
754             } else {
755                 pa_operation_unref (op);
756             }
757 
758             pa_threaded_mainloop_unlock (g->mainloop);
759         }
760     }
761     return 0;
762 }
763 
764 static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
765 {
766     PAVoiceIn *pa = (PAVoiceIn *) hw;
767     pa_operation *op;
768     pa_cvolume v;
769     paaudio *g = pa->g;
770 
771 #ifdef PA_CHECK_VERSION
772     pa_cvolume_init (&v);
773 #endif
774 
775     switch (cmd) {
776     case VOICE_VOLUME:
777         {
778             SWVoiceIn *sw;
779             va_list ap;
780 
781             va_start (ap, cmd);
782             sw = va_arg (ap, SWVoiceIn *);
783             va_end (ap);
784 
785             v.channels = 2;
786             v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
787             v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
788 
789             pa_threaded_mainloop_lock (g->mainloop);
790 
791             op = pa_context_set_source_output_volume (g->context,
792                 pa_stream_get_index (pa->stream),
793                 &v, NULL, NULL);
794             if (!op) {
795                 qpa_logerr (pa_context_errno (g->context),
796                             "set_source_output_volume() failed\n");
797             } else {
798                 pa_operation_unref(op);
799             }
800 
801             op = pa_context_set_source_output_mute (g->context,
802                 pa_stream_get_index (pa->stream),
803                 sw->vol.mute, NULL, NULL);
804             if (!op) {
805                 qpa_logerr (pa_context_errno (g->context),
806                             "set_source_output_mute() failed\n");
807             } else {
808                 pa_operation_unref (op);
809             }
810 
811             pa_threaded_mainloop_unlock (g->mainloop);
812         }
813     }
814     return 0;
815 }
816 
817 static int qpa_validate_per_direction_opts(Audiodev *dev,
818                                            AudiodevPaPerDirectionOptions *pdo)
819 {
820     if (!pdo->has_buffer_length) {
821         pdo->has_buffer_length = true;
822         pdo->buffer_length = 46440;
823     }
824     if (!pdo->has_latency) {
825         pdo->has_latency = true;
826         pdo->latency = 15000;
827     }
828     return 1;
829 }
830 
831 static void *qpa_audio_init(Audiodev *dev)
832 {
833     paaudio *g;
834     AudiodevPaOptions *popts = &dev->u.pa;
835     const char *server;
836 
837     if (!popts->has_server) {
838         char pidfile[64];
839         char *runtime;
840         struct stat st;
841 
842         runtime = getenv("XDG_RUNTIME_DIR");
843         if (!runtime) {
844             return NULL;
845         }
846         snprintf(pidfile, sizeof(pidfile), "%s/pulse/pid", runtime);
847         if (stat(pidfile, &st) != 0) {
848             return NULL;
849         }
850     }
851 
852     assert(dev->driver == AUDIODEV_DRIVER_PA);
853 
854     g = g_malloc(sizeof(paaudio));
855     server = popts->has_server ? popts->server : NULL;
856 
857     if (!qpa_validate_per_direction_opts(dev, popts->in)) {
858         goto fail;
859     }
860     if (!qpa_validate_per_direction_opts(dev, popts->out)) {
861         goto fail;
862     }
863 
864     g->dev = dev;
865     g->mainloop = NULL;
866     g->context = NULL;
867 
868     g->mainloop = pa_threaded_mainloop_new ();
869     if (!g->mainloop) {
870         goto fail;
871     }
872 
873     g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop),
874                                  server);
875     if (!g->context) {
876         goto fail;
877     }
878 
879     pa_context_set_state_callback (g->context, context_state_cb, g);
880 
881     if (pa_context_connect(g->context, server, 0, NULL) < 0) {
882         qpa_logerr (pa_context_errno (g->context),
883                     "pa_context_connect() failed\n");
884         goto fail;
885     }
886 
887     pa_threaded_mainloop_lock (g->mainloop);
888 
889     if (pa_threaded_mainloop_start (g->mainloop) < 0) {
890         goto unlock_and_fail;
891     }
892 
893     for (;;) {
894         pa_context_state_t state;
895 
896         state = pa_context_get_state (g->context);
897 
898         if (state == PA_CONTEXT_READY) {
899             break;
900         }
901 
902         if (!PA_CONTEXT_IS_GOOD (state)) {
903             qpa_logerr (pa_context_errno (g->context),
904                         "Wrong context state\n");
905             goto unlock_and_fail;
906         }
907 
908         /* Wait until the context is ready */
909         pa_threaded_mainloop_wait (g->mainloop);
910     }
911 
912     pa_threaded_mainloop_unlock (g->mainloop);
913 
914     return g;
915 
916 unlock_and_fail:
917     pa_threaded_mainloop_unlock (g->mainloop);
918 fail:
919     AUD_log (AUDIO_CAP, "Failed to initialize PA context");
920     qpa_audio_fini(g);
921     return NULL;
922 }
923 
924 static void qpa_audio_fini (void *opaque)
925 {
926     paaudio *g = opaque;
927 
928     if (g->mainloop) {
929         pa_threaded_mainloop_stop (g->mainloop);
930     }
931 
932     if (g->context) {
933         pa_context_disconnect (g->context);
934         pa_context_unref (g->context);
935     }
936 
937     if (g->mainloop) {
938         pa_threaded_mainloop_free (g->mainloop);
939     }
940 
941     g_free(g);
942 }
943 
944 static struct audio_pcm_ops qpa_pcm_ops = {
945     .init_out = qpa_init_out,
946     .fini_out = qpa_fini_out,
947     .run_out  = qpa_run_out,
948     .write    = qpa_write,
949     .ctl_out  = qpa_ctl_out,
950 
951     .init_in  = qpa_init_in,
952     .fini_in  = qpa_fini_in,
953     .run_in   = qpa_run_in,
954     .read     = qpa_read,
955     .ctl_in   = qpa_ctl_in
956 };
957 
958 static struct audio_driver pa_audio_driver = {
959     .name           = "pa",
960     .descr          = "http://www.pulseaudio.org/",
961     .init           = qpa_audio_init,
962     .fini           = qpa_audio_fini,
963     .pcm_ops        = &qpa_pcm_ops,
964     .can_be_default = 1,
965     .max_voices_out = INT_MAX,
966     .max_voices_in  = INT_MAX,
967     .voice_size_out = sizeof (PAVoiceOut),
968     .voice_size_in  = sizeof (PAVoiceIn),
969     .ctl_caps       = VOICE_VOLUME_CAP
970 };
971 
972 static void register_audio_pa(void)
973 {
974     audio_driver_register(&pa_audio_driver);
975 }
976 type_init(register_audio_pa);
977