Implement audio calls

This commit is contained in:
2025-09-21 19:09:39 +03:00
Unverified
parent 27902cf092
commit a853164b50
20 changed files with 1265 additions and 12 deletions
+115
View File
@@ -0,0 +1,115 @@
import type { WebSocketMessage, CallSignalingData, CallInvite } from "@/core/types";
import * as WebRTC from "./webrtc";
export interface CallState {
receiveCall: (userId: number, username: string) => void;
endCall: () => void;
}
export class CallSignalingHandler {
private getState: () => CallState;
constructor(getState: () => CallState) {
this.getState = getState;
}
handleWebSocketMessage(message: WebSocketMessage<CallSignalingData>) {
if (message.type !== "call_signaling") {
return;
}
const { data } = message;
if (!data) {
console.warn("Received call_signaling message with no data:", message);
return;
}
console.log("Received signaling message:", data.type, "from user", data.fromUserId, "full data:", data);
switch (data.type) {
case "call_invite":
this.handleCallInvite(data as CallInvite);
break;
case "call_accept":
this.handleCallAccept(data);
break;
case "call_reject":
this.handleCallReject(data);
break;
case "call_offer":
this.handleCallOffer(data);
break;
case "call_answer":
this.handleCallAnswer(data);
break;
case "call_ice_candidate":
this.handleIceCandidate(data);
break;
case "call_end":
this.handleCallEnd(data);
break;
}
}
private async handleCallInvite(data: CallInvite) {
const { fromUserId, fromUsername } = data;
const state = this.getState();
// Show incoming call UI
state.receiveCall(fromUserId, fromUsername);
// Handle incoming call in WebRTC service
await WebRTC.handleIncomingCall(fromUserId, fromUsername);
}
private async handleCallAccept(data: any) {
const { fromUserId } = data;
// Initiator should create and send offer now
try {
await WebRTC.onRemoteAccepted(fromUserId);
} catch (error) {
console.error("Failed to proceed after accept:", error);
}
}
private handleCallReject(data: any) {
const state = this.getState();
const { fromUserId } = data;
// Clean up WebRTC connection first
if (fromUserId) {
WebRTC.cleanupCall(fromUserId);
}
// End the call
state.endCall();
}
private async handleCallOffer(data: any) {
const { fromUserId, data: offer } = data;
await WebRTC.handleCallOffer(fromUserId, offer);
}
private async handleCallAnswer(data: any) {
const { fromUserId, data: answer } = data;
await WebRTC.handleCallAnswer(fromUserId, answer);
}
private async handleIceCandidate(data: any) {
const { fromUserId, data: candidate } = data;
await WebRTC.handleIceCandidate(fromUserId, candidate);
}
private handleCallEnd(data: any) {
const state = this.getState();
const { fromUserId } = data;
// Clean up WebRTC connection first
if (fromUserId) {
WebRTC.cleanupCall(fromUserId);
}
// End the call
state.endCall();
}
}