You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#使用AsterNET开发时如何取消已发起的外呼通话

问题描述

基于AsterNET组件开发管理端程序时,已实现员工点击按钮一键呼叫客户的功能,当前需要补充取消外呼、主动断开与客户呼叫连接的能力,但未找到对应的实现方法。
当前呼叫业务流程如下:

  • 点击呼叫按钮后,系统首先呼叫对应员工分机
  • 员工摘机后,系统开始拨打客户号码,同时弹出窗口向员工展示呼叫进度
  • 已额外添加取消呼叫按钮,但未找到可终止向客户拨号的相关事件或函数
    核心实现代码如下:
manager = new ManagerConnection(host, port, username, password);
manager.DialBegin += Manager_DialBegin;
manager.DialEnd += Manager_DialEnd;
manager.Hangup += Manager_Hangup;
manager.PingInterval = 0;
try
{
    manager.Login();
    OriginateAction oc = new OriginateAction();
    oc.Context = "from-internal";
    oc.Priority = "1";
    oc.Channel = "SIP/100";
    oc.CallerId = "100";
    oc.Exten = lblPhoneNumber.Text;
    oc.Timeout = 30000;
    oc.Async = true;
    manager.SendAction(oc, null);
}
catch (ManagerException ex)
{
    var sendMail = Task.Run(async () => await Email.SendMail(Properties.Settings.Default.SmtpEmailLogAddress, "", "", "Error connecting to Asterisk",
        "Could not connect to the Asterisk-server for employee: " + Functions.GetEmployeeByID(Manager.Employee_ID),
        true, "", System.Net.Mail.MailPriority.Normal));
}
实现方案

你当前使用异步OriginateAction发起外呼,整个外呼过程分两个阶段,取消逻辑需要对应阶段分别处理:

阶段1:系统正在呼叫员工分机,员工尚未摘机

这个阶段还未启动客户号码呼叫,直接发送CancelOriginateAction即可终止外呼任务。需要注意提前保存发起外呼时的ActionId,用于匹配要取消的外呼任务。
首先修改原外呼发起逻辑,新增全局状态变量存储外呼相关标识:

// 全局状态变量
private string _currentOriginateActionId;
private string _employeeChannel;
private string _customerChannel;

// 外呼发起部分代码修改
OriginateAction oc = new OriginateAction();
oc.Context = "from-internal";
oc.Priority = "1";
oc.Channel = "SIP/100";
oc.CallerId = "100";
oc.Exten = lblPhoneNumber.Text;
oc.Timeout = 30000;
oc.Async = true;
// 生成唯一ActionId并赋值,用于后续取消匹配
_currentOriginateActionId = Guid.NewGuid().ToString("N");
oc.ActionId = _currentOriginateActionId;
manager.SendAction(oc, null);

该阶段的取消按钮逻辑如下:

if (!string.IsNullOrEmpty(_currentOriginateActionId) && string.IsNullOrEmpty(_customerChannel))
{
    CancelOriginateAction cancelOriginate = new CancelOriginateAction();
    cancelOriginate.ActionId = _currentOriginateActionId;
    manager.SendAction(cancelOriginate);
    ResetCallState();
}

阶段2:员工已摘机,系统正在振铃客户/已和客户接通

这个阶段Originate任务已经执行完成,CancelOriginateAction不再生效,需要通过HangupAction挂断对应通道实现取消/断开:

  • 客户未接通时,挂断客户侧振铃通道即可,员工分机通道会被Asterisk自动回收
  • 客户已接通时,可根据业务需求选择仅挂断客户通道、或同时挂断员工分机通道
    首先配合已注册的事件回调,实时更新通道状态:
private void Manager_DialBegin(object sender, DialBeginEvent e)
{
    // 匹配当前员工分机,记录主被叫通道
    if (e.Channel.StartsWith("SIP/100"))
    {
        _employeeChannel = e.Channel;
        _customerChannel = e.Destination;
    }
}

private void Manager_Hangup(object sender, HangupEvent e)
{
    // 通道释放后清除对应标记
    if (e.Channel == _employeeChannel) _employeeChannel = null;
    if (e.Channel == _customerChannel) _customerChannel = null;
    // 所有通道释放完成后重置状态
    if (string.IsNullOrEmpty(_employeeChannel) && string.IsNullOrEmpty(_customerChannel))
    {
        ResetCallState();
    }
}

// 状态重置公共方法
private void ResetCallState()
{
    _currentOriginateActionId = null;
    _employeeChannel = null;
    _customerChannel = null;
}

该阶段的取消/断开逻辑如下:

if (!string.IsNullOrEmpty(_customerChannel))
{
    // 挂断客户侧通道
    HangupAction hangupCustomer = new HangupAction();
    hangupCustomer.Channel = _customerChannel;
    hangupCustomer.Cause = 16; // 16为正常呼叫清除原因码
    manager.SendAction(hangupCustomer);

    // 如需取消后直接把员工分机也挂断,取消下方注释即可
    // if (!string.IsNullOrEmpty(_employeeChannel))
    // {
    //     HangupAction hangupEmployee = new HangupAction(_employeeChannel, 16);
    //     manager.SendAction(hangupEmployee);
    // }
}

兼容说明:如果使用13以前的老旧Asterisk版本,CancelOriginateAction可能不被支持,此时可以直接挂断员工分机通道终止整个外呼流程,仅会在员工已摘机的场景下直接挂断分机,体验略差,新版本优先使用分阶段处理逻辑。

内容的提问来源于stack exchange,提问作者Paul Albers

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 04:01:07