Delphi之東進模擬語音卡(D160A)可複用原始碼
作者:成曉旭
Blog:http://blog.csdn.net/cxxsoft
(宣告:歡迎轉載,請保證文章的完整性)
設計簡介:
1、 將卡、通道分別單獨進行設計與封裝。
2、 所有的外部操作介面都封裝在卡類這一類。
3、 在我的專案中,在卡類這一級還增加了介面卡或者代理,分別實現了Adapter或Proxy模式;以儘可能地解耦卡裝置的實現細節與具體應用業務之間的關係。因為,我們的系統中使用了幾家不同的卡裝置,另一方面,這些卡裝置,在不同的軟體系統中,又有不同的業務應用需求。
4、 當然,卡這一級,也可以實現一個統一的介面,這樣對外部可以表現出相對統一的行為,以方便業務層程式碼的呼叫,比如說:在資料採集的應用中,統一的介面可以讓採集控制層不必依賴於具體的採集裝置和通訊方式,可以一致地實現資料收發,不管通訊方式是RS232、RS485、TCP/IP、PSTN,還是別的方式或者通訊裝置。
5、 在通道設計中,核心的就是一個“狀態機模式”,通過輪巡通道狀態來管理硬體卡裝置,並且,還自己設計了一個業務級的“業務狀態機”,來抽象業務方面需要關心的“業務狀態”,通過增加“業務狀態機”這樣一箇中間層,以解耦業務狀態與裝置狀態之間的依賴。(這一點,在我看到的所有卡廠商提供的各類Demo程式裡面都沒有這樣做,這也無形中誤導了很多的開發人員,我看到的所有應用軟體開發的原始碼都是:裝置細節、尤其是通道狀態,與業務邏輯程式碼緊緊地耦合在一起,難解難分)。
6、 此設計的另一個亮點是:IoC模式的應用(2004年自己在設計此類時還不知道這個概念,全憑自己的經驗總結出這樣的設計)。對通道進入“呼入成功”、“撥出成功”等業務狀態的呼叫程式碼從通道類是解耦出來:設計一個介面,在各個業務狀態的處理方法中,再呼叫介面方法,將具體的業務處理邏輯委託給實現此介面的物件。並且這個介面的實現是通過“依賴注入”實現IoC的。這樣設計,就達到了很好的可複用性和靈活性。
7、 當然,更好的實現可以採用AOP(面向方法程式設計)的思想或者實現技術,這樣可複用性更好,如此設計,在業務與卡方法的呼叫之間,耦合度將是最低的。
8、 目前的版本,沒有在程式碼中體現介面的實現……
9、 類圖(以後補上):
10、卡類原始碼:
//
// 產品名稱: 成曉旭的個人軟體Delphi原始碼庫
// 產品版本: CXXSoft delphi code source lib 2.0
// 模組名稱: Delphi之東進模擬語音卡類
// 模組描述:
// 單元檔案: unDJCard160A.pas
// 開發作者: 成曉旭
// 備註: 任何人使用此檔案時,請保留此段自述檔案,謝謝!
// 開發時間: 2004-08-03
// 修改歷史:
// 修改描述:
//------------------------------------------------------------------------------
unit unDJCard160A;
interface
uses
Windows,
unDJTC08a32,unDJNewSig,
unBaseDefine,unDJ160ADefine,
unDJChanne160A;
type
TCXXCommCard160A = class(TObject)
private
ChannelNumber:Word;
channelObject:array of TCXXDJChannel160A;
OnCardChannelState:TTrunkStatusEvent;
procedure Stop();
procedure ReleaseCommDevice();
function GetChannelObjectOrder(const aChannelID:Word):Word;
public
constructor Create(const trunkEvent:TTrunkStatusEvent);
destructor Destroy(); override;
function LoadCommDevice(const loadAll:boolean=false):boolean;
function Startup():boolean;
function GetAFreeChannel():Word;
function GetChannelNumber():Word;
function DialPhone(const aChannelID:Word;const DialPhoneNumber:PChar):boolean;
function HangUp(const aChannelID:Word):boolean;
end;
implementation
{ TCXXCommCard160A }
constructor TCXXCommCard160A.Create(const trunkEvent:TTrunkStatusEvent);
begin
ChannelNumber := 0;
Self.OnCardChannelState := trunkEvent;
end;
destructor TCXXCommCard160A.Destroy;
var
Loop:Word;
begin
Stop();
if (Length(channelObject) > 0) and (channelNumber > 0) then
begin
for Loop := 0 to ChannelNumber - 1 do
begin
if Assigned(channelObject[Loop]) then
begin
channelObject[Loop].Free();
channelObject[Loop] := nil;
end;
end;
end;
ReleaseCommDevice();
end;
function TCXXCommCard160A.DialPhone(const aChannelID: Word;
const DialPhoneNumber: PChar): boolean;
var
K:Word;
begin
Result := false;
K := GetChannelObjectOrder(aChannelID);
if (K <> ErrorTrunkNumber) and (Assigned(channelObject[K])) then
begin
Result := channelObject[K].DialPhone(DialPhoneNumber);
end;
end;
procedure TCXXCommCard160A.ReleaseCommDevice();
begin
DisableCard();
FreeDrv();
end;
function TCXXCommCard160A.GetAFreeChannel(): Word;
var
Loop:Word;
begin
Result := ErrorTrunkNumber;
for Loop := Low(channelObject) to High(channelObject) do
begin
if (channelObject[Loop].GetChannelType() = ctEmpty) then continue;
if (channelObject[Loop].GetChannelStatus() = atsFree) then
begin
Result := channelObject[Loop].GetChannelID();
break;
end;
end;
end;
function TCXXCommCard160A.GetChannelNumber(): Word;
begin
Result := channelNumber;
end;
function TCXXCommCard160A.GetChannelObjectOrder(
const aChannelID: Word): Word;
var
Loop:Word;
begin
Result := ErrorTrunkNumber;
for Loop := Low(channelObject) to High(channelObject) do
begin
if (channelObject[Loop].GetChannelID = aChannelID) then
begin
Result := Loop;
break;
end;
end;
end;
function TCXXCommCard160A.HangUp(const aChannelID: Word): boolean;
var
K:Word;
begin
Result := false;
K := GetChannelObjectOrder(aChannelID);
if (K <> ErrorTrunkNumber) and (Assigned(channelObject[K])) then
begin
channelObject[K].ChannelHangUp();
Result := true;
end;
end;
function TCXXCommCard160A.LoadCommDevice(const loadAll:boolean): boolean;
const
loadEmpty = true;
var
Loop,tempNumber:Word;
isFlag:LongInt;
function CheckLoadTrunk():boolean;
begin
Result := loadAll or ((NOT loadAll) and(TChannelType(CheckChType(Loop)) <> ctEmpty));
end;
begin
isFlag := LoadDRV();
Result := (isFlag=0);
if NOT Result then Exit;
tempNumber := CheckValidCh();
Result := EnableCard(tempNumber,1024*8)=0;
if NOT Result then
begin
FreeDrv();
Exit;
end;
Result := Sig_Init()=1;
if NOT Result then Exit;
SetBusyPara(700);
SetPackRate(PACK_64KBPS );
channelNumber := tempNumber;
SetLength(channelObject,channelNumber);
for Loop := 0 to channelNumber - 1 do
begin
if CheckLoadTrunk() then
begin
channelObject[Loop] := TCXXDJChannel160A.Create(OnCardChannelState);
channelObject[Loop].CreateCommChannel(Loop);
end;
end;
end;
function TCXXCommCard160A.Startup(): boolean;
var
Loop:integer;
begin
for Loop := 0 to channelNumber - 1 do
begin
channelObject[Loop].Resume();
end;
Result := true;
end;
procedure TCXXCommCard160A.Stop();
var
Loop:integer;
begin
for Loop := 0 to channelNumber - 1 do
begin
channelObject[Loop].Suspend();
channelObject[Loop].Terminate();
channelObject[Loop] := nil;
end;
end;
end.
//
// 產品名稱: 成曉旭的個人軟體Delphi原始碼庫
// 產品版本: CXXSoft delphi code source lib 2.0
// 模組名稱: Delphi之東進模擬語音卡通道類
// 模組描述:
// 單元檔案: unDJChanne160A.pas
// 開發作者: 成曉旭
// 備註: 任何人使用此檔案時,請保留此段自述檔案,謝謝!
// 開發時間: 2004-08-03
// 修改歷史:
// 修改描述:
//------------------------------------------------------------------------------
unit unDJChanne160A;
interface
uses
Windows,Classes,SysUtils,
unBaseDefine,unDJ160ADefine,
unDJTC08a32,unDJNewSig;
Type
TCXXDJChannel160A = class(TThread)
//TCXXDJChannel160A = class(TObject)
private
channelType:TChannelType;
oldChannelState,channelState:TTrunkState;
channelID:Word;
phoneNumber:string;
dtmfString:string;
isConntectd:boolean;
isDialOut:boolean;
aTrunkState:TTrunkStatus;
procedure InformTrunkStatus(const aMsgFlag: TLVOperateFlag);
procedure ClearTrunkStatus();
function CheckSigHangup():boolean;
function CheckCallIn():boolean;
function SwitchOnCallIn():boolean;
procedure ProcessCallInSuccess();
procedure ProcessDialSuccess();
procedure ProcessCheckDialSend();
protected
procedure Execute(); override;
public
strMessage:string;
OnChannelState:TTrunkStatusEvent;
constructor Create(const trunkEvent:TTrunkStatusEvent);
destructor Destroy();override;
procedure CreateCommChannel(const aChennelID: Word);
procedure ChannelProcessor();
function GetChannelID():Word;
function GetChannelStatus():TTrunkState;
function GetChannelType():TChannelType;
function DialPhone(const DialPhoneNumber:PChar):boolean;overload;
function DialPhone(const DialPhoneNumber:PChar;const PreDialNumber:PChar):boolean;overload;
procedure ChannelHangUp();
function GetDialOut():boolean;
end;
implementation
{ TCXXDJChannel160A }
procedure TCXXDJChannel160A.ChannelHangUp();
begin
isDialOut := false;
StopSigCheck(channelID);
HangUp(channelID);
Sig_ResetCheck(channelID);
StartSigCheck(channelID);
InitDTMFBuf(channelID);
ClearTrunkStatus();
InformTrunkStatus(lvofUpdate);
end;
procedure TCXXDJChannel160A.ChannelProcessor();
var
dState:Word;
begin
PUSH_PLAY();
FeedSigFunc();
CheckCallIn();
case channelState of
atsFree:
begin
//
end;
atsCallIning:
begin
SwitchOnCallIn();
end;
atsCallInSuccess:
begin
if CheckSigHangup() then Exit;
ProcessCallInSuccess();
end;
atsCheckSendDial:
begin
ProcessCheckDialSend();
end;
atsDialing:
begin
dState := Sig_CheckDial(channelID);
case dState of
// S_NORESULT:
S_CONNECT:
begin
channelState := atsDialSuccess;
isConntectd := true;
end;
S_BUSY,
S_NOBODY,
S_NODIALSIG,
S_NOSIGNAL:
begin
channelState := atsHangOff;
end;
end;
strMessage := '撥號中...';
end;
atsDialSuccess:
begin
if CheckSigHangup() then Exit;
ProcessDialSuccess();
strMessage := '撥號成功';
end;
atsHangOff:
begin
ChannelHangUp();
end;
end;
if (oldChannelState <> channelState) then
begin
oldChannelState := channelState;
InformTrunkStatus(lvofUpdate);
end;
end;
function TCXXDJChannel160A.CheckCallIn(): boolean;
begin
Result := RingDetect(channelID);
if Result then
begin
OffHook(channelID);
if isDialOut then
channelState := atsDialSuccess
else
channelState := atsCallIning;
end;
end;
function TCXXDJChannel160A.CheckSigHangup(): boolean;
begin
Result := false;
if (Sig_CheckBusy(channelID)=1) then
begin
strMessage := '對方已掛機';
InformTrunkStatus(lvofUpdate);
StopPlayFile(channelID);
channelState := atsHangOff;
Result := true;
end;
end;
procedure TCXXDJChannel160A.ClearTrunkStatus();
begin
channelState := atsFree;
oldChannelState := channelState;
phoneNumber := '';
dtmfString := '';
strMessage := '';
isConntectd := false;
end;
constructor TCXXDJChannel160A.Create(const trunkEvent:TTrunkStatusEvent);
begin
Self.OnChannelState := trunkEvent;
Self.FreeOnTerminate := true;
inherited Create(true);
end;
destructor TCXXDJChannel160A.Destroy;
begin
Suspend();
ChannelHangUp();
//inherited Destroy();
end;
function TCXXDJChannel160A.DialPhone(const DialPhoneNumber:PChar;
const PreDialNumber:PChar): boolean;
begin
isDialOut := true;
phoneNumber := DialPhoneNumber;
OffHook(channelID);
InitDTMFBuf(channelID);
Result := Sig_StartDial(channelID,DialPhoneNumber,PreDialNumber,0)=1;
channelState := atsCheckSendDial;
end;
function TCXXDJChannel160A.DialPhone(
const DialPhoneNumber: PChar): boolean;
begin
Result := DialPhone(DialPhoneNumber,'');
end;
procedure TCXXDJChannel160A.Execute;
begin
while NOT Terminated do
begin
Synchronize(ChannelProcessor);
Sleep(10);
end;
end;
function TCXXDJChannel160A.GetChannelID(): Word;
begin
Result := channelID;
end;
function TCXXDJChannel160A.GetChannelStatus(): TTrunkState;
begin
Result := channelState;
end;
procedure TCXXDJChannel160A.InformTrunkStatus(const aMsgFlag: TLVOperateFlag);
begin
aTrunkState.lvFlag := aMsgFlag;
aTrunkState.TrunkID := IntToStr(channelID);
aTrunkState.TrunkType := channelType;
aTrunkState.TrunkTypeStr := ChannelTypeString[channelType];
aTrunkState.TrunkStep := channelState;
aTrunkState.TrunkStepStr := TrunkStateString[channelState];
aTrunkState.TrunkPhone := phoneNumber;
aTrunkState.TrunkData := dtmfString;
OnChannelState(aTrunkState);
end;
procedure TCXXDJChannel160A.ProcessCallInSuccess();
begin
end;
function TCXXDJChannel160A.SwitchOnCallIn(): boolean;
begin
OffHook(channelID);
InitDTMFBuf(channelID);
StartSigCheck(channelID);
channelState := atsCallInSuccess;
Result := true;
end;
procedure TCXXDJChannel160A.ProcessDialSuccess();
begin
end;
procedure TCXXDJChannel160A.CreateCommChannel(const aChennelID: Word);
begin
channelID := aChennelID;
channelType := TChannelType(CheckChType(channelID));
ClearTrunkStatus();
InformTrunkStatus(lvofAdd);
end;
function TCXXDJChannel160A.GetChannelType(): TChannelType;
begin
Result := channelType;
end;
function TCXXDJChannel160A.GetDialOut(): boolean;
begin
Result := isDialOut;
end;
procedure TCXXDJChannel160A.ProcessCheckDialSend();
begin
if(CheckSendEnd(channelID) = 1) then
begin
StartSigCheck(channelID);
channelState := atsDialing;
end;
end;
end.
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1108211
相關文章
- Delphi之東進數字語音卡(SS1)可複用原始碼原始碼
- Delphi之三匯模擬語音卡(SHT-8B/PCI/FAX)可複用原始碼原始碼
- 用 DELPHI 為 WINDOWS 做一個帶聲音的模擬鬧鐘 (轉)Windows
- 【原始碼】使用MATLAB進行ECG模擬原始碼Matlab
- 如何用python模擬點選進行重複話語?Python
- delphi成功進銷存 原始碼500元原始碼
- 人工智慧語音機器人如何完美模模擬人語調?人工智慧機器人
- COST231-WI模型通道模擬,原始碼模擬matlab程式設計原始碼模型原始碼Matlab程式設計
- React Hooks 原始碼模擬與解讀ReactHook原始碼
- JavaScript進階之模擬new Object()過程JavaScriptObject
- JavaScript進階之模擬new Object過程JavaScriptObject
- win10手機模擬器卡怎麼辦_win10手機模擬器卡頓嚴重修複方法Win10
- bootstrap原始碼分析之tab(選項卡)boot原始碼
- Gem Mod音訊模擬工具音訊
- 原始碼分析axios(1)~原始碼分析、模擬axios的建立原始碼iOS
- JavaScript進階之模擬call,apply和bindJavaScriptAPP
- 語音直播系統原始碼開發語音直播系統部署搭建原始碼
- [轉]delphi 有授權許可的字串拷貝函式原始碼字串函式原始碼
- 【向重複工作說不】c#之模擬滑鼠操作C#
- 蒙特卡羅模擬技術 (轉載)
- 用Delphi進行word開發
- Saber電源模擬之——基礎應用
- AI語音:ChatTTS 真有點東西啊!AITTS
- 教你用Excel進行語音校對Excel
- C語言50題之模擬實現atof、atoiC語言
- elixir模擬ruby快速複製字串字串
- VS2005入門之建立可複用的程式碼 – 概述
- 對於複雜系統只能採用模擬性建模? - Cilliers
- Security8:許可權模擬
- HackingTeam原始碼洩漏——語音監控分析原始碼
- 語音聊天系統原始碼有哪些特色功能原始碼
- 語音聊天系統原始碼如何才能快速搭建原始碼
- 語音陪玩原始碼如何做到不卡頓?原始碼
- Python運用蒙特卡洛演算法模擬植物生長Python演算法
- 企業髮卡網原始碼_知宇髮卡系統原始碼原始碼
- 通過模擬vuex的核心原始碼快速掌握其原理Vue原始碼
- 【原始碼】基於MPPT的光伏(PV)系統模擬原始碼
- 無線自組網AODV路由機制模擬原始碼路由原始碼