fix start restart bugs
This commit is contained in:
@@ -336,10 +336,7 @@ class Streamer():
|
|||||||
self.is_streaming = False
|
self.is_streaming = False
|
||||||
if self.task is not None:
|
if self.task is not None:
|
||||||
self.task.cancel()
|
self.task.cancel()
|
||||||
try:
|
|
||||||
await self.task
|
|
||||||
except asyncio.CancelledError:
|
|
||||||
pass
|
|
||||||
self.task = None
|
self.task = None
|
||||||
|
|
||||||
# Close audio inputs (await to ensure ALSA devices are released)
|
# Close audio inputs (await to ensure ALSA devices are released)
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ if audio_mode in ["Webapp", "USB"]:
|
|||||||
# Input device selection for USB mode
|
# Input device selection for USB mode
|
||||||
if audio_mode == "USB":
|
if audio_mode == "USB":
|
||||||
try:
|
try:
|
||||||
resp = requests.get(f"{BACKEND_URL}/audio_inputs", timeout=1)
|
resp = requests.get(f"{BACKEND_URL}/audio_inputs")
|
||||||
if resp.status_code == 200:
|
if resp.status_code == 200:
|
||||||
input_options = [f"{d['id']}:{d['name']}" for d in resp.json().get('inputs', [])]
|
input_options = [f"{d['id']}:{d['name']}" for d in resp.json().get('inputs', [])]
|
||||||
else:
|
else:
|
||||||
@@ -71,6 +71,10 @@ if audio_mode in ["Webapp", "USB"]:
|
|||||||
selected_option = st.selectbox("Input Device", input_options, index=input_options.index(default_input))
|
selected_option = st.selectbox("Input Device", input_options, index=input_options.index(default_input))
|
||||||
with col2:
|
with col2:
|
||||||
if st.button("Refresh"):
|
if st.button("Refresh"):
|
||||||
|
try:
|
||||||
|
requests.post(f"{BACKEND_URL}/refresh_audio_inputs", timeout=3)
|
||||||
|
except Exception as e:
|
||||||
|
st.error(f"Failed to refresh devices: {e}")
|
||||||
st.rerun()
|
st.rerun()
|
||||||
# We send only the numeric/card identifier (before :) or 'default'
|
# We send only the numeric/card identifier (before :) or 'default'
|
||||||
input_device = selected_option.split(":", 1)[0] if ":" in selected_option else selected_option
|
input_device = selected_option.split(":", 1)[0] if ":" in selected_option else selected_option
|
||||||
|
|||||||
@@ -15,12 +15,13 @@ from aiortc import RTCPeerConnection, RTCSessionDescription, MediaStreamTrack
|
|||||||
import av
|
import av
|
||||||
import av.audio.layout
|
import av.audio.layout
|
||||||
import sounddevice as sd # type: ignore
|
import sounddevice as sd # type: ignore
|
||||||
from typing import Set
|
from typing import Set, List, Dict, Any
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
|
||||||
PTIME = 40 # TODO: seems to have no effect at all
|
PTIME = 40 # TODO: seems to have no effect at all
|
||||||
pcs: Set[RTCPeerConnection] = set() # keep refs so they don’t GC early
|
pcs: Set[RTCPeerConnection] = set() # keep refs so they don’t GC early
|
||||||
|
AUDIO_INPUT_DEVICES_CACHE: List[Dict[str, Any]] = []
|
||||||
|
|
||||||
class Offer(BaseModel):
|
class Offer(BaseModel):
|
||||||
sdp: str
|
sdp: str
|
||||||
@@ -169,6 +170,7 @@ async def stop_audio():
|
|||||||
|
|
||||||
return {"status": "stopped", "was_running": running}
|
return {"status": "stopped", "was_running": running}
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
log.error("Exception in /stop_audio: %s", traceback.format_exc())
|
||||||
raise HTTPException(status_code=500, detail=str(e))
|
raise HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
|
|
||||||
@@ -182,11 +184,12 @@ async def get_status():
|
|||||||
status.update(load_stream_settings())
|
status.update(load_stream_settings())
|
||||||
return status
|
return status
|
||||||
|
|
||||||
@app.get("/audio_inputs")
|
|
||||||
async def list_audio_inputs():
|
async def scan_audio_devices():
|
||||||
"""Return available hardware audio input devices for USB mode."""
|
"""Scans for available audio devices and updates the cache."""
|
||||||
|
global AUDIO_INPUT_DEVICES_CACHE
|
||||||
|
log.info("Scanning for audio input devices...")
|
||||||
try:
|
try:
|
||||||
# Re-scan devices on Linux, see https://github.com/spatialaudio/python-sounddevice/issues/16
|
|
||||||
if sys.platform == 'linux':
|
if sys.platform == 'linux':
|
||||||
log.info("Re-initializing sounddevice to scan for new devices")
|
log.info("Re-initializing sounddevice to scan for new devices")
|
||||||
sd._terminate()
|
sd._terminate()
|
||||||
@@ -197,12 +200,30 @@ async def list_audio_inputs():
|
|||||||
for idx, d in enumerate(devs)
|
for idx, d in enumerate(devs)
|
||||||
if d.get("max_input_channels", 0) > 0 and ("(hw:" in d["name"].lower() or "usb" in d["name"].lower())
|
if d.get("max_input_channels", 0) > 0 and ("(hw:" in d["name"].lower() or "usb" in d["name"].lower())
|
||||||
]
|
]
|
||||||
log.info('Found %d audio input devices:', len(inputs))
|
log.info('Found %d audio input devices: %s', len(inputs), inputs)
|
||||||
for i in inputs:
|
AUDIO_INPUT_DEVICES_CACHE = inputs
|
||||||
log.info(' %s', i)
|
except Exception:
|
||||||
return {"inputs": inputs}
|
log.error("Exception while scanning audio devices:", exc_info=True)
|
||||||
except Exception as e:
|
# Do not clear cache on error, keep the last known good list
|
||||||
raise HTTPException(status_code=500, detail=str(e))
|
|
||||||
|
|
||||||
|
@app.on_event("startup")
|
||||||
|
async def startup_event():
|
||||||
|
"""Pre-scans audio devices on startup."""
|
||||||
|
await scan_audio_devices()
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/audio_inputs")
|
||||||
|
async def list_audio_inputs():
|
||||||
|
"""Return available hardware audio input devices from cache."""
|
||||||
|
return {"inputs": AUDIO_INPUT_DEVICES_CACHE}
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/refresh_audio_inputs")
|
||||||
|
async def refresh_audio_inputs():
|
||||||
|
"""Triggers a re-scan of audio devices."""
|
||||||
|
await scan_audio_devices()
|
||||||
|
return {"status": "ok", "inputs": AUDIO_INPUT_DEVICES_CACHE}
|
||||||
|
|
||||||
|
|
||||||
@app.post("/offer")
|
@app.post("/offer")
|
||||||
|
|||||||
Reference in New Issue
Block a user