实例428 语音卡电话呼叫系统

实例说明

随着科学技术的不断发展,语音卡被广泛地应用于商业软件中。本例实现了利用语音卡实现电话呼叫的功能。实例运行结果如图13.12所示。

文本框:图13.12  语音卡电话呼叫系统技术要点

本例采用东进公司开发的8路模拟语音卡,该卡采用灵活的模式化设计,可按需配置外线、内线两种模块。该语音卡可实现坐席、会议、FSK数据收发、语音合成等多种功能,并提供SDK开发工具包。

在安装完驱动程序后,相应的动态链接库(NewSig.dll和Tc08a32.dll文件)会复制到Windows的系统目录下。在语音卡的开发过程中,主要通过调用NewSig.dll和Tc08a32.dll来实现相应的功能。下面介绍这两个动态库中的主要使用函数。

(1)LoadDRV函数

该函数用于加载动态链接库。语法如下:

        [DllImport("Tc08a32.dll", CharSet = CharSet.Auto)]

        public static extern long LoadDRV();

返回值:返回值为0表示成功;?1表示打开设备驱动程序错误。?2表示在读取TC08A-V.INI文件时发生错误;?3表示INI文件的设置与实际的硬件不一致时发生错误。

(2)FreeDRV函数

该函数用于关闭驱动程序。语法如下:

        [DllImport("Tc08a32.dll", CharSet = CharSet.Auto)]

        public static extern long EnableCard(short wusedCh, short wFileBufLen);

(3)EnableCard函数

该函数用于初始化语音卡硬件,并为每个通道分配语音缓冲区。语法如下:

        [DllImport("Tc08a32.dll", CharSet = CharSet.Auto)]

        public static extern long EnableCard(short wusedCh, short wFileBufLen);

参数说明如下。

l     wUsedCh:标识通道数量。

l     WFileBufLen:标识分配的缓冲区大小。

(4)CheckValidCh函数

该函数检测在当前机器内可用的通道总数。语法如下:

        [DllImport("Tc08a32.dll", CharSet = CharSet.Auto)]

        public static extern short CheckValidCh();

l     返回值:通道总数量。

(5)CheckChType函数

该函数用于测试某个通道的类型。语法如下:

        [DllImport("Tc08a32.dll", CharSet = CharSet.Auto)]

        public static extern short CheckChType(short wChnlNo);

参数说明如下。

l     wChnlNo:标识通道号。

l     返回值:为0表示内线;为1表示外线;为2表示悬空。

(6)PUSH_PLAY函数

该函数用于维持文件录放音的持续进行,需在处理函数的大循环中调用。语法如下:

        [DllImport("Tc08a32.dll", CharSet = CharSet.Auto)]

        public static extern void PUSH_PLAY();

(7)SetBusyPara函数

该函数用于设置要检测的挂机忙音的参数。语法如下:

        [DllImport("Tc08a32.dll", CharSet = CharSet.Auto)]

        public static extern void SetBusyPara(short BusyLen);

参数说明:

l     BusyLen:标识忙音的时间长度,单位为毫秒。

(8)RingDetect函数

该函数用于测试外线是否振铃或内线是否提机。语法如下:

       [DllImport("Tc08a32.dll", CharSet = CharSet.Auto)]

        public static extern bool RingDetect(short wChnlNo);

参数说明如下。

l     wChnlNo:标识通道号。

返回值:如果为1,对于外线表示有振铃信息;对于内线,表示提机。如果为0,对于外线,表示无振铃信息;对于内线,表示挂机。

(9)OffHook函数

该函数用于外线提机。对于内线,不起作用。语法如下:

        [DllImport("Tc08a32.dll", CharSet = CharSet.Auto)]

        public static extern void OffHook(short wChnlNo);

参数说明如下。

l     wChnlNo:标识外线通道。

(10)HangUp函数

该函数用于外线挂机。对于内线,不起作用。语法如下:

        [DllImport("Tc08a32.dll", CharSet = CharSet.Auto)]

        public static extern void HangUp(short wChnlNo);

