您的位置:首页 > 编程语言 > Delphi

Delphi之东进模拟语音卡(D160A)可复用源码

2008-04-10 02:52 120 查看
  [align=center]Delphi之东进模拟语音卡(D160A)可复用源码[/align][b]作者:成晓旭Bloghttp://blog.csdn.net/cxxsoft(声明:欢迎转载,请保证文章的完整性)[/b][align=center][/align]设计简介:1、   将卡、通道分别单独进行设计与封装。2、   所有的外部操作接口都封装在卡类这一类。3、   在我的项目中,在卡类这一级还增加了适配器或者代理,分别实现了Adapter或Proxy模式;以尽可能地解耦卡设备的实现细节与具体应用业务之间的关系。因为,我们的系统中使用了几家不同的卡设备,另一方面,这些卡设备,在不同的软件系统中,又有不同的业务应用需求。4、   当然,卡这一级,也可以实现一个统一的接口,这样对外部可以表现出相对统一的行为,以方便业务层代码的调用,比如说:在数据采集的应用中,统一的接口可以让采集控制层不必依赖于具体的采集设备和通信方式,可以一致地实现数据收发,不管通信方式是RS232、RS485、TCP/IP、PSTN,还是别的方式或者通信设备。5、   在通道设计中,核心的就是一个“状态机模式”,通过轮巡通道状态来管理硬件卡设备,并且,还自己设计了一个业务级的“业务状态机”,来抽象业务方面需要关心的“业务状态”,通过增加“业务状态机”这样一个中间层,以解耦业务状态与设备状态之间的依赖。(这一点,在我看到的所有卡厂商提供的各类Demo程序里面都没有这样做,这也无形中误导了很多的开发人员,我看到的所有应用软件开发的源码都是:设备细节、尤其是通道状态,与业务逻辑代码紧紧地耦合在一起,难解难分)。6、   此设计的另一个亮点是:IoC模式的应用(2004年自己在设计此类时还不知道这个概念,全凭自己的经验总结出这样的设计)。对通道进入“呼入成功”、“呼出成功”等业务状态的调用代码从通道类是解耦出来:设计一个接口,在各个业务状态的处理方法中,再调用接口方法,将具体的业务处理逻辑委托给实现此接口的对象。并且这个接口的实现是通过“依赖注入”实现IoC的。这样设计,就达到了很好的可复用性和灵活性。7、   当然,更好的实现可以采用AOP(面向方法编程)的思想或者实现技术,这样可复用性更好,如此设计,在业务与卡方法的调用之间,耦合度将是最低的。8、   目前的版本,没有在代码中体现接口的实现……9、   类图(以后补上):    10、卡类源码:

//------------------------------------------------------------------------------


//


//      产品名称:   成晓旭的个人软件Delphi源码库


//      产品版本:   CXXSoft delphi code source lib 2.0


//      模块名称:   Delphi之东进模拟语音卡类


//      模块描述:   


//      单元文件:   unDJCard160A.pas   


//      开发作者:   成晓旭


//      备注:       任何人使用此文件时,请保留此段自述文件,谢谢!


//      开发时间:   2004-08-03


//      修改历史:   


//      修改描述:


//------------------------------------------------------------------------------


unit unDJCard160A;




interface


uses


  Windows,


  unDJTC08a32,unDJNewSig,


  unBaseDefine,unDJ160ADefine,


  unDJChanne160A;


type


  TCXXCommCard160A = class(TObject)


  private




    ChannelNumber:Word;


    channelObject:array of TCXXDJChannel160A;


    OnCardChannelState:TTrunkStatusEvent;




    procedure Stop();


    procedure ReleaseCommDevice();


    function  GetChannelObjectOrder(const aChannelID:Word):Word;




  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






...{ TCXXCommCard160A }


constructor TCXXCommCard160A.Create(const trunkEvent:TTrunkStatusEvent);


begin


  ChannelNumber := 0;


  Self.OnCardChannelState := trunkEvent;


end;




destructor TCXXCommCard160A.Destroy;


var


  Loop:Word;


begin


  Stop();


  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 TCXXCommCard160A.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 TCXXCommCard160A.ReleaseCommDevice();


begin


  DisableCard();


  FreeDrv();


end;




function TCXXCommCard160A.GetAFreeChannel(): Word;


var


  Loop:Word;


begin


  Result := ErrorTrunkNumber;


  for Loop := Low(channelObject) to High(channelObject) do


  begin


    if (channelObject[Loop].GetChannelType() = ctEmpty) then continue;


    if (channelObject[Loop].GetChannelStatus() = atsFree) then


    begin


      Result := channelObject[Loop].GetChannelID();


      break;


    end;


  end;


