|
@@ -1015,6 +1015,34 @@ public class CallApi extends MsgHandlerBase {
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 网关列表诊断摘要(uuid/register/callProfile 等),便于对照外呼日志。
|
|
|
|
|
+ */
|
|
|
|
|
+ private String summarizeGatewayList(List<GatewayConfig> gatewayList) {
|
|
|
|
|
+ if (gatewayList == null || gatewayList.isEmpty()) {
|
|
|
|
|
+ return "[]";
|
|
|
|
|
+ }
|
|
|
|
|
+ StringBuilder sb = new StringBuilder("[");
|
|
|
|
|
+ for (int i = 0; i < gatewayList.size(); i++) {
|
|
|
|
|
+ GatewayConfig g = gatewayList.get(i);
|
|
|
|
|
+ if (i > 0) {
|
|
|
|
|
+ sb.append("; ");
|
|
|
|
|
+ }
|
|
|
|
|
+ sb.append(String.format(
|
|
|
|
|
+ "uuid=%s,register=%s,callProfile=%s,authUsername=%s,gatewayAddr=%s,gwName=%s,audioCodec=%s",
|
|
|
|
|
+ g.getUuid(),
|
|
|
|
|
+ g.getRegister(),
|
|
|
|
|
+ g.getCallProfile(),
|
|
|
|
|
+ g.getAuthUsername(),
|
|
|
|
|
+ g.getGatewayAddr(),
|
|
|
|
|
+ g.getGwName(),
|
|
|
|
|
+ g.getAudioCodec()
|
|
|
|
|
+ ));
|
|
|
|
|
+ }
|
|
|
|
|
+ sb.append("]");
|
|
|
|
|
+ return sb.toString();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
private String genCallPhoneString(GatewayConfig gatewayConfig, String projectId, String caseNo,
|
|
private String genCallPhoneString(GatewayConfig gatewayConfig, String projectId, String caseNo,
|
|
|
String uuidInner, String uuidOuter, String phone,
|
|
String uuidInner, String uuidOuter, String phone,
|
|
|
String callType, String videoLevel)
|
|
String callType, String videoLevel)
|
|
@@ -1068,23 +1096,39 @@ public class CallApi extends MsgHandlerBase {
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
if(gatewayConfig.getRegister() == 1){
|
|
if(gatewayConfig.getRegister() == 1){
|
|
|
|
|
+ // 注册模式:优先 gwName;兼容历史把网关名写在 gatewayAddr 的写法
|
|
|
|
|
+ String gatewayName = gatewayConfig.getGwName();
|
|
|
|
|
+ if(StringUtils.isNullOrEmpty(gatewayName)){
|
|
|
|
|
+ gatewayName = gatewayAddress;
|
|
|
|
|
+ }
|
|
|
bridgeString = String.format("{execute_on_answer='record_session %s',%s%s}sofia/gateway/%s/%s%s &park",
|
|
bridgeString = String.format("{execute_on_answer='record_session %s',%s%s}sofia/gateway/%s/%s%s &park",
|
|
|
CallConfig.RECORDINGS_PATH + fullRecordPath,
|
|
CallConfig.RECORDINGS_PATH + fullRecordPath,
|
|
|
callPrefixOuterLine,
|
|
callPrefixOuterLine,
|
|
|
extraParamsFinal,
|
|
extraParamsFinal,
|
|
|
- gatewayConfig.getGwName(),
|
|
|
|
|
|
|
+ gatewayName,
|
|
|
calleePrefix,
|
|
calleePrefix,
|
|
|
phone
|
|
phone
|
|
|
);
|
|
);
|
|
|
} else if(gatewayConfig.getRegister() == 2) {
|
|
} else if(gatewayConfig.getRegister() == 2) {
|
|
|
|
|
+ // 反向注册:按 authUsername 查已注册分机 Contact,再经 callProfile 出局
|
|
|
String authUsername = gatewayConfig.getAuthUsername();
|
|
String authUsername = gatewayConfig.getAuthUsername();
|
|
|
- String dynamicGateway = CommonUtils.getDynamicGatewayAddr(authUsername, getTraceId());
|
|
|
|
|
- logger.info("{} successfully get dynamic gateway address : {}", getTraceId(), dynamicGateway);
|
|
|
|
|
- // for dynamic gateway, we must use internal profile
|
|
|
|
|
- bridgeString = String.format("{execute_on_answer='record_session %s',%s%s}sofia/internal/%s%s@%s &park()",
|
|
|
|
|
|
|
+ logger.info("{} 软电话外呼 register=2:查询 Contact,authUsername={}, callProfile={}",
|
|
|
|
|
+ getTraceId(), authUsername, sipProfile);
|
|
|
|
|
+ String dynamicGateway = CommonUtils.getDynamicGatewayAddr(authUsername, getTraceId(), sipProfile);
|
|
|
|
|
+ if(StringUtils.isNullOrEmpty(dynamicGateway)){
|
|
|
|
|
+ logger.warn("{} 软电话外呼 register=2:Contact 为空,authUsername={}, profile={},跳过空地址 originate",
|
|
|
|
|
+ getTraceId(), authUsername, sipProfile);
|
|
|
|
|
+ return "";
|
|
|
|
|
+ }
|
|
|
|
|
+ String outboundProfile = StringUtils.isNullOrEmpty(sipProfile) ? "external" : sipProfile;
|
|
|
|
|
+ logger.info("{} 软电话外呼 register=2:已找到 Contact={},出局 profile={}",
|
|
|
|
|
+ getTraceId(), dynamicGateway, outboundProfile);
|
|
|
|
|
+ // sip_sticky_contact=true:对话内请求(ACK/BYE)发往实际网络地址,避免对端 200 OK 的 Contact 为内网时 ACK 无法送达
|
|
|
|
|
+ bridgeString = String.format("{sip_sticky_contact=true,execute_on_answer='record_session %s',%s%s}sofia/%s/%s%s@%s &park()",
|
|
|
CallConfig.RECORDINGS_PATH + fullRecordPath,
|
|
CallConfig.RECORDINGS_PATH + fullRecordPath,
|
|
|
callPrefixOuterLine,
|
|
callPrefixOuterLine,
|
|
|
extraParamsFinal,
|
|
extraParamsFinal,
|
|
|
|
|
+ outboundProfile,
|
|
|
calleePrefix,
|
|
calleePrefix,
|
|
|
callee,
|
|
callee,
|
|
|
dynamicGateway
|
|
dynamicGateway
|
|
@@ -1173,6 +1217,9 @@ public class CallApi extends MsgHandlerBase {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ logger.info("{} 软电话外呼收到 startSession:destPhone={}, callType={}, gatewayList摘要={}",
|
|
|
|
|
+ getTraceId(), phone, callType, summarizeGatewayList(gatewayList));
|
|
|
|
|
+
|
|
|
String uuidInner = UuidGenerator.GetOneUuid();
|
|
String uuidInner = UuidGenerator.GetOneUuid();
|
|
|
String uuidOuter = UuidGenerator.GetOneUuid();
|
|
String uuidOuter = UuidGenerator.GetOneUuid();
|
|
|
SwitchChannel agentChannel = new SwitchChannel(uuidInner, uuidOuter, callType, CallDirection.OUTBOUND);
|
|
SwitchChannel agentChannel = new SwitchChannel(uuidInner, uuidOuter, callType, CallDirection.OUTBOUND);
|
|
@@ -1262,21 +1309,36 @@ public class CallApi extends MsgHandlerBase {
|
|
|
);
|
|
);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
- logger.info("{} successfully get a gateway: {} ", getTraceId(), JSON.toJSONString(gatewayConfig));
|
|
|
|
|
|
|
+ logger.info("{} 软电话外呼选中网关:uuid={}, register={}, callProfile={}, authUsername={}, gatewayAddr={}, gwName={}",
|
|
|
|
|
+ getTraceId(),
|
|
|
|
|
+ gatewayConfig.getUuid(),
|
|
|
|
|
+ gatewayConfig.getRegister(),
|
|
|
|
|
+ gatewayConfig.getCallProfile(),
|
|
|
|
|
+ gatewayConfig.getAuthUsername(),
|
|
|
|
|
+ gatewayConfig.getGatewayAddr(),
|
|
|
|
|
+ gatewayConfig.getGwName());
|
|
|
|
|
|
|
|
String originationStr = genCallPhoneString(gatewayConfig, projectId, caseNo, uuidInner,
|
|
String originationStr = genCallPhoneString(gatewayConfig, projectId, caseNo, uuidInner,
|
|
|
uuidOuter, phone, callType, videoLevel);
|
|
uuidOuter, phone, callType, videoLevel);
|
|
|
customerChannel.setGatewayConfig(gatewayConfig);
|
|
customerChannel.setGatewayConfig(gatewayConfig);
|
|
|
|
|
+ // 反向注册 Contact 解析失败时 dialstring 为空,换下一网关重试
|
|
|
|
|
+ if(StringUtils.isNullOrEmpty(originationStr)){
|
|
|
|
|
+ logger.warn("{} 软电话外呼 dialstring 为空(多为 register=2 Contact 未找到),跳过 originate,标记网关已尝试:uuid={}, register={}",
|
|
|
|
|
+ getTraceId(), gatewayConfig.getUuid(), gatewayConfig.getRegister());
|
|
|
|
|
+ triedList.add(gatewayConfig);
|
|
|
|
|
+ SipGatewayLoadBalance.releaseGateway(gatewayConfig);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
connectionPool.getDefaultEslConn().addListener(uuidOuter, listener);
|
|
connectionPool.getDefaultEslConn().addListener(uuidOuter, listener);
|
|
|
- logger.info("{} originationStr: originate {}", getTraceId(), originationStr);
|
|
|
|
|
|
|
+ logger.info("{} 软电话外呼最终 dialstring:register={}, originate {}", getTraceId(), gatewayConfig.getRegister(), originationStr);
|
|
|
String jobId = EslConnectionUtil.sendAsyncApiCommand("originate", originationStr, connectionPool);
|
|
String jobId = EslConnectionUtil.sendAsyncApiCommand("originate", originationStr, connectionPool);
|
|
|
- logger.info("{} fs bgapi originate response: {}", getTraceId(), jobId);
|
|
|
|
|
|
|
+ logger.info("{} 软电话外呼 originate 已提交,bgJobId={}", getTraceId(), jobId);
|
|
|
if (!StringUtils.isNullOrEmpty(jobId)) {
|
|
if (!StringUtils.isNullOrEmpty(jobId)) {
|
|
|
connectionPool.getDefaultEslConn().addListener(jobId.trim(), listener);
|
|
connectionPool.getDefaultEslConn().addListener(jobId.trim(), listener);
|
|
|
this.listener.setBackgroundJobUuid(jobId.trim());
|
|
this.listener.setBackgroundJobUuid(jobId.trim());
|
|
|
} else {
|
|
} else {
|
|
|
- logger.error("{} cant not get FreeSWITCH backGroundJobUuid", getTraceId());
|
|
|
|
|
|
|
+ logger.error("{} 软电话外呼未能获取 FreeSWITCH backGroundJobUuid", getTraceId());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
listener.waitForSignal();
|
|
listener.waitForSignal();
|
|
@@ -1285,10 +1347,13 @@ public class CallApi extends MsgHandlerBase {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (!listener.checkCustomerChannelCallStatus()) {
|
|
if (!listener.checkCustomerChannelCallStatus()) {
|
|
|
- logger.info("{} call originate failed,add current gateway to triedList: gateway = {} ", getTraceId(), gatewayConfig);
|
|
|
|
|
|
|
+ logger.warn("{} 软电话外呼 originate 失败:uuid={}, register={}, sipCode={},加入 triedList",
|
|
|
|
|
+ getTraceId(), gatewayConfig.getUuid(), gatewayConfig.getRegister(),
|
|
|
|
|
+ customerChannel.getHangupSipCode());
|
|
|
triedList.add(gatewayConfig);
|
|
triedList.add(gatewayConfig);
|
|
|
} else {
|
|
} else {
|
|
|
- logger.info("{} call originate finished successfully,tried gateway list count:{} , details: {}", getTraceId(), triedList.size(), triedList);
|
|
|
|
|
|
|
+ logger.info("{} 软电话外呼 originate 成功:uuid={}, register={}, 已尝试网关数={}",
|
|
|
|
|
+ getTraceId(), gatewayConfig.getUuid(), gatewayConfig.getRegister(), triedList.size());
|
|
|
}
|
|
}
|
|
|
} while (!listener.checkCustomerChannelCallStatus() &&
|
|
} while (!listener.checkCustomerChannelCallStatus() &&
|
|
|
agentChannel.getHangupTime() == 0L && !getIsDisposed());
|
|
agentChannel.getHangupTime() == 0L && !getIsDisposed());
|