📄 advoip.pas
字号:
{ Create the TAPI3 event sink so we get TAPI messages }
procedure ReleaseTheCall;
{ Cleans up the call interface }
function SelectTerminalOnCall(pAddress : ITAddress;
pCall : ITBasicCallControl) : HRESULT;
{ Find and select the terminals for the call }
procedure ShutDownTapi;
{ Cleans up the call interface and the TAPI interface }
public
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
procedure Loaded; override;
procedure Notification(AComponent : TComponent; Operation: TOperation); override;
procedure CancelCall;
{ Terminates whatever we were doing }
procedure Connect(DestAddr : string);
{ Establishes a connection by dialing or answering (if DestAddr is '') }
function ShowMediaSelectionDialog : Boolean;
{ Display the media selection dialog to select terminals }
{ property to remain unpublished }
property AvailableTerminalDevices : TApdTerminals
read FAvailableTerminalDevices;
{ the following three properties are transmitted to the answering }
{ station when placing a call. CallingParyID is used by PhoneDialer }
{ to indicate the originator of the call. }
property CallComment : string { comment for outbound calls }
read FCallComment write FCallComment;
property CallDisplayableAddress : string { displayable address for outbound calls }
read FCallDisplayableAddress write FCallDisplayableAddress;
property CallCallingPartyID : string { CallingParyID for outbound calls }
read FCallCallingPartyID write FCallCallingPartyID;
property CallInfo : TApdVoIPCallInfo
read GetCallInfo;
property CallInfoInterface : ITCallInfo
read GetCallInfoInterface;
property CallerIDName : string
read FCallerIDName;
property CallerIDNumber : string
read FCallerIDNumber;
property CallerDisplayName : string
read FCallerDisplayName;
property Connected : Boolean
read FConnected;
property ErrorCode : Integer {!!.01}
read FErrorCode; {!!.01}
property VoIPAvailable : Boolean
read FVoIPAvailable;
property WaitingForCall : Boolean
read FWaitingForCall;
{ properties to publish in TApdVoIP component }
property AudioInDevice : string
read FAudioInDevice write SetAudioInDevice;
property AudioOutDevice : string
read FAudioOutDevice write SetAudioOutDevice;
property ConnectTimeout : Integer {!!.04}
read FConnectTimeout write FConnectTimeout; {!!.04}
property EnablePreview : Boolean
read FEnablePreview write SetEnablePreview;
property EnableVideo : Boolean
read FEnableVideo write SetEnableVideo;
property VideoInDevice : string
read FVideoInDevice write SetVideoInDevice;
property VideoOutWindow : TWinControl
read FVideoOutWindow write SetVideoOutDevice;
property VideoOutWindowAutoSize : Boolean
read FVideoOutWindowAutoSize write SetVideoOutWindowAutoSize;
property PreviewWindow : TWinControl
read FPreviewWindow write SetPreviewWindow;
property PreviewWindowAutoSize : Boolean
read FPreviewWindowAutoSize write SetPreviewWindowAutoSize;
property EventLog : TApdVoIPLog
read FEventLog write FEventLog;
{Events}
property OnConnect : TApdVoIPNotifyEvent
read FOnConnect write FOnConnect;
property OnDisconnect : TApdVoIPNotifyEvent
read FOnDisconnect write FOnDisconnect;
property OnFail : TApdVoIPFailEvent
read FOnFail write FOnFail;
property OnIncomingCall : TApdVoIPIncomingCallEvent
read FOnIncomingCall write FOnIncomingCall;
property OnStatus : TApdVoIPStatusEvent
read FOnStatus write FOnStatus;
end;
TApdVoIP = class(TApdCustomVoIP)
published
property AudioInDevice;
property AudioOutDevice;
property ConnectTimeout; {!!.04}
property EnablePreview;
property EnableVideo;
property EventLog;
property PreviewWindow;
property PreviewWindowAutoSize;
property VideoInDevice;
property VideoOutWindow;
property VideoOutWindowAutoSize;
property OnConnect;
property OnDisconnect;
property OnFail;
property OnIncomingCall;
property OnStatus;
end;
implementation
uses
AdVoIPEd;
const
{ consts used in the wParam of our message to indicate what the message does }
etConnect = 0; { generate OnConnect }
etDisconnect = 1; { generate OnDisconnect }
etFail = 2; { generate OnFail }
etIncomingCall = 3; { generate OnIncomingCall }
etStatus = 4; { generate OnStatus }
etAnswer = 5; { answer the call }
etDisconnected = 6; { we're disconnected }
etCallState = 7; { processing a callstate event }
{ TApdCustomVoIP }
function TApdCustomVoIP.AddressSupportsMediaType(pAddress: ITAddress;
lMediaType: TOleEnum): Boolean;
{ see if this address supports the media type }
var
pMediaSupport : ITMediaSupport;
begin
Result := False;
if (pAddress.QueryInterface(IID_ITMediaSupport, pMediaSupport) = S_OK) then
Result := pMediaSupport.QueryMediaType(lMediaType);
end;
function TApdCustomVoIP.AnswerTheCall: HRESULT;
{ answer the call }
var
pCallInfo : ITCallInfo;
pAddress : ITAddress;
begin
if gpCall = nil then begin
Result := E_UNEXPECTED;
Exit;
end;
{ get the address object of this call }
Result := gpCall.QueryInterface(IID_ITCallInfo, pCallInfo);
if Result <> S_OK then begin
gpCall := nil;
Exit;
end;
pAddress := pCallInfo.get_Address;
if pAddress = nil then begin
gpCall := nil;
Result := E_OUTOFMEMORY;
Exit;
end;
{ select the terminals, if any fail we'll just skip them }
Result := SelectTerminalOnCall(pAddress, gpCall);
{ now, we'll answer the call }
gpCall.Answer;
end;
procedure TApdCustomVoIP.CancelCall;
{ terminates the call, returns to normal }
begin
DisconnectTheCall;
end;
procedure TApdCustomVoIP.Connect(DestAddr: string);
{ starts an outbound or inbound call }
begin
if not FVoIPAvailable then
raise EVoIPNotSupported.CreateUnknown(sVoIPNotAvailable, 0);
FErrorCode := ecOK;
if not (FTapiInitialized) then
FTapiInitialized := InitializeTapi = S_OK;
{ remove leading/trailing spaces and embedded control chars }
Trim(DestAddr);
if DestAddr = '' then begin
{ wait for a call }
FWaitingForCall := True;
end else begin
{ place the call }
FWaitingForCall := False;
MakeTheCall(DetermineAddressType(DestAddr), DestAddr);
end;
end;
constructor TApdCustomVoIP.Create(AOwner: TComponent);
{ create ourselves, set up the defaults }
begin
inherited;
FTapiInitialized := False;
FWaitingForCall := False;
FConnected := False;
FConnectTimeout := 120; { seconds to wait for the remote to answer } {!!.04}
FConnectTimer := 1;
FErrorCode := ecOK;
FHandle := AllocateHWnd(WndProc);
FEnableVideo := True;
FEnablePreview := True;
FVideoOutWindowAutoSize := True;
FPreviewWindowAutoSize := True;
FEventLog := TApdVoIPLog.Create;
FEventLog.FLogName := 'VoIP.log';
FAvailableTerminalDevices := TApdTerminals.Create(TApdVoIPTerminal);
end;
destructor TApdCustomVoIP.Destroy;
{ destroy ourselves }
begin
ShutDownTapi;
FAvailableTerminalDevices.Free; {!!.04}
gpTAPIEventNotification.Free; {!!.04}
KillTimer(FHandle, FConnectTimer); {!!.04}
if FHandle <> 0 then DeallocateHWnd(FHandle);
FEventLog.Free;
inherited;
end;
function TApdCustomVoIP.DetermineAddressType(const Addr: string): Cardinal;
{ determine whether this is an IP or machine name address }
var
I, DotCnt : Integer;
begin
{ making some assumptions: an IP address will not have alpha chars, a }
{ fully qualified machine name will have alpha chars, a truncated machine }
{ name will not have 3 dots }
DotCnt := 0;
I := 1;
Result := 0;
while (Result = 0) and (I <= Length(Addr)) do begin
if Addr[I] in ['A'..'Z', 'a'..'z'] then
Result := LINEADDRESSTYPE_DOMAINNAME;
if Addr[I] = '.' then
inc(DotCnt);
inc(I);
end;
if I > Length(Addr) then
if DotCnt = 3 then
Result := LINEADDRESSTYPE_IPADDRESS;
end;
function TApdCustomVoIP.DisconnectTheCall: HRESULT;
{ terminate a call }
begin
if gpCall = nil then begin
Result := S_FALSE;
Exit;
end;
gpCall.Disconnect(DC_NORMAL);
Result := S_OK;
end;
procedure TApdCustomVoIP.DoConnectEvent;
{ generate the OnConnect event }
begin
if FConnectTimer > 0 then begin {!!.04}
KillTimer(FHandle, FConnectTimer); {!!.04}
FConnectTimer := 0; {!!.04}
end; {!!.04}
FEventLog.AddLogString(False, 'Connected');
FConnected := True;
if Assigned(FOnConnect) then begin
FOnConnect(Self);
end;
end;
procedure TApdCustomVoIP.DoDisconnectEvent;
{ generate the OnDisconnect event }
begin
FEventLog.AddLogString(False, 'Disconnected');
if NotifyRegister > 0 then
gpTapi.UnregisterNotifications(NotifyRegister);
NotifyRegister := 0;
if FConnected and Assigned(FOnDisconnect) then begin
FOnDisconnect(Self);
end;
FConnected := False;
end;
procedure TApdCustomVoIP.DoFailEvent;
{ generate the OnFail event }
begin
if FConnectTimer > 0 then begin {!!.04}
KillTimer(FHandle, FConnectTimer); {!!.04}
FConnectTimer := 0; {!!.04}
end; {!!.04}
FEventLog.AddLogString(False, 'Failed (' + IntToStr(FErrorCode) + ')');
if Assigned(FOnFail) then begin
FOnFail(Self, FErrorCode);
end;
end;
procedure TApdCustomVoIP.DoIncomingCallEvent;
{ generate the OnIncomingCall event, determine whether we answer or not }
var
Accept : Boolean;
Addr : string;
begin
Accept := True;
if FCallerDisplayName > '' then
Addr := FCallerDisplayName
else if FCallerIDName > '' then
Addr := FCallerIDName
else
Addr := FCallerIDNumber;
FEventLog.AddLogString(True, 'Incoming call, DisplayName: ' + FCallerDisplayName);
FEventLog.AddLogString(True, 'Incoming call, CallerIDNumber: ' + FCallerIDNumber);
FEventLog.AddLogString(True, 'Incoming call, CallerIDName: ' + FCallerIDName);
if Assigned(FOnIncomingCall) then
FOnIncomingCall(Self, Addr, Accept);
if Accept then begin
{ accepting the call }
FEventLog.AddLogString(False, 'Incoming call accepted');
AnswerTheCall;
end else begin
{ rejecting the call }
FEventLog.AddLogString(False, 'Rejecting the call');
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -