www.pudn.com > MPlayer0623.zip > VolumeOutWave.cpp


// VolumeOutWave.cpp : Module interface implementation. 
// Developer : Alex Chmut 
// Created : 8/11/98 
#include "StdAfx.h" 
#include "VolumeOutWave.h" 
 
///////////////////////////////////////////////////////////////////////////// 
// 		Defines 
#define	BAD_DWORD	(DWORD)-1 
#define	WND_CLASS_NAME	"Wave Output Volume Msg Wnd Class" 
#define	WND_NAME		"Wave Output Volume Msg Wnd" 
 
///////////////////////////////////////////////////////////////////////////// 
// 		Globals 
PCVolumeOutWave g_pThis = NULL; 
 
//////////////////////////////////////////////////////////// 
 
//{{{ Audio specific functions 
#define AUDFREQ			22050	// Frequency 
#define AUDCHANNELS		1		// Number of channels 
#define AUDBITSMPL		16		// Number of bits per sample 
inline 
void SetDeviceType( WAVEFORMATEX* pwfe ) 
{ 
	memset( pwfe, 0, sizeof(WAVEFORMATEX) ); 
	WORD  nBlockAlign = (AUDCHANNELS*AUDBITSMPL)/8; 
	DWORD nSamplesPerSec = AUDFREQ; 
	pwfe->wFormatTag = WAVE_FORMAT_PCM; 
	pwfe->nChannels = AUDCHANNELS; 
	pwfe->nBlockAlign = nBlockAlign; 
	pwfe->nSamplesPerSec = nSamplesPerSec; 
	pwfe->wBitsPerSample = AUDBITSMPL; 
	pwfe->nAvgBytesPerSec = nSamplesPerSec*nBlockAlign; 
} 
//}}} Audio specific functions 
 
