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"
15 #include "qemu/error-report.h"
16 #include "qapi/error.h"
17 #include <spa/param/audio/format-utils.h>
18 #include <spa/utils/ringbuffer.h>
19 #include <spa/utils/result.h>
20 #include <spa/param/props.h>
22 #include <pipewire/pipewire.h>
25 #define AUDIO_CAP "pipewire"
26 #define RINGBUFFER_SIZE (1u << 22)
27 #define RINGBUFFER_MASK (RINGBUFFER_SIZE - 1)
29 #include "audio_int.h"
31 typedef struct pwvolume
{
33 float values
[SPA_AUDIO_MAX_CHANNELS
];
36 typedef struct pwaudio
{
38 struct pw_thread_loop
*thread_loop
;
39 struct pw_context
*context
;
42 struct spa_hook core_listener
;
43 int last_seq
, pending_seq
, error
;
46 typedef struct PWVoice
{
48 struct pw_stream
*stream
;
49 struct spa_hook stream_listener
;
50 struct spa_audio_info_raw info
;
51 uint32_t highwater_mark
;
52 uint32_t frame_size
, req
;
53 struct spa_ringbuffer ring
;
54 uint8_t buffer
[RINGBUFFER_SIZE
];
60 typedef struct PWVoiceOut
{
65 typedef struct PWVoiceIn
{
70 #define PW_VOICE_IN(v) ((PWVoiceIn *)v)
71 #define PW_VOICE_OUT(v) ((PWVoiceOut *)v)
74 stream_destroy(void *data
)
76 PWVoice
*v
= (PWVoice
*) data
;
77 spa_hook_remove(&v
->stream_listener
);
81 /* output data processing function to read stuffs from the buffer */
83 playback_on_process(void *data
)
88 struct spa_buffer
*buf
;
89 uint32_t req
, index
, n_bytes
;
94 /* obtain a buffer to read from */
95 b
= pw_stream_dequeue_buffer(v
->stream
);
97 error_report("out of buffers: %s", strerror(errno
));
102 p
= buf
->datas
[0].data
;
106 /* calculate the total no of bytes to read data from buffer */
107 req
= b
->requested
* v
->frame_size
;
111 n_bytes
= SPA_MIN(req
, buf
->datas
[0].maxsize
);
113 /* get no of available bytes to read data from buffer */
114 avail
= spa_ringbuffer_get_read_index(&v
->ring
, &index
);
117 PWVoiceOut
*vo
= container_of(data
, PWVoiceOut
, v
);
118 audio_pcm_info_clear_buf(&vo
->hw
.info
, p
, n_bytes
/ v
->frame_size
);
120 if ((uint32_t) avail
< n_bytes
) {
122 * PipeWire immediately calls this callback again if we provide
123 * less than n_bytes. Then audio_pcm_info_clear_buf() fills the
124 * rest of the buffer with silence.
129 spa_ringbuffer_read_data(&v
->ring
,
130 v
->buffer
, RINGBUFFER_SIZE
,
131 index
& RINGBUFFER_MASK
, p
, n_bytes
);
134 spa_ringbuffer_read_update(&v
->ring
, index
);
137 buf
->datas
[0].chunk
->offset
= 0;
138 buf
->datas
[0].chunk
->stride
= v
->frame_size
;
139 buf
->datas
[0].chunk
->size
= n_bytes
;
141 /* queue the buffer for playback */
142 pw_stream_queue_buffer(v
->stream
, b
);
145 /* output data processing function to generate stuffs in the buffer */
147 capture_on_process(void *data
)
149 PWVoice
*v
= (PWVoice
*) data
;
152 struct spa_buffer
*buf
;
154 uint32_t index
, offs
, n_bytes
;
158 /* obtain a buffer */
159 b
= pw_stream_dequeue_buffer(v
->stream
);
161 error_report("out of buffers: %s", strerror(errno
));
165 /* Write data into buffer */
167 p
= buf
->datas
[0].data
;
171 offs
= SPA_MIN(buf
->datas
[0].chunk
->offset
, buf
->datas
[0].maxsize
);
172 n_bytes
= SPA_MIN(buf
->datas
[0].chunk
->size
, buf
->datas
[0].maxsize
- offs
);
174 filled
= spa_ringbuffer_get_write_index(&v
->ring
, &index
);
178 error_report("%p: underrun write:%u filled:%d", p
, index
, filled
);
180 if ((uint32_t) filled
+ n_bytes
> RINGBUFFER_SIZE
) {
181 error_report("%p: overrun write:%u filled:%d + size:%u > max:%u",
182 p
, index
, filled
, n_bytes
, RINGBUFFER_SIZE
);
185 spa_ringbuffer_write_data(&v
->ring
,
186 v
->buffer
, RINGBUFFER_SIZE
,
187 index
& RINGBUFFER_MASK
,
188 SPA_PTROFF(p
, offs
, void), n_bytes
);
190 spa_ringbuffer_write_update(&v
->ring
, index
);
192 /* queue the buffer for playback */
193 pw_stream_queue_buffer(v
->stream
, b
);
197 on_stream_state_changed(void *data
, enum pw_stream_state old
,
198 enum pw_stream_state state
, const char *error
)
200 PWVoice
*v
= (PWVoice
*) data
;
202 trace_pw_state_changed(pw_stream_get_node_id(v
->stream
),
203 pw_stream_state_as_string(state
));
206 static const struct pw_stream_events capture_stream_events
= {
207 PW_VERSION_STREAM_EVENTS
,
208 .destroy
= stream_destroy
,
209 .state_changed
= on_stream_state_changed
,
210 .process
= capture_on_process
213 static const struct pw_stream_events playback_stream_events
= {
214 PW_VERSION_STREAM_EVENTS
,
215 .destroy
= stream_destroy
,
216 .state_changed
= on_stream_state_changed
,
217 .process
= playback_on_process
221 qpw_read(HWVoiceIn
*hw
, void *data
, size_t len
)
223 PWVoiceIn
*pw
= (PWVoiceIn
*) hw
;
226 const char *error
= NULL
;
231 pw_thread_loop_lock(c
->thread_loop
);
232 if (pw_stream_get_state(v
->stream
, &error
) != PW_STREAM_STATE_STREAMING
) {
233 /* wait for stream to become ready */
237 /* get no of available bytes to read data from buffer */
238 avail
= spa_ringbuffer_get_read_index(&v
->ring
, &index
);
240 trace_pw_read(avail
, index
, len
);
242 if (avail
< (int32_t) len
) {
246 spa_ringbuffer_read_data(&v
->ring
,
247 v
->buffer
, RINGBUFFER_SIZE
,
248 index
& RINGBUFFER_MASK
, data
, len
);
250 spa_ringbuffer_read_update(&v
->ring
, index
);
254 pw_thread_loop_unlock(c
->thread_loop
);
258 static size_t qpw_buffer_get_free(HWVoiceOut
*hw
)
260 PWVoiceOut
*pw
= (PWVoiceOut
*)hw
;
263 const char *error
= NULL
;
264 int32_t filled
, avail
;
267 pw_thread_loop_lock(c
->thread_loop
);
268 if (pw_stream_get_state(v
->stream
, &error
) != PW_STREAM_STATE_STREAMING
) {
269 /* wait for stream to become ready */
274 filled
= spa_ringbuffer_get_write_index(&v
->ring
, &index
);
275 avail
= v
->highwater_mark
- filled
;
278 pw_thread_loop_unlock(c
->thread_loop
);
283 qpw_write(HWVoiceOut
*hw
, void *data
, size_t len
)
285 PWVoiceOut
*pw
= (PWVoiceOut
*) hw
;
288 const char *error
= NULL
;
289 int32_t filled
, avail
;
292 pw_thread_loop_lock(c
->thread_loop
);
293 if (pw_stream_get_state(v
->stream
, &error
) != PW_STREAM_STATE_STREAMING
) {
294 /* wait for stream to become ready */
298 filled
= spa_ringbuffer_get_write_index(&v
->ring
, &index
);
299 avail
= v
->highwater_mark
- filled
;
301 trace_pw_write(filled
, avail
, index
, len
);
308 error_report("%p: underrun write:%u filled:%d", pw
, index
, filled
);
310 if ((uint32_t) filled
+ len
> RINGBUFFER_SIZE
) {
311 error_report("%p: overrun write:%u filled:%d + size:%zu > max:%u",
312 pw
, index
, filled
, len
, RINGBUFFER_SIZE
);
316 spa_ringbuffer_write_data(&v
->ring
,
317 v
->buffer
, RINGBUFFER_SIZE
,
318 index
& RINGBUFFER_MASK
, data
, len
);
320 spa_ringbuffer_write_update(&v
->ring
, index
);
323 pw_thread_loop_unlock(c
->thread_loop
);
328 audfmt_to_pw(AudioFormat fmt
, int endianness
)
333 case AUDIO_FORMAT_S8
:
334 format
= SPA_AUDIO_FORMAT_S8
;
336 case AUDIO_FORMAT_U8
:
337 format
= SPA_AUDIO_FORMAT_U8
;
339 case AUDIO_FORMAT_S16
:
340 format
= endianness
? SPA_AUDIO_FORMAT_S16_BE
: SPA_AUDIO_FORMAT_S16_LE
;
342 case AUDIO_FORMAT_U16
:
343 format
= endianness
? SPA_AUDIO_FORMAT_U16_BE
: SPA_AUDIO_FORMAT_U16_LE
;
345 case AUDIO_FORMAT_S32
:
346 format
= endianness
? SPA_AUDIO_FORMAT_S32_BE
: SPA_AUDIO_FORMAT_S32_LE
;
348 case AUDIO_FORMAT_U32
:
349 format
= endianness
? SPA_AUDIO_FORMAT_U32_BE
: SPA_AUDIO_FORMAT_U32_LE
;
351 case AUDIO_FORMAT_F32
:
352 format
= endianness
? SPA_AUDIO_FORMAT_F32_BE
: SPA_AUDIO_FORMAT_F32_LE
;
355 dolog("Internal logic error: Bad audio format %d\n", fmt
);
356 format
= SPA_AUDIO_FORMAT_U8
;
363 pw_to_audfmt(enum spa_audio_format fmt
, int *endianness
,
364 uint32_t *sample_size
)
367 case SPA_AUDIO_FORMAT_S8
:
369 return AUDIO_FORMAT_S8
;
370 case SPA_AUDIO_FORMAT_U8
:
372 return AUDIO_FORMAT_U8
;
373 case SPA_AUDIO_FORMAT_S16_BE
:
376 return AUDIO_FORMAT_S16
;
377 case SPA_AUDIO_FORMAT_S16_LE
:
380 return AUDIO_FORMAT_S16
;
381 case SPA_AUDIO_FORMAT_U16_BE
:
384 return AUDIO_FORMAT_U16
;
385 case SPA_AUDIO_FORMAT_U16_LE
:
388 return AUDIO_FORMAT_U16
;
389 case SPA_AUDIO_FORMAT_S32_BE
:
392 return AUDIO_FORMAT_S32
;
393 case SPA_AUDIO_FORMAT_S32_LE
:
396 return AUDIO_FORMAT_S32
;
397 case SPA_AUDIO_FORMAT_U32_BE
:
400 return AUDIO_FORMAT_U32
;
401 case SPA_AUDIO_FORMAT_U32_LE
:
404 return AUDIO_FORMAT_U32
;
405 case SPA_AUDIO_FORMAT_F32_BE
:
408 return AUDIO_FORMAT_F32
;
409 case SPA_AUDIO_FORMAT_F32_LE
:
412 return AUDIO_FORMAT_F32
;
415 dolog("Internal logic error: Bad spa_audio_format %d\n", fmt
);
416 return AUDIO_FORMAT_U8
;
421 qpw_stream_new(pwaudio
*c
, PWVoice
*v
, const char *stream_name
,
422 const char *name
, enum spa_direction dir
)
426 const struct spa_pod
*params
[2];
427 uint8_t buffer
[1024];
428 struct spa_pod_builder b
;
429 uint64_t buf_samples
;
430 struct pw_properties
*props
;
432 props
= pw_properties_new(NULL
, NULL
);
434 error_report("Failed to create PW properties: %s", g_strerror(errno
));
438 /* 75% of the timer period for faster updates */
439 buf_samples
= (uint64_t)v
->g
->dev
->timer_period
* v
->info
.rate
441 pw_properties_setf(props
, PW_KEY_NODE_LATENCY
, "%" PRIu64
"/%u",
442 buf_samples
, v
->info
.rate
);
444 trace_pw_period(buf_samples
, v
->info
.rate
);
446 pw_properties_set(props
, PW_KEY_TARGET_OBJECT
, name
);
448 v
->stream
= pw_stream_new(c
->core
, stream_name
, props
);
449 if (v
->stream
== NULL
) {
450 error_report("Failed to create PW stream: %s", g_strerror(errno
));
454 if (dir
== SPA_DIRECTION_INPUT
) {
455 pw_stream_add_listener(v
->stream
,
456 &v
->stream_listener
, &capture_stream_events
, v
);
458 pw_stream_add_listener(v
->stream
,
459 &v
->stream_listener
, &playback_stream_events
, v
);
463 spa_pod_builder_init(&b
, buffer
, sizeof(buffer
));
464 params
[n_params
++] = spa_format_audio_raw_build(&b
,
465 SPA_PARAM_EnumFormat
,
468 /* connect the stream to a sink or source */
469 res
= pw_stream_connect(v
->stream
,
471 SPA_DIRECTION_INPUT
? PW_DIRECTION_INPUT
:
472 PW_DIRECTION_OUTPUT
, PW_ID_ANY
,
473 PW_STREAM_FLAG_AUTOCONNECT
|
474 PW_STREAM_FLAG_INACTIVE
|
475 PW_STREAM_FLAG_MAP_BUFFERS
|
476 PW_STREAM_FLAG_RT_PROCESS
, params
, n_params
);
478 error_report("Failed to connect PW stream: %s", g_strerror(errno
));
479 pw_stream_destroy(v
->stream
);
487 qpw_set_position(uint32_t channels
, uint32_t position
[SPA_AUDIO_MAX_CHANNELS
])
489 memcpy(position
, (uint32_t[SPA_AUDIO_MAX_CHANNELS
]) { SPA_AUDIO_CHANNEL_UNKNOWN
, },
490 sizeof(uint32_t) * SPA_AUDIO_MAX_CHANNELS
);
492 * TODO: This currently expects the only frontend supporting more than 2
493 * channels is the usb-audio. We will need some means to set channel
494 * order when a new frontend gains multi-channel support.
498 position
[6] = SPA_AUDIO_CHANNEL_SL
;
499 position
[7] = SPA_AUDIO_CHANNEL_SR
;
502 position
[2] = SPA_AUDIO_CHANNEL_FC
;
503 position
[3] = SPA_AUDIO_CHANNEL_LFE
;
504 position
[4] = SPA_AUDIO_CHANNEL_RL
;
505 position
[5] = SPA_AUDIO_CHANNEL_RR
;
508 position
[0] = SPA_AUDIO_CHANNEL_FL
;
509 position
[1] = SPA_AUDIO_CHANNEL_FR
;
512 position
[0] = SPA_AUDIO_CHANNEL_MONO
;
515 dolog("Internal error: unsupported channel count %d\n", channels
);
520 qpw_init_out(HWVoiceOut
*hw
, struct audsettings
*as
, void *drv_opaque
)
522 PWVoiceOut
*pw
= (PWVoiceOut
*) hw
;
524 struct audsettings obt_as
= *as
;
525 pwaudio
*c
= v
->g
= drv_opaque
;
526 AudiodevPipewireOptions
*popts
= &c
->dev
->u
.pipewire
;
527 AudiodevPipewirePerDirectionOptions
*ppdo
= popts
->out
;
530 pw_thread_loop_lock(c
->thread_loop
);
532 v
->info
.format
= audfmt_to_pw(as
->fmt
, as
->endianness
);
533 v
->info
.channels
= as
->nchannels
;
534 qpw_set_position(as
->nchannels
, v
->info
.position
);
535 v
->info
.rate
= as
->freq
;
538 pw_to_audfmt(v
->info
.format
, &obt_as
.endianness
, &v
->frame_size
);
539 v
->frame_size
*= as
->nchannels
;
541 v
->req
= (uint64_t)c
->dev
->timer_period
* v
->info
.rate
542 * 1 / 2 / 1000000 * v
->frame_size
;
544 /* call the function that creates a new stream for playback */
545 r
= qpw_stream_new(c
, v
, ppdo
->stream_name
? : c
->dev
->id
,
546 ppdo
->name
, SPA_DIRECTION_OUTPUT
);
548 pw_thread_loop_unlock(c
->thread_loop
);
552 /* report the audio format we support */
553 audio_pcm_init_info(&hw
->info
, &obt_as
);
555 /* report the buffer size to qemu */
556 hw
->samples
= audio_buffer_frames(
557 qapi_AudiodevPipewirePerDirectionOptions_base(ppdo
), &obt_as
, 46440);
558 v
->highwater_mark
= MIN(RINGBUFFER_SIZE
,
559 (ppdo
->has_latency
? ppdo
->latency
: 46440)
560 * (uint64_t)v
->info
.rate
/ 1000000 * v
->frame_size
);
562 pw_thread_loop_unlock(c
->thread_loop
);
567 qpw_init_in(HWVoiceIn
*hw
, struct audsettings
*as
, void *drv_opaque
)
569 PWVoiceIn
*pw
= (PWVoiceIn
*) hw
;
571 struct audsettings obt_as
= *as
;
572 pwaudio
*c
= v
->g
= drv_opaque
;
573 AudiodevPipewireOptions
*popts
= &c
->dev
->u
.pipewire
;
574 AudiodevPipewirePerDirectionOptions
*ppdo
= popts
->in
;
577 pw_thread_loop_lock(c
->thread_loop
);
579 v
->info
.format
= audfmt_to_pw(as
->fmt
, as
->endianness
);
580 v
->info
.channels
= as
->nchannels
;
581 qpw_set_position(as
->nchannels
, v
->info
.position
);
582 v
->info
.rate
= as
->freq
;
585 pw_to_audfmt(v
->info
.format
, &obt_as
.endianness
, &v
->frame_size
);
586 v
->frame_size
*= as
->nchannels
;
588 /* call the function that creates a new stream for recording */
589 r
= qpw_stream_new(c
, v
, ppdo
->stream_name
? : c
->dev
->id
,
590 ppdo
->name
, SPA_DIRECTION_INPUT
);
592 pw_thread_loop_unlock(c
->thread_loop
);
596 /* report the audio format we support */
597 audio_pcm_init_info(&hw
->info
, &obt_as
);
599 /* report the buffer size to qemu */
600 hw
->samples
= audio_buffer_frames(
601 qapi_AudiodevPipewirePerDirectionOptions_base(ppdo
), &obt_as
, 46440);
603 pw_thread_loop_unlock(c
->thread_loop
);
608 qpw_voice_fini(PWVoice
*v
)
615 pw_thread_loop_lock(c
->thread_loop
);
616 pw_stream_destroy(v
->stream
);
618 pw_thread_loop_unlock(c
->thread_loop
);
622 qpw_fini_out(HWVoiceOut
*hw
)
624 qpw_voice_fini(&PW_VOICE_OUT(hw
)->v
);
628 qpw_fini_in(HWVoiceIn
*hw
)
630 qpw_voice_fini(&PW_VOICE_IN(hw
)->v
);
634 qpw_voice_set_enabled(PWVoice
*v
, bool enable
)
637 pw_thread_loop_lock(c
->thread_loop
);
638 pw_stream_set_active(v
->stream
, enable
);
639 pw_thread_loop_unlock(c
->thread_loop
);
643 qpw_enable_out(HWVoiceOut
*hw
, bool enable
)
645 qpw_voice_set_enabled(&PW_VOICE_OUT(hw
)->v
, enable
);
649 qpw_enable_in(HWVoiceIn
*hw
, bool enable
)
651 qpw_voice_set_enabled(&PW_VOICE_IN(hw
)->v
, enable
);
655 qpw_voice_set_volume(PWVoice
*v
, Volume
*vol
)
660 pw_thread_loop_lock(c
->thread_loop
);
661 v
->volume
.channels
= vol
->channels
;
663 for (i
= 0; i
< vol
->channels
; ++i
) {
664 v
->volume
.values
[i
] = (float)vol
->vol
[i
] / 255;
667 ret
= pw_stream_set_control(v
->stream
,
668 SPA_PROP_channelVolumes
, v
->volume
.channels
, v
->volume
.values
, 0);
669 trace_pw_vol(ret
== 0 ? "success" : "failed");
671 v
->muted
= vol
->mute
;
672 float val
= v
->muted
? 1.f
: 0.f
;
673 ret
= pw_stream_set_control(v
->stream
, SPA_PROP_mute
, 1, &val
, 0);
674 pw_thread_loop_unlock(c
->thread_loop
);
678 qpw_volume_out(HWVoiceOut
*hw
, Volume
*vol
)
680 qpw_voice_set_volume(&PW_VOICE_OUT(hw
)->v
, vol
);
684 qpw_volume_in(HWVoiceIn
*hw
, Volume
*vol
)
686 qpw_voice_set_volume(&PW_VOICE_IN(hw
)->v
, vol
);
689 static int wait_resync(pwaudio
*pw
)
692 pw
->pending_seq
= pw_core_sync(pw
->core
, PW_ID_CORE
, pw
->pending_seq
);
695 pw_thread_loop_wait(pw
->thread_loop
);
702 if (pw
->pending_seq
== pw
->last_seq
) {
710 on_core_error(void *data
, uint32_t id
, int seq
, int res
, const char *message
)
714 error_report("error id:%u seq:%d res:%d (%s): %s",
715 id
, seq
, res
, spa_strerror(res
), message
);
717 /* stop and exit the thread loop */
718 pw_thread_loop_signal(pw
->thread_loop
, FALSE
);
722 on_core_done(void *data
, uint32_t id
, int seq
)
725 assert(id
== PW_ID_CORE
);
727 if (pw
->pending_seq
== seq
) {
728 /* stop and exit the thread loop */
729 pw_thread_loop_signal(pw
->thread_loop
, FALSE
);
733 static const struct pw_core_events core_events
= {
734 PW_VERSION_CORE_EVENTS
,
735 .done
= on_core_done
,
736 .error
= on_core_error
,
740 qpw_audio_init(Audiodev
*dev
, Error
**errp
)
742 g_autofree pwaudio
*pw
= g_new0(pwaudio
, 1);
744 assert(dev
->driver
== AUDIODEV_DRIVER_PIPEWIRE
);
745 trace_pw_audio_init();
750 pw
->thread_loop
= pw_thread_loop_new("PipeWire thread loop", NULL
);
751 if (pw
->thread_loop
== NULL
) {
752 error_setg_errno(errp
, errno
, "Could not create PipeWire loop");
757 pw_context_new(pw_thread_loop_get_loop(pw
->thread_loop
), NULL
, 0);
758 if (pw
->context
== NULL
) {
759 error_setg_errno(errp
, errno
, "Could not create PipeWire context");
763 if (pw_thread_loop_start(pw
->thread_loop
) < 0) {
764 error_setg_errno(errp
, errno
, "Could not start PipeWire loop");
768 pw_thread_loop_lock(pw
->thread_loop
);
770 pw
->core
= pw_context_connect(pw
->context
, NULL
, 0);
771 if (pw
->core
== NULL
) {
772 pw_thread_loop_unlock(pw
->thread_loop
);
776 if (pw_core_add_listener(pw
->core
, &pw
->core_listener
,
777 &core_events
, pw
) < 0) {
778 pw_thread_loop_unlock(pw
->thread_loop
);
781 if (wait_resync(pw
) < 0) {
782 pw_thread_loop_unlock(pw
->thread_loop
);
785 pw_thread_loop_unlock(pw
->thread_loop
);
787 return g_steal_pointer(&pw
);
790 error_setg(errp
, "Failed to initialize PW context");
792 if (pw
->thread_loop
) {
793 pw_thread_loop_stop(pw
->thread_loop
);
795 g_clear_pointer(&pw
->context
, pw_context_destroy
);
796 g_clear_pointer(&pw
->thread_loop
, pw_thread_loop_destroy
);
801 qpw_audio_fini(void *opaque
)
803 pwaudio
*pw
= opaque
;
805 if (pw
->thread_loop
) {
806 pw_thread_loop_stop(pw
->thread_loop
);
810 spa_hook_remove(&pw
->core_listener
);
811 spa_zero(pw
->core_listener
);
812 pw_core_disconnect(pw
->core
);
816 pw_context_destroy(pw
->context
);
818 pw_thread_loop_destroy(pw
->thread_loop
);
823 static struct audio_pcm_ops qpw_pcm_ops
= {
824 .init_out
= qpw_init_out
,
825 .fini_out
= qpw_fini_out
,
827 .buffer_get_free
= qpw_buffer_get_free
,
828 .run_buffer_out
= audio_generic_run_buffer_out
,
829 .enable_out
= qpw_enable_out
,
830 .volume_out
= qpw_volume_out
,
831 .volume_in
= qpw_volume_in
,
833 .init_in
= qpw_init_in
,
834 .fini_in
= qpw_fini_in
,
836 .run_buffer_in
= audio_generic_run_buffer_in
,
837 .enable_in
= qpw_enable_in
840 static struct audio_driver pw_audio_driver
= {
842 .descr
= "http://www.pipewire.org/",
843 .init
= qpw_audio_init
,
844 .fini
= qpw_audio_fini
,
845 .pcm_ops
= &qpw_pcm_ops
,
846 .max_voices_out
= INT_MAX
,
847 .max_voices_in
= INT_MAX
,
848 .voice_size_out
= sizeof(PWVoiceOut
),
849 .voice_size_in
= sizeof(PWVoiceIn
),
853 register_audio_pw(void)
855 audio_driver_register(&pw_audio_driver
);
858 type_init(register_audio_pw
);