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

Delphi之东进数字语音卡(SS1)可复用源码

2008-01-03 12:12 127 查看
Delphi之东进数字语音卡(SS1)可复用源码作者:成晓旭Bloghttp://blog.csdn.net/cxxsoft(声明:欢迎转载,请保证文章的完整性)        由于工作原因,本人将不在从事商业应有软件的开发工作,现在开始逐级“解密”自己以前写的部分自有产权代码,但愿对后来的朋友有点参考、借鉴的价值。        本代码是本人开发的计划开源的CIT通用平台的东进1号信令数字语言卡封装,设计思路与模拟语音卡的封装非常类似,在此不再赘述。有兴趣的朋友,请参考本人的另外一篇文章《Delphi之东进模拟语音卡(D160A)可复用源码》:http://blog.csdn.net/cxxsoft/archive/2006/08/23/1108211.aspx        核心思想是一致的:卡、通道分别设计和实现;通道内,核心的还是“状态机模式”轮巡通道状态来管理硬件卡设备;板卡封装内实现不实现任何业务接口,但允许动态注入实现业务接口的对象,来近一步分发、处理板卡层采集的基础数据。卡类源代码:

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


//


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


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


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


//      模块描述:   


//      单元文件:   unDJCardSS1.pas   


//      开发作者:   成晓旭


//      作者blog:   http://blog.csdn.net/CXXSoft


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


//      开发时间:   2005-01-09


//      修改历史:   


//      修改描述:


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


unit unDJCardSS1;




interface


uses


  Windows,SysUtils,Classes,


  unBaseDefine,


  Tce1_32,


  Tce1_FSK;




type


  TDJCommCardSS1 = class(TThread)


  private


    onTrunkEvent:TTrunkSatausEvent;


    onRecEvent:TTrunkReceiveEvent;


    isLoadFSK:boolean;


    CommIsFSK:boolean;


    Trunks:array of TObject;


    function  InitCardForFSK():boolean;


    procedure FreeCardForFSK();


    procedure ThreadKernelProcess();


  protected


    procedure Execute(); override;


  public


    TotalTrunkNum,InTrunkNum,OutTrunkNum:Word;


    TrunkConnected:array of boolean;




    constructor Create(const aStateEvent: TTrunkSatausEvent;const aRecEvent:TTrunkReceiveEvent);


    destructor Destroy(); override;


    //初始化中继卡


    function  InitCard(const isFSKComm: boolean): Boolean;


    //释放中继卡  


    function  FreeCommCard():boolean;


    //开始运行中继卡管理模块


    procedure StartRunCommModule();


    //获取一个空闲通道(指定通道类型)


    function  GetAFreeTrunkByType(const aTrunkType:TTrunkType):integer;


    //获取一个空闲呼出通道


    function  GetAFreeTrunkByOut():integer;


    //挂断指定通道


    procedure HangOfByTrunkID(const aChannelID:integer);


    //通过指定通道拨号


    procedure DialPhoneByTrunkID(const aChannelID:integer;const phoneNumber,callerNumber:PChar;const aDevID:integer=-1);


    //通过指定通道发送数据


    function  SendStringByTrunkID(const aChannelID:integer;const sendBuffer:PChar):boolean;


  end;




implementation






...{ TDJCommCardSS1 }


uses


  unDJChannelSS1;




constructor TDJCommCardSS1.Create(const aStateEvent: TTrunkSatausEvent;


  const aRecEvent:TTrunkReceiveEvent);


begin


  inherited Create(true);


  Self.FreeOnTerminate := true;


  onTrunkEvent := aStateEvent;


  onRecEvent := aRecEvent;


end;




destructor TDJCommCardSS1.Destroy();


begin


  Self.Suspend();


  Self.Terminate();


  FreeCommCard();


end;




procedure TDJCommCardSS1.DialPhoneByTrunkID(const aChannelID: integer;


  const phoneNumber, callerNumber: PChar;const aDevID:integer);


begin


  if (aChannelID > ErrTrunkId) and (DJTrk_CheckTrunkFree(aChannelID)) then


    TDJCommChannelsSS1(Trunks[aChannelID]).StartDialPhone(phoneNumber,callerNumber,aDevID,);


