import React, {useEffect, useState} from 'react';
import { useNavigation } from '@react-navigation/core';
import {View, StyleSheet, Button, Alert} from 'react-native';
import {Text, IconButton} from 'react-native-paper';
import InCallManager from 'react-native-incall-manager';
import HuddleClient, { emitter } from 'react-native-huddle-client';
import {
RTCView,
MediaStream,
} from 'react-native-webrtc';
export default function RoomScreen({...props}) {
const navigation = useNavigation();
const params = props.route.params;
[huddle, setHuddle] = useState(null);
[remoteStream, setRemoteStream] = useState({toURL: () => null});
[localStream, setLocalStream] = useState({toURL: () => null});
[peer, setPeer] = useState(null);
[isMute, setMute] = useState(true);
[isCameraOn, setCameraOn] = useState(false);
[isOpenWaitingRoom, setOpenWaitingRoom] = useState(false);
[lobbyPeers, setLobbyPeers] = useState([]);
React.useLayoutEffect(() => {
navigation.setOptions({
headerRight: () => (
<Button onPress={() => {
navigation.push('Waiting', {huddle, lobbyPeers});
}} title="Waiting Room" />
),
})
}, [navigation]);
useEffect(() => {
let roomId = params.roomId;
const userName = params.userName;
const userId = generateId(8);
if (!roomId) {
roomId = generateId(8);
}
const config = {
apiKey: 'abcd',
hostname: 'alpha.huddle01.com:4443',
roomId: roomId,
peerId: userId,
displayName: userName,
isBot: false,
};
const h = new HuddleClient(config);
setHuddle(h);
navigation.setOptions({ title: roomId });
InCallManager.start({media: 'audio'});
InCallManager.setForceSpeakerphoneOn(true);
InCallManager.setSpeakerphoneOn(true);
return async () => {
await leaveRoom();
}
}, []);
useEffect(() => {
joinRoom();
}, [huddle]);
generateId = (length) => {
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
for ( var i = 0; i < length; i++ ) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
};
const enableDataProducers = async () => {
await huddle.enableChatDataProducer();
await huddle.enableBotDataProducer();
await huddle.enableMiscDataProducer();
await huddle.enableRaiseHandDataProducer();
await huddle.enableReactionsDataProducer();
await huddle.enableMiroDataProducer();
};
const setupEventListeners = async () => {
emitter.on("roomState", async (state) => {
console.log('emitter::roomState: ', state);
if (state === 'connected') {
await enableDataProducers();
await huddle.enableMic();
await disableMic();
}
});
emitter.on("error", (error) => {
console.log('emitter::error: ', JSON.stringify(error));
});
emitter.on("addPeer", (peer) => {
setPeer(peer);
console.log('emitter::addPeer: ', JSON.stringify(peer));
});
emitter.on("addProducer", (producer) => {
console.log('emitter::addProducer: ', JSON.stringify(producer));
if (producer.type === 'camera') {
const track = producer.track;
const stream = new MediaStream();
stream.addTrack(track);
setLocalStream(stream);
}
});
emitter.on("addConsumer", (consumer) => {
console.log('emitter::addConsumer: ', JSON.stringify(consumer));
const track = consumer.track;
const stream = new MediaStream();
stream.addTrack(track);
setRemoteStream(stream);
});
emitter.on("removePeer", (peer) => {
setPeer(null);
console.log('emitter::removePeer: ', JSON.stringify(peer));
});
emitter.on("removeProducer", (producer) => {
setLocalStream({toURL: () => null});
console.log('emitter::removeProducer: ', JSON.stringify(producer));
});
emitter.on("removeConsumer", (consumer) => {
setRemoteStream({toURL: () => null});
console.log('emitter::removeConsumer: ', JSON.stringify(consumer));
});
emitter.on("newLobbyPeer", (peers) => {
const lobbyPeers = peers.peers;
setLobbyPeers(lobbyPeers);
});
emitter.on("updatedPeersArray", (peers) => {
const lobbyPeers = peers.peers;
setLobbyPeers(lobbyPeers);
})
};
const joinRoom = async () => {
if (!huddle) return;
try {
setupEventListeners();
await huddle.join();
} catch (error) {
console.log(error);
}
};
const leaveRoom = async () => {
if (!huddle) return;
try {
await huddle.close();
// setRoomState(false);
} catch (error) {
console.log(error);
}
};
const enableCamera = async () => {
if (!huddle) return;
try {
await huddle.enableCamera();
} catch (error) {
console.log(error);
}
};
const disableCamera = async () => {
if (!huddle) return;
try {
await huddle.disableCamera();
} catch (error) {
console.log(error);
}
};
const enableMic = async () => {
if (!huddle) return;
try {
// await huddle.enableMic();
await huddle.unmuteMic();
} catch (error) {
console.log(error);
}
};
const disableMic = async () => {
if (!huddle) return;
try {
// await huddle.disableMic();
await huddle.muteMic();
} catch (error) {
console.log(error);
}
};
const sendMsg = async () => {
if (!huddle) return;
try {
await huddle.sendReaction("😂");
} catch (error) {
console.log(error);
}
};
const changeCamera = async () => {
if (!huddle) return;
try {
await huddle.changeCamera();
} catch (error) {
console.log(error);
}
};
const changeCameraResolution = async () => {
if (!huddle) return;
try {
await huddle.changeCameraResolution();
} catch (error) {
console.log(error);
}
};
const onToggleCamera = () => {
if (isCameraOn) {
disableCamera();
setCameraOn(false);
} else {
enableCamera();
setCameraOn(true);
}
};
const onToggleAudio = () => {
if (isMute) {
enableMic();
setMute(false);
} else {
disableMic();
setMute(true);
}
};
const onSwitchCamera = () => {
changeCamera();
};
const onAction = async () => {
if (!huddle) return;
try {
await huddle.sendReaction("😂");
} catch (error) {
console.log(error);
}
}
const onRaiseHand = async () => {
if (!huddle) return;
try {
await huddle.raiseHand("true");
} catch (error) {
console.log(error);
}
}
useEffect(() => {
}, []);
return (
<>
<View style={styles.root}>
<View style={[styles.videoContainer]}>
<Text>My Video</Text>
<RTCView streamURL={localStream.toURL()} style={styles.localVideo} />
<View style={{position: 'absolute', top: 20, right: 5}}>
<IconButton
style={styles.controlIcon}
icon={ isCameraOn ? 'camera' : 'camera-off' }
color='#777'
size={25}
onPress={onToggleCamera} />
<IconButton
style={styles.controlIcon}
icon={isMute ? 'microphone-off' : 'microphone'}
color='#777'
size={25}
onPress={onToggleAudio} />
<IconButton
style={styles.controlIcon}
icon='camera-party-mode'
color='#777'
size={25}
onPress={onSwitchCamera} />
<IconButton
style={styles.controlIcon}
icon='emoticon'
color='#777'
size={25}
onPress={onAction} />
<IconButton
style={styles.controlIcon}
icon='hand'
color='#777'
size={25}
onPress={onRaiseHand} />
</View>
</View>
<View style={[styles.videoContainer]}>
<Text>{(peer ?? {}).displayName ?? 'Friends Video'}</Text>
<RTCView
streamURL={remoteStream.toURL()}
style={styles.remoteVideo}
/>
</View>
</View>
</>
);
}
const styles = StyleSheet.create({
root: {
backgroundColor: '#fff',
flex: 1,
paddingHorizontal: 20,
},
videoContainer: {
flex: 1,
overflow: 'hidden',
borderRadius: 6,
marginVertical: 10,
},
localVideo: {
backgroundColor: '#f2f2f2',
flex: 1,
alignItems: 'flex-end',
},
remoteVideo: {
backgroundColor: '#f2f2f2',
flex: 1,
},
controlIcon: {
backgroundColor: '#d0d0d0',
marginHorizontal: 10,
marginTop: 10,
}
});