2 * QEMU PipeWire audio driver
4 * Copyright (c) 2023 Red Hat Inc.
6 * Author: Dorinda Bassey <dbassey@redhat.com>
8 * SPDX-License-Identifier: GPL-2.0-or-later
11 #include "qemu/osdep.h"
12 #include "qemu/module.h"
14 #include "qemu/error-report.h"
15 #include "qapi/error.h"
16 #include <spa/param/audio/format-utils.h>
17 #include <spa/utils/ringbuffer.h>
18 #include <spa/utils/result.h>
19 #include <spa/param/props.h>
21 #include <pipewire/pipewire.h>
24 #define AUDIO_CAP "pipewire"
25 #define RINGBUFFER_SIZE (1u << 22)
26 #define RINGBUFFER_MASK (RINGBUFFER_SIZE - 1)
28 #include "audio_int.h"
30 typedef struct pwvolume
{
32 float values
[SPA_AUDIO_MAX_CHANNELS
];
35 typedef struct pwaudio
{
37 struct pw_thread_loop
*thread_loop
;
38 struct pw_context
*context
;
41 struct spa_hook core_listener
;
42 int last_seq
, pending_seq
, error
;
45 typedef struct PWVoice
{
47 struct pw_stream
*stream
;
48 struct spa_hook stream_listener
;
49 struct spa_audio_info_raw info
;
50 uint32_t highwater_mark
;
51 uint32_t frame_size
, req
;
52 struct spa_ringbuffer ring
;
53 uint8_t buffer
[RINGBUFFER_SIZE
];
59 typedef struct PWVoiceOut
{
64 typedef struct PWVoiceIn
{
69 #define PW_VOICE_IN(v) ((PWVoiceIn *)v)
70 #define PW_VOICE_OUT(v) ((PWVoiceOut *)v)
73 stream_destroy(void *data
)
75 PWVoice
*v
= (PWVoice
*) data
;
76 spa_hook_remove(&v
->stream_listener
);
80 /* output data processing function to read stuffs from the buffer */
82 playback_on_process(void *data
)
87 struct spa_buffer
*buf
;
88 uint32_t req
, index
, n_bytes
;
93 /* obtain a buffer to read from */
94 b
= pw_stream_dequeue_buffer(v
->stream
);
96 error_report("out of buffers: %s", strerror(errno
));
101 p
= buf
->datas
[0].data
;
105 /* calculate the total no of bytes to read data from buffer */
106 req
= b
->requested
* v
->frame_size
;
110 n_bytes
= SPA_MIN(req
, buf
->datas
[0].maxsize
);
112 /* get no of available bytes to read data from buffer */
113 avail
= spa_ringbuffer_get_read_index(&v
->ring
, &index
);
116 PWVoiceOut
*vo
= container_of(data
, PWVoiceOut
, v
);
117 audio_pcm_info_clear_buf(&vo
->hw
.info
, p
, n_bytes
/ v
->frame_size
);
119 if ((uint32_t) avail
< n_bytes
) {
121 * PipeWire immediately calls this callback again if we provide
122 * less than n_bytes. Then audio_pcm_info_clear_buf() fills the
123 * rest of the buffer with silence.
128 spa_ringbuffer_read_data(&v
->ring
,
129 v
->buffer
, RINGBUFFER_SIZE
,
130 index
& RINGBUFFER_MASK
, p
, n_bytes
);
133 spa_ringbuffer_read_update(&v
->ring
, index
);
136 buf
->datas
[0].chunk
->offset
= 0;
137 buf
->datas
[0].chunk
->stride
= v
->frame_size
;
138 buf
->datas
[0].chunk
->size
= n_bytes
;
140 /* queue the buffer for playback */
141 pw_stream_queue_buffer(v
->stream
, b
);
144 /* output data processing function to generate stuffs in the buffer */
146 capture_on_process(void *data
)
148 PWVoice
*v
= (PWVoice
*) data
;
151 struct spa_buffer
*buf
;
153 uint32_t index
, offs
, n_bytes
;
157 /* obtain a buffer */
158 b
= pw_stream_dequeue_buffer(v
->stream
);
160 error_report("out of buffers: %s", strerror(errno
));
164 /* Write data into buffer */
166 p
= buf
->datas
[0].data
;
170 offs
= SPA_MIN(buf
->datas
[0].chunk
->offset
, buf
->datas
[0].maxsize
);
171 n_bytes
= SPA_MIN(buf
->datas
[0].chunk
->size
, buf
->datas
[0].maxsize
- offs
);
173 filled
= spa_ringbuffer_get_write_index(&v
->ring
, &index
);
177 error_report("%p: underrun write:%u filled:%d", p
, index
, filled
);
179 if ((uint32_t) filled
+ n_bytes
> RINGBUFFER_SIZE
) {
180 error_report("%p: overrun write:%u filled:%d + size:%u > max:%u",
181 p
, index
, filled
, n_bytes
, RINGBUFFER_SIZE
);
184 spa_ringbuffer_write_data(&v
->ring
,
185 v
->buffer
, RINGBUFFER_SIZE
,
186 index
& RINGBUFFER_MASK
,
187 SPA_PTROFF(p
, offs
, void), n_bytes
);
189 spa_ringbuffer_write_update(&v
->ring
, index
);
191 /* queue the buffer for playback */
192 pw_stream_queue_buffer(v
->stream
, b
);
196 on_stream_state_changed(void *data
, enum pw_stream_state old
,
197 enum pw_stream_state state
, const char *error
)
199 PWVoice
*v
= (PWVoice
*) data
;
201 trace_pw_state_changed(pw_stream_get_node_id(v
->stream
),
202 pw_stream_state_as_string(state
));
205 static const struct pw_stream_events capture_stream_events
= {
206 PW_VERSION_STREAM_EVENTS
,
207 .destroy
= stream_destroy
,
208 .state_changed
= on_stream_state_changed
,
209 .process
= capture_on_process
212 static const struct pw_stream_events playback_stream_events
= {
213 PW_VERSION_STREAM_EVENTS
,
214 .destroy
= stream_destroy
,
215 .state_changed
= on_stream_state_changed
,
216 .process
= playback_on_process
220 qpw_read(HWVoiceIn
*hw
, void *data
, size_t len
)
222 PWVoiceIn
*pw
= (PWVoiceIn
*) hw
;
225 const char *error
= NULL
;
230 pw_thread_loop_lock(c
->thread_loop
);
231 if (pw_stream_get_state(v
->stream
, &error
) != PW_STREAM_STATE_STREAMING
) {
232 /* wait for stream to become ready */
236 /* get no of available bytes to read data from buffer */
237 avail
= spa_ringbuffer_get_read_index(&v
->ring
, &index
);
239 trace_pw_read(avail
, index
, len
);
241 if (avail
< (int32_t) len
) {
245 spa_ringbuffer_read_data(&v
->ring
,
246 v
->buffer
, RINGBUFFER_SIZE
,
247 index
& RINGBUFFER_MASK
, data
, len
);
249 spa_ringbuffer_read_update(&v
->ring
, index
);
253 pw_thread_loop_unlock(c
->thread_loop
);
257 static size_t qpw_buffer_get_free(HWVoiceOut
*hw
)
259 PWVoiceOut
*pw
= (PWVoiceOut
*)hw
;
262 const char *error
= NULL
;
263 int32_t filled
, avail
;
266 pw_thread_loop_lock(c
->thread_loop
);
267 if (pw_stream_get_state(v
->stream
, &error
) != PW_STREAM_STATE_STREAMING
) {
268 /* wait for stream to become ready */
273 filled
= spa_ringbuffer_get_write_index(&v
->ring
, &index
);
274 avail
= v
->highwater_mark
- filled
;
277 pw_thread_loop_unlock(c
->thread_loop
);
282 qpw_write(HWVoiceOut
*hw
, void *data
, size_t len
)
284 PWVoiceOut
*pw
= (PWVoiceOut
*) hw
;
287 const char *error
= NULL
;
288 int32_t filled
, avail
;
291 pw_thread_loop_lock(c
->thread_loop
);
292 if (pw_stream_get_state(v
->stream
, &error
) != PW_STREAM_STATE_STREAMING
) {
293 /* wait for stream to become ready */
297 filled
= spa_ringbuffer_get_write_index(&v
->ring
, &index
);
298 avail
= v
->highwater_mark
- filled
;
300 trace_pw_write(filled
, avail
, index
, len
);
307 error_report("%p: underrun write:%u filled:%d", pw
, index
, filled
);
309 if ((uint32_t) filled
+ len
> RINGBUFFER_SIZE
) {
310 error_report("%p: overrun write:%u filled:%d + size:%zu > max:%u",
311 pw
, index
, filled
, len
, RINGBUFFER_SIZE
);
315 spa_ringbuffer_write_data(&v
->ring
,
316 v
->buffer
, RINGBUFFER_SIZE
,
317 index
& RINGBUFFER_MASK
, data
, len
);
319 spa_ringbuffer_write_update(&v
->ring
, index
);
322 pw_thread_loop_unlock(c
->thread_loop
);
327 audfmt_to_pw(AudioFormat fmt
, int endianness
)
332 case AUDIO_FORMAT_S8
:
333 format
= SPA_AUDIO_FORMAT_S8
;
335 case AUDIO_FORMAT_U8
:
336 format
= SPA_AUDIO_FORMAT_U8
;
338 case AUDIO_FORMAT_S16
:
339 format
= endianness
? SPA_AUDIO_FORMAT_S16_BE
: SPA_AUDIO_FORMAT_S16_LE
;
341 case AUDIO_FORMAT_U16
:
342 format
= endianness
? SPA_AUDIO_FORMAT_U16_BE
: SPA_AUDIO_FORMAT_U16_LE
;
344 case AUDIO_FORMAT_S32
:
345 format
= endianness
? SPA_AUDIO_FORMAT_S32_BE
: SPA_AUDIO_FORMAT_S32_LE
;
347 case AUDIO_FORMAT_U32
:
348 format
= endianness
? SPA_AUDIO_FORMAT_U32_BE
: SPA_AUDIO_FORMAT_U32_LE
;
350 case AUDIO_FORMAT_F32
:
351 format
= endianness
? SPA_AUDIO_FORMAT_F32_BE
: SPA_AUDIO_FORMAT_F32_LE
;
354 dolog("Internal logic error: Bad audio format %d\n", fmt
);
355 format
= SPA_AUDIO_FORMAT_U8
;
362 pw_to_audfmt(enum spa_audio_format fmt
, int *endianness
,
363 uint32_t *sample_size
)
366 case SPA_AUDIO_FORMAT_S8
:
368 return AUDIO_FORMAT_S8
;
369 case SPA_AUDIO_FORMAT_U8
:
371 return AUDIO_FORMAT_U8
;
372 case SPA_AUDIO_FORMAT_S16_BE
:
375 return AUDIO_FORMAT_S16
;
376 case SPA_AUDIO_FORMAT_S16_LE
:
379 return AUDIO_FORMAT_S16
;
380 case SPA_AUDIO_FORMAT_U16_BE
:
383 return AUDIO_FORMAT_U16
;
384 case SPA_AUDIO_FORMAT_U16_LE
:
387 return AUDIO_FORMAT_U16
;
388 case SPA_AUDIO_FORMAT_S32_BE
:
391 return AUDIO_FORMAT_S32
;
392 case SPA_AUDIO_FORMAT_S32_LE
:
395 return AUDIO_FORMAT_S32
;
396 case SPA_AUDIO_FORMAT_U32_BE
:
399 return AUDIO_FORMAT_U32
;
400 case SPA_AUDIO_FORMAT_U32_LE
:
403 return AUDIO_FORMAT_U32
;
404 case SPA_AUDIO_FORMAT_F32_BE
:
407 return AUDIO_FORMAT_F32
;
408 case SPA_AUDIO_FORMAT_F32_LE
:
411 return AUDIO_FORMAT_F32
;
414 dolog("Internal logic error: Bad spa_audio_format %d\n", fmt
);
415 return AUDIO_FORMAT_U8
;
420 qpw_stream_new(pwaudio
*c
, PWVoice
*v
, const char *stream_name
,
421 const char *name
, enum spa_direction dir
)
425 const struct spa_pod
*params
[2];
426 uint8_t buffer
[1024];
427 struct spa_pod_builder b
;
428 uint64_t buf_samples
;
429 struct pw_properties
*props
;
431 props
= pw_properties_new(NULL
, NULL
);
433 error_report("Failed to create PW properties: %s", g_strerror(errno
));
437 /* 75% of the timer period for faster updates */
438 buf_samples
= (uint64_t)v
->g
->dev
->timer_period
* v
->info
.rate
440 pw_properties_setf(props
, PW_KEY_NODE_LATENCY
, "%" PRIu64
"/%u",
441 buf_samples
, v
->info
.rate
);
443 trace_pw_period(buf_samples
, v
->info
.rate
);
445 pw_properties_set(props
, PW_KEY_TARGET_OBJECT
, name
);
447 v
->stream
= pw_stream_new(c
->core
, stream_name
, props
);
448 if (v
->stream
== NULL
) {
449 error_report("Failed to create PW stream: %s", g_strerror(errno
));
453 if (dir
== SPA_DIRECTION_INPUT
) {
454 pw_stream_add_listener(v
->stream
,
455 &v
->stream_listener
, &capture_stream_events
, v
);
457 pw_stream_add_listener(v
->stream
,
458 &v
->stream_listener
, &playback_stream_events
, v
);
462 spa_pod_builder_init(&b
, buffer
, sizeof(buffer
));
463 params
[n_params
++] = spa_format_audio_raw_build(&b
,
464 SPA_PARAM_EnumFormat
,
467 /* connect the stream to a sink or source */
468 res
= pw_stream_connect(v
->stream
,
470 SPA_DIRECTION_INPUT
? PW_DIRECTION_INPUT
:
471 PW_DIRECTION_OUTPUT
, PW_ID_ANY
,
472 PW_STREAM_FLAG_AUTOCONNECT
|
473 PW_STREAM_FLAG_INACTIVE
|
474 PW_STREAM_FLAG_MAP_BUFFERS
|
475 PW_STREAM_FLAG_RT_PROCESS
, params
, n_params
);
477 error_report("Failed to connect PW stream: %s", g_strerror(errno
));
478 pw_stream_destroy(v
->stream
);
486 qpw_set_position(uint32_t channels
, uint32_t position
[SPA_AUDIO_MAX_CHANNELS
])
488 memcpy(position
, (uint32_t[SPA_AUDIO_MAX_CHANNELS
]) { SPA_AUDIO_CHANNEL_UNKNOWN
, },
489 sizeof(uint32_t) * SPA_AUDIO_MAX_CHANNELS
);
491 * TODO: This currently expects the only frontend supporting more than 2
492 * channels is the usb-audio. We will need some means to set channel
493 * order when a new frontend gains multi-channel support.
497 position
[6] = SPA_AUDIO_CHANNEL_SL
;
498 position
[7] = SPA_AUDIO_CHANNEL_SR
;
501 position
[2] = SPA_AUDIO_CHANNEL_FC
;
502 position
[3] = SPA_AUDIO_CHANNEL_LFE
;
503 position
[4] = SPA_AUDIO_CHANNEL_RL
;
504 position
[5] = SPA_AUDIO_CHANNEL_RR
;
507 position
[0] = SPA_AUDIO_CHANNEL_FL
;
508 position
[1] = SPA_AUDIO_CHANNEL_FR
;
511 position
[0] = SPA_AUDIO_CHANNEL_MONO
;
514 dolog("Internal error: unsupported channel count %d\n", channels
);
519 qpw_init_out(HWVoiceOut
*hw
, struct audsettings
*as
, void *drv_opaque
)
521 PWVoiceOut
*pw
= (PWVoiceOut
*) hw
;
523 struct audsettings obt_as
= *as
;
524 pwaudio
*c
= v
->g
= drv_opaque
;
525 AudiodevPipewireOptions
*popts
= &c
->dev
->u
.pipewire
;
526 AudiodevPipewirePerDirectionOptions
*ppdo
= popts
->out
;
529 pw_thread_loop_lock(c
->thread_loop
);
531 v
->info
.format
= audfmt_to_pw(as
->fmt
, as
->endianness
);
532 v
->info
.channels
= as
->nchannels
;
533 qpw_set_position(as
->nchannels
, v
->info
.position
);
534 v
->info
.rate
= as
->freq
;
537 pw_to_audfmt(v
->info
.format
, &obt_as
.endianness
, &v
->frame_size
);
538 v
->frame_size
*= as
->nchannels
;
540 v
->req
= (uint64_t)c
->dev
->timer_period
* v
->info
.rate
541 * 1 / 2 / 1000000 * v
->frame_size
;
543 /* call the function that creates a new stream for playback */
544 r
= qpw_stream_new(c
, v
, ppdo
->stream_name
? : c
->dev
->id
,
545 ppdo
->name
, SPA_DIRECTION_OUTPUT
);
547 pw_thread_loop_unlock(c
->thread_loop
);
551 /* report the audio format we support */
552 audio_pcm_init_info(&hw
->info
, &obt_as
);
554 /* report the buffer size to qemu */
555 hw
->samples
= audio_buffer_frames(
556 qapi_AudiodevPipewirePerDirectionOptions_base(ppdo
), &obt_as
, 46440);
557 v
->highwater_mark
= MIN(RINGBUFFER_SIZE
,
558 (ppdo
->has_latency
? ppdo
->latency
: 46440)
559 * (uint64_t)v
->info
.rate
/ 1000000 * v
->frame_size
);
561 pw_thread_loop_unlock(c
->thread_loop
);
566 qpw_init_in(HWVoiceIn
*hw
, struct audsettings
*as
, void *drv_opaque
)
568 PWVoiceIn
*pw
= (PWVoiceIn
*) hw
;
570 struct audsettings obt_as
= *as
;
571 pwaudio
*c
= v
->g
= drv_opaque
;
572 AudiodevPipewireOptions
*popts
= &c
->dev
->u
.pipewire
;
573 AudiodevPipewirePerDirectionOptions
*ppdo
= popts
->in
;
576 pw_thread_loop_lock(c
->thread_loop
);
578 v
->info
.format
= audfmt_to_pw(as
->fmt
, as
->endianness
);
579 v
->info
.channels
= as
->nchannels
;
580 qpw_set_position(as
->nchannels
, v
->info
.position
);
581 v
->info
.rate
= as
->freq
;
584 pw_to_audfmt(v
->info
.format
, &obt_as
.endianness
, &v
->frame_size
);
585 v
->frame_size
*= as
->nchannels
;
587 /* call the function that creates a new stream for recording */
588 r
= qpw_stream_new(c
, v
, ppdo
->stream_name
? : c
->dev
->id
,
589 ppdo
->name
, SPA_DIRECTION_INPUT
);
591 pw_thread_loop_unlock(c
->thread_loop
);
595 /* report the audio format we support */
596 audio_pcm_init_info(&hw
->info
, &obt_as
);
598 /* report the buffer size to qemu */
599 hw
->samples
= audio_buffer_frames(
600 qapi_AudiodevPipewirePerDirectionOptions_base(ppdo
), &obt_as
, 46440);
602 pw_thread_loop_unlock(c
->thread_loop
);
607 qpw_voice_fini(PWVoice
*v
)
614 pw_thread_loop_lock(c
->thread_loop
);
615 pw_stream_destroy(v
->stream
);
617 pw_thread_loop_unlock(c
->thread_loop
);
621 qpw_fini_out(HWVoiceOut
*hw
)
623 qpw_voice_fini(&PW_VOICE_OUT(hw
)->v
);
627 qpw_fini_in(HWVoiceIn
*hw
)
629 qpw_voice_fini(&PW_VOICE_IN(hw
)->v
);
633 qpw_voice_set_enabled(PWVoice
*v
, bool enable
)
636 pw_thread_loop_lock(c
->thread_loop
);
637 pw_stream_set_active(v
->stream
, enable
);
638 pw_thread_loop_unlock(c
->thread_loop
);
642 qpw_enable_out(HWVoiceOut
*hw
, bool enable
)
644 qpw_voice_set_enabled(&PW_VOICE_OUT(hw
)->v
, enable
);
648 qpw_enable_in(HWVoiceIn
*hw
, bool enable
)
650 qpw_voice_set_enabled(&PW_VOICE_IN(hw
)->v
, enable
);
654 qpw_voice_set_volume(PWVoice
*v
, Volume
*vol
)
659 pw_thread_loop_lock(c
->thread_loop
);
660 v
->volume
.channels
= vol
->channels
;
662 for (i
= 0; i
< vol
->channels
; ++i
) {
663 v
->volume
.values
[i
] = (float)vol
->vol
[i
] / 255;
666 ret
= pw_stream_set_control(v
->stream
,
667 SPA_PROP_channelVolumes
, v
->volume
.channels
, v
->volume
.values
, 0);
668 trace_pw_vol(ret
== 0 ? "success" : "failed");
670 v
->muted
= vol
->mute
;
671 float val
= v
->muted
? 1.f
: 0.f
;
672 ret
= pw_stream_set_control(v
->stream
, SPA_PROP_mute
, 1, &val
, 0);
673 pw_thread_loop_unlock(c
->thread_loop
);
677 qpw_volume_out(HWVoiceOut
*hw
, Volume
*vol
)
679 qpw_voice_set_volume(&PW_VOICE_OUT(hw
)->v
, vol
);
683 qpw_volume_in(HWVoiceIn
*hw
, Volume
*vol
)
685 qpw_voice_set_volume(&PW_VOICE_IN(hw
)->v
, vol
);
688 static int wait_resync(pwaudio
*pw
)
691 pw
->pending_seq
= pw_core_sync(pw
->core
, PW_ID_CORE
, pw
->pending_seq
);
694 pw_thread_loop_wait(pw
->thread_loop
);
701 if (pw
->pending_seq
== pw
->last_seq
) {
709 on_core_error(void *data
, uint32_t id
, int seq
, int res
, const char *message
)
713 error_report("error id:%u seq:%d res:%d (%s): %s",
714 id
, seq
, res
, spa_strerror(res
), message
);
716 /* stop and exit the thread loop */
717 pw_thread_loop_signal(pw
->thread_loop
, FALSE
);
721 on_core_done(void *data
, uint32_t id
, int seq
)
724 assert(id
== PW_ID_CORE
);
726 if (pw
->pending_seq
== seq
) {
727 /* stop and exit the thread loop */
728 pw_thread_loop_signal(pw
->thread_loop
, FALSE
);
732 static const struct pw_core_events core_events
= {
733 PW_VERSION_CORE_EVENTS
,
734 .done
= on_core_done
,
735 .error
= on_core_error
,
739 qpw_audio_init(Audiodev
*dev
, Error
**errp
)
741 g_autofree pwaudio
*pw
= g_new0(pwaudio
, 1);
743 assert(dev
->driver
== AUDIODEV_DRIVER_PIPEWIRE
);
744 trace_pw_audio_init();
749 pw
->thread_loop
= pw_thread_loop_new("PipeWire thread loop", NULL
);
750 if (pw
->thread_loop
== NULL
) {
751 error_setg_errno(errp
, errno
, "Could not create PipeWire loop");
756 pw_context_new(pw_thread_loop_get_loop(pw
->thread_loop
), NULL
, 0);
757 if (pw
->context
== NULL
) {
758 error_setg_errno(errp
, errno
, "Could not create PipeWire context");
762 if (pw_thread_loop_start(pw
->thread_loop
) < 0) {
763 error_setg_errno(errp
, errno
, "Could not start PipeWire loop");
767 pw_thread_loop_lock(pw
->thread_loop
);
769 pw
->core
= pw_context_connect(pw
->context
, NULL
, 0);
770 if (pw
->core
== NULL
) {
771 pw_thread_loop_unlock(pw
->thread_loop
);
775 if (pw_core_add_listener(pw
->core
, &pw
->core_listener
,
776 &core_events
, pw
) < 0) {
777 pw_thread_loop_unlock(pw
->thread_loop
);
780 if (wait_resync(pw
) < 0) {
781 pw_thread_loop_unlock(pw
->thread_loop
);
784 pw_thread_loop_unlock(pw
->thread_loop
);
786 return g_steal_pointer(&pw
);
789 error_setg(errp
, "Failed to initialize PW context");
791 if (pw
->thread_loop
) {
792 pw_thread_loop_stop(pw
->thread_loop
);
794 g_clear_pointer(&pw
->context
, pw_context_destroy
);
795 g_clear_pointer(&pw
->thread_loop
, pw_thread_loop_destroy
);
800 qpw_audio_fini(void *opaque
)
802 pwaudio
*pw
= opaque
;
804 if (pw
->thread_loop
) {
805 pw_thread_loop_stop(pw
->thread_loop
);
809 spa_hook_remove(&pw
->core_listener
);
810 spa_zero(pw
->core_listener
);
811 pw_core_disconnect(pw
->core
);
815 pw_context_destroy(pw
->context
);
817 pw_thread_loop_destroy(pw
->thread_loop
);
822 static struct audio_pcm_ops qpw_pcm_ops
= {
823 .init_out
= qpw_init_out
,
824 .fini_out
= qpw_fini_out
,
826 .buffer_get_free
= qpw_buffer_get_free
,
827 .run_buffer_out
= audio_generic_run_buffer_out
,
828 .enable_out
= qpw_enable_out
,
829 .volume_out
= qpw_volume_out
,
830 .volume_in
= qpw_volume_in
,
832 .init_in
= qpw_init_in
,
833 .fini_in
= qpw_fini_in
,
835 .run_buffer_in
= audio_generic_run_buffer_in
,
836 .enable_in
= qpw_enable_in
839 static struct audio_driver pw_audio_driver
= {
841 .descr
= "http://www.pipewire.org/",
842 .init
= qpw_audio_init
,
843 .fini
= qpw_audio_fini
,
844 .pcm_ops
= &qpw_pcm_ops
,
845 .max_voices_out
= INT_MAX
,
846 .max_voices_in
= INT_MAX
,
847 .voice_size_out
= sizeof(PWVoiceOut
),
848 .voice_size_in
= sizeof(PWVoiceIn
),
852 register_audio_pw(void)
854 audio_driver_register(&pw_audio_driver
);
857 type_init(register_audio_pw
);