mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-09-15 17:12:59 -04:00
gologle
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -11,8 +11,8 @@
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="apple-mobile-web-app-title" content="Multi Roomba Rover" />
|
||||
<title>Multi Roomba Rover</title>
|
||||
<script type="module" crossorigin src="/assets/index-ChF3_rCg.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BhESptqT.css">
|
||||
<script type="module" crossorigin src="/assets/index-D8STCiny.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-Bz1ixYh7.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -68,6 +68,7 @@ export default function VideoTile({
|
||||
const [audioStatus, setAudioStatus] = useState('idle');
|
||||
const [audioDetail, setAudioDetail] = useState(null);
|
||||
const [levelIndicator, setLevelIndicator] = useState(null);
|
||||
const [compressorActive, setCompressorActive] = useState(false);
|
||||
const [restartToken, setRestartToken] = useState(0);
|
||||
const [audioRestartToken, setAudioRestartToken] = useState(0);
|
||||
const [muted, setMuted] = useState(true);
|
||||
@@ -415,26 +416,26 @@ export default function VideoTile({
|
||||
clearInterval(reductionPollRef.current);
|
||||
reductionPollRef.current = null;
|
||||
if (!audioEl || !audioSessionInfo?.url) {
|
||||
setCompressorActive(false);
|
||||
setLevelIndicator(null);
|
||||
logAudio('route/no-audio-url');
|
||||
return;
|
||||
}
|
||||
|
||||
// Phase 1 stabilization: bypass WebAudio compressor path and use plain media element audio.
|
||||
// This restores the known-good autoplay/retry behavior while we isolate Chrome-specific issues.
|
||||
const compressorMode = false;
|
||||
const compressorMode = autoLevelEnabled && autoLevelMode === 'compressor';
|
||||
const duckMode = autoLevelEnabled && autoLevelMode === 'duck';
|
||||
const graphReady = compressorMode && ensureAudioGraph();
|
||||
const graphReady = compressorMode ? ensureAudioGraph() : false;
|
||||
|
||||
if (graphReady) {
|
||||
const compressor = audioCompressorRef.current;
|
||||
const gainNode = audioGainRef.current;
|
||||
const contextRunning = audioContextRef.current?.state === 'running';
|
||||
// Keep direct element audio until WebAudio is actually running in Chrome.
|
||||
audioEl.volume = contextRunning ? 0 : effectiveRoverGain;
|
||||
logAudio('route/graph', { contextRunning, elementVolume: audioEl.volume });
|
||||
const canActivate = Boolean(contextRunning && compressorActive);
|
||||
// Strict gating: graph-only output only after context is running and compressor is explicitly activated.
|
||||
audioEl.volume = canActivate ? 0 : effectiveRoverGain;
|
||||
logAudio('route/graph', { contextRunning, canActivate, elementVolume: audioEl.volume });
|
||||
if (gainNode) {
|
||||
const graphGain = contextRunning
|
||||
const graphGain = canActivate
|
||||
? Math.max(0, Math.min(4, effectiveRoverGain * COMPRESSOR_MAKEUP_GAIN))
|
||||
: 0;
|
||||
gainNode.gain.value = graphGain;
|
||||
@@ -447,25 +448,29 @@ export default function VideoTile({
|
||||
compressor.attack.value = COMPRESSOR_SETTINGS.attack;
|
||||
compressor.release.value = COMPRESSOR_SETTINGS.release;
|
||||
}
|
||||
resumeAudioContext();
|
||||
reductionPollRef.current = setInterval(() => {
|
||||
if (audioContextRef.current?.state !== 'running') {
|
||||
setLevelIndicator(null);
|
||||
return;
|
||||
}
|
||||
const reduction = compressor?.reduction;
|
||||
if (typeof reduction === 'number' && reduction <= COMPRESSOR_REDUCTION_ACTIVE_DB) {
|
||||
const amount = Math.round(Math.abs(reduction) * 10) / 10;
|
||||
const formatted = Number.isInteger(amount) ? amount.toFixed(0) : amount.toFixed(1);
|
||||
setLevelIndicator(`Level: ${formatted}dB`);
|
||||
logAudio('compressor/reduction', { reduction, formatted });
|
||||
} else {
|
||||
setLevelIndicator(null);
|
||||
}
|
||||
}, 180);
|
||||
if (canActivate) {
|
||||
reductionPollRef.current = setInterval(() => {
|
||||
if (audioContextRef.current?.state !== 'running') {
|
||||
setLevelIndicator(null);
|
||||
return;
|
||||
}
|
||||
const reduction = compressor?.reduction;
|
||||
if (typeof reduction === 'number' && reduction <= COMPRESSOR_REDUCTION_ACTIVE_DB) {
|
||||
const amount = Math.round(Math.abs(reduction) * 10) / 10;
|
||||
const formatted = Number.isInteger(amount) ? amount.toFixed(0) : amount.toFixed(1);
|
||||
setLevelIndicator(`Level: ${formatted}dB`);
|
||||
logAudio('compressor/reduction', { reduction, formatted });
|
||||
} else {
|
||||
setLevelIndicator(null);
|
||||
}
|
||||
}, 180);
|
||||
} else {
|
||||
setLevelIndicator(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
setCompressorActive(false);
|
||||
audioEl.volume = effectiveRoverGain;
|
||||
logAudio('route/direct', { elementVolume: audioEl.volume, duckMode, brushOrVacuumActive });
|
||||
if (audioCompressorRef.current) {
|
||||
@@ -489,9 +494,9 @@ export default function VideoTile({
|
||||
autoLevelEnabled,
|
||||
autoLevelMode,
|
||||
brushOrVacuumActive,
|
||||
compressorActive,
|
||||
effectiveRoverGain,
|
||||
ensureAudioGraph,
|
||||
resumeAudioContext,
|
||||
logAudio,
|
||||
]);
|
||||
|
||||
@@ -517,11 +522,6 @@ export default function VideoTile({
|
||||
});
|
||||
if (nextStatus === 'playing') {
|
||||
resumeAudioContext();
|
||||
const target = audioRef.current;
|
||||
if (target) {
|
||||
target.muted = false;
|
||||
target.play().then(() => logAudio('audio/play-ok')).catch((err) => logAudio('audio/play-fail', { error: err?.message }));
|
||||
}
|
||||
}
|
||||
if (['error', 'failed'].includes(nextStatus)) {
|
||||
scheduleAudioRestart();
|
||||
@@ -573,9 +573,18 @@ export default function VideoTile({
|
||||
const target = audioRef.current;
|
||||
if (!target) return;
|
||||
target.muted = false;
|
||||
const wantCompressor = autoLevelEnabled && autoLevelMode === 'compressor';
|
||||
if (wantCompressor) {
|
||||
ensureAudioGraph();
|
||||
await resumeAudioContext();
|
||||
const running = audioContextRef.current?.state === 'running';
|
||||
if (running && !compressorActive) {
|
||||
setCompressorActive(true);
|
||||
logAudio('compressor/activated');
|
||||
}
|
||||
}
|
||||
if (!target.paused && !target.ended) return;
|
||||
logAudio('retry/play-attempt');
|
||||
await resumeAudioContext();
|
||||
target
|
||||
.play()
|
||||
.then(() => {
|
||||
@@ -593,7 +602,16 @@ export default function VideoTile({
|
||||
audioPlayInterval.current = setInterval(attemptPlay, AUDIO_RETRY_MS);
|
||||
|
||||
return () => clearInterval(audioPlayInterval.current);
|
||||
}, [audioSessionInfo?.url, audioStatus, resumeAudioContext, logAudio]);
|
||||
}, [
|
||||
audioSessionInfo?.url,
|
||||
audioStatus,
|
||||
autoLevelEnabled,
|
||||
autoLevelMode,
|
||||
compressorActive,
|
||||
ensureAudioGraph,
|
||||
resumeAudioContext,
|
||||
logAudio,
|
||||
]);
|
||||
|
||||
// Reflect audio element events back into status/detail so the HUD stays accurate.
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user