188 lines
5.9 KiB
TypeScript
188 lines
5.9 KiB
TypeScript
import { onProxyEvent } from '../proxybridge.ts';
|
|
import type { VoiceboxManager } from '../voicebox.ts';
|
|
import type { StatusStore } from './status-store.ts';
|
|
import type { IProviderMediaInfo, WebRtcLinkManager } from './webrtc-linking.ts';
|
|
|
|
export interface IRegisterProxyEventHandlersOptions {
|
|
log: (msg: string) => void;
|
|
statusStore: StatusStore;
|
|
voiceboxManager: VoiceboxManager;
|
|
webRtcLinks: WebRtcLinkManager;
|
|
getBrowserDeviceIds: () => string[];
|
|
sendToBrowserDevice: (deviceId: string, data: unknown) => boolean;
|
|
broadcast: (type: string, data: unknown) => void;
|
|
onLinkWebRtcSession: (callId: string, sessionId: string, media: IProviderMediaInfo) => void;
|
|
onCloseWebRtcSession: (sessionId: string) => void;
|
|
}
|
|
|
|
export function registerProxyEventHandlers(options: IRegisterProxyEventHandlersOptions): void {
|
|
const {
|
|
log,
|
|
statusStore,
|
|
voiceboxManager,
|
|
webRtcLinks,
|
|
getBrowserDeviceIds,
|
|
sendToBrowserDevice,
|
|
broadcast,
|
|
onLinkWebRtcSession,
|
|
onCloseWebRtcSession,
|
|
} = options;
|
|
|
|
onProxyEvent('provider_registered', (data) => {
|
|
const previous = statusStore.noteProviderRegistered(data);
|
|
if (previous) {
|
|
if (data.registered && !previous.wasRegistered) {
|
|
log(`[provider:${data.provider_id}] registered (publicIp=${data.public_ip})`);
|
|
} else if (!data.registered && previous.wasRegistered) {
|
|
log(`[provider:${data.provider_id}] registration lost`);
|
|
}
|
|
}
|
|
broadcast('registration', { providerId: data.provider_id, registered: data.registered });
|
|
});
|
|
|
|
onProxyEvent('device_registered', (data) => {
|
|
if (statusStore.noteDeviceRegistered(data)) {
|
|
log(`[registrar] ${data.display_name} registered from ${data.address}:${data.port}`);
|
|
}
|
|
});
|
|
|
|
onProxyEvent('incoming_call', (data) => {
|
|
log(`[call] incoming: ${data.from_uri} -> ${data.to_number} via ${data.provider_id} (${data.call_id})`);
|
|
statusStore.noteIncomingCall(data);
|
|
|
|
if (data.ring_browsers === false) {
|
|
return;
|
|
}
|
|
|
|
for (const deviceId of getBrowserDeviceIds()) {
|
|
sendToBrowserDevice(deviceId, {
|
|
type: 'webrtc-incoming',
|
|
callId: data.call_id,
|
|
from: data.from_uri,
|
|
deviceId,
|
|
});
|
|
}
|
|
});
|
|
|
|
onProxyEvent('outbound_device_call', (data) => {
|
|
log(`[call] outbound: device ${data.from_device} -> ${data.to_number} (${data.call_id})`);
|
|
statusStore.noteOutboundDeviceCall(data);
|
|
});
|
|
|
|
onProxyEvent('outbound_call_started', (data) => {
|
|
log(`[call] outbound started: ${data.call_id} -> ${data.number} via ${data.provider_id}`);
|
|
statusStore.noteOutboundCallStarted(data);
|
|
|
|
for (const deviceId of getBrowserDeviceIds()) {
|
|
sendToBrowserDevice(deviceId, {
|
|
type: 'webrtc-incoming',
|
|
callId: data.call_id,
|
|
from: data.number,
|
|
deviceId,
|
|
});
|
|
}
|
|
});
|
|
|
|
onProxyEvent('call_ringing', (data) => {
|
|
statusStore.noteCallRinging(data);
|
|
});
|
|
|
|
onProxyEvent('call_answered', (data) => {
|
|
if (statusStore.noteCallAnswered(data)) {
|
|
log(`[call] ${data.call_id} connected`);
|
|
}
|
|
|
|
if (!data.provider_media_addr || !data.provider_media_port) {
|
|
return;
|
|
}
|
|
|
|
const target = webRtcLinks.noteCallAnswered(data.call_id, {
|
|
addr: data.provider_media_addr,
|
|
port: data.provider_media_port,
|
|
sipPt: data.sip_pt ?? 9,
|
|
});
|
|
|
|
if (!target) {
|
|
log(`[webrtc] media info cached for call=${data.call_id}, waiting for session accept`);
|
|
return;
|
|
}
|
|
|
|
onLinkWebRtcSession(data.call_id, target.sessionId, target.media);
|
|
});
|
|
|
|
onProxyEvent('call_ended', (data) => {
|
|
if (statusStore.noteCallEnded(data)) {
|
|
log(`[call] ${data.call_id} ended: ${data.reason} (${data.duration}s)`);
|
|
}
|
|
|
|
broadcast('webrtc-call-ended', { callId: data.call_id });
|
|
|
|
const sessionId = webRtcLinks.cleanupCall(data.call_id);
|
|
if (sessionId) {
|
|
onCloseWebRtcSession(sessionId);
|
|
}
|
|
});
|
|
|
|
onProxyEvent('sip_unhandled', (data) => {
|
|
log(`[sip] unhandled ${data.method_or_status} Call-ID=${data.call_id?.slice(0, 20)} from=${data.from_addr}:${data.from_port}`);
|
|
});
|
|
|
|
onProxyEvent('leg_added', (data) => {
|
|
log(`[leg] added: call=${data.call_id} leg=${data.leg_id} kind=${data.kind} state=${data.state}`);
|
|
statusStore.noteLegAdded(data);
|
|
});
|
|
|
|
onProxyEvent('leg_removed', (data) => {
|
|
log(`[leg] removed: call=${data.call_id} leg=${data.leg_id}`);
|
|
statusStore.noteLegRemoved(data);
|
|
});
|
|
|
|
onProxyEvent('leg_state_changed', (data) => {
|
|
log(`[leg] state: call=${data.call_id} leg=${data.leg_id} -> ${data.state}`);
|
|
statusStore.noteLegStateChanged(data);
|
|
});
|
|
|
|
onProxyEvent('webrtc_ice_candidate', (data) => {
|
|
broadcast('webrtc-ice', {
|
|
sessionId: data.session_id,
|
|
candidate: {
|
|
candidate: data.candidate,
|
|
sdpMid: data.sdp_mid,
|
|
sdpMLineIndex: data.sdp_mline_index,
|
|
},
|
|
});
|
|
});
|
|
|
|
onProxyEvent('webrtc_state', (data) => {
|
|
log(`[webrtc] session=${data.session_id?.slice(0, 8)} state=${data.state}`);
|
|
});
|
|
|
|
onProxyEvent('webrtc_track', (data) => {
|
|
log(`[webrtc] session=${data.session_id?.slice(0, 8)} track=${data.kind} codec=${data.codec}`);
|
|
});
|
|
|
|
onProxyEvent('webrtc_audio_rx', (data) => {
|
|
if (data.packet_count === 1 || data.packet_count === 50) {
|
|
log(`[webrtc] session=${data.session_id?.slice(0, 8)} browser audio rx #${data.packet_count}`);
|
|
}
|
|
});
|
|
|
|
onProxyEvent('voicemail_started', (data) => {
|
|
log(`[voicemail] started for call ${data.call_id} caller=${data.caller_number}`);
|
|
});
|
|
|
|
onProxyEvent('recording_done', (data) => {
|
|
log(`[voicemail] recording done: ${data.file_path} (${data.duration_ms}ms) caller=${data.caller_number}`);
|
|
voiceboxManager.addMessage('default', {
|
|
callerNumber: data.caller_number || 'Unknown',
|
|
callerName: null,
|
|
fileName: data.file_path,
|
|
durationMs: data.duration_ms,
|
|
});
|
|
});
|
|
|
|
onProxyEvent('voicemail_error', (data) => {
|
|
log(`[voicemail] error: ${data.error} call=${data.call_id}`);
|
|
});
|
|
}
|