aa7ae277ed
- hook polarity active-HIGH + auto-resync (was LOW) - ring cadence FT 1.5s ON / 3.5s OFF - DTMF Goertzel decoder (dtmf.c/h) + rotary debounce - LISTEN half-duplex: capture → /v1/voice/reply → play - WAV playback buffered PSRAM + mono→stereo upmix - SPIFFS mount at boot for pre-loaded greetings - ES8388: DAC digital vol + mic PGA + GPIO INPUT_OUTPUT - turn_client multipart + 90s timeout + fixed routing - debug endpoints: vol/dacvol/offhook/getfile/hookmon
94 lines
3.6 KiB
C
94 lines
3.6 KiB
C
#pragma once
|
|
/*
|
|
* audio.h — I2S + ES8388 audio interface for the PLIP voice annex.
|
|
*
|
|
* Provides:
|
|
* - es8388 + I2S initialisation (called once from app_main)
|
|
* - Blocking 440 Hz tone (Phase A proof)
|
|
* - WAV file playback from SD or embedded asset
|
|
* - Ring tone (400/450 Hz cadence) for Phase D
|
|
* - Async playback command queue (used by cmd_exec / ESP-NOW)
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include "esp_err.h"
|
|
#include "driver/i2s_std.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* Initialise ES8388 and I2S channels. Must be called before any other
|
|
* audio_* function. Returns ESP_OK on success. */
|
|
esp_err_t audio_init(void);
|
|
|
|
/* Return the speaker I2S TX channel handle (used by cmd_exec for WAV play). */
|
|
i2s_chan_handle_t audio_spk_handle(void);
|
|
|
|
/* Play a pure sine tone for duration_ms (blocking). */
|
|
void audio_play_tone(float frequency_hz, int duration_ms);
|
|
|
|
/* Enqueue an async play command. path may be:
|
|
* - "/sdcard/<file>.wav" — read from SD
|
|
* - "embedded://" — built-in C5-E5-G5 cue
|
|
* - "" or NULL — same as embedded://
|
|
* Returns ESP_OK if the command was enqueued (non-blocking from any task). */
|
|
esp_err_t audio_play_async(const char *path);
|
|
|
|
/* Stop current playback immediately. */
|
|
esp_err_t audio_stop(void);
|
|
|
|
/* True while the audio worker is playing a clip (tone/WAV). The conversation
|
|
* LISTEN loop polls this to stay half-duplex: never capture while playing
|
|
* (avoids the earpiece→mic feedback that saturated the line). */
|
|
bool audio_is_playing(void);
|
|
|
|
/* Start ring tone cadence (ON 1s / OFF 2s) at ~440 Hz. Continues until
|
|
* audio_stop() is called. Non-blocking — spawns an internal task. */
|
|
esp_err_t audio_ring_start(void);
|
|
|
|
/* Enable or disable the power amplifier (GPIO21 PA_ENABLE).
|
|
* Call audio_pa_set(true) on off-hook, audio_pa_set(false) on on-hook.
|
|
* ring_start forces PA on internally; ring_stop calls audio_pa_set(false)
|
|
* only if the handset is on-hook. */
|
|
void audio_pa_set(bool enable);
|
|
|
|
/*
|
|
* Capture microphone audio and encode as WAV (16 kHz, mono, S16-LE).
|
|
*
|
|
* out : caller-provided buffer (must be >= 44 + PCM bytes)
|
|
* out_max : size of out in bytes
|
|
* max_ms : hard cap on capture duration in milliseconds
|
|
* silence_ms: milliseconds of silence after voice onset to trigger stop
|
|
*
|
|
* Returns total bytes written (44-byte WAV header + PCM), or -1 on error.
|
|
* Uses half-duplex: disables TX speaker during capture and re-enables it
|
|
* on return. Safe to call from any task; not reentrant.
|
|
*/
|
|
int audio_capture_wav(uint8_t *out, size_t out_max, int max_ms, int silence_ms);
|
|
|
|
/*
|
|
* Streaming capture API — avoids a large output buffer by letting the caller
|
|
* write chunks incrementally (e.g. directly into a TCP socket).
|
|
*
|
|
* Usage:
|
|
* audio_capture_begin(max_ms, silence_ms) — enable RX, returns 0 on OK
|
|
* audio_capture_read_frame(mono_out, n_samples, rms_sq_out)
|
|
* — read one 20 ms frame (mono S16)
|
|
* fills n_samples mono samples,
|
|
* sets *rms_sq_out (energy metric)
|
|
* returns actual samples read, 0=timeout, -1=error
|
|
* audio_capture_end() — disable RX, re-enable TX
|
|
*
|
|
* n_samples must be 320 (= SAMPLE_RATE/1000*20, one 20 ms frame).
|
|
* The caller is responsible for VAD and stop logic.
|
|
*/
|
|
int audio_capture_begin(int max_ms, int silence_ms);
|
|
int audio_capture_read_frame(int16_t *mono_out, int n_samples, int64_t *rms_sq_out);
|
|
void audio_capture_end(void);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|