Add UDP listener for lip sync amplitude from voice service

Listens on UDP :8782 for bare integer amplitude values (0-100),
forwards directly to Pico serial as fire-and-forget jaw commands.
Runs as daemon thread alongside the HTTP server.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Alex
2026-01-31 22:10:41 -06:00
parent f0767772f5
commit 23becfec39

View File

@@ -15,9 +15,11 @@ API:
POST /state - Set state {"state": "listening"}
POST /jaw/level - Set jaw level {"level": 0-100}
POST /jaw/mode - Set jaw mode {"mode": "talking"}
UDP :8782 - Jaw amplitude (bare integer, fire-and-forget lip sync)
"""
import time
import socket
import threading
import json
import signal
@@ -26,6 +28,7 @@ import serial
# === Configuration ===
HTTP_PORT = 8781
UDP_PORT = 8782
SERIAL_PORT = "/dev/ttyACM0"
SERIAL_BAUD = 115200
@@ -152,6 +155,24 @@ class LightAPIHandler(BaseHTTPRequestHandler):
self.send_header('Access-Control-Allow-Headers', 'Content-Type')
self.end_headers()
# === UDP Amplitude Listener ===
def run_udp_listener():
"""Listen for jaw amplitude via UDP (fire-and-forget from voice service)."""
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('0.0.0.0', UDP_PORT))
sock.settimeout(1.0)
print(f"[LIGHT] UDP listener on port {UDP_PORT}")
while running:
try:
data, _ = sock.recvfrom(16)
level = max(0, min(100, int(data)))
send_amplitude(level)
except socket.timeout:
continue
except (ValueError, Exception):
pass
sock.close()
# === Signal Handler ===
def signal_handler(sig, frame):
global running
@@ -173,6 +194,10 @@ def main():
# Set initial mood on Pico
send_mode_command("mood idle")
# Start UDP listener for lip sync amplitude
udp_thread = threading.Thread(target=run_udp_listener, daemon=True)
udp_thread.start()
server = HTTPServer(('0.0.0.0', HTTP_PORT), LightAPIHandler)
print(f"[LIGHT] HTTP API listening on port {HTTP_PORT}")
print("[LIGHT] Service ready")