Audio System + Drivers (#562)

This commit is contained in:
Shadowtrance
2026-07-14 16:34:29 +10:00
committed by GitHub
parent fa4a6e255c
commit 955416dac8
137 changed files with 8847 additions and 387 deletions
@@ -0,0 +1,218 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <tactility/freertos/freertos.h>
#include <tactility/error.h>
struct Device;
/**
* @brief Direction of an audio codec operation or capability.
*/
enum AudioCodecDirection {
AUDIO_CODEC_DIR_INPUT = 1,
AUDIO_CODEC_DIR_OUTPUT = 2,
AUDIO_CODEC_DIR_BOTH = 3,
};
/**
* @brief Stream configuration used to open a codec for reading or writing.
*/
struct AudioCodecStreamConfig {
uint32_t sample_rate;
uint8_t bits_per_sample; // 16, 24, 32
uint8_t channels;
enum AudioCodecDirection direction;
};
/**
* @brief API for audio codec drivers (e.g. ES8388, ES7210, AW88298).
*
* Implementations typically wrap a vendor codec library (e.g. esp_codec_dev) and
* the underlying I2S/I2C/GPIO controllers. This API is intentionally low-level and
* codec-agnostic: it does not perform resampling or mixing. Most apps should use
* the higher-level audio_stream API (see audio_stream.h) instead.
*/
struct AudioCodecApi {
/**
* @brief Opens the codec for streaming in the given direction(s).
* @param[in] device the audio codec device
* @param[in] config the stream configuration
* @retval ERROR_NONE on success
* @retval ERROR_NOT_SUPPORTED if the requested direction is not supported
*/
error_t (*open)(struct Device* device, const struct AudioCodecStreamConfig* config);
/**
* @brief Closes the codec, stopping any active streams.
* @param[in] device the audio codec device
* @retval ERROR_NONE on success
*/
error_t (*close)(struct Device* device);
/**
* @brief Reads recorded audio data from the codec. Only valid for codecs opened with input direction.
* @param[in] device the audio codec device
* @param[out] data the buffer to store the read data
* @param[in] data_size the number of bytes to read
* @param[out] bytes_read the number of bytes actually read
* @param[in] timeout the maximum time to wait for the operation to complete
* @retval ERROR_NONE on success
* @retval ERROR_TIMEOUT when the operation timed out
*/
error_t (*read)(struct Device* device, void* data, size_t data_size, size_t* bytes_read, TickType_t timeout);
/**
* @brief Writes audio data for playback to the codec. Only valid for codecs opened with output direction.
* @param[in] device the audio codec device
* @param[in] data the buffer containing the data to write
* @param[in] data_size the number of bytes to write
* @param[out] bytes_written the number of bytes actually written
* @param[in] timeout the maximum time to wait for the operation to complete
* @retval ERROR_NONE on success
* @retval ERROR_TIMEOUT when the operation timed out
*/
error_t (*write)(struct Device* device, const void* data, size_t data_size, size_t* bytes_written, TickType_t timeout);
/**
* @brief Sets the volume for the given direction.
* @param[in] device the audio codec device
* @param[in] direction AUDIO_CODEC_DIR_INPUT or AUDIO_CODEC_DIR_OUTPUT
* @param[in] volume_percent volume in the range 0..100
* @retval ERROR_NONE on success
* @retval ERROR_NOT_SUPPORTED if the direction is not supported by this codec
*/
error_t (*set_volume)(struct Device* device, enum AudioCodecDirection direction, float volume_percent);
/**
* @brief Gets the volume for the given direction.
* @param[in] device the audio codec device
* @param[in] direction AUDIO_CODEC_DIR_INPUT or AUDIO_CODEC_DIR_OUTPUT
* @param[out] volume_percent volume in the range 0..100
* @retval ERROR_NONE on success
* @retval ERROR_NOT_SUPPORTED if the direction is not supported by this codec
*/
error_t (*get_volume)(struct Device* device, enum AudioCodecDirection direction, float* volume_percent);
/**
* @brief Mutes or unmutes the given direction.
* @param[in] device the audio codec device
* @param[in] direction AUDIO_CODEC_DIR_INPUT or AUDIO_CODEC_DIR_OUTPUT
* @param[in] muted true to mute, false to unmute
* @retval ERROR_NONE on success
* @retval ERROR_NOT_SUPPORTED if the direction is not supported by this codec
*/
error_t (*set_mute)(struct Device* device, enum AudioCodecDirection direction, bool muted);
/**
* @brief Gets the mute state for the given direction.
* @param[in] device the audio codec device
* @param[in] direction AUDIO_CODEC_DIR_INPUT or AUDIO_CODEC_DIR_OUTPUT
* @param[out] muted true if muted, false otherwise
* @retval ERROR_NONE on success
* @retval ERROR_NOT_SUPPORTED if the direction is not supported by this codec
*/
error_t (*get_mute)(struct Device* device, enum AudioCodecDirection direction, bool* muted);
/**
* @brief Gets the native sample rate the codec hardware runs at for the given direction.
* @param[in] device the audio codec device
* @param[in] direction AUDIO_CODEC_DIR_INPUT or AUDIO_CODEC_DIR_OUTPUT
* @param[out] rate_hz the native sample rate in Hz
* @retval ERROR_NONE on success
* @retval ERROR_NOT_SUPPORTED if the direction is not supported by this codec
*/
error_t (*get_native_sample_rate)(struct Device* device, enum AudioCodecDirection direction, uint32_t* rate_hz);
/**
* @brief Gets the number of channels the codec hardware natively expects/produces for the
* given direction (e.g. a 4-slot TDM microphone ADC reports 4 here even if an app only
* wants 1). Callers that need a different channel count must downmix/upmix themselves --
* opening the codec with a channel count that doesn't match its native layout can produce
* corrupted audio (e.g. ES7210 in TDM mode silently halves its configured bit depth when
* asked for <= 2 channels).
* @param[in] device the audio codec device
* @param[in] direction AUDIO_CODEC_DIR_INPUT or AUDIO_CODEC_DIR_OUTPUT
* @param[out] channels the native channel count
* @retval ERROR_NONE on success
* @retval ERROR_NOT_SUPPORTED if the direction is not supported by this codec
*/
error_t (*get_native_channels)(struct Device* device, enum AudioCodecDirection direction, uint8_t* channels);
/**
* @brief Gets the directions supported by this codec.
* @param[in] device the audio codec device
* @param[out] supported_directions AUDIO_CODEC_DIR_INPUT, AUDIO_CODEC_DIR_OUTPUT, or AUDIO_CODEC_DIR_BOTH
* @retval ERROR_NONE on success
*/
error_t (*get_capabilities)(struct Device* device, enum AudioCodecDirection* supported_directions);
/**
* @brief Gets a fixed digital gain multiplier to apply to this codec's input samples,
* on top of whatever audio_codec_set_volume() controls. Compensates for mic capsules
* that are quiet even at full hardware gain (e.g. small PDM/MEMS mics), or codecs with
* no working hardware gain control at all (e.g. a dummy PDM codec). Set from the
* codec's own devicetree config; 1.0 (no boost) if this field is NULL or the codec
* doesn't implement it.
* @param[in] device the audio codec device
* @param[out] gain the multiplier to apply (1.0 = no change)
* @retval ERROR_NONE on success
* @retval ERROR_NOT_SUPPORTED if the direction is not supported by this codec
*/
error_t (*get_input_gain_multiplier)(struct Device* device, float* gain);
};
/** @brief See AudioCodecApi::open */
error_t audio_codec_open(struct Device* device, const struct AudioCodecStreamConfig* config);
/** @brief See AudioCodecApi::close */
error_t audio_codec_close(struct Device* device);
/** @brief See AudioCodecApi::read */
error_t audio_codec_read(struct Device* device, void* data, size_t data_size, size_t* bytes_read, TickType_t timeout);
/** @brief See AudioCodecApi::write */
error_t audio_codec_write(struct Device* device, const void* data, size_t data_size, size_t* bytes_written, TickType_t timeout);
/** @brief See AudioCodecApi::set_volume */
error_t audio_codec_set_volume(struct Device* device, enum AudioCodecDirection direction, float volume_percent);
/** @brief See AudioCodecApi::get_volume */
error_t audio_codec_get_volume(struct Device* device, enum AudioCodecDirection direction, float* volume_percent);
/** @brief See AudioCodecApi::set_mute */
error_t audio_codec_set_mute(struct Device* device, enum AudioCodecDirection direction, bool muted);
/** @brief See AudioCodecApi::get_mute */
error_t audio_codec_get_mute(struct Device* device, enum AudioCodecDirection direction, bool* muted);
/** @brief See AudioCodecApi::get_native_sample_rate */
error_t audio_codec_get_native_sample_rate(struct Device* device, enum AudioCodecDirection direction, uint32_t* rate_hz);
/** @brief See AudioCodecApi::get_native_channels */
error_t audio_codec_get_native_channels(struct Device* device, enum AudioCodecDirection direction, uint8_t* channels);
/** @brief See AudioCodecApi::get_capabilities */
error_t audio_codec_get_capabilities(struct Device* device, enum AudioCodecDirection* supported_directions);
/**
* @brief See AudioCodecApi::get_input_gain_multiplier. Returns 1.0 (no change) if the
* codec doesn't implement this field, rather than ERROR_NOT_SUPPORTED -- callers can treat
* the multiplier as always present.
*/
error_t audio_codec_get_input_gain_multiplier(struct Device* device, float* gain);
extern const struct DeviceType AUDIO_CODEC_TYPE;
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,211 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <tactility/freertos/freertos.h>
#include <tactility/error.h>
#include <tactility/drivers/audio_codec.h>
struct Device;
/**
* @brief Handle to an open audio stream (see audio_stream_open_input/open_output).
*
* The `device` field identifies the owning audio stream device so that
* audio_stream_read/write/close can dispatch to the correct driver; implementations
* embed this as the first member of a larger private struct and may store additional
* state after it.
*/
struct AudioStreamHandleData {
struct Device* device;
};
typedef struct AudioStreamHandleData* AudioStreamHandle;
/**
* @brief Stream configuration requested by the caller.
*
* The sample_rate is the rate the caller wants to read/write at; the audio-stream
* device transparently resamples to/from the bound codec's native rate, so the same
* app code works regardless of which codec hardware is present.
*/
struct AudioStreamConfig {
uint32_t sample_rate; // e.g. 16000, 44100, 48000
uint8_t bits_per_sample; // 16, 24, 32
uint8_t channels;
};
/** @brief Identifies which cached field changed in an AudioStreamChangeCallback. */
enum AudioStreamChange {
AUDIO_STREAM_CHANGE_VOLUME,
AUDIO_STREAM_CHANGE_MUTE,
AUDIO_STREAM_CHANGE_ENABLED,
};
typedef void (*AudioStreamChangeCallback)(struct Device* device, enum AudioCodecDirection direction, enum AudioStreamChange change, void* user_data);
/**
* @brief API for the high-level full-duplex audio stream device.
*
* Implementations bind to one input-capable and/or one output-capable AUDIO_CODEC_TYPE
* device, and provide resampling plus shared volume/mute/enable state on top. This is
* the API apps (including ELF side-loaded apps) and AudioService should use — most code
* should not talk to AUDIO_CODEC_TYPE devices directly.
*
* read/write are blocking and must be called from the caller's own task, never from the
* main/LVGL thread.
*/
struct AudioStreamApi {
/**
* @brief Opens an input (recording) stream at the requested configuration.
* @param[in] device the audio stream device
* @param[in] config the requested stream configuration
* @param[out] out_handle receives the opened stream handle
* @retval ERROR_NONE on success
* @retval ERROR_NOT_SUPPORTED if no input-capable codec is bound
* @retval ERROR_INVALID_STATE if an input stream is already open
*/
error_t (*open_input)(struct Device* device, const struct AudioStreamConfig* config, AudioStreamHandle* out_handle);
/**
* @brief Opens an output (playback) stream at the requested configuration.
* @param[in] device the audio stream device
* @param[in] config the requested stream configuration
* @param[out] out_handle receives the opened stream handle
* @retval ERROR_NONE on success
* @retval ERROR_NOT_SUPPORTED if no output-capable codec is bound
* @retval ERROR_INVALID_STATE if an output stream is already open
*/
error_t (*open_output)(struct Device* device, const struct AudioStreamConfig* config, AudioStreamHandle* out_handle);
/**
* @brief Reads recorded audio data from an input stream, resampled to the requested rate.
* @param[in] handle the stream handle returned by open_input
* @param[out] data the buffer to store the read data
* @param[in] data_size the number of bytes to read
* @param[out] bytes_read the number of bytes actually read
* @param[in] timeout the maximum time to wait for the operation to complete
* @retval ERROR_NONE on success
* @retval ERROR_TIMEOUT when the operation timed out
*/
error_t (*read)(AudioStreamHandle handle, void* data, size_t data_size, size_t* bytes_read, TickType_t timeout);
/**
* @brief Writes audio data for playback to an output stream, resampled from the requested rate.
* @param[in] handle the stream handle returned by open_output
* @param[in] data the buffer containing the data to write
* @param[in] data_size the number of bytes to write
* @param[out] bytes_written the number of bytes actually written
* @param[in] timeout the maximum time to wait for the operation to complete
* @retval ERROR_NONE on success
* @retval ERROR_TIMEOUT when the operation timed out
*/
error_t (*write)(AudioStreamHandle handle, const void* data, size_t data_size, size_t* bytes_written, TickType_t timeout);
/**
* @brief Closes a stream opened with open_input or open_output.
* @param[in] handle the stream handle to close
* @retval ERROR_NONE on success
*/
error_t (*close)(AudioStreamHandle handle);
/**
* @brief Sets the shared volume for the given direction. Visible to all consumers
* (other apps, AudioService, Settings UI) since the state lives on the bound codec.
* @param[in] device the audio stream device
* @param[in] direction AUDIO_CODEC_DIR_INPUT or AUDIO_CODEC_DIR_OUTPUT
* @param[in] volume_percent volume in the range 0..100
* @retval ERROR_NONE on success
* @retval ERROR_NOT_SUPPORTED if no codec is bound for the given direction
*/
error_t (*set_volume)(struct Device* device, enum AudioCodecDirection direction, float volume_percent);
/** @brief Gets the shared volume for the given direction. See set_volume. */
error_t (*get_volume)(struct Device* device, enum AudioCodecDirection direction, float* volume_percent);
/** @brief Sets the shared mute state for the given direction. See set_volume. */
error_t (*set_mute)(struct Device* device, enum AudioCodecDirection direction, bool muted);
/** @brief Gets the shared mute state for the given direction. See set_volume. */
error_t (*get_mute)(struct Device* device, enum AudioCodecDirection direction, bool* muted);
/**
* @brief Enables or disables the given direction. A disabled direction cannot be
* opened (open_input/open_output return ERROR_NOT_ALLOWED) and any open stream in
* that direction is closed. Used by Settings UI / AudioService to govern access.
* @param[in] device the audio stream device
* @param[in] direction AUDIO_CODEC_DIR_INPUT or AUDIO_CODEC_DIR_OUTPUT
* @param[in] enabled true to enable, false to disable
* @retval ERROR_NONE on success
* @retval ERROR_NOT_SUPPORTED if no codec is bound for the given direction
*/
error_t (*set_enabled)(struct Device* device, enum AudioCodecDirection direction, bool enabled);
/** @brief Gets the enabled state for the given direction. See set_enabled. */
error_t (*get_enabled)(struct Device* device, enum AudioCodecDirection direction, bool* enabled);
/**
* @brief Checks whether a codec supporting the given direction is bound.
* @param[in] device the audio stream device
* @param[in] direction AUDIO_CODEC_DIR_INPUT or AUDIO_CODEC_DIR_OUTPUT
* @param[out] supported true if a codec for this direction is bound, false otherwise
* @retval ERROR_NONE on success
*/
error_t (*is_supported)(struct Device* device, enum AudioCodecDirection direction, bool* supported);
/** @brief See audio_stream_set_change_callback. */
error_t (*set_change_callback)(struct Device* device, AudioStreamChangeCallback callback, void* user_data);
};
/** @brief See AudioStreamApi::open_input */
error_t audio_stream_open_input(struct Device* device, const struct AudioStreamConfig* config, AudioStreamHandle* out_handle);
/** @brief See AudioStreamApi::open_output */
error_t audio_stream_open_output(struct Device* device, const struct AudioStreamConfig* config, AudioStreamHandle* out_handle);
/** @brief See AudioStreamApi::read */
error_t audio_stream_read(AudioStreamHandle handle, void* data, size_t data_size, size_t* bytes_read, TickType_t timeout);
/** @brief See AudioStreamApi::write */
error_t audio_stream_write(AudioStreamHandle handle, const void* data, size_t data_size, size_t* bytes_written, TickType_t timeout);
/** @brief See AudioStreamApi::close */
error_t audio_stream_close(AudioStreamHandle handle);
/** @brief See AudioStreamApi::set_volume */
error_t audio_stream_set_volume(struct Device* device, enum AudioCodecDirection direction, float volume_percent);
/** @brief See AudioStreamApi::get_volume */
error_t audio_stream_get_volume(struct Device* device, enum AudioCodecDirection direction, float* volume_percent);
/** @brief See AudioStreamApi::set_mute */
error_t audio_stream_set_mute(struct Device* device, enum AudioCodecDirection direction, bool muted);
/** @brief See AudioStreamApi::get_mute */
error_t audio_stream_get_mute(struct Device* device, enum AudioCodecDirection direction, bool* muted);
/** @brief See AudioStreamApi::set_enabled */
error_t audio_stream_set_enabled(struct Device* device, enum AudioCodecDirection direction, bool enabled);
/** @brief See AudioStreamApi::get_enabled */
error_t audio_stream_get_enabled(struct Device* device, enum AudioCodecDirection direction, bool* enabled);
/** @brief See AudioStreamApi::is_supported */
error_t audio_stream_is_supported(struct Device* device, enum AudioCodecDirection direction, bool* supported);
/** @brief See AudioStreamApi::set_change_callback */
error_t audio_stream_set_change_callback(struct Device* device, AudioStreamChangeCallback callback, void* user_data);
extern const struct DeviceType AUDIO_STREAM_TYPE;
#ifdef __cplusplus
}
#endif
@@ -40,6 +40,16 @@ struct I2sTdmRxConfig {
uint8_t slot_bit_width; // bit width of each TDM slot (0 = auto, matches bits_per_sample)
};
/**
* @brief I2S PDM RX config (e.g. for a PDM MEMS microphone such as the SPM1423).
* Only supported on I2S controller 0 on ESP32 targets -- PDM RX is hardware-restricted
* to that controller. PDM only supports 16-bit samples and mono or stereo.
*/
struct I2sPdmRxConfig {
uint32_t sample_rate_hz;
bool stereo; // false = mono (single PDM mic), true = stereo (two PDM mics)
};
/**
* @brief I2S Config
*/
@@ -104,13 +114,40 @@ struct I2sControllerApi {
/**
* @brief Reconfigures the RX channel to TDM mode (e.g. for ES7210).
* Must be called after set_config() which creates the channel handles.
* Does not require set_config() to be called first -- TDM allocates its own RX
* channel handle independently of standard mode (calling set_config() first would
* leave its TX/RX channel pair bound to the shared BCLK/WS/MCLK pins, which then
* blocks this call from claiming them; callers should pick TDM or standard mode
* up front, not call both in sequence).
* @param[in] device the I2S controller device
* @param[in] config TDM parameters
* @retval ERROR_NONE when the operation was successful
* @retval ERROR_NOT_SUPPORTED if the driver does not implement TDM
*/
error_t (*set_rx_tdm_config)(struct Device* device, const struct I2sTdmRxConfig* config);
/**
* @brief Reconfigures the RX channel to PDM mode (e.g. for a PDM MEMS microphone).
* Does not require set_config() to be called first -- PDM RX allocates its own
* channel handle independently of standard/TDM mode.
* @param[in] device the I2S controller device
* @param[in] config PDM parameters
* @retval ERROR_NONE when the operation was successful
* @retval ERROR_NOT_SUPPORTED if the driver/controller does not support PDM RX
*/
error_t (*set_rx_pdm_config)(struct Device* device, const struct I2sPdmRxConfig* config);
/**
* @brief Disables and releases only the TX or only the RX channel, leaving the other
* direction (if active) running. Unlike reset(), which tears down both directions --
* unsuitable when a single controller carries an independent TX user (e.g. a speaker
* amp) and RX user (e.g. a PDM mic) that must be able to close without affecting each
* other.
* @param[in] device the I2S controller device
* @param[in] is_input true to disable the RX channel, false to disable the TX channel
* @retval ERROR_NONE when the operation was successful
*/
error_t (*disable_direction)(struct Device* device, bool is_input);
};
/**
@@ -160,7 +197,9 @@ error_t i2s_controller_reset(struct Device* device);
/**
* @brief Reconfigures the RX channel to TDM mode (e.g. for ES7210 4-slot mic ADC).
* Must be called after i2s_controller_set_config() which creates the channel handles.
* Does not require i2s_controller_set_config() to be called first -- see
* I2sControllerApi::set_rx_tdm_config for why standard mode and TDM mode are
* alternative setup paths rather than sequential steps.
* @param[in] device the I2S controller device
* @param[in] config TDM parameters
* @retval ERROR_NONE when the operation was successful
@@ -168,6 +207,24 @@ error_t i2s_controller_reset(struct Device* device);
*/
error_t i2s_controller_set_rx_tdm_config(struct Device* device, const struct I2sTdmRxConfig* config);
/**
* @brief Reconfigures the RX channel to PDM mode (e.g. for a PDM MEMS microphone).
* @param[in] device the I2S controller device
* @param[in] config PDM parameters
* @retval ERROR_NONE when the operation was successful
* @retval ERROR_NOT_SUPPORTED if the driver/controller does not support PDM RX
*/
error_t i2s_controller_set_rx_pdm_config(struct Device* device, const struct I2sPdmRxConfig* config);
/**
* @brief See I2sControllerApi::disable_direction. Falls back to the full reset() if the
* driver doesn't implement direction-aware teardown.
* @param[in] device the I2S controller device
* @param[in] is_input true to disable the RX channel, false to disable the TX channel
* @retval ERROR_NONE when the operation was successful
*/
error_t i2s_controller_disable_direction(struct Device* device, bool is_input);
extern const struct DeviceType I2S_CONTROLLER_TYPE;
#ifdef __cplusplus
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: Apache-2.0
#include <tactility/drivers/audio_codec.h>
#include <tactility/error.h>
#include <tactility/device.h>
#define AUDIO_CODEC_DRIVER_API(driver) ((struct AudioCodecApi*)driver->api)
extern "C" {
error_t audio_codec_open(Device* device, const struct AudioCodecStreamConfig* config) {
const auto* driver = device_get_driver(device);
return AUDIO_CODEC_DRIVER_API(driver)->open(device, config);
}
error_t audio_codec_close(Device* device) {
const auto* driver = device_get_driver(device);
return AUDIO_CODEC_DRIVER_API(driver)->close(device);
}
error_t audio_codec_read(Device* device, void* data, size_t data_size, size_t* bytes_read, TickType_t timeout) {
const auto* driver = device_get_driver(device);
return AUDIO_CODEC_DRIVER_API(driver)->read(device, data, data_size, bytes_read, timeout);
}
error_t audio_codec_write(Device* device, const void* data, size_t data_size, size_t* bytes_written, TickType_t timeout) {
const auto* driver = device_get_driver(device);
return AUDIO_CODEC_DRIVER_API(driver)->write(device, data, data_size, bytes_written, timeout);
}
error_t audio_codec_set_volume(Device* device, AudioCodecDirection direction, float volume_percent) {
const auto* driver = device_get_driver(device);
return AUDIO_CODEC_DRIVER_API(driver)->set_volume(device, direction, volume_percent);
}
error_t audio_codec_get_volume(Device* device, AudioCodecDirection direction, float* volume_percent) {
const auto* driver = device_get_driver(device);
return AUDIO_CODEC_DRIVER_API(driver)->get_volume(device, direction, volume_percent);
}
error_t audio_codec_set_mute(Device* device, AudioCodecDirection direction, bool muted) {
const auto* driver = device_get_driver(device);
return AUDIO_CODEC_DRIVER_API(driver)->set_mute(device, direction, muted);
}
error_t audio_codec_get_mute(Device* device, AudioCodecDirection direction, bool* muted) {
const auto* driver = device_get_driver(device);
return AUDIO_CODEC_DRIVER_API(driver)->get_mute(device, direction, muted);
}
error_t audio_codec_get_native_sample_rate(Device* device, AudioCodecDirection direction, uint32_t* rate_hz) {
const auto* driver = device_get_driver(device);
return AUDIO_CODEC_DRIVER_API(driver)->get_native_sample_rate(device, direction, rate_hz);
}
error_t audio_codec_get_native_channels(Device* device, AudioCodecDirection direction, uint8_t* channels) {
const auto* driver = device_get_driver(device);
return AUDIO_CODEC_DRIVER_API(driver)->get_native_channels(device, direction, channels);
}
error_t audio_codec_get_capabilities(Device* device, AudioCodecDirection* supported_directions) {
const auto* driver = device_get_driver(device);
return AUDIO_CODEC_DRIVER_API(driver)->get_capabilities(device, supported_directions);
}
error_t audio_codec_get_input_gain_multiplier(Device* device, float* gain) {
const auto* driver = device_get_driver(device);
if (AUDIO_CODEC_DRIVER_API(driver)->get_input_gain_multiplier == nullptr) {
*gain = 1.0f;
return ERROR_NONE;
}
return AUDIO_CODEC_DRIVER_API(driver)->get_input_gain_multiplier(device, gain);
}
const struct DeviceType AUDIO_CODEC_TYPE {
.name = "audio-codec"
};
}
@@ -0,0 +1,79 @@
// SPDX-License-Identifier: Apache-2.0
#include <tactility/drivers/audio_stream.h>
#include <tactility/error.h>
#include <tactility/device.h>
#define AUDIO_STREAM_DRIVER_API(driver) ((struct AudioStreamApi*)driver->api)
extern "C" {
error_t audio_stream_open_input(Device* device, const struct AudioStreamConfig* config, AudioStreamHandle* outHandle) {
const auto* driver = device_get_driver(device);
return AUDIO_STREAM_DRIVER_API(driver)->open_input(device, config, outHandle);
}
error_t audio_stream_open_output(Device* device, const struct AudioStreamConfig* config, AudioStreamHandle* outHandle) {
const auto* driver = device_get_driver(device);
return AUDIO_STREAM_DRIVER_API(driver)->open_output(device, config, outHandle);
}
error_t audio_stream_read(AudioStreamHandle handle, void* data, size_t data_size, size_t* bytes_read, TickType_t timeout) {
const auto* driver = device_get_driver(handle->device);
return AUDIO_STREAM_DRIVER_API(driver)->read(handle, data, data_size, bytes_read, timeout);
}
error_t audio_stream_write(AudioStreamHandle handle, const void* data, size_t data_size, size_t* bytes_written, TickType_t timeout) {
const auto* driver = device_get_driver(handle->device);
return AUDIO_STREAM_DRIVER_API(driver)->write(handle, data, data_size, bytes_written, timeout);
}
error_t audio_stream_close(AudioStreamHandle handle) {
const auto* driver = device_get_driver(handle->device);
return AUDIO_STREAM_DRIVER_API(driver)->close(handle);
}
error_t audio_stream_set_volume(Device* device, AudioCodecDirection direction, float volume_percent) {
const auto* driver = device_get_driver(device);
return AUDIO_STREAM_DRIVER_API(driver)->set_volume(device, direction, volume_percent);
}
error_t audio_stream_get_volume(Device* device, AudioCodecDirection direction, float* volume_percent) {
const auto* driver = device_get_driver(device);
return AUDIO_STREAM_DRIVER_API(driver)->get_volume(device, direction, volume_percent);
}
error_t audio_stream_set_mute(Device* device, AudioCodecDirection direction, bool muted) {
const auto* driver = device_get_driver(device);
return AUDIO_STREAM_DRIVER_API(driver)->set_mute(device, direction, muted);
}
error_t audio_stream_get_mute(Device* device, AudioCodecDirection direction, bool* muted) {
const auto* driver = device_get_driver(device);
return AUDIO_STREAM_DRIVER_API(driver)->get_mute(device, direction, muted);
}
error_t audio_stream_set_enabled(Device* device, AudioCodecDirection direction, bool enabled) {
const auto* driver = device_get_driver(device);
return AUDIO_STREAM_DRIVER_API(driver)->set_enabled(device, direction, enabled);
}
error_t audio_stream_get_enabled(Device* device, AudioCodecDirection direction, bool* enabled) {
const auto* driver = device_get_driver(device);
return AUDIO_STREAM_DRIVER_API(driver)->get_enabled(device, direction, enabled);
}
error_t audio_stream_is_supported(Device* device, AudioCodecDirection direction, bool* supported) {
const auto* driver = device_get_driver(device);
return AUDIO_STREAM_DRIVER_API(driver)->is_supported(device, direction, supported);
}
error_t audio_stream_set_change_callback(Device* device, AudioStreamChangeCallback callback, void* user_data) {
const auto* driver = device_get_driver(device);
return AUDIO_STREAM_DRIVER_API(driver)->set_change_callback(device, callback, user_data);
}
const struct DeviceType AUDIO_STREAM_TYPE {
.name = "audio-stream"
};
}
@@ -38,6 +38,20 @@ error_t i2s_controller_set_rx_tdm_config(struct Device* device, const struct I2s
return I2S_DRIVER_API(driver)->set_rx_tdm_config(device, config);
}
error_t i2s_controller_set_rx_pdm_config(struct Device* device, const struct I2sPdmRxConfig* config) {
const auto* driver = device_get_driver(device);
if (!I2S_DRIVER_API(driver)->set_rx_pdm_config) return ERROR_NOT_SUPPORTED;
return I2S_DRIVER_API(driver)->set_rx_pdm_config(device, config);
}
error_t i2s_controller_disable_direction(struct Device* device, bool isInput) {
const auto* driver = device_get_driver(device);
if (!I2S_DRIVER_API(driver)->disable_direction) {
return I2S_DRIVER_API(driver)->reset(device);
}
return I2S_DRIVER_API(driver)->disable_direction(device, isInput);
}
const struct DeviceType I2S_CONTROLLER_TYPE {
.name = "i2s-controller"
};
+28
View File
@@ -4,6 +4,8 @@
#include <tactility/concurrent/timer.h>
#include <tactility/device.h>
#include <tactility/driver.h>
#include <tactility/drivers/audio_codec.h>
#include <tactility/drivers/audio_stream.h>
#include <tactility/drivers/bluetooth.h>
#include <tactility/drivers/bluetooth_serial.h>
#include <tactility/drivers/bluetooth_midi.h>
@@ -80,6 +82,32 @@ const struct ModuleSymbol KERNEL_SYMBOLS[] = {
DEFINE_MODULE_SYMBOL(driver_is_compatible),
DEFINE_MODULE_SYMBOL(driver_find_compatible),
DEFINE_MODULE_SYMBOL(driver_get_device_type),
// drivers/audio_codec
DEFINE_MODULE_SYMBOL(audio_codec_open),
DEFINE_MODULE_SYMBOL(audio_codec_close),
DEFINE_MODULE_SYMBOL(audio_codec_read),
DEFINE_MODULE_SYMBOL(audio_codec_write),
DEFINE_MODULE_SYMBOL(audio_codec_set_volume),
DEFINE_MODULE_SYMBOL(audio_codec_get_volume),
DEFINE_MODULE_SYMBOL(audio_codec_set_mute),
DEFINE_MODULE_SYMBOL(audio_codec_get_mute),
DEFINE_MODULE_SYMBOL(audio_codec_get_native_sample_rate),
DEFINE_MODULE_SYMBOL(audio_codec_get_native_channels),
DEFINE_MODULE_SYMBOL(audio_codec_get_capabilities),
DEFINE_MODULE_SYMBOL(AUDIO_CODEC_TYPE),
// drivers/audio_stream
DEFINE_MODULE_SYMBOL(audio_stream_open_input),
DEFINE_MODULE_SYMBOL(audio_stream_open_output),
DEFINE_MODULE_SYMBOL(audio_stream_read),
DEFINE_MODULE_SYMBOL(audio_stream_write),
DEFINE_MODULE_SYMBOL(audio_stream_close),
DEFINE_MODULE_SYMBOL(audio_stream_set_volume),
DEFINE_MODULE_SYMBOL(audio_stream_get_volume),
DEFINE_MODULE_SYMBOL(audio_stream_set_mute),
DEFINE_MODULE_SYMBOL(audio_stream_get_mute),
DEFINE_MODULE_SYMBOL(audio_stream_set_enabled),
DEFINE_MODULE_SYMBOL(audio_stream_get_enabled),
DEFINE_MODULE_SYMBOL(AUDIO_STREAM_TYPE),
// drivers/gpio_controller
DEFINE_MODULE_SYMBOL(gpio_descriptor_acquire),
DEFINE_MODULE_SYMBOL(gpio_descriptor_release),