#I was trying to establish websocket connection with elevenlabs. If i initialize websocket each tim
1 messages · Page 1 of 1 (latest)
When working with websockets, it's important to manage your connections efficiently. Reusing an established SSL/TLS session can help reduce latency by skipping the handshake process, which improves latency for all requests after the session’s first.
However, you should also limit the number of times a connection is closed and reopened to the extent possible. This is because an SSL/TLS handshake takes place at the beginning of a connection, which adds overhead.
If you're experiencing issues with a globally initialized websocket, it might be due to the connection being closed and reopened too many times. Try to manage your websocket connections in a way that minimizes the number of closures and reconnections.
Here's an example of how you might manage a websocket connection in an Express.js application:
// src/app.ts
import 'dotenv/config';
import express, { Response } from 'express';
import ExpressWs from 'express-ws';
import VoiceResponse from 'twilio/lib/twiml/VoiceResponse';
import { ElevenLabsClient } from 'elevenlabs';
import { type WebSocket } from 'ws';
import { type Readable } from 'stream';
const app = ExpressWs(express()).app;
const PORT: number = parseInt(process.env.PORT || '5000');
const elevenlabs = new ElevenLabsClient();
const voiceId = '21m00Tcm4TlvDq8ikWAM';
const outputFormat = 'ulaw_8000';
const text = 'This is a test. You can now hang up. Thank you.';
function startApp() {
app.post('/call/incoming', (_, res: Response) => {
const twiml = new VoiceResponse();
twiml.connect().stream({
url: `wss://${process.env.SERVER_DOMAIN}/call/connection`,
});
res.writeHead(200, { 'Content-Type': 'text/xml' });
res.end(twiml.toString());
});
app.ws('/call/connection', (ws: WebSocket) => {
ws.on('message', async (data: string) => {
const message: {
event: string;
start?: { streamSid: string; callSid: string };
} = JSON.parse(data);
if (message.event === 'start' && message.start) {
const streamSid = message.start.streamSid;
const response = await elevenlabs.textToSpeech.convert(voiceId, {
model_id: 'eleven_turbo_v2',
output_format: outputFormat,
text,
});
const audioArrayBuffer = await streamToArrayBuffer(response);
ws.send(
JSON.stringify({
streamSid,
event: 'media',
media: {
payload: Buffer.from(audioArrayBuffer as any).toString('base64'),
},
}),
);
}
});
ws.on('error', console.error);
});
app.listen(PORT, () => {
console.log(`Local: http://localhost:${PORT}`);
console.log(`Remote: https://${process.env.SERVER_DOMAIN}`);
});
}
function streamToArrayBuffer(readableStream: Readable) {
return new Promise((resolve, reject) => {
const chunks: Buffer[] = [];
readableStream.on('data', (chunk) => {
chunks.push(chunk);
});
readableStream.on('end', () => {
resolve(Buffer.concat(chunks).buffer);
});
readableStream.on('error', reject);
});
}
startApp();
In this example, the websocket connection is managed within the '/call/connection' route. The connection is opened when a message is received, and the connection is closed when an error occurs. This approach helps to limit the number of times the connection is closed and reopened.
I'm doing it on client side