blob: 2923307315f1e37cfb5f27142990fbbd67c60e94 [file] [log] [blame]
// 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;
/// Delay information as returned by the driver.
@available(added=HEAD)
type DelayInfo = table {
/// The driver's best estimate of the delay internal to the hardware it abstracts for
/// the chosen format.
///
/// "Internal" refers to the hardware on the side of any hardware interconnect (DAI)
/// that provides the ring buffer, for instance an SoC audio subsystem, whereas "external"
/// refers to hardware on the other side of any hardware interconnect (DAI), for
/// instance hardware codecs.
///
/// For a given frame during playback, this is any delay after the driver/HW copies it
/// out of the ring-buffer, before it exits any hardware interconnect.
/// For a given frame during recording, this is any delay before the driver/HW copies
/// it into the ring-buffer, after it enters the hardware interconnect.
///
/// `internal_delay` must be taken into account by the client when determining either
/// the minimum lead time requirement (for playback) or the minimum capture delay (for
/// capture).
///
/// This delay must not include the inherent delay added by the temporary buffering needed
/// to copy data in and out of the ring buffer, specified via `RingBufferProperties`
/// `driver_transfer_bytes`.
///
/// Required.
1: internal_delay zx.duration;
/// The driver's best estimate of the delay external to the hardware it abstracts for
/// the chosen format.
///
/// "Internal" refers to the hardware on the side of any hardware interconnect (DAI)
/// that provides the ring buffer, for instance an SoC audio subsystem, whereas "external"
/// refers to hardware on the other side of any hardware interconnect (DAI), for
/// instance hardware codecs.
///
/// If not included `external_delay` is unknown. If unknown, the client may treat
/// `external_delay` as it chooses, e.g. may autodetect it, consider it zero, consider
/// it a large number, etc.
///
/// `external_delay` must be taken into account by the client when determining either
/// the minimum lead time requirement (for playback) or the minimum capture delay (for
/// capture).
///
/// This delay must not include the inherent delay added by the temporary buffering needed
/// to copy data in and out of the ring buffer, specified via `RingBufferProperties`
/// `driver_transfer_bytes`.
///
2: external_delay zx.duration;
};
/// 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.
//
// # Deprecation
//
// Not needed anymore since the functionality is available via `WatchDelayInfo` below.
// Should match `DelayInfo` `external_delay` until it's removed.
@available(deprecated=9)
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.
//
// # Deprecation
//
// Not needed anymore since the functionality is available via `driver_transfer_bytes` below.
@available(deprecated=9, removed=HEAD)
2: fifo_depth uint32;
/// When set to true, indicates that the ring buffer runs in a different cache coherency domain,
/// hence clients need to make sure that their data has been flushed all the way to main 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).
///
/// When set to false, indicates that the ring buffer runs in the same cache coherency domain,
/// hence the driver does not require flushing/invalidation, as in there is no hardware external
/// to the CPUs reading/writing from/to main memory bypassing the CPUs.
/// Note that in this case the driver and client still need to make sure they synchronize their
/// access to the data, for instance inserting the appropriate acquire fences before reading
/// and release fences after writing.
///
/// 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 a channel is activated by `SetActiveChannels`.
/// Restated: the driver estimates that after `SetActiveChannels` enables a channel, its data
/// will resume flowing at approximately `set_time` + `turn_on_delay`.
/// 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 unknown.
4: turn_on_delay zx.duration;
/// Size (in bytes) representing a temporary buffer used by the driver/HW in order to transfer
/// (consume or produce) the ring buffer contents.
///
/// 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 `driver_transfer_bytes`. For capture, the data is produced by the
/// driver holding up to `driver_transfer_bytes` at a time before committing it to the ring
/// buffer.
///
/// Let's define ‘begin pointer’ and 'end pointer' as position pointers in the ring buffer,
/// represented as 'B' and 'E' in the figures below, that bound the portion of the ring buffer
/// that are unsafe for reading or writing by the client at a given point in time.
///
/// ## Playback
///
/// For playback, it is safe for a client to write only to the part of the ring buffer that is
/// not simultaneously being read by the driver/HW. Before the ring buffer is started, clients
/// of output devices may write initial data starting at the very beginning of the ring buffer
/// at least `driver_transfer_bytes` of audio since they must always stay at least that far
/// ahead of where the driver/HW is reading. Note that if the client does not write to the
/// beginning of the ring buffer, then it is relying on the zeroed-out contents of the VMO as
/// the initial audio to be read by the driver/HW.
/// It is therefore not safe for the client to copy additional data to the ring buffer between
/// 'B' and 'E', the part already in use which may or may not already be consumed. The client
/// may safely write to any other portion of the ring buffer from 'E' to '0/B'.
///
/// ```
/// Ring Buffer
/// +-------------------------+-------------------------------------------------------------+
/// |<--- unsafe --->|<--- safe (empty) --->|
/// |<`driver_transfer_bytes`>| |
/// +-------------------------+-------------------------------------------------------------+
/// 0/B E 0
/// ```
///
/// As time passes, the driver/HW reads the data in chunks of unknown size (up to the amount of
/// `driver_transfer_bytes`) at the rate specified in `CreateRingBuffer`, and the begin/end
/// pointers move to the right of '0' at the same rate. As a result, the area to which it is
/// unsafe for the client to write moves gradually forward through the ring buffer, but
/// maintains a constant size equal to `driver_transfer_bytes`. For instance after some time we
/// now have:
///
/// ```
/// Ring Buffer
/// +------------+-------------------------+------------------------------------------------+
/// [<-- safe -->|<--- unsafe --->|<-- safe (empty) -->|
/// | |<`driver_transfer_bytes`>| |
/// +------------+-------------------------+------------------------------------------------+
/// 0 B E 0
/// ```
///
/// In steady state, i.e. once the process has wrapped around the ring buffer, any area outside
/// of the pointers 'B' and 'E' is safe to write:
///
/// ```
/// Ring Buffer
/// +--------------------------------+-------------------------+----------------------------+
/// [<-- safe -->|<--- unsafe --->|<-- safe -->|
/// | |<`driver_transfer_bytes`>| |
/// +--------------------------------+-------------------------+----------------------------+
/// 0 B E 0
/// ```
///
///
/// ## Recording
///
/// For recording, it is safe for a client to read only the part of the ring buffer that is not
/// simultaneously being written by the driver/HW. At the moment when the ring buffer is started
/// by the client, the driver has not written any amount of data to the ring buffer, so there
/// is nothing for the client to read:
///
/// ```
/// Ring Buffer
/// +---------------------------------------------------------------------------------------+
/// [<--- empty -->|
/// +---------------------------------------------------------------------------------------+
///0/B/E 0
/// ```
///
/// The driver/HW begins writing to the ring buffer starting at '0'. As time passes, the
/// driver/HW writes data in chunks of unknown size (up to `driver_transfer_bytes`) at the rate
/// specified in `CreateRingBuffer`. Until an amount of data equal to `driver_transfer_bytes`
/// has been written into the ring buffer by the driver/HW, it is not safe for the client to
/// read any data:
///
/// ```
/// Ring Buffer
/// +----------------+----------------------------------------------------------------------+
/// [<--- unsafe --->|<-- empty -->|
/// |<`driver_transfer_bytes`>| |
/// +----------------+----------------------------------------------------------------------+
/// 0/B E 0
/// ```
///
/// Once `driver_transfer_bytes` of data have been copied into the ring buffer by the driver/HW,
/// it is safe for the client to read the data from '0' to 'B'. It is unsafe to read the data
/// from ‘B’ to ‘E’, the area in which the driver/HW is simultaneously writing. This unsafe
/// area moves gradually forward through the ring buffer, but maintains a constant size equal
/// to `driver_transfer_bytes`. For instance after some time we now have:
///
/// ```
/// Ring Buffer
/// +------------+-------------------------+------------------------------------------------+
/// [<-- safe -->|<--- unsafe --->|<-- empty -->|
/// | |<`driver_transfer_bytes`>| |
/// +------------+-------------------------+------------------------------------------------+
/// 0 B E 0
/// ```
///
/// In steady state, i.e. once the process has wrapped around the ring buffer, any area outside
/// of the pointers 'B' and 'E' is safe to read:
///
/// ```
/// Ring Buffer
/// +--------------------------------+-------------------------+----------------------------+
/// [<-- safe -->|<--- unsafe --->|<-- safe -->|
/// | |<`driver_transfer_bytes`>| |
/// +--------------------------------+-------------------------+----------------------------+
/// 0 B E 0
/// ```
///
/// ## Hardware versus software
///
/// The ring buffer data may be directly consumed/generated by hardware, i.e.
/// `driver_transfer_bytes` can be mapped directly to the size of a hardware FIFO block, since a
/// hardware FIFO block determines the upper limit amount of data read ahead or held back.
/// Note that if the FIFO buffer is used in a "ping pong" manner (such that only half the FIFO
/// buffer size is copied at a time), and this is true not only on steady state but also the
/// very first time the driver copies data to or from the ring buffer, then
/// `driver_transfer_bytes` may be set to half the FIFO buffer size. If the hardware at any time
/// copies data to/from the ring buffer in an amount equal to the entire FIFO buffer size (for
/// instance the first copy from the ring buffer to fill an initially empty hardware FIFO), then
/// `driver_transfer_bytes` must be set to the entire size of the FIFO buffer.
///
/// 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 `driver_transfer_bytes` 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
/// `driver_transfer_bytes` 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.
///
///
/// This size must not include the impact of any delays caused by hardware or software
/// processing abstracted by the driver; those are communicated by the `internal_delay` and
/// `external_delay` fields in `DelayInfo` and are entirely orthogonal to this value.
///
/// Required.
@available(added=HEAD)
5: driver_transfer_bytes uint32;
};
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`.
/// `turn_on_delay` impact should not be incorporated into 'timestamp'.
/// No delays indicated in `DelayInfo` should be incorporated.
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 between client and driver.
/// The client requests `min_frames` as the size for part of the ring buffer it needs.
/// The driver returns the actual size of allocated ring buffer space in `num_frames`.
///
/// `num_frames` must be at least `min_frames` plus `driver_transfer_bytes` (in frames) such
/// that ring buffer contents can be transfered in and out, or else the call must be failed
/// with GetVmoError.INVALID_ARGS.
///
/// The driver may increase the ring buffer size beyond `min_frames` plus
/// `driver_transfer_bytes` (in frames) due to any internal requirements, for instance
/// alignment.
///
/// Clients can treat the entire returned ring buffer as safe to access, except for the
/// `driver_transfer_bytes` immediately adjacent to the current position, see the
/// `driver_transfer_bytes` parameter specification in `RingBufferProperties` for more details.
///
/// 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.
///
// TODO(fxbug.dev/116353): Reconsider the `clock_recovery_notifications_per_ring` parameter,
// once we must recover a clock from a device being actively rate-adjusted in hardware.
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 `Start` is called before `SetActiveChannels`, then by default all channels are active.
/// If `Start` is called before `GetVmo`, the channel must be closed with `ZX_ERR_BAD_STATE`.
/// If `Start` is called while this RingBuffer is already started, the channel must be closed
/// with an error `ZX_ERR_BAD_STATE` returned.
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.
/// If `Stop` is called before `GetVmo`, the channel must be closed with `ZX_ERR_BAD_STATE`.
// 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 must 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;
/// Get information about delays via a hanging get. The driver will immediately reply to the
/// first `WatchDelayInfo` sent by the client. The driver will not respond to subsequent client
/// `WatchDelayInfo` calls until the delay info changes from what was most recently reported.
@available(added=HEAD)
WatchDelayInfo() -> (struct {
delay_info DelayInfo;
});
};