📄 advoip.pas
字号:
DisconnectTheCall;
end;
end;
procedure TApdCustomVoIP.DoStatusEvent(TapiEvent, Status, SubStatus : Word);
{ generate the OnStatus event }
begin
FEventLog.AddLogString(True, 'DoStatusEvent (TapiEvent=' +
IntToStr(TapiEvent) + ', Status=' + IntToStr(Status) +
', SubStatus=' + IntToStr(SubStatus) + ')');
if Assigned(FOnStatus) then begin
FOnStatus(Self, TapiEvent, Status, SubStatus);
end;
end;
function TApdCustomVoIP.EnablePreviewWindow(pAddress: ITAddress;
pStream: ITStream): HRESULT;
{ hook up the preview dynamic terminal }
var
pTerminal : ITTerminal;
begin
Result := GetVideoRenderTerminal(pAddress, pTerminal);
if Result = S_OK then
pStream.SelectTerminal(pTerminal);
end;
function TApdCustomVoIP.FindTerminal(DevName: string;
MediaType: TOleEnum; MediaDir: TOleEnum;
var ppTerminal: ITTerminal): HRESULT;
{ searches the collection for the selected terminal }
var
pTerminalSupport : ITTerminalSupport;
pTerminal : ITTerminal;
pTermEnum : IEnumTerminal;
Fetched : DWORD;
begin
Result := S_FALSE;
pTerminalSupport := (gpAddress as ITTerminalSupport);
pTermEnum := pTerminalSupport.EnumerateStaticTerminals;
if pTermEnum <> nil then begin
while pTermEnum.Next(1, pTerminal, Fetched) = S_OK do begin
{ got a terminal, see if it is the one that was selected }
if (pTerminal.Name = DevName) and (pTerminal.Get_MediaType = Integer(MediaType))
and (pTerminal.Get_Direction = MediaDir) then begin
Result := S_OK;
ppTerminal := pTerminal;
Exit;
end;
end;
end;
end;
function TApdCustomVoIP.FindTheAddress: HRESULT;
var
pEnumAddress : IEnumAddress;
pAddress : ITAddress;
Fetched : DWORD;
lMediaTypes : TOleEnum;
begin
{ enumerate the addresses }
pEnumAddress := gpTapi.EnumerateAddresses;
if pEnumAddress = nil then begin
Result := E_INVALIDARG;
Exit;
end;
Result := S_OK;
{for each address found}
while Result in [S_OK, S_FALSE] do begin
Result := pEnumAddress.Next(1, pAddress, Fetched);
if pAddress = nil then
{at end of address enumerations}
Break;
{ we only support H.323 }
{if pAddress.AddressName = 'H323 Line' then begin} {!!.01}
if UpperCase(pAddress.ServiceProviderName) = 'H323.TSP' then begin {!!.01}
gpAddress := pAddress;
{ register for event notifications }
lMediaTypes := TAPIMEDIATYPE_AUDIO;
if FEnableVideo and not((FVideoInDevice = '') or
(FVideoInDevice = ApdNoTerminalName)) then
if AddressSupportsMediaType(pAddress, TAPIMEDIATYPE_VIDEO) then
lMediaTypes := lMediaTypes or TAPIMEDIATYPE_Video;
NotifyRegister := gpTapi.RegisterCallNotifications(pAddress,
True, True, lMediaTypes, gulAdvise);
{ found the address, we can exit now }
Result := S_OK; {!!.01}
Exit; {!!.01}
end;
end;
{ if we got here, we didn't find our address }
Result := S_FALSE; {!!.01}
{if Result = S_FALSE then} {!!.01}
{Result := S_OK;} {!!.01}
end;
function TApdCustomVoIP.GetCallInfo: TApdVoIPCallInfo;
{ return the ITCallInfo interface for the call }
var
pCallInfo : ITCallInfo;
Res : Integer;
{ using nested functions to trap exceptions if the requested info is }
{ not available }
function CallInfoString(CallInfoString: CALLINFO_STRING) : WideString;
begin
Result := '';
try
Result := pCallInfo.Get_CallInfoString(CallInfoString);
except
{ not available, just eat the exception and move on }
end;
end;
function CallInfoLong(CallInfoLong: CALLINFO_LONG): Integer;
begin
Result := 0;
try
Result := pCallInfo.Get_CallInfoLong(CallInfoLong);
except
{ not available, just eat the exception }
end;
end;
begin
if not FVoIPAvailable then
raise EVoIPNotSupported.CreateUnknown(sVoIPNotAvailable, 0);
{ NOTE: not all of these fields are available for all TAPI3 instances }
{ the docs are a bit unclear why, it may be security related }
{ if it's not available, an exception is raised, which we'll trap }
Res := gpCall.QueryInterface(IID_ITCallInfo, pCallInfo);
if Res = S_OK then begin
Result.InfoAvailable := True;
{ string types }
Result.CallerIDName := CallInfoString(CIS_CALLERIDNAME);
Result.CallerIDNumber := CallInfoString(CIS_CALLERIDNUMBER);
Result.CalledIDName := CallInfoString(CIS_CALLEDIDNAME);
Result.CalledIDNumber := CallInfoString(CIS_CALLEDIDNUMBER);
Result.ConnectedIDName := CallInfoString(CIS_CONNECTEDIDNAME);
Result.ConnectedIDNumber := CallInfoString(CIS_CONNECTEDIDNUMBER);
Result.CalledPartyFriendlyName := CallInfoString(CIS_CALLEDPARTYFRIENDLYNAME);
Result.Comment := CallInfoString(CIS_COMMENT);
Result.DisplayableAddress := CallInfoString(CIS_DISPLAYABLEADDRESS);
Result.CallingPartyID := CallInfoString(CIS_CALLINGPARTYID);
{ DWORD types }
Result.MediaTypesAvailable := CallInfoLong(CIL_MEDIATYPESAVAILABLE);
Result.CallerIDAddressType := CallInfoLong(CIL_CALLERIDADDRESSTYPE);
Result.CalledIDAddressType := CallInfoLong(CIL_CALLEDIDADDRESSTYPE);
Result.ConnectedIDAddressType := CallInfoLong(CIL_CONNECTEDIDADDRESSTYPE);
Result.Origin := CallInfoLong(CIL_ORIGIN);
Result.Reason := CallInfoLong(CIL_REASON);
Result.MinRate := CallInfoLong(CIL_MINRATE);
Result.MaxRate := CallInfoLong(CIL_MAXRATE);
Result.Rate := CallInfoLong(CIL_RATE);
end else
Result.InfoAvailable := False;
end;
function TApdCustomVoIP.GetCallInfoInterface: ITCallInfo;
{ ITCallInfo is described in the TAPI3 MSDN documentation, available at: }
{ http://msdn.microsoft.com/library/default.asp?url=/library/en-us/tapi/int_itfo_8acv.asp }
{ this page seems to move around a lot, search for ITCallInfo from the }
{ MSDN home page http://msdn.microsoft.com/default.asp for the latest info }
begin
if not FVoIPAvailable then
raise EVoIPNotSupported.CreateUnknown(sVoIPNotAvailable, 0);
{ if the interface is not available, the result will be nil }
if gpCall = nil then
Result := nil
else
gpCall.QueryInterface(IID_ITCallInfo, Result);
end;
function TApdCustomVoIP.GetTerminal(pAddress: ITAddress; pStream: ITStream;
var ppTerminal: ITTerminal): HRESULT;
{ hook up the terminals for audio/video input/output }
var
lMediaType : TOleEnum;
dir : TOleEnum;
pTerminalSupport : ITTerminalSupport;
begin
lMediaType := pStream.get_MediaType;
dir := pStream.get_Direction;
{ video render is handled differently (it's a dynamic terminal) }
if FEnableVideo and IsVideoRenderStream(pStream) then begin
Result := GetVideoRenderTerminal(pAddress, ppTerminal);
Exit;
end;
{ NOTE: we do not currently support selecting the specific static terminal }
{ if the property is an empty string or '<none>' then we won't hook the }
{ terminal to the stream, otherwise we'll select the default terminal. }
{ audio and video capture terminals are static }
Result := pAddress.QueryInterface(IID_ITTerminalSupport, pTerminalSupport);
if Result = S_OK then begin
if IsAudioCaptureStream(pStream) then begin
{ select the audio capture terminal (microphone) }
if (AudioInDevice = '') or (AudioInDevice = ApdNoTerminalName) then begin
{ don't select a terminal }
end else if (AudioInDevice = ApdDefaultTerminalName) then begin
{ select the default terminal }
ppTerminal := pTerminalSupport.GetDefaultStaticTerminal(lMediaType, dir)
end else begin
{ try to find the selected terminal from the collection }
FindTerminal(AudioInDevice, TAPIMEDIATYPE_AUDIO, TD_CAPTURE, ppTerminal);
end;
end else if IsAudioRenderStream(pStream) then begin
{ select the audio render terminal (speakers) }
if (AudioOutDevice = '') or (AudioOutDevice = ApdNoTerminalName) then begin
{ don't select a terminal }
end else if (AudioOutDevice = ApdDefaultTerminalName) then begin
{ select the default terminal }
ppTerminal := pTerminalSupport.GetDefaultStaticTerminal(lMediaType, dir)
end else begin
{ try to find the selected terminal from the collection }
FindTerminal(AudioInDevice, TAPIMEDIATYPE_AUDIO, TD_RENDER, ppTerminal);
end;
end else if IsVideoCaptureStream(pStream) then begin
{ TAPI3 only allows the default video capture (local camera) to be selected }
if (FVideoInDevice = '') or (FVideoInDevice = ApdNoTerminalName) then begin
{ don't select the terminal }
end else begin
ppTerminal := pTerminalSupport.GetDefaultStaticTerminal(lMediaType, dir);
end;
end;
end;
end;
function TApdCustomVoIP.GetVideoRenderTerminal(pAddress: ITAddress;
var ppTerminal: ITTerminal): HRESULT;
{ find the video render terminal (displays video locally) }
var
pTerminalSupport : ITTerminalSupport;
begin
Result := pAddress.QueryInterface(IID_ITTerminalSupport, pTerminalSupport);
if Result = S_OK then
ppTerminal := pTerminalSupport.CreateTerminal(
GuidToString(CLSID_VideoWindowTerm),
TAPIMEDIATYPE_VIDEO, TD_RENDER);
end;
function TApdCustomVoIP.GetVideoRenderTerminalFromStream(
pCallMediaEvent: ITCallMediaEvent; var ppTerminal: ITTerminal;
var pfRenderStream: Boolean): HRESULT;
{ hook the incoming video (or preview) stream to our window }
var
pStream : ITStream;
lMediaType : TOleEnum;
pEnumTerminal : IEnumTerminal;
Fetched : DWORD;
begin
{ get the stream for this event }
pStream := pCallMediaEvent.get_Stream;
if pStream = nil then begin
Result := E_FAIL;
Exit;
end;
{ See if it's a video stream }
lMediaType := pStream.get_MediaType;
if lMediaType <> TAPIMEDIATYPE_VIDEO then begin
Result := E_FAIL;
Exit;
end;
{ See if it's a render stream }
pfRenderStream := pStream.get_Direction = TD_RENDER;
{ enumerate the terminals }
pStream.EnumerateTerminals(pEnumTerminal);
if pEnumTerminal = nil then begin
Result := E_FAIL;
Exit;
end;
{ search for the first video render terminal }
while pEnumTerminal.Next(1, ppTerminal, Fetched) = S_OK do begin
if ppTerminal.Get_Direction = TD_RENDER then begin
Result := S_OK;
Exit;
end;
end;
Result := E_FAIL;
end;
procedure TApdCustomVoIP.HostWindow(pVideoWindow: IVideoWindow;
IsRenderStream: Boolean);
{ set up the preview/render terminals }
var
Width, Height : Integer;
begin
if IsRenderStream then begin
if FEnableVideo and (FVideoOutWindow <> nil)then begin
pVideoWindow.put_Owner(FVideoOutWindow.Handle);
pVideoWindow.put_WindowStyle(WS_CHILDWINDOW or WS_BORDER);
pVideoWindow.get_Width(Width); { width of the incoming stream }
pVideoWindow.get_Height(Height); { height of the incoming stream }
if FVideoOutWindowAutoSize then begin
pVideoWindow.SetWindowPosition(1, 1, Width, Height);
FVideoOutWindow.Width := Width + 2;
FVideoOutWindow.Height := Height + 2;
end else
pVideoWindow.SetWindowPosition(1, 1, FVideoOutWindow.Width - 2,
FVideoOutWindow.Height - 2);
pVideoWindow.put_Visible(True);
end else if FEnableVideo then begin
{ create popup window }
pVideoWindow.put_AutoShow(True);
pVideoWindow.put_Visible(True);
end;
end else begin
if FEnablePreview and (FPreviewWindow <> nil)then begin
pVideoWindow.put_Owner(FPreviewWindow.Handle);
pVideoWindow.put_WindowStyle(WS_CHILDWINDOW or WS_BORDER);
pVideoWindow.get_Width(Width); { width of the incoming stream }
pVideoWindow.get_Height(Height); { height of the incoming stream }
if FPreviewWindowAutoSize then begin
pVideoWindow.SetWindowPosition(1, 1, Width, Height);
FPreviewWindow.Width := Width + 2;
FPreviewWindow.Height := Height + 2;
end else
pVideoWindow.SetWindowPosition(1, 1, FPreviewWindow.Width - 2,
FPreviewWindow.Height - 2);
pVideoWindow.put_Visible(True);
end else if FEnablePreview then begin
{ create popup window }
pVideoWindow.put_AutoShow(True);
pVideoWindow.put_Visible(True);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -