`
caozuiba
  • 浏览: 903893 次
文章分类
社区版块
存档分类
最新评论

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

 
阅读更多

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

作者:成晓旭

Bloghttp://blog.csdn.net/cxxsoft

(声明:欢迎转载,请保证文章的完整性)

由于工作原因,本人将不在从事商业应有软件的开发工作,现在开始逐级“解密”自己以前写的部分自有产权代码,但愿对后来的朋友有点参考、借鉴的价值。

本代码是本人开发的计划开源的CIT通用平台的东进1号信令数字语言卡封装,设计思路与模拟语音卡的封装非常类似,在此不再赘述。有兴趣的朋友,请参考本人的另外一篇文章《Delphi之东进模拟语音卡(D<chmetcnv w:st="on" tcsc="0" numbertype="1" negative="False" hasspace="False" sourcevalue="160" unitname="a">160A</chmetcnv>)可复用源码》:http://blog.csdn.net/cxxsoft/archive/2006/08/23/1108211.aspx

核心思想是一致的:卡、通道分别设计和实现;通道内,核心的还是状态机模式轮巡通道状态来管理硬件卡设备;板卡封装内实现不实现任何业务接口,但允许动态注入实现业务接口的对象,来近一步分发、处理板卡层采集的基础数据。

卡类源代码:

//------------------------------------------------------------------------------
//
//产品名称:成晓旭的个人软件Delphi源码库
//产品版本:CXXSoftdelphicodesourcelib2.0
//模块名称:Delphi之东进数字语音卡类
//模块描述:
//单元文件:unDJCardSS1.pas
//开发作者:成晓旭
//作者blog:http://blog.csdn.net/CXXSoft
//备注:任何人使用此文件时,请保留此段自述文件,谢谢!
//开发时间:2005-01-09
//修改历史:
//修改描述:
//------------------------------------------------------------------------------
unitunDJCardSS1;

interface
uses
Windows,SysUtils,Classes,
unBaseDefine,
Tce1_32,
Tce1_FSK;

type
TDJCommCardSS1
=class(TThread)
private
onTrunkEvent:TTrunkSatausEvent;
onRecEvent:TTrunkReceiveEvent;
isLoadFSK:boolean;
CommIsFSK:boolean;
Trunks:arrayofTObject;
functionInitCardForFSK():boolean;
procedureFreeCardForFSK();
procedureThreadKernelProcess();
protected
procedureExecute();
override;
public
TotalTrunkNum,InTrunkNum,OutTrunkNum:Word;
TrunkConnected:arrayofboolean;

constructorCreate(
constaStateEvent:TTrunkSatausEvent;constaRecEvent:TTrunkReceiveEvent);
destructorDestroy();
override;
//初始化中继卡
functionInitCard(constisFSKComm:boolean):Boolean;
//释放中继卡
functionFreeCommCard():boolean;
//开始运行中继卡管理模块
procedureStartRunCommModule();
//获取一个空闲通道(指定通道类型)
functionGetAFreeTrunkByType(constaTrunkType:TTrunkType):integer;
//获取一个空闲呼出通道
functionGetAFreeTrunkByOut():integer;
//挂断指定通道
procedureHangOfByTrunkID(constaChannelID:integer);
//通过指定通道拨号
procedureDialPhoneByTrunkID(constaChannelID:integer;constphoneNumber,callerNumber:PChar;constaDevID:integer=-1);
//通过指定通道发送数据
functionSendStringByTrunkID(constaChannelID:integer;constsendBuffer:PChar):boolean;
end;

implementation

...{TDJCommCardSS1}
uses
unDJChannelSS1;

constructorTDJCommCardSS1.Create(
constaStateEvent:TTrunkSatausEvent;
constaRecEvent:TTrunkReceiveEvent);
begin
inheritedCreate(
true);
Self.FreeOnTerminate:
=true;
onTrunkEvent:
=aStateEvent;
onRecEvent:
=aRecEvent;
end;

destructorTDJCommCardSS1.Destroy();
begin
Self.Suspend();
Self.Terminate();
FreeCommCard();
end;

procedureTDJCommCardSS1.DialPhoneByTrunkID(
constaChannelID:integer;
constphoneNumber,callerNumber:PChar;constaDevID:integer);
begin
if(aChannelID>ErrTrunkId)and(DJTrk_CheckTrunkFree(aChannelID))then
TDJCommChannelsSS1(Trunks[aChannelID]).StartDialPhone(phoneNumber,callerNumber,aDevID,);
end;

procedureTDJCommCardSS1.Execute;
begin
whileNOTTerminateddo
begin
Synchronize(ThreadKernelProcess);
Sleep(
1);
end;
end;

procedureTDJCommCardSS1.FreeCardForFSK();
begin
ifCommIsFSKandisLoadFSKthen
begin
DJFsk_Release();
end;
end;

functionTDJCommCardSS1.FreeCommCard():boolean;
var
Loop:Word;
begin
Sleep(
1000);
ifTotalTrunkNum>0then
begin
forLoop:=0toTotalTrunkNum-1do
begin
ifAssigned(TDJCommChannelsSS1(Trunks[Loop]))then
begin
TDJCommChannelsSS1(Trunks[Loop]).Free();
TDJCommChannelsSS1(Trunks[Loop]):
=nil;
end;
end;
end;
DJSys_DisableCard();
FreeCardForFSK();
Result:
=true;
end;

functionTDJCommCardSS1.GetAFreeTrunkByOut():integer;
begin
Result:
=GetAFreeTrunkByType(Type_Export);
end;

functionTDJCommCardSS1.GetAFreeTrunkByType(
constaTrunkType:TTrunkType):integer;
var
Loop:Word;
begin
Result:
=ErrTrunkID;
forLoop:=0toTotalTrunkNum-1do
begin
if((TDJCommChannelsSS1(Trunks[Loop]).GetTrunkType()=aTrunkType)
and(DJTrk_CheckTrunkFree(Loop)))then
begin
Result:
=Loop;
break;
end;
end;
end;

procedureTDJCommCardSS1.HangOfByTrunkID(
constaChannelID:integer);
begin
TDJCommChannelsSS1(Trunks[aChannelID]).InOutHangOff();
end;

functionTDJCommCardSS1.InitCard(
constisFSKComm:boolean):Boolean;
const
PromptFile
='Prompt.ini';
var
Loop:Integer;
isOK:boolean;
TimeOfNow:SystemTime;
begin
Result:
=False;
CommIsFSK:
=isFSKComm;
isOK:
=(DJSys_EnableCard('',PromptFile)=_ERR_OK);
ifNotisOKthenexit;
isOK:
=InitCardForFSK();
ifNOTisOKthenExit;
isLoadFSK:
=isOK;
GetLocalTime(TimeOfNow);
DJSys_SetSysTime(TimeOfNow.wHour,TimeOfNow.wMinute,TimeOfNow.wSecond);
TotalTrunkNum:
=DJTrk_GetTotalTrunkNum();
InTrunkNum:
=TotalTrunkNumshr1;
OutTrunkNum:
=TotalTrunkNum-InTrunkNum;

SetLength(Trunks,TotalTrunkNum);
SetLength(TrunkConnected,TotalTrunkNum);

forLoop:=0toOutTrunkNum-1do
Trunks[Loop]:
=TDJCommChannelsSS1.Create(Self,Loop,Type_Export,CommIsFSK,onTrunkEvent,onRecEvent);
forLoop:=OutTrunkNumtoTotalTrunkNum-1do
Trunks[Loop]:
=TDJCommChannelsSS1.Create(Self,Loop,Type_Import,CommIsFSK,onTrunkEvent,onRecEvent);
forLoop:=0toTotalTrunkNum-1do
begin
TDJCommChannelsSS1(Trunks[Loop]).ClearTrunkBuffer(csReceiving);
end;

DJSys_AutoApplyDtmf(ENABLEDTMF);
//自动分配DTMF资源
DJSys_EnableAutoKB();//自动回送KB信号
isOK:=isOKandDJSys_EnableDtmfSend();
Result:
=isOK;
end;

functionTDJCommCardSS1.InitCardForFSK():boolean;
var
k:integer;
begin
Result:
=true;
ifCommIsFSKthen
begin
k:
=DJFsk_InitForFsk(SZK_Mode);
Result:
=(k=1);
end;
end;

functionTDJCommCardSS1.SendStringByTrunkID(
constaChannelID:integer;
constsendBuffer:PChar):boolean;
begin
Result:
=TDJCommChannelsSS1(Trunks[aChannelID]).SendString(sendBuffer);
end;

procedureTDJCommCardSS1.StartRunCommModule();
begin
Resume();
end;

procedureTDJCommCardSS1.ThreadKernelProcess();
var
Loop:Word;
begin
DJSys_PushPlay();
forLoop:=0toTotalTrunkNum-1do
begin
try
TDJCommChannelsSS1(Trunks[Loop]).DJChannelProcessor();
except
end;
end;
end;

end.

通道类源代码:

//------------------------------------------------------------------------------
//
//产品名称:成晓旭的个人软件Delphi源码库
//产品版本:CXXSoftdelphicodesourcelib2.0
//模块名称:Delphi之东进数字语音卡通道类
//模块描述:
//单元文件:unDJChannelSS1.pas
//开发作者:成晓旭
//作者blog:http://blog.csdn.net/CXXSoft
//备注:任何人使用此文件时,请保留此段自述文件,谢谢!
//开发时间:2005-01-09
//修改历史:
//修改描述:
//------------------------------------------------------------------------------
unitunDJChannelSS1;

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]ofChar;
msgChannel:TTrunkStatusInfo;
msgFrame:TRecCommFrame;

commFrameNumber,recPos:Word;
subStatus:TCXXStatus;
commPhone:
string;
commFrameStr:
string;

//应该进一步优化为注入的接口,非简单的回调句柄
onTrunkState:TTrunkSatausEvent;
onRecEvent:TTrunkReceiveEvent;
InOutType:TTrunkType;

functionSendDataFromTrunk():boolean;
functionCheckSendDataEnd():boolean;
procedureSaveMaxBufferToFrameStr();
procedureProcessConnected();
//注意:此方法与具体业务的通信协议存在严重依赖关系(IoC实现依赖反转)
functionCheckReceiveOverFSK(constdataBuffer:arrayofchar;constdataNumber:Word):boolean;
//注意:此方法与具体业务的通信协议存在严重依赖关系(IoC实现依赖反转)
functionCheckReceiveOverDTMF(constdataBuffer:arrayofchar;constdataNumber:Word):boolean;
functionGetCommData(
constdataBuffer:arrayofchar;constdataNumber:Word):string;
functionReceiveDataFromTrunk():boolean;

procedureInformChannelStatus(
constaStep:TTrunkStep;constlvof:TLVOperateFlag);
procedureInformBusinessStatus(
constaCommData:string;constcif:TCommInformFlag);
procedureInformDialStatus(
constaStep:TTrunkStep);
procedureInWaitingIntoToConnect();
functionGetCommFrameFromSendString(
constcommFrame:string):string;

procedureRegisterTrunkEvent(
consttrunkStateEvent:TTrunkSatausEvent);
procedureRegisterReceiveEvent(
consttrunkRecEvent:TTrunkReceiveEvent);
public

constructorCreate(
consttrunkController:TDJCommCardSS1;constTrkID:Integer;
constTrunkType:TTrunkType;constisFSKComm:boolean;
constaStateEvent:TTrunkSatausEvent;constaRecEvent:TTrunkReceiveEvent);
destructorDestroy;
override;

//获取通道状态
functionGetTrunkType():TTrunkType;
procedureDJChannelProcessor();
//通道挂机
procedureInOutHangOff();
//开始拨号
procedureStartDialPhone(constphoneNumber,callerNumber:PChar;constaDevID:integer=-1);
//发送通信数据
functionSendString(constpchSend:PChar):boolean;
//清空通道数据缓冲
procedureClearTrunkBuffer(constaSB:TCXXStatus);
//获取通道号
functionGetTrunkID():integer;
end;

implementation

...{TDJCommChannelsSS1}
const
Frame_FillChar
=#0;
Leader_Flag
=$55;
HeadNumber
=30;
hasLeader
=true;

functionTDJCommChannelsSS1.CheckSendDataEnd():boolean;
begin
Result:
=false;
ifCommIsFSKthen
begin
if(DJFsk_CheckSendFSKEnd(TrunkID,SZK_Mode)=1)then
begin
DJFsk_StopSend(TrunkID,SZK_Mode);
Result:
=true;
end;
end
else
begin
ifDJTrk_CheckDtmfSendEnd(TrunkID)then
begin
DJVoc_StopPlayFile(TrunkID);
Result:
=true;
end;
end;
ifResultthen
ClearTrunkBuffer(csReceiving);
end;

procedureTDJCommChannelsSS1.ClearTrunkBuffer(
constaSB:TCXXStatus);
begin
subStatus:
=aSB;
ifCommIsFSKthen
DJFsk_ResetFskBuffer(TrunkID,SZK_Mode)
else
DJTrk_InitDtmfBufNew(TrunkID);
commFrameNumber:
=0;
recPos:
=0;
end;

constructorTDJCommChannelsSS1.Create(
consttrunkController:TDJCommCardSS1;constTrkID:Integer;
constTrunkType:TTrunkType;constisFSKComm:boolean;
constaStateEvent:TTrunkSatausEvent;constaRecEvent:TTrunkReceiveEvent);
var
t:TTrunkType;
begin
inheritedCreate;
RegisterTrunkEvent(aStateEvent);
RegisterReceiveEvent(aRecEvent);
controller:
=trunkController;
TrunkID:
=TrkID;
commPhone:
='';
TrunkStep:
=TTrunkStep(-1);
t:
=TrunkType;
ifDJTrk_SetTrunkType(TrkID,t)then
InOutType:
=TrunkType;
CommIsFSK:
=isFSKComm;
controller.TrunkConnected[TrunkID]:
=false;
ClearTrunkBuffer(csReceiving);
InformChannelStatus(Step_Free,lvofAdd);
end;

destructorTDJCommChannelsSS1.Destroy();
begin
inherited;
DJTrk_BackwardHangUp(TrunkID);
end;

procedureTDJCommChannelsSS1.DJChannelProcessor();
var
aStep:TTrunkStep;
begin
//DJSys_PushPlay();
aStep:=DJTrk_GetTrunkStatus(TrunkID);
//状态变化
ifTrunkStep<>aStepthen
begin
TrunkStep:
=aStep;
InformChannelStatus(TrunkStep,lvofUpdate);
end;
//前向挂机
if(TrunkStep<>Step_Free)andDJTrk_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;
//出通道拨号失败
ifTrunkStep=Step_DialFailthen
begin
InformDialStatus(TrunkStep);
end;
ifTrunkStep=Step_Delaythen
Exit;
//出入通道空闲
ifTrunkStep=Step_Freethen
begin
//等待接收呼入
end;
end;

functionTDJCommChannelsSS1.GetTrunkID():integer;
begin
Result:
=Self.TrunkID;
end;

procedureTDJCommChannelsSS1.InformChannelStatus(
constaStep:TTrunkStep;constlvof:TLVOperateFlag);
begin
msgChannel.lvFlag:
=lvof;
msgChannel.TrunkID:
=IntToStr(Self.TrunkID);
msgChannel.DeviceID:
='';
msgChannel.TrunkTypeStr:
=TrunkTypeInStr[InOutType];
msgChannel.TrunkStep:
=Ord(aStep);
msgChannel.TrunkStepStr:
=TrunkStepInStr[aStep];
ifaStep=Step_Freethen
begin
msgChannel.Phone:
='';
msgChannel.Data:
='';
end
else
begin
msgChannel.Phone:
=commPhone;
msgChannel.Data:
=commFrameStr;
end;
ifAssigned(onTrunkState)then
onTrunkState(msgChannel);
end;

procedureTDJCommChannelsSS1.InformDialStatus(
constaStep:TTrunkStep);
var
dStatus:TDialStatus;
begin
dStatus:
=DJTrk_GetDialStatus(TrunkID);
casedStatusof
DS_Busy,DS_OverTime,DS_NoUser,DS_LineError:
begin
InOutHangOff();
end;
end;
end;

procedureTDJCommChannelsSS1.InformBusinessStatus(
constaCommData:string;constcif:TCommInformFlag);
begin
//依赖注入的业务处理接口调用,实现业务处理的
end;

procedureTDJCommChannelsSS1.InOutHangOff();
begin
DJTrk_BackwardHangUp(TrunkID);
controller.TrunkConnected[TrunkID]:
=false;
InformBusinessStatus(
'',cifDisconnected);
end;

procedureTDJCommChannelsSS1.InWaitingIntoToConnect;
begin
DJVoc_PlayFile(TrunkID,
'.Voicedtmf13');
DJVoc_StopPlayFile(TrunkID);
end;


procedureTDJCommChannelsSS1.ProcessConnected();
var
ss:TCXXStatus;
begin
ifNOTcontroller.TrunkConnected[TrunkID]then
begin
controller.TrunkConnected[TrunkID]:
=true;
ss:
=csReceiving;
InformBusinessStatus(
'',cifConnected);
ClearTrunkBuffer(ss);
end;
casesubStatusof
csSending:
begin
ifCheckSendDataEnd()then
begin
InformChannelStatus(Step_Connect,lvofUpdate);
InformBusinessStatus(commFrameStr,cifSend);
end;
end;
csReceiving:
begin
ifReceiveDataFromTrunk()then
begin
msgFrame.CommFrame:
=commFrameStr;
msgFrame.CommType:
=Comm_FSK;
InformChannelStatus(Step_Connect,lvofUpdate);
InformBusinessStatus(commFrameStr,cifReceive);
end;
end;
csPlaying:
begin

end;
end;
end;

functionTDJCommChannelsSS1.ReceiveDataFromTrunk():boolean;
var
num,Loop:integer;
tempBuffer:array[
0..DTMF_BUFFER_SIZE-1]ofChar;
begin
Result:
=false;
try
ifSelf.CommIsFSKthen
begin
//FSK方式版本
FillChar(tempBuffer,DTMF_BUFFER_SIZE,Frame_FillChar);
num:
=DJFsk_GetFSK(TrunkID,tempBuffer,SZK_MODE);
if(num>0)then
begin
ifCheckReceiveOverFSK(tempBuffer,num)then
begin
Self.commFrameStr:
=GetCommData(tempBuffer,num);
Self.ClearTrunkBuffer(csReceiving);
Result:
=true;
end;
end;
end
else
begin
//DTMF方式版本
num:=DJTrk_GetReceiveDtmfNumNew(TrunkID);
ifnum>0then
begin
forLoop:=0tonum-1do
begin
MaxBuffer[recPos
+Loop]:=DJTrk_GetDtmfCodeNew(TrunkID);
recPos:
=(recPos+1)modDTMF_BUFFER_SIZE;
end;
Inc(commFrameNumber,num);
ifCheckReceiveOverDTMF(tempBuffer,num)then
begin
ClearTrunkBuffer(csReceiving);
Result:
=true;
end;
end;
end;
except
Result:
=false;
end;
end;

procedureTDJCommChannelsSS1.RegisterReceiveEvent(
consttrunkRecEvent:TTrunkReceiveEvent);
begin
onRecEvent:
=trunkRecEvent;
end;

procedureTDJCommChannelsSS1.RegisterTrunkEvent(
consttrunkStateEvent:TTrunkSatausEvent);
begin
onTrunkState:
=trunkStateEvent;
end;

procedureTDJCommChannelsSS1.SaveMaxBufferToFrameStr();
var
Loop:Word;
begin
commFrameStr:
='';
forLoop:=0tocommFrameNumber-1do
begin
commFrameStr:
=commFrameStr+MaxBuffer[Loop];
end;
end;

functionTDJCommChannelsSS1.SendDataFromTrunk():boolean;
begin
Result:
=false;
ifcontroller.TrunkConnected[TrunkID]then
begin
ifCommIsFSKthen
begin
Result:
=DJFsk_SendFSK(TrunkID,@MaxBuffer[0],commFrameNumber,SZK_Mode)=1;
end
else
begin
Result:
=DJTrk_SendDtmfStr(TrunkID,@MaxBuffer[0])=1;
end;
end;
ifResultthen
subStatus:
=csSending;
end;

functionTDJCommChannelsSS1.SendString(
constpchSend:PChar):boolean;
var
Loop:integer;
strTemp:
string;
begin
Result:
=false;
ifSelf.CommIsFSKandhasLeaderthen
begin
//加FSK前导字符的版本
strTemp:=GetCommFrameFromSendString(pchSend);
commFrameNumber:
=Length(strTemp);
ifcommFrameNumber>0then
begin
forLoop:=0tocommFrameNumber-1do
MaxBuffer[Loop]:
=strTemp[Loop+1];
MaxBuffer[commFrameNumber]:
=#0;
SaveMaxBufferToFrameStr();
Result:
=SendDataFromTrunk();
end;
end
else
begin
//不加前导字符的版本
commFrameNumber:=Length(pchSend);
ifcommFrameNumber>0then
begin
forLoop:=0tocommFrameNumber-1do
MaxBuffer[Loop]:
=pchSend[Loop];
MaxBuffer[commFrameNumber]:
=#0;
SaveMaxBufferToFrameStr();
Result:
=SendDataFromTrunk();
end;
end;
end;

procedureTDJCommChannelsSS1.StartDialPhone(
constphoneNumber,
callerNumber:PChar;
constaDevID:integer);
begin
ifDJTrk_CheckTrunkFree(TrunkID)and(Trim(phoneNumber)<>'')then
begin
commPhone:
=Trim(phoneNumber);
DJTrk_StartDial(TrunkID,PChar(commPhone),
'');
end;
end;

functionTDJCommChannelsSS1.CheckReceiveOverFSK(
constdataBuffer:arrayofchar;
constdataNumber:Word):boolean;
begin
//业务实现方法:判定通信帧串发送结束
Result:=true;
end;

functionTDJCommChannelsSS1.GetCommData(
constdataBuffer:arrayofchar;
constdataNumber:Word):string;
var
Loop:Word;
begin
Result:
='';
ifdataNumber<=0thenExit;
forLoop:=0todataNumber-1do
begin
if(dataBuffer[Loop]<>Frame_FillChar)then
Result:
=Result+dataBuffer[Loop];
end;
end;

functionTDJCommChannelsSS1.GetCommFrameFromSendString(
constcommFrame:string):string;
var
Loop:integer;
begin
Result:
=commFrame;
forLoop:=0toHeadNumber-1do
Result:
=CHR(Leader_Flag)+Result;
end;

functionTDJCommChannelsSS1.CheckReceiveOverDTMF(
constdataBuffer:arrayofchar;constdataNumber:Word):boolean;
begin
//业务实现方法:判定通信帧串发送结束
Result:=true;
end;

functionTDJCommChannelsSS1.GetTrunkType():TTrunkType;
begin
Result:
=Self.InOutType;
end;

end.

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics