The intention of the Virtual Audio Device is to provide a flexibly-configurable audio device on all Fuchsia systems (even in the absence of audio hardware) for end-to-end testing of the audio subsystem.
The Virtual Audio Device and its drivers are provided by virtual_audio_driver.so and are only included in Fuchsia as part of the “media/tests” component group.
When virtual_audio_driver.so is installed (as part of media/tests), the VirtualAudioBus driver attaches to the /dev/test device node, automatically adding a device for controlling virtual audio devices. This device node is exposed at /dev/test/virtual_audio and is backed by a controller driver, implemented by a singleton of the VirtualAudioControlImpl class. Virtual audio devices are created by interacting with this virtual audio controller, via FIDL (more on the FIDL connection and interfafces below).
The controller can be instructed to create a device configuration, and to create a virtual audio device using this configuration. To Add a device, it creates a VirtualAudioStreamIn or VirtualAudioStreamOut object, which inherits significant functionality from parent class SimpleAudioStream - this parent class is located in Zircon and is used by other audio drivers as well. VirtualAudioStream methods provide very basic support for gain, position notification, and supported formats.
TRACE and SPEW levels of logging are disabled by default. To enable them, use an ‘fx set’ command like the following:
fx set x64 --args=kernel_cmdline_args=[\"driver.virtual_audio.log=+trace\"]
Currently, a separate virtual_audio_service accepts FIDL binding requests and forwards them onward to the driver. In addition to writing test client code that directly generates FIDL calls to these interfaces, the cmdline utility ‘virtual_audio’ interactively exercises these. The driver fully implements the three fuchsia.virtualaudio FIDL interfaces:
The virtualaudio.Control interface is used for top-level activation or deactivation of virtual audio devices. The Disable function deactivates/removes any active virtual audio devices and disallows any subsequent virtual device activations. Conversely, the Enable function once again allows virtual audio devices to be activated/added (although it does not automatically re-activate any previously active devices).
These FIDL interfaces are used to configure and add virtual audio input and output devices. virtualaudio.Config is a subset of the top-level input and output interfaces, and includes methods to statically configure these virtual devices before they are created, specifically to set the following properties:
The virtualaudio.Device interface (another subset of Input and Output) contains methods to make the following dynamic changes:
Once virtual audio input and output devices are created, they can interact with the audio subsystem, including accepting/completing packets and transitioning into/out of playback mode. This functionality is in large part provided by the SimpleAudioStream library.
These features may eventually be added to the virtualaudio driver/service:
Data received by a virtual audio output driver could be sent to:
Data transmitted from a virtual audio input driver could originate from:
Dynamic gain changes (originating externally, e.g. from AVRCP or HID)
Devices with more than 15 supported ranges
Static configuration of the following:
On-the-fly (post-device-creation) configurability of the following:
The validation that AudioCore performs on audio drivers can be validated by a badly-behaved synthetic driver. We should add “bad actor” modes for the virtual driver, to verify our resiliency to common driver errors in which they “fail to honor the driver contract”. These may include failing to provide the notifications promised, etc.
To exercise error handling and other resiliency in audio_core, test clients should be able to specify that a driver emit malformed versions of the following messages (including error result, for those marked with +):
Malformed patterns may include:
audio_cmd_t
enum as message.hdr.cmd
)AUDIO_INVALID_TRANSACTION_ID
as val of message.hdr.transaction_id