もくじ
https://tera1707.com/entry/2022/02/06/144447#COM
やりたいこと
以前の記事で、つながっているマイク・スピーカーを全部列挙してデバイス名を出す、ということをしたが、今回は、複数のマイク・スピーカーが刺さっているときに、今使われているもの(実際に音が出たり集音したりするもの)の情報を取りたい。
用語的に、今使われているもののことを「デフォルトオーディオエンドポイント」とか「デフォルトデバイス」とか言うらしい。
デフォルトのマイクとか、デフォルトのデバイスとか言われたら、「今使ってるやつ」と思ったらよさそう。
実験コード
以前の記事とあまりやっていることは変わらないが、今回は下記のような流れでやった。
- MMDeviceEnumeratorのコクラスを取ってくる
- GetDefaultAudioEndpoint関数で、デフォルトエンドポイントを取ってくる ←★ここが追加したところ!
- そのMMDeviceのプロパティから、デバイス名などを取り出す
#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; IMMDevice* pEndpoint[8] = { NULL }; IPropertyStore* pProperties[8] = { NULL }; IAudioEndpointVolume* pAudioEndVol[8] = { NULL }; // COMの初期化(COMのお作法) hr = CoInitializeEx(0, COINIT_MULTITHREADED); // COMからMMDeviceEnumeratorを取ってくる hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, IID_PPV_ARGS(&pEnum)); while (1) { { // デフォルト(OSが現在使用している)オーディオエンドポイントを取る(今回はCapture(マイク)EP) IMMDevice* pDefEndpoint = NULL; hr = pEnum->GetDefaultAudioEndpoint(EDataFlow::eRender, ERole::eMultimedia, &pDefEndpoint); LPWSTR id = NULL; hr = pDefEndpoint->GetId(&id); // デバイスのプロパティを取る IPropertyStore* pDefProperties = { NULL }; pDefEndpoint->OpenPropertyStore(STGM_READ, &pDefProperties); // 取ったプロパティから、値を指定して取得する PROPVARIANT vDefName; PropVariantInit(&vDefName); pDefProperties->GetValue(PKEY_Device_FriendlyName, &vDefName); wprintf(L"default speaker Device\r\n"); wprintf(L"\r\n"); wprintf(L" %s\r\n", vDefName.bstrVal); wprintf(L" %s\r\n", id); } { // すべてのCaptureデバイスを列挙する wprintf(L"\r\n"); wprintf(L"List all render(speaker) Device.\r\n"); wprintf(L"\r\n"); // オーディオエンドポイントの列挙を実行 hr = pEnum->EnumAudioEndpoints(EDataFlow::eRender, DEVICE_STATE_ACTIVE, &pCollection); // とれた数を数える hr = pCollection->GetCount(&deviceCount); for (int i = 0; i < deviceCount; i++) { // デバイスの情報を取る pCollection->Item(i, &pEndpoint[i]); LPWSTR id = NULL; hr = pEndpoint[i]->GetId(&id); // デバイスのプロパティを取る pEndpoint[i]->OpenPropertyStore(STGM_READ, &pProperties[i]); // 取ったプロパティから、値を指定して取得する PROPVARIANT vName; PropVariantInit(&vName); pProperties[i]->GetValue(PKEY_Device_FriendlyName, &vName); // エンドポイントの情報を取る hr = pEndpoint[i]->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void**)&pAudioEndVol[i]); std::wstring outString = std::to_wstring(i) + L":" + vName.pwszVal; wprintf(L" %s\r\n", outString.c_str()); wprintf(L" %s\r\n", id); OutputDebugString(outString.c_str()); // 後処理系 if (pProperties) pProperties[i]->Release(); } } Sleep(1000); std::system("cls"); } // 後処理系 for (size_t i = 0; i < sizeof(pAudioEndVol) / sizeof(pAudioEndVol[0]); i++) { if (pAudioEndVol[i] != NULL) pAudioEndVol[i]->Release(); if (pEndpoint[i] != NULL) pEndpoint[i]->Release(); } if (pCollection) pCollection->Release(); if (pEnum) pEnum->Release(); // COMの後処理(COMのお作法) CoUninitialize(); }
※下半分はオマケで、全デバイスを列挙している。
このコードを実行しながら、イヤホンジャックにイヤホンを指したり、USBヘッドセットを指したりすると、今使われているデバイスが、デバイスを指すたびにパタパタ変わっていく。
こういう感じ。
※どうでもいいが、上図の「?????」となってる部分は、VSのウォッチで見ると「スピーカー」となっている。C++で、日本語をコンソールに出そうとすると、いっつもこうなる。地味に、C++のこういう部分が理解不足だったりする、、、(たぶんこうしたら治るだろう、ちゃんと見えるようにできるだろう、はあるが、めんどくさくて端折ってしまう)
参考
以前の記事
つながっているマイク・スピーカーを全部列挙する