mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
audio/pwaudio.c: Add Pipewire audio backend for QEMU
This commit adds a new audiodev backend to allow QEMU to use Pipewire as both an audio sink and source. This backend is available on most systems Add Pipewire entry points for QEMU Pipewire audio backend Add wrappers for QEMU Pipewire audio backend in qpw_pcm_ops() qpw_write function returns the current state of the stream to pwaudio and Writes some data to the server for playback streams using pipewire spa_ringbuffer implementation. qpw_read function returns the current state of the stream to pwaudio and reads some data from the server for capture streams using pipewire spa_ringbuffer implementation. These functions qpw_write and qpw_read are called during playback and capture. Added some functions that convert pw audio formats to QEMU audio format and vice versa which would be needed in the pipewire audio sink and source functions qpw_init_in() & qpw_init_out(). These methods that implement playback and recording will create streams for playback and capture that will start processing and will result in the on_process callbacks to be called. Built a connection to the Pipewire sound system server in the qpw_audio_init() method. Signed-off-by: Dorinda Bassey <dbassey@redhat.com> Reviewed-by: Volker Rümelin <vr_qemu@t-online.de> Message-Id: <20230417105654.32328-1-dbassey@redhat.com> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
committed by
Marc-André Lureau
parent
f6b761bdbd
commit
c2d3d1c294
@@ -2061,6 +2061,9 @@ void audio_create_pdos(Audiodev *dev)
|
||||
#ifdef CONFIG_AUDIO_PA
|
||||
CASE(PA, pa, Pa);
|
||||
#endif
|
||||
#ifdef CONFIG_AUDIO_PIPEWIRE
|
||||
CASE(PIPEWIRE, pipewire, Pipewire);
|
||||
#endif
|
||||
#ifdef CONFIG_AUDIO_SDL
|
||||
CASE(SDL, sdl, Sdl);
|
||||
#endif
|
||||
|
||||
@@ -362,6 +362,10 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
|
||||
case AUDIODEV_DRIVER_PA:
|
||||
return qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.TYPE);
|
||||
#endif
|
||||
#ifdef CONFIG_AUDIO_PIPEWIRE
|
||||
case AUDIODEV_DRIVER_PIPEWIRE:
|
||||
return qapi_AudiodevPipewirePerDirectionOptions_base(dev->u.pipewire.TYPE);
|
||||
#endif
|
||||
#ifdef CONFIG_AUDIO_SDL
|
||||
case AUDIODEV_DRIVER_SDL:
|
||||
return qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.TYPE);
|
||||
|
||||
@@ -19,6 +19,7 @@ foreach m : [
|
||||
['sdl', sdl, files('sdlaudio.c')],
|
||||
['jack', jack, files('jackaudio.c')],
|
||||
['sndio', sndio, files('sndioaudio.c')],
|
||||
['pipewire', pipewire, files('pwaudio.c')],
|
||||
['spice', spice, files('spiceaudio.c')]
|
||||
]
|
||||
if m[1].found()
|
||||
|
||||
+915
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,14 @@ dbus_audio_register(const char *s, const char *dir) "sender = %s, dir = %s"
|
||||
dbus_audio_put_buffer_out(size_t len) "len = %zu"
|
||||
dbus_audio_read(size_t len) "len = %zu"
|
||||
|
||||
# pwaudio.c
|
||||
pw_state_changed(int nodeid, const char *s) "node id: %d stream state: %s"
|
||||
pw_read(int32_t avail, uint32_t index, size_t len) "avail=%d index=%u len=%zu"
|
||||
pw_write(int32_t filled, int32_t avail, uint32_t index, size_t len) "filled=%d avail=%d index=%u len=%zu"
|
||||
pw_vol(const char *ret) "set volume: %s"
|
||||
pw_period(uint64_t quantum, uint32_t rate) "period =%" PRIu64 "/%u"
|
||||
pw_audio_init(void) "Initialize Pipewire context"
|
||||
|
||||
# audio.c
|
||||
audio_timer_start(int interval) "interval %d ms"
|
||||
audio_timer_stop(void) ""
|
||||
|
||||
@@ -734,6 +734,12 @@ if not get_option('jack').auto() or have_system
|
||||
jack = dependency('jack', required: get_option('jack'),
|
||||
method: 'pkg-config', kwargs: static_kwargs)
|
||||
endif
|
||||
pipewire = not_found
|
||||
if not get_option('pipewire').auto() or (targetos == 'linux' and have_system)
|
||||
pipewire = dependency('libpipewire-0.3', version: '>=0.3.60',
|
||||
required: get_option('pipewire'),
|
||||
method: 'pkg-config', kwargs: static_kwargs)
|
||||
endif
|
||||
sndio = not_found
|
||||
if not get_option('sndio').auto() or have_system
|
||||
sndio = dependency('sndio', required: get_option('sndio'),
|
||||
@@ -1671,6 +1677,7 @@ if have_system
|
||||
'jack': jack.found(),
|
||||
'oss': oss.found(),
|
||||
'pa': pulse.found(),
|
||||
'pipewire': pipewire.found(),
|
||||
'sdl': sdl.found(),
|
||||
'sndio': sndio.found(),
|
||||
}
|
||||
@@ -3981,6 +3988,7 @@ if targetos == 'linux'
|
||||
summary_info += {'ALSA support': alsa}
|
||||
summary_info += {'PulseAudio support': pulse}
|
||||
endif
|
||||
summary_info += {'Pipewire support': pipewire}
|
||||
summary_info += {'JACK support': jack}
|
||||
summary_info += {'brlapi support': brlapi}
|
||||
summary_info += {'vde support': vde}
|
||||
|
||||
+3
-1
@@ -21,7 +21,7 @@ option('tls_priority', type : 'string', value : 'NORMAL',
|
||||
option('default_devices', type : 'boolean', value : true,
|
||||
description: 'Include a default selection of devices in emulators')
|
||||
option('audio_drv_list', type: 'array', value: ['default'],
|
||||
choices: ['alsa', 'coreaudio', 'default', 'dsound', 'jack', 'oss', 'pa', 'sdl', 'sndio'],
|
||||
choices: ['alsa', 'coreaudio', 'default', 'dsound', 'jack', 'oss', 'pa', 'pipewire', 'sdl', 'sndio'],
|
||||
description: 'Set audio driver list')
|
||||
option('block_drv_rw_whitelist', type : 'string', value : '',
|
||||
description: 'set block driver read-write whitelist (by default affects only QEMU, not tools like qemu-img)')
|
||||
@@ -255,6 +255,8 @@ option('oss', type: 'feature', value: 'auto',
|
||||
description: 'OSS sound support')
|
||||
option('pa', type: 'feature', value: 'auto',
|
||||
description: 'PulseAudio sound support')
|
||||
option('pipewire', type: 'feature', value: 'auto',
|
||||
description: 'Pipewire sound support')
|
||||
option('sndio', type: 'feature', value: 'auto',
|
||||
description: 'sndio sound support')
|
||||
|
||||
|
||||
@@ -324,6 +324,47 @@
|
||||
'*out': 'AudiodevPaPerDirectionOptions',
|
||||
'*server': 'str' } }
|
||||
|
||||
##
|
||||
# @AudiodevPipewirePerDirectionOptions:
|
||||
#
|
||||
# Options of the Pipewire backend that are used for both playback and
|
||||
# recording.
|
||||
#
|
||||
# @name: name of the sink/source to use
|
||||
#
|
||||
# @stream-name: name of the Pipewire stream created by qemu. Can be
|
||||
# used to identify the stream in Pipewire when you
|
||||
# create multiple Pipewire devices or run multiple qemu
|
||||
# instances (default: audiodev's id)
|
||||
#
|
||||
# @latency: latency you want Pipewire to achieve in microseconds
|
||||
# (default 46000)
|
||||
#
|
||||
# Since: 8.1
|
||||
##
|
||||
{ 'struct': 'AudiodevPipewirePerDirectionOptions',
|
||||
'base': 'AudiodevPerDirectionOptions',
|
||||
'data': {
|
||||
'*name': 'str',
|
||||
'*stream-name': 'str',
|
||||
'*latency': 'uint32' } }
|
||||
|
||||
##
|
||||
# @AudiodevPipewireOptions:
|
||||
#
|
||||
# Options of the Pipewire audio backend.
|
||||
#
|
||||
# @in: options of the capture stream
|
||||
#
|
||||
# @out: options of the playback stream
|
||||
#
|
||||
# Since: 8.1
|
||||
##
|
||||
{ 'struct': 'AudiodevPipewireOptions',
|
||||
'data': {
|
||||
'*in': 'AudiodevPipewirePerDirectionOptions',
|
||||
'*out': 'AudiodevPipewirePerDirectionOptions' } }
|
||||
|
||||
##
|
||||
# @AudiodevSdlPerDirectionOptions:
|
||||
#
|
||||
@@ -416,6 +457,7 @@
|
||||
{ 'name': 'jack', 'if': 'CONFIG_AUDIO_JACK' },
|
||||
{ 'name': 'oss', 'if': 'CONFIG_AUDIO_OSS' },
|
||||
{ 'name': 'pa', 'if': 'CONFIG_AUDIO_PA' },
|
||||
{ 'name': 'pipewire', 'if': 'CONFIG_AUDIO_PIPEWIRE' },
|
||||
{ 'name': 'sdl', 'if': 'CONFIG_AUDIO_SDL' },
|
||||
{ 'name': 'sndio', 'if': 'CONFIG_AUDIO_SNDIO' },
|
||||
{ 'name': 'spice', 'if': 'CONFIG_SPICE' },
|
||||
@@ -456,6 +498,8 @@
|
||||
'if': 'CONFIG_AUDIO_OSS' },
|
||||
'pa': { 'type': 'AudiodevPaOptions',
|
||||
'if': 'CONFIG_AUDIO_PA' },
|
||||
'pipewire': { 'type': 'AudiodevPipewireOptions',
|
||||
'if': 'CONFIG_AUDIO_PIPEWIRE' },
|
||||
'sdl': { 'type': 'AudiodevSdlOptions',
|
||||
'if': 'CONFIG_AUDIO_SDL' },
|
||||
'sndio': { 'type': 'AudiodevSndioOptions',
|
||||
|
||||
@@ -793,6 +793,12 @@ DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev,
|
||||
" in|out.name= source/sink device name\n"
|
||||
" in|out.latency= desired latency in microseconds\n"
|
||||
#endif
|
||||
#ifdef CONFIG_AUDIO_PIPEWIRE
|
||||
"-audiodev pipewire,id=id[,prop[=value][,...]]\n"
|
||||
" in|out.name= source/sink device name\n"
|
||||
" in|out.stream-name= name of pipewire stream\n"
|
||||
" in|out.latency= desired latency in microseconds\n"
|
||||
#endif
|
||||
#ifdef CONFIG_AUDIO_SDL
|
||||
"-audiodev sdl,id=id[,prop[=value][,...]]\n"
|
||||
" in|out.buffer-count= number of buffers\n"
|
||||
@@ -956,6 +962,21 @@ SRST
|
||||
Desired latency in microseconds. The PulseAudio server will try
|
||||
to honor this value but actual latencies may be lower or higher.
|
||||
|
||||
``-audiodev pipewire,id=id[,prop[=value][,...]]``
|
||||
Creates a backend using Pipewire. This backend is available on
|
||||
most systems.
|
||||
|
||||
Pipewire specific options are:
|
||||
|
||||
``in|out.latency=usecs``
|
||||
Desired latency in microseconds.
|
||||
|
||||
``in|out.name=sink``
|
||||
Use the specified source/sink for recording/playback.
|
||||
|
||||
``in|out.stream-name``
|
||||
Specify the name of pipewire stream.
|
||||
|
||||
``-audiodev sdl,id=id[,prop[=value][,...]]``
|
||||
Creates a backend using SDL. This backend is available on most
|
||||
systems, but you should use your platform's native backend if
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# This file is generated by meson-buildoptions.py, do not edit!
|
||||
meson_options_help() {
|
||||
printf "%s\n" ' --audio-drv-list=CHOICES Set audio driver list [default] (choices: alsa/co'
|
||||
printf "%s\n" ' reaudio/default/dsound/jack/oss/pa/sdl/sndio)'
|
||||
printf "%s\n" ' --audio-drv-list=CHOICES Set audio driver list [default] (choices: al'
|
||||
printf "%s\n" ' sa/coreaudio/default/dsound/jack/oss/pa/'
|
||||
printf "%s\n" ' pipewire/sdl/sndio)'
|
||||
printf "%s\n" ' --block-drv-ro-whitelist=VALUE'
|
||||
printf "%s\n" ' set block driver read-only whitelist (by default'
|
||||
printf "%s\n" ' affects only QEMU, not tools like qemu-img)'
|
||||
@@ -136,6 +137,7 @@ meson_options_help() {
|
||||
printf "%s\n" ' oss OSS sound support'
|
||||
printf "%s\n" ' pa PulseAudio sound support'
|
||||
printf "%s\n" ' parallels parallels image format support'
|
||||
printf "%s\n" ' pipewire Pipewire sound support'
|
||||
printf "%s\n" ' png PNG support with libpng'
|
||||
printf "%s\n" ' pvrdma Enable PVRDMA support'
|
||||
printf "%s\n" ' qcow1 qcow1 image format support'
|
||||
@@ -370,6 +372,8 @@ _meson_option_parse() {
|
||||
--disable-pa) printf "%s" -Dpa=disabled ;;
|
||||
--enable-parallels) printf "%s" -Dparallels=enabled ;;
|
||||
--disable-parallels) printf "%s" -Dparallels=disabled ;;
|
||||
--enable-pipewire) printf "%s" -Dpipewire=enabled ;;
|
||||
--disable-pipewire) printf "%s" -Dpipewire=disabled ;;
|
||||
--with-pkgversion=*) quote_sh "-Dpkgversion=$2" ;;
|
||||
--enable-png) printf "%s" -Dpng=enabled ;;
|
||||
--disable-png) printf "%s" -Dpng=disabled ;;
|
||||
|
||||
Reference in New Issue
Block a user