Files
var-monorepo/apps/dispatch/app/_components/MicVolumeIndication.tsx

76 lines
2.1 KiB
TypeScript

"use client";
import { cn } from "@repo/shared-components";
import { useEffect, useState } from "react";
type MicrophoneLevelProps = {
deviceId: string;
volumeInput: number; // Verstärkung der Lautstärke
};
export default function MicrophoneLevel({ deviceId, volumeInput }: MicrophoneLevelProps) {
const [volumeLevel, setVolumeLevel] = useState(0);
useEffect(() => {
let audioContext: AudioContext | null = null;
let analyser: AnalyserNode | null = null;
let source: MediaStreamAudioSourceNode | null = null;
let rafId: number;
async function start() {
audioContext = new AudioContext();
const stream = await navigator.mediaDevices.getUserMedia({
audio: { deviceId: deviceId ? { exact: deviceId } : undefined },
});
source = audioContext.createMediaStreamSource(stream);
analyser = audioContext.createAnalyser();
analyser.fftSize = 256;
source.connect(analyser);
const dataArray = new Uint8Array(analyser.frequencyBinCount);
const updateVolume = () => {
if (!analyser) return;
analyser.getByteFrequencyData(dataArray);
const avg = dataArray.reduce((a, b) => a + b, 0) / dataArray.length;
setVolumeLevel(avg * volumeInput);
rafId = requestAnimationFrame(updateVolume);
};
updateVolume();
}
start();
return () => {
cancelAnimationFrame(rafId);
audioContext?.close();
};
}, [deviceId, volumeInput]);
const barWidth = Math.min((volumeLevel / 140) * 100, 100);
return (
<div className="w-full">
<div className="relative w-full bg-base-300 h-5 rounded">
<div
className={cn("bg-primary h-full rounded", barWidth == 100 && "bg-red-400")}
style={{
width: `${barWidth}%`,
transition: "width 0.2s",
}}
/>
<div
className="absolute top-0 left-[60%] w-[30%] h-full bg-green-500 opacity-40 rounded"
style={{
transform: "translateX(-50%)",
}}
/>
</div>
<p className="text-gray-500 text-sm">
Lautstärke sollte beim Sprechen in dem Grünen bereich bleiben. Beachte das scharfe Laute
(z.B. "S" oder "Z") die Anzeige verfälschen können.
</p>
</div>
);
}