📄 tapisend.cpp
字号:
/*
Copyright (c) 1999 Microsoft Corporation
Module Name:
TAPISend.cpp
Abstract:
This sample illustrates use of Media Streaming Terminal for sending audio.
The application makes a TAPI call to the address specified in the command
line and uses Media Streaming Terminal to send the media content of a wav
file, also specified in the command line, to the remote machibe.
*/
#include "common.h"
#include "avifilereader.h"
//
// global TAPI object
//
ITTAPI *g_pTapi = NULL;
//
// a global flag, set true to request stop streaming
//
BOOL g_bExitRequested = FALSE;
//
// possible address types strings and corresponding LINEADDRESSTYPE_ constants
//
char *g_szAddressTypes[] =
{"PHONENUMBER", "CONFERENCE", "EMAIL", "MACHINE", "IP"};
long g_nAddressTypeConstants[] =
{ LINEADDRESSTYPE_PHONENUMBER,
LINEADDRESSTYPE_SDP,
LINEADDRESSTYPE_EMAILNAME,
LINEADDRESSTYPE_DOMAINNAME,
LINEADDRESSTYPE_IPADDRESS };
//
// number of different address types
//
const UINT g_nNumberOfAddressTypes =
sizeof(g_szAddressTypes)/sizeof(g_szAddressTypes[0]);
///////////////////////////////////////////////////////////////////////////////
//
// LogMessage
//
//
// log a message using printf
//
///////////////////////////////////////////////////////////////////////////////
void LogMessage(IN 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);
}
#define LogError LogMessage
///////////////////////////////////////////////////////////////////////////////
//
// LogFormat
//
// use LogMessage to log wave format
//
///////////////////////////////////////////////////////////////////////////////
void LogFormat(IN 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 (0 != 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);
}
}
///////////////////////////////////////////////////////////////////////////////
//
// InitializeTAPI()
//
// create and initialize the TAPI object
//
///////////////////////////////////////////////////////////////////////////////
HRESULT InitializeTAPI()
{
HRESULT hr = E_FAIL;
LogMessage("InitializeTAPI: started");
//
// create the TAPI object
//
hr = CoCreateInstance(
CLSID_TAPI,
NULL,
CLSCTX_INPROC_SERVER,
IID_ITTAPI,
(LPVOID *)&g_pTapi
);
if (FAILED(hr))
{
LogError("InitializeTAPI: CoCreateInstance on TAPI failed");
return hr;
}
//
// must initialize tapi object before using it
//
LogMessage("InitializeTAPI: calling ITTAPI::Initialize()");
hr = g_pTapi->Initialize();
if (FAILED(hr))
{
LogError("InitializeTAPI: TAPI failed to initialize");
g_pTapi->Release();
g_pTapi = NULL;
return hr;
}
//
// setting event filtering -- this is required for synchronous
// ITBasicCallControl->Connect to work
//
LogMessage("InitializeTAPI: calling ITTAPI::put_EventFilter()");
hr = g_pTapi->put_EventFilter(TE_CALLSTATE);
if (FAILED(hr))
{
LogError("InitializeTAPI: TAPI failed to put event filtering");
g_pTapi->Shutdown();
g_pTapi->Release();
g_pTapi = NULL;
return hr;
}
LogMessage("InitializeTAPI: succeeded");
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
//
// ShutdownTAPI
//
// shutdown and release the tapi object
//
///////////////////////////////////////////////////////////////////////////////
void ShutdownTAPI()
{
LogMessage("ShutdownTAPI: started");
if (NULL != g_pTapi)
{
g_pTapi->Shutdown();
g_pTapi->Release();
g_pTapi = NULL;
}
LogMessage("ShutdownTAPI: completed");
}
///////////////////////////////////////////////////////////////////////////////
//
// IsValidAudioFile
//
// returns TRUE if the file specified by pszFileName
// exists and is a valid audio file
//
///////////////////////////////////////////////////////////////////////////////
BOOL IsValidAudioFile(IN char *pszFileName)
{
//
// open the file
//
CAVIFileReader FileReader;
HRESULT hr = FileReader.Initialize(pszFileName);
//
// see if it is a valid audio file
//
if ((FAILED(hr)) || !FileReader.IsValidAudioFile())
{
LogError("IsValidAudioFile: file [%s] does not exist or is not "
"a valid wav file", pszFileName);
return FALSE;
}
else
{
LogMessage("IsValidAudioFile: file [%s] is a valid audio file",
pszFileName);
return TRUE;
}
}
///////////////////////////////////////////////////////////////////////////////
//
// FindAddress
//
// find an address of the requested type that supports audio. returns S_OK
// if address found, failure otherwise
//
///////////////////////////////////////////////////////////////////////////////
HRESULT FindAddress(IN long nAddressType,
OUT ITAddress **ppAddress)
{
HRESULT hr = E_FAIL;
//
// don't return garbage even if we fail
//
*ppAddress = NULL;
//
// enumerate all available addresses
//
IEnumAddress *pEnumAddress = NULL;
hr = g_pTapi->EnumerateAddresses(&pEnumAddress);
if (FAILED(hr))
{
LogError("FindAddress: Failed to enumerate addresses");
return hr;
}
//
// walk through the enumeration of addresses and look for those which are
// of requested type and supports audio
//
while (TRUE)
{
//
// get the next address from the enumeration
//
ITAddress *pAddress = NULL;
hr = pEnumAddress->Next( 1, &pAddress, NULL );
if (S_OK != hr)
{
//
// no more addresses
//
LogMessage("FindAddress: no more addresses");
break;
}
//
// we got an address. check its capabilities
//
ITAddressCapabilities *pAddressCaps = NULL;
hr = pAddress->QueryInterface( IID_ITAddressCapabilities,
(void**)&pAddressCaps );
if (FAILED(hr))
{
LogError("FindAddress: "
"Failed to QI address for address capabilities");
//
// just continue to the next address
//
pAddress->Release();
pAddress = NULL;
continue;
}
//
// is this the right address type?
//
long nType = 0;
hr = pAddressCaps->get_AddressCapability(AC_ADDRESSTYPES, &nType);
pAddressCaps->Release();
pAddressCaps = NULL;
if (FAILED(hr))
{
LogError("FindAddress: Failed to get_AddressCapability");
pAddress->Release();
pAddress = NULL;
continue;
}
if (nType & nAddressType)
{
//
// this address is of the right type. does it support audio?
//
ITMediaSupport *pMediaSupport = NULL;
hr = pAddress->QueryInterface(IID_ITMediaSupport,
(void **)&pMediaSupport);
if (FAILED(hr))
{
//
// continue to the next address
//
LogError("FindAddress: "
"failed to qi address for ITMediaSupport");
pAddress->Release();
pAddress = NULL;
continue;
}
VARIANT_BOOL bAudioSupported = VARIANT_FALSE;
hr = pMediaSupport->QueryMediaType(TAPIMEDIATYPE_AUDIO,
&bAudioSupported);
pMediaSupport->Release();
pMediaSupport = NULL;
if (SUCCEEDED(hr) && (VARIANT_TRUE == bAudioSupported))
{
LogMessage("FindAddress: address found");
//
// log the name of this address
//
BSTR bstrAddressName = NULL;
hr = pAddress->get_AddressName(&bstrAddressName);
if (FAILED(hr))
{
LogError("FindAddress: failed to get address name");
}
else
{
LogMessage(" %S\n", bstrAddressName);
}
SysFreeString(bstrAddressName);
//
// will use this address
//
*ppAddress = pAddress;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -