呼叫中心(CallCenter)开发应用系列(4)

接下来是最关键的对象登场了:语音控制核心线程!

 

using System; using System.Collections.Generic; using System.Text; using CC.QJ.Tools; using System.Threading; using CC.DJ081A.Lib; using System.Collections; using CC.QJSocket.Server; using System.Net.Sockets; using System.Configuration; namespace CallCenterApp { public class CallThread : MainThread { public SocketListener _socketListener; public CardHelper.refreshlv _RefreshLv; int chn; Trunk[] _channel; private static readonly string recordpaht = ConfigurationManager.AppSettings["recordpath"]; public CallThread(Trunk[] ichannel,int ichn) { chn = ichn; _channel = ichannel; } public override void run() { do { base.run(); MainEvent(); Thread.Sleep(50); } while (isStart); } private void MainEvent() { Tc08a32.PUSH_PLAY(); Tc08a32.FeedSigFunc(); for (int i = 0; i < chn; i++) { _RefreshLv(_channel[i]); if (_channel[i].chnstatus == CHN_STATUS.LINE_INIT) { ResetChannel(i); } else { if (_channel[i].chntype == CHN_TYPE.CHTYPE_TRUNK) { if (Tc08a32.Sig_CheckBusy(i) == 1) //监测到忙音 { if (_channel[i].connchn != -1) Tc08a32.StartPlaySignal(_channel[i].connchn, 2); ////给与外线相连的内线忙音 ResetChannel(i); } } if (_channel[i].chntype == CHN_TYPE.CHTYPE_USER) { if (!Tc08a32.OffHookDetect(i) && _channel[i].chnstatus != CHN_STATUS.LINE_IDLE && _channel[i].busyflag == false) ResetChannel(i); } } DoWork(i); } } private void ResetChannel(int ichn) { Tc08a32.StopPlayFile(ichn); Tc08a32.StartPlaySignal(ichn, (int)SingleVType.SIG_STOP); _channel[ichn].callee = string.Empty; _channel[ichn].caller = string.Empty; _channel[ichn].calltime = string.Empty; _channel[ichn].chn = ichn; _channel[ichn].connchn = -1; _channel[ichn].filename = null; _channel[ichn].dtmflength = 0; _channel[ichn].dtmf = string.Empty; _channel[ichn].play_count = 0; _channel[ichn].workflag = false; _channel[ichn].busyflag = false; _channel[ichn].eventtype = -1; _channel[ichn].dispstatus = CardHelper.GetDescByStatus(CHN_STATUS.LINE_IDLE); _channel[ichn].chnstatus = CHN_STATUS.LINE_IDLE; if (_channel[ichn].chntype == CHN_TYPE.CHTYPE_TRUNK) { _myLog(LogFile.Trace, "重置外线通道属性,通道号" + ichn.ToString()); Tc08a32.HangUp(ichn); Tc08a32.InitDtmfBuf(ichn); Tc08a32.ResetCallerIDBuffer(ichn); } if (_channel[ichn].chntype == CHN_TYPE.CHTYPE_USER) { _myLog(LogFile.Trace, "重置内线通道属性,通道号" + ichn.ToString()); Tc08a32.FeedPower(ichn); } } //核心线程 private void DoWork(int i) { switch (_channel[i].chnstatus) { case CHN_STATUS.LINE_IDLE: { if (Tc08a32.RingDetect(i)) //检测外线振铃,或者内线是否摘机 { _channel[i].busyflag = true; if (_channel[i].chntype == CHN_TYPE.CHTYPE_TRUNK) { _channel[i].dispstatus = "外线用户振铃"; byte[] IDStr = new byte[128]; /* int callerId = Tc08a32.GetCallerIDStr(i, IDStr); if (callerId == 3 || callerId == 4) { Tc08a32.OffHook(i); //外线摘机 Tc08a32.StartSigCheck(i); string caller = Encoding.UTF8.GetString(IDStr); _channel[i].caller = caller; _myLog(LogFile.Trace, "接收的主叫号码:" + caller); _channel[i].chnstatus = CHN_STATUS.LINE_WELCOME; }*/ Tc08a32.OffHook(i); //外线摘机 Tc08a32.StartSigCheck(i); _channel[i].chnstatus = CHN_STATUS.LINE_WELCOME; } /* if (_channel[i].chntype == CHN_TYPE.CHTYPE_USER) { Tc08a32.StartHangUpDetect(i); Tc08a32.StartPlaySignal(i, (int)SingleVType.SIG_DIALTONE); _channel[i].dispstatus = "内线用户振铃"; _channel[i].chnstatus = CHN_STATUS.LINE_GET_DTMF; //内线收DTMF }*/ } } break; case CHN_STATUS.LINE_WELCOME: { Tc08a32.InitDtmfBuf(i); //清空接收DTMF的缓冲区 _channel[i].dtmflength = 0; _channel[i].dispstatus = "对外线用户播放提示音..."; StringBuilder filename = new StringBuilder("voc//1.pcm"); _channel[i].filename = filename; Tc08a32.StartPlayFile(i, filename, 1); _myLog(LogFile.Trace, "播放提示音:" + filename); _channel[i].play_count = 1; Tc08a32.StartSigCheck(i); Tc08a32.StartTimer(i, pubparam.TIMER_NO); //通道启动计时器 _channel[i].chnstatus = CHN_STATUS.LINE_WELCOME1; filename = null; } break; case CHN_STATUS.LINE_WELCOME1: { int check2 = Tc08a32.ReadCheckResult(i, 1); if (check2 == 0x21) { _myLog(LogFile.Trace, "播放欢迎词时,检测到外线挂机"); _channel[i].chnstatus = CHN_STATUS.LINE_WAIT_HANGUP; break; } int b = -1; b = Tc08a32.GetDtmfCode(i); if (b < 0 || b > 16) { if (Tc08a32.CheckPlayEnd(i) == 1) //放音结束 { if (_channel[i].play_count < 2) { _channel[i].play_count++; Tc08a32.StartPlayFile(i, _channel[i].filename, 0); _myLog(LogFile.Trace, "播放提示音:" + _channel[i].filename); } else { _channel[i].chnstatus = CHN_STATUS.LINE_WAIT_HANGUP; } } break; } else { _myLog(LogFile.Trace, "播放欢迎词检测到其他按键,dtmf=:" + b.ToString()+"chn ="+i.ToString()); Tc08a32.StopPlayFile(i); Tc08a32.StartPlaySignal(i, (int)SingleVType.SIG_STOP); if (_channel[i].chntype == CHN_TYPE.CHTYPE_USER) { _channel[i].dispstatus = "内线收DTMF号码..."; } if (_channel[i].chntype == CHN_TYPE.CHTYPE_TRUNK) { _channel[i].dispstatus = "接收外线DTMF按键..."; switch (b) { case 12: //#号键,返回主菜单: { _channel[i].chnstatus = CHN_STATUS.LINE_WELCOME; break; } case 1: //播放水厂地址 { _channel[i].dispstatus = "对外播放水厂地址信息..."; StringBuilder filename = new StringBuilder("voc//9.pcm"); _myLog(LogFile.Trace, "播放水厂地址:" + filename); _channel[i].filename = filename; Tc08a32.StartPlayFile(i, filename, 0); _channel[i].play_count = 1; _channel[i].eventtype = 1; Tc08a32.StartTimer(i, pubparam.TIMER_NO); //通道启动计时器 _channel[i].chnstatus = CHN_STATUS.LINE_PLAY_ONLY; } break; case 2: { StringBuilder filename = new StringBuilder("voc//10.pcm"); _channel[i].filename = filename; Tc08a32.StartPlayFile(i, filename, 0); _channel[i].play_count = 1; _channel[i].eventtype = 2; _channel[i].chnstatus = CHN_STATUS.LINE_SELECT; } break; case 3: //播放水质监测中心电话:85723236多文件拼接播放方式 { StringBuilder filename = new StringBuilder("voc//6.pcm"); //播放整个文件 _channel[i].filename = filename; Tc08a32.StartPlayFile(i, filename, 0); _channel[i].play_count = 1; _channel[i].eventtype = 3; _channel[i].chnstatus = CHN_STATUS.LINE_PLAY_ONLY; } break; case 4: //播报停水通知文件 { object f = CardHelper.GetFileNameByDb(1); StringBuilder sb = new StringBuilder(); if (f == null) { sb.Append("voc//8.pcm"); //您好,没有停水通知 } else { string filepah = recordpaht + f.ToString(); bool bexsit = CardHelper.fileExist(filepah, recordpaht); if (bexsit) { sb.Append(filepah); //播放停水通知文件 } else { sb.Append("voc//8.pcm"); //您好,没有停水通知 } } _channel[i].filename = sb; Tc08a32.StartPlayFile(i, sb, 0); _channel[i].play_count = 1; _channel[i].eventtype = 9; _channel[i].chnstatus = CHN_STATUS.LINE_PLAY_ONLY; } break; case 9: //告知客户端为咨询 { Tc08a32.StopPlayFile(i); _channel[i].eventtype = 3; _channel[i].chnstatus = CHN_STATUS.LINE_CHECK_IDLE; } break; case 10: //0号键:转坐席://告知客户端为受理 { Tc08a32.StopPlayFile(i); _channel[i].eventtype = 4; _channel[i].chnstatus = CHN_STATUS.LINE_CHECK_IDLE; } break; default: { StringBuilder filename = new StringBuilder("voc//7.pcm"); //选择了其他按键 _channel[i].filename = filename; Tc08a32.StartPlayFile(i, filename, 0); _channel[i].play_count = 1; _channel[i].chnstatus = CHN_STATUS.LINE_OTHER_KEY; } break; } } } break; } case CHN_STATUS.LINE_SELECT: //第二集菜单的选择 { if (Tc08a32.Sig_CheckBusy(i) == 1) { Tc08a32.HangUp(i); _channel[i].chnstatus = CHN_STATUS.LINE_INIT; break; } int b = Tc08a32.GetDtmfCode(i); if (b < 0 || b > 16) { if (Tc08a32.CheckPlayEnd(i) == 1) //放音结束 { if (_channel[i].play_count < 2) { _channel[i].play_count++; Tc08a32.StartPlayFile(i, _channel[i].filename, 0); break; } else { _channel[i].chnstatus = CHN_STATUS.LINE_WAIT_HANGUP; } } } else { Tc08a32.StopPlayFile(i); Tc08a32.StartPlaySignal(i, (int)SingleVType.SIG_STOP); switch (b) { case 1: //非节假日 4 { StringBuilder filename = new StringBuilder("voc//4.pcm"); _channel[i].filename = filename; Tc08a32.StartPlayFile(i, filename, 0); _channel[i].play_count = 1; _channel[i].chnstatus = CHN_STATUS.LINE_PLAY_ONLY; } break; case 2: //节假日 5 { StringBuilder filename = new StringBuilder("voc//5.pcm"); _channel[i].filename = filename; Tc08a32.StartPlayFile(i, filename, 0); _channel[i].play_count = 1; _channel[i].chnstatus = CHN_STATUS.LINE_PLAY_ONLY; } break; case 12: //#号键,返回主菜单: { _channel[i].chnstatus = CHN_STATUS.LINE_WELCOME; } break; default: { StringBuilder filename = new StringBuilder("voc//7.pcm"); //选择了其他按键 _channel[i].filename = filename; Tc08a32.StartPlayFile(i, filename, 0); _channel[i].play_count = 1; _channel[i].chnstatus = CHN_STATUS.LINE_OTHER_KEY; } break; } } } break; case CHN_STATUS.LINE_PLAY_ONLY: //播放水厂地址,播放水质电话 if (Tc08a32.CheckPlayEnd(i) == 1) { if (_channel[i].play_count < 2) { _channel[i].play_count++; Tc08a32.StartPlayFile(i, _channel[i].filename, 0); break; } else { _channel[i].chnstatus = CHN_STATUS.LINE_WAIT_HANGUP; } } break; case CHN_STATUS.LINE_OTHER_KEY: //其他按键. { if (Tc08a32.CheckPlayEnd(i) == 1) { if (_channel[i].play_count < 2) { _channel[i].play_count++; Tc08a32.StartPlayFile(i, _channel[i].filename, 0); _channel[i].chnstatus = CHN_STATUS.LINE_WELCOME1; break; } else { _channel[i].chnstatus = CHN_STATUS.LINE_WAIT_HANGUP; } } } break; case CHN_STATUS.LINE_CHECK_IDLE: //检测是否有空闲坐席 { int userchn = GetIdleUserChn(); if (userchn < 0) //提示坐席忙请等待. { StringBuilder filename = new StringBuilder("voc//11.pcm"); //对不起,坐席全忙. _channel[i].filename = filename; Tc08a32.StartPlayFile(i, filename, 0); _channel[i].play_count = 1; _channel[i].chnstatus = CHN_STATUS.LINE_CHECK_IDLE; } else //连通坐席人员... { _channel[i].connchn = userchn; _channel[userchn].connchn = i; _channel[userchn].busyflag = true; //将该通道占用。 Tc08a32.StartPlaySignal(i,(int)SingleVType.SIG_RINGBACK); Tc08a32.FeedRealRing(userchn); //对某一路内线通道馈断续的铃流 _channel[i].chnstatus = CHN_STATUS.LINE_LINK_USER; _channel[userchn].chnstatus = CHN_STATUS.LINE_LINK_USER; } } break; case CHN_STATUS.LINE_LINK_USER: //连通坐席 { if (Tc08a32.OffHookDetect(_channel[i].connchn)) //检测外线振铃,或者内线是否摘机 { //再处理相应的状态.... Tc08a32.StartPlaySignal(i, (int)SingleVType.SIG_STOP); Tc08a32.FeedPower(_channel[i].connchn); _channel[i].dispstatus = "内线用户摘机"; Tc08a32.StopPlayFile(_channel[i].connchn); int k = Tc08a32.SetLink( _channel[i].connchn,i); Tc08a32.StartHangUpDetect(_channel[i].connchn); //开始挂机检测 Tc08a32.InitDtmfBuf(_channel[i].connchn); //如果不初始化,则无法收到按键... _channel[i].chnstatus = CHN_STATUS.LINE_LINK_CONNECT; _channel[_channel[i].connchn].chnstatus = CHN_STATUS.LINE_LINK_CONNECT; Tc08a32.StartSigCheck(_channel[i].connchn); Tc08a32.StartSigCheck(i); //发送消息到客户端:::::://eventtype 有具体的定义 ... string caller = "12345678"; SendMessageToClient(caller, _channel[i].connchn, _channel[i].eventtype); } } break; //case CHN_STATUS.LINE_RECORDING: case CHN_STATUS.LINE_LINK_CONNECT: { _channel[i].dispstatus = "话路联通"; //内线挂机 int check = Tc08a32.HangUpDetect(i); if (check == 1) { _myLog(LogFile.Trace, "话路通,内线挂机.." + i.ToString()); } //联通过程中,任何一方挂机。(检测不到内线挂机???) int check2 = Tc08a32.ReadCheckResult(i, 1); if (check2 == 0x21) { _myLog(LogFile.Trace, "话路通,外线挂机.." + i.ToString()); } if(check2 == 0x21 || check == 1) { _myLog(LogFile.Trace, "停止可能的录音,开始挂机流程.." + i.ToString()); Tc08a32.StopRecordFile(i); _channel[i].chnstatus = CHN_STATUS.LINE_WAIT_HANGUP; //将另一方挂断. if (_channel[i].connchn >= 0 && _channel[_channel[i].connchn].chnstatus != CHN_STATUS.LINE_IDLE) { Tc08a32.HangUp(_channel[i].connchn); _channel[_channel[i].connchn].chnstatus = CHN_STATUS.LINE_INIT; } } if (_channel[i].chntype == CHN_TYPE.CHTYPE_TRUNK) { break; } //下列是内线处理。。。。。。。。 int b = Tc08a32.GetDtmfCode(i); if (b == 11) //是否需要开始录音 * { _channel[_channel[i].connchn].dispstatus = "话路录音"; bool f = Tc08a32.StartRecordFile(_channel[i].connchn, Encoding.UTF8.GetBytes(CardHelper.GetFileName()), 36000 * 100); _myLog(LogFile.Trace, "对外线通道录音,通道号:" + _channel[i].connchn.ToString()); } if (b == 12) //#号键:坐席挂机、对外线放音(外线暂时不能挂) { _myLog(LogFile.Trace, "接收到#,通道号:" + _channel[i].connchn.ToString()); //检测socket消息队列........... Tc08a32.StopRecordFile(i); if (_channel[i].chntype == CHN_TYPE.CHTYPE_USER) { _myLog(LogFile.Trace, "准备内线挂机,并对外线放音,通道号:" + _channel[i].connchn.ToString()); _channel[i].chnstatus = CHN_STATUS.LINE_WAIT_HANGUP; //准备接收Socket通讯,开始对外放音... } } } break; case CHN_STATUS.LINE_WAIT_HANGUP: { Tc08a32.HangUp(i); _channel[i].chnstatus = CHN_STATUS.LINE_INIT; } break; case CHN_STATUS.LINE_PLAY_RECORD: if (Tc08a32.CheckIndexPlayFile(i) == 1) { if (_channel[i].play_count < 2) { _channel[i].play_count++; Tc08a32.StartIndexPlayFile(i); break; } else { Tc08a32.StopIndexPlayFile(i); _channel[i].chnstatus = CHN_STATUS.LINE_WAIT_HANGUP; } } break; default: break; } } //来自socket客户端的消息... public void listener_CbMessage(string ip, string message) { _myLog(LogFile.Trace, "回调到语音卡线程,IP:" + ip + " 信息:" + message); //对收到的数据进行解析,然后做相应的处理. if (message == string.Empty) { _myLog(LogFile.Trace, "内容为空!为什么?"); return; } string[] sip = ip.Split(':'); string[] data = message.Split('|'); if (data == null || data.Length < 2) { _myLog(LogFile.Trace, "内容不全,什么意思?"); return; } int ifunc = int.Parse(data[0]); switch (ifunc) { case -1: //注销 { _myLog(LogFile.Trace, "坐席离开!"); } break; case 1: //坐席注册 { if (data[1].ToString() != "hello qianjia") { _myLog(LogFile.Trace, "注册信息不正确!"); } else { //注册 CardHelper.ChangerRegStatusOfInner(sip[0], 1); _myLog(LogFile.Trace, "坐席注册信息成功,IP:" + sip[0]); } } break; case 2: //对外线放音电话号码 { int ichn = CardHelper.GetChnByIp(sip[0]); //内线通道 if (ichn < 0) { _myLog(LogFile.Trace, "没有该IP对应的通道号,IP:" + sip[0]); } else { int outichn = _channel[ichn].connchn; //外线通道 if (outichn > -1) { string telephone = data[1]; string[] files = CardHelper.GetFileNameByTelephone(telephone); if (files == null) { _myLog(LogFile.Trace, "无法获取语音文件,可能是传入的号码有误,原文:" + telephone); break; } else { Tc08a32.StopPlayFile(outichn); Tc08a32.RsetIndexPlayFile(outichn); foreach (string s in files) { Tc08a32.AddIndexPlayFile(outichn, new StringBuilder(s)); } Tc08a32.StartIndexPlayFile(outichn); _channel[outichn].play_count = 1; _channel[ichn].chnstatus = CHN_STATUS.LINE_WAIT_HANGUP; _channel[outichn].chnstatus = CHN_STATUS.LINE_PLAY_RECORD; } } else { _myLog(LogFile.Trace, "没有对应的连接通道!"); } } } break; default: _myLog(LogFile.Trace, "未知功能按键!"); break; } } /// <summary> /// 根据业务流程给对应的客户端发送消息 /// </summary> /// <param name="message"></param> /// <param name="ichn"></param> private void SendMessageToClient(string message,int ichn,int eventtype) { if (_socketListener.Connection == null) { _myLog(LogFile.Error, "socket的监听不为空!"); return; } string senders = string.Empty; foreach (configObject obj in pubvar.configlist) { if(ichn == obj.ClinetLine && obj.ClientStatus == 1) //==1 表示已经注册信息 { senders = obj.ClinetIP; break; } } if (senders == string.Empty) { _myLog(LogFile.Error, "没有对应的socket客户端,无法发送消息!"); return; } foreach (DictionaryEntry socket in _socketListener.Connection) { string[] sip = socket.Key.ToString().Split(':'); if (senders == sip[0]) { string temp = eventtype.ToString()+"|"+ message ; byte[] bs = Encoding.UTF8.GetBytes(temp); if (((Connection)(socket.Value))._connection != null) { ((Connection)(socket.Value))._connection.Send(bs, bs.Length, 0); _myLog(LogFile.Trace, "发送消息到对应的客户端:" + senders + " 消息内容:" + temp); bs = null; } break; } } } private int GetIdleUserChn() { int userchn = -1; for (int j = 0; j < chn; j++) { if (_channel[j].chntype == CHN_TYPE.CHTYPE_USER && _channel[j].chnstatus == CHN_STATUS.LINE_IDLE) { userchn = j; _myLog(LogFile.Trace, "获取一个空闲通道.通道号:." + j.ToString()); break; } } return userchn; } } }

你可能感兴趣的:(socket,String,user,null,byte,电话)