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