<iframe align="top" marginwidth="0" marginheight="0" src="http://www.zealware.com/csdnblog01.html" frameborder="0" width="728" scrolling="no" height="90"></iframe>
Delphi之東進(jìn)模擬語(yǔ)音卡(D160A)可復(fù)用源碼
作者:成曉旭
Blog
:
http://blog.csdn.net/cxxsoft
(
聲明:歡迎轉(zhuǎn)載,請(qǐng)保證文章的完整性
)
設(shè)計(jì)簡(jiǎn)介:
1、
將卡、通道分別單獨(dú)進(jìn)行設(shè)計(jì)與封裝。
2、
所有的外部操作接口都封裝在卡類這一類。
3、
在我的項(xiàng)目中,在卡類這一級(jí)還增加了適配器或者代理,分別實(shí)現(xiàn)了
Adapter
或
Proxy
模式;以盡可能地解耦卡設(shè)備的實(shí)現(xiàn)細(xì)節(jié)與具體應(yīng)用業(yè)務(wù)之間的關(guān)系。因?yàn)椋覀兊南到y(tǒng)中使用了幾家不同的卡設(shè)備,另一方面,這些卡設(shè)備,在不同的軟件系統(tǒng)中,又有不同的業(yè)務(wù)應(yīng)用需求。
4、
當(dāng)然,卡這一級(jí),也可以實(shí)現(xiàn)一個(gè)統(tǒng)一的接口,這樣對(duì)外部可以表現(xiàn)出相對(duì)統(tǒng)一的行為,以方便業(yè)務(wù)層代碼的調(diào)用,比如說(shuō):在數(shù)據(jù)采集的應(yīng)用中,統(tǒng)一的接口可以讓采集控制層不必依賴于具體的采集設(shè)備和通信方式,可以一致地實(shí)現(xiàn)數(shù)據(jù)收發(fā),不管通信方式是
RS232
、
RS485
、
TCP/IP
、
PSTN
,還是別的方式或者通信設(shè)備。
5、
在通道設(shè)計(jì)中,核心的就是一個(gè)“狀態(tài)機(jī)模式”,通過(guò)輪巡通道狀態(tài)來(lái)管理硬件卡設(shè)備,并且,還自己設(shè)計(jì)了一個(gè)業(yè)務(wù)級(jí)的“業(yè)務(wù)狀態(tài)機(jī)”,來(lái)抽象業(yè)務(wù)方面需要關(guān)心的“業(yè)務(wù)狀態(tài)”,通過(guò)增加“業(yè)務(wù)狀態(tài)機(jī)”這樣一個(gè)中間層,以解耦業(yè)務(wù)狀態(tài)與設(shè)備狀態(tài)之間的依賴。
(
這一點(diǎn),在我看到的所有卡廠商提供的各類
Demo
程序里面都沒(méi)有這樣做,這也無(wú)形中誤導(dǎo)了很多的開(kāi)發(fā)人員,我看到的所有應(yīng)用軟件開(kāi)發(fā)的源碼都是:設(shè)備細(xì)節(jié)、尤其是通道狀態(tài),與業(yè)務(wù)邏輯代碼緊緊地耦合在一起,難解難分
)
。
6、
此設(shè)計(jì)的另一個(gè)亮點(diǎn)是:
IoC
模式的應(yīng)用
(2004
年自己在設(shè)計(jì)此類時(shí)還不知道這個(gè)概念,全憑自己的經(jīng)驗(yàn)總結(jié)出這樣的設(shè)計(jì)
)
。對(duì)通道進(jìn)入“呼入成功”、“呼出成功”等業(yè)務(wù)狀態(tài)的調(diào)用代碼從通道類是解耦出來(lái):設(shè)計(jì)一個(gè)接口,在各個(gè)業(yè)務(wù)狀態(tài)的處理方法中,再調(diào)用接口方法,將具體的業(yè)務(wù)處理邏輯委托給實(shí)現(xiàn)此接口的對(duì)象。并且這個(gè)接口的實(shí)現(xiàn)是通過(guò)“依賴注入”實(shí)現(xiàn)
IoC
的。這樣設(shè)計(jì),就達(dá)到了很好的可復(fù)用性和靈活性。
7、
當(dāng)然,更好的實(shí)現(xiàn)可以采用
AOP(
面向方法編程
)
的思想或者實(shí)現(xiàn)技術(shù),這樣可復(fù)用性更好,如此設(shè)計(jì),在業(yè)務(wù)與卡方法的調(diào)用之間,耦合度將是最低的。
8、
目前的版本,沒(méi)有在代碼中體現(xiàn)接口的實(shí)現(xiàn)
……
9、
類圖
(
以后補(bǔ)上
)
:
10、卡類源碼:
//
------------------------------------------------------------------------------
//
//
產(chǎn)品名稱:成曉旭的個(gè)人軟件Delphi源碼庫(kù)
//
產(chǎn)品版本:CXXSoftdelphicodesourcelib2.0
//
模塊名稱:Delphi之東進(jìn)模擬語(yǔ)音卡類
//
模塊描述:
//
單元文件:unDJCard160A.pas
//
開(kāi)發(fā)作者:成曉旭
//
備注:任何人使用此文件時(shí),請(qǐng)保留此段自述文件,謝謝!
//
開(kāi)發(fā)時(shí)間:2004-08-03
//
修改歷史:
//
修改描述:
//
------------------------------------------------------------------------------
unitunDJCard160A;
interface
uses
Windows,
unDJTC08a32,unDJNewSig,
unBaseDefine,unDJ160ADefine,
unDJChanne160A;
type
TCXXCommCard160A
=
class
(TObject)
private
ChannelNumber:Word;
channelObject:arrayofTCXXDJChannel160A;
OnCardChannelState:TTrunkStatusEvent;
procedureStop();
procedureReleaseCommDevice();
functionGetChannelObjectOrder(
const
aChannelID:Word):Word;
public
constructorCreate(
const
trunkEvent:TTrunkStatusEvent);
destructorDestroy();
override
;
functionLoadCommDevice(
const
loadAll:boolean
=
false
):boolean;
functionStartup():boolean;
functionGetAFreeChannel():Word;
functionGetChannelNumber():Word;
functionDialPhone(
const
aChannelID:Word;
const
DialPhoneNumber:PChar):boolean;
functionHangUp(
const
aChannelID:Word):boolean;
end;
implementation
...
{TCXXCommCard160A}
constructorTCXXCommCard160A.Create(
const
trunkEvent:TTrunkStatusEvent);
begin
ChannelNumber:
=
0
;
Self.OnCardChannelState:
=
trunkEvent;
end;
destructorTCXXCommCard160A.Destroy;
var
Loop:Word;
begin
Stop();
if
(Length(channelObject)
>
0
)and(channelNumber
>
0
)then
begin
for
Loop:
=
0
toChannelNumber
-
1
do
begin
if
Assigned(channelObject[Loop])then
begin
channelObject[Loop].Free();
channelObject[Loop]:
=
nil;
end;
end;
end;
ReleaseCommDevice();
end;
functionTCXXCommCard160A.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;
procedureTCXXCommCard160A.ReleaseCommDevice();
begin
DisableCard();
FreeDrv();
end;
functionTCXXCommCard160A.GetAFreeChannel():Word;
var
Loop:Word;
begin
Result:
=
ErrorTrunkNumber;
for
Loop:
=
Low(channelObject)toHigh(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;
functionTCXXCommCard160A.GetChannelNumber():Word;
begin
Result:
=
channelNumber;
end;
functionTCXXCommCard160A.GetChannelObjectOrder(
const
aChannelID:Word):Word;
var
Loop:Word;
begin
Result:
=
ErrorTrunkNumber;
for
Loop:
=
Low(channelObject)toHigh(channelObject)
do
begin
if
(channelObject[Loop].GetChannelID
=
aChannelID)then
begin
Result:
=
Loop;
break
;
end;
end;
end;
functionTCXXCommCard160A.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;
functionTCXXCommCard160A.LoadCommDevice(
const
loadAll:boolean):boolean;
const
loadEmpty
=
true
;
var
Loop,tempNumber:Word;
isFlag:LongInt;
functionCheckLoadTrunk():boolean;
begin
Result:
=
loadAllor((NOTloadAll)and(TChannelType(CheckChType(Loop))
ctEmpty));
end;
begin
isFlag:
=
LoadDRV();
Result:
=
(isFlag
=
0
);
if
NOTResultthenExit;
tempNumber:
=
CheckValidCh();
Result:
=
EnableCard(tempNumber,
1024
*
8
)
=
0
;
if
NOTResultthen
begin
FreeDrv();
Exit;
end;
Result:
=
Sig_Init()
=
1
;
if
NOTResultthenExit;
SetBusyPara(
700
);
SetPackRate(PACK_64KBPS);
channelNumber:
=
tempNumber;
SetLength(channelObject,channelNumber);
for
Loop:
=
0
tochannelNumber
-
1
do
begin
if
CheckLoadTrunk()then
begin
channelObject[Loop]:
=
TCXXDJChannel160A.Create(OnCardChannelState);
channelObject[Loop].CreateCommChannel(Loop);
end;
end;
end;
functionTCXXCommCard160A.Startup():boolean;
var
Loop:integer;
begin
for
Loop:
=
0
tochannelNumber
-
1
do
begin
channelObject[Loop].Resume();
end;
Result:
=
true
;
end;
procedureTCXXCommCard160A.Stop();
var
Loop:integer;
begin
for
Loop:
=
0
tochannelNumber
-
1
do
begin
channelObject[Loop].Suspend();
channelObject[Loop].Terminate();
channelObject[Loop]:
=
nil;
end;
end;
end.
11、
通道類源碼:
//
------------------------------------------------------------------------------
//
//
產(chǎn)品名稱:成曉旭的個(gè)人軟件Delphi源碼庫(kù)
//
產(chǎn)品版本:CXXSoftdelphicodesourcelib2.0
//
模塊名稱:Delphi之東進(jìn)模擬語(yǔ)音卡通道類
//
模塊描述:
//
單元文件:unDJChanne160A.pas
//
開(kāi)發(fā)作者:成曉旭
//
備注:任何人使用此文件時(shí),請(qǐng)保留此段自述文件,謝謝!
//
開(kāi)發(fā)時(shí)間:2004-08-03
//
修改歷史:
//
修改描述:
//
------------------------------------------------------------------------------
unitunDJChanne160A;
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;
procedureInformTrunkStatus(
const
aMsgFlag:TLVOperateFlag);
procedureClearTrunkStatus();
functionCheckSigHangup():boolean;
functionCheckCallIn():boolean;
functionSwitchOnCallIn():boolean;
procedureProcessCallInSuccess();
procedureProcessDialSuccess();
procedureProcessCheckDialSend();
protected
procedureExecute();
override
;
public
strMessage:
string
;
OnChannelState:TTrunkStatusEvent;
constructorCreate(
const
trunkEvent:TTrunkStatusEvent);
destructorDestroy();
override
;
procedureCreateCommChannel(
const
aChennelID:Word);
procedureChannelProcessor();
functionGetChannelID():Word;
functionGetChannelStatus():TTrunkState;
functionGetChannelType():TChannelType;
functionDialPhone(
const
DialPhoneNumber:PChar):boolean;overload;
functionDialPhone(
const
DialPhoneNumber:PChar;
const
PreDialNumber:PChar):boolean;overload;
procedureChannelHangUp();
functionGetDialOut():boolean;
end;
implementation
...
{TCXXDJChannel160A}
procedureTCXXDJChannel160A.ChannelHangUp();
begin
isDialOut:
=
false
;
StopSigCheck(channelID);
HangUp(channelID);
Sig_ResetCheck(channelID);
StartSigCheck(channelID);
InitDTMFBuf(channelID);
ClearTrunkStatus();
InformTrunkStatus(lvofUpdate);
end;
procedureTCXXDJChannel160A.ChannelProcessor();
var
dState:Word;
begin
PUSH_PLAY();
FeedSigFunc();
CheckCallIn();
case
channelStateof
atsFree:
begin
//
end;
atsCallIning:
begin
SwitchOnCallIn();
end;
atsCallInSuccess:
begin
if
CheckSigHangup()thenExit;
ProcessCallInSuccess();
end;
atsCheckSendDial:
begin
ProcessCheckDialSend();
end;
atsDialing:
begin
dState:
=
Sig_CheckDial(channelID);
case
dStateof
//
S_NORESULT:
S_CONNECT:
begin
channelState:
=
atsDialSuccess;
isConntectd:
=
true
;
end;
S_BUSY,
S_NOBODY,
S_NODIALSIG,
S_NOSIGNAL:
begin
channelState:
=
atsHangOff;
end;
end;
strMessage:
=
'
<spa
分享到:
-
瀏覽: 1292150 次
-
性別:
-
來(lái)自: 杭州
-
評(píng)論