block: Take main AioContext lock when calling bdrv_open()
[qemu/ar7.git] / audio / pwaudio.c
blob1d108bdebb831448ad852ee2a1f8655a63f6c8cc
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 static void
70 stream_destroy(void *data)
72 PWVoice *v = (PWVoice *) data;
73 spa_hook_remove(&v->stream_listener);
74 v->stream = NULL;
77 /* output data processing function to read stuffs from the buffer */
78 static void
79 playback_on_process(void *data)
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;
88 assert(v->stream);
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;
97 buf = b->buffer;
98 p = buf->datas[0].data;
99 if (p == NULL) {
100 return;
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;
107 n_bytes = SPA_MIN(req, buf->datas[0].maxsize);
109 /* get no of available bytes to read data from buffer */
110 avail = spa_ringbuffer_get_read_index(&v->ring, &index);
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) {
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.
122 n_bytes = avail;
125 spa_ringbuffer_read_data(&v->ring,
126 v->buffer, RINGBUFFER_SIZE,
127 index & RINGBUFFER_MASK, p, n_bytes);
129 index += n_bytes;
130 spa_ringbuffer_read_update(&v->ring, index);
133 buf->datas[0].chunk->offset = 0;
134 buf->datas[0].chunk->stride = v->frame_size;
135 buf->datas[0].chunk->size = n_bytes;
137 /* queue the buffer for playback */
138 pw_stream_queue_buffer(v->stream, b);
141 /* output data processing function to generate stuffs in the buffer */
142 static void
143 capture_on_process(void *data)
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;
152 assert(v->stream);
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;
161 /* Write data into buffer */
162 buf = b->buffer;
163 p = buf->datas[0].data;
164 if (p == NULL) {
165 return;
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);
170 filled = spa_ringbuffer_get_write_index(&v->ring, &index);
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);
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);
188 /* queue the buffer for playback */
189 pw_stream_queue_buffer(v->stream, b);
192 static void
193 on_stream_state_changed(void *data, enum pw_stream_state old,
194 enum pw_stream_state state, const char *error)
196 PWVoice *v = (PWVoice *) data;
198 trace_pw_state_changed(pw_stream_get_node_id(v->stream),
199 pw_stream_state_as_string(state));
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;
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
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
226 static size_t
227 qpw_read(HWVoiceIn *hw, void *data, size_t len)
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;
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;
243 /* get no of available bytes to read data from buffer */
244 avail = spa_ringbuffer_get_read_index(&v->ring, &index);
246 trace_pw_read(avail, index, len);
248 if (avail < (int32_t) len) {
249 len = avail;
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;
259 done_unlock:
260 pw_thread_loop_unlock(c->thread_loop);
261 return l;
264 static size_t qpw_buffer_get_free(HWVoiceOut *hw)
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;
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;
280 filled = spa_ringbuffer_get_write_index(&v->ring, &index);
281 avail = v->highwater_mark - filled;
283 done_unlock:
284 pw_thread_loop_unlock(c->thread_loop);
285 return avail;
288 static size_t
289 qpw_write(HWVoiceOut *hw, void *data, size_t len)
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;
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;
304 filled = spa_ringbuffer_get_write_index(&v->ring, &index);
305 avail = v->highwater_mark - filled;
307 trace_pw_write(filled, avail, index, len);
309 if (len > avail) {
310 len = avail;
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);
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);
328 done_unlock:
329 pw_thread_loop_unlock(c->thread_loop);
330 return len;
333 static int
334 audfmt_to_pw(AudioFormat fmt, int endianness)
336 int format;
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;
365 return format;
368 static AudioFormat
369 pw_to_audfmt(enum spa_audio_format fmt, int *endianness,
370 uint32_t *sample_size)
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;
426 static int
427 create_stream(pwaudio *c, PWVoice *v, const char *stream_name,
428 const char *name, enum spa_direction dir)
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;
438 props = pw_properties_new(NULL, NULL);
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);
446 trace_pw_period(buf_samples, v->info.rate);
447 if (name) {
448 pw_properties_set(props, PW_KEY_TARGET_OBJECT, name);
450 v->stream = pw_stream_new(c->core, stream_name, props);
452 if (v->stream == NULL) {
453 return -1;
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);
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);
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;
484 return 0;
487 static int
488 qpw_stream_new(pwaudio *c, PWVoice *v, const char *stream_name,
489 const char *name, enum spa_direction dir)
491 int r;
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;
541 break;
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;
551 return r;
554 static int
555 qpw_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque)
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;
565 pw_thread_loop_lock(c->thread_loop);
567 v->info.format = audfmt_to_pw(as->fmt, as->endianness);
568 v->info.channels = as->nchannels;
569 v->info.rate = as->freq;
571 obt_as.fmt =
572 pw_to_audfmt(v->info.format, &obt_as.endianness, &v->frame_size);
573 v->frame_size *= as->nchannels;
575 v->req = (uint64_t)c->dev->timer_period * v->info.rate
576 * 1 / 2 / 1000000 * v->frame_size;
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;
587 /* report the audio format we support */
588 audio_pcm_init_info(&hw->info, &obt_as);
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);
597 pw_thread_loop_unlock(c->thread_loop);
598 return 0;
601 static int
602 qpw_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
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;
612 pw_thread_loop_lock(c->thread_loop);
614 v->info.format = audfmt_to_pw(as->fmt, as->endianness);
615 v->info.channels = as->nchannels;
616 v->info.rate = as->freq;
618 obt_as.fmt =
619 pw_to_audfmt(v->info.format, &obt_as.endianness, &v->frame_size);
620 v->frame_size *= as->nchannels;
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;
631 /* report the audio format we support */
632 audio_pcm_init_info(&hw->info, &obt_as);
634 /* report the buffer size to qemu */
635 hw->samples = audio_buffer_frames(
636 qapi_AudiodevPipewirePerDirectionOptions_base(ppdo), &obt_as, 46440);
638 pw_thread_loop_unlock(c->thread_loop);
639 return 0;
642 static void
643 qpw_fini_out(HWVoiceOut *hw)
645 PWVoiceOut *pw = (PWVoiceOut *) hw;
646 PWVoice *v = &pw->v;
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);
657 static void
658 qpw_fini_in(HWVoiceIn *hw)
660 PWVoiceIn *pw = (PWVoiceIn *) hw;
661 PWVoice *v = &pw->v;
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);
672 static void
673 qpw_enable_out(HWVoiceOut *hw, bool enable)
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);
683 static void
684 qpw_enable_in(HWVoiceIn *hw, bool enable)
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);
694 static void
695 qpw_volume_out(HWVoiceOut *hw, Volume *vol)
697 PWVoiceOut *pw = (PWVoiceOut *) hw;
698 PWVoice *v = &pw->v;
699 pwaudio *c = v->g;
700 int i, ret;
702 pw_thread_loop_lock(c->thread_loop);
703 v->volume.channels = vol->channels;
705 for (i = 0; i < vol->channels; ++i) {
706 v->volume.values[i] = (float)vol->vol[i] / 255;
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");
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);
719 static void
720 qpw_volume_in(HWVoiceIn *hw, Volume *vol)
722 PWVoiceIn *pw = (PWVoiceIn *) hw;
723 PWVoice *v = &pw->v;
724 pwaudio *c = v->g;
725 int i, ret;
727 pw_thread_loop_lock(c->thread_loop);
728 v->volume.channels = vol->channels;
730 for (i = 0; i < vol->channels; ++i) {
731 v->volume.values[i] = (float)vol->vol[i] / 255;
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");
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);
744 static int wait_resync(pwaudio *pw)
746 int res;
747 pw->pending_seq = pw_core_sync(pw->core, PW_ID_CORE, pw->pending_seq);
749 while (true) {
750 pw_thread_loop_wait(pw->thread_loop);
752 res = pw->error;
753 if (res < 0) {
754 pw->error = 0;
755 return res;
757 if (pw->pending_seq == pw->last_seq) {
758 break;
761 return 0;
763 static void
764 on_core_error(void *data, uint32_t id, int seq, int res, const char *message)
766 pwaudio *pw = data;
768 error_report("error id:%u seq:%d res:%d (%s): %s",
769 id, seq, res, spa_strerror(res), message);
771 /* stop and exit the thread loop */
772 pw_thread_loop_signal(pw->thread_loop, FALSE);
775 static void
776 on_core_done(void *data, uint32_t id, int seq)
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);
787 static const struct pw_core_events core_events = {
788 PW_VERSION_CORE_EVENTS,
789 .done = on_core_done,
790 .error = on_core_error,
793 static void *
794 qpw_audio_init(Audiodev *dev)
796 g_autofree pwaudio *pw = g_new0(pwaudio, 1);
797 pw_init(NULL, NULL);
799 trace_pw_audio_init();
800 assert(dev->driver == AUDIODEV_DRIVER_PIPEWIRE);
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;
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;
816 if (pw_thread_loop_start(pw->thread_loop) < 0) {
817 error_report("Could not start Pipewire loop");
818 goto fail;
821 pw_thread_loop_lock(pw->thread_loop);
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;
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;
834 if (wait_resync(pw) < 0) {
835 pw_thread_loop_unlock(pw->thread_loop);
838 pw_thread_loop_unlock(pw->thread_loop);
840 return g_steal_pointer(&pw);
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);
847 if (pw->context) {
848 g_clear_pointer(&pw->context, pw_context_destroy);
850 if (pw->thread_loop) {
851 g_clear_pointer(&pw->thread_loop, pw_thread_loop_destroy);
853 return NULL;
856 static void
857 qpw_audio_fini(void *opaque)
859 pwaudio *pw = opaque;
861 if (pw->thread_loop) {
862 pw_thread_loop_stop(pw->thread_loop);
865 if (pw->core) {
866 spa_hook_remove(&pw->core_listener);
867 spa_zero(pw->core_listener);
868 pw_core_disconnect(pw->core);
871 if (pw->context) {
872 pw_context_destroy(pw->context);
874 pw_thread_loop_destroy(pw->thread_loop);
876 g_free(pw);
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,
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
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),
909 static void
910 register_audio_pw(void)
912 audio_driver_register(&pw_audio_driver);
915 type_init(register_audio_pw);