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

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

2007-10-29 10:55 549 查看
2007年09月03日 15:09:00
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>

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