end;




function TCXXCommCard160A.GetChannelNumber(): Word;


begin


  Result := channelNumber;


end;




function TCXXCommCard160A.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 TCXXCommCard160A.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 TCXXCommCard160A.LoadCommDevice(const loadAll:boolean): boolean;


const


  loadEmpty = true;


var


  Loop,tempNumber:Word;


  isFlag:LongInt;


  function CheckLoadTrunk():boolean;


  begin


    Result := loadAll or ((NOT loadAll) and(TChannelType(CheckChType(Loop)) <> ctEmpty));


  end;


begin


  isFlag := LoadDRV();


  Result := (isFlag=0);


  if NOT Result then Exit;


  tempNumber := CheckValidCh();


  Result := EnableCard(tempNumber,1024*8)=0;


  if NOT Result then


  begin


    FreeDrv();


    Exit;


  end;


  Result := Sig_Init()=1;


  if NOT Result then Exit;


  SetBusyPara(700);


  SetPackRate(PACK_64KBPS );


  channelNumber := tempNumber;


  SetLength(channelObject,channelNumber);


  for Loop := 0 to channelNumber - 1 do


  begin


    if CheckLoadTrunk() then


    begin


      channelObject[Loop] := TCXXDJChannel160A.Create(OnCardChannelState);


      channelObject[Loop].CreateCommChannel(Loop);


    end;


  end;


end;




function TCXXCommCard160A.Startup(): boolean;


var


  Loop:integer;


begin


  for Loop := 0 to channelNumber - 1 do


  begin


    channelObject[Loop].Resume();


  end;


  Result := true;


end;




procedure TCXXCommCard160A.Stop();


var


  Loop:integer;


begin


  for Loop := 0 to channelNumber - 1 do


  begin


    channelObject[Loop].Suspend();


    channelObject[Loop].Terminate();


    channelObject[Loop] := nil;


  end;


end;




end.


[align=left]11、              通道类源码:[/align]

//------------------------------------------------------------------------------


//


//      产品名称:   成晓旭的个人软件Delphi源码库


//      产品版本:   CXXSoft delphi code source lib 2.0


//      模块名称:   Delphi之东进模拟语音卡通道类


//      模块描述:   


//      单元文件:   unDJChanne160A.pas   


//      开发作者:   成晓旭


//      备注:       任何人使用此文件时,请保留此段自述文件,谢谢!


//      开发时间:   2004-08-03


//      修改历史:   


//      修改描述:


//------------------------------------------------------------------------------


unit unDJChanne160A;




interface




uses


  Windows,Classes,SysUtils,


  unBaseDefine,unDJ160ADefine,


  unDJTC08a32,unDJNewSig;


Type


  TCXXDJChannel160A = class(TThread)


  //TCXXDJChannel160A = class(TObject)


  private


    channelType:TChannelType;


    oldChannelState,channelState:TTrunkState;


    channelID:Word;


    phoneNumber:string;


    dtmfString:string;




    isConntectd:boolean;




    isDialOut:boolean;


    aTrunkState:TTrunkStatus;


    


    procedure InformTrunkStatus(const aMsgFlag: TLVOperateFlag);




    procedure ClearTrunkStatus();


    function  CheckSigHangup():boolean;


    function  CheckCallIn():boolean;


    function  SwitchOnCallIn():boolean;




    procedure ProcessCallInSuccess();


    procedure ProcessDialSuccess();




    procedure ProcessCheckDialSend();


  protected


    procedure Execute(); override;


  public


    strMessage:string;


    OnChannelState:TTrunkStatusEvent;




    constructor Create(const trunkEvent:TTrunkStatusEvent);


    destructor Destroy();override;




    procedure CreateCommChannel(const aChennelID: Word);


    procedure ChannelProcessor();




    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;


  end;


implementation






...{ TCXXDJChannel160A }




procedure TCXXDJChannel160A.ChannelHangUp();


begin


  isDialOut := false;


  StopSigCheck(channelID);


  HangUp(channelID);


  Sig_ResetCheck(channelID);


  StartSigCheck(channelID);


  InitDTMFBuf(channelID);


  ClearTrunkStatus();


  InformTrunkStatus(lvofUpdate);


end;




procedure TCXXDJChannel160A.ChannelProcessor();


var


  dState:Word;


