Files
Client/Library/dxx8/samples/Multimedia/DirectShow/Capture/AudioCap/AudioCapDlg.cpp
LGram16 e067522598 Initial commit: ROW Client source code
Game client codebase including:
- CharacterActionControl: Character and creature management
- GlobalScript: Network, items, skills, quests, utilities
- RYLClient: Main client application with GUI and event handlers
- Engine: 3D rendering engine (RYLGL)
- MemoryManager: Custom memory allocation
- Library: Third-party dependencies (DirectX, boost, etc.)
- Tools: Development utilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-29 16:24:34 +09:00

1057 lines
29 KiB
C++

//------------------------------------------------------------------------------
// File: AudioCapDlg.cpp
//
// Desc: DirectShow sample code - Implementation of CAudioCapDlg class for
// audio capture sample application.
//
// Copyright (c) 2000-2001 Microsoft Corporation. All rights reserved.
//------------------------------------------------------------------------------
#include "stdafx.h"
#include "AudioCap.h"
#include "AudioCapDlg.h"
#include <atlbase.h>
#include <mtype.h>
#include "mfcutil.h"
#include "dshowutil.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CAudioCapDlg dialog
CAudioCapDlg::CAudioCapDlg(CWnd* pParent /*=NULL*/)
: CDialog(CAudioCapDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CAudioCapDlg)
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CAudioCapDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAudioCapDlg)
DDX_Control(pDX, IDC_STATIC_STATUS, m_strStatus);
DDX_Control(pDX, IDC_RADIO_MONO, m_btnMono);
DDX_Control(pDX, IDC_RADIO_8BIT, m_btn8BIT);
DDX_Control(pDX, IDC_RADIO_11KHZ, m_btn11KHZ);
DDX_Control(pDX, IDC_BUTTON_PAUSE, m_btnPause);
DDX_Control(pDX, IDC_BUTTON_STOP, m_btnStop);
DDX_Control(pDX, IDC_BUTTON_PLAY, m_btnPlay);
DDX_Control(pDX, IDC_LIST_FILTER_OUTPUTS, m_ListFilterOutputs);
DDX_Control(pDX, IDC_LIST_FILTER_INPUTS, m_ListFilterInputs);
DDX_Control(pDX, IDC_BUTTON_RECORD, m_btnRecord);
DDX_Control(pDX, IDC_BUTTON_PROPERTIES, m_btnProperties);
DDX_Control(pDX, IDC_LIST_INPUT_DEVICES, m_ListInputs);
DDX_Control(pDX, IDC_LIST_INPUT_PINS, m_ListInputPins);
DDX_Control(pDX, IDC_LIST_FILTERS, m_ListFilters);
DDX_Control(pDX, IDC_EDIT_FILENAME, m_StrFilename);
DDX_Control(pDX, IDC_CHECK_WRITE, m_CheckWriteFile);
DDX_Control(pDX, IDC_CHECK_AUDITION, m_CheckAudition);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAudioCapDlg, CDialog)
//{{AFX_MSG_MAP(CAudioCapDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_CLOSE()
ON_WM_DESTROY()
ON_LBN_SELCHANGE(IDC_LIST_INPUT_DEVICES, OnSelchangeListInputDevices)
ON_LBN_SELCHANGE(IDC_LIST_FILTERS, OnSelchangeListFilters)
ON_LBN_SELCHANGE(IDC_LIST_INPUT_PINS, OnSelchangeListInputPins)
ON_BN_CLICKED(IDC_BUTTON_PROPERTIES, OnButtonProperties)
ON_BN_CLICKED(IDC_BUTTON_PLAY, OnButtonPlay)
ON_BN_CLICKED(IDC_BUTTON_PAUSE, OnButtonPause)
ON_BN_CLICKED(IDC_BUTTON_STOP, OnButtonStop)
ON_BN_CLICKED(IDC_BUTTON_RECORD, OnButtonRecord)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CAudioCapDlg message handlers
void CAudioCapDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CAudioCapDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CAudioCapDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
BOOL CAudioCapDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
////////////////////////////////////////////////////////////////////////
//
// DirectShow-specific initialization code
CoInitialize(NULL);
if (FAILED(InitializeCapture()))
{
ReleaseCapture();
return FALSE;
}
CheckDlgButton(IDC_RADIO_16BIT, TRUE);
CheckDlgButton(IDC_RADIO_STEREO, TRUE);
CheckDlgButton(IDC_RADIO_44KHZ, TRUE);
return TRUE; // return TRUE unless you set the focus to a control
}
HRESULT CAudioCapDlg::InitializeCapture()
{
HRESULT hr;
SetDefaults();
if (FAILED(hr = GetInterfaces()))
return hr;
if (FAILED(hr = FillLists()))
return hr;
return hr;
}
HRESULT CAudioCapDlg::FillLists()
{
HRESULT hr;
// Enumerate and display the audio input devices installed in the system
hr = EnumFiltersWithMonikerToList(NULL, &CLSID_AudioInputDeviceCategory, m_ListInputs);
if (FAILED(hr))
return hr;
// Select the first audio device in the list for the default
m_ListInputs.SetCurSel(0);
OnSelchangeListInputDevices();
return hr;
}
HRESULT CAudioCapDlg::GetInterfaces()
{
HRESULT hr;
// Create the filter graph.
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
IID_IGraphBuilder, (void **)&m_pGB);
if (!m_pGB)
return E_NOINTERFACE;
// Create the capture graph builder.
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,
IID_ICaptureGraphBuilder2, (void **)&m_pCapture);
if (!m_pCapture)
return E_NOINTERFACE;
// Associate the filter graph with the capture graph builder
hr = m_pCapture->SetFiltergraph(m_pGB);
if (FAILED(hr))
return hr;
// Get useful interfaces from the graph builder
JIF(hr = m_pGB->QueryInterface(IID_IMediaControl, (void **)&m_pMC));
JIF(hr = m_pGB->QueryInterface(IID_IMediaEventEx, (void **)&m_pME));
// Have the graph signal events via window callbacks
hr = m_pME->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, RECORD_EVENT);
CLEANUP:
return hr;
}
HRESULT CAudioCapDlg::GetPlaybackInterfaces()
{
HRESULT hr;
// Release any existing interface pointers
FreePlaybackInterfaces();
// Create the filter graph.
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC,
IID_IGraphBuilder, (void **)&m_pGBPlayback);
if (!m_pGBPlayback)
return E_NOINTERFACE;
// Get useful interfaces from the graph builder
JIF(hr = m_pGBPlayback->QueryInterface(IID_IMediaControl, (void **)&m_pMCPlayback));
JIF(hr = m_pGBPlayback->QueryInterface(IID_IMediaEventEx, (void **)&m_pMEPlayback));
// Have the graph signal events via window callbacks
hr = m_pMEPlayback->SetNotifyWindow((OAHWND)m_hWnd, WM_GRAPHNOTIFY, PLAYBACK_EVENT);
CLEANUP:
return hr;
}
void CAudioCapDlg::ClearAllocatedLists()
{
// Clear the list and delete its allocated CLSID bytes
ClearFilterListWithMoniker(m_ListInputs);
}
void CAudioCapDlg::ClearLists()
{
// Clear the lists that don't contain extra data
m_ListInputPins.ResetContent();
m_ListFilters.ResetContent();
m_ListFilterInputs.ResetContent();
m_ListFilterOutputs.ResetContent();
}
void CAudioCapDlg::FreeInterfaces()
{
// Disable event callbacks
if (m_pME)
m_pME->SetNotifyWindow((OAHWND)NULL, 0, 0);
// Release and zero DirectShow interface pointers
SAFE_RELEASE(m_pMC);
SAFE_RELEASE(m_pME);
SAFE_RELEASE(m_pSplitter);
SAFE_RELEASE(m_pFileWriter);
SAFE_RELEASE(m_pWAVDest);
SAFE_RELEASE(m_pInputDevice);
SAFE_RELEASE(m_pGB);
SAFE_RELEASE(m_pCapture);
}
void CAudioCapDlg::FreePlaybackInterfaces()
{
HRESULT hr;
// Disable event callbacks
if (m_pMEPlayback)
hr = m_pMEPlayback->SetNotifyWindow((OAHWND)NULL, 0, 0);
// Release and zero DirectShow interface pointers
SAFE_RELEASE(m_pMEPlayback);
SAFE_RELEASE(m_pMCPlayback);
SAFE_RELEASE(m_pGBPlayback);
}
void CAudioCapDlg::ReleaseCapture()
{
ClearAllocatedLists();
ClearLists();
DestroyPreviewStream();
DestroyCaptureStream();
FreeInterfaces();
FreePlaybackInterfaces();
}
void CAudioCapDlg::ResetCapture()
{
ClearLists();
FreeInterfaces();
GetInterfaces();
}
void CAudioCapDlg::SetDefaults()
{
// Zero DirectShow interface pointers (sanity check)
m_pGB = m_pGBPlayback = 0;
m_pMC = m_pMCPlayback = 0;
m_pME = m_pMEPlayback = 0;
m_pCapture = 0;
m_pInputDevice =0;
m_pSplitter = 0;
m_pRenderer =0;
m_pWAVDest=0;
m_pFileWriter=0;
m_bPausedRecording=FALSE;
// Set default values for controls on the dialog
m_CheckAudition.SetCheck(TRUE);
m_btnProperties.EnableWindow(FALSE);
m_StrFilename.SetWindowText(DEFAULT_FILENAME);
}
void CAudioCapDlg::EnableButtons(BOOL bEnable)
{
m_btnRecord.EnableWindow(bEnable);
m_btnPause.EnableWindow(bEnable);
m_btnStop.EnableWindow(bEnable);
m_btnPlay.EnableWindow(bEnable);
}
void CAudioCapDlg::EnableRadioButtons(BOOL bEnable)
{
GetDlgItem(IDC_RADIO_11KHZ)->EnableWindow(bEnable);
GetDlgItem(IDC_RADIO_22KHZ)->EnableWindow(bEnable);
GetDlgItem(IDC_RADIO_44KHZ)->EnableWindow(bEnable);
GetDlgItem(IDC_RADIO_8BIT)->EnableWindow(bEnable);
GetDlgItem(IDC_RADIO_16BIT)->EnableWindow(bEnable);
GetDlgItem(IDC_RADIO_MONO)->EnableWindow(bEnable);
GetDlgItem(IDC_RADIO_STEREO)->EnableWindow(bEnable);
}
void CAudioCapDlg::OnClose()
{
if (m_pMC)
m_pMC->Stop();
ReleaseCapture();
CoUninitialize();
CDialog::OnClose();
}
void CAudioCapDlg::OnDestroy()
{
ReleaseCapture();
CDialog::OnDestroy();
}
HRESULT CAudioCapDlg::HandleGraphEvent(void)
{
LONG evCode, evParam1, evParam2;
HRESULT hr=S_OK;
if (!m_pME)
return S_OK;
// Read all events currently on the event queue
while(SUCCEEDED(m_pME->GetEvent(&evCode, (LONG_PTR *) &evParam1,
(LONG_PTR *) &evParam2, 0)))
{
if(EC_DEVICE_LOST == evCode)
{
// Device was removed
if (evParam2 == 0)
{
OnButtonStop();
ReleaseCapture();
SetDefaults();
MessageBeep(0);
MessageBox(TEXT("The selected input device was removed!\0"),
TEXT("DirectShow Audio Capture Sample\0"),
MB_OK | MB_ICONEXCLAMATION);
}
// Device was reattached
else
{
// Restart from scratch
InitializeCapture();
MessageBeep(0);
MessageBox(TEXT("The audio input device has been reattached!\0"),
TEXT("DirectShow Audio Capture Sample\0"),
MB_OK | MB_ICONINFORMATION);
}
}
// Free event parameters to prevent memory leaks
hr = m_pME->FreeEventParams(evCode, evParam1, evParam2);
}
return hr;
}
HRESULT CAudioCapDlg::HandlePlaybackGraphEvent(void)
{
LONG evCode, evParam1, evParam2;
HRESULT hr=S_OK;
if (!m_pMEPlayback)
return S_OK;
// Read all events currently on the event queue
while(SUCCEEDED(m_pMEPlayback->GetEvent(&evCode, (LONG_PTR *) &evParam1,
(LONG_PTR *) &evParam2, 0)))
{
// Free event parameters to prevent memory leaks
hr = m_pMEPlayback->FreeEventParams(evCode, evParam1, evParam2);
if (evCode == EC_COMPLETE)
{
OnButtonStop();
break;
}
}
return hr;
}
LRESULT CAudioCapDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// Field notifications from the DirectShow filter graph manager
// and those posted by the application
switch (message)
{
case WM_GRAPHNOTIFY:
if (lParam == RECORD_EVENT)
HandleGraphEvent();
else
HandlePlaybackGraphEvent();
break;
}
return CDialog::WindowProc(message, wParam, lParam);
}
void CAudioCapDlg::OnButtonProperties()
{
// Use helper function to display property page for this device
ShowFilterPropertyPage(m_pInputDevice, m_hWnd);
// Increment the device's reference count
m_pInputDevice->AddRef();
}
void CAudioCapDlg::OnSelchangeListInputDevices()
{
HRESULT hr;
IMoniker *pMoniker=0;
// Release and delete any previous capture filter graph
if (m_pInputDevice)
ResetCapture();
// Get the currently selected category name
int nItem = m_ListInputs.GetCurSel();
// Read the stored moniker pointer from the list box's item data
pMoniker = (IMoniker *) m_ListInputs.GetItemDataPtr(nItem);
// Use the moniker to create the specified audio capture device
hr = pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&m_pInputDevice);
if (FAILED(hr))
return;
// Add the capture filter to the filter graph
hr = m_pGB->AddFilter(m_pInputDevice, L"Audio Capture");
if (FAILED(hr))
return;
// List and display the available input pins on the capture filter.
// Many devices offer multiple pins for input (microphone, CD, LineIn, etc.)
hr = EnumPinsOnFilter(m_pInputDevice, PINDIR_INPUT, m_ListInputPins);
if (FAILED(hr))
return;
// Enable the properties button, if supported by the selected input device
m_btnProperties.EnableWindow(SupportsPropertyPage(m_pInputDevice));
// Select the first available input pin by default
m_ListInputPins.SetCurSel(0);
OnSelchangeListInputPins();
// Now display the existing filters in the graph for diagnostic help
UpdateFilterLists(m_pGB);
}
void CAudioCapDlg::OnSelchangeListFilters()
{
// Use a helper function to display the filter's pins in listboxes
if (m_pGBPlayback)
{
AddFilterPinsToLists(m_pGBPlayback, m_ListFilters,
m_ListFilterInputs, m_ListFilterOutputs);
}
else
{
AddFilterPinsToLists(m_pGB, m_ListFilters,
m_ListFilterInputs, m_ListFilterOutputs);
}
}
void CAudioCapDlg::UpdateFilterLists(IGraphBuilder *pUpdateGB)
{
// Now display the existing filters in the graph for diagnostic help
AddGraphFiltersToList(pUpdateGB, m_ListFilters);
// Refresh the filter/pin display lists
m_ListFilters.SetCurSel(0);
OnSelchangeListFilters();
}
void CAudioCapDlg::OnButtonPlay()
{
USES_CONVERSION;
TCHAR szPlayFile[MAX_PATH];
Say(TEXT("Playing specified file..."));
m_StrFilename.GetWindowText(szPlayFile, MAX_PATH);
// Play the media file using DirectShow methods
if (SUCCEEDED(GetPlaybackInterfaces()))
{
HRESULT hr = m_pGBPlayback->RenderFile(T2W(szPlayFile), NULL);
if (SUCCEEDED(hr))
{
// Update the graph filter display to show rendered graph
UpdateFilterLists(m_pGBPlayback);
hr = m_pMCPlayback->Run();
}
}
// Disable pause button to remove need for extra pause/play handling code
m_btnPause.EnableWindow(FALSE);
}
void CAudioCapDlg::OnButtonRecord()
{
HRESULT hr;
// Don't rebuild the graphs if we're returning from paused state
if (m_bPausedRecording)
{
if (m_pMC)
hr = m_pMC->Run();
m_bPausedRecording = FALSE;
Say(TEXT("Auditioning/recording audio..."));
return;
}
// If we're currently playing back the recorded file, stop playback
// and clear the interfaces before beginning recording.
FreePlaybackInterfaces();
if (m_CheckAudition.GetCheck())
RenderPreviewStream();
if (m_CheckWriteFile.GetCheck())
RenderCaptureStream();
// Update the graph filter display to show rendered graph
UpdateFilterLists(m_pGB);
if (m_pMC)
{
hr = m_pMC->Run();
Say(TEXT("Auditioning/recording audio..."));
}
m_btnRecord.EnableWindow(FALSE);
m_btnPlay.EnableWindow(FALSE);
m_btnPause.EnableWindow(TRUE);
EnableRadioButtons(FALSE);
}
void CAudioCapDlg::OnButtonPause()
{
HRESULT hr;
// We share the functionality of the Pause button with both
// Record and Playback. If the Playback interfaces aren't NULL,
// then we're in the middle of playback, so pause playback.
// Otherwise, pause recording.
if (m_pMCPlayback)
{
hr = m_pMCPlayback->Pause();
Say(TEXT("Paused audio playback"));
}
else
{
if (m_pMC)
{
hr = m_pMC->Pause();
Say(TEXT("Paused audio recording"));
m_bPausedRecording = TRUE;
}
}
m_btnRecord.EnableWindow(TRUE);
}
void CAudioCapDlg::OnButtonStop()
{
HRESULT hr;
// We share the functionality of the Stop button with both
// Record and Playback. If the Playback interfaces aren't NULL,
// then we're in the middle of playback, so stop playback.
// Otherwise, stop recording.
if (m_pMCPlayback)
{
// Stop playback
if (m_pMCPlayback)
hr = m_pMCPlayback->Stop();
FreePlaybackInterfaces();
// Clear filter/pins list boxes, since there is no active filter graph
m_ListFilters.ResetContent();
m_ListFilterInputs.ResetContent();
m_ListFilterOutputs.ResetContent();
}
else
{
// Stop recording
if (m_pMC)
hr = m_pMC->StopWhenReady();
// Destroy the existing filter graph
DestroyPreviewStream();
DestroyCaptureStream();
m_bPausedRecording = FALSE;
// Update the graph filter display to show rendered graph
UpdateFilterLists(m_pGB);
EnableRadioButtons(TRUE);
}
EnableButtons(TRUE);
Say(TEXT("Ready"));
}
HRESULT CAudioCapDlg::RenderCaptureStream()
{
USES_CONVERSION;
HRESULT hr=0;
IFileSinkFilter2 *pFileSink;
// Create the WAVDest filter
hr = CoCreateInstance(CLSID_WavDest, NULL, CLSCTX_INPROC,
IID_IBaseFilter, (void **)&m_pWAVDest);
if (FAILED(hr))
{
MessageBox(TEXT("Couldn't create a WAVDest filter. This sample filter is installed ")
TEXT("with the DirectX 8.0 SDK in the DirectShow\\Filters\\WavDest ")
TEXT("directory.\n\nPlease build this filter (with Visual C++) and ")
TEXT("register it by running 'Tools->Register Control' once the ")
TEXT("filter finishes building.\nThis helper filter is used ")
TEXT("when writing .WAV files to disk, and this sample requires it.\n\n")
TEXT("You may still audition the audio input, but you will not be ")
TEXT("able to write the data to a file."),
TEXT("Error loading WAVDest helper filter!"));
return E_NOINTERFACE;
}
// Create the FileWriter filter
hr = CoCreateInstance(CLSID_FileWriter, NULL, CLSCTX_INPROC,
IID_IFileSinkFilter2, (void **)&pFileSink);
if (FAILED(hr))
return E_NOINTERFACE;
// Get the file sink interface from the File Writer
hr = pFileSink->QueryInterface(IID_IBaseFilter, (void **)&m_pFileWriter);
// Add the WAVDest filter to the graph
hr = m_pGB->AddFilter(m_pWAVDest, L"WAV Dest");
if (FAILED(hr))
return hr;
// Add the FileWriter filter to the graph
hr = m_pGB->AddFilter((IBaseFilter *)m_pFileWriter, L"File Writer");
if (FAILED(hr))
return hr;
// Set filter to always overwrite the file
hr = pFileSink->SetMode(AM_FILE_OVERWRITE);
// Set the output filename, which must be a wide string
TCHAR szEditFile[MAX_PATH];
WCHAR wszFilename[MAX_PATH];
m_StrFilename.GetWindowText(szEditFile, MAX_PATH);
if (szEditFile[0] == TEXT('\0'))
wcscpy(wszFilename, T2W(DEFAULT_FILENAME));
else
wcscpy(wszFilename, T2W(szEditFile));
hr = pFileSink->SetFileName(wszFilename, NULL);
if (FAILED(hr))
return hr;
// Get the pin interface for the capture pin
IPin *pPin=0;
if (m_pSplitter)
hr = GetPin(m_pSplitter, PINDIR_OUTPUT, 0, &pPin);
else
hr = GetPin(m_pInputDevice, PINDIR_OUTPUT, 0, &pPin);
// Connect the new filters
if (pPin)
{
hr = m_pGB->Render(pPin);
pPin->Release();
}
// Release the FileSinkFilter2 interface, since it's no longer needed
SAFE_RELEASE(pFileSink);
return hr;
}
HRESULT CAudioCapDlg::DestroyCaptureStream()
{
HRESULT hr=0;
// Destroy Audio renderer filter, if it exists
if (m_pWAVDest)
{
hr = m_pGB->RemoveFilter(m_pWAVDest);
SAFE_RELEASE(m_pWAVDest);
}
// Destroy Smart Tee filter, if it exists
if (m_pFileWriter)
{
hr = m_pGB->RemoveFilter(m_pFileWriter);
SAFE_RELEASE(m_pFileWriter);
}
return hr;
}
HRESULT CAudioCapDlg::RenderPreviewStream()
{
USES_CONVERSION;
HRESULT hr=0;
WCHAR wszFilter[64];
// If we've already configured the stream, just exit
if (m_pRenderer)
return S_OK;
// Set the requested audio properties - buffer sizes, channels, freq, etc.
hr = SetAudioProperties();
// Render the preview stream
hr = m_pCapture->RenderStream(
&PIN_CATEGORY_PREVIEW,
&MEDIATYPE_Audio,
m_pInputDevice,
NULL, // No compression filter.
NULL // Default renderer.
);
// Some capture sources will have only a Capture pin (no Preview pin).
// In that case, the Capture Graph builder will automatically insert
// a SmartTee filter, which will split the stream into a Capture stream
// and a Preview stream. In that case, it's not an error.
if (hr == VFW_S_NOPREVIEWPIN)
{
wcscpy(wszFilter, T2W(TEXT("Smart Tee")));
// Get the interface for the Splitter filter for later use
hr = m_pGB->FindFilterByName(wszFilter, &m_pSplitter);
}
// Get the interface for the audio renderer filter for later use
wcscpy(wszFilter, T2W(TEXT("Audio Renderer")));
hr = m_pGB->FindFilterByName(wszFilter, &m_pRenderer);
return hr;
}
HRESULT CAudioCapDlg::DestroyPreviewStream()
{
HRESULT hr=0;
// Destroy Smart Tee filter, if it exists
if (m_pSplitter)
{
hr = m_pGB->RemoveFilter(m_pSplitter);
SAFE_RELEASE(m_pSplitter);
}
// Destroy Audio renderer filter, if it exists
if (m_pRenderer)
{
hr = m_pGB->RemoveFilter(m_pRenderer);
SAFE_RELEASE(m_pRenderer);
}
return hr;
}
void CAudioCapDlg::OnSelchangeListInputPins()
{
HRESULT hr;
// Make sure that playback is stopped
OnButtonStop();
// Select the capture device's input pin
hr = ActivateSelectedInputPin();
}
HRESULT CAudioCapDlg::ActivateSelectedInputPin()
{
HRESULT hr=S_OK;
IPin *pPin=0;
IAMAudioInputMixer *pPinMixer;
// How many pins are in the input pin list?
int nPins = m_ListInputPins.GetCount();
int nActivePin = m_ListInputPins.GetCurSel();
// Activate the selected input pin and deactivate all others
for (int i=0; i<nPins; i++)
{
// Get this pin's interface
hr = GetPin(m_pInputDevice, PINDIR_INPUT, i, &pPin);
if (SUCCEEDED(hr))
{
hr = pPin->QueryInterface(IID_IAMAudioInputMixer, (void **)&pPinMixer);
if (SUCCEEDED(hr))
{
// If this is our selected pin, enable it
if (i == nActivePin)
{
// Set any other audio properties on this pin
hr = SetInputPinProperties(pPinMixer);
// If there is only one input pin, this method
// might return E_NOTIMPL.
hr = pPinMixer->put_Enable(TRUE);
}
// Otherwise, disable it
else
{
hr = pPinMixer->put_Enable(FALSE);
}
pPinMixer->Release();
}
// Release pin interfaces
pPin->Release();
}
}
return hr;
}
HRESULT CAudioCapDlg::SetInputPinProperties(IAMAudioInputMixer *pPinMixer)
{
HRESULT hr=0;
BOOL bLoudness=0, bMono=0;
double dblBass=0, dblBassRange=0, dblMixLevel=0,
dblPan=0, dblTreble=0, dblTrebleRange=0;
// Read current settings for debugging purposes. Many of these interfaces
// will not be implemented by the input device's driver, so they will
// return E_NOTIMPL. In that case, just ignore the values.
hr = pPinMixer->get_Bass(&dblBass);
hr = pPinMixer->get_BassRange(&dblBassRange);
hr = pPinMixer->get_Loudness(&bLoudness);
hr = pPinMixer->get_MixLevel(&dblMixLevel);
hr = pPinMixer->get_Mono(&bMono);
hr = pPinMixer->get_Pan(&dblPan);
hr = pPinMixer->get_Treble(&dblTreble);
hr = pPinMixer->get_TrebleRange(&dblTrebleRange);
// Manipulate desired values here (mono/stereo, pan, etc.)
return hr;
}
void CAudioCapDlg::Say(TCHAR *szMsg)
{
// Display status information on the main dialog
m_strStatus.SetWindowText(szMsg);
}
HRESULT CAudioCapDlg::SetAudioProperties()
{
HRESULT hr=0;
IPin *pPin=0;
IAMBufferNegotiation *pNeg=0;
IAMStreamConfig *pCfg=0;
int nFrequency;
// Determine audio properties
int nChannels = m_btnMono.GetCheck() ? 1 : 2;
int nBytesPerSample = m_btn8BIT.GetCheck() ? 1 : 2;
if (IsDlgButtonChecked(IDC_RADIO_11KHZ)) nFrequency = 11025;
else if (IsDlgButtonChecked(IDC_RADIO_22KHZ)) nFrequency = 22050;
else nFrequency = 44100;
// Find number of bytes in one second
long lBytesPerSecond = (long) (nBytesPerSample * nFrequency * nChannels);
// Set to 50ms worth of data
long lBufferSize = (long) ((float) lBytesPerSecond * DEFAULT_BUFFER_TIME);
// Get the buffer negotiation interface for each pin,
// since there could be both a Capture and a Preview pin.
for (int i=0; i<2; i++)
{
hr = GetPin(m_pInputDevice, PINDIR_OUTPUT, i, &pPin);
if (SUCCEEDED(hr))
{
// Get buffer negotiation interface
hr = pPin->QueryInterface(IID_IAMBufferNegotiation, (void **)&pNeg);
if (FAILED(hr))
{
pPin->Release();
break;
}
// Set the buffer size based on selected settings
ALLOCATOR_PROPERTIES prop={0};
prop.cbBuffer = lBufferSize;
prop.cBuffers = 6;
prop.cbAlign = nBytesPerSample * nChannels;
hr = pNeg->SuggestAllocatorProperties(&prop);
pNeg->Release();
// Now set the actual format of the audio data
hr = pPin->QueryInterface(IID_IAMStreamConfig, (void **)&pCfg);
if (FAILED(hr))
{
pPin->Release();
break;
}
// Read current media type/format
AM_MEDIA_TYPE *pmt={0};
hr = pCfg->GetFormat(&pmt);
if (SUCCEEDED(hr))
{
// Fill in values for the new format
WAVEFORMATEX *pWF = (WAVEFORMATEX *) pmt->pbFormat;
pWF->nChannels = (WORD) nChannels;
pWF->nSamplesPerSec = nFrequency;
pWF->nAvgBytesPerSec = lBytesPerSecond;
pWF->wBitsPerSample = (WORD) (nBytesPerSample * 8);
pWF->nBlockAlign = (WORD) (nBytesPerSample * nChannels);
// Set the new formattype for the output pin
hr = pCfg->SetFormat(pmt);
DeleteMediaType(pmt);
}
// Release interfaces
pCfg->Release();
pPin->Release();
}
// No more output pins on this filter
else
break;
}
return hr;
}