xref: /openbmc/qemu/audio/pwaudio.c (revision 1141159c)
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 static void
70 stream_destroy(void *data)
71 {
72     PWVoice *v = (PWVoice *) data;
73     spa_hook_remove(&v->stream_listener);
74     v->stream = NULL;
75 }
76 
77 /* output data processing function to read stuffs from the buffer */
78 static void
79 playback_on_process(void *data)
80 {
81     PWVoice *v = data;
82     void *p;
83     struct pw_buffer *b;
84     struct spa_buffer *buf;
85     uint32_t req, index, n_bytes;
86     int32_t avail;
87 
88     assert(v->stream);
89 
90     /* obtain a buffer to read from */
91     b = pw_stream_dequeue_buffer(v->stream);
92     if (b == NULL) {
93         error_report("out of buffers: %s", strerror(errno));
94         return;
95     }
96 
97     buf = b->buffer;
98     p = buf->datas[0].data;
99     if (p == NULL) {
100         return;
101     }
102     /* calculate the total no of bytes to read data from buffer */
103     req = b->requested * v->frame_size;
104     if (req == 0) {
105         req = v->req;
106     }
107     n_bytes = SPA_MIN(req, buf->datas[0].maxsize);
108 
109     /* get no of available bytes to read data from buffer */
110     avail = spa_ringbuffer_get_read_index(&v->ring, &index);
111 
112     if (avail <= 0) {
113         PWVoiceOut *vo = container_of(data, PWVoiceOut, v);
114         audio_pcm_info_clear_buf(&vo->hw.info, p, n_bytes / v->frame_size);
115     } else {
116         if ((uint32_t) avail < n_bytes) {
117             /*
118              * PipeWire immediately calls this callback again if we provide
119              * less than n_bytes. Then audio_pcm_info_clear_buf() fills the
120              * rest of the buffer with silence.
121              */
122             n_bytes = avail;
123         }
124 
125         spa_ringbuffer_read_data(&v->ring,
126                                     v->buffer, RINGBUFFER_SIZE,
127                                     index & RINGBUFFER_MASK, p, n_bytes);
128 
129         index += n_bytes;
130         spa_ringbuffer_read_update(&v->ring, index);
131 
132     }
133     buf->datas[0].chunk->offset = 0;
134     buf->datas[0].chunk->stride = v->frame_size;
135     buf->datas[0].chunk->size = n_bytes;
136 
137     /* queue the buffer for playback */
138     pw_stream_queue_buffer(v->stream, b);
139 }
140 
141 /* output data processing function to generate stuffs in the buffer */
142 static void
143 capture_on_process(void *data)
144 {
145     PWVoice *v = (PWVoice *) data;
146     void *p;
147     struct pw_buffer *b;
148     struct spa_buffer *buf;
149     int32_t filled;
150     uint32_t index, offs, n_bytes;
151 
152     assert(v->stream);
153 
154     /* obtain a buffer */
155     b = pw_stream_dequeue_buffer(v->stream);
156     if (b == NULL) {
157         error_report("out of buffers: %s", strerror(errno));
158         return;
159     }
160 
161     /* Write data into buffer */
162     buf = b->buffer;
163     p = buf->datas[0].data;
164     if (p == NULL) {
165         return;
166     }
167     offs = SPA_MIN(buf->datas[0].chunk->offset, buf->datas[0].maxsize);
168     n_bytes = SPA_MIN(buf->datas[0].chunk->size, buf->datas[0].maxsize - offs);
169 
170     filled = spa_ringbuffer_get_write_index(&v->ring, &index);
171 
172 
173     if (filled < 0) {
174         error_report("%p: underrun write:%u filled:%d", p, index, filled);
175     } else {
176         if ((uint32_t) filled + n_bytes > RINGBUFFER_SIZE) {
177             error_report("%p: overrun write:%u filled:%d + size:%u > max:%u",
178             p, index, filled, n_bytes, RINGBUFFER_SIZE);
179         }
180     }
181     spa_ringbuffer_write_data(&v->ring,
182                                 v->buffer, RINGBUFFER_SIZE,
183                                 index & RINGBUFFER_MASK,
184                                 SPA_PTROFF(p, offs, void), n_bytes);
185     index += n_bytes;
186     spa_ringbuffer_write_update(&v->ring, index);
187 
188     /* queue the buffer for playback */
189     pw_stream_queue_buffer(v->stream, b);
190 }
191 
192 static void
193 on_stream_state_changed(void *data, enum pw_stream_state old,
194                         enum pw_stream_state state, const char *error)
195 {
196     PWVoice *v = (PWVoice *) data;
197 
198     trace_pw_state_changed(pw_stream_get_node_id(v->stream),
199                            pw_stream_state_as_string(state));
200 
201     switch (state) {
202     case PW_STREAM_STATE_ERROR:
203     case PW_STREAM_STATE_UNCONNECTED:
204         break;
205     case PW_STREAM_STATE_PAUSED:
206     case PW_STREAM_STATE_CONNECTING:
207     case PW_STREAM_STATE_STREAMING:
208         break;
209     }
210 }
211 
212 static const struct pw_stream_events capture_stream_events = {
213     PW_VERSION_STREAM_EVENTS,
214     .destroy = stream_destroy,
215     .state_changed = on_stream_state_changed,
216     .process = capture_on_process
217 };
218 
219 static const struct pw_stream_events playback_stream_events = {
220     PW_VERSION_STREAM_EVENTS,
221     .destroy = stream_destroy,
222     .state_changed = on_stream_state_changed,
223     .process = playback_on_process
224 };
225 
226 static size_t
227 qpw_read(HWVoiceIn *hw, void *data, size_t len)
228 {
229     PWVoiceIn *pw = (PWVoiceIn *) hw;
230     PWVoice *v = &pw->v;
231     pwaudio *c = v->g;
232     const char *error = NULL;
233     size_t l;
234     int32_t avail;
235     uint32_t index;
236 
237     pw_thread_loop_lock(c->thread_loop);
238     if (pw_stream_get_state(v->stream, &error) != PW_STREAM_STATE_STREAMING) {
239         /* wait for stream to become ready */
240         l = 0;
241         goto done_unlock;
242     }
243     /* get no of available bytes to read data from buffer */
244     avail = spa_ringbuffer_get_read_index(&v->ring, &index);
245 
246     trace_pw_read(avail, index, len);
247 
248     if (avail < (int32_t) len) {
249         len = avail;
250     }
251 
252     spa_ringbuffer_read_data(&v->ring,
253                              v->buffer, RINGBUFFER_SIZE,
254                              index & RINGBUFFER_MASK, data, len);
255     index += len;
256     spa_ringbuffer_read_update(&v->ring, index);
257     l = len;
258 
259 done_unlock:
260     pw_thread_loop_unlock(c->thread_loop);
261     return l;
262 }
263 
264 static size_t qpw_buffer_get_free(HWVoiceOut *hw)
265 {
266     PWVoiceOut *pw = (PWVoiceOut *)hw;
267     PWVoice *v = &pw->v;
268     pwaudio *c = v->g;
269     const char *error = NULL;
270     int32_t filled, avail;
271     uint32_t index;
272 
273     pw_thread_loop_lock(c->thread_loop);
274     if (pw_stream_get_state(v->stream, &error) != PW_STREAM_STATE_STREAMING) {
275         /* wait for stream to become ready */
276         avail = 0;
277         goto done_unlock;
278     }
279 
280     filled = spa_ringbuffer_get_write_index(&v->ring, &index);
281     avail = v->highwater_mark - filled;
282 
283 done_unlock:
284     pw_thread_loop_unlock(c->thread_loop);
285     return avail;
286 }
287 
288 static size_t
289 qpw_write(HWVoiceOut *hw, void *data, size_t len)
290 {
291     PWVoiceOut *pw = (PWVoiceOut *) hw;
292     PWVoice *v = &pw->v;
293     pwaudio *c = v->g;
294     const char *error = NULL;
295     int32_t filled, avail;
296     uint32_t index;
297 
298     pw_thread_loop_lock(c->thread_loop);
299     if (pw_stream_get_state(v->stream, &error) != PW_STREAM_STATE_STREAMING) {
300         /* wait for stream to become ready */
301         len = 0;
302         goto done_unlock;
303     }
304     filled = spa_ringbuffer_get_write_index(&v->ring, &index);
305     avail = v->highwater_mark - filled;
306 
307     trace_pw_write(filled, avail, index, len);
308 
309     if (len > avail) {
310         len = avail;
311     }
312 
313     if (filled < 0) {
314         error_report("%p: underrun write:%u filled:%d", pw, index, filled);
315     } else {
316         if ((uint32_t) filled + len > RINGBUFFER_SIZE) {
317             error_report("%p: overrun write:%u filled:%d + size:%zu > max:%u",
318             pw, index, filled, len, RINGBUFFER_SIZE);
319         }
320     }
321 
322     spa_ringbuffer_write_data(&v->ring,
323                                 v->buffer, RINGBUFFER_SIZE,
324                                 index & RINGBUFFER_MASK, data, len);
325     index += len;
326     spa_ringbuffer_write_update(&v->ring, index);
327 
328 done_unlock:
329     pw_thread_loop_unlock(c->thread_loop);
330     return len;
331 }
332 
333 static int
334 audfmt_to_pw(AudioFormat fmt, int endianness)
335 {
336     int format;
337 
338     switch (fmt) {
339     case AUDIO_FORMAT_S8:
340         format = SPA_AUDIO_FORMAT_S8;
341         break;
342     case AUDIO_FORMAT_U8:
343         format = SPA_AUDIO_FORMAT_U8;
344         break;
345     case AUDIO_FORMAT_S16:
346         format = endianness ? SPA_AUDIO_FORMAT_S16_BE : SPA_AUDIO_FORMAT_S16_LE;
347         break;
348     case AUDIO_FORMAT_U16:
349         format = endianness ? SPA_AUDIO_FORMAT_U16_BE : SPA_AUDIO_FORMAT_U16_LE;
350         break;
351     case AUDIO_FORMAT_S32:
352         format = endianness ? SPA_AUDIO_FORMAT_S32_BE : SPA_AUDIO_FORMAT_S32_LE;
353         break;
354     case AUDIO_FORMAT_U32:
355         format = endianness ? SPA_AUDIO_FORMAT_U32_BE : SPA_AUDIO_FORMAT_U32_LE;
356         break;
357     case AUDIO_FORMAT_F32:
358         format = endianness ? SPA_AUDIO_FORMAT_F32_BE : SPA_AUDIO_FORMAT_F32_LE;
359         break;
360     default:
361         dolog("Internal logic error: Bad audio format %d\n", fmt);
362         format = SPA_AUDIO_FORMAT_U8;
363         break;
364     }
365     return format;
366 }
367 
368 static AudioFormat
369 pw_to_audfmt(enum spa_audio_format fmt, int *endianness,
370              uint32_t *sample_size)
371 {
372     switch (fmt) {
373     case SPA_AUDIO_FORMAT_S8:
374         *sample_size = 1;
375         return AUDIO_FORMAT_S8;
376     case SPA_AUDIO_FORMAT_U8:
377         *sample_size = 1;
378         return AUDIO_FORMAT_U8;
379     case SPA_AUDIO_FORMAT_S16_BE:
380         *sample_size = 2;
381         *endianness = 1;
382         return AUDIO_FORMAT_S16;
383     case SPA_AUDIO_FORMAT_S16_LE:
384         *sample_size = 2;
385         *endianness = 0;
386         return AUDIO_FORMAT_S16;
387     case SPA_AUDIO_FORMAT_U16_BE:
388         *sample_size = 2;
389         *endianness = 1;
390         return AUDIO_FORMAT_U16;
391     case SPA_AUDIO_FORMAT_U16_LE:
392         *sample_size = 2;
393         *endianness = 0;
394         return AUDIO_FORMAT_U16;
395     case SPA_AUDIO_FORMAT_S32_BE:
396         *sample_size = 4;
397         *endianness = 1;
398         return AUDIO_FORMAT_S32;
399     case SPA_AUDIO_FORMAT_S32_LE:
400         *sample_size = 4;
401         *endianness = 0;
402         return AUDIO_FORMAT_S32;
403     case SPA_AUDIO_FORMAT_U32_BE:
404         *sample_size = 4;
405         *endianness = 1;
406         return AUDIO_FORMAT_U32;
407     case SPA_AUDIO_FORMAT_U32_LE:
408         *sample_size = 4;
409         *endianness = 0;
410         return AUDIO_FORMAT_U32;
411     case SPA_AUDIO_FORMAT_F32_BE:
412         *sample_size = 4;
413         *endianness = 1;
414         return AUDIO_FORMAT_F32;
415     case SPA_AUDIO_FORMAT_F32_LE:
416         *sample_size = 4;
417         *endianness = 0;
418         return AUDIO_FORMAT_F32;
419     default:
420         *sample_size = 1;
421         dolog("Internal logic error: Bad spa_audio_format %d\n", fmt);
422         return AUDIO_FORMAT_U8;
423     }
424 }
425 
426 static int
427 create_stream(pwaudio *c, PWVoice *v, const char *stream_name,
428               const char *name, enum spa_direction dir)
429 {
430     int res;
431     uint32_t n_params;
432     const struct spa_pod *params[2];
433     uint8_t buffer[1024];
434     struct spa_pod_builder b;
435     uint64_t buf_samples;
436     struct pw_properties *props;
437 
438     props = pw_properties_new(NULL, NULL);
439 
440     /* 75% of the timer period for faster updates */
441     buf_samples = (uint64_t)v->g->dev->timer_period * v->info.rate
442                     * 3 / 4 / 1000000;
443     pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%" PRIu64 "/%u",
444                        buf_samples, v->info.rate);
445 
446     trace_pw_period(buf_samples, v->info.rate);
447     if (name) {
448         pw_properties_set(props, PW_KEY_TARGET_OBJECT, name);
449     }
450     v->stream = pw_stream_new(c->core, stream_name, props);
451 
452     if (v->stream == NULL) {
453         return -1;
454     }
455 
456     if (dir == SPA_DIRECTION_INPUT) {
457         pw_stream_add_listener(v->stream,
458                             &v->stream_listener, &capture_stream_events, v);
459     } else {
460         pw_stream_add_listener(v->stream,
461                             &v->stream_listener, &playback_stream_events, v);
462     }
463 
464     n_params = 0;
465     spa_pod_builder_init(&b, buffer, sizeof(buffer));
466     params[n_params++] = spa_format_audio_raw_build(&b,
467                             SPA_PARAM_EnumFormat,
468                             &v->info);
469 
470     /* connect the stream to a sink or source */
471     res = pw_stream_connect(v->stream,
472                             dir ==
473                             SPA_DIRECTION_INPUT ? PW_DIRECTION_INPUT :
474                             PW_DIRECTION_OUTPUT, PW_ID_ANY,
475                             PW_STREAM_FLAG_AUTOCONNECT |
476                             PW_STREAM_FLAG_INACTIVE |
477                             PW_STREAM_FLAG_MAP_BUFFERS |
478                             PW_STREAM_FLAG_RT_PROCESS, params, n_params);
479     if (res < 0) {
480         pw_stream_destroy(v->stream);
481         return -1;
482     }
483 
484     return 0;
485 }
486 
487 static int
488 qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
489                const char *name, enum spa_direction dir)
490 {
491     int r;
492 
493     switch (v->info.channels) {
494     case 8:
495         v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
496         v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
497         v->info.position[2] = SPA_AUDIO_CHANNEL_FC;
498         v->info.position[3] = SPA_AUDIO_CHANNEL_LFE;
499         v->info.position[4] = SPA_AUDIO_CHANNEL_RL;
500         v->info.position[5] = SPA_AUDIO_CHANNEL_RR;
501         v->info.position[6] = SPA_AUDIO_CHANNEL_SL;
502         v->info.position[7] = SPA_AUDIO_CHANNEL_SR;
503         break;
504     case 6:
505         v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
506         v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
507         v->info.position[2] = SPA_AUDIO_CHANNEL_FC;
508         v->info.position[3] = SPA_AUDIO_CHANNEL_LFE;
509         v->info.position[4] = SPA_AUDIO_CHANNEL_RL;
510         v->info.position[5] = SPA_AUDIO_CHANNEL_RR;
511         break;
512     case 5:
513         v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
514         v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
515         v->info.position[2] = SPA_AUDIO_CHANNEL_FC;
516         v->info.position[3] = SPA_AUDIO_CHANNEL_LFE;
517         v->info.position[4] = SPA_AUDIO_CHANNEL_RC;
518         break;
519     case 4:
520         v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
521         v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
522         v->info.position[2] = SPA_AUDIO_CHANNEL_FC;
523         v->info.position[3] = SPA_AUDIO_CHANNEL_RC;
524         break;
525     case 3:
526         v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
527         v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
528         v->info.position[2] = SPA_AUDIO_CHANNEL_LFE;
529         break;
530     case 2:
531         v->info.position[0] = SPA_AUDIO_CHANNEL_FL;
532         v->info.position[1] = SPA_AUDIO_CHANNEL_FR;
533         break;
534     case 1:
535         v->info.position[0] = SPA_AUDIO_CHANNEL_MONO;
536         break;
537     default:
538         for (size_t i = 0; i < v->info.channels; i++) {
539             v->info.position[i] = SPA_AUDIO_CHANNEL_UNKNOWN;
540         }
541         break;
542     }
543 
544     /* create a new unconnected pwstream */
545     r = create_stream(c, v, stream_name, name, dir);
546     if (r < 0) {
547         AUD_log(AUDIO_CAP, "Failed to create stream.");
548         return -1;
549     }
550 
551     return r;
552 }
553 
554 static int
555 qpw_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
556 {
557     PWVoiceOut *pw = (PWVoiceOut *) hw;
558     PWVoice *v = &pw->v;
559     struct audsettings obt_as = *as;
560     pwaudio *c = v->g = drv_opaque;
561     AudiodevPipewireOptions *popts = &c->dev->u.pipewire;
562     AudiodevPipewirePerDirectionOptions *ppdo = popts->out;
563     int r;
564 
565     pw_thread_loop_lock(c->thread_loop);
566 
567     v->info.format = audfmt_to_pw(as->fmt, as->endianness);
568     v->info.channels = as->nchannels;
569     v->info.rate = as->freq;
570 
571     obt_as.fmt =
572         pw_to_audfmt(v->info.format, &obt_as.endianness, &v->frame_size);
573     v->frame_size *= as->nchannels;
574 
575     v->req = (uint64_t)c->dev->timer_period * v->info.rate
576         * 1 / 2 / 1000000 * v->frame_size;
577 
578     /* call the function that creates a new stream for playback */
579     r = qpw_stream_new(c, v, ppdo->stream_name ? : c->dev->id,
580                        ppdo->name, SPA_DIRECTION_OUTPUT);
581     if (r < 0) {
582         error_report("qpw_stream_new for playback failed");
583         pw_thread_loop_unlock(c->thread_loop);
584         return -1;
585     }
586 
587     /* report the audio format we support */
588     audio_pcm_init_info(&hw->info, &obt_as);
589 
590     /* report the buffer size to qemu */
591     hw->samples = audio_buffer_frames(
592         qapi_AudiodevPipewirePerDirectionOptions_base(ppdo), &obt_as, 46440);
593     v->highwater_mark = MIN(RINGBUFFER_SIZE,
594                             (ppdo->has_latency ? ppdo->latency : 46440)
595                             * (uint64_t)v->info.rate / 1000000 * v->frame_size);
596 
597     pw_thread_loop_unlock(c->thread_loop);
598     return 0;
599 }
600 
601 static int
602 qpw_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
603 {
604     PWVoiceIn *pw = (PWVoiceIn *) hw;
605     PWVoice *v = &pw->v;
606     struct audsettings obt_as = *as;
607     pwaudio *c = v->g = drv_opaque;
608     AudiodevPipewireOptions *popts = &c->dev->u.pipewire;
609     AudiodevPipewirePerDirectionOptions *ppdo = popts->in;
610     int r;
611 
612     pw_thread_loop_lock(c->thread_loop);
613 
614     v->info.format = audfmt_to_pw(as->fmt, as->endianness);
615     v->info.channels = as->nchannels;
616     v->info.rate = as->freq;
617 
618     obt_as.fmt =
619         pw_to_audfmt(v->info.format, &obt_as.endianness, &v->frame_size);
620     v->frame_size *= as->nchannels;
621 
622     /* call the function that creates a new stream for recording */
623     r = qpw_stream_new(c, v, ppdo->stream_name ? : c->dev->id,
624                        ppdo->name, SPA_DIRECTION_INPUT);
625     if (r < 0) {
626         error_report("qpw_stream_new for recording failed");
627         pw_thread_loop_unlock(c->thread_loop);
628         return -1;
629     }
630 
631     /* report the audio format we support */
632     audio_pcm_init_info(&hw->info, &obt_as);
633 
634     /* report the buffer size to qemu */
635     hw->samples = audio_buffer_frames(
636         qapi_AudiodevPipewirePerDirectionOptions_base(ppdo), &obt_as, 46440);
637 
638     pw_thread_loop_unlock(c->thread_loop);
639     return 0;
640 }
641 
642 static void
643 qpw_fini_out(HWVoiceOut *hw)
644 {
645     PWVoiceOut *pw = (PWVoiceOut *) hw;
646     PWVoice *v = &pw->v;
647 
648     if (v->stream) {
649         pwaudio *c = v->g;
650         pw_thread_loop_lock(c->thread_loop);
651         pw_stream_destroy(v->stream);
652         v->stream = NULL;
653         pw_thread_loop_unlock(c->thread_loop);
654     }
655 }
656 
657 static void
658 qpw_fini_in(HWVoiceIn *hw)
659 {
660     PWVoiceIn *pw = (PWVoiceIn *) hw;
661     PWVoice *v = &pw->v;
662 
663     if (v->stream) {
664         pwaudio *c = v->g;
665         pw_thread_loop_lock(c->thread_loop);
666         pw_stream_destroy(v->stream);
667         v->stream = NULL;
668         pw_thread_loop_unlock(c->thread_loop);
669     }
670 }
671 
672 static void
673 qpw_enable_out(HWVoiceOut *hw, bool enable)
674 {
675     PWVoiceOut *po = (PWVoiceOut *) hw;
676     PWVoice *v = &po->v;
677     pwaudio *c = v->g;
678     pw_thread_loop_lock(c->thread_loop);
679     pw_stream_set_active(v->stream, enable);
680     pw_thread_loop_unlock(c->thread_loop);
681 }
682 
683 static void
684 qpw_enable_in(HWVoiceIn *hw, bool enable)
685 {
686     PWVoiceIn *pi = (PWVoiceIn *) hw;
687     PWVoice *v = &pi->v;
688     pwaudio *c = v->g;
689     pw_thread_loop_lock(c->thread_loop);
690     pw_stream_set_active(v->stream, enable);
691     pw_thread_loop_unlock(c->thread_loop);
692 }
693 
694 static void
695 qpw_volume_out(HWVoiceOut *hw, Volume *vol)
696 {
697     PWVoiceOut *pw = (PWVoiceOut *) hw;
698     PWVoice *v = &pw->v;
699     pwaudio *c = v->g;
700     int i, ret;
701 
702     pw_thread_loop_lock(c->thread_loop);
703     v->volume.channels = vol->channels;
704 
705     for (i = 0; i < vol->channels; ++i) {
706         v->volume.values[i] = (float)vol->vol[i] / 255;
707     }
708 
709     ret = pw_stream_set_control(v->stream,
710         SPA_PROP_channelVolumes, v->volume.channels, v->volume.values, 0);
711     trace_pw_vol(ret == 0 ? "success" : "failed");
712 
713     v->muted = vol->mute;
714     float val = v->muted ? 1.f : 0.f;
715     ret = pw_stream_set_control(v->stream, SPA_PROP_mute, 1, &val, 0);
716     pw_thread_loop_unlock(c->thread_loop);
717 }
718 
719 static void
720 qpw_volume_in(HWVoiceIn *hw, Volume *vol)
721 {
722     PWVoiceIn *pw = (PWVoiceIn *) hw;
723     PWVoice *v = &pw->v;
724     pwaudio *c = v->g;
725     int i, ret;
726 
727     pw_thread_loop_lock(c->thread_loop);
728     v->volume.channels = vol->channels;
729 
730     for (i = 0; i < vol->channels; ++i) {
731         v->volume.values[i] = (float)vol->vol[i] / 255;
732     }
733 
734     ret = pw_stream_set_control(v->stream,
735         SPA_PROP_channelVolumes, v->volume.channels, v->volume.values, 0);
736     trace_pw_vol(ret == 0 ? "success" : "failed");
737 
738     v->muted = vol->mute;
739     float val = v->muted ? 1.f : 0.f;
740     ret = pw_stream_set_control(v->stream, SPA_PROP_mute, 1, &val, 0);
741     pw_thread_loop_unlock(c->thread_loop);
742 }
743 
744 static int wait_resync(pwaudio *pw)
745 {
746     int res;
747     pw->pending_seq = pw_core_sync(pw->core, PW_ID_CORE, pw->pending_seq);
748 
749     while (true) {
750         pw_thread_loop_wait(pw->thread_loop);
751 
752         res = pw->error;
753         if (res < 0) {
754             pw->error = 0;
755             return res;
756         }
757         if (pw->pending_seq == pw->last_seq) {
758             break;
759         }
760     }
761     return 0;
762 }
763 static void
764 on_core_error(void *data, uint32_t id, int seq, int res, const char *message)
765 {
766     pwaudio *pw = data;
767 
768     error_report("error id:%u seq:%d res:%d (%s): %s",
769                 id, seq, res, spa_strerror(res), message);
770 
771     /* stop and exit the thread loop */
772     pw_thread_loop_signal(pw->thread_loop, FALSE);
773 }
774 
775 static void
776 on_core_done(void *data, uint32_t id, int seq)
777 {
778     pwaudio *pw = data;
779     assert(id == PW_ID_CORE);
780     pw->last_seq = seq;
781     if (pw->pending_seq == seq) {
782         /* stop and exit the thread loop */
783         pw_thread_loop_signal(pw->thread_loop, FALSE);
784     }
785 }
786 
787 static const struct pw_core_events core_events = {
788     PW_VERSION_CORE_EVENTS,
789     .done = on_core_done,
790     .error = on_core_error,
791 };
792 
793 static void *
794 qpw_audio_init(Audiodev *dev)
795 {
796     g_autofree pwaudio *pw = g_new0(pwaudio, 1);
797     pw_init(NULL, NULL);
798 
799     trace_pw_audio_init();
800     assert(dev->driver == AUDIODEV_DRIVER_PIPEWIRE);
801 
802     pw->dev = dev;
803     pw->thread_loop = pw_thread_loop_new("Pipewire thread loop", NULL);
804     if (pw->thread_loop == NULL) {
805         error_report("Could not create Pipewire loop");
806         goto fail;
807     }
808 
809     pw->context =
810         pw_context_new(pw_thread_loop_get_loop(pw->thread_loop), NULL, 0);
811     if (pw->context == NULL) {
812         error_report("Could not create Pipewire context");
813         goto fail;
814     }
815 
816     if (pw_thread_loop_start(pw->thread_loop) < 0) {
817         error_report("Could not start Pipewire loop");
818         goto fail;
819     }
820 
821     pw_thread_loop_lock(pw->thread_loop);
822 
823     pw->core = pw_context_connect(pw->context, NULL, 0);
824     if (pw->core == NULL) {
825         pw_thread_loop_unlock(pw->thread_loop);
826         goto fail;
827     }
828 
829     if (pw_core_add_listener(pw->core, &pw->core_listener,
830                              &core_events, pw) < 0) {
831         pw_thread_loop_unlock(pw->thread_loop);
832         goto fail;
833     }
834     if (wait_resync(pw) < 0) {
835         pw_thread_loop_unlock(pw->thread_loop);
836     }
837 
838     pw_thread_loop_unlock(pw->thread_loop);
839 
840     return g_steal_pointer(&pw);
841 
842 fail:
843     AUD_log(AUDIO_CAP, "Failed to initialize PW context");
844     if (pw->thread_loop) {
845         pw_thread_loop_stop(pw->thread_loop);
846     }
847     if (pw->context) {
848         g_clear_pointer(&pw->context, pw_context_destroy);
849     }
850     if (pw->thread_loop) {
851         g_clear_pointer(&pw->thread_loop, pw_thread_loop_destroy);
852     }
853     return NULL;
854 }
855 
856 static void
857 qpw_audio_fini(void *opaque)
858 {
859     pwaudio *pw = opaque;
860 
861     if (pw->thread_loop) {
862         pw_thread_loop_stop(pw->thread_loop);
863     }
864 
865     if (pw->core) {
866         spa_hook_remove(&pw->core_listener);
867         spa_zero(pw->core_listener);
868         pw_core_disconnect(pw->core);
869     }
870 
871     if (pw->context) {
872         pw_context_destroy(pw->context);
873     }
874     pw_thread_loop_destroy(pw->thread_loop);
875 
876     g_free(pw);
877 }
878 
879 static struct audio_pcm_ops qpw_pcm_ops = {
880     .init_out = qpw_init_out,
881     .fini_out = qpw_fini_out,
882     .write = qpw_write,
883     .buffer_get_free = qpw_buffer_get_free,
884     .run_buffer_out = audio_generic_run_buffer_out,
885     .enable_out = qpw_enable_out,
886     .volume_out = qpw_volume_out,
887     .volume_in = qpw_volume_in,
888 
889     .init_in = qpw_init_in,
890     .fini_in = qpw_fini_in,
891     .read = qpw_read,
892     .run_buffer_in = audio_generic_run_buffer_in,
893     .enable_in = qpw_enable_in
894 };
895 
896 static struct audio_driver pw_audio_driver = {
897     .name = "pipewire",
898     .descr = "http://www.pipewire.org/",
899     .init = qpw_audio_init,
900     .fini = qpw_audio_fini,
901     .pcm_ops = &qpw_pcm_ops,
902     .can_be_default = 1,
903     .max_voices_out = INT_MAX,
904     .max_voices_in = INT_MAX,
905     .voice_size_out = sizeof(PWVoiceOut),
906     .voice_size_in = sizeof(PWVoiceIn),
907 };
908 
909 static void
910 register_audio_pw(void)
911 {
912     audio_driver_register(&pw_audio_driver);
913 }
914 
915 type_init(register_audio_pw);
916