| // 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.hardware.audio; |
| |
| using zx; |
| |
| /// Properties of the ring buffer. These values don't change once the ring buffer is created. |
| type RingBufferProperties = table { |
| /// The driver's best estimate of the external delay present in the presentation pipeline for |
| /// the chosen format. When precisely synchronizing presentation across multiple entities |
| /// (e.g. devices), the external delay should be taken into account. |
| /// If not included `external_delay` is unknown. |
| 1: external_delay zx.duration; |
| |
| /// Size (in bytes) representing a temporary buffer used by the driver in order to consume or |
| /// generate the ring buffer contents. Required. |
| /// The ring buffer contents must be produced and consumed at the rate specified with the |
| /// `CreateRingBuffer` command, however some amount of buffering is required when the data is |
| /// written into and read from the ring buffer. For playback the data is consumed by the driver |
| /// by reading ahead up to `fifo_depth` bytes. For capture the data is produced by the driver |
| /// holding up to `fifo_depth` bytes at the time before committing it to main system |
| /// memory. Hence `fifo_depth` must be taken into account by the client when determining either |
| /// the minimum lead time requirement (for playback) or the maximum capture delay (for capture). |
| /// |
| /// To convert `fifo_depth` to the corresponding number of audio frames, use the frame size |
| /// returned by `CreateRingBuffer` in the `StreamConfig` protocol, note that the `fifo_depth` |
| /// is not necessarily a multiple size of an audio frame. |
| /// |
| /// The ring buffer data may be directly consumed/generated by hardware, in this case |
| /// `fifo_depth` maps directly to the size of a hardware FIFO block, since the hardware FIFO |
| /// block determines the amount of data read ahead or held back. |
| /// |
| /// The ring buffer data may instead be consumed/generated by audio driver software that is |
| /// conceptually situated between the ring buffer and the audio hardware. In this case, for |
| /// playback the `fifo_depth` read ahead amount is set large enough such that the driver |
| /// guarantees no undetected underruns, this assuming the client is generating the data as |
| /// determined by the `CreateRingBuffer` and `Start` commands. For capture, the |
| /// `fifo_depth` held back amount is set large enough such that the driver guarantees no |
| /// undetected underruns when generating the data as determined by the `CreateRingBuffer` and |
| /// `Start` commands. The driver must set `fifo_depth` big enough such that the potential |
| /// delays added by any software interfacing with the audio hardware do not occur under most |
| /// scenarios, and must detect and report underruns. How an underrun is reported is not defined |
| /// in this API. |
| 2: fifo_depth uint32; |
| |
| /// When set to true, indicates that clients need to make sure that their data has been flushed |
| /// all the way to physical memory (in the case of playback) or that their view of the ring |
| /// buffer will need to be invalidated before read (in the case of capture). Required. |
| 3: needs_cache_flush_or_invalidate bool; |
| |
| /// The driver's best estimate of the amount of time it takes the hardware to actually start |
| /// playback/capture after: |
| /// 1. A `Start` command is completed as defined by the returned `start_time`, or |
| /// 2. A channel is moved from the inactive to the active state using the `SetActiveChannels` |
| /// command and is completed as defined by the returned `set_time` making a channel active to |
| /// actually playback/capture some time after the same channel was made inactive by a previous |
| /// `SetActiveChannels` command. |
| /// It may take some time for the hardware to get into fully operational mode, for example due |
| /// a power state change or communication delays within the driver's multiple hardware entities |
| /// as in a Bluetooth driver. This delay must be taken into account if not getting the initial |
| /// audio samples played or captured is not acceptable. If not included, turn_on_delay is |
| /// considered 0. |
| /// If not included `turn_on_delay` is unknown. |
| 4: turn_on_delay zx.duration; |
| }; |
| |
| type RingBufferPositionInfo = struct { |
| /// The driver's best estimate of the time (in the CLOCK_MONOTONIC timeline) at which the |
| /// playback/capture pointer reached the position indicated by `position`. |
| /// external_delay impact should not be incorporated into 'timestamp'. |
| /// turn_on_delay impact should not be incorporated into 'timestamp'. |
| timestamp zx.time; |
| |
| /// The playback/capture pointer position (in bytes) in the ring buffer at time |
| /// `timestamp` as estimated by the driver. |
| position uint32; |
| }; |
| |
| type GetVmoError = strict enum { |
| /// The ring buffer setup failed due to an invalid argument, e.g. min_frames is too big. |
| INVALID_ARGS = 1; |
| |
| /// The ring buffer setup failed due to an internal error. |
| INTERNAL_ERROR = 2; |
| }; |
| |
| /// For an overview see |
| /// [Audio Driver Streaming Interface](https://fuchsia.dev/fuchsia-src/concepts/drivers/driver_architectures/audio_drivers/audio_streaming) |
| protocol RingBuffer { |
| /// Accessor for top level static properties. |
| GetProperties() -> (struct { |
| properties RingBufferProperties; |
| }); |
| |
| /// Gets the ring buffer current position via a hanging get. The driver must respond to a |
| /// client's first `WatchClockRecoveryPositionInfo` call, but will not respond to subsequent |
| /// client calls until the position information has changed from what was most recently |
| /// provided to that client. The driver must not respond to a |
| /// `WatchClockRecoveryPositionInfo` until after it has replied to the `Start` command. If |
| /// `clock_recovery_notifications_per_ring` is not zero, the driver will reply with its |
| /// estimated position to be used for clock recovery at most at |
| /// `clock_recovery_notifications_per_ring` frequency. |
| /// `WatchClockRecoveryPositionInfo` may only be called after `GetVmo` was called, hence a |
| /// `clock_recovery_notifications_per_ring` was specified. |
| /// Must be delivered with timestamps that are monotonically increasing. |
| WatchClockRecoveryPositionInfo() -> (struct { |
| position_info RingBufferPositionInfo; |
| }); |
| |
| /// Requests a shared buffer to be used for moving bulk audio data. Requests the buffer size to |
| /// fit at least `min_frames`, and returns the actual `num_frames` allocated in |
| /// `ring_buffer`. |
| /// |
| /// If `clock_recovery_notifications_per_ring` is non-zero, the driver will send replies to |
| /// `WatchClockRecoveryPositionInfo` client requests at most at |
| /// `clock_recovery_notifications_per_ring` frequency. These notifications are meant to be used |
| /// for clock recovery. |
| /// |
| GetVmo(struct { |
| min_frames uint32; |
| clock_recovery_notifications_per_ring uint32; |
| }) -> (resource struct { |
| num_frames uint32; |
| ring_buffer zx.handle:VMO; |
| }) error GetVmoError; |
| |
| /// Start the ring buffer. The `start_time` value (in the CLOCK_MONOTONIC timeline) indicates |
| /// when position began moving, starting at the beginning of the ring buffer. |
| /// external_delay impact should not be incorporated into 'start_time'. |
| /// If `SetActiveChannels` is not called before `Start`, then by default all channels will be |
| /// active. |
| Start() -> (struct { |
| start_time zx.time; |
| }); |
| |
| /// Stop the ring buffer. Once this call's response is received, no further position |
| /// notifications will be sent until `Start` is called again. |
| // TODO(fxbug.dev/39494): Add timestamp parameter. |
| Stop() -> (); |
| |
| /// Sets which channels are active via a bitmask. |
| /// The least significant bit corresponds to channel index 0. |
| /// Channels not set (bits are 0) in the bitmask are inactive. |
| /// Inactive channels indicate to the driver that it may turn off hardware associated with the |
| /// inactive channels. A subsequent `SetActiveChannels` setting an inactive channel to active |
| /// may incur in a `turn_on_delay` to actually restart playback/capture of the channels. |
| /// The total number of channels is the `number_of_channels` in `Format`, specifically in |
| /// `PcmFormat`, i.e. this bitmask has up to `number_of_channels` bits set (maximum 64). |
| /// Deactivating one, several, or all channels does not `Stop` the ring buffer. |
| /// `SetActiveChannels` does not change the ring buffer's behavior with regard to |
| /// `Start`/`Stop`, specifically position. Once `Start` is called, a ring buffer's position |
| /// advances (and position notifications sent as needed) regardless of the number of active |
| /// channels, including if no channels are active. This means that the format in the |
| /// ring buffer is not changed. |
| /// By default all channels are active. |
| /// If the driver does not support deactivating channels it must return `ZX_ERR_NOT_SUPPORTED`. |
| /// If the mask is incorrect, i.e. enables channels outside the number of bits |
| /// to use for a given `number_of_channels`, then the driver may return `ZX_ERR_INVALID_ARGS`. |
| /// The `set_time` value (in the CLOCK_MONOTONIC timeline) indicates when configuring |
| /// the hardware to activate or deactivate channels is completed. `set_time` does not include |
| /// the potential `turn_on_delay`, the driver does not delay the reply waiting for the |
| /// hardware to actually turn on, the driver replies with a `set_time` indicating when the |
| /// hardware configuration was completed. |
| /// For input channels, it is not required that the driver zero-out inactive channels. |
| SetActiveChannels(struct { |
| active_channels_bitmask uint64; |
| }) -> (struct { |
| set_time zx.time; |
| }) error zx.status; |
| }; |