📄 processing.cpp
字号:
hr = pSampleMemoryData->GetInfo(&nBufferSize,
&pnDataBuffer,
&nActualDataSize);
pSampleMemoryData->Release();
pSampleMemoryData = NULL;
if (FAILED(hr))
{
LogError("WriteSampleToFile: "
"Failed to get to the sample's data");
return hr;
}
//
// write the data buffer to the avi file
//
LogMessage("WriteSampleToFile: received a sample of size %ld bytes",
nActualDataSize);
ULONG nBytesWritten = 0;
hr = pFileWriter->Write(pnDataBuffer,
nActualDataSize,
&nBytesWritten);
if (FAILED(hr) || (0 == nBytesWritten))
{
LogError("WriteSampleToFile: FileWriter.Write() wrote no data.");
return E_FAIL;
}
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// GetSampleID
//
// given the return code fom WaitForMultipleObjects, this function determines
// which sample was signal and returns S_OK and the id of the signaled sample
// or E_FAIL if WaitForMultipleEvents returned an error
//
///////////////////////////////////////////////////////////////////////////////
HRESULT GetSampleID(IN DWORD nWaitCode, // code from WaitForMultiple...
IN DWORD nNumberOfSamples, // the total number of samples
IN OUT DWORD *pnSampleID) // the calculated id of the
// signaled sample
{
//
// event abandoned?
//
if ( (nWaitCode >= WAIT_ABANDONED_0) &&
(nWaitCode < WAIT_ABANDONED_0 + nNumberOfSamples) )
{
LogError("GetSampleID: event for sample #%lu abandoned.",
nWaitCode - WAIT_ABANDONED_0);
return E_FAIL;
}
//
// any other error?
//
if ( (WAIT_OBJECT_0 > nWaitCode) ||
(WAIT_OBJECT_0 + nNumberOfSamples <= nWaitCode) )
{
LogMessage("GetSampleID: "
"waiting for samples failed or timed out. "
"WaitForMultipleObjects returned %lu", nWaitCode);
return E_FAIL;
}
//
// which sample was signaled?
//
*pnSampleID = nWaitCode - WAIT_OBJECT_0;
return S_OK;
}
///////////////////////////////////////////////////////////////////////////////
//
// WriteStreamToFile
//
// extract samples from the terminal's media stream and write them into a file
//
// returns when the call is disconnected (call disconnect causes media streaming
// terminal to abort the samples
//
///////////////////////////////////////////////////////////////////////////////
HRESULT WriteStreamToFile(IN IMediaStream *pTerminalMediaStream)
{
LogMessage("WriteStreamToFile: started");
HRESULT hr = E_FAIL;
//
// get the number of stream samples we will be using
//
DWORD nNumberOfSamples = 0;
hr = GetNumberOfSamplesOnStream(pTerminalMediaStream, &nNumberOfSamples);
if (FAILED(hr))
{
LogError("WriteStreamToFile: failed to get the number of samples");
return hr;
}
//
// the number of samples directly corresponds the number of events we will
// be waiting on later. WaitForMultipleObjects has a limit of
// MAXIMUM_WAIT_OBJECTS events.
//
if (nNumberOfSamples > MAXIMUM_WAIT_OBJECTS)
{
LogError("WriteStreamToFile: the number of samples [%ld] "
"exceeds the number allowed by the design of this "
"application [%ld]",
nNumberOfSamples, MAXIMUM_WAIT_OBJECTS);
return E_FAIL;
}
//
// allocate events that will be signaled when each sample is ready to be
// saved to a file
//
HANDLE *pSampleReadyEvents = NULL;
pSampleReadyEvents = AllocateEvents(nNumberOfSamples);
if (NULL == pSampleReadyEvents)
{
LogError("WriteStreamToFile: Failed to allocate sample ready events.");
return E_OUTOFMEMORY;
}
//
// allocate array of stream samples
//
IStreamSample **ppStreamSamples = NULL;
ppStreamSamples = AllocateStreamSamples(pTerminalMediaStream,
nNumberOfSamples);
if (NULL == ppStreamSamples)
{
LogError("WriteStreamToFile: Failed to allocate stream sample array");
//
// release events we have allocated
//
ReleaseEvents(pSampleReadyEvents, nNumberOfSamples);
pSampleReadyEvents = NULL;
return E_FAIL;
}
//
// we have the samples, we have the events.
// associate events with samples so events get signaled when the
// corresponding samples are ready to be written to a file
//
hr = AssociateEventsWithSamples(pSampleReadyEvents,
ppStreamSamples,
nNumberOfSamples);
if (FAILED(hr))
{
LogError("WriteStreamToFile: Failed to associate events with samples");
//
// release events and samples we have allocated
//
ReleaseEvents(pSampleReadyEvents, nNumberOfSamples);
pSampleReadyEvents = NULL;
ReleaseSamples(ppStreamSamples, nNumberOfSamples);
ppStreamSamples = NULL;
return E_FAIL;
}
//
// get the format of the data delivered by media streaming terminal
//
WAVEFORMATEX *pAudioFormat = NULL;
pAudioFormat = GetAudioFormat(pTerminalMediaStream);
if (NULL == pAudioFormat)
{
LogError("WriteStreamToFile: Failed to get audio format");
//
// release events and samples we have allocated
//
ReleaseEvents(pSampleReadyEvents, nNumberOfSamples);
pSampleReadyEvents = NULL;
ReleaseSamples(ppStreamSamples, nNumberOfSamples);
ppStreamSamples = NULL;
return E_FAIL;
}
//
// create a file with the required name and format.
//
CAVIFileWriter FileWriter;
hr = FileWriter.Initialize(SZ_OUTPUTFILENAME, *pAudioFormat);
//
// no longer need audio format
//
FreeMemory(pAudioFormat);
pAudioFormat = NULL;
if (FAILED(hr))
{
LogError("WriteStreamToFile: open file");
//
// release events and samples we have allocated
//
ReleaseEvents(pSampleReadyEvents, nNumberOfSamples);
pSampleReadyEvents = NULL;
ReleaseSamples(ppStreamSamples, nNumberOfSamples);
ppStreamSamples = NULL;
return hr;
}
//
// just for logging, count the number of samples we have recorded
//
ULONG nStreamSamplesRecorded = 0;
while(TRUE)
{
//
// wait for the events associated with the samples
// when a samples has data, the corresponding event will be
// signaled
//
DWORD nWaitCode = WaitForMultipleObjects(nNumberOfSamples,
pSampleReadyEvents,
FALSE,
INFINITE);
//
// get the id of the sample that was signaled. fail if Wait returned
// error
//
DWORD nSampleID = 0;
hr = GetSampleID(nWaitCode, nNumberOfSamples, &nSampleID);
if (FAILED(hr))
{
LogError("WriteStreamToFile: wait failed");
break;
}
//
// we filtered out all invalid error codes. so nSampleID has no
// choice but be a valid sample index.
//
_ASSERTE(nSampleID < nNumberOfSamples);
//
// make sure the sample is ready to be read
//
hr = ppStreamSamples[nSampleID]->CompletionStatus(COMPSTAT_WAIT, 0);
//
// check against S_OK explicitly -- not all success codes mean the
// sample is ready to be used (MS_S_ENDOFSTREAM, etc)
//
if (S_OK != hr)
{
if (E_ABORT == hr)
{
//
// recording was aborted, probably because
// the call was disconnected
//
LogMessage("WriteStreamToFile: recording aborted");
}
else
{
LogMessage("WriteStreamToFile: sample is not completed. "
"hr = 0x%lx", hr);
}
break;
}
//
// we have the sample that was signaled and which is now ready to be
// saved to a file. Record the sample.
//
hr = WriteSampleToFile(ppStreamSamples[nSampleID], &FileWriter);
if (FAILED(hr))
{
LogError("WriteStreamToFile: failed to write sample to file");
break;
}
//
// one more sample was recorded. update the count.
//
nStreamSamplesRecorded++;
//
// we are done with this sample. return it to the source stream
// to be refilled with data
//
hr = ppStreamSamples[nSampleID]->Update(0,
pSampleReadyEvents[nSampleID],
NULL,
0);
if (FAILED(hr))
{
LogError("WriteStreamToFile: "
"Failed to Update the sample recorded. "
"hr = 0x%lx", hr);
break;
}
} // sample-writing loop
LogMessage("WriteStreamToFile: wrote the total of %lu samples",
nStreamSamplesRecorded);
//
// release samples and events
//
ReleaseSamples(ppStreamSamples, nNumberOfSamples);
ppStreamSamples = NULL;
ReleaseEvents(pSampleReadyEvents, nNumberOfSamples);
pSampleReadyEvents = NULL;
//
// deallocated samples and events. safe to exit.
//
LogMessage("WriteStreamToFile: completed, hr = 0x%lx", hr);
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// RecordMessage
//
// record the terminal's stream into a file
//
///////////////////////////////////////////////////////////////////////////////
HRESULT RecordMessage(IN ITTerminal *pRecordTerm)
{
LogMessage("RecordMessage: started");
HRESULT hr = E_FAIL;
//
// get IMediaStream interface on the terminal
//
IMediaStream *pTerminalMediaStream = NULL;
hr = pRecordTerm->QueryInterface(IID_IMediaStream,
(void**)&pTerminalMediaStream);
if (FAILED(hr))
{
LogError("RecordMessage: Failed to qi terminal for IMediaStream.");
return hr;
}
//
// write terminal stream data to a file
//
hr = WriteStreamToFile(pTerminalMediaStream);
//
// done with the terminal stream, release.
//
pTerminalMediaStream->Release();
pTerminalMediaStream = NULL;
LogMessage("RecordMessage: finished");
return hr;
}
///////////////////////////////////////////////////////////////////////////////
//
// ProcessCallNotificationEvent
//
// processing for TE_CALLNOTIFICATION event
//
///////////////////////////////////////////////////////////////////////////////
HRESULT ProcessCallNotificationEvent(IDispatch *pEvent)
{
HRESULT hr = E_FAIL;
//
// we are being notified of a new call
//
// if we own the call and there is not other active call
// consider this to be the active call
//
// wait for CS_OFFERING message before answering the call
//
ITCallNotificationEvent *pCallNotificationEvent = NULL;
hr = pEvent->QueryInterface( IID_ITCallNotificationEvent,
(void **)&pCallNotificationEvent);
if (FAILED(hr))
{
LogError("ProcessCallNotificationEvent: "
"Failed to QI event for ITCallNotificationEvent");
return hr;
}
//
// get the call from notification event
//
ITCallInfo *pCall = NULL;
hr = pCallNotificationEvent->get_Call(&pCall);
//
// release the ITCallNotificationEvent interface
//
pCallNotificationEvent->Release();
pCallNotificationEvent = NULL;
if (FAILED(hr))
{
LogError("ProcessCallNotificationEvent: "
"Failed to get call from Call notification event");
return hr;
}
//
// if we already have an active call, reject the new incoming call
//
EnterCriticalSection(&g_CurrentCallCritSection);
if (NULL != g_pCurrentCall)
{
LeaveCriticalSection(&g_CurrentCallCritSection);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -