UNPKG

@revrag-ai/embed-react-native

Version:

A powerful React Native library for integrating AI-powered voice agents into mobile applications. Features real-time voice communication, intelligent speech processing, customizable UI components, and comprehensive event handling for building conversation

141 lines (130 loc) 4.24 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _reactNative = require("@livekit/react-native"); var _react = require("react"); var _jsxRuntime = require("react/jsx-runtime"); // export interface VoiceProps { // url: string; // token: string; // onDisconnected: (data: string) => void; // onConnected: (data: string) => void; // } // Track audio session state globally to prevent multiple starts/stops let audioSessionActive = false; let audioSessionStarting = false; let audioSessionStopping = false; // Track connection to prevent unmounting while connected let activeConnectionToken = null; const Voice = props => { const { url, token, onDisconnected, onConnected, roomRef } = props; const [audioSessionStarted, setAudioSessionStarted] = (0, _react.useState)(audioSessionActive); const mountedRef = (0, _react.useRef)(true); const connectedRef = (0, _react.useRef)(false); // Start audio session safely - prevent multiple simultaneous starts const startAudioSession = async () => { if (audioSessionActive || audioSessionStarting) { console.log('Audio session already active or starting'); return; } try { audioSessionStarting = true; await _reactNative.AudioSession.startAudioSession(); audioSessionActive = true; if (mountedRef.current) { setAudioSessionStarted(true); } } catch (err) { console.error('Failed to start audio session:', err); // Set as started anyway to prevent blocking if (mountedRef.current) { setAudioSessionStarted(true); } } finally { audioSessionStarting = false; } }; // Stop audio session safely - prevent multiple simultaneous stops const stopAudioSession = async () => { if (!audioSessionActive || audioSessionStopping) { // todo: handle audio session already inactive or stopping return; } try { audioSessionStopping = true; await _reactNative.AudioSession.stopAudioSession(); audioSessionActive = false; } catch (err) { // todo: handle failed to stop audio session } finally { audioSessionStopping = false; } }; // Setup audio session (0, _react.useEffect)(() => { mountedRef.current = true; // Capture room at effect setup time for cleanup const room = roomRef.current; startAudioSession(); return () => { mountedRef.current = false; // IMPORTANT: Don't stop the audio session on unmount if there might be an active call // This prevents audio session start/stop loops when components remount if (room?.state !== 'connected' && !connectedRef.current) { stopAudioSession(); } else { // todo: handle skipping audio session stop because room is still connected } }; }, [roomRef]); // Track connection state changes to avoid unmounting while connected (0, _react.useEffect)(() => { if (token) { activeConnectionToken = token; } return () => { // Only clear token when unmounting with this specific token if (activeConnectionToken === token) { activeConnectionToken = null; } }; }, [token]); // Safety check - don't render if we don't have valid props if (!url || !token) { console.warn('Voice component missing url or token'); return null; } // Only render LiveKitRoom when audio session is ready if (!audioSessionStarted) { return null; } // IMPORTANT: Never return empty fragment when connected! // Instead, always render the LiveKitRoom component to maintain the connection return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.LiveKitRoom, { serverUrl: url, token: token, screen: false, audio: true, onConnected: () => { // todo: handle livekit room connected connectedRef.current = true; onConnected('connected'); }, room: roomRef.current || undefined, onDisconnected: () => { // todo: handle livekit room disconnected connectedRef.current = false; onDisconnected('disconnected'); } }); }; var _default = exports.default = Voice; //# sourceMappingURL=EmbedVoice.js.map