参数说明如下。

l     wChnlNo:标识外线通道。

(11)Sig_Init函数

该函数用于完成信号音检测的初始化工作。语法如下:

        [DllImport("NewSig.dll", CharSet = CharSet.Auto)]

        public static extern void Sig_Init(int Times);

参数说明如下。

l     wPara:缺省值为0,不起作用。

(12)Sig_CheckBusy函数

清空忙音检测的缓冲区以及内部计数。当检测对方挂机的忙音后,必须调用本函数。语法如下:

        [DllImport("NewSig.DLL", CharSet = CharSet.Auto)]

        public static extern void Sig_ResetCheck(short wChlNo);

参数说明如下。

l     wChNo:标识通道号。

l     返回值:为1表示检测到忙音;为0,表示没有检测到忙音。

(13)Sig_ResetCheck函数

该函数用于清空忙音检测的缓冲区以及内部计数。当检测对方挂机的忙音后,必须调用本函数。语法如下:

        [DllImport("NewSig.DLL", CharSet = CharSet.Auto)]

        public static extern void Sig_ResetCheck(short wChlNo);

参数说明如下。

l     wChNo:标识通道号。

(14)Sig_StartDial函数

该函数用于拨打电话号码。开始某通道的呼出过程。该函数只是设置通道的呼出缓冲区,真正的呼出过程需要循环调用Sig_CheckDial函数来逐步完成。语法如下:

        [DllImport("NewSig.dll", CharSet = CharSet.Auto)]

        public static extern int Sig_StartDial(short wChNo, [MarshalAs(UnmanagedType.LPArray)] byte[] DialNum, [MarshalAs(UnmanagedType.LPArray)] byte[] PreDialNum, short wMode);

参数说明如下。

l     wChNo:标识通道号。

l     DialNum:标识呼出号码。

l     PreDialNum:标识前导号码。

l     wMode:呼出检测的模式。

(15)Sig_CheckDial函数

该函数用于检测呼出结果。

在调用函数Sig_StartDial启动拨号过程后,就可以循环调用Sig_CheckDial函数维持拨号过程,并检测呼出的结果,直至得到结果为止。

拨号的一般过程如下。

1.如果参数PreDialNum不为空,则延迟1秒后拨出PreDialNum,如果参数PreDialNum为空,则直接进入步骤3。

2.检测PreDialNum是否已发完。如已发完转至步骤3。

3.检测是否有拨号音,如拨号音长度达到配置项DialToneAfterOffHook的数值,则发送DialNum码串,并转至步骤4。如在此步骤已等待配置项NoDialToneAfterOffHook定义的时间长度仍未检测到拨号音,则返回0x10。

4.检测DialNum码串是否发完,如已发完则延迟StartDelay配置项的时间长度后进入步骤5。

5.如果从进入此步骤起已经过配置项RingLen定义的时间长度,拨号音仍未停止则返回0x10;如果在此步骤已等待配置项NoRingLen定义的时间长度仍未检测到回铃音则返回0x10;如果检测到占线忙音数达到配置项BusySigCount定义的数字,则返回0x21;如果检测到对方摘机,则返回0x14;如果进入此步骤已经过配置项Ringback_NoAnswerTime定义的时间长度,并且已检测到回铃音,则返回0x13;其他情况返回0x10。

注意:在进行呼出结果检测之前必须调用函数StartSigCheck启动信号音采集过程,并且在进行呼出结果检测时,要循环调用FeedSigFunc函数维持信号音采集过程。

语法如下:

        [DllImport("NewSig.dll", CharSet = CharSet.Auto)]

        public static extern int Sig_CheckDial(short wChNo);

参数说明如下。

l     wChNo:标识通道号。

l     返回值包括以下几种情况。

l     16(0x10):尚未得出结果。

l     15(0x0F):没有拨号音。

l     33(0x21):检测到对方占线的忙音。

l     20(0x14):对方摘机,可以进行通话。

l     19(0x13):振铃若干次,无人接听电话。

