Delphi之三匯模擬語音卡(SHT-8B/PCI/FAX)可復用源碼
作者:成曉旭
設計簡介:
1、 設計思路請參考本站Blog的另一篇文章:“Delphi之東進模擬語音卡(D160A)可復用源碼”;鏈接http://blog.csdn.net/CXXSoft/archive/2006/08/23/1108211.aspx。
2、 其實,仔細對比,你會發現這兩種卡的代碼類方法簽名幾乎99%是一樣的,也就是說,這兩都之間,還需要更進一步的抽象,以解決“重復代碼”或者“相似代碼”的問題。
3、 更高層次的抽象,請參考我的設計文檔。
4、 類圖(以後補上):
5、 卡類源碼:
//------------------------------------------------------------------------------//// 產品名稱: 成曉旭的個人軟件Delphi源碼庫// 產品版本: CXXSoft delphi code source lib 2.0// 模塊名稱: Delphi之三匯模擬語音卡類// 模塊描述: // 單元文件: unSHCard8B.pas // 開發作者: 成曉旭// 備註: 任何人使用此文件時,請保留此段自述文件,謝謝!// 開發時間: 2003-12-03// 修改歷史: // 修改描述://------------------------------------------------------------------------------unit unSHCard8B;interfaceuses 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;implementationconst 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}interfaceuses 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();beginend;function TCXXSHChannel8B.SwitchOnCallIn(): boolean;begin SsmPickup(channelID); //摘機 ClearChannelBuffer(); channelState := atsCallInSuccess; Result := true;end;procedure TCXXSHChannel8B.ProcessDialSuccess();beginend;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.