///////////////////////////////////////////////////////////////////////////// 
// 		Implementation 
////////////// 
CVolumeOutWave::CVolumeOutWave() 
	:	m_bOK(false), 
		m_bInitialized(false), 
		m_bAvailable(false), 
 
		m_uMixerID(0L), 
		m_dwMixerHandle(0L), 
		m_hWnd(NULL), 
 
		m_dwMinimalVolume(BAD_DWORD), 
		m_dwMaximalVolume(BAD_DWORD), 
 
		m_pfUserSink(NULL), 
		m_dwUserValue(0L) 
{ 
	if ( m_bOK = Init() ) 
	{ 
		g_pThis = this; 
		if ( !Initialize() ) 
		{ 
			Done(); 
			g_pThis = NULL; 
		} 
	} 
} 
////////////// 
CVolumeOutWave::~CVolumeOutWave() 
{ 
	if ( m_bOK ) 
		Done(); 
	g_pThis = NULL; 
} 
////////////// 
bool CVolumeOutWave::Init() 
{ 
	if ( !mixerGetNumDevs() ) 
		return false; 
	// Getting Mixer ID 
	HWAVEOUT hwaveOut; 
	MMRESULT mmResult; 
	WAVEFORMATEX WaveFmt; 
	SetDeviceType( &WaveFmt ); 
	mmResult = waveOutOpen( &hwaveOut, WAVE_MAPPER, &WaveFmt, 0L, 0L, CALLBACK_NULL ); 
	if ( mmResult != MMSYSERR_NOERROR ) 
	{ 
		TRACE(".WaveOutputVolume: FAILURE: Could not open WaveOut Mapper. mmResult=%d\n", mmResult ); 
		return false; 
	} else { 
		mmResult = mixerGetID( (HMIXEROBJ)hwaveOut, &m_uMixerID, MIXER_OBJECTF_HWAVEOUT ); 
		waveOutClose( hwaveOut ); 
		if ( mmResult != MMSYSERR_NOERROR ) 
		{ 
			TRACE(".WaveOutputVolume: FAILURE: WaveOut Mapper in Mixer is not available. mmResult=%d\n", mmResult ); 
			return false; 
		} 
	} 
	// Exposing Window to Mixer 
	WNDCLASSEX wcx; 
	memset( &wcx, 0, sizeof(WNDCLASSEX) );	 
	wcx.cbSize = sizeof(WNDCLASSEX); 
	wcx.lpszClassName = WND_CLASS_NAME; 
	wcx.lpfnWndProc = (WNDPROC)MixerWndProc; 
	::RegisterClassEx(&wcx); 
	m_hWnd = CreateWindow(	WND_CLASS_NAME, 
							WND_NAME, 
							WS_POPUP | WS_DISABLED, 
							0, 0, 0, 0, 
							NULL, NULL, NULL, NULL ); 
	if ( !m_hWnd ) 
	{ 
		TRACE(".WaveOutputVolume: FAILURE: Could not create internal window.\n" ); 
		return false; 
	} 
	::ShowWindow(m_hWnd, SW_HIDE); 
	mmResult = mixerOpen( (LPHMIXER)&m_dwMixerHandle, m_uMixerID, (DWORD)m_hWnd, 0L, CALLBACK_WINDOW ); 
	if ( mmResult != MMSYSERR_NOERROR ) 
	{ 
		TRACE(".WaveOutputVolume: FAILURE: Could not open Mixer. mmResult=%d\n", mmResult ); 
		::DestroyWindow( m_hWnd ); 
		return false; 
	} 
	return true; 
} 
////////////// 
void CVolumeOutWave::Done() 
{ 
	if ( mixerClose( (HMIXER)m_dwMixerHandle ) != MMSYSERR_NOERROR ) 
	{ 
		TRACE(".WaveOutputVolume: WARNING: Could not close Mixer.\n" ); 
	} 
	::DestroyWindow( m_hWnd ); 
	m_bInitialized = false; 
	m_bOK = false; 
} 
////////////// 
void CVolumeOutWave::OnControlChanged( DWORD dwControlID ) 
{ 
	if ( m_dwVolumeControlID == dwControlID ) 
	{ 
		DWORD dwVolume = GetCurrentVolume(); 
		if ( (dwVolume!=BAD_DWORD) && (m_pfUserSink) ) 
		{ 
			(*m_pfUserSink)( dwVolume, m_dwUserValue ); 
		} 
	} 
} 
////////////// 
bool CVolumeOutWave::Initialize() 
{ 
	MMRESULT mmResult; 
	if ( !m_bOK ) 
		return false; 
	TRACE(".WaveOutputVolume: Initializing for Source WaveOut Line ..\n" ); 
	MIXERLINE MixerLine; 
	memset( &MixerLine, 0, sizeof(MIXERLINE) ); 
	MixerLine.cbStruct = sizeof(MIXERLINE); 
	MixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT; 
	mmResult = mixerGetLineInfo( (HMIXEROBJ)m_dwMixerHandle, &MixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE ); 
	if ( mmResult != MMSYSERR_NOERROR ) 
	{ 
		TRACE(".WaveOutputVolume: FAILURE: Could not get WaveOut Destionation Line for the WaveOut Source Line while initilaizing. mmResult=%d\n", mmResult ); 
		return false; 
	} 
 
	MIXERCONTROL Control; 
	memset( &Control, 0, sizeof(MIXERCONTROL) ); 
	Control.cbStruct = sizeof(MIXERCONTROL); 
 
	MIXERLINECONTROLS LineControls; 
	memset( &LineControls, 0, sizeof(MIXERLINECONTROLS) ); 
	LineControls.cbStruct = sizeof(MIXERLINECONTROLS); 
 
	LineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; 
	LineControls.dwLineID = MixerLine.dwLineID; 
	LineControls.cControls = 1; 
	LineControls.cbmxctrl = sizeof(MIXERCONTROL); 
	LineControls.pamxctrl = &Control; 
	mmResult = mixerGetLineControls( (HMIXEROBJ)m_dwMixerHandle, &LineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE ); 
	if ( mmResult == MMSYSERR_NOERROR ) 
	{ 
		if ( !(Control.fdwControl & MIXERCONTROL_CONTROLF_DISABLED) ) 
		{ 
			m_bAvailable = true; 
			TRACE(".WaveOutputVolume: \"%s\" Volume control for the WaveOut Source Line adopted.\n", Control.szShortName ); 
		} else { 
			TRACE(".WaveOutputVolume: WARNING: The Volume Control is disabled.\n" ); 
		} 
	} else { 
		TRACE(".WaveOutputVolume: WARNING: Could not get the WaveOut Source line Volume Control while initilaizing. mmResult=%d\n", mmResult ); 
	} 
	 
	m_nChannelCount = MixerLine.cChannels; 
	m_dwLineID = LineControls.dwLineID; 
	m_dwVolumeControlID = Control.dwControlID; 
	m_dwMinimalVolume = Control.Bounds.dwMinimum; 
	m_dwMaximalVolume = Control.Bounds.dwMaximum; 
	m_dwVolumeStep = Control.Metrics.cSteps; 
 
	m_bInitialized = true; 
	return true; 
} 
////////////// 
void CVolumeOutWave::EnableLine( bool bEnable ) 
{ 
	if ( !m_bInitialized ) 
		return; 
	bool bAnyEnabled = false; 
	MMRESULT mmResult; 
 
	MIXERLINE lineDestination; 
	memset( &lineDestination, 0, sizeof(MIXERLINE) ); 
	lineDestination.cbStruct = sizeof(MIXERLINE); 
	lineDestination.dwLineID = m_dwLineID; 
	mmResult = mixerGetLineInfo( (HMIXEROBJ)m_dwMixerHandle, &lineDestination, MIXER_GETLINEINFOF_LINEID ); 
	if ( mmResult != MMSYSERR_NOERROR ) 
	{ 
		if ( bEnable ) 
		{ 
			TRACE(".WaveOutputVolume: FAILURE: Could not get the WaveOut Destination Line while enabling. mmResult=%d\n", mmResult ); 
		} else { 
			TRACE(".WaveOutputVolume: FAILURE: Could not get the WaveOut Destination Line while disabling. mmResult=%d\n", mmResult ); 
		} 
		return; 
	} 
	// Getting all line's controls 
	int nControlCount = lineDestination.cControls; 
	int nChannelCount = lineDestination.cChannels; 
	MIXERLINECONTROLS LineControls; 
	memset( &LineControls, 0, sizeof(MIXERLINECONTROLS) ); 
	MIXERCONTROL* aControls = (MIXERCONTROL*)malloc( nControlCount * sizeof(MIXERCONTROL) ); 
	if ( !aControls ) 
	{ 
		if ( bEnable ) 
		{ 
			TRACE(".WaveOutputVolume: FAILURE: Out of memory while enabling the line.\n" ); 
		} else { 
			TRACE(".WaveOutputVolume: FAILURE: Out of memory while disabling the line.\n" ); 
		} 
		return; 
	} 
	memset( &aControls[0], 0, sizeof(nControlCount * sizeof(MIXERCONTROL)) ); 
	for ( int i = 0; i < nControlCount; i++ ) 
	{ 
		aControls[i].cbStruct = sizeof(MIXERCONTROL); 
	} 
	LineControls.cbStruct = sizeof(MIXERLINECONTROLS); 
	LineControls.dwLineID = lineDestination.dwLineID; 
	LineControls.cControls = nControlCount; 
	LineControls.cbmxctrl = sizeof(MIXERCONTROL); 
	LineControls.pamxctrl = &aControls[0]; 
	mmResult = mixerGetLineControls( (HMIXEROBJ)m_dwMixerHandle, &LineControls, MIXER_GETLINECONTROLSF_ALL ); 
	if ( mmResult == MMSYSERR_NOERROR ) 
	{ 
		for ( i = 0; i < nControlCount; i++ ) 
		{ 
			LONG lValue; 
			bool bReadyToSet = false; 
			switch (aControls[i].dwControlType) 
			{ 
			case MIXERCONTROL_CONTROLTYPE_MUTE: 
				lValue = (BOOL)!bEnable; 
				bReadyToSet = true; 
				break; 
			case MIXERCONTROL_CONTROLTYPE_SINGLESELECT: 
				lValue = (BOOL)bEnable; 
				bReadyToSet = true; 
				break; 
			case MIXERCONTROL_CONTROLTYPE_MUX: 
				lValue = (BOOL)bEnable; 
				bReadyToSet = true; 
				break; 
			case MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT: 
				lValue = (BOOL)bEnable; 
				bReadyToSet = true; 
				break; 
			case MIXERCONTROL_CONTROLTYPE_MIXER: 
				lValue = (BOOL)bEnable; 
				bReadyToSet = true; 
				break; 
			} 
			if ( bReadyToSet ) 
			{ 
				MIXERCONTROLDETAILS_BOOLEAN* aDetails = NULL; 
				int nMultipleItems = aControls[i].cMultipleItems; 
				int nChannels = nChannelCount; 
				// MIXERCONTROLDETAILS 
				MIXERCONTROLDETAILS ControlDetails; 
				memset( &ControlDetails, 0, sizeof(MIXERCONTROLDETAILS) ); 
				ControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); 
				ControlDetails.dwControlID = aControls[i].dwControlID; 
				if ( aControls[i].fdwControl & MIXERCONTROL_CONTROLF_UNIFORM ) 
				{ 
					nChannels = 1; 
				} 
				if ( aControls[i].fdwControl & MIXERCONTROL_CONTROLF_MULTIPLE ) 
				{ 
					nMultipleItems = aControls[i].cMultipleItems; 
					aDetails = (MIXERCONTROLDETAILS_BOOLEAN*)malloc(nMultipleItems*nChannels*sizeof(MIXERCONTROLDETAILS_BOOLEAN)); 
					if ( !aDetails ) 
					{ 
						TRACE(".WaveOutputVolume: FAILURE: Out of memory while enabling the line.\n" ); 
						continue; 
					} 
					for ( int nItem = 0; nItem < nMultipleItems; nItem++ ) 
					{ 
						for ( int nChannel = 0; nChannel < nChannels; nChannel++ ) 
						{ 
							aDetails[nItem+nChannel].fValue = lValue; 
						} 
					} 
				} else { 
					nMultipleItems = 0; 
					aDetails = (MIXERCONTROLDETAILS_BOOLEAN*)malloc(nChannels*sizeof(MIXERCONTROLDETAILS_BOOLEAN)); 
					if ( !aDetails ) 
					{ 
						if ( bEnable ) 
						{ 
							TRACE(".WaveOutputVolume: FAILURE: Out of memory while enabling the line.\n" ); 
						} else { 
							TRACE(".WaveOutputVolume: FAILURE: Out of memory while disabling the line.\n" ); 
						} 
						continue; 
					} 
					for ( int nChannel = 0; nChannel < nChannels; nChannel++ ) 
					{ 
						aDetails[nChannel].fValue = (LONG)lValue; 
					} 
				} 
				ControlDetails.cChannels = nChannels; 
				ControlDetails.cMultipleItems = nMultipleItems; 
				ControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); 
				ControlDetails.paDetails = &aDetails[0]; 
				mmResult = mixerSetControlDetails( (HMIXEROBJ)m_dwMixerHandle, &ControlDetails, 0L ); 
				if ( mmResult == MMSYSERR_NOERROR ) 
				{ 
					if ( bEnable ) 
					{ 
						TRACE(".WaveOutputVolume: Enabling Line: WaveOut Line control \"%s\"(0x%X) has been set to %d.\n", aControls[i].szShortName, aControls[i].dwControlType, lValue ); 
					} else { 
						TRACE(".WaveOutputVolume: Disabling Line: WaveOut Line control \"%s\"(0x%X) has been set to %d.\n", aControls[i].szShortName, aControls[i].dwControlType, lValue ); 
					} 
					bAnyEnabled = true; 
				} 
				free( aDetails ); 
			} 
		} 
	} else { 
		if ( bEnable ) 
		{ 
			TRACE(".WaveOutputVolume: FAILURE: Could not get the line controls while enabling. mmResult=%d\n", mmResult ); 
		} else { 
			TRACE(".WaveOutputVolume: FAILURE: Could not get the line controls while disabling. mmResult=%d\n", mmResult ); 
		} 
	} 
	free( aControls ); 
	if ( !bAnyEnabled ) 
	{ 
		if ( bEnable ) 
		{ 
			TRACE(".WaveOutputVolume: WARNING: No controls were found for enabling the line.\n" ); 
		} else { 
			TRACE(".WaveOutputVolume: WARNING: No controls were found for disabling the line.\n" ); 
		} 
	} 
} 
////////////////////////////////////////////// 
// IVolume interface 
////////////// 
bool CVolumeOutWave::IsAvailable() 
{ 
	return m_bAvailable; 
} 
////////////// 
void CVolumeOutWave::Enable() 
{ 
	EnableLine( true ); 
} 
////////////// 
void CVolumeOutWave::Disable() 
{ 
	EnableLine( false ); 
} 
////////////// 
DWORD CVolumeOutWave::GetVolumeMetric() 
{ 
	if ( !m_bAvailable ) 
		return BAD_DWORD; 
	return m_dwVolumeStep; 
} 
////////////// 
DWORD CVolumeOutWave::GetMinimalVolume() 
{ 
	if ( !m_bAvailable ) 
		return BAD_DWORD; 
	return m_dwMinimalVolume; 
} 
////////////// 
DWORD CVolumeOutWave::GetMaximalVolume() 
{ 
	if ( !m_bAvailable ) 
		return BAD_DWORD; 
	return m_dwMaximalVolume; 
} 
////////////// 
DWORD CVolumeOutWave::GetCurrentVolume() 
{ 
	if ( !m_bAvailable ) 
		return BAD_DWORD; 
	MIXERCONTROLDETAILS_UNSIGNED* aDetails = (MIXERCONTROLDETAILS_UNSIGNED*)malloc(m_nChannelCount*sizeof(MIXERCONTROLDETAILS_UNSIGNED)); 
	if ( !aDetails ) 
		return BAD_DWORD; 
	MIXERCONTROLDETAILS ControlDetails; 
	memset( &ControlDetails, 0, sizeof(MIXERCONTROLDETAILS) ); 
	ControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); 
	ControlDetails.dwControlID = m_dwVolumeControlID; 
	ControlDetails.cChannels = m_nChannelCount; 
	ControlDetails.cMultipleItems = 0; 
	ControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); 
	ControlDetails.paDetails = &aDetails[0]; 
	MMRESULT mmResult = mixerGetControlDetails( (HMIXEROBJ)m_dwMixerHandle, &ControlDetails, MIXER_GETCONTROLDETAILSF_VALUE ); 
	DWORD dw = aDetails[0].dwValue; 
	free( aDetails ); 
	if ( mmResult != MMSYSERR_NOERROR ) 
	{ 
		TRACE(".WaveOutputVolume: FAILURE: Could not get volume. mmResult=%d\n", mmResult ); 
		return BAD_DWORD; 
	} 
	return dw; 
} 
////////////// 
void CVolumeOutWave::SetCurrentVolume( DWORD dwValue ) 
{ 
	if ( !m_bAvailable || (dwValuem_dwMaximalVolume) ) 
		return; 
	MIXERCONTROLDETAILS_UNSIGNED* aDetails = (MIXERCONTROLDETAILS_UNSIGNED*)malloc(m_nChannelCount*sizeof(MIXERCONTROLDETAILS_UNSIGNED)); 
	if ( !aDetails ) 
		return; 
	for ( int i = 0; i < m_nChannelCount; i++ ) 
	{ 
		aDetails[i].dwValue = dwValue; 
	} 
	MIXERCONTROLDETAILS ControlDetails; 
	memset( &ControlDetails, 0, sizeof(MIXERCONTROLDETAILS) ); 
	ControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS); 
	ControlDetails.dwControlID = m_dwVolumeControlID; 
	ControlDetails.cChannels = m_nChannelCount; 
	ControlDetails.cMultipleItems = 0; 
	ControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); 
	ControlDetails.paDetails = &aDetails[0]; 
	MMRESULT mmResult = mixerSetControlDetails( (HMIXEROBJ)m_dwMixerHandle, &ControlDetails, MIXER_SETCONTROLDETAILSF_VALUE ); 
	free( aDetails ); 
	if ( mmResult != MMSYSERR_NOERROR ) 
	{ 
		TRACE(".WaveOutputVolume: FAILURE: Could not set volume(%d) mmResult=%d\n", dwValue, mmResult ); 
	} 
} 
////////////// 
void CVolumeOutWave::RegisterNotificationSink( PONMICVOULUMECHANGE pfUserSink, DWORD dwUserValue ) 
{ 
	m_pfUserSink = pfUserSink; 
	m_dwUserValue = dwUserValue; 
} 
//////////////////////////////////////////////////////////////////////// 
LRESULT CALLBACK CVolumeOutWave::MixerWndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) 
{ 
	if ( uMsg == MM_MIXM_CONTROL_CHANGE ) 
	{ 
		if ( g_pThis ) 
		{ 
			g_pThis->OnControlChanged( (DWORD)lParam ); 
		} 
	} 
	return ::DefWindowProc( hwnd, uMsg, wParam, lParam); 
}