/** * Exemplo básico de uso do Avatar Stream SDK */ import { AvatarStreamSDK, StreamStatus, StreamMetrics } from '../src'; // Elemento canvas do HTML const canvas = document.getElementById('avatar-canvas') as HTMLCanvasElement; // Elementos de UI para métricas const statusEl = document.getElementById('status')!; const latencyEl = document.getElementById('latency')!; const fpsEl = document.getElementById('fps')!; const videoDurationEl = document.getElementById('video-duration')!; const audioDurationEl = document.getElementById('audio-duration')!; const syncDiffEl = document.getElementById('sync-diff')!; // Criar instância do SDK const avatar = new AvatarStreamSDK({ wsUrl: 'ws://localhost:8080/ws', canvas, // Callbacks de status onStatusChange: (status: StreamStatus) => { console.log('Status:', status); statusEl.textContent = status; // Atualizar cor baseado no status statusEl.className = ''; if (status === 'playing') statusEl.classList.add('status-playing'); else if (status === 'error') statusEl.classList.add('status-error'); else if (status === 'completed') statusEl.classList.add('status-completed'); }, // Callback de métricas (chamado frequentemente) onMetricsUpdate: (metrics: StreamMetrics) => { fpsEl.textContent = metrics.currentFps.toFixed(0); videoDurationEl.textContent = metrics.videoDuration.toFixed(2) + 's'; audioDurationEl.textContent = metrics.audioDuration.toFixed(2) + 's'; // Colorir diferença de sync const diff = metrics.syncDiff; syncDiffEl.textContent = (diff >= 0 ? '+' : '') + diff.toFixed(2) + 's'; if (Math.abs(diff) < 0.1) { syncDiffEl.style.color = 'green'; } else if (Math.abs(diff) < 0.5) { syncDiffEl.style.color = 'orange'; } else { syncDiffEl.style.color = 'red'; } }, // Callback quando o primeiro frame chega onFirstFrame: (latencyMs: number) => { console.log(`Primeiro frame: ${latencyMs}ms`); }, // Callback quando o playback inicia onPlaybackStart: (latencyMs: number) => { console.log(`Playback iniciado: ${latencyMs}ms`); latencyEl.textContent = latencyMs + 'ms'; }, // Callback quando o stream termina onComplete: (summary) => { console.log('Stream completo:', summary); console.log(`Total frames: ${summary.totalFrames}`); console.log(`Duração: ${summary.durationSeconds.toFixed(2)}s`); console.log(`Sync final: ${summary.finalSyncDiff.toFixed(3)}s`); }, // Callback de erro onError: (error) => { console.error('Erro:', error); alert(`Erro: ${error.message}`); }, }); // Botão de conectar document.getElementById('btn-connect')?.addEventListener('click', async () => { try { await avatar.connect(); console.log('Conectado!'); } catch (e) { console.error('Erro ao conectar:', e); } }); // Botão de gerar document.getElementById('btn-generate')?.addEventListener('click', async () => { const text = (document.getElementById('text-input') as HTMLTextAreaElement)?.value; const voice = (document.getElementById('voice-select') as HTMLSelectElement)?.value; if (!text) { alert('Digite um texto!'); return; } try { await avatar.generate(text, voice); } catch (e) { console.error('Erro ao gerar:', e); } }); // Botão de parar document.getElementById('btn-stop')?.addEventListener('click', () => { avatar.stop(); }); // Botão de desconectar document.getElementById('btn-disconnect')?.addEventListener('click', () => { avatar.disconnect(); }); // Conectar automaticamente ao carregar avatar.connect().then(() => { console.log('Conectado automaticamente'); }).catch(e => { console.log('Auto-connect falhou:', e); });