end;




procedure TDJCommCardSS1.Execute;


begin


  while NOT Terminated do


  begin


    Synchronize(ThreadKernelProcess);


    Sleep(1);


  end;


end;




procedure TDJCommCardSS1.FreeCardForFSK();


begin


  if CommIsFSK and isLoadFSK then


  begin


    DJFsk_Release();


  end;


end;




function TDJCommCardSS1.FreeCommCard(): boolean;


var


  Loop:Word;


begin


  Sleep(1000);


  if TotalTrunkNum > 0 then


  begin


    for Loop:= 0 to TotalTrunkNum - 1 do


    begin


      if Assigned(TDJCommChannelsSS1(Trunks[Loop])) then


      begin


        TDJCommChannelsSS1(Trunks[Loop]).Free();


        TDJCommChannelsSS1(Trunks[Loop]) := nil;


      end;


    end;


  end;


  DJSys_DisableCard();


  FreeCardForFSK();


  Result := true;


end;




function TDJCommCardSS1.GetAFreeTrunkByOut(): integer;


begin


  Result := GetAFreeTrunkByType(Type_Export);


end;




function TDJCommCardSS1.GetAFreeTrunkByType(


  const aTrunkType: TTrunkType): integer;


var


  Loop:Word;


begin


  Result := ErrTrunkID;


  for Loop := 0 to TotalTrunkNum - 1 do


  begin


    if ((TDJCommChannelsSS1(Trunks[Loop]).GetTrunkType() = aTrunkType)


          and (DJTrk_CheckTrunkFree(Loop))) then


    begin


      Result := Loop;


      break;


    end;


  end;


end;




procedure TDJCommCardSS1.HangOfByTrunkID(const aChannelID: integer);


begin


  TDJCommChannelsSS1(Trunks[aChannelID]).InOutHangOff();


end;




function TDJCommCardSS1.InitCard(const isFSKComm: boolean): Boolean;


const


  PromptFile = 'Prompt.ini';


var


  Loop: Integer;


  isOK: boolean;


  TimeOfNow: SystemTime;


begin


  Result := False;


  CommIsFSK := isFSKComm;


  isOK :=(DJSys_EnableCard('',PromptFile)=_ERR_OK);


  if Not isOK then exit;


  isOK := InitCardForFSK();


  if NOT isOK then Exit;


  isLoadFSK := isOK;


  GetLocalTime(TimeOfNow);


  DJSys_SetSysTime(TimeOfNow.wHour,TimeOfNow.wMinute,TimeOfNow.wSecond);


  TotalTrunkNum:=DJTrk_GetTotalTrunkNum();


  InTrunkNum:=TotalTrunkNum shr 1;


  OutTrunkNum:=TotalTrunkNum - InTrunkNum;




  SetLength(Trunks,TotalTrunkNum);


  SetLength(TrunkConnected,TotalTrunkNum);




  for Loop:=0 to OutTrunkNum-1 do


    Trunks[Loop]:=TDJCommChannelsSS1.Create(Self,Loop,Type_Export,CommIsFSK,onTrunkEvent,onRecEvent);


  for Loop:=OutTrunkNum to TotalTrunkNum-1 do


    Trunks[Loop]:=TDJCommChannelsSS1.Create(Self,Loop,Type_Import,CommIsFSK,onTrunkEvent,onRecEvent);


  for Loop:= 0 to TotalTrunkNum - 1 do


  begin


    TDJCommChannelsSS1(Trunks[Loop]).ClearTrunkBuffer(csReceiving);


  end;




  DJSys_AutoApplyDtmf(ENABLEDTMF);    //自动分配DTMF资源


  DJSys_EnableAutoKB();                 //自动回送KB信号


  isOK:=isOK and DJSys_EnableDtmfSend();


  Result := isOK;


end;




function TDJCommCardSS1.InitCardForFSK(): boolean;


var


  k:integer;


