Simplify client modes and add VAD retention policy
Some checks failed
Build and Push EVS Bridge Image / docker (push) Has been cancelled

This commit is contained in:
Kai
2026-02-13 17:09:54 +01:00
parent d4d4c7224b
commit 5f20b38088
5 changed files with 57 additions and 53 deletions

View File

@@ -6,7 +6,6 @@
#include "secrets.h"
using namespace websockets;
static constexpr bool kDefaultStreamMode = EVS_DEFAULT_STREAM_MODE;
static constexpr bool kSerialCommandEcho = EVS_SERIAL_COMMAND_ECHO;
static constexpr bool kMicUseRightChannel = EVS_MIC_USE_RIGHT_CHANNEL;
static constexpr int kMicS24ToS16Shift = EVS_MIC_S24_TO_S16_SHIFT;
@@ -38,8 +37,7 @@ static constexpr float PI_F = 3.14159265358979323846f;
enum class DeviceMode : uint8_t {
Idle,
StreamToServer, // Placeholder: ship PCM to remote STT/LLM/TTS service
LocalLoopback, // Debug mode: mic directly to speaker
StreamToServer, // Ship PCM to remote STT/LLM/TTS service
};
static DeviceMode g_mode = DeviceMode::Idle;
@@ -57,6 +55,8 @@ static size_t g_rxHead = 0;
static size_t g_rxTail = 0;
static size_t g_rxCount = 0;
static void setMode(DeviceMode mode);
static bool initMicI2s() {
const i2s_config_t i2sConfig = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX),
@@ -207,18 +207,18 @@ static void onWsMessageCallback(WebsocketsMessage message) {
static void onWsEventCallback(WebsocketsEvent event, String) {
if (event == WebsocketsEvent::ConnectionOpened) {
g_wsConnected = true;
if (g_mode == DeviceMode::StreamToServer && !g_streamingActive) {
g_ws.send("{\"type\":\"start\"}");
g_streamingActive = true;
playStartTone();
}
// Connection-driven mode: always stream on connect.
setMode(DeviceMode::StreamToServer);
Serial.println("WS connected");
} else if (event == WebsocketsEvent::ConnectionClosed) {
if (g_streamingActive) {
playStopTone();
}
const bool wasStreaming = g_streamingActive;
g_wsConnected = false;
g_streamingActive = false;
// Connection-driven mode: always idle on disconnect.
setMode(DeviceMode::Idle);
if (wasStreaming) {
playStopTone();
}
Serial.println("WS disconnected");
}
}
@@ -352,13 +352,11 @@ static void serviceSpeaker() {
static void printHelp() {
Serial.println();
Serial.println("Commands:");
Serial.println(" i = idle");
Serial.println(" s = stream mode");
Serial.println(" l = local loopback mode");
Serial.println(" p = print network status");
Serial.println(" h = help");
Serial.print("Default on boot: ");
Serial.println(kDefaultStreamMode ? "StreamToServer" : "LocalLoopback");
Serial.println("Connection policy:");
Serial.println(" connect -> StreamToServer (start)");
Serial.println(" disconnect -> Idle");
}
static void handleSerialCommands() {
@@ -368,22 +366,15 @@ static void handleSerialCommands() {
Serial.print("RX cmd: ");
Serial.println(c);
}
if (c == 'i') {
setMode(DeviceMode::Idle);
Serial.println("Mode -> Idle");
} else if (c == 's') {
setMode(DeviceMode::StreamToServer);
Serial.println("Mode -> StreamToServer");
} else if (c == 'l') {
setMode(DeviceMode::LocalLoopback);
Serial.println("Mode -> LocalLoopback");
} else if (c == 'p') {
if (c == 'p') {
Serial.print("WiFi: ");
Serial.print((WiFi.status() == WL_CONNECTED) ? "connected " : "disconnected ");
Serial.print("IP=");
Serial.println(WiFi.localIP());
Serial.print("WS: ");
Serial.println(g_wsConnected ? "connected" : "disconnected");
Serial.print("Mode: ");
Serial.println((g_mode == DeviceMode::StreamToServer) ? "StreamToServer" : "Idle");
} else if (c == 'h') {
printHelp();
} else if (c != '\r' && c != '\n') {
@@ -410,11 +401,8 @@ void setup() {
g_ws.onEvent(onWsEventCallback);
g_nextOutUs = micros();
if (kDefaultStreamMode) {
setMode(DeviceMode::StreamToServer);
} else {
setMode(DeviceMode::LocalLoopback);
}
// Wait in idle until WS connect event switches to StreamToServer.
setMode(DeviceMode::Idle);
Serial.println("Audio init ok");
Serial.println("Set local environment values in include/secrets.h");
printHelp();
@@ -422,10 +410,8 @@ void setup() {
void loop() {
handleSerialCommands();
if (g_mode != DeviceMode::LocalLoopback) {
ensureConnectivity();
g_ws.poll();
}
ensureConnectivity();
g_ws.poll();
serviceSpeaker();
size_t bytesRead = 0;
@@ -444,10 +430,6 @@ void loop() {
if (g_mode == DeviceMode::StreamToServer) {
handleFrameForServer(pcm16, sampleCount);
publishMicTelemetryIfDue(pcm16, sampleCount);
} else if (g_mode == DeviceMode::LocalLoopback) {
for (size_t i = 0; i < sampleCount; ++i) {
enqueuePcmSample(pcm16[i]);
}
} else {
// idle
}