import { RouteProp } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import {
ContentHint,
StreamKinds,
VideoViewer,
useDisplayMedia,
usePublisher,
usePublisherState,
useRemoteStreams,
useSharedDisplayMedia,
useSharedUserMedia,
} from 'bluesea-media-react-native-sdk';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { Dimensions, TouchableOpacity, View } from 'react-native';
import useAppState from 'react-native-appstate-hook';
import Icon from 'react-native-vector-icons/Ionicons';
import IconM from 'react-native-vector-icons/MaterialCommunityIcons';
import { outgoingAudioIssueEvent } from '../../../App';
import {
LOCAL_AUDIO_STREAM_ID,
LOCAL_SCREEN_STREAM_ID,
LOCAL_VIDEO_STREAM_ID,
audio_config,
audio_publisher_config,
screen_config,
screen_publisher_config,
video_config,
video_publisher_config,
} from 'screens/calling/config';
import RNCallKeep from 'react-native-callkeep';
import { RootStackParamList } from 'navigation/types';
import { CallType } from 'contexts/calling/hooks';
import { DataContainer, useReactionState } from 'utils/reaction';
import ViewerItem from './ViewerItem';
import { BlueseaSenders, EBlueseaStreamPriority, Stream } from './types';
import { RemoteBigViewer } from './RemoteBigViewer';
import { usePeerRemoteStreamActive } from 'screens/calling/hooks';
import { Flex, Pressable } from 'native-base';
const { width } = Dimensions.get('window');
const widthButton = Math.min((width - 48 - 48) / 5, 80);
type Navigation = NativeStackNavigationProp<RootStackParamList, 'VideoCall'>;
type Route = RouteProp<RootStackParamList, 'VideoCall'>;
interface IProps {
navigation: Navigation;
route: Route;
exit: () => void;
toggle: () => void;
}
export const CallControlsContainer = ({ route, exit, toggle, navigation }: IProps) => {
const [using_speaker, setUsingSpeaker] = useState(false);
const { appState } = useAppState();
const call = route.params.call;
const is_video_call = call.info.call_type == CallType.Video;
const [can_use_mic, setCanUseMic] = useState(true);
const [can_use_cam, setCanUseCam] = useState(is_video_call);
const mic_outgoing_issue_at = useReactionState(outgoingAudioIssueEvent);
const displayMedia = useDisplayMedia();
const [mic_stream, mic_err, switchMicStream] = useSharedUserMedia(LOCAL_AUDIO_STREAM_ID);
const [cam_stream, cam_err, switchCamStream] = useSharedUserMedia(LOCAL_VIDEO_STREAM_ID);
//const [screenStream, err, screenStreamChanger] = useSharedDisplayMedia(LOCAL_SCREEN_STREAM_ID);
const [screenStream, err, screenStreamChanger] = useSharedDisplayMedia(LOCAL_SCREEN_STREAM_ID);
const mic_container = useMemo<DataContainer<any>>(() => new DataContainer(null), []);
const [prvScreenStream, setPrvScreenStream] = React.useState<any>(null);
const mic_publisher = usePublisher(audio_publisher_config);
const cam_publisher = usePublisher(video_publisher_config);
const screen_publisher = usePublisher({
kind: StreamKinds.VIDEO,
name: 'screen_main',
stream: screenStream,
simulcast: true,
screen: true,
});
React.useEffect(() => {
if (!screenStream) {
return;
}
screen_publisher.switchStream(screenStream);
}, [screenStream, screen_publisher]);
//const screen_publisher = usePublisher(screen_publisher_config);
//const [state_send, screen_pub_stream] = usePublisherState(screen_publisher);
const screenVideoPublisher = usePublisher(BlueseaSenders.screen_video);
const screenAudioPublisher = usePublisher(audio_publisher_config);
//const [userState, setUserState] = useMeetingParticipantState();
const [, mic_pub_stream] = usePublisherState(mic_publisher);
const [, cam_pub_stream] = usePublisherState(cam_publisher);
const [shareScreen, screenPublisherStream] = usePublisherState(screenVideoPublisher);
console.log('Start screenPublisherStream ==================================>');
console.log(screenPublisherStream);
console.log('End===========================================================>');
console.log('Start screenStream ==================================>');
console.log(screenStream);
console.log('End===========================================================>');
const video_streams = useRemoteStreams(StreamKinds.VIDEO, true);
// React.useEffect(() => {
// if (!screenStream) {
// return;
// }
// screenAudioPublisher.switchStream(screenStream);
// }, [screenAudioPublisher, screenStream]);
// React.useEffect(() => {
// screenVideoPublisher.switchStream(screenStream);
// if (screenStream) {
// //setUserState({ ...userState, screenShare: true });
// //sendEvent('screen-share', { screenShare: true });
// } else {
// if (prvScreenStream) {
// //setUserState({ ...userState, screenShare: false });
// //sendEvent('screen-share', { screenShare: false });
// }
// }
// }, [
// //currentParticipant.id,
// prvScreenStream,
// screenStream,
// screenVideoPublisher,
// // sendEvent,
// // setUserState,
// // userState,
// ]);
// For init streams
useEffect(() => {
switchMicStream(audio_config);
RNCallKeep.addEventListener('didChangeAudioRoute', ({ output }) => {
setUsingSpeaker(output == 'Speaker' || output == 'SPEAKER');
});
RNCallKeep.addEventListener('didPerformSetMutedCallAction', ({ callUUID, muted }) => {
if (muted) {
mic_publisher.switchStream(null);
} else {
mic_publisher.switchStream(mic_container.getValue || null);
}
});
return () => {
RNCallKeep.removeEventListener('didChangeAudioRoute');
RNCallKeep.removeEventListener('didPerformSetMutedCallAction');
};
}, []);
const onEndedScreenShare = React.useCallback(() => {
screenStreamChanger(undefined);
}, []);
React.useEffect(() => {
screenStream?.stream.getVideoTracks()?.[0]?.addEventListener('ended', onEndedScreenShare);
return () => {
screenStream?.stream.getVideoTracks()?.[0]?.removeEventListener('ended', onEndedScreenShare);
};
}, [screenStream?.stream]);
useEffect(() => {
if (!!mic_outgoing_issue_at && can_use_mic) {
// switchMicStream(audio_config)
}
}, [mic_outgoing_issue_at, can_use_mic]);
useEffect(() => {
if (appState == 'active' && can_use_cam) {
switchCamStream(video_config);
} else {
switchCamStream(undefined);
}
}, [switchCamStream, can_use_cam, appState]);
// For control publisher streams
useEffect(() => {
mic_container.change(mic_stream);
mic_publisher.switchStream(mic_stream);
}, [mic_stream]);
// useEffect(() => {
// console.log('screen stream', screenStream);
// if (appState == 'active' && !!screenStream) {
// screenVideoPublisher.switchStream(screenStream);
// // cam_publisher.switchStream(cam_stream);
// return () => {
// screenVideoPublisher?.switchStream(null);
// };
// }
// }, [screenVideoPublisher, appState, screenStream]);
useEffect(() => {
console.log('cam_stream', cam_stream);
if (appState == 'active' && !!cam_stream) {
cam_publisher.switchStream(cam_stream);
return () => {
cam_publisher?.switchStream(null);
};
}
}, [cam_publisher, appState, cam_stream]);
const toggleMic = React.useCallback(() => {
let new_can_use_mic = !can_use_mic;
setCanUseMic(new_can_use_mic);
if (mic_publisher) {
if (new_can_use_mic) {
RNCallKeep.setMutedCall(call.info.call_id, false);
mic_publisher.switchStream(mic_stream || null);
} else {
RNCallKeep.setMutedCall(call.info.call_id, true);
mic_publisher.switchStream(null);
}
}
}, [can_use_mic, mic_stream, mic_publisher]);
const toggleCam = React.useCallback(() => {
setCanUseCam(!can_use_cam);
}, [can_use_cam]);
const toggleShare = React.useCallback(() => {
setPrvScreenStream(screenStream);
if (screenPublisherStream) {
screenStreamChanger(undefined);
} else {
screenStreamChanger(screen_config);
}
}, []);
const actions = React.useMemo(
() => [
{
is_active: !!mic_pub_stream,
is_alert: !!mic_err || !!mic_outgoing_issue_at,
icon: !!mic_pub_stream ? 'mic-outline' : 'mic-off-outline',
onPress: toggleMic,
},
{
is_active: !!cam_pub_stream,
is_alert: false,
icon: !!cam_pub_stream ? 'videocam-outline' : 'videocam-off-outline',
//icon: 'videocam-outline',
onPress: toggleCam,
},
{
is_active: false,
is_alert: false,
icon: 'share-outline',
onPress: toggleShare,
},
{
is_active: false,
is_alert: false,
icon: 'people-outline',
onPress: toggle,
},
{
is_active: false,
is_alert: false,
icon: 'close-outline',
onPress: exit,
},
],
[mic_pub_stream, mic_err, mic_outgoing_issue_at, cam_pub_stream, screenPublisherStream]
);
return (
<View>
{/* {screenStream && (
<VideoViewer
objectFit="cover"
style={{ width: 'full', height: 300 }}
stream={screenStream}
priority={1000}
/>
)} */}
<Flex
display="flex"
flexDirection="row"
px="5"
position="absolute"
w="full"
justifyContent="space-between">
{actions.map((item, index) => {
const { is_active, is_alert, icon, onPress } = item;
return (
<Pressable
w={widthButton}
h={widthButton}
justifyContent="center"
alignItems="center"
p="1"
borderRadius="full"
bg={is_active ? 'red' : 'white'}
key={index}
_pressed={{ opacity: 0.7 }}
onPress={onPress}>
{is_alert && (
<Icon
name="alert-circle"
style={{ position: 'absolute', right: 0, top: 0 }}
size={30}
color={'red'}
/>
)}
{index === actions.length - 1 ? (
<IconM
name="phone-hangup"
style={{ left: 1 }}
size={32}
color={is_active ? 'black' : 'white'}
/>
) : (
<Icon
name={icon}
style={{ left: 1 }}
size={32}
color={is_active ? 'white' : 'black'}
/>
)}
</Pressable>
);
})}
</Flex>
</View>
);
};