begin


  Result := true;


  if CommIsFSK then


  begin


    k := DJFsk_InitForFsk(SZK_Mode);


    Result := (k = 1);


  end;


end;




function TDJCommCardSS1.SendStringByTrunkID(const aChannelID: integer;


  const sendBuffer: PChar):boolean;


begin


  Result := TDJCommChannelsSS1(Trunks[aChannelID]).SendString(sendBuffer);


end;




procedure TDJCommCardSS1.StartRunCommModule();


begin


  Resume();


end;




procedure TDJCommCardSS1.ThreadKernelProcess();


var


  Loop:Word;


begin


  DJSys_PushPlay();


  for Loop := 0 to TotalTrunkNum - 1 do


  begin


    try


      TDJCommChannelsSS1(Trunks[Loop]).DJChannelProcessor();


    except


    end;


  end;


end;




end. 通道类源代码:

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


//


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


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


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


//      模块描述:   


//      单元文件:   unDJChannelSS1.pas   


//      开发作者:   成晓旭


//      作者blog:   http://blog.csdn.net/CXXSoft


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


//      开发时间:   2005-01-09


//      修改历史:   


//      修改描述:


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


unit unDJChannelSS1;




interface


uses


  Windows, SysUtils,


  unBaseDefine,


  Tce1_32,


  Tce1_FSK,


  unDJCardSS1;


type




  TCXXStatus = (csSending,csReceiving,csPlaying);


  


  TDJCommChannelsSS1 = class(TObject)


  private


    CommIsFSK:boolean;


    controller:TDJCommCardSS1;


    TrunkID:integer;


    TrunkStep:TTrunkStep;




    MaxBuffer: array [0..DTMF_BUFFER_SIZE-1] of Char;


    msgChannel:TTrunkStatusInfo;


    msgFrame:TRecCommFrame;




    commFrameNumber,recPos:Word;


    subStatus:TCXXStatus;


    commPhone:string;


    commFrameStr:string;




    //应该进一步优化为注入的接口,非简单的回调句柄


    onTrunkState:TTrunkSatausEvent;


    onRecEvent:TTrunkReceiveEvent;


    InOutType:TTrunkType;




    function  SendDataFromTrunk():boolean;


    function  CheckSendDataEnd():boolean;


    procedure SaveMaxBufferToFrameStr();


    procedure ProcessConnected();


    //注意:此方法与具体业务的通信协议存在严重依赖关系(IoC实现依赖反转)


    function  CheckReceiveOverFSK(const dataBuffer:array of char;const dataNumber:Word):boolean;


    //注意:此方法与具体业务的通信协议存在严重依赖关系(IoC实现依赖反转)


    function  CheckReceiveOverDTMF(const dataBuffer:array of char;const dataNumber:Word):boolean;


    function  GetCommData(const dataBuffer:array of char;const dataNumber:Word):string;


    function  ReceiveDataFromTrunk():boolean;




    procedure InformChannelStatus(const aStep:TTrunkStep;const lvof:TLVOperateFlag);


    procedure InformBusinessStatus(const aCommData:string;const cif:TCommInformFlag);


    procedure InformDialStatus(const aStep:TTrunkStep);


    procedure InWaitingIntoToConnect();


    function  GetCommFrameFromSendString(const commFrame:string):string;




    procedure RegisterTrunkEvent(const trunkStateEvent:TTrunkSatausEvent);


    procedure RegisterReceiveEvent(const trunkRecEvent:TTrunkReceiveEvent);


  public


    


    constructor Create(const trunkController: TDJCommCardSS1; const TrkID: Integer;


      const TrunkType: TTrunkType;const isFSKComm: boolean;


      const aStateEvent: TTrunkSatausEvent;const aRecEvent:TTrunkReceiveEvent);


    destructor Destroy; override;




    //获取通道状态


    function GetTrunkType():TTrunkType;


    procedure DJChannelProcessor();


    //通道挂机


    procedure InOutHangOff();


    //开始拨号


    procedure StartDialPhone(const phoneNumber,callerNumber:PChar;const aDevID:integer=-1);


    //发送通信数据


    function  SendString(const pchSend:PChar):boolean;


    //清空通道数据缓冲


    procedure ClearTrunkBuffer(const aSB:TCXXStatus);


    //获取通道号


    function  GetTrunkID():integer;


  end;




