3 #include "qemu/osdep.h"
4 #include "qemu/module.h"
6 #include "qapi/opts-visitor.h"
8 #include <pulse/pulseaudio.h>
10 #define AUDIO_CAP "pulseaudio"
11 #include "audio_int.h"
13 typedef struct PAConnection
{
16 QTAILQ_ENTRY(PAConnection
) list
;
18 pa_threaded_mainloop
*mainloop
;
22 static QTAILQ_HEAD(PAConnectionHead
, PAConnection
) pa_conns
=
23 QTAILQ_HEAD_INITIALIZER(pa_conns
);
39 const void *read_data
;
44 static void qpa_conn_fini(PAConnection
*c
);
46 static void G_GNUC_PRINTF (2, 3) qpa_logerr (int err
, const char *fmt
, ...)
51 AUD_vlog (AUDIO_CAP
, fmt
, ap
);
54 AUD_log (AUDIO_CAP
, "Reason: %s\n", pa_strerror (err
));
57 #ifndef PA_CONTEXT_IS_GOOD
58 static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x
)
61 x
== PA_CONTEXT_CONNECTING
||
62 x
== PA_CONTEXT_AUTHORIZING
||
63 x
== PA_CONTEXT_SETTING_NAME
||
64 x
== PA_CONTEXT_READY
;
68 #ifndef PA_STREAM_IS_GOOD
69 static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x
)
72 x
== PA_STREAM_CREATING
||
77 #define CHECK_SUCCESS_GOTO(c, expression, label, msg) \
79 if (!(expression)) { \
80 qpa_logerr(pa_context_errno((c)->context), msg); \
85 #define CHECK_DEAD_GOTO(c, stream, label, msg) \
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); \
93 qpa_logerr(PA_ERR_BADSTATE, msg); \
99 static void *qpa_get_buffer_in(HWVoiceIn
*hw
, size_t *size
)
101 PAVoiceIn
*p
= (PAVoiceIn
*) hw
;
102 PAConnection
*c
= p
->g
->conn
;
105 pa_threaded_mainloop_lock(c
->mainloop
);
107 CHECK_DEAD_GOTO(c
, p
->stream
, unlock_and_fail
,
108 "pa_threaded_mainloop_lock failed\n");
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");
116 *size
= MIN(p
->read_length
, *size
);
118 pa_threaded_mainloop_unlock(c
->mainloop
);
119 return (void *) p
->read_data
;
122 pa_threaded_mainloop_unlock(c
->mainloop
);
127 static void qpa_put_buffer_in(HWVoiceIn
*hw
, void *buf
, size_t size
)
129 PAVoiceIn
*p
= (PAVoiceIn
*) hw
;
130 PAConnection
*c
= p
->g
->conn
;
133 pa_threaded_mainloop_lock(c
->mainloop
);
135 CHECK_DEAD_GOTO(c
, p
->stream
, unlock
,
136 "pa_threaded_mainloop_lock failed\n");
138 assert(buf
== p
->read_data
&& size
<= p
->read_length
);
140 p
->read_data
+= size
;
141 p
->read_length
-= size
;
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");
149 pa_threaded_mainloop_unlock(c
->mainloop
);
152 static size_t qpa_read(HWVoiceIn
*hw
, void *data
, size_t length
)
154 PAVoiceIn
*p
= (PAVoiceIn
*) hw
;
155 PAConnection
*c
= p
->g
->conn
;
158 pa_threaded_mainloop_lock(c
->mainloop
);
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 */
167 while (total
< length
) {
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 */
181 l
= MIN(p
->read_length
, length
- total
);
182 memcpy((char *)data
+ total
, p
->read_data
, l
);
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");
196 pa_threaded_mainloop_unlock(c
->mainloop
);
200 pa_threaded_mainloop_unlock(c
->mainloop
);
204 static size_t qpa_buffer_get_free(HWVoiceOut
*hw
)
206 PAVoiceOut
*p
= (PAVoiceOut
*)hw
;
207 PAConnection
*c
= p
->g
->conn
;
210 pa_threaded_mainloop_lock(c
->mainloop
);
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 */
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");
225 pa_threaded_mainloop_unlock(c
->mainloop
);
229 pa_threaded_mainloop_unlock(c
->mainloop
);
233 static void *qpa_get_buffer_out(HWVoiceOut
*hw
, size_t *size
)
235 PAVoiceOut
*p
= (PAVoiceOut
*)hw
;
236 PAConnection
*c
= p
->g
->conn
;
240 pa_threaded_mainloop_lock(c
->mainloop
);
242 CHECK_DEAD_GOTO(c
, p
->stream
, unlock_and_fail
,
243 "pa_threaded_mainloop_lock failed\n");
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");
250 pa_threaded_mainloop_unlock(c
->mainloop
);
254 pa_threaded_mainloop_unlock(c
->mainloop
);
259 static size_t qpa_put_buffer_out(HWVoiceOut
*hw
, void *data
, size_t length
)
261 PAVoiceOut
*p
= (PAVoiceOut
*)hw
;
262 PAConnection
*c
= p
->g
->conn
;
265 pa_threaded_mainloop_lock(c
->mainloop
);
267 CHECK_DEAD_GOTO(c
, p
->stream
, unlock_and_fail
,
268 "pa_threaded_mainloop_lock failed\n");
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");
273 pa_threaded_mainloop_unlock(c
->mainloop
);
277 pa_threaded_mainloop_unlock(c
->mainloop
);
281 static size_t qpa_write(HWVoiceOut
*hw
, void *data
, size_t length
)
283 PAVoiceOut
*p
= (PAVoiceOut
*) hw
;
284 PAConnection
*c
= p
->g
->conn
;
288 pa_threaded_mainloop_lock(c
->mainloop
);
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 */
298 l
= pa_stream_writable_size(p
->stream
);
300 CHECK_SUCCESS_GOTO(c
, l
!= (size_t) -1, unlock_and_fail
,
301 "pa_stream_writable_size failed\n");
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");
311 pa_threaded_mainloop_unlock(c
->mainloop
);
315 pa_threaded_mainloop_unlock(c
->mainloop
);
319 static pa_sample_format_t
audfmt_to_pa (AudioFormat afmt
, int endianness
)
324 case AUDIO_FORMAT_S8
:
325 case AUDIO_FORMAT_U8
:
326 format
= PA_SAMPLE_U8
;
328 case AUDIO_FORMAT_S16
:
329 case AUDIO_FORMAT_U16
:
330 format
= endianness
? PA_SAMPLE_S16BE
: PA_SAMPLE_S16LE
;
332 case AUDIO_FORMAT_S32
:
333 case AUDIO_FORMAT_U32
:
334 format
= endianness
? PA_SAMPLE_S32BE
: PA_SAMPLE_S32LE
;
336 case AUDIO_FORMAT_F32
:
337 format
= endianness
? PA_SAMPLE_FLOAT32BE
: PA_SAMPLE_FLOAT32LE
;
340 dolog ("Internal logic error: Bad audio format %d\n", afmt
);
341 format
= PA_SAMPLE_U8
;
347 static AudioFormat
pa_to_audfmt (pa_sample_format_t fmt
, int *endianness
)
351 return AUDIO_FORMAT_U8
;
352 case PA_SAMPLE_S16BE
:
354 return AUDIO_FORMAT_S16
;
355 case PA_SAMPLE_S16LE
:
357 return AUDIO_FORMAT_S16
;
358 case PA_SAMPLE_S32BE
:
360 return AUDIO_FORMAT_S32
;
361 case PA_SAMPLE_S32LE
:
363 return AUDIO_FORMAT_S32
;
364 case PA_SAMPLE_FLOAT32BE
:
366 return AUDIO_FORMAT_F32
;
367 case PA_SAMPLE_FLOAT32LE
:
369 return AUDIO_FORMAT_F32
;
371 dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt
);
372 return AUDIO_FORMAT_U8
;
376 static void context_state_cb (pa_context
*c
, void *userdata
)
378 PAConnection
*conn
= userdata
;
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);
387 case PA_CONTEXT_UNCONNECTED
:
388 case PA_CONTEXT_CONNECTING
:
389 case PA_CONTEXT_AUTHORIZING
:
390 case PA_CONTEXT_SETTING_NAME
:
395 static void stream_state_cb (pa_stream
*s
, void * userdata
)
397 PAConnection
*c
= userdata
;
399 switch (pa_stream_get_state (s
)) {
401 case PA_STREAM_READY
:
402 case PA_STREAM_FAILED
:
403 case PA_STREAM_TERMINATED
:
404 pa_threaded_mainloop_signal(c
->mainloop
, 0);
407 case PA_STREAM_UNCONNECTED
:
408 case PA_STREAM_CREATING
:
413 static pa_stream
*qpa_simple_new (
416 pa_stream_direction_t dir
,
418 const pa_sample_spec
*ss
,
419 const pa_buffer_attr
*attr
,
423 pa_stream
*stream
= NULL
;
424 pa_stream_flags_t flags
;
427 pa_threaded_mainloop_lock(c
->mainloop
);
429 pa_channel_map_init(&map
);
430 map
.channels
= ss
->channels
;
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.
437 switch (ss
->channels
) {
439 map
.map
[0] = PA_CHANNEL_POSITION_MONO
;
443 map
.map
[0] = PA_CHANNEL_POSITION_LEFT
;
444 map
.map
[1] = PA_CHANNEL_POSITION_RIGHT
;
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
;
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
;
468 dolog("Internal error: unsupported channel count %d\n", ss
->channels
);
472 stream
= pa_stream_new(c
->context
, name
, ss
, &map
);
477 pa_stream_set_state_callback(stream
, stream_state_cb
, c
);
479 flags
= PA_STREAM_EARLY_REQUESTS
;
482 /* don't move the stream if the user specified a sink/source */
483 flags
|= PA_STREAM_DONT_MOVE
;
486 if (dir
== PA_STREAM_PLAYBACK
) {
487 r
= pa_stream_connect_playback(stream
, dev
, attr
, flags
, NULL
, NULL
);
489 r
= pa_stream_connect_record(stream
, dev
, attr
, flags
);
496 pa_threaded_mainloop_unlock(c
->mainloop
);
501 pa_threaded_mainloop_unlock(c
->mainloop
);
504 pa_stream_unref (stream
);
507 *rerror
= pa_context_errno(c
->context
);
512 static int qpa_init_out(HWVoiceOut
*hw
, struct audsettings
*as
,
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
;
525 ss
.format
= audfmt_to_pa (as
->fmt
, as
->endianness
);
526 ss
.channels
= as
->nchannels
;
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
);
535 obt_as
.fmt
= pa_to_audfmt (ss
.format
, &obt_as
.endianness
);
537 pa
->stream
= qpa_simple_new (
539 ppdo
->has_stream_name
? ppdo
->stream_name
: g
->dev
->id
,
541 ppdo
->has_name
? ppdo
->name
: NULL
,
543 &ba
, /* buffering attributes */
547 qpa_logerr (error
, "pa_simple_new for playback failed\n");
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);
562 static int qpa_init_in(HWVoiceIn
*hw
, struct audsettings
*as
, void *drv_opaque
)
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
;
574 ss
.format
= audfmt_to_pa (as
->fmt
, as
->endianness
);
575 ss
.channels
= as
->nchannels
;
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
);
584 obt_as
.fmt
= pa_to_audfmt (ss
.format
, &obt_as
.endianness
);
586 pa
->stream
= qpa_simple_new (
588 ppdo
->has_stream_name
? ppdo
->stream_name
: g
->dev
->id
,
590 ppdo
->has_name
? ppdo
->name
: NULL
,
592 &ba
, /* buffering attributes */
596 qpa_logerr (error
, "pa_simple_new for capture failed\n");
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);
611 static void qpa_simple_disconnect(PAConnection
*c
, pa_stream
*stream
)
616 * wait until actually connects. workaround pa bug #247
617 * https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/247
619 while (pa_stream_get_state(stream
) == PA_STREAM_CREATING
) {
620 pa_threaded_mainloop_wait(c
->mainloop
);
623 err
= pa_stream_disconnect(stream
);
625 dolog("Failed to disconnect! err=%d\n", err
);
627 pa_stream_unref(stream
);
630 static void qpa_fini_out (HWVoiceOut
*hw
)
632 PAVoiceOut
*pa
= (PAVoiceOut
*) hw
;
635 PAConnection
*c
= pa
->g
->conn
;
637 pa_threaded_mainloop_lock(c
->mainloop
);
638 qpa_simple_disconnect(c
, pa
->stream
);
640 pa_threaded_mainloop_unlock(c
->mainloop
);
644 static void qpa_fini_in (HWVoiceIn
*hw
)
646 PAVoiceIn
*pa
= (PAVoiceIn
*) hw
;
649 PAConnection
*c
= pa
->g
->conn
;
651 pa_threaded_mainloop_lock(c
->mainloop
);
652 if (pa
->read_length
) {
653 int r
= pa_stream_drop(pa
->stream
);
655 qpa_logerr(pa_context_errno(c
->context
),
656 "pa_stream_drop failed\n");
660 qpa_simple_disconnect(c
, pa
->stream
);
662 pa_threaded_mainloop_unlock(c
->mainloop
);
666 static void qpa_volume_out(HWVoiceOut
*hw
, Volume
*vol
)
668 PAVoiceOut
*pa
= (PAVoiceOut
*) hw
;
671 PAConnection
*c
= pa
->g
->conn
;
674 #ifdef PA_CHECK_VERSION /* macro is present in 0.9.16+ */
675 pa_cvolume_init (&v
); /* function is present in 0.9.13+ */
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;
683 pa_threaded_mainloop_lock(c
->mainloop
);
685 op
= pa_context_set_sink_input_volume(c
->context
,
686 pa_stream_get_index(pa
->stream
),
689 qpa_logerr(pa_context_errno(c
->context
),
690 "set_sink_input_volume() failed\n");
692 pa_operation_unref(op
);
695 op
= pa_context_set_sink_input_mute(c
->context
,
696 pa_stream_get_index(pa
->stream
),
697 vol
->mute
, NULL
, NULL
);
699 qpa_logerr(pa_context_errno(c
->context
),
700 "set_sink_input_mute() failed\n");
702 pa_operation_unref(op
);
705 pa_threaded_mainloop_unlock(c
->mainloop
);
708 static void qpa_volume_in(HWVoiceIn
*hw
, Volume
*vol
)
710 PAVoiceIn
*pa
= (PAVoiceIn
*) hw
;
713 PAConnection
*c
= pa
->g
->conn
;
716 #ifdef PA_CHECK_VERSION
717 pa_cvolume_init (&v
);
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;
725 pa_threaded_mainloop_lock(c
->mainloop
);
727 op
= pa_context_set_source_output_volume(c
->context
,
728 pa_stream_get_index(pa
->stream
),
731 qpa_logerr(pa_context_errno(c
->context
),
732 "set_source_output_volume() failed\n");
734 pa_operation_unref(op
);
737 op
= pa_context_set_source_output_mute(c
->context
,
738 pa_stream_get_index(pa
->stream
),
739 vol
->mute
, NULL
, NULL
);
741 qpa_logerr(pa_context_errno(c
->context
),
742 "set_source_output_mute() failed\n");
744 pa_operation_unref(op
);
747 pa_threaded_mainloop_unlock(c
->mainloop
);
750 static int qpa_validate_per_direction_opts(Audiodev
*dev
,
751 AudiodevPaPerDirectionOptions
*pdo
)
753 if (!pdo
->has_latency
) {
754 pdo
->has_latency
= true;
755 pdo
->latency
= 46440;
761 static void *qpa_conn_init(const char *server
)
763 PAConnection
*c
= g_new0(PAConnection
, 1);
764 QTAILQ_INSERT_TAIL(&pa_conns
, c
, list
);
766 c
->mainloop
= pa_threaded_mainloop_new();
771 c
->context
= pa_context_new(pa_threaded_mainloop_get_api(c
->mainloop
),
772 audio_application_name());
777 pa_context_set_state_callback(c
->context
, context_state_cb
, c
);
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");
785 pa_threaded_mainloop_lock(c
->mainloop
);
787 if (pa_threaded_mainloop_start(c
->mainloop
) < 0) {
788 goto unlock_and_fail
;
792 pa_context_state_t state
;
794 state
= pa_context_get_state(c
->context
);
796 if (state
== PA_CONTEXT_READY
) {
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
;
806 /* Wait until the context is ready */
807 pa_threaded_mainloop_wait(c
->mainloop
);
810 pa_threaded_mainloop_unlock(c
->mainloop
);
814 pa_threaded_mainloop_unlock(c
->mainloop
);
816 AUD_log (AUDIO_CAP
, "Failed to initialize PA context");
821 static void *qpa_audio_init(Audiodev
*dev
)
824 AudiodevPaOptions
*popts
= &dev
->u
.pa
;
828 assert(dev
->driver
== AUDIODEV_DRIVER_PA
);
830 if (!popts
->has_server
) {
835 runtime
= getenv("XDG_RUNTIME_DIR");
839 snprintf(pidfile
, sizeof(pidfile
), "%s/pulse/pid", runtime
);
840 if (stat(pidfile
, &st
) != 0) {
845 if (!qpa_validate_per_direction_opts(dev
, popts
->in
)) {
848 if (!qpa_validate_per_direction_opts(dev
, popts
->out
)) {
852 g
= g_new0(paaudio
, 1);
853 server
= popts
->has_server
? popts
->server
: NULL
;
857 QTAILQ_FOREACH(c
, &pa_conns
, list
) {
858 if (server
== NULL
|| c
->server
== NULL
?
859 server
== c
->server
:
860 strcmp(server
, c
->server
) == 0) {
866 g
->conn
= qpa_conn_init(server
);
877 static void qpa_conn_fini(PAConnection
*c
)
880 pa_threaded_mainloop_stop(c
->mainloop
);
884 pa_context_disconnect(c
->context
);
885 pa_context_unref(c
->context
);
889 pa_threaded_mainloop_free(c
->mainloop
);
892 QTAILQ_REMOVE(&pa_conns
, c
, list
);
896 static void qpa_audio_fini (void *opaque
)
899 PAConnection
*c
= g
->conn
;
901 if (--c
->refcount
== 0) {
908 static struct audio_pcm_ops qpa_pcm_ops
= {
909 .init_out
= qpa_init_out
,
910 .fini_out
= qpa_fini_out
,
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
,
917 .init_in
= qpa_init_in
,
918 .fini_in
= qpa_fini_in
,
920 .get_buffer_in
= qpa_get_buffer_in
,
921 .put_buffer_in
= qpa_put_buffer_in
,
922 .volume_in
= qpa_volume_in
925 static struct audio_driver pa_audio_driver
= {
927 .descr
= "http://www.pulseaudio.org/",
928 .init
= qpa_audio_init
,
929 .fini
= qpa_audio_fini
,
930 .pcm_ops
= &qpa_pcm_ops
,
932 .max_voices_out
= INT_MAX
,
933 .max_voices_in
= INT_MAX
,
934 .voice_size_out
= sizeof (PAVoiceOut
),
935 .voice_size_in
= sizeof (PAVoiceIn
),
938 static void register_audio_pa(void)
940 audio_driver_register(&pa_audio_driver
);
942 type_init(register_audio_pa
);