| // 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; |
| |
| const MAX_UI_STRING_SIZE uint32 = 256; |
| |
| // 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. |
| @for_deprecated_c_bindings |
| protocol Forwarder { |
| SendControl(resource struct { |
| control server_end:Control; |
| }); |
| SendInput(resource struct { |
| input server_end:Input; |
| }); |
| SendOutput(resource struct { |
| output server_end: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() -> (struct { |
| num_input_devices uint32; |
| num_output_devices uint32; |
| }); |
| }; |
| |
| // |
| // 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() -> (struct { |
| frames_per_second uint32; |
| sample_format uint32; |
| num_channels uint32; |
| external_delay zx.duration; |
| }); |
| |
| /// Notify all subscribed listeners when the above format is set or changed. |
| -> OnSetFormat(struct { |
| frames_per_second uint32; |
| sample_format uint32; |
| num_channels uint32; |
| external_delay zx.duration; |
| }); |
| |
| /// 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() -> (struct { |
| current_mute bool; |
| current_agc bool; |
| current_gain_db float32; |
| }); |
| |
| /// Notify all subscribed listeners when the above gain is set or changed. |
| -> OnSetGain(struct { |
| current_mute bool; |
| current_agc bool; |
| current_gain_db float32; |
| }); |
| |
| /// 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() -> (resource struct { |
| ring_buffer zx.handle:VMO; |
| num_ring_buffer_frames uint32; |
| notifications_per_ring uint32; |
| }); |
| |
| /// Notify all subscribed listeners when the above buffer has been created. |
| -> OnBufferCreated(resource struct { |
| ring_buffer zx.handle:VMO; |
| num_ring_buffer_frames uint32; |
| notifications_per_ring uint32; |
| }); |
| |
| /// 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(struct { |
| notifications_per_ring uint32; |
| }); |
| |
| /// 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(struct { |
| start_time zx.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(struct { |
| stop_time zx.time; |
| ring_position uint32; |
| }); |
| |
| /// 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() -> (struct { |
| monotonic_time zx.time; |
| ring_position uint32; |
| }); |
| |
| /// 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(struct { |
| monotonic_time zx.time; |
| ring_position uint32; |
| }); |
| |
| /// 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(struct { |
| plug_change_time zx.time; |
| plugged bool; |
| }); |
| |
| /// Immediately change the virtual device's clock rate, as expressed in the |
| /// timing and content of position notifications the driver emits. |
| /// 'ppm_monotonic' cannot exceed [-1000,+1000]. Each rate change in rate is |
| /// standalone; i.e. successive rate changes are not cumulative. |
| AdjustClockRate(struct { |
| ppm_from_monotonic int32; |
| }); |
| }; |
| |
| /// 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(struct { |
| device_name string; |
| }); |
| |
| /// Set the virtual audio device's manufacturer name. Must be called before |
| /// `Add()` or after `Remove()`. After device activation, the driver returns |
| /// this value in response to an `AUDIO_STREAM_CMD_GET_STRING` command of ID |
| /// `AUDIO_STREAM_STR_ID_MANUFACTURER`. This is exposed to clients via the |
| /// `fuchsia.media.AudioDeviceEnumerator` protocol, in an `AudioDeviceInfo` |
| /// struct returned from `GetDevices()` and the `->OnDeviceAdded()` event. |
| SetManufacturer(struct { |
| manufacturer_name string:MAX_UI_STRING_SIZE; |
| }); |
| |
| /// Set the virtual audio device's product name. This must be called before |
| /// `Add()` or after `Remove()`. After device activation, the driver returns |
| /// this value in response to an `AUDIO_STREAM_CMD_GET_STRING` command of ID |
| /// `AUDIO_STREAM_STR_ID_PRODUCT`. This name is exposed to clients via the |
| /// `fuchsia.media.AudioDeviceEnumerator` protocol, in an `AudioDeviceInfo` |
| /// struct returned from `GetDevices()` and the `->OnDeviceAdded()` event. |
| SetProduct(struct { |
| product_name string:MAX_UI_STRING_SIZE; |
| }); |
| |
| /// 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(struct { |
| unique_id array<uint8, 16>; |
| }); |
| |
| /// 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(struct { |
| sample_format_flags uint32; |
| min_frame_rate uint32; |
| max_frame_rate uint32; |
| min_channels uint8; |
| max_channels uint8; |
| rate_family_flags uint16; |
| }); |
| |
| /// 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(); |
| |
| @transitional |
| SetClockDomain(struct { |
| clock_domain int32; |
| }); |
| |
| /// Set properties for this virtual device's clock. These include the clock |
| /// domain and the initial rate difference (in ppm) between its clock and |
| /// the local monotonic clock. The clock domain is an int32 provided by the |
| /// clock tree to an audio driver; special values for CLOCK_DOMAIN_MONOTONIC |
| /// [0], and CLOCK_DOMAIN_EXTERNAL [-1] (not locally controllable) are |
| /// defined in fuchsia.hardware.audio/stream.fidl. Other than -1, any |
| /// negative value for clock_domain is invalid and will be ignored. A |
| /// non-zero value for 'initial_rate_adjustment_ppm' is only valid (and will |
| /// only be accepted) if the clock_domain is NOT equal to 0. This method |
| /// must be called before calling `Add()`, or after `Remove()`. Once the |
| /// device is activated, the clock_domain value is returned by the driver in |
| /// response to an `AUDIO_STREAM_CMD_GET_CLOCK_DOMAIN` command, and the |
| /// clock rate is expressed in the timing, and values, of position |
| /// notifications. Neither clock domain nor position notifications are |
| /// directly exposed to clients by public APIs, but these are both used in |
| /// AudioCore's device (or more accurately, domain) clock recovery. |
| SetClockProperties(struct { |
| clock_domain int32; |
| initial_rate_adjustment_ppm int32; |
| }); |
| |
| /// 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(struct { |
| fifo_depth_bytes uint32; |
| }); |
| |
| /// 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(struct { |
| external_delay zx.duration; |
| }); |
| |
| /// 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(struct { |
| min_frames uint32; |
| max_frames uint32; |
| modulo_frames uint32; |
| }); |
| |
| /// 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(struct { |
| min_gain_db float32; |
| max_gain_db float32; |
| gain_step_db float32; |
| current_gain_db float32; |
| can_mute bool; |
| current_mute bool; |
| can_agc bool; |
| current_agc bool; |
| }); |
| |
| /// 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(struct { |
| plug_change_time zx.time; |
| plugged bool; |
| hardwired bool; |
| can_notify bool; |
| }); |
| |
| /// 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(); |
| }; |