9cd8292acc
Lint & Validate / lint (push) Has been cancelled
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)
121 lines
3.2 KiB
Python
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())
|