xref: /openbmc/qemu/audio/paaudio.c (revision ae3c12a0)
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     ba.tlength = pa_usec_to_bytes(ppdo->latency, &ss);
553     ba.minreq = -1;
554     ba.maxlength = -1;
555     ba.prebuf = -1;
556 
557     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
558 
559     pa->stream = qpa_simple_new (
560         g,
561         "qemu",
562         PA_STREAM_PLAYBACK,
563         ppdo->has_name ? ppdo->name : NULL,
564         &ss,
565         NULL,                   /* channel map */
566         &ba,                    /* buffering attributes */
567         &error
568         );
569     if (!pa->stream) {
570         qpa_logerr (error, "pa_simple_new for playback failed\n");
571         goto fail1;
572     }
573 
574     audio_pcm_init_info (&hw->info, &obt_as);
575     hw->samples = pa->samples = audio_buffer_samples(
576         qapi_AudiodevPaPerDirectionOptions_base(ppdo),
577         &obt_as, ppdo->buffer_length);
578     pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
579     pa->rpos = hw->rpos;
580     if (!pa->pcm_buf) {
581         dolog ("Could not allocate buffer (%d bytes)\n",
582                hw->samples << hw->info.shift);
583         goto fail2;
584     }
585 
586     if (audio_pt_init(&pa->pt, qpa_thread_out, hw, AUDIO_CAP, __func__)) {
587         goto fail3;
588     }
589 
590     return 0;
591 
592  fail3:
593     g_free (pa->pcm_buf);
594     pa->pcm_buf = NULL;
595  fail2:
596     if (pa->stream) {
597         pa_stream_unref (pa->stream);
598         pa->stream = NULL;
599     }
600  fail1:
601     return -1;
602 }
603 
604 static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
605 {
606     int error;
607     pa_sample_spec ss;
608     pa_buffer_attr ba;
609     struct audsettings obt_as = *as;
610     PAVoiceIn *pa = (PAVoiceIn *) hw;
611     paaudio *g = pa->g = drv_opaque;
612     AudiodevPaOptions *popts = &g->dev->u.pa;
613     AudiodevPaPerDirectionOptions *ppdo = popts->in;
614 
615     ss.format = audfmt_to_pa (as->fmt, as->endianness);
616     ss.channels = as->nchannels;
617     ss.rate = as->freq;
618 
619     ba.fragsize = pa_usec_to_bytes(ppdo->latency, &ss);
620     ba.maxlength = -1;
621     ba.minreq = -1;
622     ba.prebuf = -1;
623 
624     obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
625 
626     pa->stream = qpa_simple_new (
627         g,
628         "qemu",
629         PA_STREAM_RECORD,
630         ppdo->has_name ? ppdo->name : NULL,
631         &ss,
632         NULL,                   /* channel map */
633         &ba,                    /* buffering attributes */
634         &error
635         );
636     if (!pa->stream) {
637         qpa_logerr (error, "pa_simple_new for capture failed\n");
638         goto fail1;
639     }
640 
641     audio_pcm_init_info (&hw->info, &obt_as);
642     hw->samples = pa->samples = audio_buffer_samples(
643         qapi_AudiodevPaPerDirectionOptions_base(ppdo),
644         &obt_as, ppdo->buffer_length);
645     pa->pcm_buf = audio_calloc(__func__, hw->samples, 1 << hw->info.shift);
646     pa->wpos = hw->wpos;
647     if (!pa->pcm_buf) {
648         dolog ("Could not allocate buffer (%d bytes)\n",
649                hw->samples << hw->info.shift);
650         goto fail2;
651     }
652 
653     if (audio_pt_init(&pa->pt, qpa_thread_in, hw, AUDIO_CAP, __func__)) {
654         goto fail3;
655     }
656 
657     return 0;
658 
659  fail3:
660     g_free (pa->pcm_buf);
661     pa->pcm_buf = NULL;
662  fail2:
663     if (pa->stream) {
664         pa_stream_unref (pa->stream);
665         pa->stream = NULL;
666     }
667  fail1:
668     return -1;
669 }
670 
671 static void qpa_fini_out (HWVoiceOut *hw)
672 {
673     void *ret;
674     PAVoiceOut *pa = (PAVoiceOut *) hw;
675 
676     audio_pt_lock(&pa->pt, __func__);
677     pa->done = 1;
678     audio_pt_unlock_and_signal(&pa->pt, __func__);
679     audio_pt_join(&pa->pt, &ret, __func__);
680 
681     if (pa->stream) {
682         pa_stream_unref (pa->stream);
683         pa->stream = NULL;
684     }
685 
686     audio_pt_fini(&pa->pt, __func__);
687     g_free (pa->pcm_buf);
688     pa->pcm_buf = NULL;
689 }
690 
691 static void qpa_fini_in (HWVoiceIn *hw)
692 {
693     void *ret;
694     PAVoiceIn *pa = (PAVoiceIn *) hw;
695 
696     audio_pt_lock(&pa->pt, __func__);
697     pa->done = 1;
698     audio_pt_unlock_and_signal(&pa->pt, __func__);
699     audio_pt_join(&pa->pt, &ret, __func__);
700 
701     if (pa->stream) {
702         pa_stream_unref (pa->stream);
703         pa->stream = NULL;
704     }
705 
706     audio_pt_fini(&pa->pt, __func__);
707     g_free (pa->pcm_buf);
708     pa->pcm_buf = NULL;
709 }
710 
711 static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
712 {
713     PAVoiceOut *pa = (PAVoiceOut *) hw;
714     pa_operation *op;
715     pa_cvolume v;
716     paaudio *g = pa->g;
717 
718 #ifdef PA_CHECK_VERSION    /* macro is present in 0.9.16+ */
719     pa_cvolume_init (&v);  /* function is present in 0.9.13+ */
720 #endif
721 
722     switch (cmd) {
723     case VOICE_VOLUME:
724         {
725             SWVoiceOut *sw;
726             va_list ap;
727 
728             va_start (ap, cmd);
729             sw = va_arg (ap, SWVoiceOut *);
730             va_end (ap);
731 
732             v.channels = 2;
733             v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
734             v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
735 
736             pa_threaded_mainloop_lock (g->mainloop);
737 
738             op = pa_context_set_sink_input_volume (g->context,
739                 pa_stream_get_index (pa->stream),
740                 &v, NULL, NULL);
741             if (!op)
742                 qpa_logerr (pa_context_errno (g->context),
743                             "set_sink_input_volume() failed\n");
744             else
745                 pa_operation_unref (op);
746 
747             op = pa_context_set_sink_input_mute (g->context,
748                 pa_stream_get_index (pa->stream),
749                sw->vol.mute, NULL, NULL);
750             if (!op) {
751                 qpa_logerr (pa_context_errno (g->context),
752                             "set_sink_input_mute() failed\n");
753             } else {
754                 pa_operation_unref (op);
755             }
756 
757             pa_threaded_mainloop_unlock (g->mainloop);
758         }
759     }
760     return 0;
761 }
762 
763 static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
764 {
765     PAVoiceIn *pa = (PAVoiceIn *) hw;
766     pa_operation *op;
767     pa_cvolume v;
768     paaudio *g = pa->g;
769 
770 #ifdef PA_CHECK_VERSION
771     pa_cvolume_init (&v);
772 #endif
773 
774     switch (cmd) {
775     case VOICE_VOLUME:
776         {
777             SWVoiceIn *sw;
778             va_list ap;
779 
780             va_start (ap, cmd);
781             sw = va_arg (ap, SWVoiceIn *);
782             va_end (ap);
783 
784             v.channels = 2;
785             v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
786             v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
787 
788             pa_threaded_mainloop_lock (g->mainloop);
789 
790             op = pa_context_set_source_output_volume (g->context,
791                 pa_stream_get_index (pa->stream),
792                 &v, NULL, NULL);
793             if (!op) {
794                 qpa_logerr (pa_context_errno (g->context),
795                             "set_source_output_volume() failed\n");
796             } else {
797                 pa_operation_unref(op);
798             }
799 
800             op = pa_context_set_source_output_mute (g->context,
801                 pa_stream_get_index (pa->stream),
802                 sw->vol.mute, NULL, NULL);
803             if (!op) {
804                 qpa_logerr (pa_context_errno (g->context),
805                             "set_source_output_mute() failed\n");
806             } else {
807                 pa_operation_unref (op);
808             }
809 
810             pa_threaded_mainloop_unlock (g->mainloop);
811         }
812     }
813     return 0;
814 }
815 
816 static int qpa_validate_per_direction_opts(Audiodev *dev,
817                                            AudiodevPaPerDirectionOptions *pdo)
818 {
819     if (!pdo->has_buffer_length) {
820         pdo->has_buffer_length = true;
821         pdo->buffer_length = 46440;
822     }
823     if (!pdo->has_latency) {
824         pdo->has_latency = true;
825         pdo->latency = 15000;
826     }
827     return 1;
828 }
829 
830 static void *qpa_audio_init(Audiodev *dev)
831 {
832     paaudio *g;
833     AudiodevPaOptions *popts = &dev->u.pa;
834     const char *server;
835 
836     if (!popts->has_server) {
837         char pidfile[64];
838         char *runtime;
839         struct stat st;
840 
841         runtime = getenv("XDG_RUNTIME_DIR");
842         if (!runtime) {
843             return NULL;
844         }
845         snprintf(pidfile, sizeof(pidfile), "%s/pulse/pid", runtime);
846         if (stat(pidfile, &st) != 0) {
847             return NULL;
848         }
849     }
850 
851     assert(dev->driver == AUDIODEV_DRIVER_PA);
852 
853     g = g_malloc(sizeof(paaudio));
854     server = popts->has_server ? popts->server : NULL;
855 
856     if (!qpa_validate_per_direction_opts(dev, popts->in)) {
857         goto fail;
858     }
859     if (!qpa_validate_per_direction_opts(dev, popts->out)) {
860         goto fail;
861     }
862 
863     g->dev = dev;
864     g->mainloop = NULL;
865     g->context = NULL;
866 
867     g->mainloop = pa_threaded_mainloop_new ();
868     if (!g->mainloop) {
869         goto fail;
870     }
871 
872     g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop),
873                                  server);
874     if (!g->context) {
875         goto fail;
876     }
877 
878     pa_context_set_state_callback (g->context, context_state_cb, g);
879 
880     if (pa_context_connect(g->context, server, 0, NULL) < 0) {
881         qpa_logerr (pa_context_errno (g->context),
882                     "pa_context_connect() failed\n");
883         goto fail;
884     }
885 
886     pa_threaded_mainloop_lock (g->mainloop);
887 
888     if (pa_threaded_mainloop_start (g->mainloop) < 0) {
889         goto unlock_and_fail;
890     }
891 
892     for (;;) {
893         pa_context_state_t state;
894 
895         state = pa_context_get_state (g->context);
896 
897         if (state == PA_CONTEXT_READY) {
898             break;
899         }
900 
901         if (!PA_CONTEXT_IS_GOOD (state)) {
902             qpa_logerr (pa_context_errno (g->context),
903                         "Wrong context state\n");
904             goto unlock_and_fail;
905         }
906 
907         /* Wait until the context is ready */
908         pa_threaded_mainloop_wait (g->mainloop);
909     }
910 
911     pa_threaded_mainloop_unlock (g->mainloop);
912 
913     return g;
914 
915 unlock_and_fail:
916     pa_threaded_mainloop_unlock (g->mainloop);
917 fail:
918     AUD_log (AUDIO_CAP, "Failed to initialize PA context");
919     qpa_audio_fini(g);
920     return NULL;
921 }
922 
923 static void qpa_audio_fini (void *opaque)
924 {
925     paaudio *g = opaque;
926 
927     if (g->mainloop) {
928         pa_threaded_mainloop_stop (g->mainloop);
929     }
930 
931     if (g->context) {
932         pa_context_disconnect (g->context);
933         pa_context_unref (g->context);
934     }
935 
936     if (g->mainloop) {
937         pa_threaded_mainloop_free (g->mainloop);
938     }
939 
940     g_free(g);
941 }
942 
943 static struct audio_pcm_ops qpa_pcm_ops = {
944     .init_out = qpa_init_out,
945     .fini_out = qpa_fini_out,
946     .run_out  = qpa_run_out,
947     .write    = qpa_write,
948     .ctl_out  = qpa_ctl_out,
949 
950     .init_in  = qpa_init_in,
951     .fini_in  = qpa_fini_in,
952     .run_in   = qpa_run_in,
953     .read     = qpa_read,
954     .ctl_in   = qpa_ctl_in
955 };
956 
957 static struct audio_driver pa_audio_driver = {
958     .name           = "pa",
959     .descr          = "http://www.pulseaudio.org/",
960     .init           = qpa_audio_init,
961     .fini           = qpa_audio_fini,
962     .pcm_ops        = &qpa_pcm_ops,
963     .can_be_default = 1,
964     .max_voices_out = INT_MAX,
965     .max_voices_in  = INT_MAX,
966     .voice_size_out = sizeof (PAVoiceOut),
967     .voice_size_in  = sizeof (PAVoiceIn),
968     .ctl_caps       = VOICE_VOLUME_CAP
969 };
970 
971 static void register_audio_pa(void)
972 {
973     audio_driver_register(&pa_audio_driver);
974 }
975 type_init(register_audio_pa);
976