UNPKG

@airsurfer09/web-handsfree

Version:

A React package for integrating Convai's AI-powered voice assistants with LiveKit for real-time audio/video conversations

219 lines 7.54 kB
import { useCallback, useState, useEffect } from "react"; import { logger } from "../utils/logger"; /** * Hook for managing audio controls in LiveKit. * * Provides methods to enable/disable microphone, manage audio devices, * and control audio visibility state. * * @param {Room | null} room - LiveKit room instance * @returns {AudioControls} Object containing audio control methods and state * * @example * ```tsx * function AudioControls() { * const audioControls = useAudioControls(room); * * return ( * <div> * <button onClick={audioControls.toggleAudio}> * {audioControls.isAudioEnabled ? 'Mute' : 'Unmute'} * </button> * </div> * ); * } * ``` */ export const useAudioControls = (room) => { const [isAudioEnabled, setIsAudioEnabled] = useState(false); const [isAudioMuted, setIsAudioMuted] = useState(false); const [audioLevel, setAudioLevel] = useState(0); // Update audio state when room changes useEffect(() => { if (!room) { setIsAudioEnabled(false); setIsAudioMuted(false); setAudioLevel(0); return; } const localParticipant = room.localParticipant; // Set initial state setIsAudioEnabled(localParticipant.isMicrophoneEnabled); setIsAudioMuted(false); // LiveKit doesn't have a direct muted state // Listen for audio state changes const handleTrackMuted = (track) => { if (track.source === 'microphone') { setIsAudioMuted(true); setIsAudioEnabled(false); logger.log("🔇 Audio muted"); } }; const handleTrackUnmuted = (track) => { if (track.source === 'microphone') { setIsAudioMuted(false); setIsAudioEnabled(true); logger.log("🎤 Audio unmuted"); } }; const handleTrackPublished = (track) => { if (track.source === 'microphone') { setIsAudioEnabled(true); setIsAudioMuted(false); logger.log("🎤 Audio track published"); } }; const handleTrackUnpublished = (track) => { if (track.source === 'microphone') { setIsAudioEnabled(false); setIsAudioMuted(true); logger.log("🔇 Audio track unpublished"); } }; // Subscribe to events localParticipant.on('trackMuted', handleTrackMuted); localParticipant.on('trackUnmuted', handleTrackUnmuted); localParticipant.on('trackPublished', handleTrackPublished); localParticipant.on('trackUnpublished', handleTrackUnpublished); return () => { localParticipant.off('trackMuted', handleTrackMuted); localParticipant.off('trackUnmuted', handleTrackUnmuted); localParticipant.off('trackPublished', handleTrackPublished); localParticipant.off('trackUnpublished', handleTrackUnpublished); }; }, [room]); // Enable audio const enableAudio = useCallback(async () => { if (!room) { logger.warn("Cannot enable audio: no room connection"); return; } try { await room.localParticipant.setMicrophoneEnabled(true); logger.log("🎤 Audio enabled successfully"); } catch (error) { logger.error("Failed to enable audio:", error); throw error; } }, [room]); // Disable audio const disableAudio = useCallback(async () => { if (!room) { logger.warn("Cannot disable audio: no room connection"); return; } try { await room.localParticipant.setMicrophoneEnabled(false); logger.log("🔇 Audio disabled successfully"); } catch (error) { logger.error("Failed to disable audio:", error); throw error; } }, [room]); // Mute audio const muteAudio = useCallback(async () => { if (!room) { logger.warn("Cannot mute audio: no room connection"); return; } try { // For now, we'll just disable the microphone as LiveKit doesn't have a direct mute method await room.localParticipant.setMicrophoneEnabled(false); logger.log("🔇 Audio muted successfully"); } catch (error) { logger.error("Failed to mute audio:", error); throw error; } }, [room]); // Unmute audio const unmuteAudio = useCallback(async () => { if (!room) { logger.warn("Cannot unmute audio: no room connection"); return; } try { await room.localParticipant.setMicrophoneEnabled(true); logger.log("🎤 Audio unmuted successfully"); } catch (error) { logger.error("Failed to unmute audio:", error); throw error; } }, [room]); // Toggle audio const toggleAudio = useCallback(async () => { if (isAudioMuted) { await unmuteAudio(); } else { await muteAudio(); } }, [isAudioMuted, muteAudio, unmuteAudio]); // Set audio device const setAudioDevice = useCallback(async (deviceId) => { if (!room) { logger.warn("Cannot set audio device: no room connection"); return; } try { await room.localParticipant.setMicrophoneEnabled(true, { deviceId }); logger.log("🎤 Audio device changed to:", deviceId); } catch (error) { logger.error("Failed to set audio device:", error); throw error; } }, [room]); // Get available audio devices const getAudioDevices = useCallback(async () => { try { const devices = await navigator.mediaDevices.enumerateDevices(); const audioDevices = devices.filter(device => device.kind === 'audioinput'); logger.log("🎤 Available audio devices:", audioDevices); return audioDevices; } catch (error) { logger.error("Failed to get audio devices:", error); throw error; } }, []); // Start audio level monitoring const startAudioLevelMonitoring = useCallback(() => { if (!room) { logger.warn("Cannot start audio monitoring: no room connection"); return; } logger.log("🎤 Audio level monitoring not implemented yet"); // TODO: Implement audio level monitoring when LiveKit provides the API }, [room]); // Stop audio level monitoring const stopAudioLevelMonitoring = useCallback(() => { if (!room) { logger.warn("Cannot stop audio monitoring: no room connection"); return; } setAudioLevel(0); logger.log("🎤 Audio level monitoring stopped"); }, [room]); return { // Audio state isAudioEnabled, isAudioMuted, audioLevel, // Audio controls enableAudio, disableAudio, muteAudio, unmuteAudio, toggleAudio, // Audio settings setAudioDevice, getAudioDevices, // Audio monitoring startAudioLevelMonitoring, stopAudioLevelMonitoring, }; }; //# sourceMappingURL=useAudioControls.js.map