Audio Visualizer (Optional)
You can create real-time visualizations from the bot’s audio using Web Audio + the WebRTC room.
This is an example and can be adapted to your UI.
import { useConvaiClient } from "@convai/web-sdk/react";
import { useEffect, useRef, useState } from "react";
export function AudioVisualizer() {
const convaiClient = useConvaiClient({
apiKey: "your-api-key",
characterId: "your-character-id",
});
const canvasRef = useRef<HTMLCanvasElement | null>(null);
const [audioLevel, setAudioLevel] = useState(0);
useEffect(() => {
if (!convaiClient.room || !convaiClient.state.isConnected) return;
let animationId: number;
const audioContext = new AudioContext();
let analyzer: AnalyserNode | null = null;
let dataArray: Uint8Array | null = null;
const setup = async () => {
const remoteParticipants = Array.from(
convaiClient.room.remoteParticipants.values()
);
if (!remoteParticipants.length) return;
const participant = remoteParticipants[0];
const publications = Array.from(
participant.audioTrackPublications.values()
);
if (!publications.length || !publications[0].track) return;
const track = publications[0].track!;
const mediaStream = new MediaStream([track.mediaStreamTrack]);
const source = audioContext.createMediaStreamSource(mediaStream);
analyzer = audioContext.createAnalyser();
analyzer.fftSize = 256;
source.connect(analyzer);
dataArray = new Uint8Array(analyzer.frequencyBinCount);
const render = () => {
if (!analyzer || !dataArray) return;
analyzer.getByteFrequencyData(dataArray);
const sum = dataArray.reduce((a, b) => a + b, 0);
const avg = sum / dataArray.length;
setAudioLevel(avg / 255);
const canvas = canvasRef.current;
if (canvas) {
const ctx = canvas.getContext("2d");
if (ctx) {
const { width, height } = canvas;
ctx.clearRect(0, 0, width, height);
const barWidth = (width / dataArray.length) * 2.5;
let x = 0;
for (let i = 0; i < dataArray.length; i++) {
const barHeight = (dataArray[i] / 255) * height;
ctx.fillRect(x, height - barHeight, barWidth, barHeight);
x += barWidth + 1;
}
}
}
animationId = requestAnimationFrame(render);
};
render();
};
setup();
return () => {
if (animationId) cancelAnimationFrame(animationId);
audioContext.close().catch(() => {});
};
}, [convaiClient.room, convaiClient.state.isConnected]);
return (
<div>
<canvas
ref={canvasRef}
width={800}
height={200}
style={{ border: "1px solid #ccc" }}
/>
<div>Audio Level: {(audioLevel * 100).toFixed(0)}%</div>
</div>
);
}Last updated
Was this helpful?