📄 tapirecv.cpp
字号:
VARIANT_TRUE,
TAPIMEDIATYPE_AUDIO,
g_nTAPINotificationCookie,
&ulCallNotificationCookie
);
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// StartListening
//
// find all addresses that support audio and start listening on them
//
///////////////////////////////////////////////////////////////////////////////
HRESULT StartListening()
{
HRESULT hr = S_OK;
LogMessage("StartListening: started");
//
// enumerate available addresses
//
IEnumAddress *pEnumAddress = NULL;
hr = g_pTapi->EnumerateAddresses( &pEnumAddress );
if (FAILED(hr))
{
LogError("StartListening: Failed to enumerate addresses");
return hr;
}
//
// this flag remains false until we succeded starting listening on at
// least one address
//
BOOL bListenStarted = FALSE;
//
// walk through all the addresses and start listening on the ones that
// support audio
//
while (TRUE)
{
//
// check the next address
//
ITAddress *pAddress = NULL;
hr = pEnumAddress->Next(1, &pAddress, NULL);
if (S_OK != hr)
{
//
// no more addresses or error
//
break;
}
//
// log the name of the address
//
BSTR bstrAddressName;
hr = pAddress->get_AddressName(&bstrAddressName);
if (SUCCEEDED(hr))
{
LogMessage("StartListening: -> found address [%S]",
bstrAddressName);
SysFreeString(bstrAddressName);
}
else
{
LogError("StartListening: failed to get address name");
}
//
// if the address supports audio and media streaming terminal,
// start listening
//
if ( AddressSupportsAudio(pAddress) && AddressSupportsMST(pAddress) )
{
//
// start listening on this address
//
LogMessage("StartListening: Starting listening.");
hr = ListenOnAddress(pAddress);
if (SUCCEEDED(hr))
{
//
// we are listening on at least one address
//
bListenStarted = TRUE;
LogMessage("StartListening: "
"-> started listening on this address");
}
else
{
//
// log an error and continue
//
LogError("StartListening: -> failed starting listening on this address, "
"hr = 0x%lx", hr);
}
}
else
{
LogMessage("StartListening: -> no audio or MST support on this address.");
}
pAddress->Release();
pAddress = NULL;
}
pEnumAddress->Release();
pEnumAddress = NULL;
//
// depending on whether we started listening or not, log a message and
// return the appropriate error code.
//
if (bListenStarted)
{
LogMessage("StartListening: completed. "
"Listening on one or more addresses");
return S_OK;
}
else
{
LogMessage("StartListening: completed. Not listening on any address.");
return E_FAIL;
}
}
///////////////////////////////////////////////////////////////////////////////
//
// InitializeTAPI
//
// create and initialize the tapi object
//
///////////////////////////////////////////////////////////////////////////////
HRESULT InitializeTAPI()
{
LogMessage("InitializeTAPI: started");
HRESULT hr = E_FAIL;
//
// cocreate the TAPI object
//
hr = CoCreateInstance(
CLSID_TAPI,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITTAPI,
(LPVOID *)&g_pTapi
);
if (FAILED(hr))
{
LogError("InitializeTAPI: failed to CoCreateInstance TAPI");
return hr;
}
//
// cannot use tapi until it's initialized
//
hr = g_pTapi->Initialize();
if (FAILED(hr))
{
LogError("InitializeTAPI: TAPI failed to initialize");
g_pTapi->Release();
g_pTapi = NULL;
return hr;
}
//
// register the callback object that will receive tapi notifications
//
hr = RegisterCallback();
if (FAILED(hr))
{
LogError("InitializeTAPI: failed to register callback");
g_pTapi->Shutdown();
g_pTapi->Release();
g_pTapi = NULL;
return hr;
}
//
// we want to be notified of these events:
//
hr = g_pTapi->put_EventFilter(TE_CALLNOTIFICATION |
TE_CALLSTATE |
TE_CALLMEDIA);
if (FAILED(hr))
{
LogError("InitializeTAPI: Failed to put_EventFilter");
//
// unregister callback
//
UnRegisterCallBack();
//
// shutdown and release TAPI
//
g_pTapi->Shutdown();
g_pTapi->Release();
g_pTapi = NULL;
return hr;
}
//
// start listening on the addresses that support audio
//
hr = StartListening();
if (S_OK != hr)
{
LogError("InitializeTAPI: Failed to start listening");
//
// unregister callback
//
UnRegisterCallBack();
//
// shutdown and release TAPI
//
g_pTapi->Shutdown();
g_pTapi->Release();
g_pTapi = NULL;
return hr;
}
LogMessage("InitializeTAPI: succeeded");
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
//
// DisconnectAndReleaseCall
//
// disconnect and release the current call, if we have one
//
///////////////////////////////////////////////////////////////////////////////
void DisconnectAndReleaseCall()
{
//
// g_pCurrentCall can be accessed from event-processing thread and
// needs to be protected
//
EnterCriticalSection(&g_CurrentCallCritSection);
if (NULL != g_pCurrentCall)
{
//
// if the call exists, attempt to disconnect it
//
LogMessage("DisconnectAndReleaseCall: disconnecting the call");
g_pCurrentCall->Disconnect(DC_NORMAL);
//
// succeded or failed, release the call
//
g_pCurrentCall->Release();
g_pCurrentCall = NULL;
}
LeaveCriticalSection(&g_CurrentCallCritSection);
}
///////////////////////////////////////////////////////////////////////////////
//
// ShutdownTapi
//
// - unregister callback object
// - shutdown and release TAPI object
//
///////////////////////////////////////////////////////////////////////////////
void ShutdownTapi()
{
LogMessage("ShutdownTapi: started");
//
// if there is still a call, disconnect it
//
HRESULT hr = E_FAIL;
//
// by now, the call is released and disconnected.
// shutdown tapi
//
if (NULL != g_pTapi)
{
//
// unregister callback
//
UnRegisterCallBack();
//
// shutdown and release the TAPI object
//
g_pTapi->Shutdown();
g_pTapi->Release();
g_pTapi = NULL;
}
//
// in the unlikely case another call was received after we released the
// call that we had, release the new call.
//
EnterCriticalSection(&g_CurrentCallCritSection);
if (NULL != g_pCurrentCall)
{
g_pCurrentCall->Release();
g_pCurrentCall = NULL;
}
LeaveCriticalSection(&g_CurrentCallCritSection);
LogMessage("ShutdownTapi: succeeded");
}
///////////////////////////////////////////////////////////////////////////////
//
// CtrlHandler
//
// set shutdown flag when the user requests exit by pressing
// ctrl+break, attempting to log off, close the window, or
// shutdown windows. this will give use a chance to exit gracefully.
//
///////////////////////////////////////////////////////////////////////////////
BOOL CtrlHandler(DWORD nEventType)
{
static BOOL bShutdownInProgress = FALSE;
//
// are we in the middle of shutting down?
//
if (TRUE == bShutdownInProgress)
{
LogMessage("CtrlHandler: Shutdown already in progress");
return TRUE;
}
//
// any exit event (close, ctrl+break/C, logoff, shutdown)
// is a signal for the application to exit.
//
switch (nEventType)
{
case CTRL_C_EVENT:
case CTRL_CLOSE_EVENT:
case CTRL_BREAK_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
LogMessage("CtrlHandler: Initiating shutdown.");
//
// ignore subsequent shutdown requests...
//
bShutdownInProgress = TRUE;
//
// signal shutdown
//
SetEvent(g_hExitEvent);
break;
default:
break;
}
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////
//
// main
//
///////////////////////////////////////////////////////////////////////////////
int __cdecl main(int argc, char* argv[])
{
LogMessage("main: started");
//
// this event be signalled when it's time to exit
//
g_hExitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (NULL == g_hExitEvent)
{
LogError("main: Failed to create exit event");
return 1;
}
//
// we want to handle ctrl+c and ctrl+break events so we can cleanup on exit
// proceed even in case of failure
//
SetConsoleCtrlHandler( (PHANDLER_ROUTINE)CtrlHandler, TRUE);
//
// initialize COM
//
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
if ( FAILED(hr))
{
LogError("main: Failed to CoInitialize");
CloseHandle(g_hExitEvent);
g_hExitEvent = NULL;
return 1;
}
//
// start worker thread for tapi message processing
//
hr = g_WorkerThread.Initialize();
if (FAILED(hr))
{
LogError("main: Failed to initialize worker thread");
CoUninitialize();
CloseHandle(g_hExitEvent);
g_hExitEvent = NULL;
return 1;
}
//
// initialize critical section used to serialize access to global
// current call
//
// note: InitializeCriticalSection can raise STATUS_NO_MEMORY exception
//
InitializeCriticalSection(&g_CurrentCallCritSection);
//
// create and initialize tapi object, register the callback object
// and start listening
//
hr = InitializeTAPI();
if (FAILED(hr))
{
g_WorkerThread.Shutdown();
CloseHandle(g_hExitEvent);
g_hExitEvent = NULL;
DeleteCriticalSection(&g_CurrentCallCritSection);
CoUninitialize();
return 1;
}
//
// wait until ctrl+break handler or CS_DISCONNECT handler signal exit event
//
LogMessage("main: waiting for exit event");
DWORD nWaitResult = WaitForSingleObject(g_hExitEvent, INFINITE);
LogMessage("main: exit event signaled");
//
// disconnect and release call, if it exists
//
DisconnectAndReleaseCall();
//
// cleanup tapi
//
ShutdownTapi();
//
// stop the worker thread
//
g_WorkerThread.Shutdown();
//
// no longer need the critical section
//
DeleteCriticalSection(&g_CurrentCallCritSection);
//
// release com
//
CoUninitialize();
//
// no longer need the event
//
CloseHandle(g_hExitEvent);
g_hExitEvent = NULL;
//
// exiting... we no longer want to handle ctrl+c and ctrl+break
//
SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, FALSE);
//
// was the event signaled, or wait failed?
//
if (WAIT_OBJECT_0 != nWaitResult)
{
LogError("main: Failed to wait for exit event");
return 1;
}
LogMessage("main: exiting");
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -