| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| library fuchsia.virtualaudio; |
| |
| using zx; |
| |
| // fuchsia.virtualaudio.Forwarder |
| // |
| |
| /// Using this Simple Layout (C-bound) protocol, an intermediary (such as the |
| /// virtual audio service) forwards FIDL protocol requests to the virtual audio |
| /// driver, which enables clients to use more full-featured (C++ based) bindings |
| /// with this driver -- specifically the Control, Input and Output protocols. |
| [Layout = "Simple"] |
| protocol Forwarder { |
| SendControl(request<Control> control); |
| SendInput(request<Input> input); |
| SendOutput(request<Output> output); |
| }; |
| |
| // fuchsia.virtualaudio.Control |
| // |
| |
| /// This protocol provides the caller a high-level ON/OFF switch for overall |
| /// virtual audio functionality at the system level. When virtualaudio is |
| /// disabled, device configurations can be created and changed, but no devices |
| /// can be added. When virtualaudio is enabled, device configurations can again |
| /// be converted into devices by calling `Add()`. |
| [Discoverable] |
| protocol Control { |
| /// Allow inputs and outputs to be activated, but do not automatically |
| /// reactivate those previously deactivated by `Disable()`. Does not affect |
| /// existing Configs. By default, virtualaudio is enabled on system startup. |
| /// This method's callback can be used as a mechanism to synchronize with |
| /// other asynchronous in-flight virtualaudio FIDL operations. |
| Enable() -> (); |
| |
| /// Deactivate all active inputs/outputs; disallow subsequent activations. |
| /// This method's callback can be used as a mechanism to synchronize with |
| /// other asynchronous in-flight virtualaudio FIDL operations. |
| Disable() -> (); |
| |
| /// Return the number of active input and output virtual devices. |
| /// This method's callback can be used as a mechanism to synchronize with |
| /// other asynchronous in-flight virtualaudio FIDL operations. |
| GetNumDevices() -> (uint32 num_input_devices, |
| uint32 num_output_devices); |
| }; |
| |
| // |
| // The Input and Output protocols closely correspond to the capabilities |
| // exposed by the Audio Driver Streaming Interface, fully documented at |
| // driver-interfaces/audio.md and declared at device/audio.h. |
| // |
| |
| // fuchsia.virtualaudio.Input |
| // |
| /// This protocol represents an active virtual audio input device. It inherits |
| /// the parent protocols Device and Configuration. This protocol, as well as the |
| /// contents of Device, represent actions that can be taken by an active input |
| /// device -- actions that should be immediately detected and reacted upon by |
| /// the audio subsystem. |
| [Discoverable] |
| protocol Input { |
| compose Device; |
| |
| // TODO(mpuryear): `SetCaptureSignal()` -- indicate what to "capture". |
| // E.g. sinusoid, constant, square, ramp, saw, noise. Can differ by channel. |
| |
| // TODO(mpuryear): `PairWithOutput()` -- client passes an output (server) |
| // binding; input device returns as captured data the streamed output data. |
| }; |
| |
| // fuchsia.virtualaudio.Output |
| // |
| |
| /// This protocol represents an active virtual audio output device. It inherits |
| /// the parent protocols Device and Configuration. This protocol, as well as the |
| /// contents of Device, represent actions that can be taken by an active output |
| /// device -- actions that should be immediately detected and reacted upon by |
| /// the audio subsystem. |
| [Discoverable] |
| protocol Output { |
| compose Device; |
| |
| // TODO(mpuryear): any render-specific configuration or runtime triggers. |
| }; |
| |
| /// This protocol represents the base functionality of active Input and Output |
| /// audio devices -- methods that are common to both protocols. This protocol, |
| /// as well as the contents of Output and Input, represent actions that can be |
| /// taken by an active device -- actions that should be immediately detected and |
| /// reacted upon by the audio subsystem. |
| protocol Device { |
| compose Configuration; |
| |
| /// Activate (`DdkAdd`) the virtual audio device as currently configured. A |
| /// device node will be published and detected by the AudioDeviceManager, |
| /// and a driver for the virtual device will be loaded and queried. Device |
| /// arrivals are exposed to clients by the |
| /// `fuchsia.media.AudioDeviceEnumerator` protocol, in `GetDevices()` and |
| /// the `->OnDeviceAdded()` event. |
| Add(); |
| |
| /// Deactivate (`DdkRemove`) the active virtual audio device, but retain its |
| /// configuration for future activation. The driver for the virtual device |
| /// will be unloaded, and the device node closed. Device removals are |
| /// exposed to clients by `fuchsia.media.AudioDeviceEnumerator`, in |
| /// `GetDevices()` and `->OnDeviceRemoved()`. |
| Remove(); |
| |
| /// Return the format selected by the client, when that client issued an |
| /// `AUDIO_STREAM_CMD_SET_FORMAT` command. This can only occur after a |
| /// device has been added, and is only allowed to occur before the device's |
| /// ring buffer has been returned (i.e., before an |
| /// `AUDIO_RB_CMD_GET_BUFFER` command). |
| GetFormat() -> (uint32 frames_per_second, uint32 sample_format, |
| uint32 num_channels, zx.duration external_delay); |
| |
| /// Notify all subscribed listeners when the above format is set or changed. |
| -> OnSetFormat(uint32 frames_per_second, uint32 sample_format, |
| uint32 num_channels, zx.duration external_delay); |
| |
| /// Return the current gain state for this device. After a device has been |
| /// added, a client can call this at any time -- even before the ring buffer |
| /// has been established, or before the format has been set. |
| GetGain() -> (bool current_mute, bool current_agc, float32 current_gain_db); |
| |
| /// Notify all subscribed listeners when the above gain is set or changed. |
| -> OnSetGain(bool current_mute, bool current_agc, float32 current_gain_db); |
| |
| /// Return details about the ring buffer that was established in response |
| /// to a client `AUDIO_RB_CMD_GET_BUFFER` command. This will only occur |
| /// after the client sets the format and retrieves other driver information. |
| GetBuffer() -> (handle<vmo> ring_buffer, uint32 num_ring_buffer_frames, |
| uint32 notifications_per_ring); |
| |
| /// Notify all subscribed listeners when the above buffer has been created. |
| -> OnBufferCreated(handle<vmo> ring_buffer, uint32 num_ring_buffer_frames, |
| uint32 notifications_per_ring); |
| |
| /// Override the position notification frequency set by AudioCore for this |
| /// stream, with the given value. Although this method can be called at any |
| /// time (including before this Input|Output is added, or after it is |
| /// started), logically it makes most sense to call this immediately after |
| /// receiving details about the just-created ring buffer, via `GetBuffer` or |
| /// the `->OnBufferCreated` event. |
| SetNotificationFrequency(uint32 notifications_per_ring); |
| |
| /// Notify all subscribed listeners when the device is commanded to Start |
| /// streaming. This can only occur after a device is fully configured |
| /// (format is set; ring buffer is established and fetched). |
| -> OnStart(zx.time start_time); |
| |
| /// Notify all subscribed listeners when the device is commanded to Stop |
| /// streaming. This can only occur when the device is already Started. Stop |
| /// returns the device to a fully-configured state. Upon this command, the |
| /// already-set format and ring buffer are retained without change, but |
| /// position will re-begin at 0, if the device is again Started. |
| -> OnStop(zx.time stop_time, uint32 ring_position); |
| |
| /// Return the current position (in bytes) within the ring buffer, along |
| /// with the time (per MONOTONIC clock) that corresponds with that position. |
| /// This can only be called after the ring buffer is established. If the |
| /// device has not yet Started streaming, then zero will always be returned. |
| GetPosition() -> (zx.time monotonic_time, uint32 ring_position); |
| |
| /// Notify all subscribed listeners, when any `AUDIO_RB_POSITION_NOTIFY` |
| /// position notification is issued by the driver. The frequency of these |
| /// per-stream notifications is set by AudioCore, reported to VAD clients |
| /// via `GetBuffer` or the `->OnBufferCreated` event. VirtualAudioDevice |
| /// clients can enable an alternate notification frequency for a given |
| /// stream by calling `SetNotificationFrequency`. As with a direct call to |
| /// `GetPosition`, the returned parameters are the current position (in |
| /// bytes) in the ring buffer, as well as the time (per MONOTONIC clock) |
| /// that corresponds with that ring buffer position. |
| -> OnPositionNotify(zx.time monotonic_time, uint32 ring_position); |
| |
| /// Hot-plug or hot-unplug an active virtual device, at the specified time. |
| /// For devices marked as capable of asynchronously notifying the system of |
| /// plug changes, the driver will now send the values using |
| /// `AUDIO_STREAM_PLUG_DETECT_NOTIFY`. Else, values will be reflected when |
| /// the driver is next sent an `AUDIO_STREAM_CMD_PLUG_DETECT` command. This |
| /// information is used by the system when determining which device is |
| /// default. This, in turn, is exposed to clients by the |
| /// `fuchsia.media.AudioDeviceEnumerator` protocol: in `GetDevices()`, |
| /// `GetDefaultInputDevice()`/`GetDefaultOutputDevice()` and the |
| /// `->OnDefaultDeviceChanged()` event. |
| ChangePlugState(zx.time plug_change_time, bool plugged); |
| |
| // TODO(mpuryear): `TweakClockRate(uint64 numerator, uint64 denominator)` -- |
| // emulating a device clock, advance position at given ratio of MONOTONIC. |
| }; |
| |
| /// This protocol is conceptually a base protocol to Device. It exposes the |
| /// methods used to specify the properties of a virtual audio device (its |
| /// configuration), before the virtual device is instantiated by the call to |
| /// `Add()`. Although the non-Add methods on this protocol can be called after |
| /// calling `Add()` (i.e., after Configuration has been converted into active |
| /// Device), this only changes how future Devices will be created; it has no |
| /// effect on already-created Devices. |
| protocol Configuration { |
| /// Set the virtual audio device's name. This corresponds to the value |
| /// associated with the device node for this virtual device. This must be |
| /// called before calling `Add()`, or after `Remove()`. |
| SetDeviceName(string device_name); |
| |
| /// Set the virtual audio device's manufacturer name. This must be called |
| /// before calling `Add()`, or after `Remove()`. Once a device is activated, |
| /// this value is returned by the driver in response to an |
| /// `AUDIO_STREAM_CMD_GET_STRING` command of string ID |
| /// `AUDIO_STREAM_STR_ID_MANUFACTURER`. This information is exposed to |
| /// clients by the `fuchsia.media.AudioDeviceEnumerator` protocol: returned |
| /// in an `AudioDeviceInfo` struct by `GetDevices()` and the |
| /// `->OnDeviceAdded()` event. |
| SetManufacturer(string manufacturer_name); |
| |
| /// Set the virtual audio device's product name. This must be called before |
| /// calling `Add()`, or after `Remove()`. Once the device is activated, this |
| /// value is returned by the driver in response to an |
| /// `AUDIO_STREAM_CMD_GET_STRING` command of string ID |
| /// `AUDIO_STREAM_STR_ID_PRODUCT`. This information is exposed to clients by |
| /// the `fuchsia.media.AudioDeviceEnumerator` protocol: returned in an |
| /// `AudioDeviceInfo` struct by `GetDevices()` and the `->OnDeviceAdded()` |
| /// event. |
| SetProduct(string product_name); |
| |
| /// Set the virtual audio device's unique ID, a 16-character string. This |
| /// must be called before calling `Add()`, or after `Remove()`. Once the |
| /// device is activated, this value is returned by the driver in response |
| /// to an `AUDIO_STREAM_CMD_GET_UNIQUE_ID` command. This value is exposed |
| /// to clients by the `fuchsia.media.AudioDeviceEnumerator` protocol: |
| /// returned in an `AudioDeviceInfo` struct by `GetDevices()` or |
| /// `->OnDeviceAdded()`. |
| SetUniqueId(array<uint8>:16 unique_id); |
| |
| /// Add a supported format range for this audio device. This must be called |
| /// before calling `Add()`, or after `Remove()`. Once the device is |
| /// activated, format ranges are returned by the driver in response to an |
| /// `AUDIO_STREAM_CMD_GET_FORMATS` command. sample_format_flags is of type |
| /// audio_sample_format_t, and rate_family_flags is a bit field of possible |
| /// constants beginning with `ASF_RANGE_FLAG_FPS_`. See audio.h for details. |
| AddFormatRange(uint32 sample_format_flags, uint32 min_frame_rate, |
| uint32 max_frame_rate, uint8 min_channels, |
| uint8 max_channels, uint16 rate_family_flags); |
| |
| /// Remove the minimal format range that is added by default to all |
| /// configurations. As with `AddFormatRange()`, this method must be called |
| /// before calling `Add()`, or after `Remove()`. |
| ClearFormatRanges(); |
| |
| /// Set the virtual audio device's clock domain, an int32 provided by the |
| /// clock tree, with special values 0 for the MONOTONIC clock domain and |
| /// -1 for EXTERNAL domains that are not controllable locally. This method |
| /// must be called before calling `Add()`, or after `Remove()`. Once the |
| /// device is activated, this value is returned by the driver in response |
| /// to an `AUDIO_STREAM_CMD_GET_CLOCK_DOMAIN` command. This is not exposed |
| /// to clients by public APIs but is used in AudioCore's clock recovery for |
| /// this device (or more accurately, for this domain). |
| SetClockDomain(int32 clock_domain); |
| |
| /// Set the virtual audio device's fifo depth, in bytes. This must be called |
| /// before calling `Add()`, or after `Remove()`. Once the device is |
| /// activated, the depth of its FIFO is returned by the driver in response |
| /// to an `AUDIO_RB_CMD_GET_FIFO_DEPTH` command on the ring buffer channel. |
| SetFifoDepth(uint32 fifo_depth_bytes); |
| |
| /// Set the virtual audio device's external delay, in nanoseconds. This must |
| /// be called before calling `Add()`, or after `Remove()`. Once the device |
| /// is activated, this value is returned by the driver in response to an |
| /// `AUDIO_STREAM_CMD_SET_FORMAT` command. |
| // |
| // Treating this as a static property is inadequate, considering that the |
| // delay is intended to be calculated from the format that was just set. |
| SetExternalDelay(zx.duration external_delay); |
| |
| /// Set restrictions for the device ring buffer. This must be called before |
| /// calling `Add()`, or after `Remove()`. Once the device is activated, the |
| /// ring buffer and its size are returned by the driver in response to an |
| /// `AUDIO_RB_CMD_GET_BUFFER` command on the ring buffer channel. |
| /// Note: both min_frames and max_frames must be multiples of modulo_frames. |
| SetRingBufferRestrictions(uint32 min_frames, uint32 max_frames, |
| uint32 modulo_frames); |
| |
| /// Set gain properties for this virtual device. This must be called before |
| /// calling `Add()`, or after `Remove()`. Once the device is activated, gain |
| /// information is returned by the driver in an |
| /// `audio_stream_cmd_get_gain_resp` struct, in response to an |
| /// `AUDIO_STREAM_CMD_GET_GAIN` command. This information is exposed to |
| /// clients by the `fuchsia.media.AudioDeviceEnumerator` protocol: returned |
| /// in an `AudioGainInfo` struct by `GetDeviceGain()` and the |
| /// `->OnDeviceGainChanged()` event. |
| SetGainProperties(float32 min_gain_db, float32 max_gain_db, |
| float32 gain_step_db, float32 current_gain_db, |
| bool can_mute, bool current_mute, |
| bool can_agc, bool current_agc); |
| |
| /// Set plug properties for this virtual device. This must be called before |
| /// calling `Add()`, or after `Remove()`. Once the device is activated, plug |
| /// information is returned by the driver in response to an |
| /// `AUDIO_STREAM_CMD_PLUG_DETECT` command. This information is used by the |
| /// system when determining which device is default. This in turn is exposed |
| /// to clients by the `fuchsia.media.AudioDeviceEnumerator` protocol: in |
| /// `GetDevices()`, `GetDefaultInputDevice()`/`GetDefaultOutputDevice()` and |
| /// the `->OnDefaultDeviceChanged()` event. |
| SetPlugProperties(zx.time plug_change_time, bool plugged, bool hardwired, |
| bool can_notify); |
| |
| /// Return a configuration to its default settings. This call has no effect |
| /// on active devices. In other words, it must be called before calling |
| /// `Add()`, or after `Remove()`. |
| ResetConfiguration(); |
| }; |