如何在Tapiex ActiveX v3.6中每行多路通话?

时间:2018-06-26 07:34:06

标签: c# ivr tapi

我用tapiex activex v3.6编写了一个IVR程序,我希望每条线路获得多次呼叫,但是在我的程序中,当程序正在调用时,我想同时调用它,所以很忙! 我该怎么办? 我应该保持已接通的呼叫吗?如果是,当我必须这样做时? 当程序正在调用并且有人尝试同时调用它时,是否会触发事件?如果是,哪个事件? 我的程序应该是多线程的吗?我试图使其成为多线程,但发生了此错误!

  

'与其下层RCW分开的COM对象不能是   用过。”

StartIvr();
//UiGlobal.ThreadManager.StartThread(o => StartIvr());

这是我的startIvr方法

private void StartIvr()
        {
            UI.Class.IVR.EventHandler eventHandler = new Class.IVR.EventHandler();
            eventHandler.InitPhone();
            eventHandler.OpenLine(null);
            UiGlobal.eventHandler = eventHandler;
        }

这是我的事件处理程序类

class EventHandler
{
    public List<string> linesName { get; set; }
    public AxTAPIEXLib.AxTAPIExCtl Tapiex_com { get; set; }
    public bool IsOutputCall = false;
    CallHandler callHandler;


    public EventHandler()
    {
        linesName = new List<string>();
        Tapiex_com = new AxTAPIEXLib.AxTAPIExCtl();

    }

    public EventHandler(AxTAPIEXLib.AxTAPIExCtl Tapiex_com)
    {
        linesName = new List<string>();
        this.Tapiex_com = Tapiex_com;
    }

    public ITAPILine Find_line(string LineName)
    {
        ITAPILine line = null;
        for (int i = 0; i < Tapiex_com.Lines.Count; i++)
            if (Tapiex_com.Lines.Item(i).Name == LineName)
            {
                line = Tapiex_com.Lines.Item(i);
                break;
            }
        return line;

    }
    protected void Dispose(bool disposing)
    {
        if (disposing && (Tapiex_com != null))
        {
            Tapiex_com.Dispose();
        }
    }
    public bool InitPhone()
    {
        Tapiex_com.CreateControl();
        Tapiex_com.OnRing += new AxTAPIEXLib._ITAPIExEvents_OnRingEventHandler(this.Tapiex_com_OnRing);
        Tapiex_com.OnDTMF += new AxTAPIEXLib._ITAPIExEvents_OnDTMFEventHandler(this.Tapiex_com_OnDTMF);
        Tapiex_com.OnConnected += new AxTAPIEXLib._ITAPIExEvents_OnConnectedEventHandler(this.Tapiex_com_OnConnected);
        Tapiex_com.OnDisConnected += new AxTAPIEXLib._ITAPIExEvents_OnDisConnectedEventHandler(this.Tapiex_com_OnDisConnected);
        Tapiex_com.OnCallerID += new AxTAPIEXLib._ITAPIExEvents_OnCallerIDEventHandler(this.Tapiex_com_OnCallerID);
        Tapiex_com.OnNewCall += new AxTAPIEXLib._ITAPIExEvents_OnNewCallEventHandler(this.Tapiex_com_OnNewCall);
        bool init = Tapiex_com.initialize();

        foreach (ITAPILine tmpline in Tapiex_com.Lines)
            if ((tmpline.Caps.Media_Modes & LINEMEDIAMODE.MEDIAMODE_INTERACTIVEVOICE) > 0 ||
                (tmpline.Caps.Media_Modes & LINEMEDIAMODE.MEDIAMODE_AUTOMATEDVOICE) > 0)
                linesName.Add(tmpline.Name);
        return init;
    }

    public bool OpenLine(string lineName)
    {
        if (lineName == null)
        {
            foreach (string item in linesName)
            {
                var line = Find_line(item);
                if (!line.Opened)
                    line.Open();
            }
            return true;
        }
        else
        {
            var line = Find_line(lineName);
            if (line != null)
            {
                if (!line.Opened)
                    line.Open();
                return true;
            }
            else return false;
        }

    }
    private void Tapiex_com_OnDTMF(object sender, _ITAPIExEvents_OnDTMFEvent e)
    {
        if (!IsOutputCall)
        {
            isInDTMFMethod = true;
            callHandler.DTMF(e);
            isInDTMFMethod = false;
        }
    }
    private void Tapiex_com_OnNewCall(object sender, _ITAPIExEvents_OnNewCallEvent e)
    {
        callHandler = new CallHandler();
    }

    private void Tapiex_com_OnRing(object sender, AxTAPIEXLib._ITAPIExEvents_OnRingEvent e)
    {
        if (e.ringCount > 1) e.m_Call.Answer();
    }

    private void Tapiex_com_OnConnected(object sender, AxTAPIEXLib._ITAPIExEvents_OnConnectedEvent e)
    {
        callHandler.Connected(e, IsOutputCall);

    }

    private void Tapiex_com_OnDisConnected(object sender, AxTAPIEXLib._ITAPIExEvents_OnDisConnectedEvent e)
    {
        callHandler.HangUp(e.m_Call);
        IsOutputCall = false;
    }

