feat(audio): tonalite via audio_router
Composant audio_router cree : tache FreeRTOS 440 Hz, machine d'etat DIAL/BUSY/RINGBACK. Cable dans app_main, tonalite active au boot (PA ON confirme en serie).
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
idf_component_register(
|
||||
SRCS "audio_router.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES esp_driver_i2s bsp tone_gen hal_i2s
|
||||
)
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* audio_router.c — aiguillage des tonalités vers l'I2S (écouteur).
|
||||
* Adapté de plip_voice/main/tones.c : la génération de sinus est déléguée à
|
||||
* tone_gen ; l'écriture I2S passe par hal_i2s_spk_handle().
|
||||
* Cadences France Télécom (440 Hz) : DIAL continu, BUSY 500/500, RINGBACK 1500/3500.
|
||||
*/
|
||||
#include "audio_router.h"
|
||||
#include "tone_gen.h"
|
||||
#include "hal_i2s.h"
|
||||
#include "board_config.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/i2s_std.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define TAG "audio_router"
|
||||
|
||||
typedef enum { TONE_NONE, TONE_DIAL, TONE_BUSY, TONE_RINGBACK } tone_mode_t;
|
||||
|
||||
#define SR PLIP_SAMPLE_RATE /* 16000 — doit correspondre à hal_i2s */
|
||||
#define FRAME 320 /* 20 ms @ 16 kHz */
|
||||
#define TONE_AMPLITUDE 8000.0f
|
||||
#define TONE_FREQ_HZ 440.0f
|
||||
|
||||
static volatile tone_mode_t s_mode = TONE_NONE;
|
||||
static volatile bool s_tone_idle = true;
|
||||
static TaskHandle_t s_task = NULL;
|
||||
|
||||
static void tone_task(void *a)
|
||||
{
|
||||
(void)a;
|
||||
int16_t buf[FRAME * 2];
|
||||
uint32_t ph = 0;
|
||||
int64_t t = 0; /* ms écoulées dans l'état courant */
|
||||
|
||||
for (;;) {
|
||||
tone_mode_t m = s_mode;
|
||||
if (m == TONE_NONE) {
|
||||
s_tone_idle = true;
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
t = 0;
|
||||
ph = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool on = true;
|
||||
if (m == TONE_BUSY) {
|
||||
on = (t % 1000) < 500;
|
||||
} else if (m == TONE_RINGBACK) {
|
||||
on = (t % 5000) < 1500;
|
||||
}
|
||||
/* TONE_DIAL : toujours on */
|
||||
|
||||
if (on) {
|
||||
tone_gen_fill_stereo(buf, FRAME, &ph, TONE_FREQ_HZ, TONE_AMPLITUDE, SR);
|
||||
} else {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
ph += FRAME; /* garder la phase continue */
|
||||
}
|
||||
|
||||
size_t written = 0;
|
||||
s_tone_idle = false;
|
||||
i2s_channel_write(hal_i2s_spk_handle(), buf, sizeof(buf), &written,
|
||||
pdMS_TO_TICKS(50));
|
||||
t += 20;
|
||||
}
|
||||
}
|
||||
|
||||
void audio_router_init(void)
|
||||
{
|
||||
if (!s_task) {
|
||||
xTaskCreate(tone_task, "tones", 3072, NULL, 5, &s_task);
|
||||
ESP_LOGI(TAG, "tone task created");
|
||||
}
|
||||
}
|
||||
|
||||
void audio_router_dialtone_start(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "dial tone start");
|
||||
hal_audio_pa_set(true);
|
||||
audio_router_init();
|
||||
s_mode = TONE_DIAL;
|
||||
}
|
||||
|
||||
void audio_router_busy_start(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "busy tone start");
|
||||
hal_audio_pa_set(true);
|
||||
audio_router_init();
|
||||
s_mode = TONE_BUSY;
|
||||
}
|
||||
|
||||
void audio_router_ringback_start(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "ringback tone start");
|
||||
hal_audio_pa_set(true);
|
||||
audio_router_init();
|
||||
s_mode = TONE_RINGBACK;
|
||||
}
|
||||
|
||||
void audio_router_tones_stop(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "tones stop");
|
||||
s_mode = TONE_NONE;
|
||||
const int max_wait_ms = 200;
|
||||
int waited_ms = 0;
|
||||
while (!s_tone_idle && waited_ms < max_wait_ms) {
|
||||
vTaskDelay(pdMS_TO_TICKS(5));
|
||||
waited_ms += 5;
|
||||
}
|
||||
if (waited_ms >= max_wait_ms) {
|
||||
ESP_LOGW(TAG, "tones_stop: timeout waiting for tone task idle");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Create the tone task (idempotent). Call once after hal_i2s_init(). */
|
||||
void audio_router_init(void);
|
||||
|
||||
/* Start a continuous 440 Hz dial tone (enables PA). */
|
||||
void audio_router_dialtone_start(void);
|
||||
|
||||
/* Start the busy tone: 500 ms on / 500 ms off. */
|
||||
void audio_router_busy_start(void);
|
||||
|
||||
/* Start the ringback tone: 1500 ms on / 3500 ms off (France Télécom). */
|
||||
void audio_router_ringback_start(void);
|
||||
|
||||
/* Stop tones; waits (<=200 ms) until the tone task leaves i2s_channel_write. */
|
||||
void audio_router_tones_stop(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
idf_component_register(
|
||||
SRCS "app_main.c"
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES nvs_flash config_store hal_es8388 hal_i2s
|
||||
REQUIRES nvs_flash config_store hal_es8388 hal_i2s audio_router
|
||||
)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "freertos/task.h"
|
||||
#include "config_store.h"
|
||||
#include "hal_i2s.h"
|
||||
#include "audio_router.h"
|
||||
|
||||
static const char *TAG = "rtc_phone";
|
||||
|
||||
@@ -11,6 +12,9 @@ void app_main(void)
|
||||
ESP_LOGI(TAG, "RTC BL PHONE — socle ESP-IDF v5.4 (esp32 classique)");
|
||||
ESP_ERROR_CHECK(config_store_init());
|
||||
ESP_ERROR_CHECK(hal_i2s_init());
|
||||
audio_router_init();
|
||||
audio_router_dialtone_start();
|
||||
ESP_LOGI(TAG, "tonalite de numerotation demarree (combine decroche pour ecouter)");
|
||||
ESP_LOGI(TAG, "boot OK — Phase 2 HAL audio ES8388");
|
||||
while (true) {
|
||||
ESP_LOGI(TAG, "heartbeat");
|
||||
|
||||
Reference in New Issue
Block a user