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
JavaScript
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 Android - Renders audio streams with optional waveform visualization.
*
* Platform-specific implementation optimized for Android devices. Supports component override
* for the MiniAudio visualization component, enabling custom audio waveform displays.
*
* @component
* @platform android
* @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 Android.
*
* @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.android.js.map