[PATCH v4 0/5] bhyve: implement sound device support

Changes from v3: - In conf and bhyve code, cast audio->type to virDomainAudioType and use switch to make compile force handling of all possible cases, - Patch 'tests: schema: test bhyvexml2xmloutdata schemas' removed from the series as it was pushed separately. Roman Bogorodskiy (5): conf: add 'ich7' sound model bhyve: implement sound device support conf: allow to map sound device to host device bhyve: allow to specify host sound device docs: formatdomain: document <audio> element docs/formatdomain.rst | 49 +++++ docs/schemas/domaincommon.rng | 37 ++++ src/bhyve/bhyve_capabilities.c | 14 ++ src/bhyve/bhyve_capabilities.h | 1 + src/bhyve/bhyve_command.c | 62 ++++++ src/bhyve/bhyve_device.c | 9 + src/conf/domain_capabilities.c | 4 + src/conf/domain_conf.c | 196 +++++++++++++++++- src/conf/domain_conf.h | 33 +++ src/conf/virconftypes.h | 3 + src/libvirt_private.syms | 3 + src/qemu/qemu_command.c | 2 + src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain_address.c | 3 + src/qemu/qemu_driver.c | 5 + src/qemu/qemu_hotplug.c | 3 + src/qemu/qemu_validate.c | 2 + .../bhyvexml2argv-sound.args | 10 + .../bhyvexml2argv-sound.ldargs | 3 + .../bhyvexml2argvdata/bhyvexml2argv-sound.xml | 30 +++ tests/bhyvexml2argvtest.c | 6 +- .../bhyvexml2xmlout-sound.xml | 41 ++++ tests/bhyvexml2xmltest.c | 1 + 23 files changed, 515 insertions(+), 3 deletions(-) create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-sound.args create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-sound.ldargs create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-sound.xml create mode 100644 tests/bhyvexml2xmloutdata/bhyvexml2xmlout-sound.xml -- 2.27.0

