Last active
February 20, 2018 01:58
-
-
Save surinkim/18a76d281164091897af to your computer and use it in GitHub Desktop.
xp audio handling
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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