blob: 6b5f11bae88ab09b69ebad53ea0d3762f0850882 [file] [log] [blame]
// 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.hardware.audio;
using fuchsia.hardware.audio.signalprocessing;
using zx;
/// The length of the device's unique ID, in bytes.
const UNIQUE_INSTANCE_ID_SIZE uint32 = fuchsia.hardware.audio.UNIQUE_ID_SIZE;
/// When a device is detected (or added via `Provider/AddDevice`), it is
/// queried for its properties and capabilities. Once this enumeration process
/// completes, it is announced to clients that are watching for device arrivals
/// via `Registry/WatchDevicesAdded`.
///
/// An `Info` table is returned for each audio device that has been added.
type Info = table {
/// A device identifier that is guaranteed unique for this boot session, but
/// may change across reboots.
///
/// Required for all device types.
1: token_id TokenId;
/// The protocol used by the driver, and (if StreamConfig) its directionality.
///
/// Required for all device types.
2: device_type DeviceType;
/// The device's high-level name, as received from devfs or the
/// `Provider/AddDevice` caller.
///
/// Required for all device types.
3: device_name string:MAX_STRING_SIZE;
/// The name of the device's manufacturer.
///
/// Optional for all device types.
4: manufacturer string:MAX_STRING_SIZE;
/// The device's high-level product name.
///
/// Optional for all device types.
5: product string:MAX_STRING_SIZE;
/// A 16-character ID provided by the driver that (if present) can be used
/// to differentiate instances of the same device. This value should not
/// change across system reboots.
///
/// Optional for all device types.
6: unique_instance_id array<uint8, UNIQUE_INSTANCE_ID_SIZE>;
/// Whether the device is a source (is_input TRUE) or destination (is_input FALSE) of audio.
///
/// Required for StreamConfig; optional for Codec; absent for Composite.
7: is_input bool;
/// The union of all formats the device can support, across all combinations of device
/// configuration settings.
/// If the device exposes one or more RingBuffer ENDPOINT elements, this field must be present
/// and its vector must contain exactly one entry for each relevant ENDPOINT element.
/// If the device exposes NO RingBuffer ENDPOINT elements, this field must be omitted (entirely
/// absent, rather than populated with an empty vector).
///
/// Required for StreamConfig; optional for Composite; absent for Codec.
8: ring_buffer_format_sets vector<ElementRingBufferFormatSet>:MAX_COUNT_PROCESSING_ELEMENTS;
/// The union of all DAI formats the device can support, across all combinations
/// of device configuration settings.
/// If the device exposes one or more Dai ENDPOINT elements, this field must be present and its
/// vector must contain exactly one entry for each relevant ENDPOINT element.
/// If the device exposes NO Dai ENDPOINT elements, this field must be omitted (entirely absent,
/// rather than populated with an empty vector).
///
/// Required for Codec; optional for Composite; absent for StreamConfig.
9: dai_format_sets vector<ElementDaiFormatSet>:MAX_COUNT_PROCESSING_ELEMENTS;
/// The device's gain/mute capabilities.
///
/// Required for StreamConfig; absent for Codec and Composite.
//
// TODO(https://fxbug.dev/42052918): Remove legacy gain aspects once driver API does.
// Going forward, gain will be handled by `SignalProcessing`.
10: gain_caps GainCapabilities;
/// The device's hot-plug capabilities.
///
/// Required for Codec and StreamConfig; absent for Composite.
11: plug_detect_caps PlugDetectCapabilities;
/// An identifier for the clock domain in which the device's clock hardware
/// operates. Devices in the same clock domain remain perfectly
/// synchronized. They may drift relative to some other clock domain, but
/// all clocks in that domain will do so perfectly _together_. Although
/// their clocks have the same rate, their positions may be offset by an
/// arbitrary, fixed amount.
///
/// There are two special values for clock domain:
///
/// * `CLOCK_DOMAIN_MONOTONIC` means the hardware is driven by the system
/// montonic clock and will always be synchronized with that timeline.
///
/// * `CLOCK_DOMAIN_EXTERNAL` means the hardware is not synchronized with any
/// other known clocks (even any other clocks in `CLOCK_DOMAIN_EXTERNAL`).
///
/// Required for Composite and StreamConfig; absent for Codec.
12: clock_domain ClockDomain;
/// The vector of supported signal-processing elements.
/// If present, must contain at least one element.
///
/// Required for Composite; optional for Codec and StreamConfig.
13: signal_processing_elements
vector<fuchsia.hardware.audio.signalprocessing.Element>:fuchsia.hardware.audio.signalprocessing.MAX_COUNT_PROCESSING_ELEMENTS;
/// The vector of supported signal-processing topologies.
/// If present, must contain at least one element.
///
/// Required for Composite; optional for Codec and StreamConfig.
14: signal_processing_topologies
vector<fuchsia.hardware.audio.signalprocessing.Topology>:fuchsia.hardware.audio.signalprocessing.MAX_COUNT_TOPOLOGIES;
};
/// The device's overall gain capabilities.
//
// TODO(https://fxbug.dev/42052918): Remove legacy gain aspects once driver API does.
// Going forward, gain will be handled by `SignalProcessing`.
type GainCapabilities = table {
/// The device's minimum gain, in decibels.
///
/// Required.
1: min_gain_db float32;
/// The device's maximum gain, in decibels.
///
/// Required.
2: max_gain_db float32;
/// The precision of each gain-change step, in decibels.
///
/// Required.
3: gain_step_db float32;
/// If true, the device contains a distinct MUTE control. If false or
/// absent, it does not.
///
/// Optional.
4: can_mute bool;
/// Automatic Gain Control. If absent, this hardware does not support AGC.
///
/// Optional.
5: can_agc bool;
};
/// The device's hot-plug capabilities.
type PlugDetectCapabilities = flexible enum {
/// Device is always plugged in. Plug state cannot change.
HARDWIRED = 0;
/// Device can be un/plugged and can asynchronously notify of changes.
PLUGGABLE = 1;
};
/// The current plugged-in state for the device.
type PlugState = flexible enum {
/// Connected and available for audio streaming.
PLUGGED = 1;
/// Not connected; unavailable for audio streaming.
UNPLUGGED = 2;
};
/// `Registry` instances notify clients as devices arrive and depart, and they
/// create observers (see `Observer`) that notify of more detailed state changes.
@discoverable
closed protocol Registry {
/// Register for notification when one or more devices are added.
/// The `devices` vector will always contain at least one `Info` entry.
strict WatchDevicesAdded() -> (table {
/// Devices added since `WatchDevicesAdded` was last called. This method
/// returns all audio devices when called for the first time.
1: devices vector<Info>:MAX_COUNT_DEVICES;
}) error RegistryWatchDevicesAddedError;
/// Register for notification when an (active, added) device is removed.
/// Because the method only notifies of one removal, upon completion it
/// should immediately be re-called, in case other removals have occurred.
strict WatchDeviceRemoved() -> (table {
/// The token of the device least-recently removed.
1: token_id TokenId;
}) error RegistryWatchDeviceRemovedError;
/// Request an `Observer` for the specified device.
strict CreateObserver(resource table {
/// The token of the device to be observed.
///
/// Required.
1: token_id TokenId;
/// The server end of the `Observer` that will be created.
///
/// Required.
2: observer_server server_end:Observer;
}) -> (table {}) error RegistryCreateObserverError;
};
/// Errors returned by `Registry/WatchDevicesAdded`.
type RegistryWatchDevicesAddedError = flexible enum {
/// The previous `WatchDevicesAdded` call has not yet completed.
ALREADY_PENDING = 1;
};
/// Errors returned by `Registry/WatchDeviceRemoved`.
type RegistryWatchDeviceRemovedError = flexible enum {
/// The previous `WatchDeviceRemoved` call has not yet completed.
ALREADY_PENDING = 1;
};
/// Errors returned by `Registry/CreateObserver`.
type RegistryCreateObserverError = flexible enum {
/// The required `token_id` is missing.
INVALID_TOKEN_ID = 1;
/// The required `observer_server` is missing.
INVALID_OBSERVER = 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` has encountered an error and can no longer be observed.
DEVICE_ERROR = 4;
};
/// `Observer` instances are used to learn the capabilities and state of an
/// audio device, and to stay informed as its state changes over time. Each
/// `Observer` is associated with an initialized audio device. An audio device
/// may be observed by multiple `Observer` instances.
closed protocol Observer {
/// Query the device's available processing topologies and individual
/// elements, and watch for changes to those elements.
///
/// These methods must be supported by Composite devices,
/// but are optional for Codec and StreamConfig devices.
compose fuchsia.hardware.audio.signalprocessing.Reader;
/// Request notification of any change to the device's gain state.
///
/// Note: this only notifies of changes to controls described in the
/// device's`Info` table (`GainCapabilities` specifically). Use
/// `WatchElementState` for gain processing exposed as `SignalProcessing`
/// (`GetTopologies`, `GetElements`).
///
/// Should only be called for StreamConfig devices.
//
// TODO(https://fxbug.dev/42052918): Remove legacy gain aspects once driver API does.
// Going forward, gain will be handled by `SignalProcessing`.
strict WatchGainState() -> (table {
/// The device's most recent gain state.
1: state GainState;
}) error ObserverWatchGainStateError;
/// Request notification of any change to the device's plug state. When
/// called for the first time, it will return immediately.
///
/// Should only be called for Codec or StreamConfig devices.
strict WatchPlugState() -> (table {
/// The device's current plug state.
1: state PlugState;
/// The time (in CLOCK_MONOTONIC) of the most-recent change in plug state.
2: plug_time zx.Time;
}) error ObserverWatchPlugStateError;
/// Retrieve the device's reference clock.
///
/// This clock will be in the domain specified in the device's `Info` table.
///
/// Should only be called for Composite or StreamConfig devices.
strict GetReferenceClock() -> (resource table {
/// The device's reference clock.
1: reference_clock zx.Handle:CLOCK;
}) error ObserverGetReferenceClockError;
};
/// Errors returned by `Observer/WatchGainState`.
type ObserverWatchGainStateError = flexible enum {
/// This device has encountered an error and can no longer be observed.
DEVICE_ERROR = 1;
/// This device type does not support the method that was called.
WRONG_DEVICE_TYPE = 2;
/// The previous `WatchGainState` call has not yet completed.
ALREADY_PENDING = 3;
};
/// Errors returned by `Observer/WatchPlugState`.
type ObserverWatchPlugStateError = flexible enum {
/// This device has encountered an error and can no longer be observed.
DEVICE_ERROR = 1;
/// This device type does not support the method that was called.
WRONG_DEVICE_TYPE = 2;
/// The previous `WatchPlugState` call has not yet completed.
ALREADY_PENDING = 3;
};
/// Errors returned by `Observer/GetReferenceClock`.
type ObserverGetReferenceClockError = flexible enum {
/// This device has encountered an error and can no longer be observed.
DEVICE_ERROR = 1;
/// This device type does not support the method that was called.
WRONG_DEVICE_TYPE = 2;
/// The device's reference clock could not be returned.
DEVICE_CLOCK_UNAVAILABLE = 3;
};