simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2022 Savoir-faire Linux Inc. |
| 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU Affero General Public License as |
| 6 | * published by the Free Software Foundation; either version 3 of the |
| 7 | * License, or (at your option) any later version. |
| 8 | * |
| 9 | * This program is distributed in the hope that it will be useful, |
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | * GNU Affero General Public License for more details. |
| 13 | * |
| 14 | * You should have received a copy of the GNU Affero General Public |
| 15 | * License along with this program. If not, see |
| 16 | * <https://www.gnu.org/licenses/>. |
| 17 | */ |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 18 | import { ConversationInfos, WebSocketMessageTable, WebSocketMessageType } from 'jami-web-common'; |
simon | 5c67796 | 2022-12-02 16:51:54 -0500 | [diff] [blame] | 19 | import { useCallback, useContext, useEffect, useMemo, useState } from 'react'; |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 20 | import { useNavigate } from 'react-router-dom'; |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 21 | |
idillon | 07d31cc | 2022-12-06 22:40:14 -0500 | [diff] [blame] | 22 | import { ConversationMember } from '../models/conversation-member'; |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 23 | import { useConversationInfosQuery, useMembersQuery } from '../services/conversationQueries'; |
MichelleSS | 5516420 | 2022-11-25 18:36:14 -0500 | [diff] [blame] | 24 | import { callTimeoutMs } from '../utils/constants'; |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 25 | import { AsyncSetState, SetState } from '../utils/utils'; |
idillon | cf42c65 | 2023-01-31 18:56:17 -0500 | [diff] [blame] | 26 | import { useWebRtcManager } from '../webrtc/WebRtcManager'; |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 27 | import { AlertSnackbarContext } from './AlertSnackbarProvider'; |
idillon | cf42c65 | 2023-01-31 18:56:17 -0500 | [diff] [blame] | 28 | import { useAuthContext } from './AuthProvider'; |
idillon | 27dab02 | 2023-02-02 17:55:47 -0500 | [diff] [blame] | 29 | import { useUserMediaContext } from './UserMediaProvider'; |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 30 | import { useWebSocketContext } from './WebSocketProvider'; |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 31 | |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 32 | export type CallRole = 'caller' | 'receiver' | undefined; |
| 33 | |
| 34 | export type CallData = { |
| 35 | conversationId: string; |
| 36 | role: CallRole; |
| 37 | withVideoOn?: boolean; |
| 38 | }; |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 39 | |
| 40 | export enum CallStatus { |
simon | ff1cb35 | 2022-11-24 15:15:26 -0500 | [diff] [blame] | 41 | Default, |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 42 | Loading, |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 43 | Ringing, |
| 44 | Connecting, |
| 45 | InCall, |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 46 | PermissionsDenied, |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 47 | } |
| 48 | |
simon | 1e2bf34 | 2022-12-02 12:19:40 -0500 | [diff] [blame] | 49 | export enum VideoStatus { |
| 50 | Off, |
| 51 | Camera, |
| 52 | ScreenShare, |
| 53 | } |
| 54 | |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 55 | export interface ICallManager { |
| 56 | callData: CallData | undefined; |
| 57 | callConversationInfos: ConversationInfos | undefined; |
| 58 | callMembers: ConversationMember[] | undefined; |
| 59 | |
idillon | cf42c65 | 2023-01-31 18:56:17 -0500 | [diff] [blame] | 60 | remoteStreams: readonly MediaStream[]; |
| 61 | |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 62 | isAudioOn: boolean; |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 63 | setIsAudioOn: SetState<boolean>; |
simon | 1e2bf34 | 2022-12-02 12:19:40 -0500 | [diff] [blame] | 64 | videoStatus: VideoStatus; |
| 65 | updateVideoStatus: AsyncSetState<VideoStatus>; |
simon | f9d78f2 | 2022-11-25 15:47:15 -0500 | [diff] [blame] | 66 | isChatShown: boolean; |
| 67 | setIsChatShown: SetState<boolean>; |
simon | 2a5cf14 | 2022-11-25 15:47:35 -0500 | [diff] [blame] | 68 | isFullscreen: boolean; |
| 69 | setIsFullscreen: SetState<boolean>; |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 70 | callStatus: CallStatus; |
Misha Krieger-Raynauld | d0cc3e3 | 2022-11-29 19:59:31 -0500 | [diff] [blame] | 71 | callStartTime: number | undefined; |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 72 | |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 73 | startCall: (conversationId: string, withVideoOn?: boolean) => void; |
MichelleSS | 5516420 | 2022-11-25 18:36:14 -0500 | [diff] [blame] | 74 | acceptCall: (withVideoOn: boolean) => void; |
simon | accd802 | 2022-11-24 15:04:53 -0500 | [diff] [blame] | 75 | endCall: () => void; |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 76 | } |
| 77 | |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 78 | export const useCallManager = () => { |
| 79 | const { setAlertContent } = useContext(AlertSnackbarContext); |
| 80 | const [callData, setCallData] = useState<CallData>(); |
idillon | a4b96ab | 2023-02-01 15:30:12 -0500 | [diff] [blame] | 81 | const webSocket = useWebSocketContext(); |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 82 | const navigate = useNavigate(); |
| 83 | const { data: callConversationInfos } = useConversationInfosQuery(callData?.conversationId); |
| 84 | const { data: callMembers } = useMembersQuery(callData?.conversationId); |
simon | f353ef4 | 2022-11-28 23:14:53 -0500 | [diff] [blame] | 85 | |
idillon | 27dab02 | 2023-02-02 17:55:47 -0500 | [diff] [blame] | 86 | const { |
| 87 | localStream, |
| 88 | updateLocalStream, |
| 89 | screenShareLocalStream, |
| 90 | updateScreenShare, |
| 91 | setAudioInputDeviceId, |
| 92 | setVideoDeviceId, |
| 93 | stopMedias, |
| 94 | } = useUserMediaContext(); |
idillon | cf42c65 | 2023-01-31 18:56:17 -0500 | [diff] [blame] | 95 | const { account } = useAuthContext(); |
| 96 | const webRtcManager = useWebRtcManager(); |
| 97 | |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 98 | const [isAudioOn, setIsAudioOn] = useState(false); |
simon | 1e2bf34 | 2022-12-02 12:19:40 -0500 | [diff] [blame] | 99 | const [videoStatus, setVideoStatus] = useState(VideoStatus.Off); |
simon | f9d78f2 | 2022-11-25 15:47:15 -0500 | [diff] [blame] | 100 | const [isChatShown, setIsChatShown] = useState(false); |
simon | 2a5cf14 | 2022-11-25 15:47:35 -0500 | [diff] [blame] | 101 | const [isFullscreen, setIsFullscreen] = useState(false); |
simon | e35acc2 | 2022-12-02 16:51:12 -0500 | [diff] [blame] | 102 | const [callStatus, setCallStatus] = useState(CallStatus.Default); |
Misha Krieger-Raynauld | d0cc3e3 | 2022-11-29 19:59:31 -0500 | [diff] [blame] | 103 | const [callStartTime, setCallStartTime] = useState<number | undefined>(undefined); |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 104 | |
idillon | cf42c65 | 2023-01-31 18:56:17 -0500 | [diff] [blame] | 105 | useEffect(() => { |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 106 | const callInviteListener = ({ conversationId, withVideoOn }: WebSocketMessageTable['onCallInvite']) => { |
| 107 | if (callData) { |
| 108 | // TODO: Currently, we display a notification if already in a call. |
| 109 | // In the future, we should handle receiving a call while already in another. |
| 110 | setAlertContent({ |
| 111 | messageI18nKey: 'missed_incoming_call', |
| 112 | messageI18nContext: { conversationId }, |
| 113 | severity: 'info', |
| 114 | alertOpen: true, |
| 115 | }); |
| 116 | return; |
| 117 | } |
| 118 | |
| 119 | setCallData({ conversationId: conversationId, role: 'receiver', withVideoOn }); |
| 120 | navigate(`/conversation/${conversationId}`); |
| 121 | }; |
| 122 | |
| 123 | webSocket.bind(WebSocketMessageType.onCallInvite, callInviteListener); |
| 124 | |
| 125 | return () => { |
| 126 | webSocket.unbind(WebSocketMessageType.onCallInvite, callInviteListener); |
| 127 | }; |
| 128 | }, [webSocket, navigate, callData, setAlertContent]); |
| 129 | |
| 130 | const conversationId = callData?.conversationId; |
| 131 | const contactUri = callMembers?.[0]?.contact.uri; |
| 132 | const connectionInfos = contactUri ? webRtcManager.connectionsInfos[contactUri] : undefined; |
| 133 | const remoteStreams = useMemo(() => connectionInfos?.remoteStreams || [], [connectionInfos]); |
| 134 | const iceConnectionState = connectionInfos?.iceConnectionState; |
idillon | cf42c65 | 2023-01-31 18:56:17 -0500 | [diff] [blame] | 135 | |
idillon | cf42c65 | 2023-01-31 18:56:17 -0500 | [diff] [blame] | 136 | // TODO: Transform the effect into a callback |
| 137 | const updateLocalStreams = webRtcManager.updateLocalStreams; |
| 138 | useEffect(() => { |
| 139 | if ((!localStream && !screenShareLocalStream) || !updateLocalStreams) { |
| 140 | return; |
| 141 | } |
| 142 | |
| 143 | updateLocalStreams(localStream, screenShareLocalStream); |
| 144 | }, [localStream, screenShareLocalStream, updateLocalStreams]); |
| 145 | |
idillon | cf42c65 | 2023-01-31 18:56:17 -0500 | [diff] [blame] | 146 | const closeConnection = useCallback(() => { |
idillon | 27dab02 | 2023-02-02 17:55:47 -0500 | [diff] [blame] | 147 | stopMedias(); |
idillon | cf42c65 | 2023-01-31 18:56:17 -0500 | [diff] [blame] | 148 | webRtcManager.clean(); |
idillon | 27dab02 | 2023-02-02 17:55:47 -0500 | [diff] [blame] | 149 | }, [stopMedias, webRtcManager]); |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 150 | |
idillon | 27dab02 | 2023-02-02 17:55:47 -0500 | [diff] [blame] | 151 | // Tracks logic should be moved into UserMediaProvider |
simon | 492e840 | 2022-11-29 16:48:37 -0500 | [diff] [blame] | 152 | useEffect(() => { |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 153 | if (localStream) { |
| 154 | for (const track of localStream.getAudioTracks()) { |
| 155 | track.enabled = isAudioOn; |
simon | 492e840 | 2022-11-29 16:48:37 -0500 | [diff] [blame] | 156 | const deviceId = track.getSettings().deviceId; |
| 157 | if (deviceId) { |
| 158 | setAudioInputDeviceId(deviceId); |
| 159 | } |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 160 | } |
simon | feaa1db | 2022-11-26 20:13:18 -0500 | [diff] [blame] | 161 | } |
idillon | 27dab02 | 2023-02-02 17:55:47 -0500 | [diff] [blame] | 162 | }, [isAudioOn, localStream, setAudioInputDeviceId]); |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 163 | |
idillon | 27dab02 | 2023-02-02 17:55:47 -0500 | [diff] [blame] | 164 | // Tracks logic should be moved into UserMediaProvider |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 165 | useEffect(() => { |
simon | f353ef4 | 2022-11-28 23:14:53 -0500 | [diff] [blame] | 166 | if (localStream) { |
MichelleSS | 5516420 | 2022-11-25 18:36:14 -0500 | [diff] [blame] | 167 | for (const track of localStream.getVideoTracks()) { |
simon | 1e2bf34 | 2022-12-02 12:19:40 -0500 | [diff] [blame] | 168 | track.enabled = videoStatus === VideoStatus.Camera; |
simon | 492e840 | 2022-11-29 16:48:37 -0500 | [diff] [blame] | 169 | const deviceId = track.getSettings().deviceId; |
| 170 | if (deviceId) { |
| 171 | setVideoDeviceId(deviceId); |
| 172 | } |
MichelleSS | 5516420 | 2022-11-25 18:36:14 -0500 | [diff] [blame] | 173 | } |
simon | ff1cb35 | 2022-11-24 15:15:26 -0500 | [diff] [blame] | 174 | } |
idillon | 27dab02 | 2023-02-02 17:55:47 -0500 | [diff] [blame] | 175 | }, [videoStatus, localStream, setVideoDeviceId]); |
simon | 1e2bf34 | 2022-12-02 12:19:40 -0500 | [diff] [blame] | 176 | |
idillon | 27dab02 | 2023-02-02 17:55:47 -0500 | [diff] [blame] | 177 | // Track logic should be moved into UserMediaProvider |
simon | 1e2bf34 | 2022-12-02 12:19:40 -0500 | [diff] [blame] | 178 | const updateVideoStatus = useCallback( |
| 179 | async (newStatus: ((prevState: VideoStatus) => VideoStatus) | VideoStatus) => { |
| 180 | if (typeof newStatus === 'function') { |
| 181 | newStatus = newStatus(videoStatus); |
| 182 | } |
| 183 | |
| 184 | const stream = await updateScreenShare(newStatus === VideoStatus.ScreenShare); |
| 185 | if (stream) { |
| 186 | for (const track of stream.getTracks()) { |
| 187 | track.addEventListener('ended', () => { |
| 188 | console.warn('Browser ended screen sharing'); |
| 189 | updateVideoStatus(VideoStatus.Off); |
| 190 | }); |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | setVideoStatus(newStatus); |
| 195 | }, |
| 196 | [videoStatus, updateScreenShare] |
| 197 | ); |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 198 | |
| 199 | useEffect(() => { |
simon | 2a5cf14 | 2022-11-25 15:47:35 -0500 | [diff] [blame] | 200 | const onFullscreenChange = () => { |
| 201 | setIsFullscreen(document.fullscreenElement !== null); |
| 202 | }; |
| 203 | |
| 204 | document.addEventListener('fullscreenchange', onFullscreenChange); |
| 205 | return () => { |
| 206 | document.removeEventListener('fullscreenchange', onFullscreenChange); |
| 207 | }; |
| 208 | }, []); |
| 209 | |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 210 | const startCall = useCallback( |
| 211 | (conversationId: string, withVideoOn = false) => { |
| 212 | setCallData({ conversationId, withVideoOn, role: 'caller' }); |
| 213 | if (callStatus === CallStatus.Default) { |
| 214 | setCallStatus(CallStatus.Loading); |
| 215 | updateLocalStream() |
| 216 | .then(() => { |
| 217 | const callInvite: WebSocketMessageTable['sendCallInvite'] = { |
| 218 | conversationId: conversationId, |
| 219 | withVideoOn, |
| 220 | }; |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 221 | |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 222 | setCallStatus(CallStatus.Ringing); |
| 223 | setVideoStatus(withVideoOn ? VideoStatus.Camera : VideoStatus.Off); |
| 224 | webSocket.send(WebSocketMessageType.sendCallInvite, callInvite); |
| 225 | }) |
| 226 | .catch((e) => { |
| 227 | console.error(e); |
| 228 | setCallStatus(CallStatus.PermissionsDenied); |
| 229 | }); |
| 230 | } |
| 231 | }, |
| 232 | [webSocket, updateLocalStream, callStatus] |
| 233 | ); |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 234 | |
| 235 | const acceptCall = useCallback( |
| 236 | (withVideoOn: boolean) => { |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 237 | if (!callMembers || !conversationId) { |
| 238 | console.warn('acceptCall without callMembers or conversationId'); |
| 239 | return; |
| 240 | } |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 241 | setCallStatus(CallStatus.Loading); |
simon | 492e840 | 2022-11-29 16:48:37 -0500 | [diff] [blame] | 242 | updateLocalStream() |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 243 | .then(() => { |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 244 | const callAccept: WebSocketMessageTable['sendCallJoin'] = { |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 245 | conversationId, |
| 246 | }; |
| 247 | |
simon | 1e2bf34 | 2022-12-02 12:19:40 -0500 | [diff] [blame] | 248 | setVideoStatus(withVideoOn ? VideoStatus.Camera : VideoStatus.Off); |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 249 | setCallStatus(CallStatus.Connecting); |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 250 | console.info('Sending CallJoin', callAccept); |
| 251 | webSocket.send(WebSocketMessageType.sendCallJoin, callAccept); |
| 252 | // TODO: move this to "onWebRtcOffer" listener so we don't add connections for non-connected members |
| 253 | callMembers.forEach((member) => |
| 254 | webRtcManager.addConnection( |
| 255 | webSocket, |
| 256 | account, |
| 257 | member.contact.uri, |
| 258 | callData, |
| 259 | localStream, |
| 260 | screenShareLocalStream |
| 261 | ) |
| 262 | ); |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 263 | }) |
| 264 | .catch((e) => { |
| 265 | console.error(e); |
| 266 | setCallStatus(CallStatus.PermissionsDenied); |
| 267 | }); |
| 268 | }, |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 269 | [ |
| 270 | account, |
| 271 | callData, |
| 272 | conversationId, |
| 273 | localStream, |
| 274 | callMembers, |
| 275 | screenShareLocalStream, |
| 276 | updateLocalStream, |
| 277 | webRtcManager, |
| 278 | webSocket, |
| 279 | ] |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 280 | ); |
| 281 | |
| 282 | useEffect(() => { |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 283 | if (callData?.role === 'caller' && callStatus === CallStatus.Ringing) { |
| 284 | const callJoinListener = (data: WebSocketMessageTable['onCallJoin']) => { |
| 285 | console.info('Received event on CallJoin', data, callData); |
Charlie | c18d640 | 2022-11-27 13:01:04 -0500 | [diff] [blame] | 286 | if (data.conversationId !== conversationId) { |
| 287 | console.warn('Wrong incoming conversationId, ignoring action'); |
| 288 | return; |
| 289 | } |
| 290 | |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 291 | setCallStatus(CallStatus.Connecting); |
| 292 | |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 293 | webRtcManager.addConnection(webSocket, account, data.senderId, callData, localStream, screenShareLocalStream); |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 294 | }; |
| 295 | |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 296 | webSocket.bind(WebSocketMessageType.onCallJoin, callJoinListener); |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 297 | |
| 298 | return () => { |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 299 | webSocket.unbind(WebSocketMessageType.onCallJoin, callJoinListener); |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 300 | }; |
| 301 | } |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 302 | }, [account, callData, callStatus, conversationId, localStream, screenShareLocalStream, webRtcManager, webSocket]); |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 303 | |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 304 | const endCall = useCallback(() => { |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 305 | if (!conversationId) { |
| 306 | return; |
| 307 | } |
| 308 | |
| 309 | const callExit: WebSocketMessageTable['sendCallExit'] = { |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 310 | conversationId, |
| 311 | }; |
MichelleSS | 5516420 | 2022-11-25 18:36:14 -0500 | [diff] [blame] | 312 | |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 313 | console.info('Sending CallExit', callExit); |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 314 | closeConnection(); |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 315 | webSocket.send(WebSocketMessageType.sendCallExit, callExit); |
| 316 | setCallData(undefined); |
| 317 | setCallStatus(CallStatus.Default); |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 318 | // TODO: write in chat that the call ended |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 319 | }, [webSocket, conversationId, closeConnection]); |
simon | accd802 | 2022-11-24 15:04:53 -0500 | [diff] [blame] | 320 | |
| 321 | useEffect(() => { |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 322 | const callExitListener = (data: WebSocketMessageTable['onCallExit']) => { |
| 323 | console.info('Received event on CallExit', data); |
Charlie | c18d640 | 2022-11-27 13:01:04 -0500 | [diff] [blame] | 324 | if (data.conversationId !== conversationId) { |
| 325 | console.warn('Wrong incoming conversationId, ignoring action'); |
| 326 | return; |
| 327 | } |
| 328 | |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 329 | endCall(); |
simon | accd802 | 2022-11-24 15:04:53 -0500 | [diff] [blame] | 330 | // TODO: write in chat that the call ended |
| 331 | }; |
| 332 | |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 333 | webSocket.bind(WebSocketMessageType.onCallExit, callExitListener); |
simon | accd802 | 2022-11-24 15:04:53 -0500 | [diff] [blame] | 334 | return () => { |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 335 | webSocket.unbind(WebSocketMessageType.onCallExit, callExitListener); |
simon | accd802 | 2022-11-24 15:04:53 -0500 | [diff] [blame] | 336 | }; |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 337 | }, [webSocket, endCall, conversationId]); |
simon | accd802 | 2022-11-24 15:04:53 -0500 | [diff] [blame] | 338 | |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 339 | useEffect(() => { |
Charlie | b837e8f | 2022-11-28 19:18:46 -0500 | [diff] [blame] | 340 | if ( |
| 341 | callStatus === CallStatus.Connecting && |
| 342 | (iceConnectionState === 'connected' || iceConnectionState === 'completed') |
| 343 | ) { |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 344 | console.info('Changing call status to InCall'); |
| 345 | setCallStatus(CallStatus.InCall); |
Misha Krieger-Raynauld | d0cc3e3 | 2022-11-29 19:59:31 -0500 | [diff] [blame] | 346 | setCallStartTime(Date.now()); |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 347 | } |
simon | 9076a9a | 2022-11-29 17:13:01 -0500 | [diff] [blame] | 348 | }, [iceConnectionState, callStatus]); |
simon | accd802 | 2022-11-24 15:04:53 -0500 | [diff] [blame] | 349 | |
MichelleSS | 5516420 | 2022-11-25 18:36:14 -0500 | [diff] [blame] | 350 | useEffect(() => { |
Charlie | 380dc5e | 2022-11-29 16:51:42 -0500 | [diff] [blame] | 351 | if (iceConnectionState === 'disconnected' || iceConnectionState === 'failed') { |
| 352 | console.info('ICE connection disconnected or failed, ending call'); |
Charlie | b837e8f | 2022-11-28 19:18:46 -0500 | [diff] [blame] | 353 | endCall(); |
| 354 | } |
simon | 1e2bf34 | 2022-12-02 12:19:40 -0500 | [diff] [blame] | 355 | }, [iceConnectionState, callStatus, videoStatus, endCall]); |
Charlie | b837e8f | 2022-11-28 19:18:46 -0500 | [diff] [blame] | 356 | |
| 357 | useEffect(() => { |
MichelleSS | 5516420 | 2022-11-25 18:36:14 -0500 | [diff] [blame] | 358 | const checkStatusTimeout = () => { |
| 359 | if (callStatus !== CallStatus.InCall) { |
| 360 | endCall(); |
simon | ff1cb35 | 2022-11-24 15:15:26 -0500 | [diff] [blame] | 361 | } |
MichelleSS | 5516420 | 2022-11-25 18:36:14 -0500 | [diff] [blame] | 362 | }; |
| 363 | const timeoutId = setTimeout(checkStatusTimeout, callTimeoutMs); |
simon | ff1cb35 | 2022-11-24 15:15:26 -0500 | [diff] [blame] | 364 | |
MichelleSS | 5516420 | 2022-11-25 18:36:14 -0500 | [diff] [blame] | 365 | return () => { |
| 366 | clearTimeout(timeoutId); |
| 367 | }; |
| 368 | }, [callStatus, endCall]); |
simon | ff1cb35 | 2022-11-24 15:15:26 -0500 | [diff] [blame] | 369 | |
simon | 5c67796 | 2022-12-02 16:51:54 -0500 | [diff] [blame] | 370 | return useMemo( |
| 371 | () => ({ |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 372 | callData, |
| 373 | callConversationInfos, |
| 374 | callMembers, |
idillon | cf42c65 | 2023-01-31 18:56:17 -0500 | [diff] [blame] | 375 | remoteStreams, |
simon | 5c67796 | 2022-12-02 16:51:54 -0500 | [diff] [blame] | 376 | isAudioOn, |
| 377 | setIsAudioOn, |
| 378 | videoStatus, |
| 379 | updateVideoStatus, |
| 380 | isChatShown, |
| 381 | setIsChatShown, |
| 382 | isFullscreen, |
| 383 | setIsFullscreen, |
simon | 5c67796 | 2022-12-02 16:51:54 -0500 | [diff] [blame] | 384 | callStatus, |
| 385 | callStartTime, |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 386 | startCall, |
simon | 5c67796 | 2022-12-02 16:51:54 -0500 | [diff] [blame] | 387 | acceptCall, |
| 388 | endCall, |
| 389 | }), |
| 390 | [ |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 391 | callData, |
| 392 | callConversationInfos, |
| 393 | callMembers, |
idillon | cf42c65 | 2023-01-31 18:56:17 -0500 | [diff] [blame] | 394 | remoteStreams, |
simon | 5c67796 | 2022-12-02 16:51:54 -0500 | [diff] [blame] | 395 | isAudioOn, |
simon | 5c67796 | 2022-12-02 16:51:54 -0500 | [diff] [blame] | 396 | videoStatus, |
idillon | 27dab02 | 2023-02-02 17:55:47 -0500 | [diff] [blame] | 397 | setIsAudioOn, |
simon | 5c67796 | 2022-12-02 16:51:54 -0500 | [diff] [blame] | 398 | updateVideoStatus, |
| 399 | isChatShown, |
idillon | 27dab02 | 2023-02-02 17:55:47 -0500 | [diff] [blame] | 400 | setIsChatShown, |
simon | 5c67796 | 2022-12-02 16:51:54 -0500 | [diff] [blame] | 401 | isFullscreen, |
idillon | 27dab02 | 2023-02-02 17:55:47 -0500 | [diff] [blame] | 402 | setIsFullscreen, |
simon | 5c67796 | 2022-12-02 16:51:54 -0500 | [diff] [blame] | 403 | callStatus, |
| 404 | callStartTime, |
idillon | 255682e | 2023-02-06 13:25:26 -0500 | [diff] [blame^] | 405 | startCall, |
simon | 5c67796 | 2022-12-02 16:51:54 -0500 | [diff] [blame] | 406 | acceptCall, |
| 407 | endCall, |
| 408 | ] |
simon | f929a36 | 2022-11-18 16:53:45 -0500 | [diff] [blame] | 409 | ); |
| 410 | }; |