今使っているスピーカー(デフォルトスピーカー)の情報を取る

もくじ
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++のこういう部分が理解不足だったりする、、、(たぶんこうしたら治るだろう、ちゃんと見えるようにできるだろう、はあるが、めんどくさくて端折ってしまう)

参考

以前の記事
つながっているマイク・スピーカーを全部列挙する

https://tera1707.com/entry/2023/11/21/213253