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