従来の Windows マルチメディア アプリケーションのデバイス ロール

Note

MMDevice API では、デバイス ロールがサポートされます。 ただし、Windows Vista のユーザー インターフェイスでは、この機能のサポートは実装されていません。 デバイス ロールのユーザー インターフェイスのサポートは、今後のバージョンの Windows で実装される可能性があります。 詳しくは、「Windows Vista のデバイス ロール」をご覧ください。

 

従来の Windows マルチメディア waveOutXxx 関数と waveInXxx 関数には、ユーザーが特定のデバイス ロールに割り当てたオーディオ エンドポイント デバイスをアプリケーションが選択する手段が用意されていません。 ただし、Windows Vista では、コア オーディオ API を Windows マルチメディア アプリケーションと組み合わせて使用し、デバイスの役割に基づいてデバイスを選択できます。 たとえば、MMDevice API を利用することにより、waveOutXxx アプリケーションは、ロールに割り当てられているオーディオ エンドポイント デバイスを識別して、対応する波形出力デバイスを識別し、waveOutOpen 関数を呼び出してデバイスのインスタンスを開くことができます。 waveOutXxxwaveInXxx について詳しくは、Windows SDK のドキュメントをご覧ください。

次のコード例は、特定のデバイス ロールに割り当てられているレンダリング エンドポイント デバイスの波形デバイス ID を取得する方法を示しています。

//-----------------------------------------------------------
// This function gets the waveOut ID of the audio endpoint
// device that is currently assigned to the specified device
// role. The caller can use the waveOut ID to open the
// waveOut device that corresponds to the endpoint device.
//-----------------------------------------------------------
#define EXIT_ON_ERROR(hres)  \
              if (FAILED(hres)) { goto Exit; }
#define SAFE_RELEASE(punk)  \
              if ((punk) != NULL)  \
                { (punk)->Release(); (punk) = NULL; }

HRESULT GetWaveOutId(ERole role, int *pWaveOutId)
{
    HRESULT hr;
    IMMDeviceEnumerator *pEnumerator = NULL;
    IMMDevice *pDevice = NULL;
    WCHAR *pstrEndpointIdKey = NULL;
    WCHAR *pstrEndpointId = NULL;

    if (pWaveOutId == NULL)
    {
        return E_POINTER;
    }

    // Create an audio endpoint device enumerator.
    hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
                          NULL, CLSCTX_INPROC_SERVER,
                          __uuidof(IMMDeviceEnumerator),
                          (void**)&pEnumerator);
    EXIT_ON_ERROR(hr)

    // Get the audio endpoint device that the user has
    // assigned to the specified device role.
    hr = pEnumerator->GetDefaultAudioEndpoint(eRender, role,
                                              &pDevice);
    EXIT_ON_ERROR(hr)

    // Get the endpoint ID string of the audio endpoint device.
    hr = pDevice->GetId(&pstrEndpointIdKey);
    EXIT_ON_ERROR(hr)

    // Get the size of the endpoint ID string.
    size_t  cbEndpointIdKey;

    hr = StringCbLength(pstrEndpointIdKey,
                        STRSAFE_MAX_CCH * sizeof(WCHAR),
                        &cbEndpointIdKey);
    EXIT_ON_ERROR(hr)

    // Include terminating null in string size.
    cbEndpointIdKey += sizeof(WCHAR);

    // Allocate a buffer for a second string of the same size.
    pstrEndpointId = (WCHAR*)CoTaskMemAlloc(cbEndpointIdKey);
    if (pstrEndpointId == NULL)
    {
        EXIT_ON_ERROR(hr = E_OUTOFMEMORY)
    }

    // Each for-loop iteration below compares the endpoint ID
    // string of the audio endpoint device to the endpoint ID
    // string of an enumerated waveOut device. If the strings
    // match, then we've found the waveOut device that is
    // assigned to the specified device role.
    int waveOutId;
    int cWaveOutDevices = waveOutGetNumDevs();

    for (waveOutId = 0; waveOutId < cWaveOutDevices; waveOutId++)
    {
        MMRESULT mmr;
        size_t cbEndpointId;

        // Get the size (including the terminating null) of
        // the endpoint ID string of the waveOut device.
        mmr = waveOutMessage((HWAVEOUT)IntToPtr(waveOutId),
                             DRV_QUERYFUNCTIONINSTANCEIDSIZE,
                             (DWORD_PTR)&cbEndpointId, NULL);
        if (mmr != MMSYSERR_NOERROR ||
            cbEndpointIdKey != cbEndpointId)  // do sizes match?
        {
            continue;  // not a matching device
        }

        // Get the endpoint ID string for this waveOut device.
        mmr = waveOutMessage((HWAVEOUT)IntToPtr(waveOutId),
                             DRV_QUERYFUNCTIONINSTANCEID,
                             (DWORD_PTR)pstrEndpointId,
                             cbEndpointId);
        if (mmr != MMSYSERR_NOERROR)
        {
            continue;
        }

        // Check whether the endpoint ID string of this waveOut
        // device matches that of the audio endpoint device.
        if (lstrcmpi(pstrEndpointId, pstrEndpointIdKey) == 0)
        {
            *pWaveOutId = waveOutId;  // found match
            hr = S_OK;
            break;
        }
    }

    if (waveOutId == cWaveOutDevices)
    {
        // We reached the end of the for-loop above without
        // finding a waveOut device with a matching endpoint
        // ID string. This behavior is quite unexpected.
        hr = E_UNEXPECTED;
    }

