Skip to content

Commit 60c440b

Browse files
committed
fix: handle WebSocket disconnect properly and improve audio conversion
1 parent 7dbbf0f commit 60c440b

2 files changed

Lines changed: 40 additions & 14 deletions

File tree

apps/gateway/src/routes/websocket.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ async def websocket_stream(
3333

3434
try:
3535
while True:
36-
data = await websocket.receive()
36+
try:
37+
data = await websocket.receive()
38+
except RuntimeError:
39+
# WebSocket already disconnected
40+
break
3741

3842
if "bytes" in data:
3943
audio_data = data["bytes"]

apps/gateway/src/static/index.html

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -118,20 +118,42 @@ <h1>🎤 Voice Interaction</h1>
118118
}
119119
}
120120

121-
async function convertAndSend(audioBlob) {
122-
// Convert webm to raw PCM using Web Audio API
123-
const arrayBuffer = await audioBlob.arrayBuffer();
124-
const audioContext = new AudioContext();
125-
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
126-
127-
// Convert to mono 16kHz
128-
const channelData = audioBuffer.getChannelData(0);
129-
const samples = channelData.filter((_, i) => i % 3 === 0); // Downsample
130-
const int16Array = new Int16Array(samples.length);
131-
132-
for (let i = 0; i < samples.length; i++) {
133-
int16Array[i] = Math.max(-1, Math.min(1, samples[i])) * 32767;
121+
async function convertAndSend(audioBlob) {
122+
try {
123+
const arrayBuffer = await audioBlob.arrayBuffer();
124+
const audioContext = new AudioContext();
125+
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
126+
127+
// Get mono channel and convert to 16kHz
128+
const channelData = audioBuffer.getChannelData(0);
129+
const sampleRate = audioBuffer.sampleRate;
130+
const targetSampleRate = 16000;
131+
132+
// Resample
133+
const ratio = sampleRate / targetSampleRate;
134+
const newLength = Math.floor(channelData.length / ratio);
135+
const resampled = new Float32Array(newLength);
136+
137+
for (let i = 0; i < newLength; i++) {
138+
resampled[i] = channelData[Math.floor(i * ratio)];
139+
}
140+
141+
// Convert to Int16 PCM
142+
const int16Array = new Int16Array(newLength);
143+
for (let i = 0; i < newLength; i++) {
144+
const sample = Math.max(-1, Math.min(1, resampled[i]));
145+
int16Array[i] = sample * 32767;
146+
}
147+
148+
if (ws && ws.readyState === WebSocket.OPEN) {
149+
ws.send(int16Array.buffer);
150+
}
151+
152+
await audioContext.close();
153+
} catch (e) {
154+
console.error('Audio conversion error:', e);
134155
}
156+
}
135157

136158
if (ws && ws.readyState === WebSocket.OPEN) {
137159
ws.send(int16Array.buffer);

0 commit comments

Comments
 (0)