HD Audio Emulation For Bhyve

Project description

The bhyve hypervisor does not have any sound card emulation at the moment. This project aims to implement the High Definition Audio Specification which is one of the best performant and supported device in the nowadays operating systems. Some of the reasons to have this device are: support for multiple input and output streams, up to 16 channels per stream, command-response codec communication, DMA channel for each stream and it is interfaced with the PCI bus. The main goal is to have a functional implementation by the end of the summer that will allow playing sounds inside a bhyve virtual machine.

Approach to solving the problem

Architecture Overview

The main hardware blocks of the HD Audio specification are: the HD Audio Controller, the HD Audio Link, the HD Audio Codecs and the Acoustic Devices.

The HD Audio Controller is attached to the system memory via PCI, it contains one or more DMA engines and it implements all the memory mapped registers that comprise the programming interface. This module represents the main work, it will emulate the registers and implement the DMA engine in order to get the streams from the guest memory.

The Audio Link connects physically the Controller with one or more Audio codecs. Although it is a very important component for the hardware specification, in our implementation is just an interface between the Controller and the codecs.

The HD Audio Codec extracts one or more audio streams from the Audio Link and converts them to an output stream through one or more convertors. A convertor converts the digital stream to an analog signal or vice versa. Of course that in our implementation we will not convert the digital data in any analog signal but we will emulate this behavior by playing the digital stream to the /dev/dsp sound backend. The actual data stream will be played by writing to /dev/dsp and the control commands will be emulated with ioctl system calls to /dev/dsp. For example, in order to set the audio playback volume the SNDCTL_DSP_SETPLAYVOL ioctl will be used. A full list of ioctls supported by FreeBSD you can find here [0].

High Level Design

Even though I don’t intend to present a detailed design about the implementation, some operations are clear and concise and I will present them here because it will help me to describe the Proposal Timeline. The main modules which are inspired from the hardware specification and will be implemented are: the Audio Controller, the Audio Codec and Audio Player.

Controller Initialization - the controller is configured as a PCI device, the reset protocol is implemented and the Codec is discovered to the guest audio driver.

Codec Command and Control - the controller implements the mechanisms to send and receive control information between the guest driver and codecs which are the Command Outbound Ring Buffer (CORB) and the Response Input Ring Buffer (RIRB). The CORB and RIRB are some circular buffers located in the guest system memory that are used to pass commands from software to codecs and vice versa. The controller fetches these commands using DMA. The Codec will emulate these commands (verbs) which are documented in the HDA datasheet specification [1].

Stream Management - A stream is a virtual connection between a system memory buffer and the codec playing that data which is driven by a single DMA channel. The samples are collected in the guest memory into buffers which describe the Cyclic Buffer. The Buffer Descriptor List for the stream describes the starting and the length of each buffer to be played. The controller implements the mechanism to receive this data from the guest system memory using DMA. The codec will play the samples inside the buffers by writing them to the /dev/dsp.

Audio Player - its role will be to provide the codec methods to play samples and change the stream parameters using the /dev/dsp sound backend. It should be a public module inside bhyve since others sound emulations could use it in future.

Deliverables

At the end of the summer I will deliver the Audio Controller and Audio Codec modules emulating the High Definition Audio specification and the Audio Player module.

Milestones

2 weeks

Implement the Controller initialization, the Codec discovery, design and prepare the data structures.

2 weeks

Design and implement the CORB and RIRB mechanisms in the Controller in order to get the control commands from the guest audio driver.

1 week

Emulate the control commands (verbs) from the guest audio driver.

27 June - Mid Term Evaluation

Deliver the code implemented in the first 5 weeks. The emulator will initialize the controller as a PCI device and will discover the Audio Codec to the guest audio driver. The Audio codec will emulate a subset of the control commands.

1 week

Prepare and emulate the DMA engines to get the buffers from the Cyclic Buffer inside the guest system memory.

2 weeks

Extract the audio samples for each channel from the data stream and implement a mechanism to prepare them to be played by the Audio Player.

2 weeks

Implement the Audio Player that will play samples and change the stream parameters using the /dev/dsp sound backend.

2 weeks

Test the HD Audio module implementation, fix the possible bugs and prepare the deliverables and the final evaluation.

Final Results

Manage to implement the HDA emulation being able to play and records audio streams from a bhyve virtual machine. As planned, I developed 3 modules that work together in order to emulate the HDA stack:

In order to use the HDA emulation in bhyve one must add it in the configuration line:

where rec=/dev/dsp[%d] provides the name of the audio device responsible with the recording from the FreeBSD host, and play=/dev/dsp[%d] provides the name of the audio device responsible with the playing to the FreeBSD host.

For example, just to have a single output audio stream one can add the below line:

At the moment, the HDA implementation supports 16bit bit depth and sample rates in the 16.0 - 192.0kHz range.

You can get below the patch for the HDA emulation:

Apply this patch to bhyve directory as shown below:

Test Plan

I have tested the input and output streams with 3 different guest virtual machines:

In Linux I have used the aplay and arecord tools from the ALSA package in order to play and record the audio streams and mpg123 in order to play some mp3 files. In Windows I have used the Windows Media Player and Sound Recorder in order to play and record the audio streams.

Note: When play with Windows, if the sounds clarity is not good enough (there is some noise) you might need to use 'sysctl -w hw.snd.latency=0' on the FreeBSD host. The reasoning is Windows uses smaller fragments in the Cyclic Buffer in order to achieve smaller latency. To cope with it we use hw.snd.latency=0.

I have tested all supported sample rates. In Windows go to: Manage audio devices -> Playback -> Right click on the High Definition Audio Device -> Properties -> Advanced -> Choose any sample rate -> Test.

Other testing scenarios:

TODO

One feature is not implemented yet is the Volumes Control. So you won't be able to control the volumes from the guest virtual machine. Anyway with the Linux and Windows guests you can still change the volumes because they can adjust the level of the volumes in software. For example in Linux, by changing the level of the Mixer PCM channel it will affect the volume of your actual stream. Similar in windows, you can change the volume per application.

The Code

SummerOfCode2016/HDAudioEmulationForBhyve (last edited 2017-09-18 13:56:01 by KubilayKocak)