/* eslint-disable @typescript-eslint/ban-ts-comment */
import { MatrixClient, MatrixCall, CallEvent } from 'matrix-js-sdk';
import { CallErrorCode, CallState } from 'matrix-js-sdk/lib/webrtc/call';
import ringTone from '../../../assets/audio/ringtone.mp3';
const ringingTone = new Audio(ringTone); // Updated URL for a reliable ringing tone
// Timer logic to track call duration
let callTimer: NodeJS.Timeout;
const startCallTimer = (setCallTime: (arg: string | number) => void) => {
setCallTime(0); // Reset the call time
callTimer = setInterval(() => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-expect-error
setCallTime((prevTime) => prevTime + 1); // Increment the time every second
}, 1000);
};
const stopCallTimer = () => {
clearInterval(callTimer); // Stop the timer
};
// Function to handle the audio call
const handleOutgoingAudioCall = (
client: MatrixClient | null,
roomId: string,
setActiveCall: (arg: MatrixCall | null) => void,
setIsCalling: (arg: boolean) => void,
setIsCallConnected: (arg: boolean) => void,
setCallTime: (arg: string | number) => void
) => {
try {
if (!client || !roomId) {
console.error('Matrix client or room ID is missing.');
return null;
}
// Create the call
const call = client.createCall(roomId);
if (call) {
// Initiate the voice call
call.placeVoiceCall();
ringingTone.loop = true;
ringingTone.play();
setIsCalling(true); // Set calling state to true
console.log('Audio call started in room:', roomId);
// Handle call hangup
call.on(CallEvent.Hangup, () => {
setActiveCall(null);
setIsCalling(false);
ringingTone.pause();
ringingTone.currentTime = 0;
setIsCallConnected(false); // Reset call connection state
stopCallTimer(); // Stop the call timer
console.log('Call ended, ringing tone stopped.');
});
// Handle call errors
call.on(CallEvent.Error, (error) => {
console.error('Call error:', error);
ringingTone.pause();
// Optional: handle error state or notify user
});
// Handle call state changes
call.on(CallEvent.State, (state) => {
console.log('Call state changed:', state);
switch (state) {
case CallState.Connected:
ringingTone.pause();
ringingTone.currentTime = 0;
setIsCallConnected(true); // Call is connected
startCallTimer(setCallTime); // Start the call timer
console.log('Call connected, ringing tone stopped.');
break;
case CallState.Ringing:
ringingTone.loop = true;
ringingTone.play();
console.log('Call is ringing.');
break;
case CallState.Ended:
ringingTone.pause();
ringingTone.currentTime = 0;
setActiveCall(null); // Clear the call state
setIsCalling(false);
setIsCallConnected(false);
stopCallTimer(); // Stop the call timer
console.log('Call ended.');
break;
default:
console.log('Unhandled call state:', state);
}
});
// Return the created call object
return call;
} else {
console.error('Failed to create the call.');
return null;
}
} catch (error) {
console.error('Error starting the audio call:', error);
return null;
}
};
const handleIncomingAudioCall = (
call: MatrixCall | null,
setIncomingCall: (arg: MatrixCall | null) => void,
setCallConnected: (arg: boolean) => void
) => {
console.log('Incoming call detected:', call);
setIncomingCall(call);
// Play the ringtone (optional)
ringingTone.loop = true;
ringingTone.play();
// Listen for call state changes
call?.on(CallEvent.State, (state) => {
console.log('Call state changed:', state);
switch (state) {
case CallState.Connected:
ringingTone.pause();
setCallConnected(true);
console.log('Incoming call connected.');
break;
case CallState.Ended:
ringingTone.pause();
ringingTone.currentTime = 0;
setIncomingCall(null); // Reset the call state to remove the modal
setCallConnected(false);
console.log('Incoming call ended.');
break;
case CallState.Ringing:
console.log('Incoming call ringing.');
break;
default:
console.log('Unhandled call state:', state);
}
});
// Listen for the hangup event (if necessary)
call?.on(CallEvent.Hangup, () => {
ringingTone.pause();
setCallConnected(false);
console.log('Call hangup event detected');
setIncomingCall(null); // Reset the call state
});
};
const handleAcceptCall = (incomingCall: MatrixCall | null) => {
if (incomingCall) {
ringingTone.pause();
incomingCall.answer(); // Accept the incoming call
console.log('Call answered.');
}
};
const handleDeclineCall = (
incomingCall: MatrixCall | null,
setIncomingCall: (arg: MatrixCall | null) => void
) => {
if (incomingCall) {
ringingTone.pause();
incomingCall.hangup(CallErrorCode.UserHangup, false); // Provide the reason and suppressEvent
setIncomingCall(null);
console.log('Call declined.');
}
};
const handleEndCall = (
call: MatrixCall | null,
setActiveCall: (arg: MatrixCall | null) => void,
setIsCalling: (arg: boolean) => void,
setIncomingCall: (arg: MatrixCall | null) => void,
setCallConnected: (arg: boolean) => void
) => {
setActiveCall(null);
setIsCalling(false);
// Provide a reason for the hangup, e.g., 'user_hangup'
// Set suppressEvent to false to notify the server
ringingTone.pause();
call?.hangup(CallErrorCode.UserHangup, false);
setIncomingCall(null);
setCallConnected(false);
console.log('Call has been ended.');
};
const handleMuteToggle = (isMuted: boolean, setIsMuted: (arg: boolean) => void) => {
// Implement mute/unmute functionality
setIsMuted(!isMuted);
};
export {
handleOutgoingAudioCall,
handleEndCall,
handleMuteToggle,
handleIncomingAudioCall,
handleAcceptCall,
handleDeclineCall
};
This is my code I want to implement audio and video calls in react but somehow its not working both person cannot able to listen each other and caller is not able to identify whether the reciever has picked up call or not its in ringing mode always.