File size: 3,717 Bytes
3acaae2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | /**
* 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);
});
|