📄 tapieventprocess.cpp
字号:
//
V_VT(&varPlaylist) = VT_ARRAY | VT_VARIANT;
V_ARRAY(&varPlaylist) = pPlayListArray;
//
// 最后,现在可以调用 put_PlayList 把 varPlaylist 放入到播放列表里了
//
hr = pMediaPlayback->put_PlayList(varPlaylist);
if(FAILED(hr))
{
AfxMessageBox("PutPlayList: put_PlayList failed");
delete pvarArrayEntry;
return E_OUTOFMEMORY;
}
//
//释放内存
//
delete pvarArrayEntry;
pMediaPlayback->Release();
VariantClear(&varPlaylist);
return hr;
}
///////////////////////////////////////////////////////////////////
// StartRecord
//
//
// 功能:录音
// 说明:只有 WinXP 下才支持
///////////////////////////////////////////////////////////////////
HRESULT CTapi::StartRecord()
{
HRESULT hr;
hr = CreateAndSelectFileRecordTerminal();
if(FAILED(hr))
{
//
// 致命错误 - 无法继续下去 - 切断此次通话
//
m_pCall->Disconnect(DC_NORMAL);
AfxMessageBox("CreateAndSelectFileRecordTerminal failed");
return hr;
}
//
// 获得 ITMediaControl 接口 - we need to call Start
//
ITMediaControl* pITMC = NULL;
hr = m_pRecordFileTerm->QueryInterface(IID_ITMediaControl, (void**)&pITMC);
if(FAILED(hr))
{
//
// 致命错误 - 无法继续下去 - 切断此次通话
//
AfxMessageBox("ITFileTerminalEvent, but failed to QI ITMediaControl");
m_pCall->Disconnect(DC_NORMAL);
return hr;
}
hr = pITMC->Start();
pITMC->Release();
if(FAILED(hr))
{
//
// 致命错误 - 无法继续下去 - 切断此次通话
//
AfxMessageBox("ITFileTerminalEvent, but ITMediaControl::Start");
m_pCall->Disconnect(DC_NORMAL);
return hr;
}
//
// 录音一分钟后自动停止
//
SetTimer(m_hWnd,Timer_ID, Max_Rec_Time, NULL);
m_dwMessages++;
KillTimer(m_hWnd,Timer_ID);
return S_OK;
}
///////////////////////////////////////////////////////////////////
// CheckStreamMT
//
// 检测输入的 pITStream 是否支持给定的媒体类型
//
///////////////////////////////////////////////////////////////////
HRESULT CTapi::CheckStreamMT(
IN ITStream* pITStream,
IN long mt)
{
long mtStream = TAPIMEDIATYPE_AUDIO;
HRESULT hr = E_FAIL;
if(FAILED(hr=pITStream->get_MediaType(&mtStream)))
{
return hr;
}
if(!(mt&mtStream))
{
return S_FALSE;
}
else
{
return S_OK;
}
}
///////////////////////////////////////////////////////////////////
// CheckStreamDir
//
// 检测输入的 pITStream 是否有给定的媒体流方向
//
///////////////////////////////////////////////////////////////////
HRESULT CTapi::CheckStreamDir(
IN ITStream* pITStream,
IN TERMINAL_DIRECTION td)
{
TERMINAL_DIRECTION tdStream = TD_CAPTURE ;
HRESULT hr =E_FAIL;
if(FAILED(hr=pITStream->get_Direction(&tdStream)))
{
return hr;
}
if(td!=tdStream)
{
return S_FALSE;
}
else
{
return S_OK;
}
}
///////////////////////////////////////////////////////////////////
// CreateAndSelectFileRecordTerminal
//
// 功能:
// 1. 创建录音文件终端,
// 2. 并对其指定录音文件名,
// 3. 对当前输入媒体流选择音轨终端
///////////////////////////////////////////////////////////////////
HRESULT CTapi::CreateAndSelectFileRecordTerminal()
{
//
// 检测当前 m_pCall 是否有效
//
if (NULL == m_pCall)
{
AfxMessageBox("CreateAndSelectFileRecordTerminal: m_pCall 无效,可能当前没有通话");
return E_UNEXPECTED;
}
//
// 获得 ITStreamControl 接口
//
ITStreamControl* pStreamControl = NULL;
HRESULT hr = m_pCall->QueryInterface( IID_ITStreamControl, (void**)&pStreamControl );
if (FAILED(hr))
{
AfxMessageBox("CreateAndSelectFileRecordTerminal: QI for ITStreamControl failed");
return E_FAIL;
}
//
// 确保录音终端在这之前已经释放
//
if(NULL != m_pRecordFileTerm)
{
m_pRecordFileTerm->Release();
m_pRecordFileTerm = NULL;
}
//
// QI for ITBasicCallControl2 - 准备请求终端
//
ITBasicCallControl2* pITBCC2 = NULL;
hr = m_pCall->QueryInterface( IID_ITBasicCallControl2, (void**)&pITBCC2 );
if(FAILED(hr))
{
pStreamControl->Release();
AfxMessageBox("CreateAndSelectFileRecordTerminal: QI for ITBasicCallControl2 failed");
return hr;
}
//
// 为 ReqestTerminal 获得 CLSID
//
BSTR bstrCLSID = NULL;
hr = StringFromCLSID(CLSID_FileRecordingTerminal, &bstrCLSID);
if(FAILED(hr))
{
pITBCC2->Release();
pStreamControl->Release();
AfxMessageBox("CreateAndSelectFileRecordTerminal: StringFromCLSID failed");
return hr;
}
//
// 请求录音终端,需要输入 媒体类型 和 媒体流方向
//
hr = pITBCC2->RequestTerminal(bstrCLSID,
TAPIMEDIATYPE_AUDIO,
TD_RENDER,
&m_pRecordFileTerm);
//
// 释放内存
//
::CoTaskMemFree(bstrCLSID);
pITBCC2->Release();
if(FAILED(hr))
{
pStreamControl->Release();
AfxMessageBox("CreateAndSelectFileRecordTerminal: RequestTerminal failed");
return hr;
}
//
// 获得 ITMediaRecord 接口,然后可以调用 put_FileName 来指定要录音的文件名
//
ITMediaRecord* pITMediaRec = NULL;
hr = m_pRecordFileTerm->QueryInterface( IID_ITMediaRecord, (void**)&pITMediaRec );
if(FAILED(hr))
{
pStreamControl->Release();
AfxMessageBox("CreateAndSelectFileRecordTerminal: QI ITMediaRecord failed");
return hr;
}
//
// 为受到的每一个消息建立不同的文件,一文件名后面的数字来区分
//
CString RecFileName;
CString tmp;
tmp.Format("%d.", m_dwMessages);
RecFileName = m_RecFileName + tmp + m_RecFileExt;
BSTR bstrFileName = RecFileName.AllocSysString();
if(NULL == bstrFileName)
{
pStreamControl->Release();
AfxMessageBox("CreateAndSelectFileRecordTerminal: SysAllocString failed");
return E_OUTOFMEMORY;
}
//
// 设置文件名
//
hr = pITMediaRec->put_FileName(bstrFileName);
//
// 释放内存
//
::SysFreeString(bstrFileName);
pITMediaRec->Release();
if(FAILED(hr))
{
pStreamControl->Release();
AfxMessageBox("CreateAndSelectFileRecordTerminal: put_FileName failed");
return hr;
}
//
// 获得 ITMultiTrackTerminal 接口
//
ITMultiTrackTerminal* pMTRecTerminal = NULL;
hr = m_pRecordFileTerm->QueryInterface( IID_ITMultiTrackTerminal, (void**)&pMTRecTerminal );
if(FAILED(hr))
{
pStreamControl->Release();
AfxMessageBox("CreateAndSelectFileRecordTerminal: QI IID_ITMultiTrackTerminal failed");
return hr;
}
//
// 列举所有的媒体流
//
IEnumStream* pEnumStreams = NULL;
hr = pStreamControl->EnumerateStreams(&pEnumStreams);
pStreamControl->Release();
if (FAILED(hr))
{
pMTRecTerminal->Release();
AfxMessageBox("CreateAndSelectFileRecordTerminal: EnumerateStreams failed");
return hr;
}
//
// 只处理音频媒体类型
//
long lMediaTypes = TAPIMEDIATYPE_AUDIO;
//
// 遍历媒体流,创建我们需要的
//
ITStream* pStream = NULL;
while (S_OK == pEnumStreams->Next(1, &pStream, NULL))
{
if ( (S_OK==CheckStreamMT(pStream,lMediaTypes))
&& (S_OK==CheckStreamDir(pStream,TD_RENDER)))
{
//
// 我们已经有了录音文件终端,下面要创建音轨终端
//
ITTerminal* pRecordingTrack = NULL;
//
// 检测媒体类型
//
long lStreamMediaType=0;
hr = pStream->get_MediaType(&lStreamMediaType);
if (FAILED(hr))
{
pStream->Release();
pStream=NULL;
continue;
}
//
// 创建音轨终端
//
hr = pMTRecTerminal->CreateTrackTerminal(lStreamMediaType, TD_RENDER, &pRecordingTrack);
if (FAILED(hr))
{
pStream->Release();
pStream=NULL;
break;
}
//
// 让当前媒体流选择音轨终端
//
hr = pStream->SelectTerminal(pRecordingTrack);
//
// 释放内存
//
pStream->Release();
pStream=NULL;
pRecordingTrack->Release();
pRecordingTrack=NULL;
if (FAILED(hr))
{
break;
}
lMediaTypes^=lStreamMediaType;
if(lMediaTypes==0)
{
//
// 我们已经为所有媒体类型选择了终端,任务完成!
//
break;
}
}
//
// 释放内存
//
if(pStream!=NULL)
{
pStream->Release();
pStream = NULL;
}
} // while (enumerating streams on the call)
//
//释放内存
//
pMTRecTerminal->Release();
pEnumStreams->Release();
//
// 检测我们是否已经为所有媒体选择了终端
//
if (lMediaTypes==0)
{
return S_OK;
}
else
{
AfxMessageBox("CreateAndSelectFileRecordTerminal: no streams available");
return E_FAIL;
}
}
///////////////////////////////////////////////////////////////////
// SameCall
//
// 检测是否与 m_pCall 是同一个
//
///////////////////////////////////////////////////////////////////
bool CTapi::SameCall(ITCallStateEvent* pCallStateEvent)
{
if(NULL == pCallStateEvent)
{
return false;
}
//
// 获得 Call object
//
ITCallInfo* pCallInfo = NULL;
HRESULT hr = pCallStateEvent->get_Call(&pCallInfo);
if(NULL != pCallInfo && ( SUCCEEDED(hr) && NULL != m_pCall) )
{
bool bIsEqual = true;
//
// 比较两个 Call object 的 IUnknown 接口
//
IUnknown* pIUnkCallInfo = NULL;
IUnknown* pIUnkCallControl = NULL;
pCallInfo->QueryInterface(IID_IUnknown, (void**)&pIUnkCallInfo);
m_pCall->QueryInterface(IID_IUnknown, (void**)&pIUnkCallControl);
//
//比较
//
if(pIUnkCallInfo != pIUnkCallControl)
{
bIsEqual = false;
}
//
//释放内存
//
pCallInfo->Release();
if(NULL != pIUnkCallInfo)
{
pIUnkCallInfo->Release();
}
if(NULL != pIUnkCallControl)
{
pIUnkCallControl->Release();
}
return bIsEqual;
}
else
{
return false;
}
}
//////////////////////////////////////////////////////////////////
//
// GetTerminalFromStreamEvent
//
// 功能:从 MediaEvent 事件中获得媒体流,然后,再由媒体流获得终端
// 如果对应的终端存在,则返回 NULL
//////////////////////////////////////////////////////////////////
HRESULT CTapi::GetTerminalFromStreamEvent(
IN ITCallMediaEvent * pCallMediaEvent,
OUT ITTerminal ** ppTerminal )
{
HRESULT hr;
*ppTerminal = NULL;
//
// 获得这一事件当中的媒体流
//
ITStream * pStream;
hr = pCallMediaEvent->get_Stream( &pStream );
if ( FAILED(hr) || (pStream == NULL) ) return E_FAIL;
//
// 列举支持这一种媒体流的终端
//
IEnumTerminal * pEnumTerminal;
hr = pStream->EnumerateTerminals( &pEnumTerminal );
pStream->Release();
if ( FAILED(hr) ) return hr;
//
// 获得第一个终端,如果没有找到,返回 E_FAIL 跳出这一事件的处理
//
hr = pEnumTerminal->Next(1, ppTerminal, NULL);
if ( hr != S_OK )
{
pEnumTerminal->Release();
return E_FAIL;
}
//
// 进一步检测,注意这里不可能有大于一个终端,因为我们对每一各媒体流只选择
// 过一个终端
//
ITTerminal * pExtraTerminal;
hr = pEnumTerminal->Next(1, &pExtraTerminal, NULL);
pEnumTerminal->Release();
if ( hr == S_OK ) // 大于一个终端,不可能出现的情况
{
pExtraTerminal->Release();
(*ppTerminal)->Release();
*ppTerminal = NULL;
return E_UNEXPECTED;
}
return S_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -