王朝网络
分享
 
 
 

Delphi之东进模拟语音卡(D160A)可复用源码

王朝delphi·作者佚名  2007-09-15
宽屏版  字体: |||超大  

Delphi之东进模拟语音卡(D160A)可复用源码

网友急需,先开源吧,文档过几天慢慢补。

作者:成晓旭

设计简介:

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.

11、 通道类源码:

//------------------------------------------------------------------------------

//

// 产品名称: 成晓旭的个人软件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.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有