Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/DecartAI/sdk/llms.txt

Use this file to discover all available pages before exploring further.

The RealTimeClient emits events for connection state changes, errors, generation progress, diagnostics, and WebRTC statistics. Use on() to subscribe and off() to unsubscribe.

Event Methods

// Subscribe to an event
client.on<K extends keyof Events>(event: K, listener: (data: Events[K]) => void): void

// Unsubscribe from an event
client.off<K extends keyof Events>(event: K, listener: (data: Events[K]) => void): void

Event Types

connectionChange

Emitted when the WebRTC connection state changes.
state
ConnectionState
required
The new connection state. Possible values:
  • "connecting" - Establishing connection
  • "connected" - Connection active, ready for commands
  • "generating" - Model is actively generating output
  • "reconnecting" - Attempting to reconnect after connection loss
  • "disconnected" - Connection closed
Example:
client.on('connectionChange', (state) => {
  console.log('Connection state:', state);
  
  switch (state) {
    case 'connecting':
      showSpinner();
      break;
    case 'connected':
      hideSpinner();
      enableControls();
      break;
    case 'generating':
      showGeneratingIndicator();
      break;
    case 'disconnected':
      disableControls();
      showReconnectButton();
      break;
  }
});

error

Emitted when an error occurs during the WebRTC connection or operation.
error
DecartSDKError
required
An error object with the following properties:
Example:
client.on('error', (error) => {
  console.error('Error occurred:', error.code, error.message);
  
  // Show error to user
  showErrorNotification(error.message);
  
  // Handle specific error types
  if (error.code === 'WEBRTC_CONNECTION_FAILED') {
    // Attempt reconnection
    attemptReconnect();
  }
});

generationTick

Emitted periodically during generation to indicate how long the model has been generating.
data
object
required
Example:
client.on('generationTick', ({ seconds }) => {
  console.log(`Generating for ${seconds} seconds`);
  
  // Update UI with generation duration
  document.getElementById('duration').textContent = `${seconds}s`;
  
  // Warn user if generation is taking too long
  if (seconds > 30) {
    showWarning('Generation is taking longer than expected');
  }
});

diagnostic

Emitted for diagnostic events related to connection phases, ICE candidates, WebRTC state changes, reconnections, and video stalls.
event
DiagnosticEvent
required
A diagnostic event with a name and typed data payload.
Example:
client.on('diagnostic', (event) => {
  console.log('Diagnostic event:', event.name, event.data);
  
  if (event.name === 'phaseTiming') {
    console.log(`${event.data.phase}: ${event.data.durationMs}ms`);
  }
  
  if (event.name === 'videoStall') {
    if (event.data.stalled) {
      console.warn('Video stalled!');
    } else {
      console.log(`Video recovered after ${event.data.durationMs}ms`);
    }
  }
  
  if (event.name === 'reconnect') {
    console.log(`Reconnect attempt ${event.data.attempt}/${event.data.maxAttempts}`);
  }
});

stats

Emitted periodically (every ~1 second) with WebRTC statistics about video/audio quality, bitrate, packets, and connection metrics.
stats
WebRTCStats
required
WebRTC statistics object.
Example:
client.on('stats', (stats) => {
  // Log video quality metrics
  if (stats.video) {
    console.log(`Video: ${stats.video.framesPerSecond} FPS, ` +
                `${Math.round(stats.video.bitrate / 1000)} kbps, ` +
                `${stats.video.frameWidth}x${stats.video.frameHeight}`);
    
    // Warn if packets are being lost
    if (stats.video.packetsLostDelta > 0) {
      console.warn(`Lost ${stats.video.packetsLostDelta} packets`);
    }
    
    // Warn if frames are being dropped
    if (stats.video.framesDroppedDelta > 0) {
      console.warn(`Dropped ${stats.video.framesDroppedDelta} frames`);
    }
  }
  
  // Log connection quality
  if (stats.connection.currentRoundTripTime) {
    const rttMs = Math.round(stats.connection.currentRoundTripTime * 1000);
    console.log(`RTT: ${rttMs}ms`);
  }
});

