xref: /openbmc/qemu/audio/pwaudio.c (revision 669dcb60)
1 /*
2  * QEMU PipeWire audio driver
3  *
4  * Copyright (c) 2023 Red Hat Inc.
5  *
6  * Author: Dorinda Bassey       <dbassey@redhat.com>
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 
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>
20 
21 #include <pipewire/pipewire.h>
22 #include "trace.h"
23 
24 #define AUDIO_CAP "pipewire"
25 #define RINGBUFFER_SIZE    (1u << 22)
26 #define RINGBUFFER_MASK    (RINGBUFFER_SIZE - 1)
27 
28 #include "audio_int.h"
29 
30 typedef struct pwvolume {
31     uint32_t channels;
32     float values[SPA_AUDIO_MAX_CHANNELS];
33 } pwvolume;
34 
35 typedef struct pwaudio {
36     Audiodev *dev;
37     struct pw_thread_loop *thread_loop;
38     struct pw_context *context;
39 
40     struct pw_core *core;
41     struct spa_hook core_listener;
42     int last_seq, pending_seq, error;
43 } pwaudio;
44 
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];
54 
55     pwvolume volume;
56     bool muted;
57 } PWVoice;
58 
59 typedef struct PWVoiceOut {
60     HWVoiceOut hw;
61     PWVoice v;
62 } PWVoiceOut;
63 
64 typedef struct PWVoiceIn {
65     HWVoiceIn hw;
66     PWVoice v;
67 } PWVoiceIn;
68 
69 #define PW_VOICE_IN(v) ((PWVoiceIn *)v)
70 #define PW_VOICE_OUT(v) ((PWVoiceOut *)v)
71 
72 static void
73 stream_destroy(void *data)
74 {
75     PWVoice *v = (PWVoice *) data;
76     spa_hook_remove(&v->stream_listener);
77     v->stream = NULL;
78 }
79 
80 /* output data processing function to read stuffs from the buffer */
81 static void
82 playback_on_process(void *data)
83 {
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;
90 
91     assert(v->stream);
92 
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;
98     }
99 
100     buf = b->buffer;
101     p = buf->datas[0].data;
102     if (p == NULL) {
103         return;
104     }
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;
109     }
110     n_bytes = SPA_MIN(req, buf->datas[0].maxsize);
111 
112     /* get no of available bytes to read data from buffer */
113     avail = spa_ringbuffer_get_read_index(&v->ring, &index);
114 
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) {
120             /*
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.
124              */
125             n_bytes = avail;
126         }
127 
128         spa_ringbuffer_read_data(&v->ring,
129                                     v->buffer, RINGBUFFER_SIZE,
130                                     index & RINGBUFFER_MASK, p, n_bytes);
131 
132         index += n_bytes;
133         spa_ringbuffer_read_update(&v->ring, index);
134 
135     }
136     buf->datas[0].chunk->offset = 0;
137     buf->datas[0].chunk->stride = v->frame_size;
138     buf->datas[0].chunk->size = n_bytes;
139 
140     /* queue the buffer for playback */
141     pw_stream_queue_buffer(v->stream, b);
142 }
143 
144 /* output data processing function to generate stuffs in the buffer */
145 static void
146 capture_on_process(void *data)
147 {
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;
154 
155     assert(v->stream);
156 
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;
162     }
163 
164     /* Write data into buffer */
165     buf = b->buffer;
166     p = buf->datas[0].data;
167     if (p == NULL) {
168         return;
169     }
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);
172 
173     filled = spa_ringbuffer_get_write_index(&v->ring, &index);
174 
175 
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);
182         }
183     }
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);
190 
191     /* queue the buffer for playback */
192     pw_stream_queue_buffer(v->stream, b);
193 }
194 
195 static void
196 on_stream_state_changed(void *data, enum pw_stream_state old,
197                         enum pw_stream_state state, const char *error)
198 {
199     PWVoice *v = (PWVoice *) data;
200 
201     trace_pw_state_changed(pw_stream_get_node_id(v->stream),
202                            pw_stream_state_as_string(state));
203 }
204 
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
210 };
211 
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
217 };
218 
219 static size_t
220 qpw_read(HWVoiceIn *hw, void *data, size_t len)
221 {
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;
229 
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;
235     }
236     /* get no of available bytes to read data from buffer */
237     avail = spa_ringbuffer_get_read_index(&v->ring, &index);
238 
239     trace_pw_read(avail, index, len);
240 
241     if (avail < (int32_t) len) {
242         len = avail;
243     }
244 
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;
251 
252 done_unlock:
253     pw_thread_loop_unlock(c->thread_loop);
254     return l;
255 }
256 
257 static size_t qpw_buffer_get_free(HWVoiceOut *hw)
258 {
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;
265 
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;
271     }
272 
273     filled = spa_ringbuffer_get_write_index(&v->ring, &index);
274     avail = v->highwater_mark - filled;
275 
276 done_unlock:
277     pw_thread_loop_unlock(c->thread_loop);
278     return avail;
279 }
280 
281 static size_t
282 qpw_write(HWVoiceOut *hw, void *data, size_t len)
283 {
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;
290 
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;
296     }
297     filled = spa_ringbuffer_get_write_index(&v->ring, &index);
298     avail = v->highwater_mark - filled;
299 
300     trace_pw_write(filled, avail, index, len);
301 
302     if (len > avail) {
303         len = avail;
304     }
305 
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);
312         }
313     }
314 
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);
320 
321 done_unlock:
322     pw_thread_loop_unlock(c->thread_loop);
323     return len;
324 }
325 
326 static int
327 audfmt_to_pw(AudioFormat fmt, int endianness)
328 {
329     int format;
330 
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;
357     }
358     return format;
359 }
360 
361 static AudioFormat
362 pw_to_audfmt(enum spa_audio_format fmt, int *endianness,
363              uint32_t *sample_size)
364 {
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;
416     }
417 }
418 
419 static int
420 qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
421                const char *name, enum spa_direction dir)
422 {
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;
430 
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;
435     }
436 
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);
442 
443     trace_pw_period(buf_samples, v->info.rate);
444     if (name) {
445         pw_properties_set(props, PW_KEY_TARGET_OBJECT, name);
446     }
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;
451     }
452 
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);
459     }
460 
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);
466 
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;
480     }
481 
482     return 0;
483 }
484 
485 static void
486 qpw_set_position(uint32_t channels, uint32_t position[SPA_AUDIO_MAX_CHANNELS])
487 {
488     memcpy(position, (uint32_t[SPA_AUDIO_MAX_CHANNELS]) { SPA_AUDIO_CHANNEL_UNKNOWN, },
489            sizeof(uint32_t) * SPA_AUDIO_MAX_CHANNELS);
490     /*
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.
494      */
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);
515     }
516 }
517 
518 static int
519 qpw_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
520 {
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;
528 
529     pw_thread_loop_lock(c->thread_loop);
530 
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;
535 
536     obt_as.fmt =
537         pw_to_audfmt(v->info.format, &obt_as.endianness, &v->frame_size);
538     v->frame_size *= as->nchannels;
539 
540     v->req = (uint64_t)c->dev->timer_period * v->info.rate
541         * 1 / 2 / 1000000 * v->frame_size;
542 
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;
549     }
550 
551     /* report the audio format we support */
552     audio_pcm_init_info(&hw->info, &obt_as);
553 
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);
560 
561     pw_thread_loop_unlock(c->thread_loop);
562     return 0;
563 }
564 
565 static int
566 qpw_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
567 {
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;
575 
576     pw_thread_loop_lock(c->thread_loop);
577 
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;
582 
583     obt_as.fmt =
584         pw_to_audfmt(v->info.format, &obt_as.endianness, &v->frame_size);
585     v->frame_size *= as->nchannels;
586 
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;
593     }
594 
595     /* report the audio format we support */
596     audio_pcm_init_info(&hw->info, &obt_as);
597 
598     /* report the buffer size to qemu */
599     hw->samples = audio_buffer_frames(
600         qapi_AudiodevPipewirePerDirectionOptions_base(ppdo), &obt_as, 46440);
601 
602     pw_thread_loop_unlock(c->thread_loop);
603     return 0;
604 }
605 
606 static void
607 qpw_voice_fini(PWVoice *v)
608 {
609     pwaudio *c = v->g;
610 
611     if (!v->stream) {
612         return;
613     }
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);
618 }
619 
620 static void
621 qpw_fini_out(HWVoiceOut *hw)
622 {
623     qpw_voice_fini(&PW_VOICE_OUT(hw)->v);
624 }
625 
626 static void
627 qpw_fini_in(HWVoiceIn *hw)
628 {
629     qpw_voice_fini(&PW_VOICE_IN(hw)->v);
630 }
631 
632 static void
633 qpw_voice_set_enabled(PWVoice *v, bool enable)
634 {
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);
639 }
640 
641 static void
642 qpw_enable_out(HWVoiceOut *hw, bool enable)
643 {
644     qpw_voice_set_enabled(&PW_VOICE_OUT(hw)->v, enable);
645 }
646 
647 static void
648 qpw_enable_in(HWVoiceIn *hw, bool enable)
649 {
650     qpw_voice_set_enabled(&PW_VOICE_IN(hw)->v, enable);
651 }
652 
653 static void
654 qpw_voice_set_volume(PWVoice *v, Volume *vol)
655 {
656     pwaudio *c = v->g;
657     int i, ret;
658 
659     pw_thread_loop_lock(c->thread_loop);
660     v->volume.channels = vol->channels;
661 
662     for (i = 0; i < vol->channels; ++i) {
663         v->volume.values[i] = (float)vol->vol[i] / 255;
664     }
665 
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");
669 
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);
674 }
675 
676 static void
677 qpw_volume_out(HWVoiceOut *hw, Volume *vol)
678 {
679     qpw_voice_set_volume(&PW_VOICE_OUT(hw)->v, vol);
680 }
681 
682 static void
683 qpw_volume_in(HWVoiceIn *hw, Volume *vol)
684 {
685     qpw_voice_set_volume(&PW_VOICE_IN(hw)->v, vol);
686 }
687 
688 static int wait_resync(pwaudio *pw)
689 {
690     int res;
691     pw->pending_seq = pw_core_sync(pw->core, PW_ID_CORE, pw->pending_seq);
692 
693     while (true) {
694         pw_thread_loop_wait(pw->thread_loop);
695 
696         res = pw->error;
697         if (res < 0) {
698             pw->error = 0;
699             return res;
700         }
701         if (pw->pending_seq == pw->last_seq) {
702             break;
703         }
704     }
705     return 0;
706 }
707 
708 static void
709 on_core_error(void *data, uint32_t id, int seq, int res, const char *message)
710 {
711     pwaudio *pw = data;
712 
713     error_report("error id:%u seq:%d res:%d (%s): %s",
714                 id, seq, res, spa_strerror(res), message);
715 
716     /* stop and exit the thread loop */
717     pw_thread_loop_signal(pw->thread_loop, FALSE);
718 }
719 
720 static void
721 on_core_done(void *data, uint32_t id, int seq)
722 {
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);
729     }
730 }
731 
732 static const struct pw_core_events core_events = {
733     PW_VERSION_CORE_EVENTS,
734     .done = on_core_done,
735     .error = on_core_error,
736 };
737 
738 static void *
739 qpw_audio_init(Audiodev *dev)
740 {
741     g_autofree pwaudio *pw = g_new0(pwaudio, 1);
742 
743     assert(dev->driver == AUDIODEV_DRIVER_PIPEWIRE);
744     trace_pw_audio_init();
745 
746     pw_init(NULL, NULL);
747 
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;
753     }
754 
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;
760     }
761 
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;
765     }
766 
767     pw_thread_loop_lock(pw->thread_loop);
768 
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;
773     }
774 
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;
779     }
780     if (wait_resync(pw) < 0) {
781         pw_thread_loop_unlock(pw->thread_loop);
782     }
783 
784     pw_thread_loop_unlock(pw->thread_loop);
785 
786     return g_steal_pointer(&pw);
787 
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);
792     }
793     g_clear_pointer(&pw->context, pw_context_destroy);
794     g_clear_pointer(&pw->thread_loop, pw_thread_loop_destroy);
795     return NULL;
796 }
797 
798 static void
799 qpw_audio_fini(void *opaque)
800 {
801     pwaudio *pw = opaque;
802 
803     if (pw->thread_loop) {
804         pw_thread_loop_stop(pw->thread_loop);
805     }
806 
807     if (pw->core) {
808         spa_hook_remove(&pw->core_listener);
809         spa_zero(pw->core_listener);
810         pw_core_disconnect(pw->core);
811     }
812 
813     if (pw->context) {
814         pw_context_destroy(pw->context);
815     }
816     pw_thread_loop_destroy(pw->thread_loop);
817 
818     g_free(pw);
819 }
820 
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,
830 
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
836 };
837 
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),
849 };
850 
851 static void
852 register_audio_pw(void)
853 {
854     audio_driver_register(&pw_audio_driver);
855 }
856 
857 type_init(register_audio_pw);
858