- 环境:xp+vs2005+DXSDK9_sumer2004
- 目的:将采集到的麦克风声音送至声卡
- GraphEdit模拟:
- add filter:
- connect filter:
- play,即可在耳机中听到麦克风中自己的声音(确认耳机和麦克风插好,并且没有被静音),有一点延时 :-)
4. 代码实现(具体解释请参考此处,代码是俺抄的:-)):
// AudioCaptureSaveConsole.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include<iostream>
#include<cstring>
#include<dshow.h>
#include<windows.h>
#include<conio.h>
#include<stdio.h>
//#include"streams.h"
bool Bstr_Compare(BSTR,BSTR);//Function to compare BSTR strings
void HR_Failed(HRESULT hr);// hr status function
IMoniker* Device_Read(ICreateDevEnum*,IMoniker*,GUID,BSTR);//Device reading function
IBaseFilter* Device_Init(IMoniker*,IBaseFilter*);//Function to initialize Input/Output devices
void Device_Addition(IGraphBuilder*,IBaseFilter*,BSTR);//Function to add device to graph
void Device_Connect(IBaseFilter*,IBaseFilter*,BSTR,BSTR);//Function to connect the two devices
void Run_Graph(IMediaControl*);//Function to run the graph
IFileSinkFilter* Add_File(IGraphBuilder*,IBaseFilter*,IFileSinkFilter*,BSTR);//Function to access default WAV file
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr; // COM result
IGraphBuilder *pGraph = NULL;// Main graphbuilder pointer
IMediaControl *pControl = NULL; // Media Control interface
ICreateDevEnum *pDeviceEnum = NULL;// System device enumerator
IBaseFilter *pInputDevice = NULL, *pOutputDevice = NULL;// Input and output filters(devices)
IBaseFilter *pWAVRecorder = NULL;//This is the transform filter that converts raw input to WAV
IBaseFilter *pFileWriter = NULL;// FileWriter filter shall be refernced by this pointer
IFileSinkFilter *pFile = NULL;
IMoniker *pDeviceMonik = NULL;// Device moniker
GUID DEVICE_CLSID ;// GUID i.e. CLSID_Xxxxxxxxxxx
BSTR bstrDeviceName= {'\0'};// FriendlyName of device
BSTR bstrInPinName= {'\0'};// Input pin name
BSTR bstrOutPinName= {'\0'};// Output pin name
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED );// Initialise COM
if (FAILED(hr))
{
HR_Failed(hr);
return hr;
}
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,IID_IGraphBuilder, (void**)&pGraph);//Initialize Graph builder
if (FAILED(hr))
{
HR_Failed(hr);
return hr;
}
hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,IID_ICreateDevEnum, (void **)&pDeviceEnum);//Initialize Device enumerator
if (FAILED(hr))
{
HR_Failed(hr);
return hr;
}
hr = pGraph->QueryInterface(IID_IMediaControl,(void**)&pControl);// Query interface for IMediaControl
if (FAILED(hr))
{
HR_Failed(hr);
return hr;
}
/*******************************************************************************/
//Front mic input
DEVICE_CLSID = CLSID_AudioInputDeviceCategory;// the input device category
//bstrDeviceName = SysAllocString(L"Front Mic (IDT High Definition ");// device name as seen in Graphedit.exe
bstrDeviceName = SysAllocString(L"Realtek HD Audio Input");
pDeviceMonik = Device_Read(pDeviceEnum,pDeviceMonik,DEVICE_CLSID,bstrDeviceName);//read the required device
pInputDevice = Device_Init(pDeviceMonik,pInputDevice);//Return the device after initializing it
Device_Addition(pGraph,pInputDevice,bstrDeviceName);//add device to graph
SysFreeString(bstrDeviceName);
/******************************************************************************/
//Transform filter
DEVICE_CLSID = CLSID_LegacyAmFilterCategory;// the DirectShow filters category
//bstrDeviceName = SysAllocString(L"AudioRecorder WAV Dest");// device name as seen in Graphedit.exe,using SysAllicString(..) to properly allocate string
bstrDeviceName = SysAllocString(L"WAV Dest");
pDeviceMonik = Device_Read(pDeviceEnum,pDeviceMonik,DEVICE_CLSID,bstrDeviceName);//read the required device
pWAVRecorder = Device_Init(pDeviceMonik,pWAVRecorder);//Return the device after initializing it
Device_Addition(pGraph,pWAVRecorder,bstrDeviceName);//add device to graph
SysFreeString(bstrDeviceName);
/******************************************************************************/
//Connect input to output, Mic to AudioRecoder WAV Dest filter
bstrInPinName = SysAllocString(L"Capture");//Input pin name, as seen in GraphEdit
bstrOutPinName = SysAllocString(L"In");//Output pin name, this one will be input for AudioRecorder WAV Dest filter
Device_Connect(pInputDevice,pWAVRecorder,bstrInPinName,bstrOutPinName);//connect
SysFreeString(bstrInPinName);
SysFreeString(bstrOutPinName);
SysFreeString(bstrDeviceName);
/*******************************************************************************/
//Default output device
DEVICE_CLSID = CLSID_LegacyAmFilterCategory;// the DirectShow filters category
bstrDeviceName = SysAllocString(L"File writer");// device name as seen in Graphedit.exe,using SysAllicString(..) to properly allocate string
pDeviceMonik = Device_Read(pDeviceEnum,pDeviceMonik,DEVICE_CLSID,bstrDeviceName);//read the required device
pFileWriter = Device_Init(pDeviceMonik,pFileWriter);//Return the device after initializing it
SysFreeString(bstrDeviceName);
SysAllocString(L"..\\test.wav");//This is the file name as seen in GraphEdit
// access the default file before adding to the graph.
//This function must be called first before adding
//the device to the graph.
pFile = Add_File(pGraph,pFileWriter,pFile,bstrDeviceName);
Device_Addition(pGraph,pFileWriter,bstrDeviceName);//add device to graph
/******************************************************************************/
//Connect input to output, AudioRecoder WAV Dest filter to test.wav i.e. File writer filter
bstrInPinName = SysAllocString(L"Out");//Input pin name, as seen in GraphEdit
bstrOutPinName = SysAllocString(L"in");//Output pin name, this one will be input for File writer filter
Device_Connect(pWAVRecorder,pFileWriter,bstrInPinName,bstrOutPinName);//Connect
SysFreeString(bstrInPinName);
SysFreeString(bstrOutPinName);
SysFreeString(bstrDeviceName);
/*******************************************************************************/
//Now run the graph
Run_Graph(pControl);
//Loop till you don't close the console window or hit a key!
cout<<"Close the window to exit or hit any key"<<endl;
while(!_kbhit())
{
}
pFile->Release();
pControl->Release();//Release control
pDeviceEnum->Release();//Release Device enumerator
pGraph->Release();//Release the Graph
}
/************************************************************/
bool Bstr_Compare(BSTR bstrFilter,BSTR bstrDevice)
{
bool flag = true;
int strlenFilter = SysStringLen(bstrFilter);//set string length
int strlenDevice = SysStringLen(bstrDevice);//set string length
char* chrFilter = (char*)malloc(strlenFilter+1);// allocate memory
char* chrDevice = (char*)malloc(strlenDevice+1);// allocate memory
int j = 0;
if (strlenFilter!=strlenDevice)//if the strings are of not the same length,means they totall different strings
flag = false;//sety flag to false to indicate "not-same" strings
else
{
for(; j < strlenFilter;j++)//now, copy 1 by 1 each char to chrFilter and chrDevice respectively
{
chrFilter[j] = (char)bstrFilter[j];//copy
chrDevice[j] = (char)bstrDevice[j];//copy
cout<<j;
}
chrFilter[strlenFilter] = '\0';//add terminating character
chrDevice[strlenDevice] = '\0';//add terminating character
for(j=0; j < strlenFilter;j++)//check loop
{
if(chrFilter[j] != chrDevice[j])//check if there are chars that are not samne
flag = false;//if chars are not same, set flag to false to indicate "not-same" strings
}
if(flag == true && j == strlenFilter-1)//see if we went through the 'check loop'
flag = true;//means strings are same
}
return flag;
}
/************************************************************/
void HR_Failed(HRESULT hr)
{
// TCHAR szErr[MAX_ERROR_TEXT_LEN];
// DWORD res = AMGetErrorText(hr, szErr, MAX_ERROR_TEXT_LEN);
// if (res == 0)
// {
// StringCchPrintf(szErr, MAX_ERROR_TEXT_LEN, L"Unknown Error: 0x%2x", hr);
// }
//
// MessageBox(0, szErr, TEXT("Error!"), MB_OK | MB_ICONERROR);
return;
}
/************************************************************/
IMoniker* Device_Read(ICreateDevEnum* pDeviceEnum,IMoniker *pDeviceMonik,GUID DEVICE_CLSID,BSTR bstrDeviceName)
{
HRESULT hr;
IEnumMoniker *pEnumCat = NULL;// Device enumeration moniker
VARIANT varName;
hr = pDeviceEnum->CreateClassEnumerator(DEVICE_CLSID, &pEnumCat, 0);// Enumerate the specified device, distinguished by DEVICE_CLSID
if (hr == S_OK)
{
ULONG cFetched;
while (pEnumCat->Next(1, &pDeviceMonik, &cFetched) == S_OK)//Pickup as moniker
{
IPropertyBag *pPropBag = NULL;
hr = pDeviceMonik->BindToStorage(0, 0, IID_IPropertyBag,(void **)&pPropBag);//bind the properties of the moniker
if (SUCCEEDED(hr))
{
VariantInit(&varName);// Initialise the variant data type
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
if(Bstr_Compare(varName.bstrVal,bstrDeviceName) == true)//make a comparison
{
wcout<<varName.bstrVal<<" found"<<endl;
return pDeviceMonik;
}
}
else HR_Failed(hr);
VariantClear(&varName);//clear the variant data type
pPropBag->Release();//release the properties
}
else HR_Failed(hr);
pDeviceMonik->Release();//release Device moniker
}
pEnumCat->Release();//release category enumerator
}
else HR_Failed(hr);
return NULL;
}
/************************************************************/
IBaseFilter* Device_Init(IMoniker* pDeviceMonik,IBaseFilter* pDevice)
{
HRESULT hr;
hr = pDeviceMonik->BindToObject(NULL, NULL, IID_IBaseFilter,(void**)&pDevice);//Instantiate the device
if (SUCCEEDED(hr))
{
cout<<"Device initiation successful..."<<endl;
}
else HR_Failed(hr);
return pDevice;
}
/************************************************************/
void Device_Addition(IGraphBuilder* pGraph,IBaseFilter* pDevice,BSTR bstrName)
{
HRESULT hr;
hr = pGraph->AddFilter(pDevice,bstrName);//Adding to main graph
if(SUCCEEDED(hr))
{
wcout<<"Addition of "<<bstrName<<" successful..."<<endl;
}
else HR_Failed(hr);
}
/************************************************************/
void Device_Connect(IBaseFilter* pInputDevice,IBaseFilter* pOutputDevice,BSTR bstrInputPin,BSTR bstrOutputPin)
{
HRESULT hr;
IEnumPins *pInputPin = NULL,*pOutputPin = NULL;// Pin enumeration
IPin *pIn = NULL, *pOut = NULL;// Pins
hr = pInputDevice->EnumPins(&pInputPin);// Enumerate the pin
if(SUCCEEDED(hr))
{
cout<<"Input Pin Enumeration successful..."<<endl;
hr = pInputDevice->FindPin(bstrInputPin,&pIn);//Get hold of the pin as seen in GraphEdit
if(SUCCEEDED(hr))
{
wcout<<bstrInputPin<<" Input pin found"<<endl;
}
else HR_Failed(hr);
}
else HR_Failed(hr);
hr = pOutputDevice->EnumPins(&pOutputPin);//Enumerate the pin
if(SUCCEEDED(hr))
{
cout<<"Output Pin Enumeration successful..."<<endl;
hr = pOutputDevice->FindPin(bstrOutputPin,&pOut);
if(SUCCEEDED(hr))
{
wcout<<bstrOutputPin<<" Output pin found"<<endl;
}
else HR_Failed(hr);
}
else HR_Failed(hr);
hr = pIn->Connect(pOut,NULL); //Connect the input pin to output pin
if(SUCCEEDED(hr))
{
cout<<"Pin connection successful..."<<endl;
}
else HR_Failed(hr);
}
/************************************************************/
void Run_Graph(IMediaControl* pControl)
{
HRESULT hr;
hr = pControl->Run();// Now run the graph, i.e. start recording!
if(SUCCEEDED(hr))
{
cout<<"You must be recodring to something!!!"<<endl;
}
else HR_Failed(hr);
}
IFileSinkFilter* Add_File(IGraphBuilder *pGraph,IBaseFilter* pDevice,IFileSinkFilter* pFile,BSTR bstrName)
{
HRESULT hr;
IFileSinkFilter *pFileSink= NULL;// pointer to filter that allows data writing
hr = pDevice->QueryInterface(IID_IFileSinkFilter, (void**)&pFile);
if(SUCCEEDED(hr))
{
wcout<<"Querying of IFileSinkFilter "<<bstrName<<" successful..."<<endl;
}
else HR_Failed(hr);
hr = pFile->SetFileName(bstrName,NULL);//setting the name of the file
if(SUCCEEDED(hr))
{
wcout<<"Setting name to "<<bstrName<<" successful..."<<endl;
}
else HR_Failed(hr);
return pFileSink = pFile;
}