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