feat(call, voicemail, ivr): add voicemail and IVR call flows with DTMF handling, prompt playback, recording, and dashboard management

This commit is contained in:
2026-04-10 08:54:46 +00:00
parent 6ecd3f434c
commit e6bd64a534
25 changed files with 3892 additions and 10 deletions

View File

@@ -138,7 +138,16 @@ export class Call {
} else if (legs.every((l) => l.state === 'terminated')) {
this.state = 'terminated';
} else if (legs.some((l) => l.state === 'connected') && legs.filter((l) => l.state !== 'terminated').length >= 2) {
this.state = 'connected';
// If a system leg is connected, report voicemail/ivr state for the dashboard.
const systemLeg = legs.find((l) => l.type === 'system');
if (systemLeg) {
// Keep voicemail/ivr state if already set; otherwise set connected.
if (this.state !== 'voicemail' && this.state !== 'ivr') {
this.state = 'connected';
}
} else {
this.state = 'connected';
}
} else if (legs.some((l) => l.state === 'ringing')) {
this.state = 'ringing';
} else {
@@ -164,7 +173,7 @@ export class Call {
this.log(`[call:${this.id}] hanging up (${this.legs.size} legs)`);
for (const [id, leg] of this.legs) {
// Send BYE/CANCEL for SIP legs.
// Send BYE/CANCEL for SIP legs (system legs have no SIP signaling).
if (leg.type === 'sip-device' || leg.type === 'sip-provider') {
(leg as SipLeg).sendHangup();
}
@@ -197,6 +206,7 @@ export class Call {
// If this is a 2-party call, hang up the other leg too.
if (this.legs.size <= 1) {
for (const [id, leg] of this.legs) {
// Send BYE/CANCEL for SIP legs (system legs just get torn down).
if (leg.type === 'sip-device' || leg.type === 'sip-provider') {
(leg as SipLeg).sendHangup();
}