Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
11 kB
3
Indexable
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>
  );
};