| name | tuyaopen/peripheral-audio |
| description | TDL audio codec usage for TuyaOpen: discover the audio device, capture microphone PCM frames via callback, play PCM back to the speaker, and set volume. 音频、麦克风、录音、播放、喇叭、扬声器、speaker、mic、声音、语音、codec。 |
| when_to_use | Use when the user wants to record from the microphone, play audio to the speaker, adjust volume, or build a voice / audio-loopback feature. |
| id | peripheral-audio |
| surfaces | ["embedded"] |
| tags | ["audio","codec","microphone","speaker","mic","pcm","voice"] |
TuyaOpen TDL Audio
One TDL audio device covers both the microphone (capture) and the speaker
(playback). Capture is callback-driven; playback is a blocking write.
Driver Registration (TDD)
Decide by adaptation, not by whether the SDK has the driver:
- Board-adapted audio (in
board-context.md) → board_register_hardware()
registers the codec; the app only uses the TDL API below — don't register it yourself.
- Externally-attached codec (the user wired their own — NOT in
board-context.md) → register it yourself in usr_board (see
usr-board/SKILL.md), reusing the SDK's codec driver.
board_register_hardware() only wires codecs the board adapted.
Headers
#include "tdl_audio_manage.h"
Usage Template
#include "tal_api.h"
#include "tkl_output.h"
#include "tkl_memory.h"
#include "tuya_ringbuf.h"
#include "tdl_audio_manage.h"
static TDL_AUDIO_HANDLE_T s_audio_hdl = NULL;
static TDL_AUDIO_INFO_T s_audio_info = {0};
static void app_audio_mic_cb(TDL_AUDIO_FRAME_FORMAT_E type,
TDL_AUDIO_STATUS_E status,
uint8_t *data, uint32_t len)
{
(void)type; (void)status;
}
void app_audio_init(void)
{
if (OPRT_OK != tdl_audio_find(AUDIO_CODEC_NAME, &s_audio_hdl)) {
PR_ERR("audio '%s' not found", AUDIO_CODEC_NAME);
return;
}
if (OPRT_OK != tdl_audio_open(s_audio_hdl, app_audio_mic_cb)) {
PR_ERR("audio open failed");
return;
}
tdl_audio_get_info(s_audio_hdl, &s_audio_info);
PR_NOTICE("audio: rate=%u ch=%u bits=%u tm=%ums frame=%u",
s_audio_info.sample_rate, s_audio_info.sample_ch_num,
s_audio_info.sample_bits, s_audio_info.sample_tm_ms,
s_audio_info.frame_size);
tdl_audio_volume_set(s_audio_hdl, 60);
}
void app_audio_play(uint8_t *pcm, uint32_t len)
{
tdl_audio_play(s_audio_hdl, pcm, len);
}
API Reference
| Function | Description |
|---|
tdl_audio_find(name, &hdl) | Find the registered audio device (AUDIO_CODEC_NAME) |
tdl_audio_open(hdl, mic_cb) | Open device; mic_cb (type TDL_AUDIO_MIC_CB) receives capture frames (NULL = playback-only) |
tdl_audio_get_info(hdl, &info) | Read sample_rate, sample_ch_num, sample_bits, sample_tm_ms, frame_size |
tdl_audio_play(hdl, data, len) | Play PCM data to the speaker |
tdl_audio_play_stop(hdl) | Stop / flush current playback |
tdl_audio_volume_set(hdl, vol) | Set speaker volume, vol 0–100 |
tdl_audio_close(hdl) | Close device and release resources |
Mic Callback: type & status
TDL_AUDIO_FRAME_FORMAT_PCM
TDL_AUDIO_FRAME_FORMAT_SPEEX
TDL_AUDIO_FRAME_FORMAT_OPUS
TDL_AUDIO_FRAME_FORMAT_MP3
TDL_AUDIO_STATUS_VAD_START
TDL_AUDIO_STATUS_VAD_END
TDL_AUDIO_STATUS_RECEIVING
TDL_AUDIO_STATUS_RECV_FINISH
Record → Playback (loopback) pattern
The mic callback runs in driver context — never play from inside it. Buffer the
PCM in a tuya_ringbuf, then drain it from your own task:
uint32_t buf_len = (record_ms / s_audio_info.sample_tm_ms) * s_audio_info.frame_size;
tuya_ring_buff_create(buf_len, OVERFLOW_PSRAM_STOP_TYPE, &s_rb);
Large buffers belong in PSRAM (tkl_system_psram_malloc / tkl_system_psram_free).
Enable Macro and NAME Macro
CONFIG_ENABLE_AUDIO_CODECS=y # enables the audio codec subsystem
CONFIG_AUDIO_CODEC_NAME="audio" # device name passed to tdl_audio_find()
CONFIG_AUDIO_CODECS_NUM=1 # number of codecs
For board-adapted audio the board Kconfig already selects these — do NOT
write them. Only set them when adding a custom codec via usr_board.
AUDIO_CODEC_NAME is the name passed to tdl_audio_find().
Reference Example
examples/peripherals/audio_codecs/