Skip to content

Instantly share code, notes, and snippets.

@surinkim
Last active February 20, 2018 01:58
Show Gist options
  • Save surinkim/18a76d281164091897af to your computer and use it in GitHub Desktop.
Save surinkim/18a76d281164091897af to your computer and use it in GitHub Desktop.
xp audio handling
#include "AudioWrapper.h"
#include <QSysInfo>
#include <QCoreApplication>
AudioWrapper::AudioWrapper(void)
: m_isVistaLater( false )
, m_curPid( 0 )
{
CoInitialize( NULL );
Init();
}
AudioWrapper::~AudioWrapper(void)
{
m_mapSpeakerDevice.clear();
m_mapMicDevice.clear();
CoUninitialize();
}
bool AudioWrapper::IsVistaLater()
{
const QSysInfo::WinVersion ver = QSysInfo::windowsVersion();
if ( ver >= QSysInfo::WV_VISTA )
return true;
return false;
}
bool AudioWrapper::Init()
{
if ( IsVistaLater() )
m_isVistaLater = true;
m_curPid = QCoreApplication::applicationPid();
return true;
}
bool AudioWrapper::SetMasterVolume( std::wstring deviceName, std::wstring deviceId, const int volume )
{
if ( m_isVistaLater )
{
return SetMasterVolumeWin7( deviceId, volume);
}
return SetMasterVolumeXp( deviceName, volume );
}
int AudioWrapper::GetMasterVolume( std::wstring deviceName, std::wstring deviceId )
{
if ( m_isVistaLater )
{
return GetMasterVolumeWin7( deviceId );
}
return GetMasterVolumeXp( deviceName );
}
bool AudioWrapper::SetMasterMute( std::wstring deviceName, std::wstring deviceId, int state )
{
if ( m_isVistaLater )
{
return SetMasterMuteWin7( deviceId, state);
}
return SetMasterMuteXp( deviceName, state );
}
bool AudioWrapper::GetMasterMute( std::wstring deviceName, std::wstring deviceId )
{
if ( m_isVistaLater )
{
return GetMasterMuteWin7( deviceId );
}
return GetMasterMuteXp( deviceName );
}
bool AudioWrapper::SetWaveVolume( std::wstring deviceName, const int volume )
{
if ( m_isVistaLater )
{
return SetWaveVolumeWin7( volume );
}
return SetWaveVolumeXp( deviceName, volume );
}
int AudioWrapper::GetWaveVolume( std::wstring deviceName )
{
if ( m_isVistaLater )
{
return GetWaveVolumeWin7();
}
return GetWaveVolumeXp( deviceName );
}
bool AudioWrapper::SetWaveMute( std::wstring deviceName, int state )
{
if ( m_isVistaLater )
{
return SetWaveMuteWin7( state);
}
return SetWaveMuteXp( deviceName, state );
}
bool AudioWrapper::GetWaveMute( std::wstring deviceName )
{
if ( m_isVistaLater )
{
return GetWaveMuteWin7();
}
return GetWaveMuteXp( deviceName );
}
bool AudioWrapper::GetSpeakerDeviceInfo( std::wstring deviceName, SpeakerDevice& speakerDevice )
{
// 캐싱된 스피커 장비 데이터가 있는지 찾음.
auto it = m_mapSpeakerDevice.find( deviceName );
if ( it != m_mapSpeakerDevice.end() )
{
// 캐싱된 데이터가 있으면 전달
speakerDevice = it->second;
return true;
}
/////////////////////////////////////////////////
//캐싱된 데이터가 없으면 직접 찾고, 찾은 정보로 캐싱.
//device name으로, 믹서 핸들, mixer caps 정보를 얻음.
HMIXER mixer = NULL;
MIXERCAPS mixerCaps;
memset( &mixerCaps, 0, sizeof( MIXERCAPS ) );
bool find = GetMixerCaps( deviceName, mixer, MIXERLINE_TARGETTYPE_WAVEOUT, mixerCaps );
if ( find == false )
{
return false;
}
// 스피커 mixer line 정보를 얻음.
MIXERLINE mixerLine;
memset( &mixerLine, 0, sizeof(MIXERLINE) );
find = GetMixerLine( mixer, mixerCaps, MIXERLINE_TARGETTYPE_WAVEOUT, mixerLine );
if ( find == false )
{
return false;
}
// 스피커 wave line 정보를 얻음.
MIXERLINE mixerWaveLine;
memset( &mixerWaveLine, 0, sizeof( MIXERLINE ) );
find = GetMixerWaveLine( mixer, mixerLine, mixerWaveLine );
if ( find == false )
{
return false;
}
// 스피커 장치 캐싱
SpeakerDevice foundDevice;
foundDevice.m_mixer = mixer;
foundDevice.m_mixerMasterLine = mixerLine;
foundDevice.m_mixerWaveLine = mixerWaveLine;
m_mapSpeakerDevice.insert( std::pair< std::wstring, SpeakerDevice > ( deviceName, foundDevice ) );
speakerDevice = foundDevice;
return true;
}
bool AudioWrapper::GetMixerWaveLine( const HMIXER& mixer, const MIXERLINE& mixerLine, MIXERLINE& findMixerLine )
{
for (int i = 0; i < mixerLine.cConnections; i++)
{
MIXERLINE mixerWaveLine;
mixerWaveLine.cbStruct = sizeof(MIXERLINE);
mixerWaveLine.dwDestination = mixerLine.dwDestination;
mixerWaveLine.dwSource = i;
MMRESULT ret = ::mixerGetLineInfo(reinterpret_cast<HMIXEROBJ>( mixer ),
&mixerWaveLine,
MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_SOURCE);
if ( ret == MMSYSERR_NOERROR &&
mixerWaveLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT)
{
// found speaker wave mixer line
findMixerLine = mixerWaveLine;
return true;
}
}
return false;
}
bool AudioWrapper::GetMicDeviceInfo( std::wstring deviceName, MicDevice& micDevice )
{
// 캐싱된 마이크 장비 데이터가 있는지 찾음.
auto it = m_mapMicDevice.find( deviceName );
if ( it != m_mapMicDevice.end() )
{
// 캐싱된 데이터가 있으면 전달
micDevice = it->second;
return true;
}
/////////////////////////////////////////////////
//캐싱된 데이터가 없으면 직접 찾고, 찾은 정보로 캐싱.
//device name으로, 믹서 핸들, mixer caps 정보를 얻음.
HMIXER mixer = NULL;
MIXERCAPS mixerCaps;
memset( &mixerCaps, 0, sizeof( MIXERCAPS ) );
bool find = GetMixerCaps( deviceName, mixer, MIXERLINE_TARGETTYPE_WAVEIN, mixerCaps );
if ( find == false )
{
return false;
}
// 마이크 mixer line 정보를 얻음.
MIXERLINE mixerLine;
memset( &mixerLine, 0, sizeof(MIXERLINE) );
find = GetMixerLine( mixer, mixerCaps, MIXERLINE_TARGETTYPE_WAVEIN, mixerLine );
if ( find == false )
{
return false;
}
//VOLUME 컨트롤 정보를 얻음.
MIXERCONTROL volumeControl;
memset( &volumeControl, 0, sizeof ( MIXERCONTROL ) );
find = GetMixerControl( mixer, mixerLine, MIXERCONTROL_CONTROLTYPE_VOLUME, volumeControl );
if ( find == false )
{
return false;
}
//MUTE 컨트롤 정보를 얻음.
MIXERCONTROL muteControl;
memset( &muteControl, 0, sizeof ( MIXERCONTROL ) );
find = GetMixerControl( mixer, mixerLine, MIXERCONTROL_CONTROLTYPE_MUTE, muteControl );
if ( find == false )
{
return false;
}
// 마이크 장치 캐싱
MicDevice foundDevice;
foundDevice.m_mixer = mixer;
foundDevice.m_mixerLine = mixerLine;
foundDevice.m_mixerVolumeControl = volumeControl;
foundDevice.m_mixerMuteControl = muteControl;
m_mapMicDevice.insert( std::pair< std::wstring, MicDevice > ( deviceName, foundDevice ) );
micDevice = foundDevice;
return true;
}
bool AudioWrapper::SetMicVolume( std::wstring deviceName, int value )
{
MicDevice micDevice;
bool find = GetMicDeviceInfo( deviceName, micDevice );
if ( find == false )
{
return false;
}
const int channelCount = micDevice.m_mixerLine.cChannels;
MIXERCONTROLDETAILS_UNSIGNED* aDetails = (MIXERCONTROLDETAILS_UNSIGNED*)malloc( channelCount * sizeof( MIXERCONTROLDETAILS_UNSIGNED ) );
for ( int i = 0; i < channelCount; i++ )
{
aDetails[i].dwValue = value;
}
MIXERCONTROLDETAILS controlDetails;
memset( &controlDetails, 0, sizeof(MIXERCONTROLDETAILS) );
controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
controlDetails.dwControlID = micDevice.m_mixerVolumeControl.dwControlID;
controlDetails.cChannels = channelCount;
controlDetails.cMultipleItems = 0;
controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
controlDetails.paDetails = &aDetails[0];
MMRESULT ret = ::mixerSetControlDetails( reinterpret_cast< HMIXEROBJ >( micDevice.m_mixer ), &controlDetails, MIXER_SETCONTROLDETAILSF_VALUE );
if ( ret != MMSYSERR_NOERROR )
{
free( aDetails );
return false;
}
free( aDetails );
return true;
}
int AudioWrapper::GetMicVolume( std::wstring deviceName )
{
MicDevice micDevice;
bool find = GetMicDeviceInfo( deviceName, micDevice );
if ( find == false )
{
return false;
}
const int channelCount = micDevice.m_mixerLine.cChannels;
MIXERCONTROLDETAILS_UNSIGNED* aDetails = (MIXERCONTROLDETAILS_UNSIGNED*)malloc( channelCount * sizeof( MIXERCONTROLDETAILS_UNSIGNED ) );
MIXERCONTROLDETAILS controlDetails;
memset( &controlDetails, 0, sizeof(MIXERCONTROLDETAILS) );
controlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
controlDetails.dwControlID = micDevice.m_mixerVolumeControl.dwControlID;
controlDetails.cChannels = channelCount;
controlDetails.cMultipleItems = 0;
controlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
controlDetails.paDetails = &aDetails[0];
MMRESULT ret = ::mixerGetControlDetails( reinterpret_cast< HMIXEROBJ >( micDevice.m_mixer ), &controlDetails, MIXER_GETCONTROLDETAILSF_VALUE );
if ( ret != MMSYSERR_NOERROR )
{
free( aDetails );
return 0;
}
float volume = aDetails[0].dwValue;
free( aDetails );
return volume;
}
bool AudioWrapper::SetMicMute( std::wstring deviceName, int state )
{
MicDevice micDevice;
bool find = GetMicDeviceInfo( deviceName, micDevice );
if ( find == false )
{
return false;
}
const int channelCount = micDevice.m_mixerLine.cChannels;
MIXERCONTROLDETAILS_BOOLEAN* aDetails = (MIXERCONTROLDETAILS_BOOLEAN*)malloc( channelCount * sizeof( MIXERCONTROLDETAILS_BOOLEAN ) );
for ( int i = 0; i < channelCount; i++ )
{
aDetails[i].fValue = state;
}
MIXERCONTROLDETAILS mxcd;
memset( &mxcd, 0, sizeof(MIXERCONTROLDETAILS) );
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mxcd.dwControlID = micDevice.m_mixerMuteControl.dwControlID;
mxcd.cChannels = channelCount;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
mxcd.paDetails = &aDetails[0];
MMRESULT ret = ::mixerSetControlDetails(reinterpret_cast<HMIXEROBJ>( micDevice.m_mixer ), &mxcd, MIXER_SETCONTROLDETAILSF_VALUE);
if ( ret != MMSYSERR_NOERROR)
{
free( aDetails );
return false;
}
free( aDetails );
return true;
}
bool AudioWrapper::GetMicMute( std::wstring deviceName )
{
MicDevice micDevice;
bool find = GetMicDeviceInfo( deviceName, micDevice );
if ( find == false )
{
return false;
}
const int channelCount = micDevice.m_mixerLine.cChannels;
MIXERCONTROLDETAILS_BOOLEAN* aDetails = (MIXERCONTROLDETAILS_BOOLEAN*)malloc( channelCount * sizeof( MIXERCONTROLDETAILS_BOOLEAN ) );
MIXERCONTROLDETAILS mxcd;
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mxcd.dwControlID = micDevice.m_mixerMuteControl.dwControlID;
mxcd.cChannels = channelCount;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mxcd.paDetails = &aDetails[0];
MMRESULT ret = mixerGetControlDetails(reinterpret_cast<HMIXEROBJ>( micDevice.m_mixer ),
&mxcd, MIXER_GETCONTROLDETAILSF_VALUE);
if ( ret != MMSYSERR_NOERROR)
{
free( aDetails );
return false;
}
bool mute = aDetails[0].fValue;
free( aDetails );
return mute;
}
std::vector< OutputDeviceInfo > AudioWrapper::GetSpeakerDevices()
{
std::vector< OutputDeviceInfo > vecInfo;
const int mixerCount = ::mixerGetNumDevs();
if ( mixerCount == 0 )
return vecInfo;
for ( int i = 0; i < mixerCount; i++ )
{
OutputDeviceInfo info;
HMIXER mixer;
MMRESULT ret = ::mixerOpen( &mixer, i, 0, NULL, MIXER_OBJECTF_MIXER );
if ( ret != MMSYSERR_NOERROR)
{
continue;
}
//Get Speaker Device Handle
info.m_mixer = mixer;
MIXERCAPS mixerCaps;
memset( &mixerCaps, 0, sizeof(MIXERCAPS) );
ret = mixerGetDevCaps( (UINT_PTR)mixer, &mixerCaps, sizeof(MIXERCAPS) );
if( ret != MMSYSERR_NOERROR )
{
continue;
}
//Get Speaker Device Name
info.m_name = mixerCaps.szPname;
MIXERLINE mixerLine;
mixerLine.cbStruct = sizeof(MIXERLINE);
mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
ret = ::mixerGetLineInfo( reinterpret_cast< HMIXEROBJ >( mixer ), &mixerLine, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE );
if( ret != MMSYSERR_NOERROR )
{
mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_DIGITAL; // ex) Realtek Digital Output
ret = ::mixerGetLineInfo( reinterpret_cast< HMIXEROBJ >( mixer ), &mixerLine, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE );
if( ret != MMSYSERR_NOERROR )
{
continue;
}
}
//Get Master line id
info.m_masterLineId = mixerLine.dwLineID;
for (int j = 0; j < mixerLine.cConnections; j++)
{
MIXERLINE mixerWaveLine;
mixerWaveLine.cbStruct = sizeof(MIXERLINE);
mixerWaveLine.dwDestination = mixerLine.dwDestination;
mixerWaveLine.dwSource = j;
ret = ::mixerGetLineInfo(reinterpret_cast<HMIXEROBJ>( mixer ),
&mixerWaveLine,
MIXER_OBJECTF_HMIXER |
MIXER_GETLINEINFOF_SOURCE);
if ( ret == MMSYSERR_NOERROR &&
mixerWaveLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT)
{
//Get Wave line id
info.m_waveLineId = mixerWaveLine.dwLineID;
break;
}
}
vecInfo.push_back( info );
}
return vecInfo;
}
bool AudioWrapper::GetMixerCaps( const std::wstring deviceName, HMIXER& findMixer, const int mixerLineType, MIXERCAPS& findMixerCaps )
{
const int mixerCount = ::mixerGetNumDevs();
if ( mixerCount == 0 )
return false;
HMIXER defaultMixer;
MIXERCAPS defaultMixerCaps;
memset( &defaultMixerCaps, 0, sizeof(MIXERCAPS) );
bool IsFoundDefaltMixer = false;
// device를 순회하면서, deviceName과 동일한 장치를 찾는다.
for ( int i = 0; i < mixerCount; i++ )
{
HMIXER mixer;
MMRESULT ret = ::mixerOpen( &mixer, i, 0, NULL, MIXER_OBJECTF_MIXER );
if ( ret != MMSYSERR_NOERROR)
{
continue;
}
MIXERCAPS mixerCaps;
memset( &mixerCaps, 0, sizeof(MIXERCAPS) );
ret = mixerGetDevCaps( (UINT_PTR)mixer, &mixerCaps, sizeof(MIXERCAPS) );
if( ret != MMSYSERR_NOERROR || deviceName != mixerCaps.szPname)
{
// 동일 이름의 장비가 없는 경우를 위해, default용으로 사용할 mixerLineType( 마이크 OR 스피커 ) 믹서가 있는지 미리 체크해 둠.
if ( IsFoundDefaltMixer == false )
{
MIXERLINE mixerLine;
memset( &mixerLine, 0, sizeof(MIXERLINE) );
IsFoundDefaltMixer = GetMixerLine( mixer, mixerCaps, mixerLineType, mixerLine );
if ( IsFoundDefaltMixer )
{
defaultMixer = mixer;
defaultMixerCaps = mixerCaps;
}
}
continue;
}
//found device which is equal with 'deviceName'
findMixer = mixer;
findMixerCaps = mixerCaps;
return true;
}
// 동일 이름을 가진 장비가 없는 경우는, voice chat wizard에서 "Default Device"를 넘겨주거나 해당 이름의 장비가 정말 없는 경우 등인데,
// 이때는 위에서 기본 장치를 찾은 것이 있다면, 이 정보를 넘겨주도록 한다.
if ( IsFoundDefaltMixer )
{
findMixer = defaultMixer;
findMixerCaps = defaultMixerCaps;
return true;
}
return false;
}
bool AudioWrapper::GetMixerLine( const HMIXER& mixer, const MIXERCAPS& mixerCaps, const int mixerLineType, MIXERLINE& findMixerLine )
{
for ( int i = 0; i < mixerCaps.cDestinations; i++ )
{
MIXERLINE mixerLine;
memset( &mixerLine, 0, sizeof(MIXERLINE) );
mixerLine.cbStruct = sizeof(MIXERLINE);
mixerLine.dwDestination = i;
// Get Mic Line info
MMRESULT ret = ::mixerGetLineInfo( reinterpret_cast< HMIXEROBJ >( mixer ), &mixerLine, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_DESTINATION );
if( ret != MMSYSERR_NOERROR || mixerLine.Target.dwType != mixerLineType )
{
continue;
}
//found mic mixer line
findMixerLine = mixerLine;
return true;
}
return false;
}
bool AudioWrapper::GetMixerControl( const HMIXER& mixer, const MIXERLINE& mixerLine, const int controlType, MIXERCONTROL& findControl )
{
const int connectionCount = mixerLine.cConnections;
MIXERLINE* pConnectionsMixerLine = (MIXERLINE*)new MIXERLINE[ connectionCount ];
for ( int i = 0; i < connectionCount; i++ )
{
memcpy( (void*)&pConnectionsMixerLine[ i ] , (void*)&mixerLine, sizeof(MIXERLINE) ) ;
pConnectionsMixerLine[ i ].dwSource = i;
MMRESULT ret = mixerGetLineInfo( (HMIXEROBJ)mixer, &pConnectionsMixerLine[ i ], MIXER_GETLINEINFOF_SOURCE ) ;
if( ret != MMSYSERR_NOERROR || pConnectionsMixerLine[ i ].dwComponentType != MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE )
{
continue;
}
const int controlCount = pConnectionsMixerLine[ i ].cControls;
MIXERCONTROL *pMixerControl = new MIXERCONTROL[controlCount] ;
MIXERLINECONTROLS mixerLineControls;
mixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
mixerLineControls.dwLineID = pConnectionsMixerLine[ i ].dwLineID ;
mixerLineControls.dwControlType = 0 ;
mixerLineControls.cControls = pConnectionsMixerLine[ i ].cControls ;
mixerLineControls.cbmxctrl = sizeof(MIXERCONTROL) ;
mixerLineControls.pamxctrl = pMixerControl ;
ret = mixerGetLineControls( (HMIXEROBJ)mixer, &mixerLineControls, MIXER_GETLINECONTROLSF_ALL ) ;
if( ret != MMSYSERR_NOERROR )
{
delete [] pMixerControl;
continue;
}
for ( int j = 0; j < controlCount; j++ )
{
if ( pMixerControl[ j ].dwControlType == controlType )
{//found!
findControl = pMixerControl[ j ];
delete [] pMixerControl;
delete [] pConnectionsMixerLine;
return true;
}
}
delete [] pMixerControl;
}
delete [] pConnectionsMixerLine;
return false;
}
std::vector< InputDeviceInfo > AudioWrapper::GetMicDevices()
{
std::vector< InputDeviceInfo > vecInfo;
const int mixerCount = ::mixerGetNumDevs();
if ( mixerCount == 0 )
return vecInfo;
for ( int i = 0; i < mixerCount; i++ )
{
InputDeviceInfo info;
HMIXER mixer;
MMRESULT ret = ::mixerOpen( &mixer, i, 0, NULL, MIXER_OBJECTF_MIXER );
if ( ret != MMSYSERR_NOERROR)
{
continue;
}
//Get Mic Device Handle
info.m_mixer = mixer;
MIXERCAPS mixerCaps;
memset( &mixerCaps, 0, sizeof(MIXERCAPS) );
ret = mixerGetDevCaps( (UINT_PTR)mixer, &mixerCaps, sizeof(MIXERCAPS) );
if( ret != MMSYSERR_NOERROR )
{
continue;
}
//Get Mic Device Name
info.m_name = mixerCaps.szPname;
for ( int j = 0; j < mixerCaps.cDestinations; j++ )
{
MIXERLINE mixerLine;
memset( &mixerLine, 0, sizeof(MIXERLINE) );
mixerLine.cbStruct = sizeof(MIXERLINE);
mixerLine.dwDestination = j;
// Get Mic Line info
ret = ::mixerGetLineInfo( reinterpret_cast< HMIXEROBJ >( mixer ), &mixerLine, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_DESTINATION );
if( ret != MMSYSERR_NOERROR || mixerLine.Target.dwType != MIXERLINE_TARGETTYPE_WAVEIN )
{
continue;
}
//Get Mic Channel Count
info.m_channelCount = mixerLine.cChannels;
const int connectionCount = mixerLine.cConnections;
MIXERLINE* pConnectionsMixerLine = (MIXERLINE*)new MIXERLINE[ connectionCount ];
for ( int k = 0; k < connectionCount; k++ )
{
memcpy( (void*)&pConnectionsMixerLine[ k ] , (void*)&mixerLine, sizeof(MIXERLINE) ) ;
pConnectionsMixerLine[ k ].dwSource = k;
ret = mixerGetLineInfo( (HMIXEROBJ)mixer, &pConnectionsMixerLine[ k ], MIXER_GETLINEINFOF_SOURCE ) ;
if( ret != MMSYSERR_NOERROR || pConnectionsMixerLine[ k ].dwComponentType != MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE )
{
continue;
}
const int controlCount = pConnectionsMixerLine[ k ].cControls;
MIXERCONTROL *pMixerControl = new MIXERCONTROL[controlCount] ;
MIXERLINECONTROLS mixerLineControls;
mixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
mixerLineControls.dwLineID = pConnectionsMixerLine[ k ].dwLineID ;
mixerLineControls.dwControlType = 0 ;
mixerLineControls.cControls = pConnectionsMixerLine[ k ].cControls ;
mixerLineControls.cbmxctrl = sizeof(MIXERCONTROL) ;
mixerLineControls.pamxctrl = pMixerControl ;
ret = mixerGetLineControls( (HMIXEROBJ)mixer, &mixerLineControls, MIXER_GETLINECONTROLSF_ALL ) ;
if( ret != MMSYSERR_NOERROR )
{
continue;
}
for ( int l = 0; l < controlCount; l++ )
{
if ( pMixerControl[ l ].dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE )
{
info.m_micMuteControlId = pMixerControl[ l ].dwControlID;
}
else if ( pMixerControl[ l ].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME )
{
info.m_micVolumeControlId = pMixerControl[ l ].dwControlID;
}
}
free ( pMixerControl );
vecInfo.push_back( info );
}
free( pConnectionsMixerLine );
}
}
return vecInfo;
}
bool AudioWrapper::SetMasterVolumeWin7( std::wstring deviceId, const int volume )
{
float newVolume = volume * 0.01;// parameter로 받는 volume 범위는 0 ~ 65535이고, SetMasterVolumeLevelScalar에 넘겨줄때는 0.0 ~ 1.0의 범위에 있어야 함.
IMMDevice *pDevice = nullptr;
bool find = FindDevice( deviceId, &pDevice );
if ( find == false || pDevice == nullptr )
{
return false;
}
IAudioEndpointVolume *endpointVolume = NULL;
pDevice->Activate( __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
float curVolume;
HRESULT hr = endpointVolume->GetMasterVolumeLevelScalar( &curVolume );
if ( FAILED( hr ) )
{
return false;
}
// 현재 볼륨 값과 설정한 볼륨 값을 int로 변환해서 같으면 return
float a = curVolume * 100;
float b = newVolume * 100;
int x = a;
int y = b;
if ( x == y )
return true;
hr = endpointVolume->SetMasterVolumeLevelScalar( newVolume, NULL);
if ( FAILED( hr ) )
{
return false;
}
return true;
}
bool AudioWrapper::SetMasterVolumeXp( std::wstring deviceName, int value )
{
return SetVolume( MASTER, deviceName, value );
}
int AudioWrapper::GetMasterVolumeWin7( std::wstring deviceId )
{
IMMDevice *pDevice = nullptr;
bool find = FindDevice( deviceId, &pDevice );
if ( find == false || pDevice == nullptr )
{
return 0;
}
IAudioEndpointVolume *endpointVolume = NULL;
pDevice->Activate( __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
float level;
HRESULT hr = endpointVolume->GetMasterVolumeLevelScalar( &level );
if ( FAILED( hr ) )
{
return false;
}
int newVolume = level * 100; // level로 받는 volume 범위는 0.0 ~ 1.0이고, slider control로 넘겨줄때는 0 ~ 100의 범위에 있어야 함.
return newVolume;
}
int AudioWrapper::GetMasterVolumeXp( std::wstring deviceName )
{
return GetVolume( MASTER, deviceName );
}
bool AudioWrapper::SetMasterMuteWin7( std::wstring deviceId, int state )
{
IMMDevice *pDevice = nullptr;
bool find = FindDevice( deviceId, &pDevice );
if ( find == false || pDevice == nullptr )
{
return false;
}
IAudioEndpointVolume *endpointVolume = NULL;
pDevice->Activate( __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
HRESULT hr = endpointVolume->SetMute( (bool)state, NULL );
if ( FAILED( hr ) )
{
return false;
}
//win7 볼륨 믹서에서 마스터 볼륨 컨트롤을 mute하면, 현재 process의 볼륨 컨트롤도 mute되는데,
//이때, wasapi api로 현재 process의 볼륨 컨트롤 mute 상태를 구하면 unchecked로 나온다.
//이 현상을 해결하기 위해, 마스터 볼륨 컨트롤을 mute하거나 unmute하면, 현재 process의 볼륨 컨트롤도 동일하게 상태 처리해준다.
if ( (bool)state != GetWaveMuteWin7() )
{
SetWaveMuteWin7( state );
}
return true;
}
bool AudioWrapper::SetMasterMuteXp( std::wstring deviceName, int state )
{
return SetMute( MASTER, deviceName, state );
}
bool AudioWrapper::GetMasterMuteWin7( std::wstring deviceId )
{
IMMDevice *pDevice = nullptr;
bool find = FindDevice( deviceId, &pDevice );
if ( find == false || pDevice == nullptr )
{
return false;
}
IAudioEndpointVolume *endpointVolume = NULL;
pDevice->Activate( __uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID *)&endpointVolume);
BOOL mute;
HRESULT hr = endpointVolume->GetMute( &mute );
if ( FAILED( hr ) )
{
return false;
}
return mute;
}
bool AudioWrapper::GetMasterMuteXp( std::wstring deviceName )
{
return GetMute( MASTER, deviceName );
}
bool AudioWrapper::SetWaveVolumeWin7( const int volume )
{
float newVolume = volume * 0.01;// parameter로 받는 volume 범위는 0 ~ 65535이고, SetMasterVolumeLevelScalar에 넘겨줄때는 0.0 ~ 1.0의 범위에 있어야 함.
IAudioSessionControl2* pControl2 = nullptr;
bool find = FindControl( &pControl2 );
if ( find == false || pControl2 == nullptr )
{
return false;
}
ISimpleAudioVolume *pVolume = NULL;
HRESULT hr = pControl2->QueryInterface(__uuidof(ISimpleAudioVolume), (void **) &pVolume);
if ( FAILED( hr ) )
{
return false;
}
float curVolume;
pVolume->GetMasterVolume( &curVolume );
// 현재 볼륨 값과 설정한 볼륨 값을 int로 변환해서 같으면 return
float a = curVolume * 100;
float b = newVolume * 100;
int x = a;
int y = b;
if ( x == y )
return true;
pVolume->SetMasterVolume( newVolume, NULL );
pVolume->Release();
return true;
}
bool AudioWrapper::SetWaveVolumeXp( std::wstring deviceName, int value )
{
return SetVolume( WAVE, deviceName, value );
}
int AudioWrapper::GetWaveVolumeWin7()
{
IAudioSessionControl2* pControl2 = nullptr;
bool find = FindControl( &pControl2 );
if ( find == false || pControl2 == nullptr )
{
return false;
}
ISimpleAudioVolume *pVolume = NULL;
HRESULT hr = pControl2->QueryInterface(__uuidof(ISimpleAudioVolume), (void **) &pVolume);
if ( FAILED( hr ) )
{
return 0;
}
float volume;
pVolume->GetMasterVolume( &volume );
pVolume->Release();
int newVolume = volume * 100; // level로 받는 volume 범위는 0.0 ~ 1.0이고, slider control로 넘겨줄때는 0 ~ 100의 범위에 있어야 함.
return newVolume;
}
int AudioWrapper::GetWaveVolumeXp( std::wstring deviceName )
{
return GetVolume( WAVE, deviceName );
}
bool AudioWrapper::SetWaveMuteWin7( int state )
{
IAudioSessionControl2* pControl2 = nullptr;
bool find = FindControl( &pControl2 );
if ( find == false || pControl2 == nullptr )
{
return false;
}
ISimpleAudioVolume *pVolume = NULL;
HRESULT hr = pControl2->QueryInterface(__uuidof(ISimpleAudioVolume), (void **) &pVolume);
if ( FAILED( hr ) )
{
return false;
}
pVolume->SetMute( (BOOL) state, NULL );
pVolume->Release();
return true;
}
bool AudioWrapper::SetWaveMuteXp( std::wstring deviceName, int state )
{
return SetMute( WAVE, deviceName, state );
}
bool AudioWrapper::GetWaveMuteWin7()
{
IAudioSessionControl2* pControl2 = nullptr;
bool find = FindControl( &pControl2 );
if ( find == false || pControl2 == nullptr )
{
return false;
}
ISimpleAudioVolume *pVolume = NULL;
HRESULT hr = pControl2->QueryInterface(__uuidof(ISimpleAudioVolume), (void **) &pVolume);
if ( FAILED( hr ) )
{
return false;
}
BOOL mute;
pVolume->GetMute( &mute);
pVolume->Release();
return mute;
}
bool AudioWrapper::GetWaveMuteXp( std::wstring deviceName )
{
return GetMute( WAVE, deviceName );
}
bool AudioWrapper::SetMute( ControlType type, std::wstring deviceName, int state )
{
if ( type != MASTER && type != WAVE )
{
return false;
}
SpeakerDevice speakerDevice;
bool find = GetSpeakerDeviceInfo( deviceName, speakerDevice );
if ( find == false )
{
return false;
}
DWORD lineId = 0;
if ( type == WAVE )
{
lineId = speakerDevice.m_mixerWaveLine.dwLineID;
}
else
{
lineId = speakerDevice.m_mixerMasterLine.dwLineID;
}
// Get Mute Control
MIXERCONTROL mxc;
MIXERLINECONTROLS mxlc;
mxlc.cbStruct = sizeof(MIXERLINECONTROLS);
mxlc.dwLineID = lineId;
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE;
mxlc.cControls = 1;
mxlc.cbmxctrl = sizeof(MIXERCONTROL);
mxlc.pamxctrl = &mxc;
MMRESULT ret = ::mixerGetLineControls(reinterpret_cast<HMIXEROBJ>( speakerDevice.m_mixer ), &mxlc, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE );
if ( ret != MMSYSERR_NOERROR)
{
return false;
}
MIXERCONTROLDETAILS_BOOLEAN mxcdMute = { (LONG) state };
MIXERCONTROLDETAILS mxcd;
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mxcd.dwControlID = mxc.dwControlID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mxcd.paDetails = &mxcdMute;
ret = mixerSetControlDetails(reinterpret_cast<HMIXEROBJ>( speakerDevice.m_mixer ),
&mxcd, MIXER_SETCONTROLDETAILSF_VALUE);
if ( ret != MMSYSERR_NOERROR)
{
return false;
}
return true;
}
bool AudioWrapper::GetMute( ControlType type, std::wstring deviceName )
{
if ( type != MASTER && type != WAVE )
{
return false;
}
SpeakerDevice speakerDevice;
bool find = GetSpeakerDeviceInfo( deviceName, speakerDevice );
if ( find == false )
{
return false;
}
DWORD lineId = 0;
if ( type == WAVE )
{
lineId = speakerDevice.m_mixerWaveLine.dwLineID;
}
else
{
lineId = speakerDevice.m_mixerMasterLine.dwLineID;
}
// Get Mute Control
MIXERCONTROL mxc;
MIXERLINECONTROLS mxlc;
mxlc.cbStruct = sizeof(MIXERLINECONTROLS);
mxlc.dwLineID = lineId;
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE;
mxlc.cControls = 1;
mxlc.cbmxctrl = sizeof(MIXERCONTROL);
mxlc.pamxctrl = &mxc;
MMRESULT ret = ::mixerGetLineControls(reinterpret_cast<HMIXEROBJ>( speakerDevice.m_mixer ), &mxlc, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE );
if ( ret != MMSYSERR_NOERROR)
{
return false;
}
MIXERCONTROLDETAILS_BOOLEAN mxcdMute;
MIXERCONTROLDETAILS mxcd;
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mxcd.dwControlID = mxc.dwControlID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mxcd.paDetails = &mxcdMute;
ret = mixerGetControlDetails(reinterpret_cast<HMIXEROBJ>( speakerDevice.m_mixer ),
&mxcd, MIXER_GETCONTROLDETAILSF_VALUE);
if ( ret != MMSYSERR_NOERROR)
{
return false;
}
return mxcdMute.fValue;
}
bool AudioWrapper::SetVolume( ControlType type, std::wstring deviceName, int value )
{
if ( type != MASTER && type != WAVE )
{
return false;
}
SpeakerDevice speakerDevice;
bool find = GetSpeakerDeviceInfo( deviceName, speakerDevice );
if ( find == false )
{
return false;
}
DWORD lineId = 0;
if ( type == WAVE )
{
lineId = speakerDevice.m_mixerWaveLine.dwLineID;
}
else
{
lineId = speakerDevice.m_mixerMasterLine.dwLineID;
}
// Get Volume Control
MIXERCONTROL mxc;
MIXERLINECONTROLS mxlc;
mxlc.cbStruct = sizeof(MIXERLINECONTROLS);
mxlc.dwLineID = lineId;
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mxlc.cControls = 1;
mxlc.cbmxctrl = sizeof(MIXERCONTROL);
mxlc.pamxctrl = &mxc;
MMRESULT ret = ::mixerGetLineControls(reinterpret_cast<HMIXEROBJ>( speakerDevice.m_mixer ), &mxlc, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE );
if ( ret != MMSYSERR_NOERROR)
{
return false;
}
MIXERCONTROLDETAILS_UNSIGNED mxcdVolume;
mxcdVolume.dwValue = value;
MIXERCONTROLDETAILS mxcd;
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mxcd.dwControlID = mxc.dwControlID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mxcd.paDetails = &mxcdVolume;
ret = mixerSetControlDetails(reinterpret_cast<HMIXEROBJ>( m_curOutputDevice.m_mixer ),
&mxcd, MIXER_SETCONTROLDETAILSF_VALUE);
if ( ret != MMSYSERR_NOERROR)
{
return false;
}
return true;
}
int AudioWrapper::GetVolume( ControlType type, std::wstring deviceName )
{
if ( type != MASTER && type != WAVE )
{
return 0;
}
SpeakerDevice speakerDevice;
bool find = GetSpeakerDeviceInfo( deviceName, speakerDevice );
if ( find == false )
{
return false;
}
DWORD lineId = 0;
if ( type == WAVE )
{
lineId = speakerDevice.m_mixerWaveLine.dwLineID;
}
else
{
lineId = speakerDevice.m_mixerMasterLine.dwLineID;
}
// Get Volume Control
MIXERCONTROL mxc;
MIXERLINECONTROLS mxlc;
mxlc.cbStruct = sizeof(MIXERLINECONTROLS);
mxlc.dwLineID = lineId;
mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mxlc.cControls = 1;
mxlc.cbmxctrl = sizeof(MIXERCONTROL);
mxlc.pamxctrl = &mxc;
MMRESULT ret = ::mixerGetLineControls(reinterpret_cast<HMIXEROBJ>( speakerDevice.m_mixer ), &mxlc, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE );
if( ret != MMSYSERR_NOERROR )
{
return 0;
}
MIXERCONTROLDETAILS_UNSIGNED mxcdVolume;
MIXERCONTROLDETAILS mxcd;
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mxcd.dwControlID = mxc.dwControlID;
mxcd.cChannels = 1;
mxcd.cMultipleItems = 0;
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mxcd.paDetails = &mxcdVolume;
ret = mixerGetControlDetails(reinterpret_cast<HMIXEROBJ>( speakerDevice.m_mixer ),
&mxcd, MIXER_SETCONTROLDETAILSF_VALUE);
if ( ret != MMSYSERR_NOERROR)
{
return 0;
}
return mxcdVolume.dwValue;
}
bool AudioWrapper::FindDevice( std::wstring deviceId, IMMDevice **pDevice )
{
//os check
if ( m_isVistaLater == false )
{
return false;
}
HRESULT hr;
IMMDeviceEnumerator *deviceEnumerator = NULL;
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
if ( FAILED( hr ) )
return false;
IMMDevice *findDevice = NULL;
if ( deviceId.empty() )
{//device id가 없으면 defalult 스피커 장치 찾음.
hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &findDevice);
if ( FAILED( hr ) )
{
return false;
}
*(pDevice) = findDevice;
deviceEnumerator->Release();
return true;
}
//device id가 있는 경우 장비 목록을 순회하면서 장치를 찾음.
IMMDeviceCollection *pDevices;
hr = deviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &pDevices);
if ( FAILED(hr) )
{
deviceEnumerator->Release();
return false;
}
UINT count;
pDevices->GetCount( &count );
deviceEnumerator->Release();
for ( int i = 0; i < count; i++ )
{
IMMDevice *findDevice = NULL;
hr = pDevices->Item( i, &findDevice);
if ( FAILED(hr) )
{
continue;
}
LPWSTR wstrID = NULL;
hr = findDevice->GetId( &wstrID );
if ( FAILED(hr) )
{
findDevice->Release();
continue;
}
if ( deviceId == wstrID )
{// find device
*(pDevice) = findDevice;
findDevice->Release();
return true;
}
findDevice->Release();
}
return false;
}
bool AudioWrapper::FindControl( IAudioSessionControl2 **pControl2 )
{
HRESULT hr;
IMMDeviceEnumerator *deviceEnumerator = NULL;
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID *)&deviceEnumerator);
if ( FAILED( hr ) )
return false;
IMMDevice *pDevice = nullptr;
hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice);
if ( FAILED( hr ) )
{
return false;
}
IAudioSessionManager2* pSessionManager = NULL;
hr = pDevice->Activate(__uuidof(IAudioSessionManager2), CLSCTX_ALL,NULL, (void**)&pSessionManager);
if ( FAILED( hr ) )
{
return false;
}
IAudioSessionEnumerator *pEnumerator = NULL;
hr = pSessionManager->GetSessionEnumerator( &pEnumerator );
if ( FAILED( hr ) )
{
return false;
}
int count = 0;
hr = pEnumerator->GetCount( &count );
for (int i = 0; i < count; i++ )
{
IAudioSessionControl *pSessionControl = NULL;
hr = pEnumerator->GetSession( i, &pSessionControl );
IAudioSessionControl2 *pSessionControl2 = NULL;
hr = pSessionControl->QueryInterface( __uuidof(IAudioSessionControl2), (void **) &pSessionControl2 );
if ( FAILED( hr ) )
{
return false;
}
DWORD dwPid;
pSessionControl2->GetProcessId( &dwPid );
if ( m_curPid == dwPid )
{
*( pControl2 ) = pSessionControl2;
pSessionManager->Release();
pEnumerator->Release();
return true;
}
pSessionControl->Release();
pSessionControl2->Release();
}
pSessionManager->Release();
pEnumerator->Release();
return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment