📄 advoip.pas
字号:
CME_STREAM_INACTIVE :
begin
{ refresh our terminal collection }
LoadTerminals;
end;
CME_TERMINAL_FAIL :
begin
{ DoMessage('Call media event: terminal failed'); }
end;
CME_STREAM_ACTIVE :
begin
{ see if this is a video render terminal }
hr := GetVideoRenderTerminalFromStream(pCallMediaEvent,
pTerminal, fRenderStream);
if hr = S_OK then begin
pVideoWindow := nil;
hr := pTerminal.QueryInterface(IID_IVideoWindow,
pVideoWindow);
if hr = S_OK then begin
HostWindow(pVideoWindow, fRenderStream);
end;
end;
{ refresh our terminal collection }
LoadTerminals;
end;
end;
end;
end;
end;
end;
function TApdCustomVoIP.RegisterTapiEventInterface: HRESULT;
{ create the event sink and register it }
var
pCPC : IConnectionPointContainer;
pCP : IConnectionPoint;
begin
{Create event sink}
gpTAPIEventNotification := TApdTapiEventSink.Create(self);
{ensure valid}
if gpTAPIEventNotification = nil then begin
Result := E_FAIL;
Exit;
end;
Result := gpTapi.QueryInterface(IID_IConnectionPointContainer, pCPC);
if Result <> S_OK then Exit;
Result := pCPC.FindConnectionPoint(IID_ITTAPIEventNotification, pCP);
if Result <> S_OK then Exit;
Result := pCP.Advise(gpTAPIEventNotification, gulAdvise);
{ set the event filter to only give us the events we want }
gpTapi.Set_EventFilter(TE_CALLNOTIFICATION or TE_CALLSTATE or TE_CALLMEDIA);
end;
procedure TApdCustomVoIP.ReleaseTheCall;
{ um, release the call }
begin
if gpCall <> nil then
gpCall := nil;
end;
function TApdCustomVoIP.SelectTerminalOnCall(pAddress: ITAddress;
pCall: ITBasicCallControl): HRESULT;
{ find and select the terminals for the call }
var
pStreamControl : ITStreamControl;
pEnumStreams : IEnumStream;
pStream : ITStream;
pTerminal : ITTerminal;
Fetched : DWORD;
begin
{ get the ITStreamControl interface for this call }
Result := pCall.QueryInterface(IID_ITStreamControl, pStreamControl);
if Result = S_OK then begin
{ enumerate the streams }
pStreamControl.EnumerateStreams(pEnumStreams);
if pEnumStreams = nil then begin
Result := E_OUTOFMEMORY;
Exit;
end;
while pEnumStreams.Next(1, pStream, Fetched) = S_OK do begin
{ find the media type and direction of this stream and create }
{ the default terminal for this media type and direction }
Result := GetTerminal(pAddress, pStream, pTerminal);
if Result = S_OK then begin
{ select the terminal on the stream }
pStream.SelectTerminal(pTerminal);
if IsVideoCaptureStream(pStream) and FEnablePreview then
EnablePreviewWindow(pAddress, pStream);
end;
end;
end;
end;
procedure TApdCustomVoIP.SetAudioInDevice(const Value: string);
{ AudioOutDevice write access method }
begin
FAudioInDevice := Value;
if UpperCase(FAudioInDevice) = UpperCase(ApdDefaultTerminalName) then
FAudioInDevice := ApdDefaultTerminalName;
if (UpperCase(FAudioInDevice) = UpperCase(ApdNoTerminalName)) or
(FAudioInDevice = '') then
FAudioInDevice := ApdNoTerminalName;
end;
procedure TApdCustomVoIP.SetAudioOutDevice(const Value: string);
{ AudioOutDevice write access method }
begin
FAudioOutDevice := Value;
if UpperCase(FAudioOutDevice) = UpperCase(ApdDefaultTerminalName) then
FAudioOutDevice := ApdDefaultTerminalName;
if (UpperCase(FAudioOutDevice) = UpperCase(ApdNoTerminalName)) or
(FAudioOutDevice = '') then
FAudioOutDevice := ApdNoTerminalName;
end;
procedure TApdCustomVoIP.SetEnablePreview(const Value: Boolean);
{ EnablePreview write access method }
begin
FEnablePreview := Value;
if not FEnableVideo then
{ Preview is only available if we're transmitting video }
FEnablePreview := False;
end;
procedure TApdCustomVoIP.SetEnableVideo(const Value: Boolean);
{ EnableVideo write access method }
begin
FEnableVideo := Value;
if not FEnableVideo then
{ Preview is only available if we're transmitting video }
FEnablePreview := False;
end;
procedure TApdCustomVoIP.SetPreviewWindow(const Value: TWinControl);
{ PreviewWindow write access method }
begin
FPreviewWindow := Value;
end;
procedure TApdCustomVoIP.SetPreviewWindowAutoSize(const Value: Boolean);
begin
{ NOTE: Setting this property while stream is being rendered not supported }
FPreviewWindowAutoSize := Value;
end;
procedure TApdCustomVoIP.SetVideoInDevice(const Value: string);
{ VideoInDevice write access method }
begin
{ only default video in (local camera) terminal supported }
{ property is limited to '<none>' or '<default>' }
FVideoInDevice := Value;
if (UpperCase(FVideoInDevice) = UpperCase(ApdNoTerminalName)) or
(FVideoInDevice = '') then
FVideoInDevice := ApdNoTerminalName
else
FVideoInDevice := ApdDefaultTerminalName;
end;
procedure TApdCustomVoIP.SetVideoOutDevice(const Value: TWinControl);
{ VideoOutWindow write access method }
begin
FVideoOutWindow := Value;
end;
procedure TApdCustomVoIP.SetVideoOutWindowAutoSize(const Value: Boolean);
begin
{ NOTE: Setting this property while stream is being rendered not supported }
FVideoOutWindowAutoSize := Value;
end;
function TApdCustomVoIP.ShowMediaSelectionDialog: Boolean;
{ display the media selection dialog to select the audio/video in/out devices }
begin
if not FVoIPAvailable then
raise EVoIPNotSupported.CreateUnknown(sVoIPNotAvailable, 0);
Result := EditVoIPAudioVideo(Self, Name);
end;
procedure TApdCustomVoIP.ShutDownTapi;
{ deallocate our TAPI hooks }
begin
if gpCall <> nil then begin
gpCall := nil;
end;
if gpTapi <> nil then begin
gpTapi.Shutdown;
end;
end;
procedure TApdCustomVoIP.WndProc(var Message: TMessage);
{ message handler }
begin
case Message.Msg of
apw_VoIPNotifyMessage : {message sent by event sink }
begin
ProcessTapiEvent(TAPI_EVENT(Message.wParam), IDispatch(Message.lParam));
end;
apw_VoIPEventMessage : { message sent to generate event asynchronously }
begin
if Message.wParam in [etDisconnected, etFail] then begin {!!.01}
case Message.lParam of {!!.01}
CEC_NONE : FErrorCode := ecOK; {!!.01}
CEC_DISCONNECT_BUSY : FErrorCode := ecVoIPCallBusy; {!!.01}
CEC_DISCONNECT_BADADDRESS : FErrorCode := ecVoIPBadAddress; {!!.01}
CEC_DISCONNECT_NOANSWER : FErrorCode := ecVoIPNoAnswer; {!!.01}
CEC_DISCONNECT_CANCELLED : FErrorCode := ecVoIPCancelled; {!!.01}
CEC_DISCONNECT_REJECTED : FErrorCode := ecVoIPRejected; {!!.01}
CEC_DISCONNECT_FAILED : FErrorCode := ecVoIPFailed; {!!.01}
end; {!!.01}
end; {!!.01}
case Message.wParam of
etConnect : DoConnectEvent;
etDisconnected : DoDisconnectEvent;
etFail : DoFailEvent;
etIncomingCall : DoIncomingCallEvent;
etStatus : DoStatusEvent(0, 0, 0);
end;
end;
WM_TIMER : { this is our ConnectTimeout timer } {!!.04}
begin {!!.04}
if Message.WParam = FConnectTimer then begin
{ ConnectTimeout seconds have elapsed, cancel the attempt } {!!.04}
KillTimer(FHandle, FConnectTimer); {!!.04}
DisconnectTheCall; {!!.04}
end; {!!.04}
end; {!!.04}
else begin { default message processing }
try
Dispatch(Message);
if Message.Msg = WM_QUERYENDSESSION then
Message.Result := 1;
except
Application.HandleException(Self);
end;
end;
end;
end;
{ TApdTapiEventSink }
{ the event sink is an interface that gets the TAPI events, we post a message }
{ to the TApdCustomVoIP component to handle the events asynchronously }
function TApdTapiEventSink._AddRef: Integer;
begin
inc(FRefCount);
Result := FRefCount;
end;
function TApdTapiEventSink._Release: Integer;
begin
Dec(FRefCount);
if FRefCount = 0 then begin
Result := 0;
Free;
end else
Result := FRefCount;
end;
constructor TApdTapiEventSink.Create(AOwner: TApdCustomVoIP);
begin
FOwner := AOwner;
FAnswer := False;
end;
function TApdTapiEventSink.Event(TapiEvent: TAPI_EVENT;
const pEvent: IDispatch): HResult;
{ this is the event interface itself }
begin
pEvent._AddRef;
{ post a message to our WndProc so the event sink can respond to the next }
{ event }
PostMessage(FOwner.FHandle, apw_VoIPNotifyMessage,
wParam(TapiEvent), lParam(pEvent));
Result := S_OK;
end;
function TApdTapiEventSink.QueryInterface(const IID: TGUID;
out Obj): HResult;
begin
if (IsEqualGUID(IID, IUnknown) or IsEqualGUID(IID, IID_ITTAPIEventNotification)) then begin
inc(FRefCount);
if GetInterface(IID, Obj) then
Result := S_OK else Result := E_NOINTERFACE;
end else
Result := E_NOINTERFACE;
end;
{ TApdVoIPLog }
procedure TApdVoIPLog.AddLogString(Verbose : Boolean; const S: string);
var
LogStream : TFileStream;
TimeStamp : string;
begin
if FEnabled then
if Verbose and FVerboseLog then begin
if FileExists(FLogName) then
LogStream := TFileStream.Create(FLogName, fmOpenReadWrite or fmShareDenyNone)
else
LogStream := TFileStream.Create(FLogName, fmCreate or fmShareDenyNone);
LogStream.Seek(0, soFromEnd);
TimeStamp := FormatDateTime('dd/mm/yy : hh:mm:ss - ', Now) + S + #13#10;
LogStream.WriteBuffer(TimeStamp[1], Length(TimeStamp));
LogStream.Free;
end;
end;
procedure TApdVoIPLog.ClearLog;
begin
SysUtils.DeleteFile(FLogName);
end;
{ TApdVoIPTerminal }
function TApdVoIPTerminal.GetDeviceInUse: Boolean;
begin
Result := FTerminalState = tsInUse;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -