📄 advoip.pas
字号:
end;
end;
end;
function TApdCustomVoIP.InitializeTapi: HRESULT;
{ get the interface to TAPI3 }
begin
Result := CoCreateInstance(CLASS_TAPI, nil, CLSCTX_INPROC_SERVER,
IID_ITTAPI, gpTapi);
if Result <> S_OK then begin {!!.01}
FErrorCode := ecVoIPTapi3NotInstalled; {!!.01}
DoFailEvent; {!!.01}
Exit;
end; {!!.01}
gpTapi.Initialize;
{ create the event notification object and register it }
Result := RegisterTapiEventInterface;
if Result <> S_OK then begin
FErrorCode := ecVoIPTapi3EventFailure; {!!.01}
DoFailEvent; {!!.01}
Exit;
end;
Result := FindTheAddress;
if Result <> S_OK then begin
{ no address (H.323 line) found }
FErrorCode := ecVoIPBadAddress; {!!.01}
DoFailEvent; {!!.01}
gpTapi := nil;
end;
end;
function TApdCustomVoIP.IsAudioCaptureStream(pStream: ITStream): Boolean;
{ see if this stream is the audio capture stream }
begin
Result := (pStream.Get_Direction in [TD_CAPTURE, TD_BIDIRECTIONAL]) and
(pStream.Get_MediaType = TAPIMEDIATYPE_AUDIO);
end;
function TApdCustomVoIP.IsAudioRenderStream(pStream: ITStream): Boolean;
{ see if this stream is the audio render stream }
begin
Result := (pStream.Get_Direction in [TD_RENDER, TD_BIDIRECTIONAL]) and
(pStream.Get_MediaType = TAPIMEDIATYPE_AUDIO);
end;
function TApdCustomVoIP.IsVideoCaptureStream(pStream: ITStream): Boolean;
{ see if this stream is the video capture stream }
begin
Result := (pStream.Get_Direction in [TD_CAPTURE, TD_BIDIRECTIONAL]) and
(pStream.Get_MediaType = TAPIMEDIATYPE_VIDEO);
end;
function TApdCustomVoIP.IsVideoRenderStream(pStream: ITStream): Boolean;
{ see if this stream is the video render stream }
begin
Result := (pStream.Get_Direction in [TD_RENDER, TD_BIDIRECTIONAL]) and
(pStream.Get_MediaType = TAPIMEDIATYPE_VIDEO);
end;
procedure TApdCustomVoIP.Loaded;
var
Res : HRESULT;
begin
inherited;
FVoIPAvailable := False;
{ determine whether TAPI 3 is installed }
Res := CoCreateInstance(CLASS_TAPI, nil, CLSCTX_INPROC_SERVER,
IID_ITTAPI, gpTapi);
if Res <> S_OK then begin {!!.01}
FErrorCode := ecVoIPTapi3NotInstalled; {!!.01}
DoFailEvent; {!!.01}
Exit;
end; {!!.01}
try
gpTapi.Initialize;
{ determine whether the H323 address is available }
Res := FindTheAddress;
if Res <> S_OK then begin
{FVoIPAvailable := False;} {!!.01}
FErrorCode := ecVoIPH323NotFound; {!!.01}
DoFailEvent; {!!.01}
gpTapi := nil;
Exit;
end;
{ figure out which terminals are available to us }
LoadTerminals;
FVoIPAvailable := True;
finally
{ unregister our call notification }
if NotifyRegister > 0 then
gpTapi.UnregisterNotifications(NotifyRegister);
NotifyRegister := 0;
gpAddress := nil;
gpCall := nil;
gpTapi := nil;
gpTAPIEventNotification := nil;
end;
end;
procedure TApdCustomVoIP.LoadTerminals;
{- Enumerates available terminals (audio/video hardware devices) }
{ adding each to AvailableTerminalDevices collection }
var
pTerminal : ITTerminal;
pTerminalSupport : ITTerminalSupport;
RecordsFound : DWORD;
Term : TApdVoIPTerminal;
pTermEnum : IEnumTerminal;
WS : WideString;
begin
{ clear the collection }
FAvailableTerminalDevices.Clear;
{ get the terminal support interface from our address }
pTerminalSupport := (gpAddress as ITTerminalSupport);
{ enumerate the terminals }
pTermEnum := pTerminalSupport.EnumerateStaticTerminals;
if pTermEnum <> nil then
while pTermEnum.Next(1, pTerminal, RecordsFound) = S_OK do begin
{ found a terminal, extract the terminal properties }
Term := (FAvailableTerminalDevices.Add as TApdVoIPTerminal);
Term.FDeviceName := pTerminal.Name;
case pTerminal.Get_MediaType of
TAPIMEDIATYPE_AUDIO : Term.FMediaType := mtAudio;
TAPIMEDIATYPE_VIDEO : Term.FMediaType := mtVideo;
TAPIMEDIATYPE_DATAMODEM : Term.FMediaType := mtDataModem;
TAPIMEDIATYPE_G3FAX : Term.FMediaType := mtG3_Fax;
end;
case pTerminal.Get_Direction of
TD_CAPTURE : Term.FMediaDirection := mdCapture;
TD_RENDER : Term.FMediaDirection := mdRender;
TD_BIDIRECTIONAL : Term.FMediaDirection := mdBidirectional;
end;
WS := pTerminal.Get_TerminalClass;
if WS = CLSID_String_HandsetTerminal then
Term.FTerminalDeviceClass := dcHandsetTerminal
else if WS = CLSID_String_HeadsetTerminal then
Term.FTerminalDeviceClass := dcHeadsetTerminal
else if WS = CLSID_String_MediaStreamTerminal then
Term.FTerminalDeviceClass := dcMediaStreamTerminal
else if WS = CLSID_String_MicrophoneTerminal then
Term.FTerminalDeviceClass := dcMicrophoneTerminal
else if WS = CLSID_String_SpeakerphoneTerminal then
Term.FTerminalDeviceClass := dcSpeakerPhoneTerminal
else if WS = CLSID_String_SpeakersTerminal then
Term.FTerminalDeviceClass := dcSpeakersTerminal
else if WS = CLSID_String_VideoInputTerminal then
Term.FTerminalDeviceClass := dcVideoInputTerminal
else if WS = CLSID_String_VideoWindowTerm then
Term.FTerminalDeviceClass := dcVideoWindowTerminal;
case pTerminal.Get_TerminalType of
TT_STATIC : Term.FTerminalType := ttStatic;
TT_DYNAMIC : Term.FTerminalType := ttDynamic;
end;
case pTerminal.Get_State of
TS_INUSE : Term.FTerminalState := tsInUse;
TS_NOTINUSE : Term.FTerminalState := tsNotInUse;
end;
end;
end;
function TApdCustomVoIP.MakeTheCall(dwAddressType: DWORD;
szAddressToCall: WideString): Boolean;
var
lMediaTypes : TOleEnum;
pCallInfo : ITCallInfo;
begin
Result := False;
lMediaTypes := 0;
if (AddressSupportsMediaType (gpAddress, TAPIMEDIATYPE_AUDIO)) then
lMediaTypes := TAPIMEDIATYPE_AUDIO;
{ only enable the video media mode if we want video }
if (AddressSupportsMediaType (gpAddress, TAPIMEDIATYPE_VIDEO)) then
lMediaTypes := lMediaTypes or TAPIMEDIATYPE_VIDEO;
gpCall := gpAddress.CreateCall(szAddressToCall, dwAddressType, lMediaTypes);
if not Assigned(gpCall) then
Exit;
if gpCall.QueryInterface(IID_ITCallInfo, pCallInfo) = S_OK then begin
{ these are the only parts of the pCallInfo that can be set }
if Length(FCallComment) > 0 then {!!.01}
pCallInfo.Set_CallInfoString(CIS_COMMENT, FCallComment);
if Length(FCallDisplayableAddress) > 0 then {!!.01}
pCallInfo.Set_CallInfoString(CIS_DISPLAYABLEADDRESS,
FCallDisplayableAddress);
{ PhoneDialer uses CallingPartyID for it's display }
if Length(FCallCallingPartyID) > 0 then {!!.01}
pCallInfo.Set_CallInfoString(CIS_CALLINGPARTYID, FCallCallingPartyID);
end;
if SelectTerminalOnCall(gpAddress, gpCall) <> S_OK then begin
{ couldn't select a terminal, just go without it }
end;
try
{ start the connection timer, FConnectTimeout is measured in seconds }
if FConnectTimeout > 0 then {!!.04}
SetTimer(FHandle, FConnectTimer, (FConnectTimeout * 1000), nil); {!!.04}
gpCall.Connect(False);
Result := True;
except
{ call failed, the exception will be raised here (and trapped here) }
{ the OnFail event will be generated with the reason for the error }
{ from the event sink }
end;
end;
procedure TApdCustomVoIP.Notification(AComponent : TComponent; Operation: TOperation);
begin
inherited;
if (Operation = opRemove) then begin
if (AComponent = FVideoOutWindow) then
FVideoOutWindow := nil;
if (AComponent = FPreviewWindow) then
FPreviewWindow := nil;
end;
end;
procedure TApdCustomVoIP.ProcessTapiEvent(TapiEvent: TAPI_EVENT;
pEvent: IDispatch);
{ called as a result of receiving apw_VoIPEventMessage message from the sink }
var
hr : HRESULT;
pNotify : ITCallNotificationEvent;
pCallInfo : ITCallInfo;
pCallStateEvent : ITCallStateEvent;
pCallMediaEvent : ITCallMediaEvent;
pTerminal : ITTerminal;
fRenderStream : Boolean;
pVideoWindow : IVideoWindow;
begin
case TapiEvent of
TE_CALLNOTIFICATION : { we're being notified of a new call }
begin
hr := pEvent.QueryInterface(IID_ITCallNotificationEvent, pNotify);
if hr <> S_OK then begin
{ DoMessage('Incoming call, but failed to get the interface'); }
end else begin
pCallInfo := pNotify.Get_Call;
pNotify._Release;
if pCallInfo <> nil then begin
try
FCallerIDName := pCallInfo.Get_CallInfoString(CIS_CALLERIDNAME);
except
FCallerIDName := 'Not available';
end;
try
FCallerIDNumber := pCallInfo.Get_CallInfoString(CIS_CALLERIDNUMBER);
except
FCallerIDNumber := 'Not available';
end;
try
FCallerDisplayName := pCallInfo.Get_CallInfoString(CIS_DISPLAYABLEADDRESS);
except
FCallerDisplayName := 'Not available';
end;
if pCallInfo.get_Privilege <> CP_OWNER then begin
{ not our call, just exit }
Exit;
end;
{ get the ITBasicCallControl interface }
hr := pCallInfo.QueryInterface(IID_ITBasicCallControl, gpCall);
if hr = S_OK then begin
PostMessage(FHandle, apw_VoIPEventMessage, etIncomingCall, 0);
end;
end;
end;
end;
TE_CALLSTATE : { call state event }
begin
hr := pEvent.QueryInterface(IID_ITCallStateEvent, pCallStateEvent);
if hr = S_OK then begin
{ get the CallState event }
case pCallStateEvent.get_State of
CS_IDLE,
CS_INPROGRESS :
begin
PostMessage(FHandle, apw_VoIPEventMessage, etCallState,
pCallStateEvent.get_State);
end;
CS_OFFERING :
begin
if FWaitingForCall then
PostMessage(FHandle, apw_VoIPEventMessage, etAnswer, 0);
end;
CS_DISCONNECTED :
begin
PostMessage(FHandle, apw_VoIPEventMessage, etDisconnected,
pCallStateEvent.Get_Cause); {!!.01}
end;
CS_CONNECTED :
begin
PostMessage(FHandle, apw_VoIPEventMessage, etConnect, 0);
end;
end;
{ get the CallState event cause }
case pCallStateEvent.Get_Cause of
CEC_NONE,
CEC_DISCONNECT_NORMAL :
begin
{ nothing to do, normal disconnect }
end;
CEC_DISCONNECT_BUSY,
CEC_DISCONNECT_BADADDRESS,
CEC_DISCONNECT_NOANSWER,
CEC_DISCONNECT_CANCELLED,
CEC_DISCONNECT_REJECTED,
CEC_DISCONNECT_FAILED :
begin
PostMessage(FHandle, apw_VoIPEventMessage, etFail,
pCallStateEvent.Get_Cause);
end;
end;
end;
end;
TE_CALLMEDIA :
begin
hr := pEvent.QueryInterface(IID_ITCallMediaEvent, pCallMediaEvent);
if hr = S_OK then begin
case pCallMediaEvent.get_Event of
CME_STREAM_NOT_USED,
CME_NEW_STREAM : { nothing to do } ;
CME_STREAM_FAIL :
begin
{ DoMessage('Call media event: stream failed'); }
end;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -