Closes the WebRTC connection, stops telemetry reporting, and cleans up all resources associated with the real-time client.
Method Signature
Parameters
None.
Return Value
This method returns immediately and performs cleanup synchronously.
What Gets Cleaned Up
When you call disconnect(), the following cleanup occurs:
- WebRTC Statistics Collection - Stops collecting and reporting WebRTC stats
- Telemetry Reporter - Stops sending telemetry data to the server
- Event Buffer - Stops buffering and emitting events
- WebRTC Manager - Closes the WebRTC peer connection and WebSocket
- Audio Stream Manager - Cleans up audio resources (for
live_avatar model)
After calling disconnect(), the client instance should not be used anymore. Create a new connection if you need to reconnect.
Usage Examples
Basic Disconnection
import { createDecartClient, models } from '@decart/sdk';
const decart = createDecartClient({ apiKey: 'your-api-key' });
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const client = await decart.realtime.connect(stream, {
model: models.realtime.mirage(),
onRemoteStream: (remoteStream) => {
videoElement.srcObject = remoteStream;
}
});
// ... use the client ...
// Disconnect when done
client.disconnect();
console.log('Disconnected');
Cleanup on Page Unload
let client: RealTimeClient | null = null;
// Connect
client = await decart.realtime.connect(stream, options);
// Clean up when user leaves the page
window.addEventListener('beforeunload', () => {
if (client) {
client.disconnect();
}
});
Cleanup with Try-Finally
let client: RealTimeClient | null = null;
try {
client = await decart.realtime.connect(stream, options);
// Use the client
await client.setPrompt('anime style');
// Wait for some time
await new Promise(resolve => setTimeout(resolve, 30000));
} finally {
// Always clean up, even if errors occur
if (client) {
client.disconnect();
}
}
Manual Reconnection
let client: RealTimeClient | null = null;
async function reconnect() {
// Disconnect existing client if any
if (client) {
client.disconnect();
client = null;
}
// Create new connection
try {
client = await decart.realtime.connect(stream, options);
console.log('Reconnected successfully');
} catch (error) {
console.error('Reconnection failed:', error);
}
}
// Trigger reconnection
await reconnect();
Connection Manager Class
class RealtimeConnection {
private client: RealTimeClient | null = null;
private decart: ReturnType<typeof createDecartClient>;
constructor(apiKey: string) {
this.decart = createDecartClient({ apiKey });
}
async connect(
stream: MediaStream,
options: Omit<RealTimeClientConnectOptions, 'onRemoteStream'>,
onRemoteStream: (stream: MediaStream) => void
) {
// Disconnect existing connection
this.disconnect();
this.client = await this.decart.realtime.connect(stream, {
...options,
onRemoteStream
});
return this.client;
}
disconnect() {
if (this.client) {
this.client.disconnect();
this.client = null;
}
}
isConnected(): boolean {
return this.client?.isConnected() ?? false;
}
}
const connection = new RealtimeConnection('your-api-key');
// Connect
await connection.connect(stream, { model: models.realtime.mirage() },
(remoteStream) => {
videoElement.srcObject = remoteStream;
}
);
// Disconnect
connection.disconnect();
React Hook Example
import { useEffect, useRef } from 'react';
import { createDecartClient, models, type RealTimeClient } from '@decart/sdk';
function useRealtimeConnection(
apiKey: string,
stream: MediaStream | null,
onRemoteStream: (stream: MediaStream) => void
) {
const clientRef = useRef<RealTimeClient | null>(null);
useEffect(() => {
if (!stream) return;
const decart = createDecartClient({ apiKey });
// Connect
decart.realtime.connect(stream, {
model: models.realtime.mirage(),
onRemoteStream
})
.then(client => {
clientRef.current = client;
})
.catch(error => {
console.error('Connection failed:', error);
});
// Cleanup on unmount or when dependencies change
return () => {
if (clientRef.current) {
clientRef.current.disconnect();
clientRef.current = null;
}
};
}, [apiKey, stream]);
return clientRef.current;
}
// Usage in component
function RealtimeVideo() {
const [stream, setStream] = useState<MediaStream | null>(null);
const videoRef = useRef<HTMLVideoElement>(null);
const client = useRealtimeConnection(
'your-api-key',
stream,
(remoteStream) => {
if (videoRef.current) {
videoRef.current.srcObject = remoteStream;
}
}
);
return <video ref={videoRef} autoPlay />;
}
Disconnect with Event Cleanup
const client = await decart.realtime.connect(stream, options);
// Add event listeners
const errorHandler = (error: DecartSDKError) => {
console.error('Error:', error);
};
const stateHandler = (state: ConnectionState) => {
console.log('State:', state);
};
client.on('error', errorHandler);
client.on('connectionChange', stateHandler);
// Later: remove listeners before disconnect (optional, as disconnect cleans up)
client.off('error', errorHandler);
client.off('connectionChange', stateHandler);
client.disconnect();
Important Notes
Connection State After Disconnect
After calling disconnect(), the connection state becomes "disconnected". You can verify this:
console.log(client.getConnectionState()); // "connected" or "generating"
client.disconnect();
console.log(client.getConnectionState()); // "disconnected"
Cannot Reuse Client
Once disconnected, you cannot reconnect the same client instance. You must create a new connection:
// ❌ Wrong: Cannot reconnect after disconnect
client.disconnect();
await client.setPrompt('new prompt'); // Error: connection is disconnected
// ✓ Correct: Create new connection
client.disconnect();
const newClient = await decart.realtime.connect(stream, options);
await newClient.setPrompt('new prompt');
Synchronous Operation
Unlike connect() which is asynchronous, disconnect() is synchronous and returns immediately. You don’t need to await it:
// No await needed
client.disconnect();
No Error Throwing
The method doesn’t throw errors. It safely handles cleanup even if the connection is already closed or in an error state.
See Also