feat(plip): tones module — France Télécom dial/busy/ringback
This commit is contained in:
@@ -7,6 +7,9 @@ idf_component_register(
|
||||
"cmd_exec.c"
|
||||
"hook_client.c"
|
||||
"phone.c"
|
||||
"tones.c"
|
||||
"dialer.c"
|
||||
"conversation.c"
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES
|
||||
driver
|
||||
@@ -14,6 +17,7 @@ idf_component_register(
|
||||
esp_http_client
|
||||
esp_http_server
|
||||
esp_netif
|
||||
esp_timer
|
||||
esp_wifi
|
||||
json
|
||||
nvs_flash
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* tones.c — France Télécom telephone tones (dial / busy / ringback).
|
||||
*
|
||||
* Generates 440 Hz sinusoid with on/off cadence written directly to the
|
||||
* I2S speaker handle (stereo — ES8388 requires L+R pairs).
|
||||
*
|
||||
* Cadences (all at 440 Hz):
|
||||
* DIAL : continuous
|
||||
* BUSY : 0.5 s on / 0.5 s off (1 s cycle)
|
||||
* RINGBACK : 1.5 s on / 3.5 s off (5 s cycle)
|
||||
*/
|
||||
|
||||
#include "tones.h"
|
||||
#include "audio.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/i2s_std.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define TAG "tones"
|
||||
|
||||
typedef enum { TONE_NONE, TONE_DIAL, TONE_BUSY, TONE_RINGBACK } tone_mode_t;
|
||||
|
||||
static volatile tone_mode_t s_mode = TONE_NONE;
|
||||
static TaskHandle_t s_task = NULL;
|
||||
|
||||
#define SR 16000 /* sample rate (must match audio_init) */
|
||||
#define FRAME 320 /* 20 ms @ 16 kHz */
|
||||
|
||||
/*
|
||||
* Fill `n` stereo frames (L=R = 440 Hz sine) into buf.
|
||||
* buf must hold n * 2 int16_t (stereo interleaved).
|
||||
* ph: running phase accumulator (mono sample index).
|
||||
*/
|
||||
static void fill_440_stereo(int16_t *buf, int n, int *ph)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
int16_t v = (int16_t)(8000.0f * sinf(2.0f * (float)M_PI * 440.0f * (*ph) / SR));
|
||||
buf[i * 2] = v; /* L */
|
||||
buf[i * 2 + 1] = v; /* R */
|
||||
(*ph)++;
|
||||
}
|
||||
}
|
||||
|
||||
static void tone_task(void *a)
|
||||
{
|
||||
(void)a;
|
||||
/* Stereo buffer: FRAME mono samples × 2 channels × 2 bytes = FRAME*4 bytes */
|
||||
int16_t buf[FRAME * 2];
|
||||
int ph = 0;
|
||||
int64_t t = 0; /* ms elapsed in current tone state */
|
||||
|
||||
for (;;) {
|
||||
tone_mode_t m = s_mode;
|
||||
if (m == TONE_NONE) {
|
||||
vTaskDelay(pdMS_TO_TICKS(20));
|
||||
t = 0;
|
||||
ph = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool on = true;
|
||||
if (m == TONE_BUSY) {
|
||||
on = (t % 1000) < 500; /* 500ms on / 500ms off */
|
||||
} else if (m == TONE_RINGBACK) {
|
||||
on = (t % 5000) < 1500; /* 1.5s on / 3.5s off */
|
||||
}
|
||||
/* TONE_DIAL: always on */
|
||||
|
||||
if (on) {
|
||||
fill_440_stereo(buf, FRAME, &ph);
|
||||
} else {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
/* Keep phase accumulator advancing so pitch is smooth on resumption */
|
||||
ph += FRAME;
|
||||
}
|
||||
|
||||
size_t written = 0;
|
||||
i2s_channel_write(audio_spk_handle(), buf, sizeof(buf), &written, pdMS_TO_TICKS(500));
|
||||
t += 20; /* each frame = 20 ms */
|
||||
}
|
||||
}
|
||||
|
||||
static void ensure_task(void)
|
||||
{
|
||||
if (!s_task) {
|
||||
xTaskCreate(tone_task, "tones", 3072, NULL, 5, &s_task);
|
||||
ESP_LOGI(TAG, "tone_task created");
|
||||
}
|
||||
}
|
||||
|
||||
void tones_dialtone_start(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "dial tone start");
|
||||
audio_pa_set(true);
|
||||
ensure_task();
|
||||
s_mode = TONE_DIAL;
|
||||
}
|
||||
|
||||
void tones_busy_start(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "busy tone start");
|
||||
audio_pa_set(true);
|
||||
ensure_task();
|
||||
s_mode = TONE_BUSY;
|
||||
}
|
||||
|
||||
void tones_ringback_start(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "ringback tone start");
|
||||
audio_pa_set(true);
|
||||
ensure_task();
|
||||
s_mode = TONE_RINGBACK;
|
||||
}
|
||||
|
||||
void tones_stop(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "tones stop");
|
||||
s_mode = TONE_NONE;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include "esp_err.h"
|
||||
|
||||
void tones_dialtone_start(void); /* 440 Hz continuous */
|
||||
void tones_busy_start(void); /* 440 Hz 0.5s on/off */
|
||||
void tones_ringback_start(void); /* 440 Hz 1.5s/3.5s */
|
||||
void tones_stop(void);
|
||||
Reference in New Issue
Block a user