📄 tapirecv.cpp
字号:
/*
Copyright (c) 1999 - 2000 Microsoft Corporation
Module Name:
TAPIRecv.cpp
Abstract:
This sample illustrates the use of Media Streaming Terminal for receiving
audio.
The application listens on addresses that support audio, accepts an
incoming call and uses Media Streaming Terminal to get the incoming
data, which is written into a wav file.
*/
#include "common.h"
#include "Processing.h"
//
// main thread will wait on this event before exiting
//
HANDLE g_hExitEvent = NULL;
//
// the tapi object
//
ITTAPI *g_pTapi = NULL;
//
// the current call
//
ITBasicCallControl *g_pCurrentCall = NULL;
//
// critical section for protecting the global current call
//
CRITICAL_SECTION g_CurrentCallCritSection;
//
// the cookie from registering tapi event notification
//
ULONG g_nTAPINotificationCookie = 0;
///////////////////////////////////////////////////////////////////////////////
//
// LogMessage
//
//
// logs a message using printf
//
///////////////////////////////////////////////////////////////////////////////
void LogMessage(CHAR *pszFormat, ... )
{
//
// output buffer -- note: hardcoded limit
//
static const BUFFER_SIZE = 1280;
char szBuffer[BUFFER_SIZE];
//
// get current time
//
SYSTEMTIME SystemTime;
GetLocalTime(&SystemTime);
//
// format thread id and time
//
StringCbPrintf( szBuffer, BUFFER_SIZE, "[%lx]:[%02u:%02u:%02u.%03u]::",
GetCurrentThreadId(),
SystemTime.wHour,
SystemTime.wMinute,
SystemTime.wSecond,
SystemTime.wMilliseconds);
size_t iStringLength = 0;
HRESULT hr = StringCbLength(szBuffer, BUFFER_SIZE, &iStringLength);
if (FAILED(hr))
{
// either this code is wrong, or someone else in the process corrupted
// our memory.
return;
}
//
// get the actual message
//
va_list vaArguments;
va_start(vaArguments, pszFormat);
size_t iBytesLeft = BUFFER_SIZE - iStringLength;
//
// not checking the return code of this function. even if it fails, we will
// have a null-terminated string that we will be able to log.
//
StringCbVPrintf( &(szBuffer[iStringLength]), iBytesLeft, pszFormat, vaArguments);
va_end(vaArguments);
//
// how big is the string now, and how many bytes do we have left?
//
hr = StringCbLength(szBuffer, BUFFER_SIZE, &iStringLength);
if (FAILED(hr))
{
// either this code is wrong, or someone else in the process corrupted
// our memory.
return;
}
iBytesLeft = BUFFER_SIZE - iStringLength;
//
// append a carriage return to the string. ignore the result code, the
// result string will be null-terminated no matter what.
//
StringCbCat(szBuffer, iBytesLeft, "\n");
//
// log the buffer
//
printf(szBuffer);
}
///////////////////////////////////////////////////////////////////////////////
//
// LogFormat
//
// use LogMessage to log wave format
//
///////////////////////////////////////////////////////////////////////////////
void LogFormat(const WAVEFORMATEX *pWaveFormat)
{
LogMessage(" Format: ");
LogMessage(" tag: %u", pWaveFormat->wFormatTag);
LogMessage(" channels: %u", pWaveFormat->nChannels);
LogMessage(" samples/sec: %lu", pWaveFormat->nSamplesPerSec);
LogMessage(" align: %u", pWaveFormat->nBlockAlign);
LogMessage(" bits/sample: %u", pWaveFormat->wBitsPerSample);
}
///////////////////////////////////////////////////////////////////////////////
//
// AllocateMemory
//
// use win32 heap api to allocate memory on the application's heap
// and zero the allocated memory
//
///////////////////////////////////////////////////////////////////////////////
void *AllocateMemory(SIZE_T nMemorySize)
{
//
// use HeapAlloc to allocate and clear memory
//
return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nMemorySize);
}
///////////////////////////////////////////////////////////////////////////////
//
// FreeMemory
//
// use win32 heap api to free memory previously allocated on the application's
// heap
//
///////////////////////////////////////////////////////////////////////////////
void FreeMemory(void *pMemory)
{
//
// get size of the allocated memory
//
SIZE_T nMemorySize = HeapSize(GetProcessHeap(), 0, pMemory);
if (-1 == nMemorySize)
{
LogError("FreeMemory: failed to get size of the memory block %p",
pMemory);
//
// don't exit -- try freeing anyway
//
}
else
{
//
// fill memory with 0xdd's before freeing, so it is easier to debug
// failures caused by using pointer to deallocated memory
//
if (NULL != pMemory)
{
FillMemory(pMemory, nMemorySize, 0xdd);
}
}
//
// use HeapFree to free memory. use return code to log the result, but
// do not return it to the caller
//
BOOL bFreeSuccess = HeapFree(GetProcessHeap(), 0, pMemory);
if (FALSE == bFreeSuccess)
{
LogError("FreeMemory: HeapFree failed");
//
// if this assertion fires, it is likely there is a problem with the
// memory we are trying to deallocate. Was it allocated using heapalloc
// and on the same heap? Is this a valid pointer?
//
_ASSERTE(FALSE);
}
}
///////////////////////////////////////////////////////////////////////////////
//
// RegisterCallBack
//
//
// instantiate the callback object and register it with TAPI
//
///////////////////////////////////////////////////////////////////////////////
HRESULT RegisterCallback()
{
LogMessage("RegisterCallback: started");
HRESULT hr = S_OK;
//
// get connection point container on the tapi object
//
IConnectionPointContainer *pCPContainer = NULL;
hr = g_pTapi->QueryInterface(
IID_IConnectionPointContainer,
(void **)&pCPContainer
);
if (FAILED(hr))
{
LogError("RegisterCallback: "
"Failed to get IConnectionPointContainer on TAPI");
return hr;
}
//
// find connection point for our interface
//
IConnectionPoint *pCP = NULL;
hr = pCPContainer->FindConnectionPoint(IID_ITTAPIEventNotification, &pCP);
pCPContainer->Release();
pCPContainer = NULL;
if (FAILED(hr))
{
LogError("RegisterCallback: "
"Failed to get a connecion point for ITTAPIEventNotification");
return hr;
}
//
// create the callback object and register it with TAPI.
// for simplicity, the callback in this sample is not a
// full-fledged COM object. So create is with new.
//
ITTAPIEventNotification *pTAPIEventNotification =
new CTAPIEventNotification;
if (NULL == pTAPIEventNotification)
{
LogError("RegisterCallback: Failed to create a tapi event notification object.");
pCP->Release();
pCP = NULL;
return E_OUTOFMEMORY;
}
//
// will use the cookie later to register for events from addresses
// and to unregister the callback when we no longer needs the events
//
hr = pCP->Advise(pTAPIEventNotification,
&g_nTAPINotificationCookie);
pCP->Release();
pCP = NULL;
//
// whether Advise failed or succeeded, we no longer need a reference to
// the callback
//
pTAPIEventNotification->Release();
pTAPIEventNotification = NULL;
if (FAILED(hr))
{
g_nTAPINotificationCookie = 0;
LogError("RegisterCallback: Failed to Advise");
}
LogMessage("RegisterCallback: completed");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// UnRegisterCallBack
//
//
// unregister call notification object
//
///////////////////////////////////////////////////////////////////////////////
HRESULT UnRegisterCallBack()
{
LogMessage("UnRegisterCallBack: started");
HRESULT hr = S_OK;
//
// get connection point container on the tapi object
//
IConnectionPointContainer *pCPContainer = NULL;
hr = g_pTapi->QueryInterface(IID_IConnectionPointContainer,
(void **)&pCPContainer);
if (FAILED(hr))
{
LogError("UnRegisterCallBack: "
"Failed to get IConnectionPointContainer on TAPI");
return hr;
}
//
// find connection point for our interface
//
IConnectionPoint *pConnectionPoint = NULL;
hr = pCPContainer->FindConnectionPoint(IID_ITTAPIEventNotification,
&pConnectionPoint);
pCPContainer->Release();
pCPContainer = NULL;
if (FAILED(hr))
{
LogError("RegisterCallback: Failed to get a connection point for "
"ITTAPIEventNotification");
return hr;
}
//
// unregister the callback
//
hr = pConnectionPoint->Unadvise(g_nTAPINotificationCookie);
pConnectionPoint->Release();
pConnectionPoint = NULL;
g_nTAPINotificationCookie = 0;
if (FAILED(hr))
{
LogError("UnRegisterCallBack: Unadvise failed");
}
else
{
LogMessage("UnRegisterCallBack: succeeded");
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// AddressSupportsAudio
//
// return TRUE if the address supports audio
//
///////////////////////////////////////////////////////////////////////////////
BOOL AddressSupportsAudio(IN ITAddress *pAddress)
{
//
// get the address's ITMediaSupport so we can check
// the media type it supports
//
ITMediaSupport *pMediaSupport = NULL;
HRESULT hr = pAddress->QueryInterface(IID_ITMediaSupport,
(void**)&pMediaSupport);
if (FAILED(hr))
{
LogError("AddressSupportsAudio: "
"Failed to QI address for ITMediaSupport");
return FALSE;
}
//
// does the address support audio?
//
VARIANT_BOOL bAudioSupported = VARIANT_FALSE;
hr = pMediaSupport->QueryMediaType(TAPIMEDIATYPE_AUDIO, &bAudioSupported);
pMediaSupport->Release();
pMediaSupport = NULL;
if (FAILED(hr))
{
LogError("AddressSupportsAudio: Failed to QueryMediaType");
return FALSE;
}
if (VARIANT_TRUE == bAudioSupported)
{
LogMessage("AddressSupportsAudio: audio supported on this address");
return TRUE;
}
else
{
LogMessage("AddressSupportsAudio: "
"audio NOT supported on this address");
return FALSE;
}
}
///////////////////////////////////////////////////////////////////////////////
//
// AddressSupportsMST
//
// return TRUE if the address supports media streaming terminal
//
///////////////////////////////////////////////////////////////////////////////
BOOL AddressSupportsMST(IN ITAddress *pAddress)
{
//
// get the address's ITTerminalSupport so we can check
// the terminals it supports
//
ITTerminalSupport *pTerminalSupport = NULL;
HRESULT hr = pAddress->QueryInterface( IID_ITTerminalSupport,
(void **)&pTerminalSupport );
if (FAILED(hr))
{
LogError("AddressSupportsMST: Failed to QI address for ITTerminalSupport");
return FALSE;
}
//
// get enumeration of dynamic terminal classes this address supports
//
IEnumTerminalClass *pTerminalClassEnumerator = NULL;
hr = pTerminalSupport->EnumerateDynamicTerminalClasses(&pTerminalClassEnumerator);
pTerminalSupport->Release();
pTerminalSupport = NULL;
if (FAILED(hr))
{
LogError("AddressSupportsMST: Failed to get dynamic terminal classes");
return FALSE;
}
//
// walk through terminal class enumeration and see if the
// media streaming terminal is in it
//
while (TRUE)
{
GUID guid;
hr = pTerminalClassEnumerator->Next(1, &guid, NULL);
if (S_OK != hr)
{
LogMessage("AddressSupportsMST: no more terminal classes. "
"MST not supported on this address");
break;
}
if ( IsEqualGUID(guid, CLSID_MediaStreamTerminal))
{
LogMessage("AddressSupportsMST: media streaming terminal supported");
break;
}
}
//
// no longer need the enumeration
//
pTerminalClassEnumerator->Release();
pTerminalClassEnumerator = NULL;
//
// if we did not break out of the loop because the enumeration ended,
// media streaming terminal was not in the list of supported terminals
//
if (S_OK == hr)
{
return TRUE;
}
else
{
return FALSE;
}
}
///////////////////////////////////////////////////////////////////////////////
//
// ListenOnAddress
//
// register to receieve notifications of calls on this addres.
// calls on this address will trigger events on the callback object
// we have registered with TAPI earlier.
//
///////////////////////////////////////////////////////////////////////////////
HRESULT ListenOnAddress(ITAddress *pAddress)
{
long ulCallNotificationCookie = 0;
//
// we want to be notified of the status of this address
//
// the app can keep the cookies to later unregister from events
// from specific addresses (by calling ITTAPI::UnregisterNotifications)
// when it no longer wants to receive events for this specific address.
// this sample does not do this for simplicity.
//
HRESULT hr= g_pTapi->RegisterCallNotifications(pAddress,
VARIANT_TRUE,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -