blob: e342072d15838a9015b33be380d63d9a66dfebf3 [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.virtualaudio;
using zx;
using fuchsia.hardware.audio;
using fuchsia.hardware.audio.signalprocessing;
const MAX_UI_STRING_SIZE uint32 = 256;
const MAX_FORMAT_RANGES uint32 = 64;
// Can't have more ring buffers than processing elements.
const MAX_COUNT_RING_BUFFERS uint32
= fuchsia.hardware.audio.signalprocessing.MAX_COUNT_PROCESSING_ELEMENTS;
// Can't have more DAI interconnects than processing elements.
const MAX_COUNT_DAI_INTERCONNECTS uint32
= fuchsia.hardware.audio.signalprocessing.MAX_COUNT_PROCESSING_ELEMENTS;
const CONTROL_NODE_NAME string = "sys/platform/00:00:2f/virtual_audio";
type Direction = table {
/// Device type is input (true) or output (false)
/// If unspecified, then the driver may be used for both input and output.
///
/// For StreamConfig devices `is_input` is required.
/// For Dai devices `is_input` is required.
/// For Codec devices `is_input` is optional.
/// For Composite devices `is_input` is ignored.
///
/// Optional.
1: is_input bool;
};
/// This protocol provides methods for adding and removing virtual audio
/// devices. This protocol is made available through the device tree via
/// `CONTROL_NODE_NAME`.
closed protocol Control {
/// Returns the default configuration for the given device type and direction.
strict GetDefaultConfiguration(struct {
type DeviceType;
direction Direction;
}) -> (struct {
config Configuration;
}) error Error;
/// Adds a device to the device tree.
/// The device lives until the `Device` FIDL channel is closed.
strict AddDevice(resource struct {
config Configuration;
server server_end:Device;
}) -> () error Error;
/// Returns the number of active input and output devices and devices with unspecified
/// direction.
// TODO(https://fxbug.dev/42075676): Consider adding per-driver type info here.
strict GetNumDevices() -> (struct {
num_input_devices uint32;
num_output_devices uint32;
num_unspecified_direction_devices uint32;
});
/// Synchronously remove all all active input and output devices.
strict RemoveAll() -> ();
};
/// Configures a virtual audio device.
type Configuration = table {
/// Device's name.
///
/// Optional.
1: device_name string:MAX_UI_STRING_SIZE;
/// Device manufacturer's name.
///
/// Optional.
2: manufacturer_name string:MAX_UI_STRING_SIZE;
/// Device's product name.
///
/// Optional.
3: product_name string:MAX_UI_STRING_SIZE;
/// Device's unique identifier, a 16 byte string.
/// This field is only valid for `device_type` `STREAM_CONFIG` and `CODEC`.
/// If it is specified for another device_type, the AddDevice call will
/// fail with `INVALID_ARGS`.
///
/// Optional.
4: unique_id array<uint8, 16>;
/// The configuration specific to this device type.
/// The device type is determined by which `DeviceSpecific` union
/// member is defined.
///
/// Required.
5: device_specific DeviceSpecific;
};
/// Configuration for various types of drivers.
type DeviceSpecific = flexible union {
/// Configuration for a fuchsia.hardware.audio/StreamConfig driver.
1: stream_config StreamConfig;
/// Configuration for a fuchsia.hardware.audio/Dai driver.
2: dai Dai;
/// Configuration for a fuchsia.hardware.audio/Codec driver.
3: codec Codec;
/// Configuration for a fuchsia.hardware.audio/Composite driver.
4: composite Composite;
};
/// Configuration for a fuchsia.hardware.audio/StreamConfig driver.
type StreamConfig = table {
/// Device type is input (true) or output (false).
/// This is required such that a user can find a device in devfs in either
/// the `/dev/class/audio-output' or `/dev/class/audio-input`, otherwise it
/// would be optional such that a driver could be misconfigured on purpose to
/// not have an `is_input` field.
///
/// Required.
1: is_input bool;
/// Configuration for the device ring buffer.
///
/// Required.
2: ring_buffer RingBuffer;
/// Configuration for the device's clock.
///
/// Required.
3: clock_properties ClockProperties;
/// Configuration of the device gain.
///
/// Required.
4: gain_properties GainProperties;
/// Configuration of the device's plug state.
///
/// Required.
5: plug_properties PlugProperties;
};
/// Configuration for a fuchsia.hardware.audio/Dai driver.
type Dai = table {
/// Device type is input (true) or output (false).
///
/// Optional.
1: is_input bool;
/// Configuration for the device ring buffer.
///
/// Required.
2: ring_buffer RingBuffer;
/// Configuration for the device DAI interconnect.
///
/// Required.
3: dai_interconnect DaiInterconnect;
/// Configuration for the device's clock.
///
/// Required.
4: clock_properties ClockProperties;
};
/// Configuration for a fuchsia.hardware.audio/Codec driver.
type Codec = table {
/// Device type is input (true) or output (false).
/// If unspecified, then the driver may be used for both input and output.
///
/// Optional.
1: is_input bool;
/// Configuration for the device's DAI interconnect.
///
/// Required.
2: dai_interconnect DaiInterconnect;
/// Configuration of the device's plug state.
///
/// Required.
3: plug_properties PlugProperties;
};
/// Configuration for a fuchsia.hardware.audio/Composite driver.
type Composite = table {
/// Ring buffers configuration.
///
/// Required.
1: ring_buffers vector<CompositeRingBuffer>:MAX_COUNT_RING_BUFFERS;
/// DAI interconnects configurations.
///
/// Required.
2: dai_interconnects vector<CompositeDaiInterconnect>:MAX_COUNT_DAI_INTERCONNECTS;
/// Configuration for the device's clock.
///
/// Required.
3: clock_properties ClockProperties;
/// Topologies supported via the signalprocessing API.
///
/// Optional.
4: topologies
vector<fuchsia.hardware.audio.signalprocessing.Topology>:fuchsia.hardware.audio.signalprocessing.MAX_COUNT_TOPOLOGIES;
};
/// Configuration for a fuchsia.hardware.audio/RingBuffer.
type RingBuffer = table {
/// Driver transfer bytes.
///
/// Optional.
1: driver_transfer_bytes uint32;
/// Internal delay.
///
/// Optional.
2: internal_delay zx.Duration;
/// External delay.
///
/// Optional.
3: external_delay zx.Duration;
/// Supported ring buffer format ranges for this ring buffer.
///
/// Required.
4: supported_formats vector<FormatRange>:MAX_FORMAT_RANGES;
/// Constraints on the ring buffer.
/// If unspecified, there are no constraints.
///
/// Optional.
5: ring_buffer_constraints RingBufferConstraints;
/// Notification frequency.
/// This can be changed later with SetNotificationFrequency.
/// If unspecified, the notification frequency will be the same as that
/// specified by the client when retrieving the RingBuffer VMO.
///
/// Optional.
6: notifications_per_ring uint32;
};
type FormatRange = struct {
/// Has type audio_sample_format_t (see zircon/device/audio.h)
sample_format_flags uint32;
min_frame_rate uint32;
max_frame_rate uint32;
min_channels uint8;
max_channels uint8;
/// Bitfield of `ASF_RANGE_FLAG_FPS_*` flags (see zircon/device/audio.h)
rate_family_flags uint16;
};
/// Configuration for a DAI interconnect.
type DaiInterconnect = table {
/// DAI interconnect supported formats.
///
/// Required.
1: dai_supported_formats
vector<fuchsia.hardware.audio.DaiSupportedFormats>:fuchsia.hardware.audio.MAX_COUNT_DAI_FORMATS;
};
/// Configuration for a fuchsia.hardware.audio/RingBuffer as used by a Composite driver.
type CompositeRingBuffer = table {
/// Signal processing id for this composite device ring buffer.
///
/// Required.
1: id uint64;
/// Configuration for this ring buffer.
///
/// Required.
2: ring_buffer RingBuffer;
};
/// Configuration for a DAI interconnect as used by a Composite driver.
type CompositeDaiInterconnect = table {
/// Signal processing id for this composite device DAI interconnect.
///
/// Required.
1: id uint64;
/// Configuration for this DAI interconnect.
///
/// Required.
2: dai_interconnect DaiInterconnect;
};
type ClockProperties = table {
/// The clock domain is an int32 provided by the clock tree to an audio
/// driver. special values for `CLOCK_DOMAIN_MONOTONIC` (0), and
/// `CLOCK_DOMAIN_EXTERNAL` (-1) (not locally controllable) are defined in
/// `fuchsia.hardware.audio`. Note: other than -1, clients should treat any
/// negative `clock_domain` value as invalid.
///
/// Optional.
1: domain int32;
/// Rate-adjustment value for this clock. If omitted, treated as 0 ppm.
///
/// Optional.
2: rate_adjustment_ppm int32;
};
/// Set restrictions for the device ring buffer. This must be called before
/// calling `Add()`, or after `Remove()`. Once the device is activated, the
/// ring buffer and its size are returned by the driver in response to an
/// `AUDIO_RB_CMD_GET_BUFFER` command on the ring buffer channel.
/// Note: both min_frames and max_frames must be multiples of modulo_frames.
type RingBufferConstraints = struct {
/// The ring buffer must have at least this many frames.
/// Must be a multiple of `modulo_frames`.
min_frames uint32;
/// The ring buffer can have at most this many frames.
/// Must be a multiple of `modulo_frames`.
max_frames uint32;
/// The ring buffer must have a multiple of this many frames.
/// Cannot be zero.
modulo_frames uint32;
};
type GainProperties = table {
/// The initial gain state at device initialization time.
///
/// Required.
1: gain_state fuchsia.hardware.audio.GainState;
/// The device's minimum gain, in decibels.
///
/// Optional.
2: min_gain_db float32;
/// The device's maximum gain, in decibels.
///
/// Optional.
3: max_gain_db float32;
/// The precision of each gain-change step, in decibels.
///
/// Optional.
4: gain_step_db float32;
/// If true, the device contains a distinct MUTE control. If false or
/// absent, it does not.
///
/// Optional.
5: can_mute bool;
/// Automatic Gain Control. If absent, this hardware does not support AGC.
///
/// Optional.
6: can_agc bool;
};
type PlugProperties = table {
/// The initial plug state at device initialization time.
///
/// Required.
1: plug_state fuchsia.hardware.audio.PlugState;
/// Plug Detect Capabilities.
///
/// Optional.
2: plug_detect_capabilities fuchsia.hardware.audio.PlugDetectCapabilities;
};
/// This protocol represents the base functionality of active audio devices. A
/// device is active until this protocol is closed, at which point the device is
/// automatically removed.
closed protocol Device {
/// Returns the format selected by the client, or `NO_RING_BUFFER` if the
/// client has not yet selected a ring buffer format.
strict GetFormat() -> (struct {
frames_per_second uint32;
sample_format uint32;
num_channels uint32;
external_delay zx.Duration;
}) error Error;
/// Notifies all subscribed listeners when the above format is set or changed.
strict -> OnSetFormat(struct {
frames_per_second uint32;
sample_format uint32;
num_channels uint32;
external_delay zx.Duration;
});
/// Returns the current gain state for this device.
strict GetGain() -> (struct {
current_mute bool;
current_agc bool;
current_gain_db float32;
}) error Error;
/// Notifies all subscribed listeners when the above gain is set or changed.
strict -> OnSetGain(struct {
current_mute bool;
current_agc bool;
current_gain_db float32;
});
/// Returns details about the ring buffer. Returns `NO_RING_BUFFER` if the
/// client has not yet created the ring buffer.
strict GetBuffer() -> (resource struct {
ring_buffer zx.Handle:VMO;
num_ring_buffer_frames uint32;
notifications_per_ring uint32;
}) error Error;
/// Notifies all subscribed listeners when the above buffer has been
/// created.
strict -> OnBufferCreated(resource struct {
ring_buffer zx.Handle:VMO;
num_ring_buffer_frames uint32;
notifications_per_ring uint32;
});
/// Overrides the position notification frequency for this stream.
/// This affects the frequency of `OnPositionNotify` events only. It does
/// not affect the frequency of notification events sent through the audio
/// driver APIs.
strict SetNotificationFrequency(struct {
notifications_per_ring uint32;
}) -> () error Error;
/// Notifies all subscribed listeners when the device is commanded to Start
/// streaming. This can only occur after a device is fully configured
/// (format is set; ring buffer is established and fetched).
strict -> OnStart(struct {
start_time zx.Time;
});
/// Notifies all subscribed listeners when the device is commanded to Stop
/// streaming. This can only occur when the device is already Started. Stop
/// returns the device to a fully-configured state. Upon this command, the
/// already-set format and ring buffer are retained without change, but
/// position will re-begin at 0, if the device is again Started.
strict -> OnStop(struct {
stop_time zx.Time;
ring_position uint32;
});
/// Returns the current position (in bytes) within the ring buffer, along
/// with the time (per MONOTONIC clock) that corresponds with that position.
/// This can only be called after the ring buffer is established. Returns
/// `NOT_STARTED` if the device has not yet Started streaming.
strict GetPosition() -> (struct {
monotonic_time zx.Time;
ring_position uint32; // position in bytes
}) error Error;
/// Notifies all subscribed listeners when any position notification is
/// issued by the driver. The frequency of these per-stream notifications is
/// set by whoever opened the device,, though the frequency can be overriden
/// by `SetNotificationFrequency`.
strict -> OnPositionNotify(struct {
monotonic_time zx.Time;
ring_position uint32; // position in bytes
});
/// Hot-plugs or hot-unplugs an active virtual device, at the specified
/// time.
strict ChangePlugState(struct {
plug_change_time zx.Time;
plugged bool;
}) -> () error Error;
/// Immediately change the virtual device's clock rate, as expressed in the
/// timing and content of position notifications the driver emits.
/// 'ppm_monotonic' cannot exceed [-1000,+1000]. Each rate change in rate is
/// standalone; i.e. successive rate changes are not cumulative.
strict AdjustClockRate(struct {
ppm_from_monotonic int32;
}) -> () error Error;
};
type DeviceType = flexible enum {
/// Device supports the fuchsia.hardware.audio/StreamConfig protocol.
STREAM_CONFIG = 1;
/// Device supports the fuchsia.hardware.audio/Dai protocol.
DAI = 2;
/// Device supports the fuchsia.hardware.audio/Codec protocol.
CODEC = 3;
/// Device supports the fuchsia.hardware.audio/Composite protocol.
COMPOSITE = 4;
};
type Error = flexible enum {
/// Unknown internal error occurred.
INTERNAL = 1;
/// The ring buffer has not been created yet.
NO_RING_BUFFER = 2;
/// The device has not yet started streaming.
NOT_STARTED = 3;
/// The operation is not implemented, supported, or enabled.
NOT_SUPPORTED = 4;
/// An argument is invalid.
INVALID_ARGS = 5;
};