Exit:
    SAFE_RELEASE(pEnumerator);
    SAFE_RELEASE(pDevice);
    CoTaskMemFree(pstrEndpointIdKey);  // NULL pointer okay
    CoTaskMemFree(pstrEndpointId);
    return hr;
}

前のコード例では、GetWaveOutId 関数は、デバイス ロール (eConsole、eMultimedia、または eCommunications) を入力パラメーターとして受け入れます。 2 番目のパラメーターは、指定されたロールに割り当てられている波形出力デバイスの波形デバイス ID を関数が書き込むポインターです。 その後、アプリケーションはこの ID で waveOutOpen を呼び出し、デバイスを開くことができます。

前のコード例のメイン ループには、waveOutMessage 関数の 2 つの呼び出しが含まれています。 最初の呼び出しでは、waveOutId パラメーターによって識別される波形デバイスのエンドポイント ID 文字列のサイズ (バイト単位) を取得するDRV_QUERYFUNCTIONINSTANCEIDSIZE メッセージが送信されます。 (エンドポイント ID 文字列は、波形デバイスの抽象化の基になるオーディオ エンドポイント デバイスを識別します)。この呼び出しによって報告されるサイズには、文字列の末尾にある終端の null 文字の領域が含まれています。 プログラムは、サイズ情報を使用して、エンドポイント ID 文字列全体を格納するのに十分な大きさのバッファーを割り当てることができます。

waveOutMessage の 2 番目の呼び出しは、波形出力デバイスのデバイス ID 文字列を取得する DRV_QUERYFUNCTIONINSTANCEID メッセージを送信します。 コード例では、この文字列を、指定されたデバイス ロールを持つオーディオ エンドポイント デバイスのデバイス ID 文字列と比較します。 文字列が一致する場合、関数は、パラメーター pWaveOutId が指す場所に波形デバイス ID を書き込みます。 呼び出し元はこの ID を使用し、指定されたデバイス ロールを持つ波形出力デバイスを開くことができます。

Windows Vista では、DRV_QUERYFUNCTIONINSTANCEIDSIZE メッセージと DRV_QUERYFUNCTIONINSTANCEID メッセージがサポートされます。 Windows Server 2003、Windows XP、Windows 2000 など、以前のバージョンの Windows ではサポートされません。

前のコード例の関数は、レンダリング デバイスの波形デバイス ID を取得しますが、いくつかの変更を加えて、キャプチャ デバイスの波形デバイス ID を取得するよう調整できます。 その後、アプリケーションはこの ID で waveInOpen を呼び出し、デバイスを開くことができます。 前のコード例を変更して、特定のロールに割り当てられているオーディオ キャプチャ エンドポイント デバイスの波形デバイス ID を取得するには、次の操作を実行します。

  • 前の例のすべての waveOutXxx 関数呼び出しを、対応する waveInXxx 関数呼び出しに置き換えます。
  • ハンドルの種類 HWAVEOUT を HWAVEIN に変更します。
  • ERole 列挙定数 eRender を eCapture に置き換えます。

Windows Vista では、waveOutOpen 関数と waveInOpen 関数は、作成したオーディオ ストリームを必ず既定のセッション (セッション GUID 値 GUID_NULL により識別されるプロセス固有のセッション) に割り当てます。

レガシ オーディオ API との相互運用性