UNPKG

mediasfu-reactnative-expo

Version:

mediasfu-reactnative-expo – Expo-managed React Native WebRTC SDK for video conferencing, webinars, live streaming, broadcast, screen sharing, whiteboard, chat, recording, live subtitles, translation, and AI agent rooms on iOS, Android, and web. Prebuilt r

279 lines 13.3 kB
import React, { useEffect, useRef, useState } from 'react'; import { View, StyleSheet, Platform } from 'react-native'; import { RTCView } from '../webrtc/webrtc'; const getParticipantForProducer = (participants, remoteProducerId) => participants.find((participant) => participant.audioID === remoteProducerId); const isTranslationSuppressingOriginal = (updatedParams, remoteProducerId, participant) => { if (!participant?.name) { return false; } const speakerTranslationStates = updatedParams.speakerTranslationStates; const speakerState = speakerTranslationStates?.get(participant.name); return Boolean(speakerState?.enabled && speakerState.originalProducerId === remoteProducerId); }; /** * MiniAudioPlayer component for Web - Renders audio streams with optional waveform visualization. * * Platform-specific implementation optimized for web browsers. Supports component override * for the MiniAudio visualization component, enabling custom audio waveform displays. * * @component * @platform web * @param {MiniAudioPlayerOptions} props - The properties for the MiniAudioPlayer component. * @param {MediaStream | null} props.stream - The media stream to be played by the audio player. * @param {Consumer} props.consumer - The consumer object for consuming media. * @param {string} props.remoteProducerId - The ID of the remote producer. * @param {MiniAudioPlayerParameters} props.parameters - The parameters object containing various settings and methods. * @param {React.ComponentType} [props.MiniAudioComponent] - Optional component override for audio visualization. * Replaces the default MiniAudio component with your custom visualization component. * @param {Object} [props.miniAudioProps] - Additional properties to pass to the MiniAudioComponent. * * @returns {JSX.Element} The rendered MiniAudioPlayer component optimized for web browsers. * * @see {@link MiniAudioPlayer} for complete documentation and usage examples. * * @example * ```tsx * // Import and use MiniAudioPlayer in a React component * import { MiniAudioPlayer } from 'mediasfu-reactnative-expo'; * * const WaveformVisualizer = ({ stream }: { stream: MediaStream }) => ( * <canvas width='300' height='50' /> * ); * * const App = () => { * const stream = useMediaStream(); // Custom hook to get MediaStream * const parameters = { * // Mocked parameters with required functions * getUpdatedAllParams: () => updatedParameters, * reUpdateInter: () => {}, * updateParticipantAudioDecibels: () => {}, * breakOutRoomStarted: false, * breakOutRoomEnded: false, * limitedBreakRoom: [], * }; * * return ( * <MiniAudioPlayer * stream={stream} * consumer={consumer} * remoteProducerId='producer123' * parameters={parameters} * MiniAudioComponent={WaveformVisualizer} * miniAudioProps={{ color: 'blue' }} * /> * ); * }; * ``` */ const MiniAudioPlayer = ({ stream, remoteProducerId, consumer, parameters, MiniAudioComponent, miniAudioProps, }) => { const { getUpdatedAllParams } = parameters; parameters = getUpdatedAllParams(); const { reUpdateInter, updateParticipantAudioDecibels, breakOutRoomStarted, breakOutRoomEnded, limitedBreakRoom, } = parameters; const parameterMiniAudioComponent = parameters .miniAudioComponent; const resolvedMiniAudioComponent = MiniAudioComponent ?? parameterMiniAudioComponent; const [showWaveModal, setShowWaveModal] = useState(false); const [isMuted, setIsMuted] = useState(true); const autoWaveCheck = useRef(false); useEffect(() => { if (stream) { let consLow = false; let averageLoudness = 128; const intervalId = setInterval(() => { try { const receiver = consumer.rtpReceiver; receiver?.getStats().then((stats) => { stats.forEach((report) => { if (report.type === 'inbound-rtp' && report.kind === 'audio' && report.audioLevel) { averageLoudness = 127.5 + report.audioLevel * 127.5; } }); }); } catch { // Do nothing } const updatedParams = getUpdatedAllParams(); let { eventType, meetingDisplayType, shared, shareScreenStarted, dispActiveNames, adminNameStream, participants, activeSounds, autoWave, updateActiveSounds, paginatedStreams, currentUserPage, } = updatedParams; const participant = getParticipantForProducer(participants, remoteProducerId); const translationSuppressingOriginal = isTranslationSuppressingOriginal(updatedParams, remoteProducerId, participant); let audioActiveInRoom = true; if (participant) { if (breakOutRoomStarted && !breakOutRoomEnded) { if (participant.name && !limitedBreakRoom .map((obj) => obj.name) .includes(participant.name)) { audioActiveInRoom = false; } } } if (meetingDisplayType !== 'video') { autoWaveCheck.current = true; } if (shared || shareScreenStarted) { autoWaveCheck.current = false; } if (participant) { if (translationSuppressingOriginal) { setShowWaveModal(false); setIsMuted(true); if (participant.name && activeSounds.includes(participant.name)) { activeSounds.splice(activeSounds.indexOf(participant.name), 1); } updateActiveSounds(activeSounds); return; } setIsMuted(participant.muted ?? false); if (eventType !== 'chat' && eventType !== 'broadcast') { updateParticipantAudioDecibels({ name: participant.name ?? '', averageLoudness, audioDecibels: updatedParams.audioDecibels, updateAudioDecibels: updatedParams.updateAudioDecibels, }); } const inPage = paginatedStreams[currentUserPage]?.findIndex((obj) => obj.name === participant.name) ?? -1; if (participant.name && !dispActiveNames.includes(participant.name) && inPage == -1) { autoWaveCheck.current = false; if (!adminNameStream) { const adminParticipant = participants.find((obj) => obj.islevel == '2'); adminNameStream = adminParticipant ? adminParticipant.name : ''; } if (participant.name == adminNameStream) { autoWaveCheck.current = true; } } else { autoWaveCheck.current = true; } if (participant.videoID || autoWaveCheck.current || (breakOutRoomStarted && !breakOutRoomEnded && audioActiveInRoom)) { setShowWaveModal(false); if (averageLoudness > 127.5) { if (participant.name && !activeSounds.includes(participant.name)) { activeSounds.push(participant.name); consLow = false; if (!(shareScreenStarted || shared) || participant.videoID) { if (eventType !== 'chat' && eventType !== 'broadcast' && participant.name) { reUpdateInter({ name: participant.name ?? '', add: true, average: averageLoudness, parameters: updatedParams, }); } } } } else if (participant.name && activeSounds.includes(participant.name) && consLow) { activeSounds.splice(activeSounds.indexOf(participant.name), 1); if (!(shareScreenStarted || shared) || participant.videoID) { if (eventType !== 'chat' && eventType !== 'broadcast' && participant.name) { reUpdateInter({ name: participant.name ?? '', average: averageLoudness, parameters: updatedParams, }); } } } else { consLow = true; } } else if (averageLoudness > 127.5) { if (!autoWave) { setShowWaveModal(false); } else { setShowWaveModal(true); } if (participant.name && !activeSounds.includes(participant.name)) { activeSounds.push(participant.name); } if ((shareScreenStarted || shared) && !participant.videoID) { /* empty */ } else if (eventType != 'chat' && eventType != 'broadcast' && participant.name) { reUpdateInter({ name: participant.name, add: true, average: averageLoudness, parameters: updatedParams, }); } } else { setShowWaveModal(false); if (participant.name && activeSounds.includes(participant.name)) { activeSounds.splice(activeSounds.indexOf(participant.name), 1); } if ((shareScreenStarted || shared) && !participant.videoID) { /* empty */ } else if (eventType != 'chat' && eventType != 'broadcast' && participant.name) { reUpdateInter({ name: participant.name, average: averageLoudness, parameters: updatedParams, }); } } updateActiveSounds(activeSounds); } else { setShowWaveModal(false); setIsMuted(true); } }, 2000); return () => { clearInterval(intervalId); }; } }, [stream]); const renderMiniAudioComponent = () => { if (resolvedMiniAudioComponent) { const MiniAudioComponentToRender = resolvedMiniAudioComponent; return (<MiniAudioComponentToRender showWaveform={showWaveModal} visible={showWaveModal && !isMuted} {...miniAudioProps}/>); } return null; }; return (<View style={styles.container}> {/* RTCView for displaying the audio stream */} {!isMuted && stream && Platform.OS === 'web' ? (<RTCView stream={stream} style={styles.audioPlayer}/>) : !isMuted && stream ? (<RTCView streamURL={stream?.toURL()} style={styles.audioPlayer}/>) : null} {renderMiniAudioComponent()} </View>); }; const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', elevation: 9, zIndex: 9, }, audioPlayer: { width: 0, height: 0, }, }); export default MiniAudioPlayer; //# sourceMappingURL=MiniAudioPlayer.web.js.map