Delphi之东进数字语音卡(SS1)可复用源码

来源:互联网 发布:淘宝无线活动 编辑:程序博客网 时间:2024/05/21 11:07

Delphi之东进数字语音卡(SS1)可复用源码

作者:成晓旭

Bloghttp://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之东进数字语音卡通道类
//      模块描述:   
//      单元文件:   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 charconst 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