📄 adtapi.pas
字号:
(***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is TurboPower Async Professional
*
* The Initial Developer of the Original Code is
* TurboPower Software
*
* Portions created by the Initial Developer are Copyright (C) 1991-2002
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** *)
{*********************************************************}
{* ADTAPI.PAS 4.06 *}
{*********************************************************}
{* TApdTapiDevice, status and log components *}
{*********************************************************}
{
The TApdTapiDevice negotiates for TAPI 1.4, which is pre-installed
in all 32-bit Windows versions (Win9x through XP). Voice extensions
are available for Win95OSR2/Win98/ME/2K/XP through the default Windows
installation (Unimodem/V and Unimodem/5).
By far, the biggest problem with TAPI is the TAPI device itself. Always
check the modem drivers first, and strongly suggest to your users that
they periodically update their modem drivers.
Known problem areas: TAPI handles answering differently when doing data or
voice, we aren't doing any special processing to get common/consistent
events. The notification we receive varies a bit between TAPI versions
also, so check to see which events fire. The TapiTest example from
ftp://ftp.turbopower.com/pub/apro/demos/_Index.htm lets you see everything
that happens, use that to see how your modem/environment will react.
TAPI voice using regular modems (Unimodem/V or Unimodem/5) was not designed
for outbound/dialed automated voice calls. You will get an OnTapiConnect
event shortly after dialing, regardless of whether the line was busy, and
completely independent upon when the remote side actually answers. The
APROFAQ.HLP file has some tips to get around this. Of course, the TAPI
Service Providers (TSP) that ship with dedicated voice boards usually handle
this correctly, and you get much higher quality of voice play/record, so
get one of those boards (Dialogic, MediaPhonics, etc) if you need to do
outbound/dialed automated voice calls.
}
{Global defines potentially affecting this unit}
{$I AWDEFINE.INC}
{Options required for this unit}
{$G+,X+,F+,B-,J+}
{$C MOVEABLE,DEMANDLOAD,DISCARDABLE}
unit AdTapi;
{-Delphi TAPI interface component}
interface
uses
WinTypes,
WinProcs,
Registry,
Classes,
Messages,
Controls,
Forms,
{$IFDEF Delphi6}
Variants,
{$ENDIF}
ExtCtrls,
Dialogs,
MMSystem,
SysUtils,
AdTUtil,
OoMisc,
AwUser,
AdExcept,
AdTSel,
AdPort;
type
{TAPI states}
TTapiState = (tsIdle, tsOffering, tsAccepted, tsDialTone, tsDialing,
tsRingback, tsBusy, tsSpecialInfo, tsConnected,
tsProceeding, tsOnHold, tsConferenced, tsOnHoldPendConf,
tsOnHoldPendTransfer, tsDisconnected, tsUnknown);
{TTapiConfigRec definition moved to OOMisc to support RAS} {!!.06}
{Wave device states}
TWaveState = (wsIdle, wsPlaying, wsRecording, wsData);
TWaveMessage = (waPlayOpen, waPlayDone, waPlayClose,
waRecordOpen, waDataReady, waRecordClose);
{TAPI logging codes}
TTapiLogCode = (
ltapiNone, { None }
ltapiCallStart, { Call started }
ltapiCallFinish, { Call finished }
ltapiDial, { Dialing }
ltapiAccept, { Accepting an incoming call }
ltapiAnswer, { Answering an incoming call }
ltapiConnect, { Connected }
ltapiCancel, { Call cancelled }
ltapiDrop, { Call drop }
ltapiBusy, { Called number was busy }
ltapiDialFail, { Dial failed }
ltapiReceivedDigit); { Received a DTMF tone }
{TAPI status event}
TTapiStatusEvent = procedure(CP : TObject;
First, Last : Boolean;
Device, Message,
Param1, Param2, Param3 : LongInt) of object;
{TAPI log event}
TTapiLogEvent = procedure(CP : TObject; Log : TTapiLogCode) of object;
{TAPI DTMF event}
TTapiDTMFEvent = procedure(CP : TObject; Digit : Char;
ErrorCode: LongInt) of object;
{TAPI Caller ID event}
TTapiCallerIDEvent =
procedure(CP : TObject; ID, IDName: string) of object;
{TAPI wave notify event}
TTapiWaveNotify = procedure(CP : TObject;
Msg : TWaveMessage) of object;
{TAPI wave silence event}
TTapiWaveSilence = procedure(CP : TObject;
var StopRecording : Boolean;
var Hangup : Boolean) of object;
const
Success = 0;
WaitErr_WaitAborted = 1;
WaitErr_WaitTimedOut = 2;
LineCallState_Any = 0;
WaitTimeout = 30000;
{ Base of error strings in the resource }
TapiErrorBase = 13800;
{ Base of status strings in the resource }
TapiStatusBase = 13500;
{ Offsets from TapiStatusBase for the separate TAPI message classes }
lcsBase = 0; { Line Call State }
ldsBase = 32; { Line Device State }
lrBase = 64; { Line Reply }
asBase = 96; { Apro-specific }
lcsdBase = 150; { Line Call State -- Disconnect }
{Defaults for TApdTapiLog properties}
DefTapiHistoryName = 'APROTAPI.HIS';
{Property inits}
DefMaxAttempts = 3;
DefAnsRings = 2;
DefRetryWait = 60; { seconds }
DefShowTapiDevices = True;
DefShowPorts = True;
DefMaxMessageLength = 60; { 1 minute }
DefWaveState = wsIdle;
DefUseSoundCard = False;
DefTrimSeconds = 2;
DefSilenceThreshold = 50;
DefChannels = 1;
DefBitsPerSample = 16;
DefSamplesPerSecond = 8000;
DefMonitorRecording = False;
{Wave Error Types}
WaveInError = 1;
WaveOutError = 2;
MMioError = 3;
BufferSeconds = 1;
WaveOutBufferSeconds = 3;
type
{Forwards}
TApdAbstractTapiStatus = class;
TApdTapiLog = class;
{Custom TAPI component}
TApdCustomTapiDevice = class(TApdBaseComponent)
protected
{private data}
LineApp : TLineApp; {TAPI handle for this application}
LineExt : TLineExtensionID; {Line extension data}
LineHandle : TLine; {Handle of the opened line device}
CallHandle : TCall; {Handle of the current call}
SelectedLine : Integer; {Device ID of selected line}
VS : TVarString; {Used to return Cid}
DialTimer : TTimer; {Timer component}
RequestedId : LongInt; {ID being waited for}
AsyncReply : LongInt; {Requested reply}
CallState : LongInt; {Received CallState}
ReplyReceived : Boolean; {True if Line Reply received}
CallStateReceived : Boolean; {True if CallState received}
TapiInUse : Boolean; {True means a call is active}
TapiHasOpened : Boolean; {True means TAPI has been opened}
Initializing : Boolean; {True during StartTapi}
Connected : Boolean; {True when connected}
StoppingCall : Boolean; {True during HangupCall}
ShuttingDown : Boolean; {True during StopTapi}
RetryPending : Boolean; {True if a retry is pending}
TapiFailFired : Boolean; {True if OnTapiFailed fired}
ReplyWait : Boolean; {True if waiting for reply}
StateWait : Boolean; {True if waiting for call state}
PassThruMode : Boolean; {True if in passthrough mode}
WaveOutHeader : PWaveHdr; {Wave header for playing}
WaveInHeader : PWaveHdr; {Wave header for recording}
WaveOutHandle : HWaveOut; {Handle of the wave out device}
WaveInHandle : HWaveIn; {Handle of the wave in device}
BytesRecorded : LongInt; {Bytes recorded for this buffer}
TotalBytesRecorded : LongInt; {Bytes recorded overall }
WaveInBuffer1 : Pointer; {Buffer for wave recording}
WaveInBuffer2 : Pointer; {Buffer for wave recording}
WaveOutBuffer1 : Pointer; {Buffer for wave playing }
WaveOutBuffer2 : Pointer; {Buffer for wave playing }
ActiveBuffer : Byte; {The active wave in buffer}
MmioInHandle : Integer; {File handle for recording}
MmioOutHandle : Integer; {File handle for recording}
RootChunk : TMMCkInfo; {Root chunk for wave file}
DataChunk : TMMCkInfo; {Data chunk for wave file}
TempFileName : TFileName; {Temporary file for recording}
Channels : Byte; {# of channels for recording}
BitsPerSample : Byte; {Bits per sample for recording}
SamplesPerSecond : Integer; {Samples per sec for recording}
WaveInBufferSize : LongInt; {# of bytes in a wave in buffer}
BytesToPlay : LongInt; {# of bytes in the wave file}
BytesPlayed : LongInt; {# of bytes already played}
BytesInBuffer : LongInt; {# of bytes in current buffer}
ActiveWaveOutBuffer: Byte; {The active wave out buffer}
WaveOutBufferSize : LongInt; {# of bytes in wave out buffer}
{private data stores}
FAvgWaveInAmplitude: Integer; {Average amplitude for recording}
FCancelled : Boolean; {True if call was cancelled}
FDialing : Boolean; {True when dialing, False not}
FDialTime : LongInt; {Elapsed dial time}
FTapiDevices : TStrings; {List of tapi device names}
FSelectedDevice : string; {Name of selected device}
FApiVersion : LongInt; {Negotiated version}
FDeviceCount : DWORD; {Number of supported TAPI devices}
FTrueDeviceCount: DWORD; {Total number of TAPI devices}
FOpen : Boolean; {True to open a line device}
FCallInfo : PCallInfo; {Holds current call info}
FComPort : TApdCustomComPort; {Attached comport}
FStatusDisplay : TApdAbstractTapiStatus; {Built-in status display}
FTapiLog : TApdTapiLog; {Built-in logging component}
FNumber : string; {Last dialed number}
FMaxAttempts : Word; {Max number of dial attempts}
FAttempt : Word; {Dialing attempt number}
FRetryWait : Word; {Seconds between dialing attempts}
FAnsRings : Byte; {Rings to allow before answer}
FParentHWnd : HWnd; {Window handle of parent}
FShowTapiDevices: Boolean; {Show TAPI devices}
FShowPorts : Boolean; {Show ports}
FEnableVoice : Boolean; {Monitor DTMF Tones if capable}
FMaxMessageLength : LongInt; {Max message length for wave recording}
FWaveFileName : TFileName; {Wave file name}
FInterruptWave : Boolean; {Stops playing wave file on DTMF tone}
FHandle : HWnd; {Window handle for hidden window}
FWaveState : TWaveState; {Current wave device state}
FUseSoundCard : Boolean; {Play the sound through the sound card}
FSilence : TLineMonitorTone;
FTrimSeconds : Byte; {Trim silence after x seconds}
FSilenceThreshold : Integer; {Silence threshold for trimming}
FMonitorRecording : Boolean; {Echo wave recording to sound card}
FFailCode : Integer; {Failure code}
FFilterUnsupportedDevices: Boolean; {Display only supported devices}
FWaitingForCall: Boolean; {True if in AutoAnswer mode} {!!.04}
{Events}
FOnTapiCallerID : TTapiCallerIDEvent;
FOnTapiConnect : TNotifyEvent;
FOnTapiDTMF : TTapiDTMFEvent;
FOnTapiFail : TNotifyEvent;
FOnTapiLog : TTapiLogEvent;
FOnTapiPortClose : TNotifyEvent;
FOnTapiPortOpen : TNotifyEvent;
FOnTapiStatus : TTapiStatusEvent;
FOnTapiWaveNotify : TTapiWaveNotify;
FOnTapiWaveSilence : TTapiWaveSilence;
{Callback virtual methods}
procedure DoLineCallInfo(Device, P1, P2, P3 : LongInt); virtual;
procedure DoLineCallState(Device, P1, P2, P3 : LongInt); virtual;
procedure DoLineClose(Device, P1, P2, P3 : LongInt); virtual;
procedure DoLineCreate(Device, P1, P2, P3 : LongInt); virtual;
procedure DoLineDevState(Device, P1, P2, P3 : LongInt); virtual;
procedure DoLineGenerate(Device, P1, P2, P3 : LongInt); virtual;
procedure DoLineMonitorDigits(Device, P1, P2, P3 : LongInt); virtual;
procedure DoLineMonitorMedia(Device, P1, P2, P3 : LongInt); virtual;
procedure DoLineMonitorTone(Device, P1, P2, P3 : LongInt); virtual;
procedure DoLineReply(Device, P1, P2, P3 : LongInt); virtual;
procedure DoLineRequest(Device, P1, P2, P3 : LongInt); virtual;
function HandleLineErr(LineErr : LongInt): Boolean;
function HangupCall(AbortRetries : Boolean) : Boolean;
procedure UpdateCallInfo(Device : LongInt);
function WaitForCallState(DesiredCallState : LongInt) : LongInt;
function WaitForReply(ID : LongInt) : LongInt;
{Property access methods}
procedure SetOpen(NewOpen : Boolean);
{Private methods}
procedure AssureTapiReady;
function CidFromTapiDevice : LongInt;
procedure CheckVoiceCapable;
procedure CheckWaveException(ErrorCode : Integer; Mode : Integer);
procedure CheckWaveInSilence;
function CloseTapiPort : Boolean;
procedure CloseWaveFile;
procedure CreateDialTimer;
function DeviceIDFromName(const Name : string) : Integer;
procedure DialPrim(PassThru : Boolean);
procedure EnumLineDevices;
procedure FreeWaveInBuffers;
procedure FreeWaveOutBuffer;
function GetSelectedLine : Integer;
function GetWaveDeviceId(const Play : Boolean) : DWORD;
procedure LoadWaveOutBuffer;
procedure MonitorDTMF(var CallHandle: LongInt;
const DTMFMode: LongInt);
procedure OpenTapiPort;
procedure OpenWaveFile;
procedure PlayWaveOutBuffer;
procedure PrepareWaveInHeader;
function StartTapi : Boolean;
function StopTapi : Boolean;
procedure TapiDialTimer(Sender : TObject);
procedure WndProc(var Message : TMessage);
procedure WriteWaveBuffer;
{Property access methods}
function GetBPSRate : DWORD;
function GetCalledID: string;
function GetCalledIDName: string;
function GetCallerID : string;
function GetCallerIDName : string;
function GetComNumber : Integer;
function GetParentHWnd : HWnd;
function GetTapiState : TTapiState;
procedure SetStatusDisplay(const NewDisplay : TApdAbstractTapiStatus);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -