blob: c230881d61b4d56c9022ba07a6afe8e4afda3d48 [file] [log] [blame] [edit]
// 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 fuchsia.audio;
using zx;
alias ClockDomain = fuchsia.hardware.audio.ClockDomain;
alias TokenId = uint64;
/// Maximum number of audio devices in the system at any time.
const MAX_COUNT_DEVICES uint32 = 256;
/// Maximum number of `PcmFormatSet`s that a device can report as supported.
const MAX_COUNT_FORMATS uint32 = fuchsia.hardware.audio.MAX_COUNT_FORMATS;
/// Maximum number of `ChannelSet`s that a device can report in a single PcmFormatSet.
const MAX_COUNT_CHANNEL_SETS uint32 = fuchsia.hardware.audio.MAX_COUNT_CHANNEL_SETS;
/// Maximum number of distinct sample formats that a single PcmFormatSet can contain.
const MAX_COUNT_SAMPLE_TYPES uint32 = 32;
/// Maximum number of frame rates that a device can report in a PcmFormatSet.
const MAX_COUNT_RATES uint32 = fuchsia.hardware.audio.MAX_COUNT_SUPPORTED_RATES;
/// Maximum number of channels that a device can report as supported.
const MAX_COUNT_CHANNELS uint32 = fuchsia.hardware.audio.MAX_COUNT_CHANNELS_IN_RING_BUFFER;
/// The length of the device's unique ID, in bytes.
const UNIQUE_INSTANCE_ID_SIZE uint32 = fuchsia.hardware.audio.UNIQUE_ID_SIZE;
/// Maximum length of the strings for device, manufacturer and product names.
const MAX_STRING_SIZE uint32 = fuchsia.hardware.audio.MAX_UI_STRING_SIZE;
/// The device's type (e.g. directionality).
type DeviceType = flexible enum {
/// The device is a source of audio streams.
INPUT = 1;
/// The device is a destination for audio streams.
OUTPUT = 2;
};
/// 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.
1: token_id TokenId;
/// Whether the device is an input (a source of audio) or an output
/// (a destination for audio).
///
/// Required.
2: device_type DeviceType;
/// The device's high-level name, as received from devfs or the
/// `Provider/AddDevice` caller.
///
/// Required.
3: device_name string:MAX_STRING_SIZE;
/// The name of the device's manufacturer.
///
/// Optional.
4: manufacturer string:MAX_STRING_SIZE;
/// The device's high-level product name.
///
/// Optional.
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.
6: unique_instance_id array<uint8, UNIQUE_INSTANCE_ID_SIZE>;
/// The union of all formats the device can support, across all combinations
/// of device configuration settings. Must contain at least one entry.
///
/// Required.
7: supported_formats vector<PcmFormatSet>:MAX_COUNT_FORMATS;
/// The device's gain/mute capabilities.
///
/// Required.
//
// TODO(fxbug.dev/102027): Remove legacy gain aspects once driver API does.
// Going forward, gain will be handled by `SignalProcessing`.
8: gain_caps GainCapabilities;
/// The device's hot-plug capabilities.
///
/// Required.
9: 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.
10: clock_domain ClockDomain;
};
/// This table contains vectors representing three dimensions of device
/// configuration (channelization, sample format, frame rate). The device should
/// support all combinations of the items in these vectors.
type PcmFormatSet = table {
/// The number of channel sets that the device supports. This must contain
/// at least one `ChannelSet` entry.
///
/// Required.
1: channel_sets vector<ChannelSet>:MAX_COUNT_CHANNEL_SETS;
/// The number of sample formats that the device supports. This must
/// contain least one `AudioSampleFormat` entry.
///
/// Required.
2: sample_types vector<fuchsia.audio.SampleType>:MAX_COUNT_SAMPLE_TYPES;
/// The number of frame rates that the device supports. This must contain at
/// least one frame rate entry.
///
/// Required.
3: frame_rates vector<uint32>:MAX_COUNT_RATES;
};
/// One possible channel configuration for the device.
type ChannelSet = table {
/// Each item in this vector describes the attributes (e.g. frequency range)
/// of that channel. The length of this vector defines the number of
/// channels supported by this ChannelSet. Must contain at least one entry.
///
/// Required.
1: attributes vector<ChannelAttributes>:MAX_COUNT_CHANNELS;
// TODO(fxbug.dev/105130): Incorporate this, once it lands.
// 2: config AudioChannelConfig;
};
/// The attributes (e.g. frequency range) of a single channel.
type ChannelAttributes = table {
/// Minimum frequency that this channel guarantees to emit/capture, in Hz.
/// If absent, this channel extends to the bottom of the device range.
///
/// Optional.
1: min_frequency uint32;
/// Maximum frequency that this channel guarantees to emit/capture, in Hz.
/// If absent, this channel extends to the top of the device range.
///
/// Optional.
2: max_frequency uint32;
};
/// The device's overall gain capabilities.
//
// TODO(fxbug.dev/102027): 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 current state of gain.
//
// TODO(fxbug.dev/102027): Remove legacy gain aspects once driver API does.
// Going forward, gain will be handled by `SignalProcessing`.
type GainState = table {
/// Device-wide gain, in decibels.
///
/// Required.
1: gain_db float32;
/// Mute state for all channels. If absent, all channels are unmuted.
///
/// Optional.
2: muted bool;
/// Automatic Gain Control. If absent, disabled.
///
/// Optional.
3: agc_enabled 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.
WATCH_ALREADY_PENDING = 1;
};
/// Errors returned by `Registry/WatchDeviceRemoved`.
type RegistryWatchDeviceRemovedError = flexible enum {
/// The previous `WatchDeviceRemoved` call has not yet completed.
WATCH_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.
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`).
//
// TODO(fxbug.dev/102027): 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.
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.
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 {
/// The previous `WatchGainState` call has not yet completed.
WATCH_ALREADY_PENDING = 1;
/// This device has encountered an error and can no longer be observed.
DEVICE_ERROR = 2;
};
/// Errors returned by `Observer/WatchPlugState`.
type ObserverWatchPlugStateError = flexible enum {
/// The previous `WatchPlugState` call has not yet completed.
WATCH_ALREADY_PENDING = 1;
/// This device has encountered an error and can no longer be observed.
DEVICE_ERROR = 2;
};
/// Errors returned by `Observer/GetReferenceClock`.
type ObserverGetReferenceClockError = flexible enum {
/// This device has encountered an error and can no longer be observed.
DEVICE_ERROR = 1;
/// The device's reference clock could not be returned.
DEVICE_CLOCK_UNAVAILABLE = 2;
};