feat(frontend): perbagus voice & audio playback UX

- Recordings: custom RecordingAudioPlayer (play/pause, buffering spinner,
  click-to-seek, time label, eq bars, single-playback antar kartu) +
  highlight kartu now-playing
- Media: thumbnail di disc hero + queue row, equalizer saat playing,
  badge 'up next', label Paused vs Now playing
- MiniPlayer global di AppFrame (fixed bottom-right, hidden on /media)
  menggantikan use-media-player.tsx dead provider (dihapus)
- Voice: mic level meter live (AnalyserNode RMS) + slider mic/listen volume
This commit is contained in:
asepharyana
2026-08-22 12:53:18 +07:00
parent df69b3f05d
commit 4e0c21d86c
10 changed files with 677 additions and 184 deletions
+11 -1
View File
@@ -106,6 +106,7 @@ export function useMicTransmit(ws: {
sendBinary: (data: ArrayBufferLike) => void;
}) {
const transmitterRef = useRef<MicTransmitter | null>(null);
const [micLevel, setMicLevel] = useState(0);
const action = useAction(async (active: boolean) => {
if (active) {
@@ -116,6 +117,7 @@ export function useMicTransmit(ws: {
} else {
transmitterRef.current?.stop();
transmitterRef.current = null;
setMicLevel(0);
await voiceApi.sendCommand("voice:transmit:stop");
}
});
@@ -124,7 +126,15 @@ export function useMicTransmit(ws: {
transmitterRef.current?.setVolume(volume / 100);
}, []);
return { ...action, setVolume };
// Poll the analyser RMS so the UI can render a live input meter.
useEffect(() => {
const timer = setInterval(() => {
setMicLevel(transmitterRef.current?.getLevel() ?? 0);
}, 120);
return () => clearInterval(timer);
}, []);
return { ...action, setVolume, micLevel };
}
/**