l     21(0x15):没有信号音。

注意:关于语音卡其他函数语法请参见光盘中的本实例文件D161A.CS,该文件给出大部分语音卡的函数语法。

实现过程

(1)新建一个项目,命名为Ex13_11,默认窗体为Form1。

(2)在Form1窗体中,主要添加两个Button控件,用于执行电话拨号和电话挂机,添加一个DataGridView控件,显示语音卡各通道及通道状态,添加Timer组件实现电话的呼出过程,添加一个TextBox控件,用于输入呼出电话号码。

(3)主要程序代码。

在窗体装载事件中,主要进行初始化语音卡驱动程序,并且检测通道总数及状态,为每一条通道分配语音缓冲区。代码如下:

        private void Form1_Load(object sender, EventArgs e)

        {

            //初始化驱动程序

            long load = DJ160API.LoadDRV();

            //检测通道总数,并为每个通道分配语音缓冲区

            short wuseCh = DJ160API.CheckValidCh();

            short wFileBufLen = 16 * 1024;

            long card = DJ160API.EnableCard(wuseCh, wFileBufLen);

            //设置表格通道的行数

            dataGridView1.RowCount = wuseCh;

            //检测每个通道类型

            short chanelTpye = 0; //定义通道类型变量

            string strType = "";

            for (short i = 0; i < wuseCh; i++)

            {

                chanelTpye = DJ160API.CheckChType(i);

                dataGridView1[0, i].Value = i;

                switch (chanelTpye)

                {

                    case 0:

                        strType = "内线";

                         break;

                    case 1:

                        strType = "外线";

                        break;

                    case 2:

                        strType = "悬空";

                        break;

                }

                dataGridView1[1, i].Value = strType;

                dataGridView1[2, i].Value = "空闲";

            }

        }

在DataGridView控件中选择一个外线空闲通道,单击【拨号】按钮,进行电话拨号,并且将拨号过程中的状态显示在相应的DataGirdView表格中。代码如下:

        private void button1_Click(object sender, EventArgs e)

        {

            short wuseCh = DJ160API.CheckValidCh();

            short wFileBufLen = 16 * 1024;

            long card = DJ160API.EnableCard(wuseCh, wFileBufLen);

            DJ160API.Sig_Init(chanel);

            //检查(外线)是否有振铃信号或(内线)是否有提机

             bool ring = DJ160API.RingDetect(chanel);

            //外线提机

            DJ160API.OffHook(chanel);

            byte[] ss =new byte[textBox1.Text.Length];

            byte[] s ={ 0 };

            for (int i = 0; i < textBox1.Text.Length; i++)

            {

                ss[i] = Convert.ToByte(textBox1.Text.Substring(i, 1));

            }

            DJ160API.Sig_StartDial(chanel, ss, s, 0);

            timer1.Enabled = true;

            dataGridView1[2, chanel].Value = "拨号中...";

            dataGridView1[3, chanel].Value = textBox1.Text;

        }

单击【挂机】按钮,实现电话挂机功能。代码如下:

        private void button2_Click(object sender, EventArgs e)

        {

            DJ160API.HangUp(chanel);

            DJ160API.Sig_ResetCheck(chanel);

            DJ160API.StartSigCheck(chanel);

            timer1.Enabled = false;

            dataGridView1[2, chanel].Value = "空闲";

            dataGridView1[3, chanel].Value = "";

        }

Sig_StartDial函数用于拨打电话号码。开始某通道的呼出过程。该函数只是设置通道的呼出缓冲区,真正的呼出过程需循环调用Sig_CheckDial函数来逐步完成。代码如下:

        private void timer1_Tick(object sender, EventArgs e)

        {

            DJ160API.Sig_CheckDial(chanel);

        }

单击DataGridView控件的相应行记录相应的通道号,代码如下:

   private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)

        {

             chanel = (short)e.RowIndex;

        }

举一反三

根据本实例,读者可以开发以下程序。

* 实现电话自助服务系统。

* 实现电话自动报警系统。