mirror of
https://github.com/smittix/intercept.git
synced 2026-07-26 17:48:15 -07:00
Add fetch stream fallback for listening audio
This commit is contained in:
@@ -26,6 +26,7 @@ const MAX_AUDIO_RECONNECT = 3;
|
|||||||
let audioWebSocket = null;
|
let audioWebSocket = null;
|
||||||
let audioQueue = [];
|
let audioQueue = [];
|
||||||
let isWebSocketAudio = false;
|
let isWebSocketAudio = false;
|
||||||
|
let audioFetchController = null;
|
||||||
|
|
||||||
// Visualizer state
|
// Visualizer state
|
||||||
let visualizerContext = null;
|
let visualizerContext = null;
|
||||||
@@ -2147,11 +2148,14 @@ async function _startDirectListenInternal() {
|
|||||||
console.log('[LISTEN] Initial play blocked, waiting for canplay');
|
console.log('[LISTEN] Initial play blocked, waiting for canplay');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Fallback: if stream never starts, switch to WebSocket audio
|
// Fallback: if stream never starts, try fetch-based stream
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
if (!isDirectListening || !audioPlayer) return;
|
if (!isDirectListening || !audioPlayer) return;
|
||||||
if (audioPlayer.readyState > 0) return;
|
if (audioPlayer.readyState > 0) return;
|
||||||
console.warn('[LISTEN] HTTP stream not ready, attempting WebSocket audio fallback');
|
console.warn('[LISTEN] HTTP stream not ready, attempting fetch stream fallback');
|
||||||
|
const fetchOk = await startFetchAudioStream(streamUrl, audioPlayer);
|
||||||
|
if (fetchOk) return;
|
||||||
|
console.warn('[LISTEN] Fetch stream failed, attempting WebSocket audio fallback');
|
||||||
await startWebSocketListen({
|
await startWebSocketListen({
|
||||||
frequency: freq,
|
frequency: freq,
|
||||||
modulation: currentModulation,
|
modulation: currentModulation,
|
||||||
@@ -2178,6 +2182,80 @@ async function _startDirectListenInternal() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function startFetchAudioStream(streamUrl, audioPlayer) {
|
||||||
|
if (!window.MediaSource) {
|
||||||
|
console.warn('[LISTEN] MediaSource not supported for fetch fallback');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abort any previous fetch stream
|
||||||
|
if (audioFetchController) {
|
||||||
|
audioFetchController.abort();
|
||||||
|
}
|
||||||
|
audioFetchController = new AbortController();
|
||||||
|
|
||||||
|
// Reset audio element for MediaSource
|
||||||
|
try {
|
||||||
|
audioPlayer.pause();
|
||||||
|
} catch (e) {}
|
||||||
|
audioPlayer.removeAttribute('src');
|
||||||
|
audioPlayer.load();
|
||||||
|
|
||||||
|
const mediaSource = new MediaSource();
|
||||||
|
audioPlayer.src = URL.createObjectURL(mediaSource);
|
||||||
|
audioPlayer.muted = false;
|
||||||
|
audioPlayer.autoplay = true;
|
||||||
|
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
mediaSource.addEventListener('sourceopen', async () => {
|
||||||
|
let sourceBuffer;
|
||||||
|
try {
|
||||||
|
sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg');
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[LISTEN] Failed to create source buffer:', e);
|
||||||
|
resolve(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(streamUrl, {
|
||||||
|
cache: 'no-store',
|
||||||
|
signal: audioFetchController.signal
|
||||||
|
});
|
||||||
|
if (!response.ok || !response.body) {
|
||||||
|
console.warn('[LISTEN] Fetch stream response invalid', response.status);
|
||||||
|
resolve(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reader = response.body.getReader();
|
||||||
|
const appendChunk = async (chunk) => {
|
||||||
|
if (!chunk || chunk.length === 0) return;
|
||||||
|
if (!sourceBuffer.updating) {
|
||||||
|
sourceBuffer.appendBuffer(chunk);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await new Promise(r => sourceBuffer.addEventListener('updateend', r, { once: true }));
|
||||||
|
sourceBuffer.appendBuffer(chunk);
|
||||||
|
};
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const { done, value } = await reader.read();
|
||||||
|
if (done) break;
|
||||||
|
await appendChunk(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(true);
|
||||||
|
} catch (e) {
|
||||||
|
if (e.name !== 'AbortError') {
|
||||||
|
console.error('[LISTEN] Fetch stream error:', e);
|
||||||
|
}
|
||||||
|
resolve(false);
|
||||||
|
}
|
||||||
|
}, { once: true });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function startWebSocketListen(config, audioPlayer) {
|
async function startWebSocketListen(config, audioPlayer) {
|
||||||
const selectedType = typeof getSelectedSDRType === 'function'
|
const selectedType = typeof getSelectedSDRType === 'function'
|
||||||
? getSelectedSDRType()
|
? getSelectedSDRType()
|
||||||
@@ -2234,6 +2312,10 @@ function stopDirectListen() {
|
|||||||
audioPlayer.src = '';
|
audioPlayer.src = '';
|
||||||
}
|
}
|
||||||
audioQueue = [];
|
audioQueue = [];
|
||||||
|
if (audioFetchController) {
|
||||||
|
audioFetchController.abort();
|
||||||
|
audioFetchController = null;
|
||||||
|
}
|
||||||
|
|
||||||
// Stop via WebSocket if connected
|
// Stop via WebSocket if connected
|
||||||
if (audioWebSocket && audioWebSocket.readyState === WebSocket.OPEN) {
|
if (audioWebSocket && audioWebSocket.readyState === WebSocket.OPEN) {
|
||||||
|
|||||||
Reference in New Issue
Block a user