#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);

/* Mount the microSD card at /sdcard on demand (best-effort, idempotent) and
 * report whether it is mounted. Unlike playback, this does NOT depend on the
 * hook state — it lets the REST layer stage a voice pack onto the SD while the
 * handset is down. Returns true if /sdcard is usable. */
bool audio_ensure_sd(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
