Files
raspberry-pi-mixer/src/network/run.py
T
shawn 9cd8292acc
Lint & Validate / lint (push) Has been cancelled
Phase 1-4: Audio stack, mixer engine, MIDI, and network API
P2-R1: ALSA + JACK2 low-latency config (scripts, quirks, tuning)
P2-R2: Carla integration (build scripts, 8ch rack config, NAM LV2 support)
P2-R3: Plugin manager, categories, blacklist, NAM model support
P3-R1: Mixer DSP engine (channel strip, routing matrix, bus mgr, automation)
P4-R1: MIDI engine (learn mode, clock sync, HID discovery, mapping store)
P4-R2: Network API (OSC server, FastAPI REST, WebSocket, auth, rate limiter)
P5-R1: Touchscreen UI evaluation + main entry point
docs: Audio stack, Carla integration, MIDI support, UI evaluation
tests: Full test suite (292 passing)
2026-05-19 20:39:17 -04:00

121 lines
3.2 KiB
Python

#!/usr/bin/env python3
"""Standalone network API server for the RPi Audio Mixer.
Starts the OSC, REST, and WebSocket servers. The DSP engine must
be running with Carla and JACK for full functionality.
Usage:
python -m src.network.run [--host HOST] [--port PORT] [--osc-port PORT]
Environment:
MIXER_API_KEY — API key for authentication (default: mixer-local)
"""
import argparse
import asyncio
import logging
import os
import signal
import sys
# Add project root to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from src.mixer.dsp_engine import DSPEngine, DSPEngineConfig
from src.network.server import NetworkServer
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
datefmt="%H:%M:%S",
)
logger = logging.getLogger("mixer-network")
def parse_args():
parser = argparse.ArgumentParser(
description="RPi Audio Mixer — Network API Server",
)
parser.add_argument(
"--host", default="0.0.0.0",
help="HTTP/WS listen address (default: 0.0.0.0)",
)
parser.add_argument(
"--port", type=int, default=8080,
help="HTTP/WS listen port (default: 8080)",
)
parser.add_argument(
"--osc-port", type=int, default=9001,
help="OSC UDP listen port (default: 9001)",
)
parser.add_argument(
"--channels", type=int, default=16,
help="Number of mixer channels (default: 16)",
)
parser.add_argument(
"--no-osc", action="store_true",
help="Disable OSC server",
)
parser.add_argument(
"--api-key",
help="API key (overrides MIXER_API_KEY env var)",
)
return parser.parse_args()
async def main():
args = parse_args()
# API key
if args.api_key:
os.environ["MIXER_API_KEY"] = args.api_key
# Create DSP engine (simplified — no Carla OSC connection)
config = DSPEngineConfig(
num_channels=args.channels,
osc_enabled=False, # Don't connect to Carla in standalone mode
jack_routing_enabled=False, # Don't touch JACK connections in standalone
)
engine = DSPEngine(config)
engine.start(connect_osc=False)
# Create network server
server = NetworkServer(
engine=engine,
osc_host=args.host,
osc_port=args.osc_port if not args.no_osc else 0,
http_host=args.host,
http_port=args.port,
)
# Graceful shutdown
shutdown_event = asyncio.Event()
def _shutdown(sig=None, frame=None):
logger.info("Shutdown signal received")
shutdown_event.set()
signal.signal(signal.SIGINT, _shutdown)
signal.signal(signal.SIGTERM, _shutdown)
# Start server
await server.start()
if not args.no_osc:
logger.info("OSC server: udp://%s:%d", args.host, args.osc_port)
logger.info("REST API: http://%s:%d/api/v1", args.host, args.port)
logger.info("WebSocket: ws://%s:%d/ws", args.host, args.port)
logger.info("API Key: %s", os.environ.get("MIXER_API_KEY", "mixer-local"))
# Wait for shutdown
await shutdown_event.wait()
# Stop
await server.stop()
engine.stop()
logger.info("Server stopped")
if __name__ == "__main__":
asyncio.run(main())