begin


  PUSH_PLAY();


  FeedSigFunc();


  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


      dState := Sig_CheckDial(channelID);


      case dState of


  //      S_NORESULT:


        S_CONNECT:


        begin


          channelState := atsDialSuccess;


          isConntectd := true;


        end;


        S_BUSY,


        S_NOBODY,


        S_NODIALSIG,


        S_NOSIGNAL:


        begin


          channelState := atsHangOff;


        end;


      end;


      strMessage := '拨号中...';


    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 TCXXDJChannel160A.CheckCallIn(): boolean;


begin


  Result := RingDetect(channelID);


  if Result then


  begin


    OffHook(channelID);


    if isDialOut then


      channelState := atsDialSuccess


    else


      channelState := atsCallIning;


  end;


end;




function TCXXDJChannel160A.CheckSigHangup(): boolean;


begin


  Result := false;


  if (Sig_CheckBusy(channelID)=1) then


  begin


    strMessage := '对方已挂机';


    InformTrunkStatus(lvofUpdate);


    StopPlayFile(channelID);


    channelState := atsHangOff;


    Result := true;


  end;


end;




procedure TCXXDJChannel160A.ClearTrunkStatus();


begin


  channelState := atsFree;


  oldChannelState := channelState;


  phoneNumber := '';


  dtmfString := '';


  strMessage := '';


  isConntectd := false;


end;




constructor TCXXDJChannel160A.Create(const trunkEvent:TTrunkStatusEvent);


begin


  Self.OnChannelState := trunkEvent;


  Self.FreeOnTerminate := true;


  inherited Create(true);


end;






destructor TCXXDJChannel160A.Destroy;


begin


  Suspend();


  ChannelHangUp();


  //inherited Destroy();


end;




function TCXXDJChannel160A.DialPhone(const DialPhoneNumber:PChar;


  const PreDialNumber:PChar): boolean;


begin


  isDialOut := true;


  phoneNumber := DialPhoneNumber;


  OffHook(channelID);


  InitDTMFBuf(channelID);


  Result := Sig_StartDial(channelID,DialPhoneNumber,PreDialNumber,0)=1;


  channelState := atsCheckSendDial;


end;




function TCXXDJChannel160A.DialPhone(


  const DialPhoneNumber: PChar): boolean;


begin


  Result := DialPhone(DialPhoneNumber,'');


end;




procedure TCXXDJChannel160A.Execute;


begin


  while NOT Terminated do


  begin


    Synchronize(ChannelProcessor);


    Sleep(10);


  end;


end;




function TCXXDJChannel160A.GetChannelID(): Word;


begin


  Result := channelID;


end;




function TCXXDJChannel160A.GetChannelStatus(): TTrunkState;


begin


  Result := channelState;


end;




procedure TCXXDJChannel160A.InformTrunkStatus(const aMsgFlag: TLVOperateFlag);


begin


  aTrunkState.lvFlag := aMsgFlag;


  aTrunkState.TrunkID := IntToStr(channelID);


  aTrunkState.TrunkType := channelType;


  aTrunkState.TrunkTypeStr := ChannelTypeString[channelType];


  aTrunkState.TrunkStep := channelState;


  aTrunkState.TrunkStepStr := TrunkStateString[channelState];


  aTrunkState.TrunkPhone := phoneNumber;


  aTrunkState.TrunkData := dtmfString;


  OnChannelState(aTrunkState);


end;




procedure TCXXDJChannel160A.ProcessCallInSuccess();


begin




end;




function TCXXDJChannel160A.SwitchOnCallIn(): boolean;


begin


  OffHook(channelID);


  InitDTMFBuf(channelID);


  StartSigCheck(channelID);


  channelState := atsCallInSuccess;


  Result := true;


end;




procedure TCXXDJChannel160A.ProcessDialSuccess();


begin




end;




procedure TCXXDJChannel160A.CreateCommChannel(const aChennelID: Word);


begin


  channelID := aChennelID;


  channelType := TChannelType(CheckChType(channelID));


  ClearTrunkStatus();


  InformTrunkStatus(lvofAdd);


end;




function TCXXDJChannel160A.GetChannelType(): TChannelType;


begin


  Result := channelType;


end;




function TCXXDJChannel160A.GetDialOut(): boolean;


begin


  Result := isDialOut;


end;




procedure TCXXDJChannel160A.ProcessCheckDialSend();


begin


  if(CheckSendEnd(channelID) = 1) then


  begin


    StartSigCheck(channelID);


    channelState := atsDialing;


  end;


end;




end.

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: