| // Copyright 2022 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.audio.device; |
| |
| using fuchsia.audio; |
| using fuchsia.hardware.audio.signalprocessing; |
| using zx; |
| |
| /// Parameters specified by a caller when creating a ring buffer. |
| type RingBufferOptions = table { |
| /// The format (sample format, channelization, frame rate) of the ring |
| /// buffer to be created. |
| /// |
| /// Required. |
| // |
| // TODO(fxbug.dev/105130): Use a union, to accommodate non-PCM |
| 1: format fuchsia.audio.Format; |
| |
| /// The minimum number of bytes required in the ring buffer. The actual |
| /// buffer may be larger, as required by the encoding, driver, device or OS. |
| /// |
| /// Required. |
| 2: ring_buffer_min_bytes uint32; |
| }; |
| |
| /// Information about the ring buffer or associated audio stream. |
| type RingBufferProperties = table { |
| /// The number of bits (starting with the most significant) that are valid, |
| /// within each individual sample. This may be be smaller than the actual |
| /// sample size, in the case of an input ring buffer fed by an 18-bit ADC |
| /// for example. Any additional bits of precision should be ignored. |
| /// |
| /// Required. |
| // |
| // TODO(fxbug.dev/105130): Adopt `fuchsia.mediastreams.AudioEncoding`, and |
| // change to the following comment: |
| // Optional (Required for PCM encodings, including 'packed' formats). |
| 1: valid_bits_per_sample uint8; |
| |
| /// The maximum delay until disabled channels become fully operational, |
| /// after calling `SetActiveChannels`. This is the worst-case duration when |
| /// reenabling all channels. The value must be non-negative. |
| /// |
| /// Required. |
| 2: turn_on_delay zx.Duration; |
| }; |
| |
| type DelayInfo = table { |
| /// The driver's best estimate of the delay internal to the hardware it abstracts for |
| /// the chosen format. This duration must be non-negative. |
| /// |
| /// Required. |
| 1: internal_delay zx.Duration; |
| |
| /// The amount of pipeline delay beyond the interconnect (subsequent to the |
| /// DMA "read" position for output devices, or prior to the DMA "write" |
| /// position for input devices). This duration must be non-negative. |
| /// |
| /// Required. |
| 2: external_delay zx.Duration; |
| }; |
| |
| /// A `ControlCreator` interface creates `Control` instances. Each `Control` binds |
| /// to a single device. A device can only be bound to one `Control` at any time. |
| @discoverable |
| closed protocol ControlCreator { |
| // Create a `Control` for the specified device. |
| strict Create(resource table { |
| /// The token id for the device to be controlled. |
| /// |
| /// Required. |
| 1: token_id TokenId; |
| |
| /// The server_end of the `Control` to be created. |
| /// |
| /// Required. |
| 2: control_server server_end:Control; |
| }) -> (table {}) error ControlCreatorError; |
| }; |
| |
| /// Errors returned by `ControlCreator/Create`. |
| type ControlCreatorError = flexible enum { |
| /// The required `token_id` is missing. |
| INVALID_TOKEN_ID = 1; |
| |
| /// The required `control_server` is missing. |
| INVALID_CONTROL = 2; |
| |
| /// No device with `token_id` was found. Either this token has never been |
| /// used, or the device with `token_id` has been removed. |
| DEVICE_NOT_FOUND = 3; |
| |
| /// The device with `token_id` encountered an error and cannot be observed. |
| DEVICE_ERROR = 4; |
| |
| /// A `Control` associated with `token_id` already exists. This device is |
| /// already being actively controlled. |
| DEVICE_ALREADY_ALLOCATED = 5; |
| }; |
| |
| /// A `Control` instance is used to change the settings or state of an audio |
| /// device. It also creates the ring buffer used to pass audio data between |
| /// client and device. Each `Control` is associated with an initialized audio |
| /// device; conversely each device is associated with either zero or one |
| /// `Control` at any time. |
| closed protocol Control { |
| /// Change the processing topology (via `SetTopology`) or the state of a |
| /// single processing node (via `SetElementState`). |
| compose fuchsia.hardware.audio.signalprocessing.SignalProcessing; |
| |
| /// Change the device's overall gain state. |
| // |
| // TODO(fxbug.dev/102027): Remove legacy gain aspects once driver API does. |
| // Going forward, gain will be handled by `SignalProcessing`. |
| strict SetGain(table { |
| /// The gain state to be set. |
| /// |
| /// Required. |
| 1: target_state GainState; |
| }) -> (table {}) error ControlSetGainError; |
| |
| /// Retrieve the subset of formats that are possible, as the device is |
| /// currently configured. |
| strict GetCurrentlyPermittedFormats() -> (table { |
| /// Possible formats, as configured. Must contain at least one entry. |
| 1: permitted_formats vector<PcmFormatSet>:MAX_COUNT_FORMATS; |
| }) error ControlGetCurrentlyPermittedFormatsError; |
| |
| /// Create the ring buffer used to pass audio to/from this device. |
| strict CreateRingBuffer(resource table { |
| /// Additional requirements about the actual ring buffer being created. |
| /// |
| /// Required. |
| 1: options RingBufferOptions; |
| |
| /// The server_end of the `RingBuffer` to be created. |
| /// |
| /// Required. |
| 2: ring_buffer_server server_end:RingBuffer; |
| }) -> (resource table { |
| /// Properties about the ring buffer and active audio stream as created. |
| 1: properties RingBufferProperties; |
| |
| /// An object that represents the audio stream and ring memory itself. |
| /// Note: ring-buffer VMO memory ranges must be cache-invalidated before |
| /// each read, and cache-flushed after each write. |
| 2: ring_buffer fuchsia.audio.RingBuffer; |
| }) error ControlCreateRingBufferError; |
| }; |
| |
| /// Errors returned by `Control/SetGain`. |
| type ControlSetGainError = flexible enum { |
| /// The required `target_state` is missing. |
| INVALID_GAIN_STATE = 1; |
| |
| /// This device has encountered an error and can no longer be controlled. |
| DEVICE_ERROR = 2; |
| |
| /// The required `target_state.gain_db` is missing. |
| INVALID_GAIN_DB = 3; |
| |
| /// The specified gain is outside the device's allowed range. |
| GAIN_OUT_OF_RANGE = 4; |
| |
| /// MUTE is requested, but the device has no MUTE control. |
| MUTE_UNAVAILABLE = 5; |
| |
| /// Enabling AGC is requested, but the device has no AGC. |
| AGC_UNAVAILABLE = 6; |
| }; |
| |
| /// Errors returned by `Control/GetCurrentlyPermittedFormats`. |
| type ControlGetCurrentlyPermittedFormatsError = flexible enum { |
| /// This device has encountered an error and can no longer be queried. |
| DEVICE_ERROR = 1; |
| }; |
| |
| /// Errors returned by `Control/CreateRingBuffer`. |
| type ControlCreateRingBufferError = flexible enum { |
| /// The required `options` is missing. |
| INVALID_OPTIONS = 1; |
| |
| /// The required `options.format` is missing. |
| INVALID_FORMAT = 2; |
| |
| /// The required `options.ring_buffer_min_bytes` is missing. |
| INVALID_MIN_BYTES = 3; |
| |
| /// The required `ring_buffer_server` is missing. |
| INVALID_RING_BUFFER = 4; |
| |
| /// This device has encountered an error and can no longer be controlled. |
| DEVICE_ERROR = 5; |
| |
| /// The device does not support the specified format. |
| FORMAT_MISMATCH = 6; |
| |
| /// The device cannot create a ring buffer with the specified options. |
| BAD_RING_BUFFER_OPTION = 7; |
| |
| /// An active `RingBuffer` instance already exists for this `Control`. |
| RING_BUFFER_ALREADY_ALLOCATED = 8; |
| }; |
| |
| /// A `RingBuffer` instance controls data flow for the associated audio stream. |
| closed protocol RingBuffer { |
| /// Request that specific individual channels be powered down/up, if the |
| /// device supports this. This is intended for idle power conservation. |
| /// |
| /// Channels are specified by bitmask; the least significant bit corresponds |
| /// to channel 0. Each bit not set indicates that the channel can be |
| /// deactivated. `SetActiveChannels` does not change how a ring buffer |
| /// responds to `Start`/`Stop`, specifically with regards to position. |
| /// |
| /// Devices are not required to obey `SetActiveChannels`. For example, they |
| /// are not required to zero-out an input stream's inactive channels, and |
| /// data written to inactive channels of an output stream's ring buffer may |
| /// still be played. |
| /// |
| /// If not called, then by default all channels will be active. |
| strict SetActiveChannels(table { |
| /// The channels to be activated (all others should be deactivated). No |
| /// bit should be set above the `channel_count` specified in the ring |
| /// buffer format (e.g. for a four-channel stream, `channel_bitmask` |
| /// must be in the [0x00, 0x0F] range). |
| /// |
| /// Required. |
| 1: channel_bitmask uint64; |
| }) -> (table { |
| /// The CLOCK_MONOTONIC time when the hardware was configured. Note: |
| /// this does not include the effects of `turn_on_delay` on streams. |
| /// |
| /// Required. |
| 1: set_time zx.Time; |
| }) error RingBufferSetActiveChannelsError; |
| |
| /// Start the ring buffer, beginning at the first frame of the ring buffer. |
| strict Start(table {}) -> (table { |
| /// The CLOCK_MONOTONIC time when the stream was started. |
| /// |
| /// Required. |
| 1: start_time zx.Time; |
| }) error RingBufferStartError; |
| |
| /// Stop the ring buffer. |
| strict Stop(table {}) -> (table {}) error RingBufferStopError; |
| |
| /// Request delay information via a hanging get. The RingBuffer will respond |
| /// immediately to the first `WatchDelayInfo` call. Subsequent calls will |
| /// only be completed when the delay info has changed from previously |
| /// communicated values. |
| strict WatchDelayInfo() -> (table { |
| /// Required. |
| 1: delay_info DelayInfo; |
| }) error RingBufferWatchDelayInfoError; |
| }; |
| |
| /// Errors returned by `RingBuffer/SetActiveChannels`. |
| type RingBufferSetActiveChannelsError = flexible enum { |
| /// The required `channel_bitmask` is missing. |
| INVALID_CHANNEL_BITMASK = 1; |
| |
| /// This device has encountered an error and can no longer be controlled. |
| DEVICE_ERROR = 2; |
| |
| /// The device does not support `SetActiveChannels`. Individual channels |
| /// cannot be deactivated (all channels are always active). |
| METHOD_NOT_SUPPORTED = 3; |
| |
| /// The passed `channel_bitmask` specifies channels that are beyond the |
| /// range of channels currently configured for this ring buffer. |
| CHANNEL_OUT_OF_RANGE = 4; |
| }; |
| |
| /// Errors returned by `RingBuffer/Start`. |
| type RingBufferStartError = flexible enum { |
| /// This device has encountered an error and can no longer be controlled. |
| DEVICE_ERROR = 1; |
| |
| /// `Start` was called on a ring buffer that is already started. |
| ALREADY_STARTED = 2; |
| }; |
| |
| /// Errors returned by `RingBuffer/Stop`. |
| type RingBufferStopError = flexible enum { |
| /// This device has encountered an error and can no longer be controlled. |
| DEVICE_ERROR = 1; |
| |
| /// `Stop` was called on a ring buffer that is already stopped. |
| ALREADY_STOPPED = 2; |
| }; |
| |
| /// Errors returned by `RingBuffer/WatchDelayInfo`. |
| type RingBufferWatchDelayInfoError = flexible enum { |
| /// The previous `WatchDelayInfo` call has not yet completed. |
| WATCH_ALREADY_PENDING = 1; |
| |
| /// This device has encountered an error and can no longer be observed. |
| DEVICE_ERROR = 2; |
| }; |