Notice
Recent Posts
Recent Comments
Link
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
Archives
Today
Total
관리 메뉴

Code Habit

[C++] Master Volume 제어 본문

카테고리 없음

[C++] Master Volume 제어

코드베어 2022. 6. 7. 17:00

윈도우 녹음(마이크)장치에 연결하여 Master Volume  제어 및  변경되는 값을 가져오는 예제이다.

COM 기반의 DirectShow 객체들을 이용할 것이고 이를 위해 다음과 같이 초기화 한다. 

// COM 초기화
HRESULT	hr = CoInitializeEx(NULL, ::COINIT::COINIT_APARTMENTTHREADED);
if (FAILED(hr)) {
}

// GUID 구하기
hr = CoCreateGuid(&m_guidEventContext);
if (FAILED(hr)) {
}

// NULL 체크
if (IsEqualGUID(m_guidEventContext, GUID_NULL)) {
}

 

 

캡쳐(마이크)장치 타입의 장치 리스트를 가져오고 이 중 한가지 장치에 연결하여 현재 설정된 볼륨 및 Mute정보를 가져오거나 설정할 수 있다.

CComPtr<IMMDeviceEnumerator> pIMMDE;
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pIMMDE));
if (FAILED(hr)) {
	// error
}

if (!pIMMDE) {
 	// error
}

CComPtr<IMMDeviceCollection> pIMMDC;
hr = pIMMDE->EnumAudioEndpoints(eDataFlow, DEVICE_STATE_ACTIVE, &pIMMDC);
if (FAILED(hr)) {
	// error
}

UINT uiCount = 0;
hr = pIMMDC->GetCount(&uiCount);
if (FAILED(hr)) {
	// error
}

for (UINT ui = 0; ui < uiCount; ++ui) 
{
    CComPtr<IMMDevice> pIMMDevice;
    hr = pIMMDC->Item(ui, &pIMMDevice);
    if (FAILED(hr)) {
		// error
		continue;
	}
    
    if (!pIMMDevice) {
		// error
		continue;
	}
    
    // 디바이스 명
    TCHAR* pszID = NULL;
	hr = pIMMDevice->GetId(&pszID);
	if (FAILED(hr)) {
		// error
		continue;
	}
    
    // 찾는 장치면
    if( !_tcscmp(장치이름, pszID)) {
     	// 해당 마이크에서 오디오 캡쳐 인터페이스를 활성화
    	CComPtr<IAudioEndpointVolume> m_pIAEV = NULL;
        hr = pIMMDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, reinterpret_cast<void **>(&m_pIAEV));
		if (FAILED(hr)) {
			// error
			continue;
		}

		if (!m_pIAEV) {
			// error
			continue;
		}
		
        // 오디오 상태 변화(볼륨값, Mute정보 등)를 가져오기 위해 등록
        // ** IAudioEndpointVolumeCallback 인터페이스를 구현해야 한다. **
		hr = m_pIAEV->RegisterControlChangeNotify(this);
		if (FAILED(hr)) {
			// error
		}
        
        // get 볼
        float fLevel = 0.0f;
		hr = m_pIAEV->GetMasterVolumeLevelScalar(&fLevel);
		if (FAILED(hr)) {
			// error
		}
		UINT uiVolume = (UINT)(fLevel * (FLOAT)100);
		
		// get Mute
		hr = m_pIAEV->GetMute(&m_bMute);
		if (FAILED(hr)) {
			// error
		}
        
        // set 볼륨
        if (m_uiVolume > 100) m_uiVolume = 100;
		float fLevel = m_uiVolume ? (float)m_uiVolume / (float)100 : (float)0;
		HRESULT hr = m_pIAEV->SetMasterVolumeLevelScalar(fLevel, &m_guidEventContext);
		if (FAILED(hr)) {
			// error
		}
        
        // set Mute
        HRESULT hr = m_pIAEV->SetMute(m_bMute, &m_guidEventContext);
		if (FAILED(hr)) {
			// error
		}
    }
}

볼륨값, mute 정보를 설정할 때 m_guidEventContext (GUID) 값을 매개변수로 넣는데 이는 IAudioEndpointVolumeCallback 인터페이스를 통해 변경된 볼륨값, mute정보가 넘어올 때 같이 전달되어 어디에서 변경했는지를 구분하는데 쓰인다.

 

IAudioEndpointVolumeCallback  인터페이스 (Callback)함수를 구현한 예제이다.

HRESULT CCoreAudioVolume::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify)
{
	if (!pNotify) {
		// error
		return E_FAIL;
	}
    
    // guid 비교 => 내부에서 변경한 건 거르기 위해
	if (!IsEqualGUID(pNotify->guidEventContext, m_guidEventContext) &&
		!IsEqualGUID(pNotify->guidEventContext, GUID_NULL)) { 
        
        // get 볼륨 & Mute 정보
		UINT uiVolume = (UINT)(pNotify->fMasterVolume * (FLOAT)100);
		m_uiVolume = uiVolume > 100 ? 100 : uiVolume;
		m_bMute = pNotify->bMuted;
	}

	//
	return S_OK;
}

IAudioEndpointVolumeCallback 인터페이스 구현을 위해 CCoreAudioVolume 클래스를 사용하였고 예제에는 나와있지 않지만 CCoreAudioVolume클래스는 IAudioEndpointVolumeCallback를 public 상속한다.

 

GUID 초기화 하고 COM 라이브러리를 해제한다.

m_guidEventContext = GUID_NULL;
CoUninitialize();