    private void Tapiex_com_OnCallerID(object sender, AxTAPIEXLib._ITAPIExEvents_OnCallerIDEvent e)
    {
        callHandler.GetCallerID(e);
    }

2 个答案:

答案 0 :(得分:0)

好的,一个帖子中有很多问题。如果这没有一个“实用”的答案,我深表歉意,但是我将需要几页来介绍您的所有内容。因此,在这里我将做一些一般性的观察,希望它可以帮助您缩小范围。

1)设备上的多行不是“正常”或“平均”行为,这也不是TAPI可以决定的事情,这完全取决于PBX系统。大多数只允许在一个分机上拨打电话,一些2和一些例外将允许使用特殊配置设置进行更多呼叫。 TAPI在大多数情况下都可以理解为一种设备,它代表一种物理电话设备。 IVR通常使用的是“中继线”,但是许多PBX不会通过TAPI发布/公开这些线。

2)ActiveX和COM在多线程环境中需要以不同的方式处理:不同的启动和停止功能。您可能想先寻找有关多线程COM编程的教程或书籍。

3)TAPI的主要重点是监视和控制扩展,它实际上并不适合支持IVR。我并不是说这是不可能的,但这绝对是“艰难的道路”。在呼叫中心环境中,TAPI通常用于在离开IVR后监视呼叫,而不是IVR本身。您可能需要考虑在SIP,H323或中间件堆栈上构建IVR。

4)如果确定要执行TAPI,我建议您不要使用TAPI 3。 TAPI 3是将TAPI引入现代世界(1999年)的尝试,并没有采取一切措施,因此存在很多遗漏之处。到目前为止,所使用的技术本身已过时或已过时。如果您认真构建与商业IVR系统一样复杂的内容,则不妨使用基于TAPI 2的系统,以获得更完整,更稳定的界面(如果您不熟悉本机,则可以使用一些.NET包装器。 C / C ++编码)。这是反直观的,但在这种情况下2比3更好更好。尤其是因为您需要使用诸如音频处理(很少有PBX支持!)之类的更多“特殊”部件来制作IVR。

答案 1 :(得分:0)

首先,语音调制解调器是最糟糕的电话设备。您将永远无法以所需的方式运行它。是的,您可以使用连接到模拟线路的“挂机闪光”来使用呼叫等待或三方呼叫,但是您无法控制或报告呼叫。您将不知道它是否有效以及您真正打过什么电话。参见:http://www.exceletel.com/products/TeleTools/Help/Working_With_Modems.htm。解决方案:获得用于模拟或更好的VoIP提供商的Way2Call Hi-Phone,并使用SIP Communications Server软件将SIP中继线连接到TAPI(安装2分钟)。最后,您可以安装“免费” PBX(例如3CX或Asterisk)并将其连接到模拟线路或SIP中继,并在您的计算机上安装PBX的TSP来控制它。

第一个答案充满了很多错误信息(对Kris表示歉意)。首先,TAPI并非旨在“代表物理电话设备”。 TAPI可以控制“线路设备”,“电话设备”,“终端设备”以及对wave,传真和其他设备的访问。它最常用于控制“行”。它完全控制设备制造商提供的任何功能。 TAPI当然可以支持多线IVR。这是英特尔和微软设计其工作的一部分。上面的项目3完全不正确。这是仅使用几行代码和TAPI控件的四行IVR程序的示例:http://www.exceletel.com/products/TeleTools/SamplePrograms/etIVR4Line/Index.htm。当然,您需要一台可以暴露多条线的设备,以便您一次测试多条线。

如果您查看该代码,则可以将其翻译为使用TAPI控件,因为它们从TeleTools控件复制了许多功能。通常,您必须通过所谓的“第三方” TSP通过设备的TSP暴露多条线路,而不仅仅是“第一方” TSP(否则,您将只能控制每台计算机上的一条线路(但对于每条线路,例如转接和会议,可能会超过一个呼叫)。

例如,Dialogic 4端口卡将为您提供4条模拟线路。一张T1卡可以让您访问24。PBX可以通过其TSP(电话服务提供商驱动程序软件)向您公开线路,也可以通过SIP中继向您提供上述公司的SIP通信服务器软件,以进行访问。连接到它。使用SIP DOES可以在电话的更多方面进行建模,但是对于硬件有限的TAPI支持或SIP安装更加简单或消除PBX上许可费(某些功能额外收费)的人们来说,这是一个选择。

例如,安装了呼叫管理器的Cisco PBX可以向TAPI应用程序公开多条线路。 Avaya及其IP Office软件也是如此。您不需要线程化任何东西。您只需要多个控件。每个控件都会初始化一条线(如IVR 4 Line示例中所示)。如果您使用了TeleScope或Julmar Phone之类的实用程序,或者甚至是上面的IVR程序的EXE版本,则在下拉列表中会看到系统上找到的所有设备。因此,如果看到“ Analog Line1”和“ Analog Line2”,那么您将创建2个线路控件,并将每个控件指向一个不同的线路设备。然后,您可以为每行Line1_OnConnected,Line2_Onconnected设置多个事件处理程序,或者更有效地创建自己的“ OnConnected”事件处理程序并将所有控件指向该事件处理程序,并使用控件或事件处理程序中的sender / object属性,以分析在哪一行触发了事件处理程序的控件。再次,该IVR示例页面上有一些开发环境的示例。

您可以使用上述公用程序之一来查询设备报告的“设备功能”。它会告诉您每条线路可以处理的呼叫数量,以及它支持的TAPI功能,例如保持呼叫,支持盲转,受监督的转接,会议等。如果每条线路呼叫不超过一个,那么您显然无法拨打其他电话。每条线路有2个呼叫,您可以将第一个呼叫置于保留状态(参考其呼叫句柄),然后拨打另一个呼叫,或者设置转接或会议(最少需要3个呼叫)。无论如何,除非您参加会议,否则您最多只能有几个通话,并且一次只能管理一个通话。每行使用一个控件,您可以有多个彼此完全独立的调用。希望能使您走得更远!