/**
* useAudioLevels Hook
* React hook for VU meter / audio level monitoring
* Provides real-time audio levels from the AudioMixer
*/
import { useState, useEffect, useCallback, useRef } from "react";
import type { IngestControllerV2 } from "@livepeer-frameworks/streamcrafter-core";
export interface AudioLevels {
level: number; // Current level 0-1
peakLevel: number; // Peak level with decay 0-1
}
export interface UseAudioLevelsOptions {
/** IngestControllerV2 instance to monitor */
controller: IngestControllerV2 | null;
/** Whether to automatically start monitoring (default: true) */
autoStart?: boolean;
}
export interface UseAudioLevelsReturn {
/** Current audio levels */
levels: AudioLevels;
/** Whether level monitoring is active */
isMonitoring: boolean;
/** Start level monitoring */
startMonitoring: () => void;
/** Stop level monitoring */
stopMonitoring: () => void;
}
/**
* Hook for monitoring audio levels (VU meter)
*
* @example
* ```tsx
* const { controller } = useStreamCrafterV2({ whipUrl });
* const { levels, isMonitoring } = useAudioLevels({ controller });
*
* return (
*
* );
* ```
*/
export function useAudioLevels(options: UseAudioLevelsOptions): UseAudioLevelsReturn {
const { controller, autoStart = true } = options;
const [levels, setLevels] = useState({ level: 0, peakLevel: 0 });
const [isMonitoring, setIsMonitoring] = useState(false);
const unsubscribeRef = useRef<(() => void) | null>(null);
// Start monitoring
const startMonitoring = useCallback(() => {
if (!controller) return;
const audioMixer = controller.getAudioMixer();
if (!audioMixer) return;
// Subscribe to level updates
const unsubscribe = audioMixer.on("levelUpdate", (event) => {
setLevels({ level: event.level, peakLevel: event.peakLevel });
});
unsubscribeRef.current = unsubscribe;
// Start the audio mixer's level monitoring
audioMixer.startLevelMonitoring();
setIsMonitoring(true);
}, [controller]);
// Stop monitoring
const stopMonitoring = useCallback(() => {
if (!controller) return;
const audioMixer = controller.getAudioMixer();
if (audioMixer) {
audioMixer.stopLevelMonitoring();
}
if (unsubscribeRef.current) {
unsubscribeRef.current();
unsubscribeRef.current = null;
}
setIsMonitoring(false);
setLevels({ level: 0, peakLevel: 0 });
}, [controller]);
// Auto-start monitoring when controller is available and autoStart is true
useEffect(() => {
if (autoStart && controller) {
startMonitoring();
}
return () => {
stopMonitoring();
};
}, [controller, autoStart, startMonitoring, stopMonitoring]);
return {
levels,
isMonitoring,
startMonitoring,
stopMonitoring,
};
}