Delphi之三匯模擬語音卡(SHT-8B/PCI/FAX)可複用原始碼

gudesheng發表於2008-01-03

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;

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.

 



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1206497


相關文章