From 26570603ded8a219cd916ada8b930b293e2dd9fc Mon Sep 17 00:00:00 2001 From: jack ning Date: Tue, 21 Oct 2025 07:44:47 +0800 Subject: [PATCH] update --- modules/call/pom.xml | 1 - .../call/config/CallEventListener.java | 155 +++++++++++++++++- .../call/esl/xmlcurl/XmlCurlController.java | 1 + 3 files changed, 153 insertions(+), 4 deletions(-) diff --git a/modules/call/pom.xml b/modules/call/pom.xml index bcc35d4ee3..74b0e99ddb 100644 --- a/modules/call/pom.xml +++ b/modules/call/pom.xml @@ -83,7 +83,6 @@ 2.2.4 - diff --git a/modules/call/src/main/java/com/bytedesk/call/config/CallEventListener.java b/modules/call/src/main/java/com/bytedesk/call/config/CallEventListener.java index 761e8551ae..23e3c8949a 100644 --- a/modules/call/src/main/java/com/bytedesk/call/config/CallEventListener.java +++ b/modules/call/src/main/java/com/bytedesk/call/config/CallEventListener.java @@ -17,14 +17,12 @@ import lombok.extern.slf4j.Slf4j; @ConditionalOnProperty(prefix = "bytedesk.call.freeswitch", name = "enabled", havingValue = "true", matchIfMissing = false) public class CallEventListener implements com.bytedesk.call.esl.client.inbound.IEslEventListener { - // private final CallEventPublisher eventPublisher; - // 实现 IEslEventListener 的回调 @Override public void onEslEvent(Context ctx, EslEvent eslEvent) { String eventName = eslEvent.getEventName(); - log.debug("收到Call事件: {} / {}", eventName, eslEvent.getEventHeaders()); + log.info("收到Call事件: {}", eventName); switch (eventName) { case "CHANNEL_CREATE": @@ -36,13 +34,38 @@ public class CallEventListener implements com.bytedesk.call.esl.client.inbound.I case "CHANNEL_HANGUP": handleChannelHangup(eslEvent); break; + case "CHANNEL_HANGUP_COMPLETE": + handleChannelHangupComplete(eslEvent); + break; + case "CHANNEL_DESTROY": + handleChannelDestroy(eslEvent); + break; case "DTMF": handleDtmf(eslEvent); break; case "CUSTOM": handleCustomEvent(eslEvent); break; + case "CHANNEL_EXECUTE": + handleChannelExecute(eslEvent); + break; + case "CHANNEL_EXECUTE_COMPLETE": + handleChannelExecuteComplete(eslEvent); + break; + case "CHANNEL_STATE": + handleChannelState(eslEvent); + break; + case "CHANNEL_CALLSTATE": + handleChannelCallState(eslEvent); + break; + case "PRESENCE_IN": + handlePresenceIn(eslEvent); + break; + case "API": + handleApiEvent(eslEvent); + break; default: + // log.info("handle default event: {}", eslEvent.getEventHeaders()); break; } } @@ -123,6 +146,26 @@ public class CallEventListener implements com.bytedesk.call.esl.client.inbound.I // eventPublisher.publishEvent(new CallCallHangupEvent(this, uuid, hangupCause)); } + /** + * 处理通道挂断完成事件 + */ + private void handleChannelHangupComplete(EslEvent eslEvent) { + String uuid = eslEvent.getEventHeaders().get("Unique-ID"); + String hangupCause = eslEvent.getEventHeaders().getOrDefault("hangup_cause", + eslEvent.getEventHeaders().get("Hangup-Cause")); + String duration = eslEvent.getEventHeaders().getOrDefault("duration", "0"); + String billsec = eslEvent.getEventHeaders().getOrDefault("billsec", "0"); + + log.info("通道挂断完成: UUID {} 原因 {} 通话时长(s) {} 计费时长(s) {}", uuid, hangupCause, duration, billsec); + + try { + // cdrService.finalizeCdr(uuid, hangupCause, Integer.parseInt(duration), Integer.parseInt(billsec)); + log.debug("已最终完成CDR: UUID {}", uuid); + } catch (Exception e) { + log.error("最终完成CDR失败: UUID {} - {}", uuid, e.getMessage(), e); + } + } + /** * 处理DTMF按键事件 */ @@ -143,6 +186,7 @@ public class CallEventListener implements com.bytedesk.call.esl.client.inbound.I */ private void handleCustomEvent(EslEvent eslEvent) { // String eventSubclass = eslEvent.getEventSubclass(); + log.info("自定义事件: {}", eslEvent.getEventHeaders()); // if ("bytedesk::custom".equals(eventSubclass)) { // // 处理自定义事件 @@ -150,11 +194,116 @@ public class CallEventListener implements com.bytedesk.call.esl.client.inbound.I // } } + /** + * 处理应用执行事件 + */ + private void handleChannelExecute(EslEvent eslEvent) { + var headers = eslEvent.getEventHeaders(); + String uuid = headers.get("Unique-ID"); + String application = headers.get("Application"); + String appData = headers.get("Application-Data"); + String currentApp = headers.get("variable_current_application"); + String currentAppData = headers.get("variable_current_application_data"); + + log.info("应用执行: UUID {} App {} Data {} CurrApp {} CurrData {}", uuid, application, appData, currentApp, + currentAppData); + + // 典型关键信息示例:录音文件、转接、拨号等 + String recordFile = headers.get("variable_record_filename"); + String executeOnAnswer = headers.get("variable_execute_on_answer"); + if (recordFile != null || executeOnAnswer != null) { + log.debug("执行参数: record={} execute_on_answer={}", recordFile, executeOnAnswer); + } + } + + /** + * 处理应用执行完成事件 + */ + private void handleChannelExecuteComplete(EslEvent eslEvent) { + var headers = eslEvent.getEventHeaders(); + String uuid = headers.get("Unique-ID"); + String application = headers.get("Application"); + String response = headers.get("Application-Response"); + String recordFile = headers.get("variable_record_filename"); + + log.info("应用执行完成: UUID {} App {} Response {} Record {}", uuid, application, response, recordFile); + } + + /** + * 处理通道状态事件 + */ + private void handleChannelState(EslEvent eslEvent) { + var headers = eslEvent.getEventHeaders(); + String uuid = headers.get("Unique-ID"); + String state = headers.get("Channel-State"); + String callState = headers.get("Channel-Call-State"); + String answerState = headers.get("Answer-State"); + + log.info("通道状态: UUID {} State {} CallState {} AnswerState {}", uuid, state, callState, answerState); + } + + /** + * 处理通话状态变更事件 + */ + private void handleChannelCallState(EslEvent eslEvent) { + var headers = eslEvent.getEventHeaders(); + String uuid = headers.get("Unique-ID"); + String callState = headers.get("Channel-Call-State"); + String original = headers.get("Original-Channel-Call-State"); + String hangupCause = headers.get("Hangup-Cause"); + + log.info("通话状态: UUID {} CallState {} -> {} Cause {}", uuid, original, callState, hangupCause); + } + + /** + * 处理Presence事件(座席/用户振铃、空闲等) + */ + private void handlePresenceIn(EslEvent eslEvent) { + var headers = eslEvent.getEventHeaders(); + String presenceId = headers.get("Channel-Presence-ID"); + String direction = headers.getOrDefault("presence-call-direction", headers.get("Presence-Call-Direction")); + String infoState = headers.get("presence-call-info-state"); + String status = headers.get("status"); + + log.info("Presence: {} direction={} infoState={} status={}", presenceId, direction, infoState, status); + + // 可在此更新坐席/用户实时状态 + // presenceService.update(presenceId, direction, infoState, status); + } + + /** + * 处理 API 事件(如 strftime 等调用) + */ + private void handleApiEvent(EslEvent eslEvent) { + var headers = eslEvent.getEventHeaders(); + String cmd = headers.get("API-Command"); + String arg = headers.get("API-Command-Argument"); + log.info("API事件: command={} arg={} headers={}", cmd, arg, headers); + } + + /** + * 处理通道销毁事件 + */ + private void handleChannelDestroy(EslEvent eslEvent) { + var headers = eslEvent.getEventHeaders(); + String uuid = headers.get("Unique-ID"); + String hangupCause = headers.getOrDefault("Hangup-Cause", headers.get("variable_hangup_cause")); + log.info("通道销毁: UUID {} 原因 {}", uuid, hangupCause); + + try { + // cdrService.closeSession(uuid); + log.debug("会话资源已清理: UUID {}", uuid); + } catch (Exception e) { + log.error("清理会话资源失败: UUID {} - {}", uuid, e.getMessage(), e); + } + } + /** * 更新用户在线状态 */ private void updateUserOnlineStatus(String username, boolean online) { log.debug("更新用户在线状态: {} -> {}", username, online); + try { // Optional userOptional = // userService.findByUsername(username); diff --git a/modules/call/src/main/java/com/bytedesk/call/esl/xmlcurl/XmlCurlController.java b/modules/call/src/main/java/com/bytedesk/call/esl/xmlcurl/XmlCurlController.java index aa451013eb..24c2583e16 100644 --- a/modules/call/src/main/java/com/bytedesk/call/esl/xmlcurl/XmlCurlController.java +++ b/modules/call/src/main/java/com/bytedesk/call/esl/xmlcurl/XmlCurlController.java @@ -79,6 +79,7 @@ public class XmlCurlController { ivrMenu, queueName, recordFile, phrasesLang, finalConfName, ccDsn, ccClientAddress, ccDebug, ccCdrLogDir, ccCreateTables); + return ResponseEntity.ok() .contentType(MediaType.APPLICATION_XML) .body(xml);