Add 'ich7' sound model. This is a preparation for sound support in bhyve, as 'ich7' is the only model it supports. Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- docs/schemas/domaincommon.rng | 1 + src/conf/domain_conf.c | 1 + src/conf/domain_conf.h | 1 + src/qemu/qemu_command.c | 1 + src/qemu/qemu_domain_address.c | 1 + src/qemu/qemu_validate.c | 1 + 6 files changed, 6 insertions(+) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 0d0dcbc5ce..fb9638f3f6 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -4360,6 +4360,7 @@ <value>pcspk</value> <value>ac97</value> <value>ich6</value> + <value>ich7</value> <value>ich9</value> <value>usb</value> </choice> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 8e7981bf25..8d0d342504 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -726,6 +726,7 @@ VIR_ENUM_IMPL(virDomainSoundModel, "ich6", "ich9", "usb", + "ich7", ); VIR_ENUM_IMPL(virDomainKeyWrapCipherName, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 68be32614c..7b60c28c6d 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1401,6 +1401,7 @@ typedef enum { VIR_DOMAIN_SOUND_MODEL_ICH6, VIR_DOMAIN_SOUND_MODEL_ICH9, VIR_DOMAIN_SOUND_MODEL_USB, + VIR_DOMAIN_SOUND_MODEL_ICH7, VIR_DOMAIN_SOUND_MODEL_LAST } virDomainSoundModel; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 01812cd39b..ec3d4c8d99 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4026,6 +4026,7 @@ qemuBuildSoundDevStr(const virDomainDef *def, model = "sb16"; break; case VIR_DOMAIN_SOUND_MODEL_PCSPK: /* pc-speaker is handled separately */ + case VIR_DOMAIN_SOUND_MODEL_ICH7: case VIR_DOMAIN_SOUND_MODEL_LAST: return NULL; } diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 058cbda2a2..d25fb653d3 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -759,6 +759,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, case VIR_DOMAIN_SOUND_MODEL_SB16: case VIR_DOMAIN_SOUND_MODEL_PCSPK: case VIR_DOMAIN_SOUND_MODEL_USB: + case VIR_DOMAIN_SOUND_MODEL_ICH7: case VIR_DOMAIN_SOUND_MODEL_LAST: return 0; } diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 488f258d00..4cd377c8bc 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -3588,6 +3588,7 @@ qemuValidateDomainDeviceDefSound(virDomainSoundDefPtr sound, case VIR_DOMAIN_SOUND_MODEL_SB16: case VIR_DOMAIN_SOUND_MODEL_PCSPK: break; + case VIR_DOMAIN_SOUND_MODEL_ICH7: case VIR_DOMAIN_SOUND_MODEL_LAST: virReportError(VIR_ERR_INTERNAL_ERROR, _("sound card model '%s' is not supported by qemu"), -- 2.27.0

On Sat, Aug 22, 2020 at 05:11:52PM +0400, Roman Bogorodskiy wrote:
Add 'ich7' sound model. This is a preparation for sound support in bhyve, as 'ich7' is the only model it supports.
Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- docs/schemas/domaincommon.rng | 1 + src/conf/domain_conf.c | 1 + src/conf/domain_conf.h | 1 + src/qemu/qemu_command.c | 1 + src/qemu/qemu_domain_address.c | 1 + src/qemu/qemu_validate.c | 1 + 6 files changed, 6 insertions(+)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

bhyve supports intel hda sound devices that could be specified on the command like using "-1:0,hda,play=$play_dev,rec=$rec_dev", where "1:0" is a PCI address, and "$play_dev" and "$rec_dev" point to the playback and recording device on the host respectively. Currently, schema of the 'sound' element doesn't allow specifying neither playback nor recording devices, so for now hardcode /dev/dsp0, which is the first audio device on the host. Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/bhyve/bhyve_capabilities.c | 14 ++++++++ src/bhyve/bhyve_capabilities.h | 1 + src/bhyve/bhyve_command.c | 33 +++++++++++++++++ src/bhyve/bhyve_device.c | 9 +++++ .../bhyvexml2argv-sound.args | 10 ++++++ .../bhyvexml2argv-sound.ldargs | 3 ++ .../bhyvexml2argvdata/bhyvexml2argv-sound.xml | 24 +++++++++++++ tests/bhyvexml2argvtest.c | 6 +++- .../bhyvexml2xmlout-sound.xml | 36 +++++++++++++++++++ tests/bhyvexml2xmltest.c | 1 + 10 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-sound.args create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-sound.ldargs create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-sound.xml create mode 100644 tests/bhyvexml2xmloutdata/bhyvexml2xmlout-sound.xml diff --git a/src/bhyve/bhyve_capabilities.c b/src/bhyve/bhyve_capabilities.c index fb8829d571..36f3985335 100644 --- a/src/bhyve/bhyve_capabilities.c +++ b/src/bhyve/bhyve_capabilities.c @@ -323,6 +323,17 @@ bhyveProbeCapsXHCIController(unsigned int *caps, char *binary) } +static int +bhyveProbeCapsSoundHda(unsigned int *caps, char *binary) +{ + return bhyveProbeCapsDeviceHelper(caps, binary, + "-s", + "0,hda", + "pci slot 0:0: unknown device \"hda\"", + BHYVE_CAP_SOUND_HDA); +} + + int virBhyveProbeCaps(unsigned int *caps) { @@ -351,6 +362,9 @@ virBhyveProbeCaps(unsigned int *caps) if ((ret = bhyveProbeCapsXHCIController(caps, binary))) goto out; + if ((ret = bhyveProbeCapsSoundHda(caps, binary))) + goto out; + out: VIR_FREE(binary); return ret; diff --git a/src/bhyve/bhyve_capabilities.h b/src/bhyve/bhyve_capabilities.h index 12926cf423..1ac9ff4283 100644 --- a/src/bhyve/bhyve_capabilities.h +++ b/src/bhyve/bhyve_capabilities.h @@ -49,6 +49,7 @@ typedef enum { BHYVE_CAP_FBUF = 1 << 4, BHYVE_CAP_XHCI = 1 << 5, BHYVE_CAP_CPUTOPOLOGY = 1 << 6, + BHYVE_CAP_SOUND_HDA = 1 << 7, } virBhyveCapsFlags; int virBhyveProbeGrubCaps(virBhyveGrubCapsFlags *caps); diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c index 86e6640359..1f42f71347 100644 --- a/src/bhyve/bhyve_command.c +++ b/src/bhyve/bhyve_command.c @@ -475,6 +475,34 @@ bhyveBuildGraphicsArgStr(const virDomainDef *def, } +static int +bhyveBuildSoundArgStr(const virDomainDef *def G_GNUC_UNUSED, + virDomainSoundDefPtr sound, + bhyveConnPtr driver, + virCommandPtr cmd) +{ + if (!(bhyveDriverGetBhyveCaps(driver) & BHYVE_CAP_SOUND_HDA)) { + /* Currently, bhyve only supports "hda" sound devices, so + if it's not supported, sound devices are not supported at all */ + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Sound devices emulation is not supported " + "by given bhyve binary")); + return -1; + } + + if (sound->model != VIR_DOMAIN_SOUND_MODEL_ICH7) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Sound device model is not supported")); + return -1; + } + + virCommandAddArg(cmd, "-s"); + virCommandAddArgFormat(cmd, "%d:%d,hda,play=/dev/dsp0", + sound->info.addr.pci.slot, + sound->info.addr.pci.function); + return 0; +} + virCommandPtr virBhyveProcessBuildBhyveCmd(bhyveConnPtr driver, virDomainDefPtr def, bool dryRun) @@ -619,6 +647,11 @@ virBhyveProcessBuildBhyveCmd(bhyveConnPtr driver, virDomainDefPtr def, } } + for (i = 0; i < def->nsounds; i++) { + if (bhyveBuildSoundArgStr(def, def->sounds[i], driver, cmd) < 0) + goto error; + } + if (bhyveDomainDefNeedsISAController(def)) bhyveBuildLPCArgStr(def, cmd); diff --git a/src/bhyve/bhyve_device.c b/src/bhyve/bhyve_device.c index fc52280361..3c8ff587e0 100644 --- a/src/bhyve/bhyve_device.c +++ b/src/bhyve/bhyve_device.c @@ -154,6 +154,15 @@ bhyveAssignDevicePCISlots(virDomainDefPtr def, return -1; } + for (i = 0; i < def->nsounds; i++) { + if (!virDeviceInfoPCIAddressIsWanted(&def->sounds[i]->info)) + continue; + if (virDomainPCIAddressReserveNextAddr(addrs, + &def->sounds[i]->info, + VIR_PCI_CONNECT_TYPE_PCI_DEVICE, + -1) < 0) + return -1; + } return 0; } diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-sound.args b/tests/bhyvexml2argvdata/bhyvexml2argv-sound.args new file mode 100644 index 0000000000..c242708ff1 --- /dev/null +++ b/tests/bhyvexml2argvdata/bhyvexml2argv-sound.args @@ -0,0 +1,10 @@ +/usr/sbin/bhyve \ +-c 1 \ +-m 214 \ +-u \ +-H \ +-P \ +-s 0:0,hostbridge \ +-s 2:0,ahci,hd:/tmp/freebsd.img \ +-s 3:0,virtio-net,faketapdev,mac=52:54:00:b9:94:02 \ +-s 4:0,hda,play=/dev/dsp0 bhyve diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-sound.ldargs b/tests/bhyvexml2argvdata/bhyvexml2argv-sound.ldargs new file mode 100644 index 0000000000..32538b558e --- /dev/null +++ b/tests/bhyvexml2argvdata/bhyvexml2argv-sound.ldargs @@ -0,0 +1,3 @@ +/usr/sbin/bhyveload \ +-m 214 \ +-d /tmp/freebsd.img bhyve diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-sound.xml b/tests/bhyvexml2argvdata/bhyvexml2argv-sound.xml new file mode 100644 index 0000000000..8e799301fb --- /dev/null +++ b/tests/bhyvexml2argvdata/bhyvexml2argv-sound.xml @@ -0,0 +1,24 @@ +<domain type='bhyve'> + <name>bhyve</name> + <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid> + <memory>219136</memory> + <vcpu>1</vcpu> + <os> + <type>hvm</type> + </os> + <devices> + <disk type='file'> + <driver name='file' type='raw'/> + <source file='/tmp/freebsd.img'/> + <target dev='hda' bus='sata'/> + <address type='drive' controller='0' bus='0' target='2' unit='0'/> + </disk> + <interface type='bridge'> + <mac address='52:54:00:b9:94:02'/> + <model type='virtio'/> + <source bridge="virbr0"/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </interface> + <sound model='ich7'/> + </devices> +</domain> diff --git a/tests/bhyvexml2argvtest.c b/tests/bhyvexml2argvtest.c index 7ce4dc6e58..0a05d6d892 100644 --- a/tests/bhyvexml2argvtest.c +++ b/tests/bhyvexml2argvtest.c @@ -166,7 +166,7 @@ mymain(void) driver.bhyvecaps = BHYVE_CAP_RTC_UTC | BHYVE_CAP_AHCI32SLOT | \ BHYVE_CAP_NET_E1000 | BHYVE_CAP_LPC_BOOTROM | \ BHYVE_CAP_FBUF | BHYVE_CAP_XHCI | \ - BHYVE_CAP_CPUTOPOLOGY; + BHYVE_CAP_CPUTOPOLOGY | BHYVE_CAP_SOUND_HDA; DO_TEST("base"); DO_TEST("wired"); @@ -201,6 +201,7 @@ mymain(void) DO_TEST_FAILURE("cputopology-nvcpu-mismatch"); DO_TEST("commandline"); DO_TEST("msrs"); + DO_TEST("sound"); /* Address allocation tests */ DO_TEST("addr-single-sata-disk"); @@ -240,6 +241,9 @@ mymain(void) driver.bhyvecaps &= ~BHYVE_CAP_CPUTOPOLOGY; DO_TEST_FAILURE("cputopology"); + driver.bhyvecaps &= ~BHYVE_CAP_SOUND_HDA; + DO_TEST_FAILURE("sound"); + virObjectUnref(driver.caps); virObjectUnref(driver.xmlopt); virPortAllocatorRangeFree(driver.remotePorts); diff --git a/tests/bhyvexml2xmloutdata/bhyvexml2xmlout-sound.xml b/tests/bhyvexml2xmloutdata/bhyvexml2xmlout-sound.xml new file mode 100644 index 0000000000..a64c5da27a --- /dev/null +++ b/tests/bhyvexml2xmloutdata/bhyvexml2xmlout-sound.xml @@ -0,0 +1,36 @@ +<domain type='bhyve'> + <name>bhyve</name> + <uuid>df3be7e7-a104-11e3-aeb0-50e5492bd3dc</uuid> + <memory unit='KiB'>219136</memory> + <currentMemory unit='KiB'>219136</currentMemory> + <vcpu placement='static'>1</vcpu> + <os> + <type arch='x86_64'>hvm</type> + <boot dev='hd'/> + </os> + <clock offset='utc'/> + <on_poweroff>destroy</on_poweroff> + <on_reboot>restart</on_reboot> + <on_crash>destroy</on_crash> + <devices> + <disk type='file' device='disk'> + <driver name='file' type='raw'/> + <source file='/tmp/freebsd.img'/> + <target dev='hda' bus='sata'/> + <address type='drive' controller='0' bus='0' target='2' unit='0'/> + </disk> + <controller type='pci' index='0' model='pci-root'/> + <controller type='sata' index='0'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> + </controller> + <interface type='bridge'> + <mac address='52:54:00:b9:94:02'/> + <source bridge='virbr0'/> + <model type='virtio'/> + <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> + </interface> + <sound model='ich7'> + <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> + </sound> + </devices> +</domain> diff --git a/tests/bhyvexml2xmltest.c b/tests/bhyvexml2xmltest.c index 2ac102b8e3..f9af1a364d 100644 --- a/tests/bhyvexml2xmltest.c +++ b/tests/bhyvexml2xmltest.c @@ -108,6 +108,7 @@ mymain(void) DO_TEST_DIFFERENT("vnc-autoport"); DO_TEST_DIFFERENT("commandline"); DO_TEST_DIFFERENT("msrs"); + DO_TEST_DIFFERENT("sound"); /* Address allocation tests */ DO_TEST_DIFFERENT("addr-single-sata-disk"); -- 2.27.0

