import { useEffect, useRef, useState, useCallback } from 'react'; import { ToneListenReactNativeConfig, ToneSequenceEvent, DualToneResult, BridgeToneResult, AudioRecorderState } from '../types/ToneTypes'; import { ToneListenReactNative } from '../core/ToneListenReactNative'; import { NotificationCenter, NotificationNames } from '../utils/NotificationCenter'; import { DuplicateDetector } from '../utils/DuplicateDetector'; /** * React Native hook for tone detection * Provides easy integration with React components */ export const useToneDetection = (config: ToneListenReactNativeConfig = {}) => { const toneListenerRef = useRef(null); const [isListening, setIsListening] = useState(false); const [isInitialized, setIsInitialized] = useState(false); const [error, setError] = useState(null); const [lastSequence, setLastSequence] = useState(null); const [lastDualTone, setLastDualTone] = useState(null); const [lastBridgeTone, setLastBridgeTone] = useState(null); const [amplitude, setAmplitude] = useState(0); const [peakFrequency, setPeakFrequency] = useState(0); const [spectrumData, setSpectrumData] = useState<{frequencies: number[], powers: number[]} | null>(null); // Initialize tone listener useEffect(() => { const initializeToneListener = async () => { try { const toneListener = new ToneListenReactNative({ ...config, onSequence: (event: ToneSequenceEvent) => { setLastSequence(event.sequence); config.onSequence?.(event); }, onDualTone: (result: DualToneResult) => { setLastDualTone(result); config.onDualTone?.(result); }, onBridgeTone: (result: BridgeToneResult) => { setLastBridgeTone(result); config.onBridgeTone?.(result); }, onAmplitude: (amp: number) => { setAmplitude(amp); config.onAmplitude?.(amp); }, onPeakFrequency: (freq: number) => { setPeakFrequency(freq); config.onPeakFrequency?.(freq); }, onError: (err: Error) => { setError(err); config.onError?.(err); } }); // Set up notification listeners const notificationCenter = toneListener.getNotificationCenter(); // Listen for spectrum updates notificationCenter.addObserver(NotificationNames.toneListenSpectrumDidUpdate, (info) => { setSpectrumData({ frequencies: info.frequencies || [], powers: info.powers || [] }); }); const initialized = await toneListener.initialize(); if (initialized) { toneListenerRef.current = toneListener; setIsInitialized(true); } } catch (err) { setError(err as Error); } }; initializeToneListener(); // Cleanup on unmount return () => { if (toneListenerRef.current) { toneListenerRef.current.destroy(); toneListenerRef.current = null; } }; }, []); // Start listening const startListening = useCallback(async (): Promise => { if (!toneListenerRef.current) return false; try { const started = await toneListenerRef.current.start(); if (started) { setIsListening(true); setError(null); } return started; } catch (err) { setError(err as Error); return false; } }, []); // Stop listening const stopListening = useCallback((): void => { if (toneListenerRef.current) { toneListenerRef.current.stop(); setIsListening(false); } }, []); // Update configuration const updateConfig = useCallback((newConfig: Partial): void => { if (toneListenerRef.current) { toneListenerRef.current.updateConfig(newConfig); } }, []); // Get current state const getState = useCallback((): AudioRecorderState => { return toneListenerRef.current?.getState() || { isRecording: false, isInitialized: false, currentTime: 0, duration: 0 }; }, []); return { // State isListening, isInitialized, error, lastSequence, lastDualTone, lastBridgeTone, amplitude, peakFrequency, spectrumData, // Actions startListening, stopListening, updateConfig, getState, // Direct access to tone listener (for advanced usage) toneListener: toneListenerRef.current, // Access to utilities getNotificationCenter: () => toneListenerRef.current?.getNotificationCenter(), getDuplicateDetector: () => toneListenerRef.current?.getDuplicateDetector(), updateDuplicateDetectionTiming: (timingMs: number) => toneListenerRef.current?.updateDuplicateDetectionTiming(timingMs) }; };