mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Implement audio calls
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user