misc/other: spelling fixes
[qemu/ar7.git] / audio / pwaudio.c
blobb6a38738ee93df2082605d70d29e2ed25fdf3e1a
1 /*
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
9 */
11 #include "qemu/osdep.h"
12 #include "qemu/module.h"
13 #include "audio.h"
14 #include <errno.h>
15 #include "qemu/error-report.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>
22 #include "trace.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 {
31 uint32_t channels;
32 float values[SPA_AUDIO_MAX_CHANNELS];
33 } pwvolume;
35 typedef struct pwaudio {
36 Audiodev *dev;
37 struct pw_thread_loop *thread_loop;
38 struct pw_context *context;
40 struct pw_core *core;
41 struct spa_hook core_listener;
42 int last_seq, pending_seq, error;
43 } pwaudio;
45 typedef struct PWVoice {
46 pwaudio *g;
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];
55 pwvolume volume;
56 bool muted;
57 } PWVoice;
59 typedef struct PWVoiceOut {
60 HWVoiceOut hw;
61 PWVoice v;
62 } PWVoiceOut;
64 typedef struct PWVoiceIn {
65 HWVoiceIn hw;
66 PWVoice v;
67 } PWVoiceIn;
69 #define PW_VOICE_IN(v) ((PWVoiceIn *)v)
70 #define PW_VOICE_OUT(v) ((PWVoiceOut *)v)
72 static void
73 stream_destroy(void *data)
75 PWVoice *v = (PWVoice *) data;
76 spa_hook_remove(&v->stream_listener);
77 v->stream = NULL;
80 /* output data processing function to read stuffs from the buffer */
81 static void
82 playback_on_process(void *data)
84 PWVoice *v = data;
85 void *p;
86 struct pw_buffer *b;
87 struct spa_buffer *buf;
88 uint32_t req, index, n_bytes;
89 int32_t avail;
91 assert(v->stream);
93 /* obtain a buffer to read from */
94 b = pw_stream_dequeue_buffer(v->stream);
95 if (b == NULL) {
96 error_report("out of buffers: %s", strerror(errno));
97 return;
100 buf = b->buffer;
101 p = buf->datas[0].data;
102 if (p == NULL) {
103 return;
105 /* calculate the total no of bytes to read data from buffer */
106 req = b->requested * v->frame_size;
107 if (req == 0) {
108 req = v->req;
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);
115 if (avail <= 0) {
116 PWVoiceOut *vo = container_of(data, PWVoiceOut, v);
117 audio_pcm_info_clear_buf(&vo->hw.info, p, n_bytes / v->frame_size);
118 } else {
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.
125 n_bytes = avail;
128 spa_ringbuffer_read_data(&v->ring,
129 v->buffer, RINGBUFFER_SIZE,
130 index & RINGBUFFER_MASK, p, n_bytes);
132 index += 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 */
145 static void
146 capture_on_process(void *data)
148 PWVoice *v = (PWVoice *) data;
149 void *p;
150 struct pw_buffer *b;
151 struct spa_buffer *buf;
152 int32_t filled;
153 uint32_t index, offs, n_bytes;
155 assert(v->stream);
157 /* obtain a buffer */
158 b = pw_stream_dequeue_buffer(v->stream);
159 if (b == NULL) {
160 error_report("out of buffers: %s", strerror(errno));
161 return;
164 /* Write data into buffer */
165 buf = b->buffer;
166 p = buf->datas[0].data;
167 if (p == NULL) {
168 return;
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);
176 if (filled < 0) {
177 error_report("%p: underrun write:%u filled:%d", p, index, filled);
178 } else {
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);
188 index += n_bytes;
189 spa_ringbuffer_write_update(&v->ring, index);
191 /* queue the buffer for playback */
192 pw_stream_queue_buffer(v->stream, b);
195 static void
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
219 static size_t
220 qpw_read(HWVoiceIn *hw, void *data, size_t len)
222 PWVoiceIn *pw = (PWVoiceIn *) hw;
223 PWVoice *v = &pw->v;
224 pwaudio *c = v->g;
225 const char *error = NULL;
226 size_t l;
227 int32_t avail;
228 uint32_t index;
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 */
233 l = 0;
234 goto done_unlock;
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) {
242 len = avail;
245 spa_ringbuffer_read_data(&v->ring,
246 v->buffer, RINGBUFFER_SIZE,
247 index & RINGBUFFER_MASK, data, len);
248 index += len;
249 spa_ringbuffer_read_update(&v->ring, index);
250 l = len;
252 done_unlock:
253 pw_thread_loop_unlock(c->thread_loop);
254 return l;
257 static size_t qpw_buffer_get_free(HWVoiceOut *hw)
259 PWVoiceOut *pw = (PWVoiceOut *)hw;
260 PWVoice *v = &pw->v;
261 pwaudio *c = v->g;
262 const char *error = NULL;
263 int32_t filled, avail;
264 uint32_t index;
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 */
269 avail = 0;
270 goto done_unlock;
273 filled = spa_ringbuffer_get_write_index(&v->ring, &index);
274 avail = v->highwater_mark - filled;
276 done_unlock:
277 pw_thread_loop_unlock(c->thread_loop);
278 return avail;
281 static size_t
282 qpw_write(HWVoiceOut *hw, void *data, size_t len)
284 PWVoiceOut *pw = (PWVoiceOut *) hw;
285 PWVoice *v = &pw->v;
286 pwaudio *c = v->g;
287 const char *error = NULL;
288 int32_t filled, avail;
289 uint32_t index;
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 */
294 len = 0;
295 goto done_unlock;
297 filled = spa_ringbuffer_get_write_index(&v->ring, &index);
298 avail = v->highwater_mark - filled;
300 trace_pw_write(filled, avail, index, len);
302 if (len > avail) {
303 len = avail;
306 if (filled < 0) {
307 error_report("%p: underrun write:%u filled:%d", pw, index, filled);
308 } else {
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);
318 index += len;
319 spa_ringbuffer_write_update(&v->ring, index);
321 done_unlock:
322 pw_thread_loop_unlock(c->thread_loop);
323 return len;
326 static int
327 audfmt_to_pw(AudioFormat fmt, int endianness)
329 int format;
331 switch (fmt) {
332 case AUDIO_FORMAT_S8:
333 format = SPA_AUDIO_FORMAT_S8;
334 break;
335 case AUDIO_FORMAT_U8:
336 format = SPA_AUDIO_FORMAT_U8;
337 break;
338 case AUDIO_FORMAT_S16:
339 format = endianness ? SPA_AUDIO_FORMAT_S16_BE : SPA_AUDIO_FORMAT_S16_LE;
340 break;
341 case AUDIO_FORMAT_U16:
342 format = endianness ? SPA_AUDIO_FORMAT_U16_BE : SPA_AUDIO_FORMAT_U16_LE;
343 break;
344 case AUDIO_FORMAT_S32:
345 format = endianness ? SPA_AUDIO_FORMAT_S32_BE : SPA_AUDIO_FORMAT_S32_LE;
346 break;
347 case AUDIO_FORMAT_U32:
348 format = endianness ? SPA_AUDIO_FORMAT_U32_BE : SPA_AUDIO_FORMAT_U32_LE;
349 break;
350 case AUDIO_FORMAT_F32:
351 format = endianness ? SPA_AUDIO_FORMAT_F32_BE : SPA_AUDIO_FORMAT_F32_LE;
352 break;
353 default:
354 dolog("Internal logic error: Bad audio format %d\n", fmt);
355 format = SPA_AUDIO_FORMAT_U8;
356 break;
358 return format;
361 static AudioFormat
362 pw_to_audfmt(enum spa_audio_format fmt, int *endianness,
363 uint32_t *sample_size)
365 switch (fmt) {
366 case SPA_AUDIO_FORMAT_S8:
367 *sample_size = 1;
368 return AUDIO_FORMAT_S8;
369 case SPA_AUDIO_FORMAT_U8:
370 *sample_size = 1;
371 return AUDIO_FORMAT_U8;
372 case SPA_AUDIO_FORMAT_S16_BE:
373 *sample_size = 2;
374 *endianness = 1;
375 return AUDIO_FORMAT_S16;
376 case SPA_AUDIO_FORMAT_S16_LE:
377 *sample_size = 2;
378 *endianness = 0;
379 return AUDIO_FORMAT_S16;
380 case SPA_AUDIO_FORMAT_U16_BE:
381 *sample_size = 2;
382 *endianness = 1;
383 return AUDIO_FORMAT_U16;
384 case SPA_AUDIO_FORMAT_U16_LE:
385 *sample_size = 2;
386 *endianness = 0;
387 return AUDIO_FORMAT_U16;
388 case SPA_AUDIO_FORMAT_S32_BE:
389 *sample_size = 4;
390 *endianness = 1;
391 return AUDIO_FORMAT_S32;
392 case SPA_AUDIO_FORMAT_S32_LE:
393 *sample_size = 4;
394 *endianness = 0;
395 return AUDIO_FORMAT_S32;
396 case SPA_AUDIO_FORMAT_U32_BE:
397 *sample_size = 4;
398 *endianness = 1;
399 return AUDIO_FORMAT_U32;
400 case SPA_AUDIO_FORMAT_U32_LE:
401 *sample_size = 4;
402 *endianness = 0;
403 return AUDIO_FORMAT_U32;
404 case SPA_AUDIO_FORMAT_F32_BE:
405 *sample_size = 4;
406 *endianness = 1;
407 return AUDIO_FORMAT_F32;
408 case SPA_AUDIO_FORMAT_F32_LE:
409 *sample_size = 4;
410 *endianness = 0;
411 return AUDIO_FORMAT_F32;
412 default:
413 *sample_size = 1;
414 dolog("Internal logic error: Bad spa_audio_format %d\n", fmt);
415 return AUDIO_FORMAT_U8;
419 static int
420 qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
421 const char *name, enum spa_direction dir)
423 int res;
424 uint32_t n_params;
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);
432 if (!props) {
433 error_report("Failed to create PW properties: %s", g_strerror(errno));
434 return -1;
437 /* 75% of the timer period for faster updates */
438 buf_samples = (uint64_t)v->g->dev->timer_period * v->info.rate
439 * 3 / 4 / 1000000;
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);
444 if (name) {
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));
450 return -1;
453 if (dir == SPA_DIRECTION_INPUT) {
454 pw_stream_add_listener(v->stream,
455 &v->stream_listener, &capture_stream_events, v);
456 } else {
457 pw_stream_add_listener(v->stream,
458 &v->stream_listener, &playback_stream_events, v);
461 n_params = 0;
462 spa_pod_builder_init(&b, buffer, sizeof(buffer));
463 params[n_params++] = spa_format_audio_raw_build(&b,
464 SPA_PARAM_EnumFormat,
465 &v->info);
467 /* connect the stream to a sink or source */
468 res = pw_stream_connect(v->stream,
469 dir ==
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);
476 if (res < 0) {
477 error_report("Failed to connect PW stream: %s", g_strerror(errno));
478 pw_stream_destroy(v->stream);
479 return -1;
482 return 0;
485 static void
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.
495 switch (channels) {
496 case 8:
497 position[6] = SPA_AUDIO_CHANNEL_SL;
498 position[7] = SPA_AUDIO_CHANNEL_SR;
499 /* fallthrough */
500 case 6:
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;
505 /* fallthrough */
506 case 2:
507 position[0] = SPA_AUDIO_CHANNEL_FL;
508 position[1] = SPA_AUDIO_CHANNEL_FR;
509 break;
510 case 1:
511 position[0] = SPA_AUDIO_CHANNEL_MONO;
512 break;
513 default:
514 dolog("Internal error: unsupported channel count %d\n", channels);
518 static int
519 qpw_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
521 PWVoiceOut *pw = (PWVoiceOut *) hw;
522 PWVoice *v = &pw->v;
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;
527 int r;
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;
536 obt_as.fmt =
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);
546 if (r < 0) {
547 pw_thread_loop_unlock(c->thread_loop);
548 return -1;
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);
562 return 0;
565 static int
566 qpw_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
568 PWVoiceIn *pw = (PWVoiceIn *) hw;
569 PWVoice *v = &pw->v;
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;
574 int r;
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;
583 obt_as.fmt =
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);
590 if (r < 0) {
591 pw_thread_loop_unlock(c->thread_loop);
592 return -1;
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);
603 return 0;
606 static void
607 qpw_voice_fini(PWVoice *v)
609 pwaudio *c = v->g;
611 if (!v->stream) {
612 return;
614 pw_thread_loop_lock(c->thread_loop);
615 pw_stream_destroy(v->stream);
616 v->stream = NULL;
617 pw_thread_loop_unlock(c->thread_loop);
620 static void
621 qpw_fini_out(HWVoiceOut *hw)
623 qpw_voice_fini(&PW_VOICE_OUT(hw)->v);
626 static void
627 qpw_fini_in(HWVoiceIn *hw)
629 qpw_voice_fini(&PW_VOICE_IN(hw)->v);
632 static void
633 qpw_voice_set_enabled(PWVoice *v, bool enable)
635 pwaudio *c = v->g;
636 pw_thread_loop_lock(c->thread_loop);
637 pw_stream_set_active(v->stream, enable);
638 pw_thread_loop_unlock(c->thread_loop);
641 static void
642 qpw_enable_out(HWVoiceOut *hw, bool enable)
644 qpw_voice_set_enabled(&PW_VOICE_OUT(hw)->v, enable);
647 static void
648 qpw_enable_in(HWVoiceIn *hw, bool enable)
650 qpw_voice_set_enabled(&PW_VOICE_IN(hw)->v, enable);
653 static void
654 qpw_voice_set_volume(PWVoice *v, Volume *vol)
656 pwaudio *c = v->g;
657 int i, ret;
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);
676 static void
677 qpw_volume_out(HWVoiceOut *hw, Volume *vol)
679 qpw_voice_set_volume(&PW_VOICE_OUT(hw)->v, vol);
682 static void
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)
690 int res;
691 pw->pending_seq = pw_core_sync(pw->core, PW_ID_CORE, pw->pending_seq);
693 while (true) {
694 pw_thread_loop_wait(pw->thread_loop);
696 res = pw->error;
697 if (res < 0) {
698 pw->error = 0;
699 return res;
701 if (pw->pending_seq == pw->last_seq) {
702 break;
705 return 0;
708 static void
709 on_core_error(void *data, uint32_t id, int seq, int res, const char *message)
711 pwaudio *pw = data;
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);
720 static void
721 on_core_done(void *data, uint32_t id, int seq)
723 pwaudio *pw = data;
724 assert(id == PW_ID_CORE);
725 pw->last_seq = seq;
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,
738 static void *
739 qpw_audio_init(Audiodev *dev)
741 g_autofree pwaudio *pw = g_new0(pwaudio, 1);
743 assert(dev->driver == AUDIODEV_DRIVER_PIPEWIRE);
744 trace_pw_audio_init();
746 pw_init(NULL, NULL);
748 pw->dev = dev;
749 pw->thread_loop = pw_thread_loop_new("PipeWire thread loop", NULL);
750 if (pw->thread_loop == NULL) {
751 error_report("Could not create PipeWire loop: %s", g_strerror(errno));
752 goto fail;
755 pw->context =
756 pw_context_new(pw_thread_loop_get_loop(pw->thread_loop), NULL, 0);
757 if (pw->context == NULL) {
758 error_report("Could not create PipeWire context: %s", g_strerror(errno));
759 goto fail;
762 if (pw_thread_loop_start(pw->thread_loop) < 0) {
763 error_report("Could not start PipeWire loop: %s", g_strerror(errno));
764 goto fail;
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);
772 goto fail;
775 if (pw_core_add_listener(pw->core, &pw->core_listener,
776 &core_events, pw) < 0) {
777 pw_thread_loop_unlock(pw->thread_loop);
778 goto fail;
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);
788 fail:
789 AUD_log(AUDIO_CAP, "Failed to initialize PW context");
790 if (pw->thread_loop) {
791 pw_thread_loop_stop(pw->thread_loop);
793 g_clear_pointer(&pw->context, pw_context_destroy);
794 g_clear_pointer(&pw->thread_loop, pw_thread_loop_destroy);
795 return NULL;
798 static void
799 qpw_audio_fini(void *opaque)
801 pwaudio *pw = opaque;
803 if (pw->thread_loop) {
804 pw_thread_loop_stop(pw->thread_loop);
807 if (pw->core) {
808 spa_hook_remove(&pw->core_listener);
809 spa_zero(pw->core_listener);
810 pw_core_disconnect(pw->core);
813 if (pw->context) {
814 pw_context_destroy(pw->context);
816 pw_thread_loop_destroy(pw->thread_loop);
818 g_free(pw);
821 static struct audio_pcm_ops qpw_pcm_ops = {
822 .init_out = qpw_init_out,
823 .fini_out = qpw_fini_out,
824 .write = qpw_write,
825 .buffer_get_free = qpw_buffer_get_free,
826 .run_buffer_out = audio_generic_run_buffer_out,
827 .enable_out = qpw_enable_out,
828 .volume_out = qpw_volume_out,
829 .volume_in = qpw_volume_in,
831 .init_in = qpw_init_in,
832 .fini_in = qpw_fini_in,
833 .read = qpw_read,
834 .run_buffer_in = audio_generic_run_buffer_in,
835 .enable_in = qpw_enable_in
838 static struct audio_driver pw_audio_driver = {
839 .name = "pipewire",
840 .descr = "http://www.pipewire.org/",
841 .init = qpw_audio_init,
842 .fini = qpw_audio_fini,
843 .pcm_ops = &qpw_pcm_ops,
844 .can_be_default = 1,
845 .max_voices_out = INT_MAX,
846 .max_voices_in = INT_MAX,
847 .voice_size_out = sizeof(PWVoiceOut),
848 .voice_size_in = sizeof(PWVoiceIn),
851 static void
852 register_audio_pw(void)
854 audio_driver_register(&pw_audio_driver);
857 type_init(register_audio_pw);