| // 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=HEAD) |
| 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; |
| |
| /// The start/end of a pipeline. |
| @available(removed=12) |
| END_POINT = 2; |
| |
| /// 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; |
| |
| /// The start/end of a pipeline. |
| @available(added=12) |
| ENDPOINT = 12; |
| }; |
| |
| /// 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 endpoint.fidl. |
| @available(added=12) |
| 5: endpoint Endpoint; |
| }; |
| |
| type Latency = flexible union { |
| /// Latency added to the pipeline as a zx.Duration. |
| 1: latency_time zx.Duration; |
| |
| /// Latency added to the pipeline as a number of frames. |
| 2: latency_frames uint32; |
| }; |
| |
| 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; |
| |
| /// If included, type-specific parameters for the processing element. |
| /// |
| /// Optional. |
| 3: type_specific TypeSpecificElement; |
| |
| /// If included and true, the processing element can be disabled via |
| /// `ElementSetState`. |
| /// If not included or false, the processing element is always enabled. |
| /// |
| /// Optional. |
| /// |
| /// # Deprecation |
| /// |
| /// Use `can_bypass` instead. |
| @available(deprecated=20) |
| 4: can_disable bool; |
| |
| /// If included, a textual description of the processing element. |
| /// |
| /// Optional. |
| 5: description string:MAX_STRING_SIZE; |
| |
| /// If included and true, the processing element can be stopped via `ElementSetState`. |
| /// If not included or false, the processing element is always started. |
| /// |
| /// Optional. |
| @available(added=20) |
| 6: can_stop bool; |
| |
| /// If included and true, the processing element can be bypassed via `ElementSetState`. |
| /// If not included or false, the processing element cannot be bypassed. |
| /// |
| /// Optional. |
| @available(added=20) |
| 7: can_bypass bool; |
| }; |
| |
| /// Type-specific processing element state. |
| /// The type of processing element control is defined by the type of parameters provided in this |
| /// union. Must match the type returned in the corresponding `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 endpoint.fidl. |
| @available(added=12) |
| 5: endpoint EndpointElementState; |
| }; |
| |
| type ElementState = table { |
| /// If included, 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, for instance if a `SetElementState` enables a |
| /// disabled processing element providing a `TypeSpecificElementState`, then any previous |
| /// informational `TypeSpecificElementState` is superceded. |
| /// |
| /// Optional. |
| 1: type_specific TypeSpecificElementState; |
| |
| /// Process element enable/disable state. Optional. By default processing elements are enabled. |
| /// If the corresponding `Element` returned `can_disable` equals to `false`, then |
| /// this field can't be set to `false`. |
| /// If `enabled` is not included, then `state` must be included if and only if the processing |
| /// element is currently enabled. |
| /// |
| /// Optional. |
| /// |
| /// # Deprecation |
| /// |
| /// Use `bypassed` instead. |
| @available(deprecated=20) |
| 2: enabled bool; |
| |
| /// If included, how much latency is added to the pipeline if this processing element is |
| /// enabled. This field must not be present in a `SetElementState` `state` since |
| /// the latency can't be set by a client, it can only provided by the server in a |
| /// `WatchElementState` reply. |
| /// |
| /// Optional. |
| 3: latency Latency; |
| |
| /// If included, an opaque object of octets for exchanging vendor specific information. |
| /// |
| /// Optional. |
| @available(added=HEAD) |
| 4: vendor_specific_data vector<uint8>:MAX_BYTES_ELEMENT_VENDOR_SPECIFIC; |
| |
| /// The started/stopped state for this processing element. |
| /// If true, the hardware associated with the element is started. If false, stopped. |
| /// |
| /// By default processing elements are started. |
| /// If the corresponding `Element` returned `can_stop` equals to `false`, then |
| /// this field can't be set to `false`. |
| /// |
| /// A stopped processing element does not provide its abstracted functionality. |
| /// Specifically, no audio data flows through a stopped element. |
| /// |
| /// Required. |
| @available(added=20) |
| 5: started bool; |
| |
| /// The bypassed state for this processing element. |
| /// If true, the hardware associated with the element is bypassed. If false, not bypassed. |
| /// |
| /// By default processing elements are not bypassed. |
| /// If the corresponding `Element` returned `can_bypass` equals to `false`, then |
| /// this field can't be set to `true`. |
| /// |
| /// A bypassed element does not affect the flow of audio through the topology. |
| /// |
| /// Optional. |
| @available(added=20) |
| 6: bypassed bool; |
| |
| /// If included, the driver's best estimate of the amount of time (in nanoseconds) it takes |
| /// the element hardware to get into fully operational mode after `started` has changed from |
| /// false to true. |
| /// |
| /// This field should not be present in a `SetElementState` `state` since the `turn_on_delay` |
| /// can't be set by a client. It may be provided by the server in a `WatchElementState` reply. |
| /// |
| /// It may take some time for the hardware to get into fully operational mode, for example due |
| /// a power state change. 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. |
| /// |
| /// Optional. |
| @available(added=20) |
| 7: turn_on_delay zx.Duration; |
| |
| /// If included, the driver's best estimate of the amount of time (in nanoseconds) it takes |
| /// the element hardware to get into fully disabled mode after the `ElementState` has |
| /// changed `started` from true to false. |
| /// |
| /// This field should not be present in a `SetElementState` `state` since the `turn_off_delay` |
| /// can't be set by a client. It may be provided by the server in a `WatchElementState` reply. |
| /// |
| /// It may take some time for the hardware to get into fully disabled mode, for example due to |
| /// a power state change. This delay must be taken into account if audio processing of audio |
| /// samples after disabling a processing element is not acceptable. |
| /// If not included, the turn off delay is unknown. |
| /// |
| /// Optional. |
| @available(added=20) |
| 8: turn_off_delay zx.Duration; |
| }; |
| |
| /// Edge pairs between processing elements used to define ordering in processing elements |
| /// arrangements. |
| type EdgePair = struct { |
| processing_element_id_from ElementId; |
| processing_element_id_to ElementId; |
| }; |
| |
| /// A `Topology` specifies one way 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 in this order. |
| /// The ordering of processing elements with edge pairs form pipelines. |
| /// To define multiple possible pipelines, return more `Topology` entries in `GetTopologies`. |
| /// |
| /// Required. |
| 2: processing_elements_edge_pairs vector<EdgePair>:MAX_COUNT_PROCESSING_ELEMENTS_EDGE_PAIRS; |
| }; |
| |
| /// For an overview see |
| /// [[Signal Processing Interface]](https://fuchsia.dev/fuchsia-src/concepts/drivers/driver_architectures/audio_drivers/audio_signal_processing). |
| closed protocol SignalProcessing { |
| /// Exposes read-only signal processing properties. |
| compose Reader; |
| |
| /// Controls a processing element using a unique id returned by `GetElements`. |
| /// Returns `ZX_ERR_INVALID_ARGS` if the `processing_element_id` does not match an id returned |
| /// by `GetElements` or the type of `TypeSpecificElementState` does not |
| /// match the `ElementType` of the processing element returned by |
| /// `GetElements` for this id. |
| /// The driver may return `ZX_ERR_INVALID_ARGS` if the `state` values are invalid, i.e. any |
| /// of the values violates rules specified in this protocol, e.g. trying to change an |
| /// `EQUALIZER` processing element's `EqualizerBandState` `frequency` when this processing |
| /// element did not advertise `CAN_CONTROL_FREQUENCY` in its `supported_controls`. |
| /// |
| /// `SetElementState` may be called before or after non-`SignalProcessing` protocol |
| /// calls. If called after non-`SignalProcessing` protocol calls then |
| /// `SetElementState` may or may not require renegotiation of the driver state as |
| /// reached with calls of the protocol composing `SignalProcessing`, e.g. `Dai`. |
| /// For instance, `SetElementState` changing an `AGL` processing element's parameters |
| /// may not require renegotiation of the `Dai` state because changing a gain parameter usually |
| /// does not change the set of supported audio formats. |
| /// By contrast, if `SetElementState` changes the parameters of a `CONNECTION_POINT` |
| /// element, the change may require renegotiation because it may invalidate the set of |
| /// supported formats returned in a previous `GetDaiFormats` `Dai` protocol call. |
| /// |
| /// It is the driver's job to determine when renegotiation is required. If renegotiation is |
| /// required, then `SetElementState` must return `ZX_ERR_BAD_STATE` and the client must |
| /// close the protocol channel such that the protocol negotiations are started over. |
| /// The client then must make the `SetElementState` call that returned |
| /// `ZX_ERR_BAD_STATE` before any non-`SignalProcessing` protocol calls. |
| strict SetElementState(struct { |
| processing_element_id ElementId; |
| state ElementState; |
| }) -> () error zx.Status; |
| |
| /// Sets the topology to be used using an id to the vector returned by `GetTopologies`. |
| /// The current topology is communicated by `WatchTopology` responses. To change which topology |
| /// is active, a client uses `SetTopology`. |
| /// If the specified `topology_id` is not within the`topologies` returned by `GetTopologies`, |
| /// this call will return `ZX_ERR_INVALID_ARGS`. |
| /// If `GetTopologies` returns only one `Topology`, `SetTopology` is optional and has no effect. |
| /// |
| /// `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; |
| }; |
| |
| /// For an overview see |
| /// [[Signal Processing Interface]](https://fuchsia.dev/fuchsia-src/concepts/drivers/driver_architectures/audio_drivers/audio_signal_processing). |
| closed protocol Reader { |
| /// Returns a vector of supported processing elements. |
| /// Must return one or more processing elements, or `ZX_ERR_NOT_SUPPORTED`. |
| 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 reply to the first `WatchElementState` sent by the client. |
| /// The driver will not respond to subsequent client `WatchElementState` calls for a |
| /// given `processing_element_id` until any field of the `Element` table |
| /// changes from what was most recently reported for that `processing_element_id`. |
| /// 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. |
| /// Must return one or more topologies, or `ZX_ERR_NOT_SUPPORTED`. |
| /// If more than one topology is returned, then the client may choose any of the topologies from |
| /// the list with `SetTopology`. |
| /// If only one topology is returned, then the topology definition is informational only since |
| /// the one and only topology used can't be changed with `SetTopology`. |
| /// If `GetElements` returns one or more elements, `GetTopologies` must return one or |
| /// more topologies. |
| 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, which 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=HEAD) |
| strict WatchTopology() -> (struct { |
| topology_id TopologyId; |
| }); |
| }; |