Discuz!NT
欢迎 游客 , 注册 | 登录 | 会员 | 界面 | 简洁版本 | 在线 | 帮助
商都网教育宝典宝库

发表新主题 回复该主题
本主题被查看1285次, 共1个帖子, 1页, 当前为第1页     选择页数: 1      跳转到第   上一主题   下一主题
标题: Delphi之三汇模拟语音卡(SHT-8B/PCI/FAX)可复用源码
张小峰
超级版主
UID: 14
来自:
精华: 4
积分: 313
帖子: 285
注册: 2007-8-23 10:27:00
状态: 离线
威望: 8.00
金钱: 75.55 元
只看楼主 2007-09-18 15:14
Delphi之三汇模拟语音卡(SHT-8B/PCI/FAX)可复用源码
设计简介:

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.



huahua 最后编辑于 2007-11-13 17:08:27
#1  
发表新主题 回复该主题
本主题被查看1285次, 共1个帖子, 1页, 当前为第1页     选择页数: 1      跳转到第







现在的时间是 2008-10-14 04:47:42

版权所有 商都网教育宝典
         Powered by Discuz!NT 1.0.6666    Copyright © 2001-2008 Comsenz Inc.
Processed in 0 seconds