3 #include "qemu/osdep.h"
4 #include "qemu/module.h"
5 #include "qemu-common.h"
7 #include "qapi/opts-visitor.h"
9 #include <pulse/pulseaudio.h>
11 #define AUDIO_CAP "pulseaudio"
12 #include "audio_int.h"
14 typedef struct PAConnection
{
17 QTAILQ_ENTRY(PAConnection
) list
;
19 pa_threaded_mainloop
*mainloop
;
23 static QTAILQ_HEAD(PAConnectionHead
, PAConnection
) pa_conns
=
24 QTAILQ_HEAD_INITIALIZER(pa_conns
);
41 const void *read_data
;
47 static void qpa_conn_fini(PAConnection
*c
);
49 static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err
, const char *fmt
, ...)
54 AUD_vlog (AUDIO_CAP
, fmt
, ap
);
57 AUD_log (AUDIO_CAP
, "Reason: %s\n", pa_strerror (err
));
60 #ifndef PA_CONTEXT_IS_GOOD
61 static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x
)
64 x
== PA_CONTEXT_CONNECTING
||
65 x
== PA_CONTEXT_AUTHORIZING
||
66 x
== PA_CONTEXT_SETTING_NAME
||
67 x
== PA_CONTEXT_READY
;
71 #ifndef PA_STREAM_IS_GOOD
72 static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x
)
75 x
== PA_STREAM_CREATING
||
80 #define CHECK_SUCCESS_GOTO(c, expression, label, msg) \
82 if (!(expression)) { \
83 qpa_logerr(pa_context_errno((c)->context), msg); \
88 #define CHECK_DEAD_GOTO(c, stream, label, msg) \
90 if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \
91 !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \
92 if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \
93 ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \
94 qpa_logerr(pa_context_errno((c)->context), msg); \
96 qpa_logerr(PA_ERR_BADSTATE, msg); \
102 static void *qpa_get_buffer_in(HWVoiceIn
*hw
, size_t *size
)
104 PAVoiceIn
*p
= (PAVoiceIn
*) hw
;
105 PAConnection
*c
= p
->g
->conn
;
108 pa_threaded_mainloop_lock(c
->mainloop
);
110 CHECK_DEAD_GOTO(c
, p
->stream
, unlock_and_fail
,
111 "pa_threaded_mainloop_lock failed\n");
113 if (!p
->read_length
) {
114 r
= pa_stream_peek(p
->stream
, &p
->read_data
, &p
->read_length
);
115 CHECK_SUCCESS_GOTO(c
, r
== 0, unlock_and_fail
,
116 "pa_stream_peek failed\n");
119 *size
= MIN(p
->read_length
, *size
);
121 pa_threaded_mainloop_unlock(c
->mainloop
);
122 return (void *) p
->read_data
;
125 pa_threaded_mainloop_unlock(c
->mainloop
);
130 static void qpa_put_buffer_in(HWVoiceIn
*hw
, void *buf
, size_t size
)
132 PAVoiceIn
*p
= (PAVoiceIn
*) hw
;
133 PAConnection
*c
= p
->g
->conn
;
136 pa_threaded_mainloop_lock(c
->mainloop
);
138 CHECK_DEAD_GOTO(c
, p
->stream
, unlock
,
139 "pa_threaded_mainloop_lock failed\n");
141 assert(buf
== p
->read_data
&& size
<= p
->read_length
);
143 p
->read_data
+= size
;
144 p
->read_length
-= size
;
146 if (size
&& !p
->read_length
) {
147 r
= pa_stream_drop(p
->stream
);
148 CHECK_SUCCESS_GOTO(c
, r
== 0, unlock
, "pa_stream_drop failed\n");
152 pa_threaded_mainloop_unlock(c
->mainloop
);
155 static size_t qpa_read(HWVoiceIn
*hw
, void *data
, size_t length
)
157 PAVoiceIn
*p
= (PAVoiceIn
*) hw
;
158 PAConnection
*c
= p
->g
->conn
;
161 pa_threaded_mainloop_lock(c
->mainloop
);
163 CHECK_DEAD_GOTO(c
, p
->stream
, unlock_and_fail
,
164 "pa_threaded_mainloop_lock failed\n");
165 if (pa_stream_get_state(p
->stream
) != PA_STREAM_READY
) {
166 /* wait for stream to become ready */
170 while (total
< length
) {
174 if (!p
->read_length
) {
175 r
= pa_stream_peek(p
->stream
, &p
->read_data
, &p
->read_length
);
176 CHECK_SUCCESS_GOTO(c
, r
== 0, unlock_and_fail
,
177 "pa_stream_peek failed\n");
178 if (!p
->read_length
) {
179 /* buffer is empty */
184 l
= MIN(p
->read_length
, length
- total
);
185 memcpy((char *)data
+ total
, p
->read_data
, l
);
191 if (!p
->read_length
) {
192 r
= pa_stream_drop(p
->stream
);
193 CHECK_SUCCESS_GOTO(c
, r
== 0, unlock_and_fail
,
194 "pa_stream_drop failed\n");
199 pa_threaded_mainloop_unlock(c
->mainloop
);
203 pa_threaded_mainloop_unlock(c
->mainloop
);
207 static void *qpa_get_buffer_out(HWVoiceOut
*hw
, size_t *size
)
209 PAVoiceOut
*p
= (PAVoiceOut
*) hw
;
210 PAConnection
*c
= p
->g
->conn
;
214 pa_threaded_mainloop_lock(c
->mainloop
);
216 CHECK_DEAD_GOTO(c
, p
->stream
, unlock_and_fail
,
217 "pa_threaded_mainloop_lock failed\n");
220 r
= pa_stream_begin_write(p
->stream
, &ret
, size
);
221 CHECK_SUCCESS_GOTO(c
, r
>= 0, unlock_and_fail
,
222 "pa_stream_begin_write failed\n");
224 pa_threaded_mainloop_unlock(c
->mainloop
);
228 pa_threaded_mainloop_unlock(c
->mainloop
);
233 static size_t qpa_write(HWVoiceOut
*hw
, void *data
, size_t length
)
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");
245 l
= pa_stream_writable_size(p
->stream
);
247 CHECK_SUCCESS_GOTO(c
, l
!= (size_t) -1, unlock_and_fail
,
248 "pa_stream_writable_size failed\n");
254 r
= pa_stream_write(p
->stream
, data
, l
, NULL
, 0LL, PA_SEEK_RELATIVE
);
255 CHECK_SUCCESS_GOTO(c
, r
>= 0, unlock_and_fail
, "pa_stream_write failed\n");
257 pa_threaded_mainloop_unlock(c
->mainloop
);
261 pa_threaded_mainloop_unlock(c
->mainloop
);
265 static pa_sample_format_t
audfmt_to_pa (AudioFormat afmt
, int endianness
)
270 case AUDIO_FORMAT_S8
:
271 case AUDIO_FORMAT_U8
:
272 format
= PA_SAMPLE_U8
;
274 case AUDIO_FORMAT_S16
:
275 case AUDIO_FORMAT_U16
:
276 format
= endianness
? PA_SAMPLE_S16BE
: PA_SAMPLE_S16LE
;
278 case AUDIO_FORMAT_S32
:
279 case AUDIO_FORMAT_U32
:
280 format
= endianness
? PA_SAMPLE_S32BE
: PA_SAMPLE_S32LE
;
283 dolog ("Internal logic error: Bad audio format %d\n", afmt
);
284 format
= PA_SAMPLE_U8
;
290 static AudioFormat
pa_to_audfmt (pa_sample_format_t fmt
, int *endianness
)
294 return AUDIO_FORMAT_U8
;
295 case PA_SAMPLE_S16BE
:
297 return AUDIO_FORMAT_S16
;
298 case PA_SAMPLE_S16LE
:
300 return AUDIO_FORMAT_S16
;
301 case PA_SAMPLE_S32BE
:
303 return AUDIO_FORMAT_S32
;
304 case PA_SAMPLE_S32LE
:
306 return AUDIO_FORMAT_S32
;
308 dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt
);
309 return AUDIO_FORMAT_U8
;
313 static void context_state_cb (pa_context
*c
, void *userdata
)
315 PAConnection
*conn
= userdata
;
317 switch (pa_context_get_state(c
)) {
318 case PA_CONTEXT_READY
:
319 case PA_CONTEXT_TERMINATED
:
320 case PA_CONTEXT_FAILED
:
321 pa_threaded_mainloop_signal(conn
->mainloop
, 0);
324 case PA_CONTEXT_UNCONNECTED
:
325 case PA_CONTEXT_CONNECTING
:
326 case PA_CONTEXT_AUTHORIZING
:
327 case PA_CONTEXT_SETTING_NAME
:
332 static void stream_state_cb (pa_stream
*s
, void * userdata
)
334 PAConnection
*c
= userdata
;
336 switch (pa_stream_get_state (s
)) {
338 case PA_STREAM_READY
:
339 case PA_STREAM_FAILED
:
340 case PA_STREAM_TERMINATED
:
341 pa_threaded_mainloop_signal(c
->mainloop
, 0);
344 case PA_STREAM_UNCONNECTED
:
345 case PA_STREAM_CREATING
:
350 static pa_stream
*qpa_simple_new (
353 pa_stream_direction_t dir
,
355 const pa_sample_spec
*ss
,
356 const pa_buffer_attr
*attr
,
360 pa_stream
*stream
= NULL
;
361 pa_stream_flags_t flags
;
364 pa_threaded_mainloop_lock(c
->mainloop
);
366 pa_channel_map_init(&map
);
367 map
.channels
= ss
->channels
;
370 * TODO: This currently expects the only frontend supporting more than 2
371 * channels is the usb-audio. We will need some means to set channel
372 * order when a new frontend gains multi-channel support.
374 switch (ss
->channels
) {
376 map
.map
[0] = PA_CHANNEL_POSITION_MONO
;
380 map
.map
[0] = PA_CHANNEL_POSITION_LEFT
;
381 map
.map
[1] = PA_CHANNEL_POSITION_RIGHT
;
385 map
.map
[0] = PA_CHANNEL_POSITION_FRONT_LEFT
;
386 map
.map
[1] = PA_CHANNEL_POSITION_FRONT_RIGHT
;
387 map
.map
[2] = PA_CHANNEL_POSITION_CENTER
;
388 map
.map
[3] = PA_CHANNEL_POSITION_LFE
;
389 map
.map
[4] = PA_CHANNEL_POSITION_REAR_LEFT
;
390 map
.map
[5] = PA_CHANNEL_POSITION_REAR_RIGHT
;
394 map
.map
[0] = PA_CHANNEL_POSITION_FRONT_LEFT
;
395 map
.map
[1] = PA_CHANNEL_POSITION_FRONT_RIGHT
;
396 map
.map
[2] = PA_CHANNEL_POSITION_CENTER
;
397 map
.map
[3] = PA_CHANNEL_POSITION_LFE
;
398 map
.map
[4] = PA_CHANNEL_POSITION_REAR_LEFT
;
399 map
.map
[5] = PA_CHANNEL_POSITION_REAR_RIGHT
;
400 map
.map
[6] = PA_CHANNEL_POSITION_SIDE_LEFT
;
401 map
.map
[7] = PA_CHANNEL_POSITION_SIDE_RIGHT
;
405 dolog("Internal error: unsupported channel count %d\n", ss
->channels
);
409 stream
= pa_stream_new(c
->context
, name
, ss
, &map
);
414 pa_stream_set_state_callback(stream
, stream_state_cb
, c
);
417 PA_STREAM_INTERPOLATE_TIMING
418 | PA_STREAM_AUTO_TIMING_UPDATE
419 | PA_STREAM_EARLY_REQUESTS
;
422 /* don't move the stream if the user specified a sink/source */
423 flags
|= PA_STREAM_DONT_MOVE
;
426 if (dir
== PA_STREAM_PLAYBACK
) {
427 r
= pa_stream_connect_playback(stream
, dev
, attr
, flags
, NULL
, NULL
);
429 r
= pa_stream_connect_record(stream
, dev
, attr
, flags
);
436 pa_threaded_mainloop_unlock(c
->mainloop
);
441 pa_threaded_mainloop_unlock(c
->mainloop
);
444 pa_stream_unref (stream
);
447 *rerror
= pa_context_errno(c
->context
);
452 static int qpa_init_out(HWVoiceOut
*hw
, struct audsettings
*as
,
458 struct audsettings obt_as
= *as
;
459 PAVoiceOut
*pa
= (PAVoiceOut
*) hw
;
460 paaudio
*g
= pa
->g
= drv_opaque
;
461 AudiodevPaOptions
*popts
= &g
->dev
->u
.pa
;
462 AudiodevPaPerDirectionOptions
*ppdo
= popts
->out
;
463 PAConnection
*c
= g
->conn
;
465 ss
.format
= audfmt_to_pa (as
->fmt
, as
->endianness
);
466 ss
.channels
= as
->nchannels
;
469 ba
.tlength
= pa_usec_to_bytes(ppdo
->latency
, &ss
);
474 obt_as
.fmt
= pa_to_audfmt (ss
.format
, &obt_as
.endianness
);
476 pa
->stream
= qpa_simple_new (
478 ppdo
->has_stream_name
? ppdo
->stream_name
: g
->dev
->id
,
480 ppdo
->has_name
? ppdo
->name
: NULL
,
482 &ba
, /* buffering attributes */
486 qpa_logerr (error
, "pa_simple_new for playback failed\n");
490 audio_pcm_init_info (&hw
->info
, &obt_as
);
491 hw
->samples
= pa
->samples
= audio_buffer_samples(
492 qapi_AudiodevPaPerDirectionOptions_base(ppdo
),
493 &obt_as
, ppdo
->buffer_length
);
501 static int qpa_init_in(HWVoiceIn
*hw
, struct audsettings
*as
, void *drv_opaque
)
506 struct audsettings obt_as
= *as
;
507 PAVoiceIn
*pa
= (PAVoiceIn
*) hw
;
508 paaudio
*g
= pa
->g
= drv_opaque
;
509 AudiodevPaOptions
*popts
= &g
->dev
->u
.pa
;
510 AudiodevPaPerDirectionOptions
*ppdo
= popts
->in
;
511 PAConnection
*c
= g
->conn
;
513 ss
.format
= audfmt_to_pa (as
->fmt
, as
->endianness
);
514 ss
.channels
= as
->nchannels
;
517 ba
.fragsize
= pa_usec_to_bytes(ppdo
->latency
, &ss
);
518 ba
.maxlength
= pa_usec_to_bytes(ppdo
->latency
* 2, &ss
);
522 obt_as
.fmt
= pa_to_audfmt (ss
.format
, &obt_as
.endianness
);
524 pa
->stream
= qpa_simple_new (
526 ppdo
->has_stream_name
? ppdo
->stream_name
: g
->dev
->id
,
528 ppdo
->has_name
? ppdo
->name
: NULL
,
530 &ba
, /* buffering attributes */
534 qpa_logerr (error
, "pa_simple_new for capture failed\n");
538 audio_pcm_init_info (&hw
->info
, &obt_as
);
539 hw
->samples
= pa
->samples
= audio_buffer_samples(
540 qapi_AudiodevPaPerDirectionOptions_base(ppdo
),
541 &obt_as
, ppdo
->buffer_length
);
549 static void qpa_simple_disconnect(PAConnection
*c
, pa_stream
*stream
)
554 * wait until actually connects. workaround pa bug #247
555 * https://gitlab.freedesktop.org/pulseaudio/pulseaudio/issues/247
557 while (pa_stream_get_state(stream
) == PA_STREAM_CREATING
) {
558 pa_threaded_mainloop_wait(c
->mainloop
);
561 err
= pa_stream_disconnect(stream
);
563 dolog("Failed to disconnect! err=%d\n", err
);
565 pa_stream_unref(stream
);
568 static void qpa_fini_out (HWVoiceOut
*hw
)
570 PAVoiceOut
*pa
= (PAVoiceOut
*) hw
;
573 PAConnection
*c
= pa
->g
->conn
;
575 pa_threaded_mainloop_lock(c
->mainloop
);
576 qpa_simple_disconnect(c
, pa
->stream
);
578 pa_threaded_mainloop_unlock(c
->mainloop
);
582 static void qpa_fini_in (HWVoiceIn
*hw
)
584 PAVoiceIn
*pa
= (PAVoiceIn
*) hw
;
587 PAConnection
*c
= pa
->g
->conn
;
589 pa_threaded_mainloop_lock(c
->mainloop
);
590 if (pa
->read_length
) {
591 int r
= pa_stream_drop(pa
->stream
);
593 qpa_logerr(pa_context_errno(c
->context
),
594 "pa_stream_drop failed\n");
598 qpa_simple_disconnect(c
, pa
->stream
);
600 pa_threaded_mainloop_unlock(c
->mainloop
);
604 static void qpa_volume_out(HWVoiceOut
*hw
, Volume
*vol
)
606 PAVoiceOut
*pa
= (PAVoiceOut
*) hw
;
609 PAConnection
*c
= pa
->g
->conn
;
612 #ifdef PA_CHECK_VERSION /* macro is present in 0.9.16+ */
613 pa_cvolume_init (&v
); /* function is present in 0.9.13+ */
616 v
.channels
= vol
->channels
;
617 for (i
= 0; i
< vol
->channels
; ++i
) {
618 v
.values
[i
] = ((PA_VOLUME_NORM
- PA_VOLUME_MUTED
) * vol
->vol
[i
]) / 255;
621 pa_threaded_mainloop_lock(c
->mainloop
);
623 op
= pa_context_set_sink_input_volume(c
->context
,
624 pa_stream_get_index(pa
->stream
),
627 qpa_logerr(pa_context_errno(c
->context
),
628 "set_sink_input_volume() failed\n");
630 pa_operation_unref(op
);
633 op
= pa_context_set_sink_input_mute(c
->context
,
634 pa_stream_get_index(pa
->stream
),
635 vol
->mute
, NULL
, NULL
);
637 qpa_logerr(pa_context_errno(c
->context
),
638 "set_sink_input_mute() failed\n");
640 pa_operation_unref(op
);
643 pa_threaded_mainloop_unlock(c
->mainloop
);
646 static void qpa_volume_in(HWVoiceIn
*hw
, Volume
*vol
)
648 PAVoiceIn
*pa
= (PAVoiceIn
*) hw
;
651 PAConnection
*c
= pa
->g
->conn
;
654 #ifdef PA_CHECK_VERSION
655 pa_cvolume_init (&v
);
658 v
.channels
= vol
->channels
;
659 for (i
= 0; i
< vol
->channels
; ++i
) {
660 v
.values
[i
] = ((PA_VOLUME_NORM
- PA_VOLUME_MUTED
) * vol
->vol
[i
]) / 255;
663 pa_threaded_mainloop_lock(c
->mainloop
);
665 op
= pa_context_set_source_output_volume(c
->context
,
666 pa_stream_get_index(pa
->stream
),
669 qpa_logerr(pa_context_errno(c
->context
),
670 "set_source_output_volume() failed\n");
672 pa_operation_unref(op
);
675 op
= pa_context_set_source_output_mute(c
->context
,
676 pa_stream_get_index(pa
->stream
),
677 vol
->mute
, NULL
, NULL
);
679 qpa_logerr(pa_context_errno(c
->context
),
680 "set_source_output_mute() failed\n");
682 pa_operation_unref(op
);
685 pa_threaded_mainloop_unlock(c
->mainloop
);
688 static int qpa_validate_per_direction_opts(Audiodev
*dev
,
689 AudiodevPaPerDirectionOptions
*pdo
)
691 if (!pdo
->has_buffer_length
) {
692 pdo
->has_buffer_length
= true;
693 pdo
->buffer_length
= 46440;
695 if (!pdo
->has_latency
) {
696 pdo
->has_latency
= true;
697 pdo
->latency
= 15000;
703 static void *qpa_conn_init(const char *server
)
706 PAConnection
*c
= g_malloc0(sizeof(PAConnection
));
707 QTAILQ_INSERT_TAIL(&pa_conns
, c
, list
);
709 c
->mainloop
= pa_threaded_mainloop_new();
714 vm_name
= qemu_get_vm_name();
715 c
->context
= pa_context_new(pa_threaded_mainloop_get_api(c
->mainloop
),
716 vm_name
? vm_name
: "qemu");
721 pa_context_set_state_callback(c
->context
, context_state_cb
, c
);
723 if (pa_context_connect(c
->context
, server
, 0, NULL
) < 0) {
724 qpa_logerr(pa_context_errno(c
->context
),
725 "pa_context_connect() failed\n");
729 pa_threaded_mainloop_lock(c
->mainloop
);
731 if (pa_threaded_mainloop_start(c
->mainloop
) < 0) {
732 goto unlock_and_fail
;
736 pa_context_state_t state
;
738 state
= pa_context_get_state(c
->context
);
740 if (state
== PA_CONTEXT_READY
) {
744 if (!PA_CONTEXT_IS_GOOD(state
)) {
745 qpa_logerr(pa_context_errno(c
->context
),
746 "Wrong context state\n");
747 goto unlock_and_fail
;
750 /* Wait until the context is ready */
751 pa_threaded_mainloop_wait(c
->mainloop
);
754 pa_threaded_mainloop_unlock(c
->mainloop
);
758 pa_threaded_mainloop_unlock(c
->mainloop
);
760 AUD_log (AUDIO_CAP
, "Failed to initialize PA context");
765 static void *qpa_audio_init(Audiodev
*dev
)
768 AudiodevPaOptions
*popts
= &dev
->u
.pa
;
772 assert(dev
->driver
== AUDIODEV_DRIVER_PA
);
774 if (!popts
->has_server
) {
779 runtime
= getenv("XDG_RUNTIME_DIR");
783 snprintf(pidfile
, sizeof(pidfile
), "%s/pulse/pid", runtime
);
784 if (stat(pidfile
, &st
) != 0) {
789 if (!qpa_validate_per_direction_opts(dev
, popts
->in
)) {
792 if (!qpa_validate_per_direction_opts(dev
, popts
->out
)) {
796 g
= g_malloc0(sizeof(paaudio
));
797 server
= popts
->has_server
? popts
->server
: NULL
;
801 QTAILQ_FOREACH(c
, &pa_conns
, list
) {
802 if (server
== NULL
|| c
->server
== NULL
?
803 server
== c
->server
:
804 strcmp(server
, c
->server
) == 0) {
810 g
->conn
= qpa_conn_init(server
);
821 static void qpa_conn_fini(PAConnection
*c
)
824 pa_threaded_mainloop_stop(c
->mainloop
);
828 pa_context_disconnect(c
->context
);
829 pa_context_unref(c
->context
);
833 pa_threaded_mainloop_free(c
->mainloop
);
836 QTAILQ_REMOVE(&pa_conns
, c
, list
);
840 static void qpa_audio_fini (void *opaque
)
843 PAConnection
*c
= g
->conn
;
845 if (--c
->refcount
== 0) {
852 static struct audio_pcm_ops qpa_pcm_ops
= {
853 .init_out
= qpa_init_out
,
854 .fini_out
= qpa_fini_out
,
856 .get_buffer_out
= qpa_get_buffer_out
,
857 .put_buffer_out
= qpa_write
, /* pa handles it */
858 .volume_out
= qpa_volume_out
,
860 .init_in
= qpa_init_in
,
861 .fini_in
= qpa_fini_in
,
863 .get_buffer_in
= qpa_get_buffer_in
,
864 .put_buffer_in
= qpa_put_buffer_in
,
865 .volume_in
= qpa_volume_in
868 static struct audio_driver pa_audio_driver
= {
870 .descr
= "http://www.pulseaudio.org/",
871 .init
= qpa_audio_init
,
872 .fini
= qpa_audio_fini
,
873 .pcm_ops
= &qpa_pcm_ops
,
875 .max_voices_out
= INT_MAX
,
876 .max_voices_in
= INT_MAX
,
877 .voice_size_out
= sizeof (PAVoiceOut
),
878 .voice_size_in
= sizeof (PAVoiceIn
),
881 static void register_audio_pa(void)
883 audio_driver_register(&pa_audio_driver
);
885 type_init(register_audio_pa
);