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