Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- Close
- http
- window
- GO 언어
- File
- Sync
- 리뷰
- Python
- package
- windows
- channel
- FOR
- Callback
- c++
- install
- json
- 책
- range
- mutex
- Golang
- tcp
- write
- go
- C
- go언어
- API
- bitcoin
- JavaScript
- Linux
- 영화
Archives
- Today
- Total
Code Habit
[C++] Master Volume 제어 본문
윈도우 녹음(마이크)장치에 연결하여 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();