deltacast-sdi-recorder/backend/app/main.py

116 lines
3.2 KiB
Python
Raw Normal View History

2026-04-14 09:21:08 -04:00
"""Main FastAPI application for Deltacast SDI Recorder."""
import asyncio
import json
import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from pathlib import Path
from .config import Settings
from .recorders.recorder import RecorderManager
from .recorders.scte35 import SCTE35Manager
from .utils.hls import HLSPreviewManager
from .api.routes import router
from .api import routes as routes_module
2026-04-14 09:21:08 -04:00
from .api.websocket import ConnectionManager
logger = logging.getLogger(__name__)
settings = Settings()
recorder_manager: RecorderManager | None = None
scte35_manager: SCTE35Manager | None = None
hls_manager: HLSPreviewManager | None = None
connection_manager = ConnectionManager()
@asynccontextmanager
async def lifespan(app: FastAPI):
global recorder_manager, scte35_manager, hls_manager
2026-04-14 09:21:08 -04:00
logger.info("Starting Deltacast SDI Recorder...")
2026-04-14 09:21:08 -04:00
recorder_manager = RecorderManager(settings)
recorder_manager.initialize()
2026-04-14 09:21:08 -04:00
scte35_manager = SCTE35Manager()
2026-04-14 09:21:08 -04:00
hls_manager = HLSPreviewManager(settings)
# Inject all managers into routes module
2026-04-14 09:21:08 -04:00
routes_module.recorder_manager = recorder_manager
routes_module.scte35_manager = scte35_manager
routes_module.hls_manager = hls_manager
2026-04-14 09:21:08 -04:00
status_task = asyncio.create_task(broadcast_port_status())
logger.info(f"Deltacast SDI Recorder started — {settings.deltacast_port_count} ports")
yield
2026-04-14 09:21:08 -04:00
logger.info("Shutting down Deltacast SDI Recorder...")
status_task.cancel()
try:
await status_task
except asyncio.CancelledError:
pass
2026-04-14 09:21:08 -04:00
for port_index in range(settings.deltacast_port_count):
await recorder_manager.stop_recording(port_index)
await hls_manager.stop_preview(port_index)
2026-04-14 09:21:08 -04:00
logger.info("Shutdown complete")
async def broadcast_port_status():
while True:
try:
if recorder_manager is not None:
statuses = recorder_manager.get_all_status()
data = {
"type": "port_status",
"ports": [s.model_dump() for s in statuses]
}
await connection_manager.broadcast(data)
except Exception as e:
logger.error(f"Error broadcasting port status: {e}")
await asyncio.sleep(1)
app = FastAPI(
title="Deltacast SDI Recorder",
description="Web GUI for Deltacast SDI capture card recording",
version="1.0.0",
lifespan=lifespan
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(router)
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await connection_manager.connect(websocket)
try:
while True:
data = await websocket.receive_text()
except WebSocketDisconnect:
connection_manager.disconnect(websocket)
@app.get("/hls/{filename}")
async def serve_hls(filename: str):
hls_path = Path("/tmp/hls") / filename
if not hls_path.exists():
raise HTTPException(status_code=404, detail="HLS file not found")
return FileResponse(str(hls_path))