Implement a demo mode
This commit is contained in:
@@ -277,7 +277,7 @@ async def init_broadcast(
|
||||
|
||||
logging.debug(f'big{i} parameters are:')
|
||||
logging.debug('%s', pprint.pformat(vars(big)))
|
||||
logging.debug(f'Finished setup of big{i}.')
|
||||
logging.info(f'Finished setup of big{i}.')
|
||||
|
||||
await asyncio.sleep(i+1) # Wait for advertising to set up
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# frontend/app.py
|
||||
import os
|
||||
import time
|
||||
import streamlit as st
|
||||
import requests
|
||||
from auracast import auracast_config
|
||||
@@ -12,6 +13,13 @@ if 'stream_started' not in st.session_state:
|
||||
# Global: desired packetization time in ms for Opus (should match backend)
|
||||
PTIME = 40
|
||||
BACKEND_URL = "http://localhost:5000"
|
||||
TRANSPORT1 = "auto" #'serial:/dev/ttyAMA3,1000000,rtscts', # transport for raspberry pi gpio header
|
||||
QUALITY_MAP = {
|
||||
"High (48kHz)": {"rate": 48000, "octets": 120},
|
||||
"Good (32kHz)": {"rate": 32000, "octets": 80},
|
||||
"Medium (24kHz)": {"rate": 24000, "octets": 60},
|
||||
"Fair (16kHz)": {"rate": 16000, "octets": 40},
|
||||
}
|
||||
|
||||
# Try loading persisted settings from backend
|
||||
saved_settings = {}
|
||||
@@ -25,7 +33,7 @@ except Exception:
|
||||
st.title("🎙️ Auracast Audio Mode Control")
|
||||
|
||||
# Audio mode selection with persisted default
|
||||
options = ["Webapp", "USB"]
|
||||
options = ["Webapp", "USB", "Demo"]
|
||||
saved_audio_mode = saved_settings.get("audio_mode", "Webapp")
|
||||
if saved_audio_mode not in options:
|
||||
saved_audio_mode = "Webapp"
|
||||
@@ -34,18 +42,108 @@ audio_mode = st.selectbox(
|
||||
"Audio Mode",
|
||||
options,
|
||||
index=options.index(saved_audio_mode),
|
||||
help="Select the audio input source. Choose 'Webapp' for browser microphone or 'USB' for a connected hardware device."
|
||||
help="Select the audio input source. Choose 'Webapp' for browser microphone, 'USB' for a connected hardware device, or 'Demo' for a simulated stream."
|
||||
)
|
||||
|
||||
if audio_mode in ["Webapp", "USB"]:
|
||||
# Stream quality selection (now enabled)
|
||||
quality_map = {
|
||||
"High (48kHz)": {"rate": 48000, "octets": 120},
|
||||
"Good (32kHz)": {"rate": 32000, "octets": 80},
|
||||
"Medium (24kHz)": {"rate": 24000, "octets": 60},
|
||||
"Fair (16kHz)": {"rate": 16000, "octets": 40},
|
||||
if audio_mode == "Demo":
|
||||
demo_stream_map = {
|
||||
"1 × 48kHz": {"quality": "High (48kHz)", "streams": 1,},
|
||||
"2 × 24kHz": {"quality": "Medium (24kHz)", "streams": 2,},
|
||||
"3 × 16kHz": {"quality": "Fair (16kHz)", "streams": 3,},
|
||||
}
|
||||
quality_options = list(quality_map.keys())
|
||||
demo_options = list(demo_stream_map.keys())
|
||||
default_demo = demo_options[0]
|
||||
demo_selected = st.selectbox(
|
||||
"Demo Stream Type",
|
||||
demo_options,
|
||||
index=0,
|
||||
help="Select the demo stream configuration."
|
||||
)
|
||||
#st.info(f"Demo mode selected: {demo_selected} (Streams: {demo_stream_map[demo_selected]['streams']}, Rate: {demo_stream_map[demo_selected]['rate']} Hz)")
|
||||
# Start/Stop buttons for demo mode
|
||||
if 'demo_stream_started' not in st.session_state:
|
||||
st.session_state['demo_stream_started'] = False
|
||||
col1, col2 = st.columns(2)
|
||||
with col1:
|
||||
start_demo = st.button("Start Demo Stream")
|
||||
with col2:
|
||||
stop_demo = st.button("Stop Demo Stream")
|
||||
if start_demo:
|
||||
# Always stop any running stream for clean state
|
||||
try:
|
||||
requests.post(f"{BACKEND_URL}/stop_audio").json()
|
||||
except Exception:
|
||||
pass
|
||||
time.sleep(1)
|
||||
demo_cfg = demo_stream_map[demo_selected]
|
||||
# Octets per frame logic matches quality_map
|
||||
q = QUALITY_MAP[demo_cfg['quality']]
|
||||
|
||||
if demo_cfg['streams'] >= 1:
|
||||
bigs = [
|
||||
auracast_config.AuracastBigConfigDeu(
|
||||
audio_source=f'file:../testdata/wave_particle_5min_de_{int(q["rate"]/1000)}kHz_mono.wav',
|
||||
iso_que_len=32,
|
||||
sampling_frequency=q['rate'],
|
||||
octets_per_frame=q['octets'],
|
||||
)
|
||||
]
|
||||
if demo_cfg['streams'] >= 2:
|
||||
bigs += [
|
||||
auracast_config.AuracastBigConfigEng(
|
||||
audio_source=f'file:../testdata/wave_particle_5min_en_{int(q["rate"]/1000)}kHz_mono.wav',
|
||||
iso_que_len=32,
|
||||
sampling_frequency=q['rate'],
|
||||
octets_per_frame=q['octets'],
|
||||
),
|
||||
]
|
||||
if demo_cfg['streams'] >= 3:
|
||||
bigs += [
|
||||
auracast_config.AuracastBigConfigFra(
|
||||
audio_source=f'file:../testdata/wave_particle_5min_fr_{int(q["rate"]/1000)}kHz_mono.wav',
|
||||
iso_que_len=32,
|
||||
sampling_frequency=q['rate'],
|
||||
octets_per_frame=q['octets'],
|
||||
),
|
||||
]
|
||||
|
||||
config = auracast_config.AuracastConfigGroup(
|
||||
auracast_sampling_rate_hz=q['rate'],
|
||||
octets_per_frame=q['octets'],
|
||||
transport=TRANSPORT1, # transport for raspberry pi gpio header
|
||||
bigs = bigs
|
||||
)
|
||||
|
||||
try:
|
||||
r = requests.post(f"{BACKEND_URL}/init", json=config.model_dump())
|
||||
if r.status_code == 200:
|
||||
st.session_state['demo_stream_started'] = True
|
||||
st.success(f"Demo stream started: {demo_selected}")
|
||||
else:
|
||||
st.session_state['demo_stream_started'] = False
|
||||
st.error(f"Failed to initialize demo: {r.text}")
|
||||
except Exception as e:
|
||||
st.session_state['demo_stream_started'] = False
|
||||
st.error(f"Error: {e}")
|
||||
elif stop_demo:
|
||||
try:
|
||||
r = requests.post(f"{BACKEND_URL}/stop_audio").json()
|
||||
st.session_state['demo_stream_started'] = False
|
||||
if r.get('was_running'):
|
||||
st.info("Demo stream stopped.")
|
||||
else:
|
||||
st.info("Demo stream was not running.")
|
||||
except Exception as e:
|
||||
st.error(f"Error: {e}")
|
||||
elif st.session_state['demo_stream_started']:
|
||||
st.success(f"Demo stream running: {demo_selected}")
|
||||
else:
|
||||
st.info("Demo stream not running.")
|
||||
quality = None # Not used in demo mode
|
||||
else:
|
||||
# Stream quality selection (now enabled)
|
||||
|
||||
quality_options = list(QUALITY_MAP.keys())
|
||||
default_quality = "Medium (24kHz)" if "Medium (24kHz)" in quality_options else quality_options[0]
|
||||
quality = st.selectbox(
|
||||
"Stream Quality (Sampling Rate)",
|
||||
@@ -119,7 +217,7 @@ if audio_mode in ["Webapp", "USB"]:
|
||||
input_device = selected_option.split(":", 1)[0] if ":" in selected_option else selected_option
|
||||
else:
|
||||
input_device = None
|
||||
import time
|
||||
|
||||
start_stream = st.button("Start Auracast")
|
||||
stop_stream = st.button("Stop Auracast")
|
||||
|
||||
@@ -164,13 +262,13 @@ if audio_mode in ["Webapp", "USB"]:
|
||||
st.success("Stream Stopped!")
|
||||
|
||||
# Small pause lets backend fully release audio devices before re-init
|
||||
import time; time.sleep(1)
|
||||
time.sleep(1)
|
||||
# Prepare config using the model (do NOT send qos_config, only relevant fields)
|
||||
q = quality_map[quality]
|
||||
q = QUALITY_MAP[quality]
|
||||
config = auracast_config.AuracastConfigGroup(
|
||||
auracast_sampling_rate_hz=q['rate'],
|
||||
octets_per_frame=q['octets'],
|
||||
transport='serial:/dev/ttyAMA3,1000000,rtscts', # transport for raspberry pi gpio header
|
||||
transport=TRANSPORT1, # transport for raspberry pi gpio header
|
||||
bigs = [
|
||||
auracast_config.AuracastBigConfig(
|
||||
name=stream_name,
|
||||
@@ -254,9 +352,9 @@ if audio_mode in ["Webapp", "USB"]:
|
||||
"""
|
||||
st.components.v1.html(component, height=0)
|
||||
st.session_state['stream_started'] = True
|
||||
else:
|
||||
st.header("Advertised Streams (Cloud Announcements)")
|
||||
st.info("This feature requires backend support to list advertised streams.")
|
||||
#else:
|
||||
# st.header("Advertised Streams (Cloud Announcements)")
|
||||
# st.info("This feature requires backend support to list advertised streams.")
|
||||
# Placeholder for future implementation
|
||||
# Example: r = requests.get(f"{BACKEND_URL}/advertised_streams")
|
||||
# if r.status_code == 200:
|
||||
|
||||
@@ -96,6 +96,9 @@ async def initialize(conf: auracast_config.AuracastConfigGroup):
|
||||
elif first_source == 'webrtc':
|
||||
audio_mode_persist = 'Webapp'
|
||||
input_device = None
|
||||
elif first_source.startswith('file:'):
|
||||
audio_mode_persist = 'Demo'
|
||||
input_device = None
|
||||
else:
|
||||
audio_mode_persist = 'Network'
|
||||
input_device = None
|
||||
@@ -129,7 +132,9 @@ async def initialize(conf: auracast_config.AuracastConfigGroup):
|
||||
# Auto-start streaming only when using a local USB audio device. For Webapp mode the
|
||||
# streamer is started by the /offer handler once the WebRTC track arrives so we know
|
||||
# the peer connection is established.
|
||||
if any(big.audio_source.startswith("device:") for big in conf.bigs):
|
||||
# TODO rather do a if not webrtc in the future
|
||||
if any(big.audio_source.startswith("device:") or big.audio_source.startswith("file:") for big in conf.bigs):
|
||||
log.info("Auto-starting streaming")
|
||||
await multicaster.start_streaming()
|
||||
except Exception as e:
|
||||
log.error("Exception in /init: %s", traceback.format_exc())
|
||||
@@ -362,6 +367,8 @@ async def shutdown():
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
if __name__ == '__main__':
|
||||
import os
|
||||
os.chdir(os.path.dirname(__file__))
|
||||
import uvicorn
|
||||
log.basicConfig( # for debug log level export LOG_LEVEL=DEBUG
|
||||
level=os.environ.get('LOG_LEVEL', log.INFO),
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user