implementation






...{ TDJCommChannelsSS1 }


const


  Frame_FillChar = #0;


  Leader_Flag = $55;


  HeadNumber = 30;


  hasLeader = true;


  


function TDJCommChannelsSS1.CheckSendDataEnd(): boolean;


begin


  Result := false;


  if CommIsFSK then


  begin


    if (DJFsk_CheckSendFSKEnd(TrunkID,SZK_Mode) = 1) then


    begin


      DJFsk_StopSend(TrunkID,SZK_Mode);


      Result := true;


    end;


  end


  else


  begin


    if DJTrk_CheckDtmfSendEnd(TrunkID) then


    begin


      DJVoc_StopPlayFile(TrunkID);


      Result := true;


    end;


  end;


  if Result then


    ClearTrunkBuffer(csReceiving);


end;




procedure TDJCommChannelsSS1.ClearTrunkBuffer(const aSB:TCXXStatus);


begin


  subStatus := aSB;


  if CommIsFSK then


    DJFsk_ResetFskBuffer(TrunkID,SZK_Mode)


  else


    DJTrk_InitDtmfBufNew(TrunkID);


  commFrameNumber := 0;


  recPos := 0;


end;




constructor TDJCommChannelsSS1.Create(const trunkController: TDJCommCardSS1; const TrkID: Integer;


  const TrunkType: TTrunkType; const isFSKComm: boolean;


  const aStateEvent: TTrunkSatausEvent;const aRecEvent:TTrunkReceiveEvent);


var


  t:TTrunkType;


begin


  inherited Create;


  RegisterTrunkEvent(aStateEvent);


  RegisterReceiveEvent(aRecEvent);


  controller :=trunkController;


  TrunkID:=TrkID;


  commPhone := '';


  TrunkStep:=TTrunkStep(-1);


  t := TrunkType;


  if DJTrk_SetTrunkType(TrkID,t) then


    InOutType:=TrunkType;


  CommIsFSK := isFSKComm;


  controller.TrunkConnected[TrunkID] := false;


  ClearTrunkBuffer(csReceiving);


  InformChannelStatus(Step_Free,lvofAdd);


end;




destructor TDJCommChannelsSS1.Destroy();


begin


  inherited;


  DJTrk_BackwardHangUp(TrunkID);


end;




procedure TDJCommChannelsSS1.DJChannelProcessor();


var


  aStep: TTrunkStep;


begin


  //DJSys_PushPlay();


  aStep:= DJTrk_GetTrunkStatus(TrunkID);


  //状态变化


  if TrunkStep <> aStep then


  begin


    TrunkStep:= aStep;


    InformChannelStatus(TrunkStep,lvofUpdate);


  end;


  //前向挂机


  if (TrunkStep<>Step_Free) and DJTrk_CheckForwardHangUp(TrunkID) then


  begin


    InOutHangOff();


  end;


  //入中继拨入,等待接续(建立连接)


  if (TrunkStep = Step_Wait) and (DJTrk_CheckTrunkIn(TrunkID)) then


  begin


    InWaitingIntoToConnect();


  end;


  //通道连接已经建立


  if (TrunkStep = Step_Connect) then


  begin


    ProcessConnected();


  end;


  //出通道拨号失败


  if TrunkStep=Step_DialFail then


  begin


    InformDialStatus(TrunkStep);


  end;


  if TrunkStep=Step_Delay then


    Exit;


  //出入通道空闲


  if TrunkStep = Step_Free then


  begin


    //等待接收呼入


  end;


end;




function TDJCommChannelsSS1.GetTrunkID(): integer;


begin


  Result := Self.TrunkID;


end;




procedure TDJCommChannelsSS1.InformChannelStatus(const aStep: TTrunkStep;const lvof:TLVOperateFlag);


