virtio-rng-s390: add properties.
[qemu/agraf.git] / audio / paaudio.c
blob8b69778ad96dedf6b66dc292bf3893c3d06d1ca2
1 /* public domain */
2 #include "qemu-common.h"
3 #include "audio.h"
5 #include <pulse/pulseaudio.h>
7 #define AUDIO_CAP "pulseaudio"
8 #include "audio_int.h"
9 #include "audio_pt_int.h"
11 typedef struct {
12 HWVoiceOut hw;
13 int done;
14 int live;
15 int decr;
16 int rpos;
17 pa_stream *stream;
18 void *pcm_buf;
19 struct audio_pt pt;
20 } PAVoiceOut;
22 typedef struct {
23 HWVoiceIn hw;
24 int done;
25 int dead;
26 int incr;
27 int wpos;
28 pa_stream *stream;
29 void *pcm_buf;
30 struct audio_pt pt;
31 const void *read_data;
32 size_t read_index, read_length;
33 } PAVoiceIn;
35 typedef struct {
36 int samples;
37 char *server;
38 char *sink;
39 char *source;
40 pa_threaded_mainloop *mainloop;
41 pa_context *context;
42 } paaudio;
44 static paaudio glob_paaudio = {
45 .samples = 4096,
48 static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...)
50 va_list ap;
52 va_start (ap, fmt);
53 AUD_vlog (AUDIO_CAP, fmt, ap);
54 va_end (ap);
56 AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err));
59 #ifndef PA_CONTEXT_IS_GOOD
60 static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x)
62 return
63 x == PA_CONTEXT_CONNECTING ||
64 x == PA_CONTEXT_AUTHORIZING ||
65 x == PA_CONTEXT_SETTING_NAME ||
66 x == PA_CONTEXT_READY;
68 #endif
70 #ifndef PA_STREAM_IS_GOOD
71 static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x)
73 return
74 x == PA_STREAM_CREATING ||
75 x == PA_STREAM_READY;
77 #endif
79 #define CHECK_SUCCESS_GOTO(c, rerror, expression, label) \
80 do { \
81 if (!(expression)) { \
82 if (rerror) { \
83 *(rerror) = pa_context_errno ((c)->context); \
84 } \
85 goto label; \
86 } \
87 } while (0);
89 #define CHECK_DEAD_GOTO(c, stream, rerror, label) \
90 do { \
91 if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \
92 !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \
93 if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \
94 ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \
95 if (rerror) { \
96 *(rerror) = pa_context_errno ((c)->context); \
97 } \
98 } else { \
99 if (rerror) { \
100 *(rerror) = PA_ERR_BADSTATE; \
103 goto label; \
105 } while (0);
107 static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror)
109 paaudio *g = &glob_paaudio;
111 pa_threaded_mainloop_lock (g->mainloop);
113 CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
115 while (length > 0) {
116 size_t l;
118 while (!p->read_data) {
119 int r;
121 r = pa_stream_peek (p->stream, &p->read_data, &p->read_length);
122 CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
124 if (!p->read_data) {
125 pa_threaded_mainloop_wait (g->mainloop);
126 CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
127 } else {
128 p->read_index = 0;
132 l = p->read_length < length ? p->read_length : length;
133 memcpy (data, (const uint8_t *) p->read_data+p->read_index, l);
135 data = (uint8_t *) data + l;
136 length -= l;
138 p->read_index += l;
139 p->read_length -= l;
141 if (!p->read_length) {
142 int r;
144 r = pa_stream_drop (p->stream);
145 p->read_data = NULL;
146 p->read_length = 0;
147 p->read_index = 0;
149 CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail);
153 pa_threaded_mainloop_unlock (g->mainloop);
154 return 0;
156 unlock_and_fail:
157 pa_threaded_mainloop_unlock (g->mainloop);
158 return -1;
161 static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror)
163 paaudio *g = &glob_paaudio;
165 pa_threaded_mainloop_lock (g->mainloop);
167 CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
169 while (length > 0) {
170 size_t l;
171 int r;
173 while (!(l = pa_stream_writable_size (p->stream))) {
174 pa_threaded_mainloop_wait (g->mainloop);
175 CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail);
178 CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail);
180 if (l > length) {
181 l = length;
184 r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
185 CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail);
187 data = (const uint8_t *) data + l;
188 length -= l;
191 pa_threaded_mainloop_unlock (g->mainloop);
192 return 0;
194 unlock_and_fail:
195 pa_threaded_mainloop_unlock (g->mainloop);
196 return -1;
199 static void *qpa_thread_out (void *arg)
201 PAVoiceOut *pa = arg;
202 HWVoiceOut *hw = &pa->hw;
204 if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
205 return NULL;
208 for (;;) {
209 int decr, to_mix, rpos;
211 for (;;) {
212 if (pa->done) {
213 goto exit;
216 if (pa->live > 0) {
217 break;
220 if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
221 goto exit;
225 decr = to_mix = audio_MIN (pa->live, glob_paaudio.samples >> 2);
226 rpos = pa->rpos;
228 if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
229 return NULL;
232 while (to_mix) {
233 int error;
234 int chunk = audio_MIN (to_mix, hw->samples - rpos);
235 struct st_sample *src = hw->mix_buf + rpos;
237 hw->clip (pa->pcm_buf, src, chunk);
239 if (qpa_simple_write (pa, pa->pcm_buf,
240 chunk << hw->info.shift, &error) < 0) {
241 qpa_logerr (error, "pa_simple_write failed\n");
242 return NULL;
245 rpos = (rpos + chunk) % hw->samples;
246 to_mix -= chunk;
249 if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
250 return NULL;
253 pa->rpos = rpos;
254 pa->live -= decr;
255 pa->decr += decr;
258 exit:
259 audio_pt_unlock (&pa->pt, AUDIO_FUNC);
260 return NULL;
263 static int qpa_run_out (HWVoiceOut *hw, int live)
265 int decr;
266 PAVoiceOut *pa = (PAVoiceOut *) hw;
268 if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
269 return 0;
272 decr = audio_MIN (live, pa->decr);
273 pa->decr -= decr;
274 pa->live = live - decr;
275 hw->rpos = pa->rpos;
276 if (pa->live > 0) {
277 audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
279 else {
280 audio_pt_unlock (&pa->pt, AUDIO_FUNC);
282 return decr;
285 static int qpa_write (SWVoiceOut *sw, void *buf, int len)
287 return audio_pcm_sw_write (sw, buf, len);
290 /* capture */
291 static void *qpa_thread_in (void *arg)
293 PAVoiceIn *pa = arg;
294 HWVoiceIn *hw = &pa->hw;
296 if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
297 return NULL;
300 for (;;) {
301 int incr, to_grab, wpos;
303 for (;;) {
304 if (pa->done) {
305 goto exit;
308 if (pa->dead > 0) {
309 break;
312 if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) {
313 goto exit;
317 incr = to_grab = audio_MIN (pa->dead, glob_paaudio.samples >> 2);
318 wpos = pa->wpos;
320 if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) {
321 return NULL;
324 while (to_grab) {
325 int error;
326 int chunk = audio_MIN (to_grab, hw->samples - wpos);
327 void *buf = advance (pa->pcm_buf, wpos);
329 if (qpa_simple_read (pa, buf,
330 chunk << hw->info.shift, &error) < 0) {
331 qpa_logerr (error, "pa_simple_read failed\n");
332 return NULL;
335 hw->conv (hw->conv_buf + wpos, buf, chunk);
336 wpos = (wpos + chunk) % hw->samples;
337 to_grab -= chunk;
340 if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
341 return NULL;
344 pa->wpos = wpos;
345 pa->dead -= incr;
346 pa->incr += incr;
349 exit:
350 audio_pt_unlock (&pa->pt, AUDIO_FUNC);
351 return NULL;
354 static int qpa_run_in (HWVoiceIn *hw)
356 int live, incr, dead;
357 PAVoiceIn *pa = (PAVoiceIn *) hw;
359 if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) {
360 return 0;
363 live = audio_pcm_hw_get_live_in (hw);
364 dead = hw->samples - live;
365 incr = audio_MIN (dead, pa->incr);
366 pa->incr -= incr;
367 pa->dead = dead - incr;
368 hw->wpos = pa->wpos;
369 if (pa->dead > 0) {
370 audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
372 else {
373 audio_pt_unlock (&pa->pt, AUDIO_FUNC);
375 return incr;
378 static int qpa_read (SWVoiceIn *sw, void *buf, int len)
380 return audio_pcm_sw_read (sw, buf, len);
383 static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)
385 int format;
387 switch (afmt) {
388 case AUD_FMT_S8:
389 case AUD_FMT_U8:
390 format = PA_SAMPLE_U8;
391 break;
392 case AUD_FMT_S16:
393 case AUD_FMT_U16:
394 format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE;
395 break;
396 case AUD_FMT_S32:
397 case AUD_FMT_U32:
398 format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
399 break;
400 default:
401 dolog ("Internal logic error: Bad audio format %d\n", afmt);
402 format = PA_SAMPLE_U8;
403 break;
405 return format;
408 static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
410 switch (fmt) {
411 case PA_SAMPLE_U8:
412 return AUD_FMT_U8;
413 case PA_SAMPLE_S16BE:
414 *endianness = 1;
415 return AUD_FMT_S16;
416 case PA_SAMPLE_S16LE:
417 *endianness = 0;
418 return AUD_FMT_S16;
419 case PA_SAMPLE_S32BE:
420 *endianness = 1;
421 return AUD_FMT_S32;
422 case PA_SAMPLE_S32LE:
423 *endianness = 0;
424 return AUD_FMT_S32;
425 default:
426 dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
427 return AUD_FMT_U8;
431 static void context_state_cb (pa_context *c, void *userdata)
433 paaudio *g = &glob_paaudio;
435 switch (pa_context_get_state(c)) {
436 case PA_CONTEXT_READY:
437 case PA_CONTEXT_TERMINATED:
438 case PA_CONTEXT_FAILED:
439 pa_threaded_mainloop_signal (g->mainloop, 0);
440 break;
442 case PA_CONTEXT_UNCONNECTED:
443 case PA_CONTEXT_CONNECTING:
444 case PA_CONTEXT_AUTHORIZING:
445 case PA_CONTEXT_SETTING_NAME:
446 break;
450 static void stream_state_cb (pa_stream *s, void * userdata)
452 paaudio *g = &glob_paaudio;
454 switch (pa_stream_get_state (s)) {
456 case PA_STREAM_READY:
457 case PA_STREAM_FAILED:
458 case PA_STREAM_TERMINATED:
459 pa_threaded_mainloop_signal (g->mainloop, 0);
460 break;
462 case PA_STREAM_UNCONNECTED:
463 case PA_STREAM_CREATING:
464 break;
468 static void stream_request_cb (pa_stream *s, size_t length, void *userdata)
470 paaudio *g = &glob_paaudio;
472 pa_threaded_mainloop_signal (g->mainloop, 0);
475 static pa_stream *qpa_simple_new (
476 const char *server,
477 const char *name,
478 pa_stream_direction_t dir,
479 const char *dev,
480 const char *stream_name,
481 const pa_sample_spec *ss,
482 const pa_channel_map *map,
483 const pa_buffer_attr *attr,
484 int *rerror)
486 paaudio *g = &glob_paaudio;
487 int r;
488 pa_stream *stream;
490 pa_threaded_mainloop_lock (g->mainloop);
492 stream = pa_stream_new (g->context, name, ss, map);
493 if (!stream) {
494 goto fail;
497 pa_stream_set_state_callback (stream, stream_state_cb, g);
498 pa_stream_set_read_callback (stream, stream_request_cb, g);
499 pa_stream_set_write_callback (stream, stream_request_cb, g);
501 if (dir == PA_STREAM_PLAYBACK) {
502 r = pa_stream_connect_playback (stream, dev, attr,
503 PA_STREAM_INTERPOLATE_TIMING
504 #ifdef PA_STREAM_ADJUST_LATENCY
505 |PA_STREAM_ADJUST_LATENCY
506 #endif
507 |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
508 } else {
509 r = pa_stream_connect_record (stream, dev, attr,
510 PA_STREAM_INTERPOLATE_TIMING
511 #ifdef PA_STREAM_ADJUST_LATENCY
512 |PA_STREAM_ADJUST_LATENCY
513 #endif
514 |PA_STREAM_AUTO_TIMING_UPDATE);
517 if (r < 0) {
518 goto fail;
521 pa_threaded_mainloop_unlock (g->mainloop);
523 return stream;
525 fail:
526 pa_threaded_mainloop_unlock (g->mainloop);
528 if (stream) {
529 pa_stream_unref (stream);
532 *rerror = pa_context_errno (g->context);
534 return NULL;
537 static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as)
539 int error;
540 static pa_sample_spec ss;
541 static pa_buffer_attr ba;
542 struct audsettings obt_as = *as;
543 PAVoiceOut *pa = (PAVoiceOut *) hw;
545 ss.format = audfmt_to_pa (as->fmt, as->endianness);
546 ss.channels = as->nchannels;
547 ss.rate = as->freq;
550 * qemu audio tick runs at 250 Hz (by default), so processing
551 * data chunks worth 4 ms of sound should be a good fit.
553 ba.tlength = pa_usec_to_bytes (4 * 1000, &ss);
554 ba.minreq = pa_usec_to_bytes (2 * 1000, &ss);
555 ba.maxlength = -1;
556 ba.prebuf = -1;
558 obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
560 pa->stream = qpa_simple_new (
561 glob_paaudio.server,
562 "qemu",
563 PA_STREAM_PLAYBACK,
564 glob_paaudio.sink,
565 "pcm.playback",
566 &ss,
567 NULL, /* channel map */
568 &ba, /* buffering attributes */
569 &error
571 if (!pa->stream) {
572 qpa_logerr (error, "pa_simple_new for playback failed\n");
573 goto fail1;
576 audio_pcm_init_info (&hw->info, &obt_as);
577 hw->samples = glob_paaudio.samples;
578 pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
579 pa->rpos = hw->rpos;
580 if (!pa->pcm_buf) {
581 dolog ("Could not allocate buffer (%d bytes)\n",
582 hw->samples << hw->info.shift);
583 goto fail2;
586 if (audio_pt_init (&pa->pt, qpa_thread_out, hw, AUDIO_CAP, AUDIO_FUNC)) {
587 goto fail3;
590 return 0;
592 fail3:
593 g_free (pa->pcm_buf);
594 pa->pcm_buf = NULL;
595 fail2:
596 if (pa->stream) {
597 pa_stream_unref (pa->stream);
598 pa->stream = NULL;
600 fail1:
601 return -1;
604 static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as)
606 int error;
607 static pa_sample_spec ss;
608 struct audsettings obt_as = *as;
609 PAVoiceIn *pa = (PAVoiceIn *) hw;
611 ss.format = audfmt_to_pa (as->fmt, as->endianness);
612 ss.channels = as->nchannels;
613 ss.rate = as->freq;
615 obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness);
617 pa->stream = qpa_simple_new (
618 glob_paaudio.server,
619 "qemu",
620 PA_STREAM_RECORD,
621 glob_paaudio.source,
622 "pcm.capture",
623 &ss,
624 NULL, /* channel map */
625 NULL, /* buffering attributes */
626 &error
628 if (!pa->stream) {
629 qpa_logerr (error, "pa_simple_new for capture failed\n");
630 goto fail1;
633 audio_pcm_init_info (&hw->info, &obt_as);
634 hw->samples = glob_paaudio.samples;
635 pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
636 pa->wpos = hw->wpos;
637 if (!pa->pcm_buf) {
638 dolog ("Could not allocate buffer (%d bytes)\n",
639 hw->samples << hw->info.shift);
640 goto fail2;
643 if (audio_pt_init (&pa->pt, qpa_thread_in, hw, AUDIO_CAP, AUDIO_FUNC)) {
644 goto fail3;
647 return 0;
649 fail3:
650 g_free (pa->pcm_buf);
651 pa->pcm_buf = NULL;
652 fail2:
653 if (pa->stream) {
654 pa_stream_unref (pa->stream);
655 pa->stream = NULL;
657 fail1:
658 return -1;
661 static void qpa_fini_out (HWVoiceOut *hw)
663 void *ret;
664 PAVoiceOut *pa = (PAVoiceOut *) hw;
666 audio_pt_lock (&pa->pt, AUDIO_FUNC);
667 pa->done = 1;
668 audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
669 audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
671 if (pa->stream) {
672 pa_stream_unref (pa->stream);
673 pa->stream = NULL;
676 audio_pt_fini (&pa->pt, AUDIO_FUNC);
677 g_free (pa->pcm_buf);
678 pa->pcm_buf = NULL;
681 static void qpa_fini_in (HWVoiceIn *hw)
683 void *ret;
684 PAVoiceIn *pa = (PAVoiceIn *) hw;
686 audio_pt_lock (&pa->pt, AUDIO_FUNC);
687 pa->done = 1;
688 audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC);
689 audio_pt_join (&pa->pt, &ret, AUDIO_FUNC);
691 if (pa->stream) {
692 pa_stream_unref (pa->stream);
693 pa->stream = NULL;
696 audio_pt_fini (&pa->pt, AUDIO_FUNC);
697 g_free (pa->pcm_buf);
698 pa->pcm_buf = NULL;
701 static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...)
703 PAVoiceOut *pa = (PAVoiceOut *) hw;
704 pa_operation *op;
705 pa_cvolume v;
706 paaudio *g = &glob_paaudio;
708 #ifdef PA_CHECK_VERSION /* macro is present in 0.9.16+ */
709 pa_cvolume_init (&v); /* function is present in 0.9.13+ */
710 #endif
712 switch (cmd) {
713 case VOICE_VOLUME:
715 SWVoiceOut *sw;
716 va_list ap;
718 va_start (ap, cmd);
719 sw = va_arg (ap, SWVoiceOut *);
720 va_end (ap);
722 v.channels = 2;
723 v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
724 v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
726 pa_threaded_mainloop_lock (g->mainloop);
728 op = pa_context_set_sink_input_volume (g->context,
729 pa_stream_get_index (pa->stream),
730 &v, NULL, NULL);
731 if (!op)
732 qpa_logerr (pa_context_errno (g->context),
733 "set_sink_input_volume() failed\n");
734 else
735 pa_operation_unref (op);
737 op = pa_context_set_sink_input_mute (g->context,
738 pa_stream_get_index (pa->stream),
739 sw->vol.mute, NULL, NULL);
740 if (!op) {
741 qpa_logerr (pa_context_errno (g->context),
742 "set_sink_input_mute() failed\n");
743 } else {
744 pa_operation_unref (op);
747 pa_threaded_mainloop_unlock (g->mainloop);
750 return 0;
753 static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...)
755 PAVoiceIn *pa = (PAVoiceIn *) hw;
756 pa_operation *op;
757 pa_cvolume v;
758 paaudio *g = &glob_paaudio;
760 #ifdef PA_CHECK_VERSION
761 pa_cvolume_init (&v);
762 #endif
764 switch (cmd) {
765 case VOICE_VOLUME:
767 SWVoiceIn *sw;
768 va_list ap;
770 va_start (ap, cmd);
771 sw = va_arg (ap, SWVoiceIn *);
772 va_end (ap);
774 v.channels = 2;
775 v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX;
776 v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX;
778 pa_threaded_mainloop_lock (g->mainloop);
780 /* FIXME: use the upcoming "set_source_output_{volume,mute}" */
781 op = pa_context_set_source_volume_by_index (g->context,
782 pa_stream_get_device_index (pa->stream),
783 &v, NULL, NULL);
784 if (!op) {
785 qpa_logerr (pa_context_errno (g->context),
786 "set_source_volume() failed\n");
787 } else {
788 pa_operation_unref(op);
791 op = pa_context_set_source_mute_by_index (g->context,
792 pa_stream_get_index (pa->stream),
793 sw->vol.mute, NULL, NULL);
794 if (!op) {
795 qpa_logerr (pa_context_errno (g->context),
796 "set_source_mute() failed\n");
797 } else {
798 pa_operation_unref (op);
801 pa_threaded_mainloop_unlock (g->mainloop);
804 return 0;
807 /* common */
808 static void *qpa_audio_init (void)
810 paaudio *g = &glob_paaudio;
812 g->mainloop = pa_threaded_mainloop_new ();
813 if (!g->mainloop) {
814 goto fail;
817 g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop), glob_paaudio.server);
818 if (!g->context) {
819 goto fail;
822 pa_context_set_state_callback (g->context, context_state_cb, g);
824 if (pa_context_connect (g->context, glob_paaudio.server, 0, NULL) < 0) {
825 qpa_logerr (pa_context_errno (g->context),
826 "pa_context_connect() failed\n");
827 goto fail;
830 pa_threaded_mainloop_lock (g->mainloop);
832 if (pa_threaded_mainloop_start (g->mainloop) < 0) {
833 goto unlock_and_fail;
836 for (;;) {
837 pa_context_state_t state;
839 state = pa_context_get_state (g->context);
841 if (state == PA_CONTEXT_READY) {
842 break;
845 if (!PA_CONTEXT_IS_GOOD (state)) {
846 qpa_logerr (pa_context_errno (g->context),
847 "Wrong context state\n");
848 goto unlock_and_fail;
851 /* Wait until the context is ready */
852 pa_threaded_mainloop_wait (g->mainloop);
855 pa_threaded_mainloop_unlock (g->mainloop);
857 return &glob_paaudio;
859 unlock_and_fail:
860 pa_threaded_mainloop_unlock (g->mainloop);
861 fail:
862 AUD_log (AUDIO_CAP, "Failed to initialize PA context");
863 return NULL;
866 static void qpa_audio_fini (void *opaque)
868 paaudio *g = opaque;
870 if (g->mainloop) {
871 pa_threaded_mainloop_stop (g->mainloop);
874 if (g->context) {
875 pa_context_disconnect (g->context);
876 pa_context_unref (g->context);
877 g->context = NULL;
880 if (g->mainloop) {
881 pa_threaded_mainloop_free (g->mainloop);
884 g->mainloop = NULL;
887 struct audio_option qpa_options[] = {
889 .name = "SAMPLES",
890 .tag = AUD_OPT_INT,
891 .valp = &glob_paaudio.samples,
892 .descr = "buffer size in samples"
895 .name = "SERVER",
896 .tag = AUD_OPT_STR,
897 .valp = &glob_paaudio.server,
898 .descr = "server address"
901 .name = "SINK",
902 .tag = AUD_OPT_STR,
903 .valp = &glob_paaudio.sink,
904 .descr = "sink device name"
907 .name = "SOURCE",
908 .tag = AUD_OPT_STR,
909 .valp = &glob_paaudio.source,
910 .descr = "source device name"
912 { /* End of list */ }
915 static struct audio_pcm_ops qpa_pcm_ops = {
916 .init_out = qpa_init_out,
917 .fini_out = qpa_fini_out,
918 .run_out = qpa_run_out,
919 .write = qpa_write,
920 .ctl_out = qpa_ctl_out,
922 .init_in = qpa_init_in,
923 .fini_in = qpa_fini_in,
924 .run_in = qpa_run_in,
925 .read = qpa_read,
926 .ctl_in = qpa_ctl_in
929 struct audio_driver pa_audio_driver = {
930 .name = "pa",
931 .descr = "http://www.pulseaudio.org/",
932 .options = qpa_options,
933 .init = qpa_audio_init,
934 .fini = qpa_audio_fini,
935 .pcm_ops = &qpa_pcm_ops,
936 .can_be_default = 1,
937 .max_voices_out = INT_MAX,
938 .max_voices_in = INT_MAX,
939 .voice_size_out = sizeof (PAVoiceOut),
940 .voice_size_in = sizeof (PAVoiceIn),
941 .ctl_caps = VOICE_VOLUME_CAP