Delphi之東進數字語音卡(SS1)可複用原始碼
Delphi之東進數字語音卡(SS1)可複用原始碼
作者:成曉旭
Blog:http://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之東進數字語音卡類
// 模組描述:
// 單元檔案: 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.
//
// 產品名稱: 成曉旭的個人軟體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
相關文章
- Delphi之東進模擬語音卡(D160A)可複用原始碼原始碼
- Delphi之三匯模擬語音卡(SHT-8B/PCI/FAX)可複用原始碼原始碼
- delphi成功進銷存 原始碼500元原始碼
- 卡馬克:用C++進行函數語言程式設計C++函數程式設計
- bootstrap原始碼分析之tab(選項卡)boot原始碼
- 語音直播系統原始碼開發語音直播系統部署搭建原始碼
- [轉]delphi 有授權許可的字串拷貝函式原始碼字串函式原始碼
- 數字藏品系統開發(數字藏品APP原始碼)APP原始碼
- 用Delphi進行word開發
- 教你用Excel進行語音校對Excel
- AI語音:ChatTTS 真有點東西啊!AITTS
- 數字交易所原始碼大全原始碼
- 語音訊號預處理——數字濾波器音訊
- VS2005入門之建立可複用的程式碼 – 概述
- HackingTeam原始碼洩漏——語音監控分析原始碼
- 語音聊天系統原始碼有哪些特色功能原始碼
- 語音聊天系統原始碼如何才能快速搭建原始碼
- 語音陪玩原始碼如何做到不卡頓?原始碼
- 企業髮卡網原始碼_知宇髮卡系統原始碼原始碼
- NEO從原始碼分析看數字資產原始碼
- 可複用程式碼:元件的來龍去脈元件
- [劍之offer] 03 陣列中重複的數字陣列
- 用語音寫程式碼比鍵盤更快
- 語音直播系統原始碼與視訊直播系統原始碼哪些區別原始碼
- 打造MyGetProcAddress函式(Delphi原始碼)函式原始碼
- 華為CMPP原始碼delphi6版 (轉)原始碼
- 機器學習之語音生成&&音樂生成機器學習
- UITableView的Cell複用原理和原始碼分析UIView原始碼
- 【設計模式】介面卡模式以及原始碼應用設計模式原始碼
- 匹配指定位數不重複數字
- 用樹型模型管理App數字和紅點提示(附原始碼Demo)模型APP原始碼
- 個人髮卡網原始碼_個人髮卡網原始碼最新版下載原始碼
- js生成不重複數字陣列程式碼例項JS陣列
- 數字藏品開發(上線版)丨數字藏品系統開發(NFT數字藏品原始碼)原始碼
- 支援語音識別、自然語言理解的微信小程式(“遙知之”智慧小祕)完整原始碼分享微信小程式原始碼
- 抓住機遇: 數字創新促進可持續未來
- 機器配音微信小程式原始碼 多種語音任微信小程式原始碼
- C語言“字串-數字”之間的轉換C語言字串