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