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