もくじ
https://tera1707.com/entry/2022/02/06/144447
やりたいこと
オーディオのデバイスを列挙して、それらの情報を取りたい。
やったこと
MMDeviceEnumerator
のEnumAudioEndpoints()
を使う。
APIの説明
https://learn.microsoft.com/ja-jp/windows/win32/coreaudio/mmdevice-api
オーディオエンドポイントとは?の説明
https://learn.microsoft.com/ja-jp/windows/win32/coreaudio/audio-endpoint-devices
上記MSDocsページによると、このやり方はWindows Vista以降で可能なやり方とのこと。
それ以前はまた別のやり方があったらしい。(未検証)
前提
- VisualStudio2022
- C++17 使用
マイクを取得するサンプルコード
各APIに失敗したときのエラー処理と、エラー時のリソースの解放処理は割愛。
(本番では、hrを見てエラー判定して、そこまでのリソースの解放など、ちゃんとやること。)
#include <windows.h> #include <mmdeviceapi.h> #include <functiondiscoverykeys.h> #include <endpointvolume.h> #include <string> int main() { HRESULT hr; IMMDeviceEnumerator* pEnum = NULL; IMMDeviceCollection* pCollection = NULL; UINT deviceCount = 0; // COMの初期化(COMのお作法) hr = CoInitializeEx(0, COINIT_MULTITHREADED); // COMからMMDeviceEnumeratorを取ってくる hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, IID_PPV_ARGS(&pEnum)); // オーディオエンドポイントの列挙を実行 hr = pEnum->EnumAudioEndpoints(EDataFlow::eCapture, DEVICE_STATE_ACTIVE, &pCollection); // とれた数を数える hr = pCollection->GetCount(&deviceCount); for (int i = 0; i < deviceCount; i++) { // デバイスの情報を取る IMMDevice* pEndpoint = NULL; pCollection->Item(i, &pEndpoint); // デバイスのプロパティを取る IPropertyStore* pProperties; pEndpoint->OpenPropertyStore(STGM_READ, &pProperties); // 取ったプロパティから、値を指定して取得する PROPVARIANT vName; PropVariantInit(&vName); pProperties->GetValue(PKEY_Device_FriendlyName, &vName); // エンドポイントの情報を取る IAudioEndpointVolume* pAudioEndVol = NULL; hr = pEndpoint->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void**)&pAudioEndVol); // エンドポイントに指示を出す(「IAudioEndpointVolume」のVolumeは、マイクの怨霊という意味の「ボリューム」とは別の意味っぽい) float getVolume = 0.0f; pAudioEndVol->GetMasterVolumeLevelScalar(&getVolume); // 音量を取得 float setVolume = 0.25f; pAudioEndVol->SetMasterVolumeLevelScalar(setVolume, &GUID_NULL); // 音量を設定 std::wstring outString = std::to_wstring(i) + L":" + vName.pwszVal + std::to_wstring(getVolume) + L"\r\n"; OutputDebugString(outString.c_str()); // 後処理系 if (pAudioEndVol) pAudioEndVol->Release(); if (pProperties) pProperties->Release(); if (pEndpoint) pEndpoint->Release(); } // 後処理系 if (pCollection) pCollection->Release(); if (pEnum) pEnum->Release(); // COMの後処理(COMのお作法) CoUninitialize(); }
EnumAudioEndpoints の第二引数に渡す値(DEVICE_STATE_XXX)について
hr = pEnum->EnumAudioEndpoints(EDataFlow::eCapture, DEVICE_STATE_ACTIVE, &pCollection);
で渡しているDEVICE_STATE_ACTIVE
は、下記のような値を表す。
https://learn.microsoft.com/ja-jp/windows/win32/coreaudio/device-state-xxx-constants
これらの値について、マイクについて試した限りだが、
- DEVICE_STATE_ACTIVE だけにすると、
- ステレオミニプラグのヘッドセットについて、
- ヘッドセットをつなげると、そいつのマイクが取れるようになる。
- ヘッドセットを外すと、そいつのマイクが取れなくなる。
- USBヘッドセットについて、
- ヘッドセットをつなげると、そいつのマイクが取れるようになる。
- ヘッドセットを外すと、そいつのマイクが取れなくなる。
- ステレオミニプラグのヘッドセットについて、
- DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED にすると、
- ステレオミニプラグのヘッドセットについて、
- ヘッドセットをつなげると、そいつのマイクが取れるようになる。
- ヘッドセットを外しても、マイクは取れる。 ★これが「UnPlugged」ということか。
- USBヘッドセットについて、
- こちらは、DEVICE_STATE_ACTIVE だけのときと同じ。
- ステレオミニプラグのヘッドセットについて、
となった。試した限りは、「UnPlugged」は、ミニプラグのヘッドセットのためにあるように思う。(ほかにもあるとは思うが)
EnumAudioEndpoints の第一引数に渡す値(DEVICE_STATE_XXX)について
EDataFlow::eRender
を指定すると、スピーカーが取れる。
EDataFlow::eCapture
を指定すると、マイクが取れる。
備考
APIの説明
https://learn.microsoft.com/ja-jp/windows/win32/coreaudio/mmdevice-api
オーディオエンドポイントとは?の説明
https://learn.microsoft.com/ja-jp/windows/win32/coreaudio/audio-endpoint-devices
IMMDeviceEnumerator::EnumAudioEndpoints メソッド (mmdeviceapi.h)
色々参考になるコードを挙げてくださっているページ。わかりやすい。
http://yamatyuu.net/computer/program/vc2013/mute/index.html http://yamatyuu.net/computer/program/vc2013/vollist/index.html