Usage Examples

Basic Event Subscription

const client = await decart.realtime.connect(stream, options);

// Subscribe to connection changes
client.on('connectionChange', (state) => {
  console.log('State:', state);
});

// Subscribe to errors
client.on('error', (error) => {
  console.error('Error:', error.message);
});

// Subscribe to generation progress
client.on('generationTick', ({ seconds }) => {
  console.log(`Generating: ${seconds}s`);
});

Unsubscribing from Events

const errorHandler = (error: DecartSDKError) => {
  console.error('Error:', error);
};

// Subscribe
client.on('error', errorHandler);

// Later: unsubscribe
client.off('error', errorHandler);

Quality Monitoring Dashboard

interface QualityMetrics {
  fps: number;
  bitrate: number;
  packetsLost: number;
  rtt: number | null;
}

const metrics: QualityMetrics = {
  fps: 0,
  bitrate: 0,
  packetsLost: 0,
  rtt: null
};

client.on('stats', (stats) => {
  if (stats.video) {
    metrics.fps = stats.video.framesPerSecond;
    metrics.bitrate = Math.round(stats.video.bitrate / 1000); // kbps
    metrics.packetsLost += stats.video.packetsLostDelta;
  }
  
  metrics.rtt = stats.connection.currentRoundTripTime 
    ? Math.round(stats.connection.currentRoundTripTime * 1000)
    : null;
  
  updateDashboard(metrics);
});

function updateDashboard(metrics: QualityMetrics) {
  document.getElementById('fps').textContent = `${metrics.fps} FPS`;
  document.getElementById('bitrate').textContent = `${metrics.bitrate} kbps`;
  document.getElementById('packets-lost').textContent = `${metrics.packetsLost}`;
  document.getElementById('rtt').textContent = metrics.rtt ? `${metrics.rtt}ms` : 'N/A';
}

Connection State Manager

class ConnectionStateManager {
  private state: ConnectionState = 'disconnected';
  
  constructor(private client: RealTimeClient) {
    this.client.on('connectionChange', this.handleStateChange.bind(this));
    this.client.on('error', this.handleError.bind(this));
  }
  
  private handleStateChange(state: ConnectionState) {
    console.log(`State transition: ${this.state} -> ${state}`);
    this.state = state;
    
    // Update UI based on state
    this.updateUI();
  }
  
  private handleError(error: DecartSDKError) {
    console.error('Connection error:', error);
    
    // Show error notification
    this.showNotification(`Error: ${error.message}`, 'error');
  }
  
  private updateUI() {
    const statusEl = document.getElementById('status');
    if (statusEl) {
      statusEl.textContent = this.state;
      statusEl.className = `status-${this.state}`;
    }
  }
  
  private showNotification(message: string, type: 'error' | 'info') {
    // Show notification to user
    console.log(`[${type}] ${message}`);
  }
  
  getState(): ConnectionState {
    return this.state;
  }
}

const stateManager = new ConnectionStateManager(client);

Performance Tracker

class PerformanceTracker {
  private startTime: number = Date.now();
  private totalFrames: number = 0;
  private droppedFrames: number = 0;
  
  constructor(private client: RealTimeClient) {
    this.client.on('stats', this.trackStats.bind(this));
  }
  
  private trackStats(stats: WebRTCStats) {
    if (stats.video) {
      this.totalFrames += stats.video.framesPerSecond;
      this.droppedFrames += stats.video.framesDroppedDelta;
    }
  }
  
  getReport() {
    const elapsed = (Date.now() - this.startTime) / 1000;
    const avgFps = this.totalFrames / elapsed;
    const dropRate = (this.droppedFrames / this.totalFrames) * 100;
    
    return {
      duration: Math.round(elapsed),
      averageFps: Math.round(avgFps),
      totalDropped: this.droppedFrames,
      dropRate: dropRate.toFixed(2) + '%'
    };
  }
}

const tracker = new PerformanceTracker(client);

// Later: get performance report
const report = tracker.getReport();
console.log('Performance report:', report);

See Also

Build docs developers (and LLMs) love