begin


  msgChannel.lvFlag := lvof;


  msgChannel.TrunkID := IntToStr(Self.TrunkID);


  msgChannel.DeviceID := '';


  msgChannel.TrunkTypeStr:=TrunkTypeInStr[InOutType];


  msgChannel.TrunkStep := Ord(aStep);


  msgChannel.TrunkStepStr:=TrunkStepInStr[aStep];


  if aStep = Step_Free then


  begin


    msgChannel.Phone:='';


    msgChannel.Data:='';


  end


  else


  begin


    msgChannel.Phone:=commPhone;


    msgChannel.Data:=commFrameStr;


  end;


  if Assigned(onTrunkState) then


    onTrunkState(msgChannel);


end;




procedure TDJCommChannelsSS1.InformDialStatus(const aStep: TTrunkStep);


var


  dStatus:TDialStatus;


begin


  dStatus := DJTrk_GetDialStatus(TrunkID);


  case dStatus of


  DS_Busy,DS_OverTime,DS_NoUser,DS_LineError:


  begin


    InOutHangOff();


  end;


  end;


end;




procedure TDJCommChannelsSS1.InformBusinessStatus(const aCommData: string;const cif:TCommInformFlag);


begin


  //依赖注入的业务处理接口调用,实现业务处理的


end;




procedure TDJCommChannelsSS1.InOutHangOff();


begin


  DJTrk_BackwardHangUp(TrunkID);


  controller.TrunkConnected[TrunkID] := false;


  InformBusinessStatus('',cifDisconnected);


end;




procedure TDJCommChannelsSS1.InWaitingIntoToConnect;


begin


  DJVoc_PlayFile(TrunkID,'.Voicedtmf13');


  DJVoc_StopPlayFile(TrunkID);


end;






procedure TDJCommChannelsSS1.ProcessConnected();


var


  ss:TCXXStatus;  


begin


  if NOT controller.TrunkConnected[TrunkID] then


  begin


    controller.TrunkConnected[TrunkID] := true;


    ss := csReceiving;


    InformBusinessStatus('',cifConnected);


    ClearTrunkBuffer(ss);


  end;


  case subStatus of


  csSending:


  begin


    if CheckSendDataEnd() then


    begin


        InformChannelStatus(Step_Connect,lvofUpdate);


        InformBusinessStatus(commFrameStr,cifSend);


    end;


  end;


  csReceiving:


  begin


    if ReceiveDataFromTrunk() then


    begin


      msgFrame.CommFrame := commFrameStr;


      msgFrame.CommType := Comm_FSK;


      InformChannelStatus(Step_Connect,lvofUpdate);


      InformBusinessStatus(commFrameStr,cifReceive);


    end;


  end;


  csPlaying:


  begin


    


  end;


  end;


end;




function TDJCommChannelsSS1.ReceiveDataFromTrunk(): boolean;


var


  num,Loop:integer;


  tempBuffer:array[0..DTMF_BUFFER_SIZE-1] of Char;


begin


  Result := false;


  try


    if Self.CommIsFSK then


    begin


      //FSK方式版本


      FillChar(tempBuffer,DTMF_BUFFER_SIZE,Frame_FillChar);


      num := DJFsk_GetFSK(TrunkID,tempBuffer,SZK_MODE);


      if (num > 0) then


      begin


        if CheckReceiveOverFSK(tempBuffer,num) then


        begin


          Self.commFrameStr := GetCommData(tempBuffer,num);


          Self.ClearTrunkBuffer(csReceiving);


          Result := true;


        end;


      end;


    end


    else


    begin


      //DTMF方式版本


      num := DJTrk_GetReceiveDtmfNumNew(TrunkID);


      if num > 0 then


      begin


        for Loop := 0 to num - 1 do


        begin


          MaxBuffer[recPos+Loop] := DJTrk_GetDtmfCodeNew(TrunkID);


          recPos := (recPos + 1) mod DTMF_BUFFER_SIZE;


        end;


        Inc(commFrameNumber,num);


        if CheckReceiveOverDTMF(tempBuffer,num) then


        begin


          ClearTrunkBuffer(csReceiving);


          Result := true;


        end;


      end;


    end;


  except


    Result := false;


  end;


