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