small optimizations, add comments
This commit is contained in:
@@ -75,6 +75,8 @@ stty -F /dev/ttyAMA3 -a | grep -o 'hupcl' || echo "-hupcl is set"
|
||||
# Audio latency
|
||||
if there is hearable audio error with aes67, tune sess.latency.msec in pipewire-aes67.conf
|
||||
|
||||
if latency is piling up something may be blocking the event loop in multicast_server.py - the event loop must never block at any time
|
||||
|
||||
---
|
||||
|
||||
After completing these steps, your device will be discoverable as `<hostname>.<domain>` (e.g., `box1.auracast.local`) on the local network via mDNS.
|
||||
|
||||
@@ -1 +1 @@
|
||||
5078804E6FBCF893D5537715FD928E46AD576ECA
|
||||
5078804E6FBCF893D5537715FD928E46AD576ECB
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import glob
|
||||
""" the main server where our multicaster objects live.
|
||||
TODO: in the future the multicaster objects should run in their own threads or even make a second server since everything thats blocking the main event loop leads to inceased latency.
|
||||
|
||||
"""
|
||||
import os
|
||||
import logging as log
|
||||
import uuid
|
||||
@@ -39,6 +42,9 @@ pcs: Set[RTCPeerConnection] = set() # keep refs so they don’t GC early
|
||||
|
||||
os.environ["PULSE_LATENCY_MSEC"] = "3"
|
||||
|
||||
# In-memory cache to avoid disk I/O on hot paths like /status
|
||||
SETTINGS_CACHE: dict = {}
|
||||
|
||||
class Offer(BaseModel):
|
||||
sdp: str
|
||||
type: str
|
||||
@@ -58,21 +64,37 @@ def get_device_index_by_name(name: str):
|
||||
return None
|
||||
|
||||
|
||||
def load_stream_settings() -> dict:
|
||||
"""Load persisted stream settings if available."""
|
||||
if os.path.exists(STREAM_SETTINGS_FILE):
|
||||
try:
|
||||
def _hydrate_settings_cache_from_disk() -> None:
|
||||
"""Populate SETTINGS_CACHE once from disk at startup.
|
||||
|
||||
Safe to call multiple times; errors fall back to empty dict.
|
||||
"""
|
||||
global SETTINGS_CACHE
|
||||
try:
|
||||
if os.path.exists(STREAM_SETTINGS_FILE):
|
||||
with open(STREAM_SETTINGS_FILE, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
except Exception:
|
||||
return {}
|
||||
return {}
|
||||
SETTINGS_CACHE = json.load(f)
|
||||
else:
|
||||
SETTINGS_CACHE = {}
|
||||
except Exception:
|
||||
SETTINGS_CACHE = {}
|
||||
|
||||
def load_stream_settings() -> dict:
|
||||
"""Return stream settings from in-memory cache.
|
||||
|
||||
The cache is hydrated once at startup and updated by save_stream_settings().
|
||||
No disk I/O occurs here.
|
||||
"""
|
||||
global SETTINGS_CACHE
|
||||
return SETTINGS_CACHE
|
||||
|
||||
def save_stream_settings(settings: dict):
|
||||
"""Save stream settings to disk."""
|
||||
"""Update in-memory settings cache and persist to disk."""
|
||||
global SETTINGS_CACHE
|
||||
SETTINGS_CACHE = dict(settings)
|
||||
try:
|
||||
with open(STREAM_SETTINGS_FILE, 'w', encoding='utf-8') as f:
|
||||
json.dump(settings, f, indent=2)
|
||||
json.dump(SETTINGS_CACHE, f, indent=2)
|
||||
except Exception as e:
|
||||
log.error('Unable to persist stream settings: %s', e)
|
||||
|
||||
@@ -276,13 +298,6 @@ async def get_status():
|
||||
return status
|
||||
|
||||
|
||||
@app.get("/long_block")
|
||||
async def long_block():
|
||||
"""Test endpoint that simulates a small delay without blocking the event loop."""
|
||||
time.sleep(0.3)
|
||||
return True
|
||||
|
||||
|
||||
async def _autostart_from_settings():
|
||||
"""Background task: auto-start last selected device-based input at server startup.
|
||||
|
||||
@@ -291,7 +306,6 @@ async def _autostart_from_settings():
|
||||
and initializes streaming.
|
||||
"""
|
||||
try:
|
||||
|
||||
settings = load_stream_settings() or {}
|
||||
audio_mode = settings.get('audio_mode')
|
||||
input_device_name = settings.get('input_device')
|
||||
@@ -361,17 +375,19 @@ async def _autostart_from_settings():
|
||||
bigs=bigs,
|
||||
)
|
||||
# Initialize and start
|
||||
await asyncio.sleep(0.5)
|
||||
await initialize(conf)
|
||||
return
|
||||
await asyncio.sleep(2)
|
||||
except Exception:
|
||||
log.warning("Autostart task failed", exc_info=True)
|
||||
|
||||
#TODO: enable and test this
|
||||
@app.on_event("startup")
|
||||
async def _startup_autostart_event():
|
||||
# Spawn the autostart task without blocking startup
|
||||
log.info("Refreshing PipeWire device cache.")
|
||||
# Hydrate settings cache once to avoid disk I/O during /status
|
||||
_hydrate_settings_cache_from_disk()
|
||||
refresh_pw_cache()
|
||||
asyncio.create_task(_autostart_from_settings())
|
||||
|
||||
@@ -619,4 +635,4 @@ if __name__ == '__main__':
|
||||
format='%(module)s.py:%(lineno)d %(levelname)s: %(message)s'
|
||||
)
|
||||
# Bind to localhost only for security: prevents network access, only frontend on same machine can connect
|
||||
uvicorn.run(app, host="127.0.0.1", port=5000)
|
||||
uvicorn.run(app, host="127.0.0.1", port=5000, access_log=False)
|
||||
26
src/scripts/hit_status.sh
Normal file
26
src/scripts/hit_status.sh
Normal file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
# Usage: ./hit_status.sh [COUNT] [SLEEP_SECONDS]
|
||||
# Always targets http://127.0.0.1:5000/status
|
||||
# Defaults: COUNT=100 SLEEP_SECONDS=0
|
||||
# Example: ./hit_status.sh 100 0.05
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
URL="http://127.0.0.1:5000/status"
|
||||
COUNT="${1:-100}"
|
||||
SLEEP_SECS="${2:-0}"
|
||||
|
||||
# Ensure COUNT is an integer
|
||||
if ! [[ "$COUNT" =~ ^[0-9]+$ ]]; then
|
||||
echo "COUNT must be an integer, got: $COUNT" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
for i in $(seq 1 "$COUNT"); do
|
||||
echo "[$i/$COUNT] GET $URL"
|
||||
curl -sS "$URL" > /dev/null || echo "Request $i failed"
|
||||
# Sleep if non-zero (supports floats, no bc needed)
|
||||
if [[ "$SLEEP_SECS" != "0" && "$SLEEP_SECS" != "0.0" && "$SLEEP_SECS" != "" ]]; then
|
||||
sleep "$SLEEP_SECS"
|
||||
fi
|
||||
done
|
||||
Reference in New Issue
Block a user