end;




procedure TDJCommChannelsSS1.RegisterReceiveEvent(


  const trunkRecEvent: TTrunkReceiveEvent);


begin


  onRecEvent := trunkRecEvent;


end;




procedure TDJCommChannelsSS1.RegisterTrunkEvent(


  const trunkStateEvent: TTrunkSatausEvent);


begin


  onTrunkState := trunkStateEvent;


end;




procedure TDJCommChannelsSS1.SaveMaxBufferToFrameStr();


var


  Loop:Word;


begin


  commFrameStr := '';


  for Loop := 0 to commFrameNumber - 1 do


  begin


    commFrameStr := commFrameStr + MaxBuffer[Loop];


  end;


end;




function TDJCommChannelsSS1.SendDataFromTrunk():boolean;


begin


  Result := false;


  if controller.TrunkConnected[TrunkID] then


  begin


    if CommIsFSK then


    begin


      Result := DJFsk_SendFSK(TrunkID,@MaxBuffer[0],commFrameNumber,SZK_Mode) = 1;


    end


    else


    begin


      Result := DJTrk_SendDtmfStr(TrunkID,@MaxBuffer[0]) = 1;


    end;


  end;


  if Result then


    subStatus := csSending;


end;




function TDJCommChannelsSS1.SendString(const pchSend: PChar):boolean;


var


  Loop:integer;


  strTemp:string;


begin


  Result := false;


  if Self.CommIsFSK and hasLeader then


  begin


    //加FSK前导字符的版本


    strTemp := GetCommFrameFromSendString(pchSend);


    commFrameNumber := Length(strTemp);


    if commFrameNumber > 0 then


    begin


      for Loop := 0 to commFrameNumber-1 do


        MaxBuffer[Loop] := strTemp[Loop+1];


      MaxBuffer[commFrameNumber] := #0;


      SaveMaxBufferToFrameStr();


      Result := SendDataFromTrunk();


    end;


  end


  else


  begin


    //不加前导字符的版本


    commFrameNumber := Length(pchSend);


    if commFrameNumber > 0 then


    begin


      for Loop := 0 to commFrameNumber-1 do


        MaxBuffer[Loop] := pchSend[Loop];


      MaxBuffer[commFrameNumber] := #0;


      SaveMaxBufferToFrameStr();


      Result := SendDataFromTrunk();


    end;


  end;


end;




procedure TDJCommChannelsSS1.StartDialPhone(const phoneNumber,


  callerNumber: PChar;const aDevID:integer);


begin


  if DJTrk_CheckTrunkFree(TrunkID) and(Trim(phoneNumber) <> '') then


  begin


    commPhone := Trim(phoneNumber);


    DJTrk_StartDial(TrunkID,PChar(commPhone),'');


  end;


end;




function TDJCommChannelsSS1.CheckReceiveOverFSK(const dataBuffer: array of char;


  const dataNumber: Word): boolean;


begin


  //业务实现方法:判定通信帧串发送结束


  Result := true;


end;




function TDJCommChannelsSS1.GetCommData(const dataBuffer: array of char;


  const dataNumber: Word): string;


var


  Loop:Word;


begin


  Result := '';


  if dataNumber <= 0 then Exit;


  for Loop := 0 to dataNumber - 1 do


  begin


    if (dataBuffer[Loop] <> Frame_FillChar) then


      Result := Result + dataBuffer[Loop];


  end;


end;




function TDJCommChannelsSS1.GetCommFrameFromSendString(


  const commFrame: string): string;


var


  Loop:integer;


begin


  Result := commFrame;


  for Loop := 0 to HeadNumber - 1 do


    Result := CHR(Leader_Flag) + Result;


end;




function TDJCommChannelsSS1.CheckReceiveOverDTMF(


  const dataBuffer: array of char; const dataNumber: Word): boolean;


begin


  //业务实现方法:判定通信帧串发送结束


  Result := true;


end;




function TDJCommChannelsSS1.GetTrunkType(): TTrunkType;


begin


  Result := Self.InOutType;


end;




end.  

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1770257
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: