WIP - call connecting to softphone

This commit is contained in:
Francisco Gaona
2026-01-04 04:29:25 +01:00
parent 71cd6a07b7
commit 03cbb5eb1f
11 changed files with 1190 additions and 104 deletions

View File

@@ -101,30 +101,50 @@ export function useSoftphone() {
}
const { api } = useApi();
console.log('Requesting Twilio token from /api/voice/token...');
const response = await api.get('/voice/token');
const token = response.data.token;
console.log('Token received, creating Device...');
// Log the token payload to see what identity is being used
try {
const tokenPayload = JSON.parse(atob(token.split('.')[1]));
console.log('Token identity:', tokenPayload.sub);
console.log('Token grants:', tokenPayload.grants);
} catch (e) {
console.log('Could not parse token payload');
}
twilioDevice.value = new Device(token, {
logLevel: 1,
codecPreferences: ['opus', 'pcmu'],
enableImprovedSignalingErrorPrecision: true,
// Specify audio constraints
edge: 'ashburn',
});
// Device events
twilioDevice.value.on('registered', () => {
console.log('Twilio Device registered');
console.log('Twilio Device registered - ready to receive calls');
toast.success('Softphone ready');
});
twilioDevice.value.on('unregistered', () => {
console.log('⚠ Twilio Device unregistered');
});
twilioDevice.value.on('error', (error) => {
console.error('Twilio Device error:', error);
console.error('Twilio Device error:', error);
toast.error('Device error: ' + error.message);
});
twilioDevice.value.on('incoming', (call: TwilioCall) => {
console.log('Incoming call:', call.parameters);
console.log('🔔 Twilio Device INCOMING event received:', call.parameters);
console.log('Call parameters:', {
CallSid: call.parameters.CallSid,
From: call.parameters.From,
To: call.parameters.To,
});
twilioCall.value = call;
// Update state
@@ -136,12 +156,27 @@ export function useSoftphone() {
status: 'ringing',
};
// Open softphone dialog
isOpen.value = true;
// Show notification
toast.info(`Incoming call from ${incomingCall.value.fromNumber}`, {
duration: 30000,
});
// Setup call handlers
setupCallHandlers(call);
// Play ringtone
playRingtone();
});
// Register the device
console.log('Registering Twilio Device...');
await twilioDevice.value.register();
console.log('✓ Twilio Device register() completed');
console.log('Device identity:', twilioDevice.value.identity);
console.log('Device state:', twilioDevice.value.state);
} catch (error: any) {
console.error('Failed to initialize Twilio Device:', error);
@@ -320,16 +355,22 @@ export function useSoftphone() {
* Accept incoming call
*/
const acceptCall = async (callSid: string) => {
console.log('📞 Accepting call - callSid:', callSid);
console.log('twilioCall.value:', twilioCall.value);
if (!twilioCall.value) {
console.error('❌ No incoming call to accept - twilioCall.value is null');
toast.error('No incoming call');
return;
}
try {
console.log('Calling twilioCall.value.accept()...');
await twilioCall.value.accept();
console.log('✓ Call accepted successfully');
toast.success('Call accepted');
} catch (error: any) {
console.error('Failed to accept call:', error);
console.error('Failed to accept call:', error);
toast.error('Failed to accept call: ' + error.message);
}
};
@@ -397,22 +438,10 @@ export function useSoftphone() {
// Event handlers
const handleIncomingCall = (data: Call) => {
console.log('Incoming call:', data);
incomingCall.value = data;
isOpen.value = true;
toast.info(`Incoming call from ${data.fromNumber}`, {
duration: 30000,
action: {
label: 'Answer',
onClick: () => {
acceptCall(data.callSid);
},
},
});
// Play ringtone
playRingtone();
// Socket.IO notification that a call is coming
// The actual call object will come from Twilio Device SDK's 'incoming' event
console.log('Socket.IO call notification:', data);
// Don't set incomingCall here - wait for the Device SDK incoming event
};
const handleCallInitiated = (data: any) => {
@@ -512,12 +541,31 @@ export function useSoftphone() {
let ringtoneAudio: HTMLAudioElement | null = null;
const playRingtone = () => {
// Optional: Play a simple beep tone using Web Audio API
// This is a nice-to-have enhancement but not required for incoming calls to work
try {
ringtoneAudio = new Audio('/ringtone.mp3');
ringtoneAudio.loop = true;
ringtoneAudio.play();
const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
// Phone ringtone frequency (440 Hz)
oscillator.frequency.value = 440;
oscillator.type = 'sine';
const now = audioContext.currentTime;
gainNode.gain.setValueAtTime(0.15, now);
gainNode.gain.setValueAtTime(0, now + 0.5);
gainNode.gain.setValueAtTime(0.15, now + 1.0);
gainNode.gain.setValueAtTime(0, now + 1.5);
oscillator.start(now);
oscillator.stop(now + 2);
} catch (error) {
console.error('Failed to play ringtone:', error);
// Silent fail - incoming call still works without audio
console.debug('Audio notification skipped:', error);
}
};