generated from amazon-archives/__template_Apache-2.0
-
Notifications
You must be signed in to change notification settings - Fork 102
Open
Labels
Description
Environment information
Service: AWS Transcribe (Streaming WebSocket API)
Frontend: React + WebSocket + MediaRecorder/AudioContext
Backend: AWS Lambda (Node.js) generating presigned URL using @aws-sdk/signature-v4
Region: eu-west-2
Audio format: PCM16, 16 kHz, mono
Describe the bug
When connecting to AWS Transcribe using a presigned WebSocket URL, the connection closes immediately with no error message from the service.
Even when sending empty or valid PCM16 audio chunks, the socket disconnects right after onopen
.
The client never receives transcription events.
Reproduction steps
1. Generate Presigned URL in Lambda
const request = new HttpRequest({
protocol: "wss:",
hostname: `transcribestreaming.${region}.amazonaws.com`,
path: "/stream-transcription-websocket",
method: "GET",
query: {
"language-code": "en-US",
"media-encoding": "pcm",
"sample-rate": "16000"
},
headers: {
host: `transcribestreaming.${region}.amazonaws.com`,
},
});
const signer = new SignatureV4({
credentials: defaultProvider(),
region,
service: "transcribe",
sha256: Sha256,
});
const signedRequest = await signer.presign(request, { expiresIn: 300 });
const url = `wss://${signedRequest.hostname}:8443${signedRequest.path}?${queryStr}`;
2. Connect From Frontend
const socket = new WebSocket(wsUrl);
socket.onopen = () => {
console.log("✅ Connected to Transcribe");
};
socket.onmessage = (event) => {
console.log("Message:", event.data);
};
socket.onerror = (event) => {
console.error("WebSocket error:", event);
};
socket.onclose = (event) => {
console.log("🔴 Disconnected", event.code, event.reason, event.wasClean);
};
3. Send Audio
processor.onaudioprocess = (e) => {
if (socket.readyState !== 1) return;
const float32Array = e.inputBuffer.getChannelData(0);
const int16Array = new Int16Array(float32Array.length);
for (let i = 0; i < float32Array.length; i++) {
int16Array[i] = Math.max(-32768, Math.min(32767, Math.floor(float32Array[i] * 32768)));
}
const audioEvent = {
headers: {
":content-type": { type: "string", value: "application/octet-stream" },
":event-type": { type: "string", value: "AudioEvent" },
":message-type": { type: "string", value: "event" },
},
body: new Uint8Array(int16Array.buffer),
};
socket.send(marshaller.marshall(audioEvent));
};
⚠️ Observed Behavior
- WebSocket connects (
onopen
fires ✅). - Immediately disconnects, with no transcription events.
onclose
shows no reason (event.reason
empty).- Adding silent/empty audio does not change behavior.
✅ Expected Behavior
- WebSocket should remain open until closed by client.
- Transcribe should return transcription events or at least an error message when audio is invalid.
- Empty audio should result in clean closure, not silent disconnect.
❓ Questions for AWS Team
- Is there an issue with how the presigned URL is generated (path, port
:8443
, or query params)? - Does Transcribe WebSocket require a special initial handshake message before sending audio chunks?
- What are the exact requirements for the AudioEvent payload format (PCM16, marshalling, headers)?
- Why does the connection close without returning an error or
BadRequestException
?
Would you like me to also include a Minimal Working Example repo structure (with Lambda + React frontend code) in this issue so AWS support can reproduce it in one go?