设计简介:
1、 设计思路请参考本站Blog的另一篇文章:“Delphi之东进模拟语音卡(D160A)可复用源码”; 2、 其实,仔细对比,你会发现这两种卡的代码类方法签名几乎99%是一样的,也就是说,这两都之间,还需要更进一步的抽象,以解决“重复代码”或者“相似代码”的问题。
3、 更高层次的抽象,请参考我的设计文档。
4、 类图(以后补上):
5、 卡类源码:
//------------------------------------------------------------------------------ // // 产品名称: 成晓旭的个人软件Delphi源码库 // 产品版本: CXXSoft delphi code source lib 2.0 // 模块名称: Delphi之三汇模拟语音卡类 // 模块描述: // 单元文件: unSHCard8B.pas // 开发作者: 成晓旭 // 备注: 任何人使用此文件时,请保留此段自述文件,谢谢! // 开发时间: 2003-12-03 // 修改历史: // 修改描述: //------------------------------------------------------------------------------ unit unSHCard8B;
interface uses Windows, //unDJTC08a32,unDJNewSig, unBaseDefine, //unDJ160ADefine,unDJChanne160A, unShpa3api,unSHChanne18B,unSH8BDefine; type TCXXCommCard8B = class(TObject) private
ChannelNumber:Word; channelObject:array of TCXXSHChannel8B; OnCardChannelState:TTrunkStatusEvent;
procedure ReleaseCommDevice(); function GetChannelObjectOrder(const aChannelID:Word):Word; function InitChannel():boolean; public
constructor Create(const trunkEvent:TTrunkStatusEvent); destructor Destroy(); override;
function LoadCommDevice(const loadAll:boolean=false):boolean; function Startup():boolean; function GetAFreeChannel():Word; function GetChannelNumber():Word; function DialPhone(const aChannelID:Word;const DialPhoneNumber:PChar):boolean; function HangUp(const aChannelID:Word):boolean;
end;
implementation
const SH_ConfigFile = 'C:ShCtiShConfig.ini'; SH_IndexFile = 'C:ShCtiShIndex.ini'; ...{ TCXXCommCard8B } constructor TCXXCommCard8B.Create(const trunkEvent:TTrunkStatusEvent); begin ChannelNumber := 0; Self.OnCardChannelState := trunkEvent; end;
destructor TCXXCommCard8B.Destroy; var Loop:Word; begin if (Length(channelObject) > 0) and (channelNumber > 0) then begin for Loop := 0 to ChannelNumber - 1 do begin if Assigned(channelObject[Loop]) then begin channelObject[Loop].Free(); channelObject[Loop] := nil; end; end; end; ReleaseCommDevice(); end;
function TCXXCommCard8B.DialPhone(const aChannelID: Word; const DialPhoneNumber: PChar): boolean; var K:Word; begin Result := false; K := GetChannelObjectOrder(aChannelID); if (K <> ErrorTrunkNumber) and (Assigned(channelObject[K])) then begin Result := channelObject[K].DialPhone(DialPhoneNumber); end; end;
procedure TCXXCommCard8B.ReleaseCommDevice(); begin SsmCloseCti() ; end;
function TCXXCommCard8B.GetAFreeChannel(): Word; var Loop:Word; begin Result := ErrorTrunkNumber; for Loop := Low(channelObject) to High(channelObject) do begin if NOT channelObject[Loop].CheckDialOutEnabled() then continue; if (channelObject[Loop].GetChannelStatus() = atsFree) then begin Result := channelObject[Loop].GetChannelID(); break; end; end; end;
function TCXXCommCard8B.GetChannelNumber(): Word; begin Result := channelNumber; end;
function TCXXCommCard8B.GetChannelObjectOrder( const aChannelID: Word): Word; var Loop:Word; begin Result := ErrorTrunkNumber; for Loop := Low(channelObject) to High(channelObject) do begin if (channelObject[Loop].GetChannelID = aChannelID) then begin Result := Loop; break; end; end; end;
function TCXXCommCard8B.HangUp(const aChannelID: Word): boolean; var K:Word; begin Result := false; K := GetChannelObjectOrder(aChannelID); if (K <> ErrorTrunkNumber) and (Assigned(channelObject[K])) then begin channelObject[K].ChannelHangUp(); Result := true; end; end;
function TCXXCommCard8B.LoadCommDevice(const loadAll:boolean): boolean; const loadEmpty = true; begin Result := false; if SsmStartCti(SH_ConfigFile,SH_IndexFile) <> 0 then begin TCXXSHChannel8B.InformInvodeError(); Exit; end; if(SsmGetMaxUsableBoard() <> SsmGetMaxCfgBoard()) then begin //部分板卡初始化失败,取出失败原因 TCXXSHChannel8B.InformInvodeError(); Exit; end; Result := InitChannel(); end;
function TCXXCommCard8B.Startup(): boolean; var Loop:integer; begin for Loop := 0 to channelNumber - 1 do begin channelObject[Loop].Startup(); end; Result := true; end;
function TCXXCommCard8B.InitChannel():boolean; var number,Loop:integer; begin Result := false; number := SsmGetMaxCh(); if (number < 0) then Exit; ChannelNumber := number; SetLength(channelObject,channelNumber); for Loop := 0 to channelNumber - 1 do begin channelObject[Loop] := TCXXSHChannel8B.Create(OnCardChannelState); channelObject[Loop].CreateCommChannel(Loop); end; Result := true; end;
end.
6、 通道类源码:
//------------------------------------------------------------------------------ // // 产品名称: 成晓旭的个人软件Delphi源码库 // 产品版本: CXXSoft delphi code source lib 2.0 // 模块名称: Delphi之三汇模拟语音卡通道类 // 模块描述: // 单元文件: unSHChanne18B.pas // 开发作者: 成晓旭 // 备注: 任何人使用此文件时,请保留此段自述文件,谢谢! // 开发时间: 2003-12-01 // 修改历史: // 修改描述: //------------------------------------------------------------------------------ unit unSHChanne18B;
...{$DEFINE ThreadChannel}
interface
uses Windows,Classes,SysUtils,
unBaseDefine,unShpa3api,unSH8BDefine, //unDJ160ADefine, unDJTC08a32,unDJNewSig;
Type
...{$IFDEF ThreadChannel} TCXXSHChannel8B = class(TThread) ...{$ELSE} TCXXSHChannel8B = class(TObject) ...{$ENDIF} private channelType:TChannelType; oldChannelState,channelState:TTrunkState; channelID:Word; phoneNumber:string; dtmfString:string; aCallerId:PAnsiChar; isConntectd:boolean;
isDialOut:boolean; aTrunkState:TTrunkStatus; procedure ChannelProcessor(); procedure InformTrunkStatus(const aMsgFlag: TLVOperateFlag);
procedure ClearTrunkStatus(); procedure ClearChannelBuffer(); function CheckSigHangup():boolean; function CheckCallIn():boolean; function SwitchOnCallIn():boolean;
procedure ProcessCallInSuccess(); procedure ProcessDialSuccess();
procedure ProcessCheckDialSend(); procedure ProcessDialOut();
procedure Stop();
//三汇卡专用方法 function GetTrunkStateBySsm(const ssmState: integer): TTrunkState; protected ...{$IFDEF ThreadChannel} procedure Execute(); override; ...{$ENDIF} public strMessage:string; OnChannelState:TTrunkStatusEvent;
constructor Create(const trunkEvent:TTrunkStatusEvent); destructor Destroy();override;
procedure CreateCommChannel(const aChennelID: Word); procedure Startup();
function GetChannelID():Word; function GetChannelStatus():TTrunkState; function GetChannelType():TChannelType; function DialPhone(const DialPhoneNumber:PChar):boolean;overload; function DialPhone(const DialPhoneNumber:PChar;const PreDialNumber:PChar):boolean;overload; procedure ChannelHangUp();
function GetDialOut():boolean;
//三汇卡特性方法 function CheckDialOutEnabled():boolean; class procedure InformInvodeError(); end; implementation
...{ TCXXSHChannel8B }
procedure TCXXSHChannel8B.ChannelHangUp(); begin isDialOut := false; SsmHangUp(channelID); ClearChannelBuffer(); ClearTrunkStatus(); InformTrunkStatus(lvofUpdate); end;
procedure TCXXSHChannel8B.ChannelProcessor(); var ssmState:integer; begin // ssmState := SsmGetChState(channelID); // channelState := GetTrunkStateBySsm(ssmState); CheckCallIn(); case channelState of atsFree: begin // end; atsCallIning: begin SwitchOnCallIn(); end; atsCallInSuccess: begin if CheckSigHangup() then Exit; ProcessCallInSuccess(); end; atsCheckSendDial: begin ProcessCheckDialSend(); end; atsDialing: begin ProcessDialOut(); end; atsDialSuccess: begin if CheckSigHangup() then Exit; ProcessDialSuccess(); strMessage := '拨号成功'; end; atsHangOff: begin ChannelHangUp(); end; end; if (oldChannelState <> channelState) then begin oldChannelState := channelState; InformTrunkStatus(lvofUpdate); end; end;
function TCXXSHChannel8B.CheckCallIn(): boolean; begin Result := false; if(SsmGetChState(channelID)=2) then //检测到振铃信号 begin SsmGetCallerId(channelID, aCallerId); //取出CALLERID信息 channelState := atsCallIning; Result := true; end; ...{ Result := RingDetect(channelID); if Result then begin OffHook(channelID); if isDialOut then channelState := atsDialSuccess else channelState := atsCallIning; end; } end;
function TCXXSHChannel8B.CheckSigHangup(): boolean; begin Result := false; if (SsmGetChState(channelID) = S_CALL_PENDING) then begin strMessage := '对方已挂机'; InformTrunkStatus(lvofUpdate); SsmStopPlay(channelID); channelState := atsHangOff; Result := true; end; end;
procedure TCXXSHChannel8B.ClearTrunkStatus(); begin channelState := atsFree; oldChannelState := channelState; phoneNumber := ''; dtmfString := ''; strMessage := ''; isConntectd := false; end;
constructor TCXXSHChannel8B.Create(const trunkEvent:TTrunkStatusEvent); begin GetMem(aCallerId,50); Self.OnChannelState := trunkEvent; ...{$IFDEF ThreadChannel} Self.FreeOnTerminate := true; inherited Create(true); ...{$ENDIF} end;
destructor TCXXSHChannel8B.Destroy; begin ChannelHangUp(); Stop(); ...{$IFNDEF ThreadChannel} inherited Destroy(); ...{$ENDIF} InformTrunkStatus(lvofDelete); FreeMem(aCallerId); end;
function TCXXSHChannel8B.DialPhone(const DialPhoneNumber:PChar; const PreDialNumber:PChar): boolean; begin Result := false; if (channelState <> atsFree) then Exit; phoneNumber := DialPhoneNumber; Result := (SsmPickup(channelID) = 0); if NOT Result then Exit; Result := (SsmAutoDial(channelID,DialPhoneNumber)=0); if Result then begin isDialOut := true; channelState := atsCheckSendDial; end; end;
function TCXXSHChannel8B.DialPhone( const DialPhoneNumber: PChar): boolean; begin Result := DialPhone(DialPhoneNumber,''); end;
...{$IFDEF ThreadChannel} procedure TCXXSHChannel8B.Execute; begin while NOT Terminated do begin Synchronize(ChannelProcessor); Sleep(10); end; end; ...{$ENDIF}
function TCXXSHChannel8B.GetChannelID(): Word; begin Result := channelID; end;
function TCXXSHChannel8B.GetChannelStatus(): TTrunkState; begin Result := channelState; end;
procedure TCXXSHChannel8B.InformTrunkStatus(const aMsgFlag: TLVOperateFlag); begin if NOT Assigned(OnChannelState) then Exit; aTrunkState.lvFlag := aMsgFlag; aTrunkState.TrunkID := IntToStr(channelID); aTrunkState.TrunkType := Ord(channelType); aTrunkState.TrunkTypeStr := ChannelTypeString[channelType]; aTrunkState.TrunkStep := Ord(channelState); aTrunkState.TrunkStepStr := TrunkStateString[channelState]; aTrunkState.TrunkPhone := phoneNumber; aTrunkState.TrunkData := dtmfString; OnChannelState(aTrunkState); end;
procedure TCXXSHChannel8B.ProcessCallInSuccess(); begin
end;
function TCXXSHChannel8B.SwitchOnCallIn(): boolean; begin SsmPickup(channelID); //摘机 ClearChannelBuffer(); channelState := atsCallInSuccess; Result := true; end;
procedure TCXXSHChannel8B.ProcessDialSuccess(); begin
end;
procedure TCXXSHChannel8B.CreateCommChannel(const aChennelID: Word); var ct:integer; begin channelID := aChennelID; ct := SsmGetChType(channelID); if (ct < 0) then Exit; channelType := TChannelType(ct); ClearTrunkStatus(); InformTrunkStatus(lvofAdd); end;
function TCXXSHChannel8B.GetChannelType(): TChannelType; begin Result := channelType; end;
function TCXXSHChannel8B.GetDialOut(): boolean; begin Result := isDialOut; end;
procedure TCXXSHChannel8B.ProcessCheckDialSend(); begin //三汇卡直接转换状态 channelState := atsDialing; end;
procedure TCXXSHChannel8B.Startup(); begin ...{$IFDEF ThreadChannel} Resume(); ...{$ENDIF} end;
procedure TCXXSHChannel8B.Stop(); begin ...{$IFDEF ThreadChannel} Suspend(); Terminate(); ...{$ENDIF} end;
function TCXXSHChannel8B.CheckDialOutEnabled(): boolean; begin //内线通道、坐席通道、磁石通道和录音通道不支持本SsmPicuup操作 Result := NOT((channelType = ct1) or (channelType = ct2) or (channelType = ct3) or (channelType = ct10)); end;
class procedure TCXXSHChannel8B.InformInvodeError; var msgBuffer:PAnsiChar; begin GetMem(msgBuffer,255); try SsmGetLastErrMsg(msgBuffer); //记录异常日志,或者通知用户 //Showmessage(msgBuffer); finally FreeMem(msgBuffer); end; end;
function TCXXSHChannel8B.GetTrunkStateBySsm( const ssmState: integer): TTrunkState; begin Result := atsFree; case ssmState of 0: Result := atsFree; 4,5,6,9: Result := atsCallIning; 7: Result := atsHangOff; //8:“断线”状态。只有录音通道才会进入本状态。暂时不处理 //8: Result := atsHangOff; //3: Result := atsCallInSuccess; end; end;
procedure TCXXSHChannel8B.ProcessDialOut(); var dState:integer; begin dState := SsmChkAutoDial(channelID); case dState of DIAL_VOICE, DIAL_VOICEF1, DIAL_VOICEF2: begin channelState := atsDialSuccess; isConntectd := true; end; DIAL_STANDBY, DIAL_NO_DIALTONE, DIAL_ECHO_NOVOICE, DIAL_NOVOICE, DIAL_NOANSWER, DIAL_FAILURE, DIAL_INVALID_PHONUM: begin channelState := atsHangOff; end; end; strMessage := '拨号中...'; end;
procedure TCXXSHChannel8B.ClearChannelBuffer(); begin SsmClearRxDTMFBuf(channelID); //清空驱动程序内部的DTMF按键号码接收缓冲区 SsmClearRxBuf(channelID); //清除指定通道ch上MODEM模块的接收缓冲区中的所有数据 //“抢拨” 开关是指当在放音过程中收到对方的DTMF按键字符时,由驱动程序程序立即停止正在进行的放音操作。 //SsmSetDtmfStopPlay(channelID,true); //打开抢拨开关 end;
end.
|