blob: ef965c23abcfc86da176bcec7b08f7f3399cb3a6 [file] [log] [blame]
// Copyright 2021 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.signalprocessing;
using zx;
// TODO(https://fxbug.dev/42143529): Complete parameters and types for processing elements.
alias ElementId = uint64;
alias TopologyId = uint64;
const MAX_COUNT_PROCESSING_ELEMENTS uint32 = 64;
const MAX_COUNT_TOPOLOGIES uint32 = 64;
const MAX_COUNT_PROCESSING_ELEMENTS_EDGE_PAIRS uint32 = 64;
const MAX_STRING_SIZE uint32 = 256;
@available(added=27)
const MAX_BYTES_ELEMENT_VENDOR_SPECIFIC uint32 = 4096;
type ElementType = flexible enum {
/// Vendor Specific. A type of processing element not covered by any subsequent type definition.
VENDOR_SPECIFIC = 1;
/// Controls pipelines channel mixing and routing.
CONNECTION_POINT = 3;
/// Gain control, a.k.a. Volume control.
GAIN = 4;
/// Automatic Gain Control.
/// Automatically maintains a suitable signal level regardless of variation of its input.
AUTOMATIC_GAIN_CONTROL = 5;
/// Automatic Gain Limiter.
/// Automatically maintains a signal level below a level specified.
/// Input below the level is unaffected, and peaks above the level are attenuated.
AUTOMATIC_GAIN_LIMITER = 6;
/// Alters the dynamic range of the signal, e.g. dynamic range compression.
DYNAMICS = 7;
/// Mute.
MUTE = 8;
/// Delay.
DELAY = 9;
/// Equalizer.
EQUALIZER = 10;
/// Sample Rate Conversion.
SAMPLE_RATE_CONVERSION = 11;
/// Ring Buffer.
/// This is the first of two types of elements that can start/end processing pipelines.
RING_BUFFER = 13;
/// Digital Audio Interface Interconnect.
/// This is the second of two types of elements that can start/end processing pipelines.
DAI_INTERCONNECT = 14;
};
/// Type-specific Parameters for an `Element`.
type TypeSpecificElement = flexible union {
// See vendor_specific.fidl.
1: vendor_specific VendorSpecific;
// See gain.fidl.
2: gain Gain;
// See equalizer.fidl.
3: equalizer Equalizer;
// See dynamics.fidl.
4: dynamics Dynamics;
// See dai_interconnect.fidl.
6: dai_interconnect DaiInterconnect;
};
type Element = table {
/// Unique ID for this element. The scope of this id is only within the `SignalProcessing`
/// protocol lifespan, i.e. until the channel associated with the protocol is closed.
///
/// Required.
1: id ElementId;
/// Processing element type.
///
/// Required.
2: type ElementType;
/// Type-specific parameters for the processing element.
///
/// Required for `ElementType`s DAI_INTERCONNECT, DYNAMICS, EQUALIZER, GAIN, VENDOR_SPECIFIC.
/// Invalid if specified for elements of type AUTOMATIC_GAIN_CONTROL, AUTOMATIC_GAIN_LIMITER,
/// CONNECTION_POINT, DELAY, MUTE, RING_BUFFER or SAMPLE_RATE_CONVERSION.
3: type_specific TypeSpecificElement;
/// If included, a textual description of the processing element.
///
/// Optional. If present, must not be empty.
5: description string:MAX_STRING_SIZE;
/// If true, the processing element can be stopped via `SetElementState`.
/// If not included or false, the processing element is always started.
///
/// Optional.
6: can_stop bool;
/// If true, the processing element can be bypassed via `SetElementState`.
/// If not included or false, the processing element cannot be bypassed.
/// By definition, elements of type DAI_INTERCONNECT or RING_BUFFER cannot be bypassed and
/// must never set this field to true.
///
/// Optional.
7: can_bypass bool;
};
/// Type-specific processing element state, as returned from the driver.
/// The type of processing element control is defined by the type of parameters provided in this
/// union. This type-specific variant must match the `ElementType` entry in the corresponding
/// `Element`.
type TypeSpecificElementState = flexible union {
// See vendor_specific.fidl.
1: vendor_specific VendorSpecificState;
// See gain.fidl.
2: gain GainElementState;
// See equalizer.fidl.
3: equalizer EqualizerElementState;
// See dynamics.fidl.
4: dynamics DynamicsElementState;
// See dai_interconnect.fidl.
6: dai_interconnect DaiInterconnectElementState;
};
/// The current state of an element, as returned from the driver. Note that this table contains
/// fields that are not present in `SettableElementState`, since they cannot be changed by clients.
type ElementState = table {
/// Type-specific state parameters for the processing element.
///
/// If this processing element is disabled and its type-specific state is provided, then the
/// type-specific state is only informational (e.g. the state of a stopped element, if it were
/// to be re-started without also providing additional superceding state information).
///
/// Required for DAI_INTERCONNECT, DYNAMICS, EQUALIZER, GAIN and VENDOR_SPECIFIC elements.
/// Invalid if specified for elements of type AUTOMATIC_GAIN_CONTROL, AUTOMATIC_GAIN_LIMITER,
/// CONNECTION_POINT, DELAY, MUTE, RING_BUFFER or SAMPLE_RATE_CONVERSION.
1: type_specific TypeSpecificElementState;
/// If included, an opaque object of octets for conveying vendor-specific information from the
/// driver to `SignalProcessing` clients.
///
/// Optional (permitted even if the element's type is not VENDOR_SPECIFIC).
@available(added=27)
4: vendor_specific_data vector<uint8>:MAX_BYTES_ELEMENT_VENDOR_SPECIFIC;
/// The start/stop state for this processing element.
/// If true, the hardware associated with the element is started. If false, it is stopped.
///
/// If the corresponding `Element` omitted `can_stop` or set it to `false`, then this field
/// can never be `false`.
///
/// A stopped processing element does not provide its abstracted functionality.
/// No audio data flows through stopped elements.
///
/// Required.
5: started bool;
/// The bypass state for this processing element.
/// If true, the hardware associated with the element is bypassed. If false or missing, the
/// associated hardware is not bypassed.
///
/// By default, processing elements are not bypassed.
/// If the corresponding `Element` omitted `can_bypass` or set it to `false`, then this field
/// can never be set to `true`.
///
/// A bypassed element does not affect the flow of audio through the topology.
/// Audio flows through a bypassed element, unchanged.
///
/// Optional.
6: bypassed bool;
/// If included, the driver's best estimate of the amount of time it takes the element's
/// hardware to enter a fully operational mode after `started` has changed from false to true.
/// Hardware may require some duration to reach a fully operational mode after changing its
/// power state, for example.
///
/// If `turn_on_delay` is not taken into account, then an audio stream's initial frames might
/// be lost while audio elements are powering up.
/// If not included, `turn_on_delay` is unknown.
///
/// Optional. If specified, must be non-negative.
7: turn_on_delay zx.Duration;
/// If included, the driver's best estimate of the amount of time it takes the element's
/// hardware to enter a fully disabled mode after `started` has changed from true to false.
/// Hardware may require some duration to get into a fully stopped state after a change in
/// power state, for example.
///
/// If `turn_off_delay` is not taken into account, more frames will be emitted/captured than a
/// client might expect, while audio elements are powering down.
/// If not included, `turn_off_delay` is unknown.
///
/// Optional. If specified, must be non-negative.
8: turn_off_delay zx.Duration;
/// If included, the driver's best estimate of the delay added by this processing element,
/// as it is currently configured (including `bypassed` state).
///
/// This value should be taken into account by timing-sensitive clients, when determining the
/// requirements for (playback) minimum lead time and minimum capture delay.
///
/// For an element of type `RING_BUFFER`, this delay should not include the inherent delay
/// added by the temporary buffering needed to copy data in and out of a ring buffer, which
/// is contained in the `RingBufferProperties` field `driver_transfer_bytes`.
///
/// Optional. If specified, must be non-negative.
9: processing_delay zx.Duration;
};
/// Type-specific processing element state that can be set by clients.
/// The type of processing element control is defined by the type of parameters provided in this
/// union. This type-specific variant must match the `ElementType` entry in the corresponding
/// `Element`.
type SettableTypeSpecificElementState = flexible union {
// See vendor_specific.fidl.
1: vendor_specific VendorSpecificState;
// See gain.fidl.
2: gain GainElementState;
// See equalizer.fidl.
3: equalizer EqualizerElementState;
// See dynamics.fidl.
4: dynamics DynamicsElementState;
};
/// Processing element state that can be set by clients.
type SettableElementState = table {
/// Type-specific element-state parameters that can be set by clients.
///
/// If an element is disabled, changes in this field (and all others in SettableElementState)
/// are purely informational and take no effect until the element is enabled.
///
/// If not set, then the element's previous `type_specific` state is preserved.
///
/// Optional for DYNAMICS, EQUALIZER, GAIN and VENDOR_SPECIFIC types.
/// Invalid if specified for AUTOMATIC_GAIN_CONTROL, AUTOMATIC_GAIN_LIMITER, CONNECTION_POINT,
/// DAI_INTERCONNECT, DELAY, MUTE, RING_BUFFER or SAMPLE_RATE_CONVERSION elements.
1: type_specific SettableTypeSpecificElementState;
/// If included, an opaque object of octets for conveying vendor-specific information from
/// a client to the audio driver.
/// This can be used with any element type, not just VENDOR_SPECIFIC elements.
///
/// Optional.
@available(added=27)
2: vendor_specific_data vector<uint8>:MAX_BYTES_ELEMENT_VENDOR_SPECIFIC;
/// Whether to start or stop this processing element.
/// A stopped processing element does not provide its abstracted functionality.
/// Specifically, no audio data flows through a stopped element.
///
/// If the corresponding `Element` returned `can_stop` equals to `false`, then this field must
/// not be set to `false` -- `SetElementState` will return ZX_ERR_INVALID_ARGS in that case.
/// If not set, then the element's previous `started` state will be unchanged.
///
/// Optional.
3: started bool;
/// Whether to bypass this processing element.
/// A bypassed element does not affect the flow of audio through the topology.
/// Specifically, audio flows through a bypassed element, without change.
///
/// If the corresponding `Element` omits `can_bypass` or sets it to `false`, then this field
/// must not be set to `true`. If this occurs, `SetElementState` will fail and return error
/// `ZX_ERR_INVALID_ARGS`.
/// If not set, then the element's previous `bypassed` state will be unchanged.
///
/// Optional.
4: bypassed bool;
};
/// Edge pairs between processing elements, used to specify how audio flows sequentially through
/// a collection of processing element arrangements.
type EdgePair = struct {
processing_element_id_from ElementId;
processing_element_id_to ElementId;
};
/// A `Topology` specifies how processing elements are arranged within the hardware.
type Topology = table {
/// Unique ID for this topology. The scope of this id is only within the `SignalProcessing`
/// protocol lifespan, i.e. until the channel associated with the protocol is closed.
///
/// Required.
1: id TopologyId;
/// Vector of processing elements edge pairs that specify connections between elements.
/// Processing elements are connected by edge pairs, to form multi-element pipelines.
/// A Topology can contain more than one distinct pipeline: the Topology need not be a single
/// interconnected sequence (e.g. Topology A->B->C D->E->F is valid).
///
/// To define multiple possible configurations where one possibility can be selected by the
/// client, return multiple `Topology` entries in `GetTopologies`.
///
/// If a device does support multiple Topology entries, then each specific Topology is not
/// required to include every Element. However, every element must be included in at least one
/// Topology.
///
/// Within each Topology, every sequence of connected elements must begin with an element
/// of type DAI_INTERCONNECT or RING_BUFFER, and must end with an element of type
/// DAI_INTERCONNECT or RING_BUFFER.
///
/// An DAI_INTERCONNECT element is _permitted_ to be the endpoint for an element sequence, but a
/// RING_BUFFER is _required_ to be one. If a certain RING_BUFFER element is listed in an
/// EdgeList entry as a `processing_element_id_from`, then within that Topology this same
/// element must NOT be listed in another EdgeList entry as a `processing_element_id_to` (and
/// vice versa).
///
/// As a special case, a DAI_INTERCONNECT element can refer to itself; i.e. an EdgePair may
/// contain `processing_element_id_from` and `processing_element_id_to` values that are equal.
/// However, this element must not _also_ connect to _other_ elements within the Topology (this
/// EdgePair must be the only one in `processing_elements_edge_pairs` to mention that element).
///
/// Required. Must contain at least one entry.
2: processing_elements_edge_pairs vector<EdgePair>:MAX_COUNT_PROCESSING_ELEMENTS_EDGE_PAIRS;
};
/// This protocol is required for Composite audio drivers, and unsupported for other audio driver
/// types (Codec, Dai, StreamConfig).
///
/// For an overview see
/// [[Signal Processing Interface]](https://fuchsia.dev/fuchsia-src/concepts/drivers/driver_architectures/audio_drivers/audio_signal_processing).
open protocol SignalProcessing {
/// Exposes read-only signal processing properties.
compose Reader;
/// Sets the currently active topology by specifying a `topology_id`, which matches to an entry
/// in the vector returned by `GetTopologies`.
/// The currently active topology is communicated by `WatchTopology` responses. To change which
/// topology is active, a client uses `SetTopology`.
///
/// If `GetTopologies` returns only one `Topology`, `SetTopology` is optional and has no effect.
///
/// This call will fail and return `ZX_ERR_INVALID_ARGS` if the specified `topology_id` is not
/// found within the`topologies` returned by `GetTopologies`.
///
/// `SetTopology` may be called before or after non-`SignalProcessing` protocol calls.
/// If called after non-`SignalProcessing` protocol calls, then `SetTopology` may return
/// `ZX_ERR_BAD_STATE` to indicate that the operation can not proceed without renegotiation of
/// the driver state. See `SetElementState` for further discussion.
strict SetTopology(struct {
topology_id TopologyId;
}) -> () error zx.Status;
/// Controls the processing element specified by `processing_element_id`, a unique ElementId
/// returned by `GetElements`.
/// The `state` specified in calls to `SetElementState` is a `SettableElementState`. This is a
/// subset of `ElementState` because some fields returned by `WatchElementState` (e.g. `latency`
/// or `plug_state`) can only be observed (not set) by the client.
///
/// Returns `ZX_ERR_INVALID_ARGS` if `processing_element_id` does not match a known ElementId
/// returned by `GetElements`, or if `state` is not valid for the element. This entails any
/// violation of the rules specified in this protocol.
///
/// Examples:
/// `state` specifies that an element should be stopped or bypassed, but the corresponding
/// element does not specify (or explicitly set to false) `can_stop` or `can_bypass`.
/// `state` includes a `type_specific` entry, but that `SettableTypeSpecificElementState` does
/// not match the `ElementType` of the element corresponding to `processing_element_id`.
/// `state` changes an `EqualizerBandState` for an `EQUALIZER` element (so far so good), but
/// specifies a change to `frequency` when this element did not set `CAN_CONTROL_FREQUENCY`
/// in its `supported_controls`.
/// `state` specifies a `GainElementState` for a `GAIN` element with a `gain` value that is
/// -infinity, NAN, or outside the Element's stated [`min_gain`, `max_gain`] range.
///
/// Callers may intersperse method calls to the `SignalProcessing` protocol with calls to other
/// driver protocols. Some non-`SignalProcessing` configuration changes may require a
/// renegotiation of the driver state before certain elements can receive a `SetElementState`.
/// For example, if a `DaiFormat` is changed, then `SetElementState` changing an `AGL` element's
/// parameters may not require renegotiation of driver state because changing gain parameters
/// usually does not change the set of supported audio formats.
/// By contrast, following the same `DaiFormat` change, before `SetElementState` can be called
/// on a `CONNECTION_POINT` element, the driver state may need to be reestablished because the
/// format change may invalidate the set of supported formats returned in a previous
/// `GetDaiFormats` protocol call for another part of the Topology.
///
/// It is the driver's job to determine when renegotiation is required. When this is needed,
/// the related `SetElementState` call must return `ZX_ERR_BAD_STATE` and the client must
/// close the protocol channel entirely, such that the protocol negotiations are started over.
/// The client then must re-invoke the `SetElementState` call that returned
/// `ZX_ERR_BAD_STATE` before any non-`SignalProcessing` protocol calls.
strict SetElementState(struct {
processing_element_id ElementId;
state SettableElementState;
}) -> () error zx.Status;
};
/// This protocol is required for Composite audio drivers, and unsupported for other audio driver
/// types (Codec, Dai, StreamConfig).
///
/// For an overview see
/// [[Signal Processing Interface]](https://fuchsia.dev/fuchsia-src/concepts/drivers/driver_architectures/audio_drivers/audio_signal_processing).
open protocol Reader {
/// Returns a vector of supported processing elements.
/// This vector must include one or more processing elements.
strict GetElements() -> (struct {
processing_elements vector<Element>:MAX_COUNT_PROCESSING_ELEMENTS;
}) error zx.Status;
/// Get the processing element state via a hanging get.
/// For a given `processing_element_id`, the driver will immediately reply to the first
/// `WatchElementState` sent by the client. The driver will not respond to subsequent client
/// `WatchElementState` calls for that `processing_element_id` until any portion of the
/// `ElementState` has changed from what was most recently reported for that element.
///
/// The driver will close the protocol channel with an error of `ZX_ERR_INVALID_ARGS`, if
/// `processing_element_id` does not match an ElementId returned by `GetElements`.
///
/// The driver will close the protocol channel with an error of `ZX_ERR_BAD_STATE`, if this
/// method is called again while there is already a pending `WatchElementState` for this client
/// and `processing_element_id`.
strict WatchElementState(struct {
processing_element_id ElementId;
}) -> (struct {
state ElementState;
});
/// Returns a vector of supported topologies.
/// This vector must include one or more topologies.
/// If more than one topology is returned, then the client may select any topology from the
/// list by calling `SetTopology`.
/// If only one topology is returned, `SetTopology` can still be called but causes no change.
///
/// Each Element must be included in at least one Topology, but need not be included in every
/// Topology.
strict GetTopologies() -> (struct {
topologies vector<Topology>:MAX_COUNT_TOPOLOGIES;
}) error zx.Status;
/// Get the current topology via a hanging get.
/// The driver will immediately reply to the first `WatchTopology` sent by each client.
/// The driver will not respond to subsequent `WatchTopology` calls from that client until the
/// signal processing topology changes; this occurs as a result of a `SetTopology` call.
///
/// The driver will close the protocol channel with an error of `ZX_ERR_BAD_STATE`, if this
/// method is called again while there is already a pending `WatchTopology` for this client.
@available(added=27)
flexible WatchTopology() -> (struct {
topology_id TopologyId;
});
};