📄 tapisend.cpp
字号:
pAddress->Release();
pAddress = NULL;
if (FAILED(hr))
{
LogError("CreateCaptureMediaStreamingTerminal: "
"failed to QI pAddress for ITTerminalSupport");
return NULL;
}
//
// get string for the terminal's class id
//
LPOLESTR psTerminalClass = NULL;
hr = StringFromIID(CLSID_MediaStreamTerminal, &psTerminalClass);
if (FAILED(hr))
{
LogError("CreateCaptureMediaStreamingTerminal: "
"Failed to generate string from terminal's class id");
pTerminalSupport->Release();
pTerminalSupport = NULL;
return NULL;
}
//
// make bstr out of the class id
//
BSTR bstrTerminalClass = SysAllocString (psTerminalClass);
//
// free the string returned by StringFromIID
//
CoTaskMemFree(psTerminalClass);
psTerminalClass = NULL;
if (NULL == bstrTerminalClass)
{
LogError("CreateCaptureMediaStreamingTerminal: "
"Failed to allocate BSTR for terminal class");
pTerminalSupport->Release();
pTerminalSupport = NULL;
return NULL;
}
//
// create media streaming terminal
//
ITTerminal *pTerminal = NULL;
hr = pTerminalSupport->CreateTerminal(bstrTerminalClass,
TAPIMEDIATYPE_AUDIO,
TD_CAPTURE,
&pTerminal);
//
// release resources no longer needed
//
SysFreeString(bstrTerminalClass);
pTerminalSupport->Release();
pTerminalSupport = NULL;
if (FAILED(hr))
{
LogError("CreateCaptureMediaStreamingTerminal: "
"failed to create media streaming terminal hr = 0x%lx", hr);
return NULL;
}
//
// successfully created media streaming terminal. return.
//
LogMessage("CreateCaptureMediaStreamingTerminal: "
"Terminal created successfully");
return pTerminal;
}
///////////////////////////////////////////////////////////////////////////////
//
// SetTerminalFormat
//
// tell media streaming terminal the format of the data we are going to provide
//
///////////////////////////////////////////////////////////////////////////////
HRESULT SetTerminalFormat(IN ITTerminal *pTerminal,
IN WAVEFORMATEX *pWaveFormat)
{
HRESULT hr = E_FAIL;
//
// log format requested
//
LogMessage("SetTerminalFormat: starting.");
LogFormat(pWaveFormat);
ITAMMediaFormat *pIMediaFormat = NULL;
hr = pTerminal->QueryInterface(IID_ITAMMediaFormat,
(void **)&pIMediaFormat);
if (FAILED(hr))
{
LogError("SetTerminalFormat: Failed to set terminal format");
return hr;
}
//
// fill the media format structure
//
AM_MEDIA_TYPE MediaType;
ZeroMemory(&MediaType, sizeof(AM_MEDIA_TYPE));
MediaType.majortype = MEDIATYPE_Audio;
MediaType.subtype = MEDIASUBTYPE_PCM;
MediaType.bFixedSizeSamples = TRUE;
MediaType.bTemporalCompression = FALSE;
MediaType.lSampleSize = pWaveFormat->nBlockAlign;
MediaType.formattype = FORMAT_WaveFormatEx;
MediaType.pUnk = NULL;
MediaType.cbFormat = sizeof(WAVEFORMATEX) +
pWaveFormat->cbSize;
MediaType.pbFormat = (BYTE*)pWaveFormat;
//
// set the requested format
//
hr = pIMediaFormat->put_MediaFormat(&MediaType);
if (FAILED(hr))
{
//
// try to see what format the terminal wanted
//
LogError("SetTerminalFormat: failed to set format");
AM_MEDIA_TYPE *pMediaFormat = NULL;
HRESULT hr2 = pIMediaFormat->get_MediaFormat(&pMediaFormat);
if (SUCCEEDED(hr2))
{
if (pMediaFormat->formattype == FORMAT_WaveFormatEx)
{
//
// log the terminal's format
//
LogError("SetTerminalFormat: terminal's format is");
LogFormat((WAVEFORMATEX*) pMediaFormat->pbFormat);
}
else
{
LogError("SetTerminalFormat: "
"terminal's format is not WAVEFORMATEX");
}
//
// note: we are responsible for deallocating the format returned by
// get_MediaFormat
//
DeleteMediaType(pMediaFormat);
} // succeeded to get terminal's format
else
{
LogError("SetTerminalFormat: failed to get terminal's format");
}
} // failed to set format
pIMediaFormat->Release();
pIMediaFormat = NULL;
LogMessage("SetTerminalFormat: completed");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// SetAllocatorProperties
//
// sets allocator properties to the terminal
//
///////////////////////////////////////////////////////////////////////////////
HRESULT SetAllocatorProperties(IN ITTerminal *pTerminal)
{
//
// different buffer sizes may produce different sound quality, depending
// on the underlying transport that is being used.
//
// this function illustrates how an app can control the number and size of
// buffers. A multiple of 30 ms (480 bytes at 16-bit 8 KHz PCM) is the most
// appropriate sample size for IP (especailly G.723.1).
//
// However, small buffers can cause poor audio quality on some voice boards.
//
// If this method is not called, the allocator properties suggested by the
// connecting filter will be used.
//
// Note: do not set allocator properties in the applications unless you are
// sure that sound quality will not degrade as a result. Some MSPs can have
// their own preferred allocator properties, and will not be able to
// provide the best quality if the app sets its own properties, different
// from what is preferred by the msp.
//
// Also note that ITAllocatorProperties::SetBufferSize allows the app to
// specify preferred size of the buffer allocated to the application
// without affecting terminal's allocator properties.
//
LogMessage("SetAllocatorProperties: starting.");
HRESULT hr = E_FAIL;
//
// get ITAllocator properties interface on the terminal
//
ITAllocatorProperties *pITAllocatorProperties = NULL;
hr = pTerminal->QueryInterface(IID_ITAllocatorProperties,
(void **)&pITAllocatorProperties);
if (FAILED(hr))
{
LogError("SetAllocatorProperties: "
"failed to QI terminal for ITAllocatorProperties");
return hr;
}
//
// configure allocator properties
//
ALLOCATOR_PROPERTIES AllocProps;
AllocProps.cbBuffer = 4800;
AllocProps.cBuffers = 5;
AllocProps.cbAlign = 1;
AllocProps.cbPrefix = 0;
hr = pITAllocatorProperties->SetAllocatorProperties(&AllocProps);
if (FAILED(hr))
{
LogError("SetAllocatorProperties: failed to set allocator properties. "
"hr = 0x%lx", hr);
pITAllocatorProperties->Release();
pITAllocatorProperties = NULL;
return hr;
}
//
// ask media streaming terminal to allocate buffers for us.
// TRUE is the default, so strictly speaking, we didn't have to call
// this method.
//
hr = pITAllocatorProperties->SetAllocateBuffers(TRUE);
pITAllocatorProperties->Release();
pITAllocatorProperties = NULL;
if (FAILED(hr))
{
LogError("SetAllocatorProperties: failed to SetAllocateBuffers, "
"hr = 0x%lx", hr);
return hr;
}
//
// succeeded setting allocator properties
//
LogMessage("SetAllocatorProperties: completed");
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
//
// ReadFileIntoTerminal
//
// read data from the file and submit it to media streaming terminal
//
// exit when finished reading the file, user requested exit by pressing
// ctrl+break, or the connection broke
//
// returns S_FALSE when finished streaming the file, S_OK if user requested
// exit, failure otherwise
//
///////////////////////////////////////////////////////////////////////////////
HRESULT ReadFileIntoTerminal(IN CAVIFileReader *pFileReader,
IN ITTerminal *pPlaybackTerminal)
{
HRESULT hr = E_FAIL;
LogMessage("ReadFileIntoTerminal: started.");
Sleep(20000);
//
// get terminal's IMediaStream interface
//
IMediaStream *pTerminalMediaStream = NULL;
hr = pPlaybackTerminal->QueryInterface(IID_IMediaStream,
(void**)&pTerminalMediaStream);
if (FAILED(hr))
{
LogError("ReadFileIntoTerminal: "
"failed to QI terminal for IMediaStream");
return hr;
}
//
// create a queue (STL deque) that will hold all the samples that we ever
// submitted to media streaming terminal
//
// we need this so when we are finished reading the file, we can go through
// the list of all the samples that we have submitted and make sure mst
// is finished processing them
//
// note that samples get reused, the same samples will be put in the queue
// more than once. so the size of the queue will be proportional to the
// size of the file being played. this might cause problems if
// the file is big or the source of the samples is unlimited (live audio
// feed). In this case, the logic can be modified to only enqueue each
// sample once, by comparing against existing queue entries.
//
std::deque<IStreamSample*> SampleQ;
//
// count the number of samples that have been submitted
//
ULONG nSampleCount = 0;
//
// keep reading samples from file and sending them.
// (until user requests exit, there is no more data, or failure)
//
while (!g_bExitRequested)
{
//
// allocate a sample on the terminal's media stream
//
// Note: the call to AllocateSample() will block if we filled all the
// samples with data, and there are no more samples for us to fill
// (waiting for media streaming terminal to process samples we have
// submitted). When MST is is done with at least one sample, the call
// will return. This logic will ensure that MST always has work and is
// never starved for samples.
//
IStreamSample *pStreamSample = NULL;
hr = pTerminalMediaStream->AllocateSample(0, &pStreamSample);
if (FAILED(hr))
{
LogError("ReadFileIntoTerminal: "
"failed to allocate a sample on terminal's stream");
break;
}
//
// get IMemoryData on the sample so we can get to the sample's memory
// data
//
IMemoryData *pSampleMemoryData = NULL;
hr = pStreamSample->QueryInterface(IID_IMemoryData,
(void**)&pSampleMemoryData);
if (FAILED(hr))
{
LogError("ReadFileIntoTerminal: failed to qi sample for IMemoryData");
pStreamSample->Release();
pStreamSample = NULL;
break;
}
//
// get to the sample's memory buffer
//
DWORD nBufferSize = 0;
BYTE *pBuffer = NULL;
hr = pSampleMemoryData->GetInfo(&nBufferSize, &pBuffer, NULL);
if (FAILED(hr))
{
LogError("ReadFileIntoTerminal: "
"failed to get info on sample's memory");
pStreamSample->Release();
pStreamSample = NULL;
pSampleMemoryData->Release();
pSampleMemoryData = NULL;
break;
}
//
// read file into memory buffer provided by the sample
//
LONG nBytesRead = 0;
hr = pFileReader->Read(pBuffer, nBufferSize, &nBytesRead);
if (FAILED(hr))
{
LogError("ReadFileIntoTerminal: failed to read data from file");
pStreamSample->Release();
pStreamSample = NULL;
pSampleMemoryData->Release();
pSampleMemoryData = NULL;
break;
}
else if (S_FALSE == hr)
{
//
// no more data
//
LogMessage("ReadFileIntoTerminal: finished reading file");
pStreamSample->Release();
pStreamSample = NULL;
pSampleMemoryData->Release();
pSampleMemoryData = NULL;
break;
}
//
// tell the sample how many useful bytes are in the sample's buffer
//
hr = pSampleMemoryData->SetActual(nBytesRead);
pSampleMemoryData->Release();
pSampleMemoryData = NULL;
if (FAILED(hr))
{
LogError("ReadFileIntoTerminal: failed to SetActual (%ld bytes) "
"on the sample.", nBytesRead);
pStreamSample->Release();
pStreamSample = NULL;
break;
}
//
// we are done with the sample. now let media streaming terminal
// process it asynchronously. when the terminal is finished with
// the sample, this sample will be returned to us from the call
// to AllocateSample()
//
hr = pStreamSample->Update(SSUPDATE_ASYNC, NULL, NULL, 0);
//
// with some MSPs, starting the stream can be done asynchronously, so
// there may be a delay between the time when terminal is selected
// (or call connected) and the time when the stream becomes usable.
//
// attempting to use the stream before the stream is active would
// result in the Update() returning error VFW_E_NOT_COMMITTED.
//
// Usually an application would not start using the stream until
// it gets media event CME_STREAM_ACTIVE. This requires the app
// to register a callback interface by calling
// ITTAPI::RegisterCallNotifications. Refer to documentation and other
// samples for more details on how this is done.
//
// To keep things simple, this sample doesn't do event processing.
// To deal with the problem of using the stream before it becomes
// active, we retry Update() until we succeed.
//
// Note that there is still a danger that the stream becomes
// disconnected before we process the first sample, in which case
// we will be stuck in a loop, which can be exited when the user
// presses ctrl+break
//
while ( (hr == VFW_E_NOT_COMMITTED)
&& (0 == nSampleCount)
&& !g_bExitRequested )
{
LogMessage("ReadFileIntoTerminal: "
"Update returned VFW_E_NOT_COMMITTED. "
"Likely cause: stream not yet started. Retrying.");
Sleep( 1000 );
hr = pStreamSample->Update(SSUPDATE_ASYNC, NULL, NULL, 0);
}
if (FAILED(hr))
{
LogError("ReadFileIntoTerminal: failed to Update the sample");
pStreamSample->Release();
pStreamSample = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -