chatty / client /src /hooks /usePeer.jsx
arabdullah's picture
@ARAbdullaSL
a0fda44 verified
import { useState } from "react";
import { useRef } from "react";
import { useEffect } from "react";
import useSocket from "./useSocket";
import Peer from "simple-peer";
import useSendMessage from "./useSendMessage";
import { useDispatch, useSelector } from "react-redux";
import { modalActions } from "../store/modalSlice";
import useCounter from "./useCounter";
const usePeer = ({ mediaOptions, callDetail }) => {
const userMediaRef = useRef();
const partnerMediaRef = useRef();
// Get id of chat room both user belongs to
const currentChatRoomId = useSelector(
(state) => state.chatReducer.currentChatRoom._id
);
const [userStream, setUserStream] = useState();
// Call status to show calling, ringing, ongoing
const [callStatus, setCallStatus] = useState("calling");
// Call acceptance state
const [callAccepted, setCallAccepted] = useState();
// Duration counter for call
const {
formattedTime: duration,
startCounter,
stopCounter,
} = useCounter({ showCentiseconds: false });
// Get socket instances
const { socketEmit, socketListen, socket, userId } = useSocket();
// Send call details to database
const { sendMessage } = useSendMessage();
const dispatch = useDispatch();
// Get user media and attach to ref
useEffect(() => {
if (userMediaRef.current) {
navigator.mediaDevices.getUserMedia(mediaOptions).then((stream) => {
setUserStream(stream);
userMediaRef.current.srcObject = stream;
});
}
}, []);
// If user is the one initiating call
useEffect(() => {
if (callDetail.caller && userStream) {
const peer = new Peer({
initiator: true,
trickle: false,
stream: userStream,
});
peer.on("signal", (signalData) => {
socketEmit(
"user:callRequest",
{
signalData,
callType: mediaOptions.video ? "video" : "voice",
chatRoomId: currentChatRoomId,
userId,
},
(callAcknowledged) => {
// Caller acknowledges call request
setCallStatus(callAcknowledged ? "ringing" : "calling");
// While call receiver hasn't picked call
setTimeout(() => {
if (!callAccepted) {
dispatch(modalActions.closeModal());
denyCall("Missed");
}
}, 60000);
}
);
});
socketListen("user:callAccepted", ({ signalData }) => {
peer.signal(signalData);
setCallAccepted(true);
// Start duration
startCounter();
});
peer.on("stream", (stream) => {
partnerMediaRef.current.srcObject = stream;
});
peer.on("close", () => {
socket.off("user:callAccepted");
dispatch(modalActions.closeModal());
userStream.getTracks().forEach(function (track) {
track.stop();
});
});
socketListen("user:endCall", () => {
peer.destroy();
});
}
}, [userStream]);
// If user is the one receiving call
useEffect(() => {
if (callAccepted && userStream && !callDetail.caller) {
const peer = new Peer({
initiator: false,
trickle: false,
stream: userStream,
});
peer.on("signal", (signalData) => {
socketEmit("user:callAccepted", {
signalData,
chatRoomId: callDetail.chatRoomId,
});
// Start duration
startCounter();
});
peer.signal(callDetail.callerSignal);
peer.on("stream", (stream) => {
partnerMediaRef.current.srcObject = stream;
});
peer.on("close", () => {
dispatch(modalActions.closeModal());
userStream.getTracks().forEach(function (track) {
track.stop();
});
});
}
}, [callAccepted, userStream]);
// If call is denied by any user
useEffect(() => {
socketListen("user:callDenied", () => {
// If user is the caller, show reason for disconnection
if (callDetail.caller) {
setCallStatus("Call denied");
setTimeout(() => {
dispatch(modalActions.closeModal());
}, 1000);
} else {
dispatch(modalActions.closeModal());
}
userStream.getTracks().forEach(function (track) {
track.stop();
});
});
return () => {
socket.off("user:callDenied");
};
}, [userStream]);
// Accept call
const acceptCall = () => {
setCallAccepted(true);
};
// Deny call
const denyCall = (reason) => {
// Emit call denied to caller
socketEmit("user:callDenied", {
chatRoomId: callDetail.caller ? currentChatRoomId : callDetail.chatRoomId,
});
sendMessage({
callType: mediaOptions.video ? "video" : "voice",
callRejectReason: reason,
sender: callDetail.caller ? userId : callDetail.callerId,
chatRoomId: callDetail.caller ? currentChatRoomId : callDetail.chatRoomId,
});
// End duration
stopCounter();
};
// End call
const endCall = () => {
socketEmit("user:endCall", {
duration,
chatRoomId: callDetail.caller ? currentChatRoomId : callDetail.chatRoomId,
});
sendMessage({
callType: mediaOptions.video ? "video" : "voice",
callDuration: duration,
sender: callDetail.caller ? userId : callDetail.callerId,
chatRoomId: callDetail.caller ? currentChatRoomId : callDetail.chatRoomId,
});
// End duration
stopCounter();
};
return {
userStream,
userMediaRef,
partnerMediaRef,
callStatus,
acceptCall,
callAccepted,
endCall,
denyCall,
duration,
};
};
export default usePeer;