import { Socket } from "phoenix"; export const VadHook = { async mounted() { const statusDiv = document.getElementById("vad-status"); const ortScript = document.createElement("script"); ortScript.src = "https://cdn.jsdelivr.net/npm/onnxruntime-web@1.14.0/dist/ort.js"; const vadScript = document.createElement("script"); vadScript.src = "https://cdn.jsdelivr.net/npm/@ricky0123/vad-web@0.0.22/dist/bundle.min.js"; ortScript.onload = () => { vadScript.onload = async () => { this.socket = new Socket("ws://localhost:4003/socket"); this.socket.connect(); this.channel = this.socket.channel("audio:lobby"); await this.channel.join().receive("ok", () => { console.log("✅ Canal audio:lobby unido."); }); const myvad = await vad.MicVAD.new({ onSpeechStart: () => { statusDiv.textContent = "🎤 Voz detectada..."; }, onSpeechEnd: async (float32Audio) => { statusDiv.textContent = "✅ Voz finalizada. Enviando audio..."; // Enviar el audio correctamente formateado await sendAudioChunk(float32Audio, this.channel); // Indicar stop si querés (como payload vacío JSON) this.channel.push("stop_audio", {}); } }); myvad.start(); statusDiv.textContent = "🚀 VAD iniciado."; }; document.body.appendChild(vadScript); }; document.body.appendChild(ortScript); } }; // Función de helper para enviar el chunk function float32ToInt16(float32Array) { const int16Array = new Int16Array(float32Array.length); for (let i = 0; i < float32Array.length; i++) { let s = Math.max(-1, Math.min(1, float32Array[i])); int16Array[i] = s < 0 ? s * 0x8000 : s * 0x7FFF; } return int16Array; } async function sendAudioChunk(float32Audio, channel) { const pcm16 = float32ToInt16(float32Audio); const header = JSON.stringify({ sample_rate: 16000 }); const headerBytes = new TextEncoder().encode(header); const audioBytes = new Uint8Array(pcm16.buffer); // same as merged in el otro ejemplo const totalLength = 2 + headerBytes.length + audioBytes.length; const buffer = new ArrayBuffer(totalLength); const view = new DataView(buffer); // Encabezado: longitud en big endian view.setUint16(0, headerBytes.length, false); // <== big endian // Copiar header y audio al buffer new Uint8Array(buffer, 2, headerBytes.length).set(headerBytes); new Uint8Array(buffer, 2 + headerBytes.length).set(audioBytes); // Enviar el buffer binario channel.push("audio_chunk", buffer); console.log("📤 Chunk binario enviado"); }