1 引 言
TAPI:“电话应用程序接口”的简称( Te lephONyApplicaTIon Programm ing Interface )。它是微软与INTEL共同开发的用于直接控制电话通信系统的函数集, 是微软计算机电话集成( CTI)计划的核心, 是微软的w indow s开放式服务体系(WOSA ) 的一部分。它将电话、电话网和计算机的功能进一步集成起来, 现在的计算机技术不仅可以处理语音通信等低级应用, 还能处理视频等高级应用。
计算机技术使得电话有软件化趋向, 其优势是使电话可以变得灵活, 方便地按具体要求实现电话的基本功能以及附加功能。软电话需要和通信硬件设备交互, 目前主要有两种实现方法: 一是利用电脑板卡和设备公司提供的DLL来实现, 但功能有一定的局限性; 二是利用协议公开的标准编程接口, 但难度大, 参数复杂不易实现。本设计利用标准编程接口TAPI, 为了便于系统的集成和开发, 重点介绍以统一短消息的形式实现应用系统和通信设备之间交互的TAPI模块化设计方法。该模块化组件与系统集成度高, 可以方便的实现各种电话与控制功能。
2 TAPI作用及结构分析
2. 1 TAPI在软电话系统中的作用
由于TAPI应用是电讯应用, 需要连接PC 电脑和通讯硬件设备, TAPI运行在PC 机上并监控通讯硬件设备, 所以首要任务是建立硬件环境。对于VO IP应用通信系统来说, 软交换服务器是IP电话网的控制核心, 同时落地接入PSTN (公共电话网) ,PC机与软交换服务器处于同一网段, TAPI与硬件交互也将通过网络使用TCP/ IP协议连接。本设计的开发平台是基于如下软交换系统, 系统如图1所示。
图1 软交换系统
与新硬件被安装到PC 机上相似, 需要在PC 机上安装驱动程序, 但这个驱动并不是软交换服务器的驱动, 而是这个软交换服务器上TAPI的驱动, 这个驱动通常被称为 “TAPI客户端”, 目的是使PC 机上的TAPIDLL能“ 找到”该软交换机的TAPI, 并能与之通讯。
2. 2 TAPI的结构分析
TAPI实际上是由TAPI、TSPI( Telephony Serv iceProv ider In terface) 电话服务提供者接口和MSPI(M edia Serv ice Prov ider Interface) 媒体服务提供接口三个部分组成的。TAPI是一个为程序员提供的工具包, 它和MSPI一起使微软视窗环境下的用户能够开发电话应用程序。TSPI也是一个为程序员提供的工具包, 使他们能够进行后端服务的开发, 以操纵来自符合TAPI规范的应用请求, 也就是说, 它提供了一种连接到某一特定设备的方法。服务守护程序( TAPI Server)就是基于TSPI接口设计的, 它直接驱动通信设备并通过与TAPI动态连接库进行交互为应用程序提供电话服务, 其总体结构示意图如图2所示。
图2 TAPI总体结构示意图
3 TAPI的模块化设计
本设计主要以C++ 类的设计思想, 在MFC (微软基础类) 的框架下实现对TAPI的封装。由于TAPI的函数调用非常复杂, 参数个数和形式多种多样, 为了便于系统集成和应用程序的开发, 设计了3个控制类: TAPI应用控制类Tap iApp lication、TAPI线路控制类Tap iLine、TAPI通话控制类Tap iChannel。Tap iApplication是对整个TAPI的监控, 是应用程序和通信设备的交互站; TapiL ine是对TAPI线路的管理, 它根据应用指令操作线路通话; Tap iChannel是对具体一路通话的管理, 它根据线路指令操作对应的通信设备并实时报告设备状态, 这3个类的调用关系如图3所示。
图3 TAPI调用结构
首先需要TAPI 的定义文件。由于TAPI 与W indow s集成, 定义文件在安装好W indow s操作系统后就可以被找到。以C 语言方式提供的TAPI. H和TAPI32. dll文件, 包含了所有TAPI结构和功能的定义。如果使用C、VC 或VB 开发应用, 只要在相关的开发环境中设置, 将文件引入所要开发的应用项目即可; 如果使用De lph i开发, 需要将TAPI. H转化为Delphi中的头文件, 再将这个pas文件引入即可; 如果使用Java开发, 需要TAPI的c lass文件。
该设计以VC 的MFC 为例对TAPI的功能进行模块化实现, 开发过程不需要通讯硬件的支持, 调试和运行需要与通讯硬件交互, 且该组件能很好的向上向下兼容。
3. 1 TAPI应用控制类设计
TapiA pplicat ion是对TAPI的管理, 它处于调用结构的顶层, 通过下层的服务为上层应用程序提供透明、规格化的信息服务。在通过TAPI进行远程通信程序设计时, 必不可少的是要调用lineIn itia lizeEx( )函数以初始化TAPI, 以及调用lineOpen( )函数以打开线路, 然后才能使用TAPI进行监控和代理呼叫等功能。除此之外, 为了编写可靠的远程通信程序, 还应调用有关检测线路设备能力的函数lineGetDevC aps( ) , 检测TAPI版本兼容性函数lineN egotiateAPIV ersion( ) , 检测线路当前使用状态的函数lineSetStatusM essages( )等以适应各种情况。最后调用liNEC lose( )函数来关闭线路, 调用lineShutdow n( )函数将应用程序与TAPI断开。
为了使TAPI便于操纵, 适应不同的应用开发环境, 本文设计了In itia liseTAPI( )这个不要参数的初始化函数, 把初始化和协商TAPI版本所需要的参数通过内联机制进行整合, 避免了过多的参数传递。初始化成功后表明应用程序已经获得TAPI的数据结构和应用句柄。为了便于对通信设备的控制, 需要和通信设备取得联系并打开通信线路。本文设计了OpenValidL ines( )这个不加参数的函数,只要成功返回后就可以对通信线路、通信设备进行控制了, 其函数声明如下:
class T apiApplicat ion
{
pub lic:
Tap iApp lication( CTap isamp leD lg&D lg) ;
~ T apiApplicat ion( );
/ / TAPI helper funct ions
BOOL InitialiseTAPI( ) ; / / Initialize TAPI
void ShutdownTAPI( ); / /C lose TAPI
void OpenV alidL ines ( ) ; / /Open the lines o fTAPI
/ / Variab les
CTapisamp leD lg&m_D lg;
HLINEAPP m_hLineApp; / / App lication handle
DWORD m_NumDevs; / / Number of dev ices
DWORD * m _ ApiV ersions; / / API versions
PTAPILINE* m_pL ines; / / Device variables
LONG m _Curren tL ine; / / currently se lected
ADDRARRAY m_AddressA rray;
};
TAPI初始化工作和有效线路的打开这些复杂的功能, 通过函数内置或全局变量传递, 整合成一个不要参数并且返回值为布尔类型的API函数。应用程序只要调用这两个函数就可以实现对TAPI设备的监控和操作。
3. 2 TAPI线路控制类设计
Tap iLine是对TAPI线路的管理, 为了使程序的结构更为清晰和易于升级以及为了使TAPI能够更方便的移植到别的应用程序中, 把TAPI函数中用于实现功能的一部分函数和数据结构封装成一个类来使用。下面就是通过V ISUALC + + 编程实现对TAPI线路控制函数封装类的头文件。
class T apiL ine {
private:
TapiA pplicat ion&m_m ainA pp; / / paren t object
DWORD m _LineID; / / My index
HLINE m _ hL ine; / / M y line hand le typedef
CL ist< Tap iChanne*l , Tap iChanne*l >
ExtensionLis;t m_extensionLis;t
/ / the list of call channe l
public:
TapiL ine( TapiApp licat ion&mainApp);
~ Tap iLine( ) ;
vo id OnEvent ( DWORD Device, DWORD Msg,
DWORD Param1, DWORD Param2, DWORD Param3);
HRESULT Open ( DWORD L ineID, DWORD
Ca llPr iv ilege, DWORD Med iaModes);
TapiChanne*l getChannel( DW dwAddressID);
TapiChanne*l getChanne lCall(HCALL hcall) ;
/ / Functions to support te lephony commands
BOOL M akeCa ll ( DWORD dwAddressID, LPCT??
STR pszA ddress) ;
vo id D ropCall( DWORD dwA ddressID) ;
vo idHo ldCall( DWORD dwA ddressID) ;
vo id UnholdC all( DWORD dwAddressID) ;
vo id B lindT ransferCa ll ( DWORD dwAddressID,
LPCTSTR pszAddress) ;
vo id R edirect ( DWORD dwAddressID, LPCTSTR
pszAddress) ;
vo id Ca llStatus( DWORD dwAddressID );
vo id Ca llInfo( DWORD dwA ddressID) ;
vo id Addressstatus( ) ;
};
TapiL ine通过复杂的参数传递机制, 封装了大量的内部变量, 通过API接口以统一短消息的形式接收用户指令同时返回线路的具体状态。最终应用程序通过调用Tap iL ine的具体函数对整个线路进行操作、控制。
3. 3 TAPI通话控制类设计
TapiChanne l是对具体通话进行控制, 呼叫是TAPI开发最常用的一个功能。调用Tap iL ine 的M akeC all ( DWORD dwAddressID, LPCTSTR pszAddress) , 传递当前号码和目标地址就可以进行拨打电话, 把拨打电话的其他细节进行内部传递。当以上函数调用成功后, TSP 就会控制通讯设备外呼指定的电话, 该函数调用后会立刻返回到应用程序, 但该电话是否成功拨通, 则是依靠消息来判断, 包括TAPI的其他功能也是这样的处理方式。其他常用的电话功能如接听、挂断、转移、三方等都有对应的函数实现。
TAPI初始化成功后, 应用程序就和TSP设备建立了联系。应用程序就可以通过TAPI函数控制电话线路、监控线路状态。函数lineOpen调用成功后进入消息循环, 新生成的呼叫处于IDLE 状态, 随后根据状态指令执行不同的操作。当调用lineM akeC all( )后, 线路状态进入D IAL ING、PROCEDING, 当收到异步响应或者应答后进入呼叫状态循环并依次进入CONNECTED和DISCONNECTED, 最后回到初始化状态。当有一路电话呼入时, 线路状态进入OFFER ING、自动调用lineAnsw er( )后进入ACCEPTED、PROCED ING, 当收到异步响应或者应答后进入呼叫状态循环并依次进入CONNECTED和D ISCONNECTED, 最后回到初始化状态, 整个TAPI状态图如图4所示。
图4 TAPI状态机。
3. 4 TAPI的消息处理
line ln itia lizeEx函数中第3个参数传入的参数是方法的地址, 这个方法将处理通讯设备发出来的所有TAPI消息, 这个方法必须按固定的格式定义:
vo id CALLBACK Tap iLineCa llback(
DWORD dwDev ice,
DWORD nM sg,
DWORD dw Instance,
DWORD dwParam1,
DWORD dwParam2,
DWORD dwParam3)
方法名TapiL ineC allback, 可以自己定义, 只要将此函数名作为参数传入linelnitializeEx, 该方法就可以工作, 方法参数将由通讯设备的TSP 来填写,并传给上层应用。关键是要了解在某时刻触发此方法后, 各参数值的意义以及此时收到此消息所表示的意义。要注意的是: 即使完成一个最简单的通话,都会得到许多TAPI消息, 这些消息以时间顺序产生, 每产生一个消息, 就会进入Tap iL ineCallback方法中, 所以要抓住并处理关键消息。
以收到来电为例, 主要处理2个消息。
( 1) 参数dwMsg = LINE _ CALLSTATE 并且dwParam:l LINECALLST _OFFER ING。此时可以把表示该来电的hDev ice保存到应用中, 以便随后的处理。
( 2)参数dwMsg= LINE _CALLINFO。此时通过TAPI函数lineG etCa lllnfo 可以得到来电信息, 例如来电主叫号码、被叫号码等。当收到来电消息后, 就可以在界面上切换应用状态以通知用户, 或记录数据库等, 按需要进行处理。与来电消息类似, 当有其他电话事件发生后, 就会发生相应的消息。
4 结束语
虽然TAPI产品化的应用不多, 但其提供的功能却是强大的。TAPI主要用来控制通讯设备, 在这个基础上再实现更多的功能。曾经也有人用来实现控制家用普通Mode;l 如果用于控制交换机, 可以实现对来电排队等高级功能; 也可以建立企业呼叫中心。
研究了TAPI的工作流程, 及TAPI功能模块的实现, 并对其函数进行了封装设计处理。介绍了使用TAPI编写电话控制程序的完整步骤, 对TAPI在软电话应用系统中的二次开发奠定了基础。