PCに接続されているマイク(オーディオデバイス)を取得し、音量設定をする(EnumAudioEndpoints)(C++版)

もくじ
https://tera1707.com/entry/2022/02/06/144447

やりたいこと

オーディオのデバイスを列挙して、それらの情報を取りたい。

やったこと

MMDeviceEnumeratorEnumAudioEndpoints()を使う。

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)

https://learn.microsoft.com/ja-jp/windows/win32/api/mmdeviceapi/nf-mmdeviceapi-immdeviceenumerator-enumaudioendpoints

色々参考になるコードを挙げてくださっているページ。わかりやすい。

http://yamatyuu.net/computer/program/vc2013/mute/index.html http://yamatyuu.net/computer/program/vc2013/vollist/index.html