On Sat, Aug 22, 2020 at 05:11:53PM +0400, Roman Bogorodskiy wrote:
bhyve supports intel hda sound devices that could be specified on the command like using "-1:0,hda,play=$play_dev,rec=$rec_dev", where "1:0" is a PCI address, and "$play_dev" and "$rec_dev" point to the playback and recording device on the host respectively. Currently, schema of the 'sound' element doesn't allow specifying neither playback nor recording devices, so for now hardcode /dev/dsp0, which is the first audio device on the host.
Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/bhyve/bhyve_capabilities.c | 14 ++++++++ src/bhyve/bhyve_capabilities.h | 1 + src/bhyve/bhyve_command.c | 33 +++++++++++++++++ src/bhyve/bhyve_device.c | 9 +++++ .../bhyvexml2argv-sound.args | 10 ++++++ .../bhyvexml2argv-sound.ldargs | 3 ++ .../bhyvexml2argvdata/bhyvexml2argv-sound.xml | 24 +++++++++++++ tests/bhyvexml2argvtest.c | 6 +++- .../bhyvexml2xmlout-sound.xml | 36 +++++++++++++++++++ tests/bhyvexml2xmltest.c | 1 + 10 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-sound.args create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-sound.ldargs create mode 100644 tests/bhyvexml2argvdata/bhyvexml2argv-sound.xml create mode 100644 tests/bhyvexml2xmloutdata/bhyvexml2xmlout-sound.xml
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Introduce a new device element "<audio>" which allows to map guest sound device specified using the "<sound>" element to specific audio backend. Example: <sound model='ich7'> <audio id='1'/> </sound> <audio id='1' type='oss'> <input dev='/dev/dsp0'/> <output dev='/dev/dsp0'/> </audio> This block maps to OSS audio backend on the host using /dev/dsp0 device for both input (recording) and output (playback). OSS is the only backend supported so far. Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- docs/schemas/domaincommon.rng | 36 +++++++ src/conf/domain_capabilities.c | 4 + src/conf/domain_conf.c | 182 ++++++++++++++++++++++++++++++++- src/conf/domain_conf.h | 28 +++++ src/conf/virconftypes.h | 3 + src/libvirt_private.syms | 2 + src/qemu/qemu_command.c | 1 + src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain_address.c | 2 + src/qemu/qemu_driver.c | 5 + src/qemu/qemu_hotplug.c | 3 + src/qemu/qemu_validate.c | 1 + 12 files changed, 266 insertions(+), 2 deletions(-) diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index fb9638f3f6..c933c71035 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -4372,12 +4372,47 @@ <optional> <ref name="address"/> </optional> + <optional> + <element name="audio"> + <attribute name="id"> + <ref name="uint8"/> + </attribute> + </element> + </optional> <zeroOrMore> <ref name="codec"/> </zeroOrMore> </interleave> </element> </define> + <define name="audio"> + <element name="audio"> + <attribute name="id"> + <ref name="uint8"/> + </attribute> + <attribute name="type"> + <choice> + <value>oss</value> + </choice> + </attribute> + <interleave> + <optional> + <element name="input"> + <attribute name="dev"> + <ref name="deviceName"/> + </attribute> + </element> + </optional> + <optional> + <element name="output"> + <attribute name="dev"> + <ref name="deviceName"/> + </attribute> + </element> + </optional> + </interleave> + </element> + </define> <define name="watchdog"> <element name="watchdog"> <attribute name="model"> @@ -5303,6 +5338,7 @@ <ref name="interface"/> <ref name="input"/> <ref name="sound"/> + <ref name="audio"/> <ref name="hostdev"/> <ref name="graphic"/> <ref name="video"/> diff --git a/src/conf/domain_capabilities.c b/src/conf/domain_capabilities.c index d61108e125..59ad8937a4 100644 --- a/src/conf/domain_capabilities.c +++ b/src/conf/domain_capabilities.c @@ -688,6 +688,10 @@ virDomainCapsDeviceDefValidate(const virDomainCaps *caps, ret = virDomainCapsDeviceVideoDefValidate(caps, dev->data.video); break; + case VIR_DOMAIN_DEVICE_AUDIO: + /* TODO: add validation */ + break; + case VIR_DOMAIN_DEVICE_DISK: case VIR_DOMAIN_DEVICE_REDIRDEV: case VIR_DOMAIN_DEVICE_NET: diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 8d0d342504..9c05f301dd 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -323,6 +323,7 @@ VIR_ENUM_IMPL(virDomainDevice, "memory", "iommu", "vsock", + "audio", ); VIR_ENUM_IMPL(virDomainDiskDevice, @@ -729,6 +730,11 @@ VIR_ENUM_IMPL(virDomainSoundModel, "ich7", ); +VIR_ENUM_IMPL(virDomainAudioType, + VIR_DOMAIN_AUDIO_TYPE_LAST, + "oss", +); + VIR_ENUM_IMPL(virDomainKeyWrapCipherName, VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_LAST, "aes", @@ -2864,6 +2870,24 @@ void virDomainSoundDefFree(virDomainSoundDefPtr def) VIR_FREE(def); } +void virDomainAudioDefFree(virDomainAudioDefPtr def) +{ + if (!def) + return; + + switch ((virDomainAudioType) def->type) { + case VIR_DOMAIN_AUDIO_TYPE_OSS: + VIR_FREE(def->backend.oss.inputDev); + VIR_FREE(def->backend.oss.outputDev); + break; + + case VIR_DOMAIN_AUDIO_TYPE_LAST: + break; + } + + VIR_FREE(def); +} + virDomainSoundDefPtr virDomainSoundDefRemove(virDomainDefPtr def, size_t idx) { @@ -3217,6 +3241,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def) case VIR_DOMAIN_DEVICE_VSOCK: virDomainVsockDefFree(def->data.vsock); break; + case VIR_DOMAIN_DEVICE_AUDIO: + virDomainAudioDefFree(def->data.audio); + break; case VIR_DOMAIN_DEVICE_LAST: case VIR_DOMAIN_DEVICE_NONE: break; @@ -3477,6 +3504,10 @@ void virDomainDefFree(virDomainDefPtr def) virDomainSoundDefFree(def->sounds[i]); VIR_FREE(def->sounds); + for (i = 0; i < def->naudios; i++) + virDomainAudioDefFree(def->audios[i]); + VIR_FREE(def->audios); + for (i = 0; i < def->nvideos; i++) virDomainVideoDefFree(def->videos[i]); VIR_FREE(def->videos); @@ -4065,6 +4096,7 @@ virDomainDeviceGetInfo(virDomainDeviceDefPtr device) case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_GRAPHICS: case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_LAST: case VIR_DOMAIN_DEVICE_NONE: break; @@ -4159,6 +4191,9 @@ virDomainDeviceSetData(virDomainDeviceDefPtr device, case VIR_DOMAIN_DEVICE_LEASE: device->data.lease = devicedata; break; + case VIR_DOMAIN_DEVICE_AUDIO: + device->data.audio = devicedata; + break; case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_LAST: break; @@ -4425,6 +4460,7 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def, case VIR_DOMAIN_DEVICE_MEMORY: case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_VSOCK: + case VIR_DOMAIN_DEVICE_AUDIO: break; } #endif @@ -5417,6 +5453,7 @@ virDomainDeviceDefPostParseCommon(virDomainDeviceDefPtr dev, case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_MEMORY: case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_AUDIO: ret = 0; break; @@ -6806,6 +6843,8 @@ virDomainDeviceDefValidateInternal(const virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_SHMEM: return virDomainShmemDefValidate(dev->data.shmem); + case VIR_DOMAIN_DEVICE_AUDIO: + /* TODO: validate? */ case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_FS: case VIR_DOMAIN_DEVICE_SOUND: @@ -15008,10 +15047,10 @@ virDomainSoundDefParseXML(virDomainXMLOptionPtr xmlopt, virDomainSoundDefPtr def; VIR_XPATH_NODE_AUTORESTORE(ctxt); g_autofree char *model = NULL; + xmlNodePtr audioNode; if (VIR_ALLOC(def) < 0) return NULL; - ctxt->node = node; model = virXMLPropString(node, "model"); @@ -15048,6 +15087,18 @@ virDomainSoundDefParseXML(virDomainXMLOptionPtr xmlopt, } } + audioNode = virXPathNode("./audio", ctxt); + if (audioNode) { + g_autofree char *tmp = NULL; + tmp = virXMLPropString(audioNode, "id"); + if (virStrToLong_ui(tmp, NULL, 10, &def->audioId) < 0 || + def->audioId == 0) { + virReportError(VIR_ERR_XML_ERROR, + _("Invalid audio 'id' value '%s'"), tmp); + goto error; + } + } + if (virDomainDeviceInfoParseXML(xmlopt, node, &def->info, flags) < 0) goto error; @@ -15099,6 +15150,64 @@ virDomainSoundDefFind(const virDomainDef *def, } +static virDomainAudioDefPtr +virDomainAudioDefParseXML(virDomainXMLOptionPtr xmlopt G_GNUC_UNUSED, + xmlNodePtr node G_GNUC_UNUSED, + xmlXPathContextPtr ctxt G_GNUC_UNUSED) +{ + virDomainAudioDefPtr def; + VIR_XPATH_NODE_AUTORESTORE(ctxt); + g_autofree char *tmp = NULL; + g_autofree char *type = NULL; + + if (VIR_ALLOC(def) < 0) + return NULL; + ctxt->node = node; + + type = virXMLPropString(node, "type"); + if ((def->type = virDomainAudioTypeTypeFromString(type)) < 0) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unknown audio type '%s'"), type); + goto error; + } + + tmp = virXMLPropString(node, "id"); + if (virStrToLong_ui(tmp, NULL, 10, &def->id) < 0 || + def->id == 0) { + virReportError(VIR_ERR_XML_ERROR, + _("invalid audio 'id' value '%s'"), tmp); + goto error; + } + + switch ((virDomainAudioType) def->type) { + case VIR_DOMAIN_AUDIO_TYPE_OSS: { + xmlNodePtr inputDevNode, outputDevNode; + + inputDevNode = virXPathNode("./input", ctxt); + outputDevNode = virXPathNode("./output", ctxt); + + if (!inputDevNode || !outputDevNode) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("Audio type OSS requires to have <input> " + "and <output> specified")); + goto error; + } + + def->backend.oss.inputDev = virXMLPropString(inputDevNode, "dev"); + def->backend.oss.outputDev = virXMLPropString(outputDevNode, "dev"); + break; + } + + case VIR_DOMAIN_AUDIO_TYPE_LAST: + break; + } + + return def; + + error: + virDomainAudioDefFree(def); + return NULL; +} static virDomainWatchdogDefPtr virDomainWatchdogDefParseXML(virDomainXMLOptionPtr xmlopt, xmlNodePtr node, @@ -17055,6 +17164,10 @@ virDomainDeviceDefParse(const char *xmlStr, ctxt, flags))) return NULL; break; + case VIR_DOMAIN_DEVICE_AUDIO: + if (!(dev->data.audio = virDomainAudioDefParseXML(xmlopt, node, ctxt))) + return NULL; + break; case VIR_DOMAIN_DEVICE_WATCHDOG: if (!(dev->data.watchdog = virDomainWatchdogDefParseXML(xmlopt, node, flags))) @@ -21963,6 +22076,22 @@ virDomainDefParseXML(xmlDocPtr xml, } VIR_FREE(nodes); + /* analysis of the audio devices */ + if ((n = virXPathNodeSet("./devices/audio", ctxt, &nodes)) < 0) + goto error; + if (n && VIR_ALLOC_N(def->audios, n) < 0) + goto error; + for (i = 0; i < n; i++) { + virDomainAudioDefPtr audio = virDomainAudioDefParseXML(xmlopt, + nodes[i], + ctxt); + if (!audio) + goto error; + + def->audios[def->naudios++] = audio; + } + VIR_FREE(nodes); + /* analysis of the video devices */ if ((n = virXPathNodeSet("./devices/video", ctxt, &nodes)) < 0) goto error; @@ -22477,7 +22606,6 @@ virDomainDefParse(const char *xmlStr, virDomainDefPtr def = NULL; int keepBlanksDefault = xmlKeepBlanksDefault(0); xmlNodePtr root; - if (!(xml = virXMLParse(filename, xmlStr, _("(domain_definition)")))) goto cleanup; @@ -24578,6 +24706,7 @@ virDomainDefCheckABIStabilityFlags(virDomainDefPtr src, case VIR_DOMAIN_DEVICE_MEMORY: case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_VSOCK: + case VIR_DOMAIN_DEVICE_AUDIO: break; } #endif @@ -27344,6 +27473,9 @@ virDomainSoundDefFormat(virBufferPtr buf, for (i = 0; i < def->ncodecs; i++) virDomainSoundCodecDefFormat(&childBuf, def->codecs[i]); + if (def->audioId > 0) + virBufferAsprintf(&childBuf, "<audio id='%d'/>\n", def->audioId); + if (virDomainDeviceInfoFormat(&childBuf, &def->info, flags) < 0) return -1; @@ -27360,6 +27492,44 @@ virDomainSoundDefFormat(virBufferPtr buf, } +static int +virDomainAudioDefFormat(virBufferPtr buf, + virDomainAudioDefPtr def) +{ + g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf); + const char *type = virDomainAudioTypeTypeToString(def->type); + + if (!type) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unexpected audio type %d"), def->type); + return -1; + } + + virBufferAsprintf(buf, "<audio id='%d' type='%s'", def->id, type); + + switch (def->type) { + case VIR_DOMAIN_AUDIO_TYPE_OSS: + if (def->backend.oss.inputDev) + virBufferAsprintf(&childBuf, "<input dev='%s'/>\n", + def->backend.oss.inputDev); + if (def->backend.oss.outputDev) + virBufferAsprintf(&childBuf, "<output dev='%s'/>\n", + def->backend.oss.outputDev); + break; + } + + if (virBufferUse(&childBuf)) { + virBufferAddLit(buf, ">\n"); + virBufferAddBuffer(buf, &childBuf); + virBufferAddLit(buf, "</audio>\n"); + } else { + virBufferAddLit(buf, "/>\n"); + } + + return 0; +} + + static int virDomainMemballoonDefFormat(virBufferPtr buf, virDomainMemballoonDefPtr def, @@ -30039,6 +30209,11 @@ virDomainDefFormatInternalSetRootName(virDomainDefPtr def, return -1; } + for (n = 0; n < def->naudios; n++) { + if (virDomainAudioDefFormat(buf, def->audios[n]) < 0) + return -1; + } + for (n = 0; n < def->nvideos; n++) { if (virDomainVideoDefFormat(buf, def->videos[n], flags) < 0) return -1; @@ -31211,6 +31386,9 @@ virDomainDeviceDefCopy(virDomainDeviceDefPtr src, case VIR_DOMAIN_DEVICE_VSOCK: rc = virDomainVsockDefFormat(&buf, src->data.vsock); break; + case VIR_DOMAIN_DEVICE_AUDIO: + rc = virDomainAudioDefFormat(&buf, src->data.audio); + break; case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_SMARTCARD: diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 7b60c28c6d..e0827fee74 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -85,6 +85,7 @@ typedef enum { VIR_DOMAIN_DEVICE_MEMORY, VIR_DOMAIN_DEVICE_IOMMU, VIR_DOMAIN_DEVICE_VSOCK, + VIR_DOMAIN_DEVICE_AUDIO, VIR_DOMAIN_DEVICE_LAST } virDomainDeviceType; @@ -116,6 +117,7 @@ struct _virDomainDeviceDef { virDomainMemoryDefPtr memory; virDomainIOMMUDefPtr iommu; virDomainVsockDefPtr vsock; + virDomainAudioDefPtr audio; } data; }; @@ -1417,6 +1419,27 @@ struct _virDomainSoundDef { size_t ncodecs; virDomainSoundCodecDefPtr *codecs; + + unsigned int audioId; +}; + +typedef enum { + VIR_DOMAIN_AUDIO_TYPE_OSS, + + VIR_DOMAIN_AUDIO_TYPE_LAST +} virDomainAudioType; + +struct _virDomainAudioDef { + int type; + + unsigned int id; + + union { + struct { + char *inputDev; + char *outputDev; + } oss; + } backend; }; typedef enum { @@ -2602,6 +2625,9 @@ struct _virDomainDef { size_t nsounds; virDomainSoundDefPtr *sounds; + size_t naudios; + virDomainAudioDefPtr *audios; + size_t nvideos; virDomainVideoDefPtr *videos; @@ -3032,6 +3058,7 @@ ssize_t virDomainSoundDefFind(const virDomainDef *def, const virDomainSoundDef *sound); void virDomainSoundDefFree(virDomainSoundDefPtr def); virDomainSoundDefPtr virDomainSoundDefRemove(virDomainDefPtr def, size_t idx); +void virDomainAudioDefFree(virDomainAudioDefPtr def); void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def); void virDomainNVRAMDefFree(virDomainNVRAMDefPtr def); void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def); @@ -3591,6 +3618,7 @@ VIR_ENUM_DECL(virDomainChrTcpProtocol); VIR_ENUM_DECL(virDomainChrSpicevmc); VIR_ENUM_DECL(virDomainSoundCodec); VIR_ENUM_DECL(virDomainSoundModel); +VIR_ENUM_DECL(virDomainAudioType); VIR_ENUM_DECL(virDomainKeyWrapCipherName); VIR_ENUM_DECL(virDomainMemballoonModel); VIR_ENUM_DECL(virDomainSmbiosMode); diff --git a/src/conf/virconftypes.h b/src/conf/virconftypes.h index 1c62cde251..9042a2b34f 100644 --- a/src/conf/virconftypes.h +++ b/src/conf/virconftypes.h @@ -309,6 +309,9 @@ typedef virDomainSoundCodecDef *virDomainSoundCodecDefPtr; typedef struct _virDomainSoundDef virDomainSoundDef; typedef virDomainSoundDef *virDomainSoundDefPtr; +typedef struct _virDomainAudioDef virDomainAudioDef; +typedef virDomainAudioDef *virDomainAudioDefPtr; + typedef struct _virDomainTPMDef virDomainTPMDef; typedef virDomainTPMDef *virDomainTPMDefPtr; diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 01c2e710cd..35bf9f08ef 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -224,6 +224,8 @@ virDiskNameToBusDeviceIndex; virDiskNameToIndex; virDomainActualNetDefFree; virDomainActualNetDefValidate; +virDomainAudioTypeTypeFromString; +virDomainAudioTypeTypeToString; virDomainBlockedReasonTypeFromString; virDomainBlockedReasonTypeToString; virDomainBlockIoTuneInfoCopy; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index ec3d4c8d99..40408fdd70 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -523,6 +523,7 @@ qemuBuildVirtioDevStr(virBufferPtr buf, case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_MEMORY: case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_LAST: default: return 0; diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index c27abe2f61..e0d564c437 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -5411,6 +5411,7 @@ qemuDomainDeviceDefPostParse(virDomainDeviceDefPtr dev, case VIR_DOMAIN_DEVICE_RNG: case VIR_DOMAIN_DEVICE_MEMORY: case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_AUDIO: ret = 0; break; diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index d25fb653d3..cbf8ffddd7 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -531,6 +531,7 @@ qemuDomainDeviceSupportZPCI(virDomainDeviceDefPtr device) case VIR_DOMAIN_DEVICE_MEMORY: case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_VSOCK: + case VIR_DOMAIN_DEVICE_AUDIO: break; case VIR_DOMAIN_DEVICE_NONE: @@ -1047,6 +1048,7 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDefPtr dev, case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_GRAPHICS: case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_LAST: case VIR_DOMAIN_DEVICE_NONE: return 0; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 1b2ff1b3da..168f61a9e9 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7960,6 +7960,7 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm, case VIR_DOMAIN_DEVICE_TPM: case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("live attach of device '%s' is not supported"), @@ -8094,6 +8095,7 @@ qemuDomainUpdateDeviceLive(virDomainObjPtr vm, case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_VSOCK: + case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("live update of device '%s' is not supported"), @@ -8313,6 +8315,7 @@ qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef, case VIR_DOMAIN_DEVICE_TPM: case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("persistent attach of device '%s' is not supported"), @@ -8515,6 +8518,7 @@ qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef, case VIR_DOMAIN_DEVICE_TPM: case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("persistent detach of device '%s' is not supported"), @@ -8622,6 +8626,7 @@ qemuDomainUpdateDeviceConfig(virDomainDefPtr vmdef, case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_IOMMU: case VIR_DOMAIN_DEVICE_VSOCK: + case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("persistent update of device '%s' is not supported"), diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 2c6c30ce03..3a780d00af 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -4944,6 +4944,7 @@ qemuDomainRemoveAuditDevice(virDomainObjPtr vm, case VIR_DOMAIN_DEVICE_TPM: case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_LAST: /* libvirt doesn't yet support detaching these devices */ break; @@ -5042,6 +5043,7 @@ qemuDomainRemoveDevice(virQEMUDriverPtr driver, case VIR_DOMAIN_DEVICE_TPM: case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("don't know how to remove a %s device"), @@ -5813,6 +5815,7 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm, case VIR_DOMAIN_DEVICE_TPM: case VIR_DOMAIN_DEVICE_PANIC: case VIR_DOMAIN_DEVICE_IOMMU: + case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_LAST: virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("live detach of device '%s' is not supported"), diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 4cd377c8bc..fe8a64b933 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -4145,6 +4145,7 @@ qemuValidateDomainDeviceDef(const virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_SHMEM: case VIR_DOMAIN_DEVICE_PANIC: + case VIR_DOMAIN_DEVICE_AUDIO: case VIR_DOMAIN_DEVICE_NONE: case VIR_DOMAIN_DEVICE_LAST: break; -- 2.27.0

On Sat, Aug 22, 2020 at 05:11:54PM +0400, Roman Bogorodskiy wrote:
Introduce a new device element "<audio>" which allows to map guest sound device specified using the "<sound>" element to specific audio backend.
Example:
<sound model='ich7'> <audio id='1'/> </sound> <audio id='1' type='oss'> <input dev='/dev/dsp0'/> <output dev='/dev/dsp0'/> </audio>
This block maps to OSS audio backend on the host using /dev/dsp0 device for both input (recording) and output (playback).
OSS is the only backend supported so far.
Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- docs/schemas/domaincommon.rng | 36 +++++++ src/conf/domain_capabilities.c | 4 + src/conf/domain_conf.c | 182 ++++++++++++++++++++++++++++++++- src/conf/domain_conf.h | 28 +++++ src/conf/virconftypes.h | 3 + src/libvirt_private.syms | 2 + src/qemu/qemu_command.c | 1 + src/qemu/qemu_domain.c | 1 + src/qemu/qemu_domain_address.c | 2 + src/qemu/qemu_driver.c | 5 + src/qemu/qemu_hotplug.c | 3 + src/qemu/qemu_validate.c | 1 + 12 files changed, 266 insertions(+), 2 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Allow to map sound playback and recording devices to host devices using "<audio type='oss'/>" OSS audio backend. Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/bhyve/bhyve_command.c | 35 +++++++++++++++++-- src/conf/domain_conf.c | 13 +++++++ src/conf/domain_conf.h | 4 +++ src/libvirt_private.syms | 1 + .../bhyvexml2argv-sound.args | 2 +- .../bhyvexml2argvdata/bhyvexml2argv-sound.xml | 8 ++++- .../bhyvexml2xmlout-sound.xml | 5 +++ 7 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/bhyve/bhyve_command.c b/src/bhyve/bhyve_command.c index 1f42f71347..5289e409fa 100644 --- a/src/bhyve/bhyve_command.c +++ b/src/bhyve/bhyve_command.c @@ -478,9 +478,12 @@ bhyveBuildGraphicsArgStr(const virDomainDef *def, static int bhyveBuildSoundArgStr(const virDomainDef *def G_GNUC_UNUSED, virDomainSoundDefPtr sound, + virDomainAudioDefPtr audio, bhyveConnPtr driver, virCommandPtr cmd) { + g_auto(virBuffer) params = VIR_BUFFER_INITIALIZER; + if (!(bhyveDriverGetBhyveCaps(driver) & BHYVE_CAP_SOUND_HDA)) { /* Currently, bhyve only supports "hda" sound devices, so if it's not supported, sound devices are not supported at all */ @@ -497,9 +500,33 @@ bhyveBuildSoundArgStr(const virDomainDef *def G_GNUC_UNUSED, } virCommandAddArg(cmd, "-s"); - virCommandAddArgFormat(cmd, "%d:%d,hda,play=/dev/dsp0", + + if (audio) { + switch ((virDomainAudioType) audio->type) { + case VIR_DOMAIN_AUDIO_TYPE_OSS: + if (audio->backend.oss.inputDev) + virBufferAsprintf(¶ms, ",play=%s", + audio->backend.oss.inputDev); + + if (audio->backend.oss.outputDev) + virBufferAsprintf(¶ms, ",rec=%s", + audio->backend.oss.outputDev); + + break; + + case VIR_DOMAIN_AUDIO_TYPE_LAST: + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("unsupported audio backend '%s'"), + virDomainAudioTypeTypeToString(audio->type)); + return -1; + } + } + + virCommandAddArgFormat(cmd, "%d:%d,hda%s", sound->info.addr.pci.slot, - sound->info.addr.pci.function); + sound->info.addr.pci.function, + virBufferCurrentContent(¶ms)); + return 0; } @@ -648,7 +675,9 @@ virBhyveProcessBuildBhyveCmd(bhyveConnPtr driver, virDomainDefPtr def, } for (i = 0; i < def->nsounds; i++) { - if (bhyveBuildSoundArgStr(def, def->sounds[i], driver, cmd) < 0) + if (bhyveBuildSoundArgStr(def, def->sounds[i], + virDomainDefFindAudioForSound(def, def->sounds[i]), + driver, cmd) < 0) goto error; } diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 9c05f301dd..921775edc4 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -31497,6 +31497,19 @@ virDomainDefFindDevice(virDomainDefPtr def, } +virDomainAudioDefPtr +virDomainDefFindAudioForSound(virDomainDefPtr def, + virDomainSoundDefPtr sound) +{ + size_t i; + for (i = 0; i < def->naudios; i++) + if (def->audios[i]->id == sound->audioId) + return def->audios[i]; + + return NULL; +} + + char * virDomainObjGetMetadata(virDomainObjPtr vm, int type, diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index e0827fee74..8a0f26f5c0 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -3712,6 +3712,10 @@ int virDomainDefFindDevice(virDomainDefPtr def, virDomainDeviceDefPtr dev, bool reportError); +virDomainAudioDefPtr +virDomainDefFindAudioForSound(virDomainDefPtr def, + virDomainSoundDefPtr sound); + const char *virDomainChrSourceDefGetPath(virDomainChrSourceDefPtr chr); void virDomainChrSourceDefClear(virDomainChrSourceDefPtr def); diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 35bf9f08ef..f950a68179 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -298,6 +298,7 @@ virDomainDefCheckABIStability; virDomainDefCheckABIStabilityFlags; virDomainDefCompatibleDevice; virDomainDefCopy; +virDomainDefFindAudioForSound; virDomainDefFindDevice; virDomainDefFormat; virDomainDefFormatConvertXMLFlags; diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-sound.args b/tests/bhyvexml2argvdata/bhyvexml2argv-sound.args index c242708ff1..05ff4965dd 100644 --- a/tests/bhyvexml2argvdata/bhyvexml2argv-sound.args +++ b/tests/bhyvexml2argvdata/bhyvexml2argv-sound.args @@ -7,4 +7,4 @@ -s 0:0,hostbridge \ -s 2:0,ahci,hd:/tmp/freebsd.img \ -s 3:0,virtio-net,faketapdev,mac=52:54:00:b9:94:02 \ --s 4:0,hda,play=/dev/dsp0 bhyve +-s 4:0,hda,play=/dev/dsp0,rec=/dev/dsp0 bhyve diff --git a/tests/bhyvexml2argvdata/bhyvexml2argv-sound.xml b/tests/bhyvexml2argvdata/bhyvexml2argv-sound.xml index 8e799301fb..831e8670e7 100644 --- a/tests/bhyvexml2argvdata/bhyvexml2argv-sound.xml +++ b/tests/bhyvexml2argvdata/bhyvexml2argv-sound.xml @@ -19,6 +19,12 @@ <source bridge="virbr0"/> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface> - <sound model='ich7'/> + <sound model='ich7'> + <audio id="1"/> + </sound> + <audio type="oss" id="1"> + <input dev="/dev/dsp0"/> + <output dev="/dev/dsp0"/> + </audio> </devices> </domain> diff --git a/tests/bhyvexml2xmloutdata/bhyvexml2xmlout-sound.xml b/tests/bhyvexml2xmloutdata/bhyvexml2xmlout-sound.xml index a64c5da27a..c23892eec9 100644 --- a/tests/bhyvexml2xmloutdata/bhyvexml2xmlout-sound.xml +++ b/tests/bhyvexml2xmloutdata/bhyvexml2xmlout-sound.xml @@ -30,7 +30,12 @@ <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface> <sound model='ich7'> + <audio id='1'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> </sound> + <audio id='1' type='oss'> + <input dev='/dev/dsp0'/> + <output dev='/dev/dsp0'/> + </audio> </devices> </domain> -- 2.27.0

On Sat, Aug 22, 2020 at 05:11:55PM +0400, Roman Bogorodskiy wrote:
Allow to map sound playback and recording devices to host devices using "<audio type='oss'/>" OSS audio backend.
Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- src/bhyve/bhyve_command.c | 35 +++++++++++++++++-- src/conf/domain_conf.c | 13 +++++++ src/conf/domain_conf.h | 4 +++ src/libvirt_private.syms | 1 + .../bhyvexml2argv-sound.args | 2 +- .../bhyvexml2argvdata/bhyvexml2argv-sound.xml | 8 ++++- .../bhyvexml2xmlout-sound.xml | 5 +++ 7 files changed, 63 insertions(+), 5 deletions(-)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|

Document the new <audio> element which allows to specify host audio backend for a guest <sound> device, and update the <sound> element description with the new <audio> sub-element which specifies the other end of the mapping. Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- docs/formatdomain.rst | 49 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 8365fc8bbb..fae138c2dd 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -6572,6 +6572,55 @@ Valid values are: Each ``sound`` element has an optional sub-element ``<address>`` which can tie the device to a particular PCI slot, `documented above <#elementsAddress>`__. +:since:`Since 6.7.0`, a sound device could be optionally mapped to the specific +host audio backend using the ``<audio>`` sub-element: + +:: + + ... + <devices> + <sound model='ich7'> + <audio id='1'> + </sound> + </devices> + ... + +Where ``1`` is an id of the `audio device <#elementsAudio>`__. +This is supported for bhyve only. + +:anchor:`<a id="elementsAudio"/>` + +Audio devices +~~~~~~~~~~~~~ + +A virtual audio device corresponds to a host audio backend that is mapped +to the guest sound device. :since:`Since 6.7.0, bhyve only` + +``type`` + The required ``type`` attribute specifies audio backend type. + Currently, the only supported value is 'oss'. + +``id`` + Integer id of the audio device. Must be greater than 0. + +The 'oss' audio type supports additional configuration: + +:: + + ... + <devices> + <audio type='oss' id='1'> + <input dev='/dev/dsp0'/> + <output dev='/dev/dsp0'/> + </audio> + </devices> + +``input`` + Input device. The required ``dev`` attribute specifies device path. + +``output`` + Output device. The required ``dev`` attribute specifies device path. + :anchor:`<a id="elementsWatchdog"/>` Watchdog device -- 2.27.0

On Sat, Aug 22, 2020 at 05:11:56PM +0400, Roman Bogorodskiy wrote:
Document the new <audio> element which allows to specify host audio backend for a guest <sound> device, and update the <sound> element description with the new <audio> sub-element which specifies the other end of the mapping.
Signed-off-by: Roman Bogorodskiy <bogorodskiy@gmail.com> --- docs/formatdomain.rst | 49 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+)
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Regards, Daniel -- |: https://berrange.com -o- https://www.flickr.com/photos/dberrange :| |: https://libvirt.org -o- https://fstop138.berrange.com :| |: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
participants (2)
-
Daniel P. Berrangé
-
Roman Bogorodskiy