舊版 Windows 多媒體應用程式的裝置角色

注意

MMDevice API 支援裝置角色。 不過,Windows Vista 中的使用者介面不會實作此功能的支援。 未來版本的 Windows 可能會實作裝置角色的使用者介面支援。 如需詳細資訊,請參閱 Windows Vista 中的裝置角色。

 

舊版 Windows 多媒體 waveOutXxx 和 waveInXxx 函式無法讓應用程式選取使用者指派給特定裝置角色的音訊端點裝置。 不過,在 Windows Vista 中,核心音訊 API 可以與 Windows 多媒體應用程式搭配使用,以根據裝置角色啟用裝置選取。 例如,在MMDevice API的説明下,waveOutXxx 應用程式可以識別指派給角色的音訊端點裝置、識別對應的波浪輸出裝置,以及呼叫 waveOutOpen 函式來開啟裝置的實例。 如需 waveOutXxxwaveInXxx 的詳細資訊,請參閱 Windows SDK 檔。

下列程式代碼範例示範如何取得指派給特定裝置角色之轉譯端點裝置的超聲波裝置標識碼:

//-----------------------------------------------------------
// 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)作為輸入參數。 第二個參數是指針,函式會針對指派給指定角色的電壓輸出裝置寫入電壓裝置標識符。 然後,應用程式可以使用此標識符呼叫 waveOutOpen 以開啟裝置。

上述程式代碼範例中的main迴圈包含對 waveOutMessage 函式的兩個呼叫。 第一次呼叫會傳送DRV_QUERYFUNCTIONINSTANCEIDSIZE訊息,以位元組為單位擷取 waveOutId 參數所識別之波浪裝置端點標識符字串的大小。 (端點標識符字串會識別低於電壓裝置抽象的音訊端點裝置。這個呼叫所報告的大小包含字串結尾終止 Null 字元的空間。 程式可以使用大小資訊來配置足以包含整個端點標識符字串的緩衝區。

第二次呼叫 waveOutMessage 會傳送DRV_QUERYFUNCTIONINSTANCEID訊息,以擷取波浪輸出裝置的裝置標識符字串。 此範例程式代碼會將此字串與音訊端點裝置的裝置標識符字串與指定的裝置角色進行比較。 如果字串相符,則函式會將波浪裝置標識碼寫入參數 pWaveOutId 所指向的位置。 呼叫端可以使用這個標識碼來開啟具有指定裝置角色的電壓輸出裝置。

Windows Vista 支援DRV_QUERYFUNCTIONINSTANCEIDSIZE和DRV_QUERYFUNCTIONINSTANCEID訊息。 舊版 Windows 不支持它們,包括 Windows Server 2003、Windows XP 和 Windows 2000。

上述程式代碼範例中的 函式會取得轉譯裝置的超聲波裝置標識碼,但只要進行一些修改,就可以調整它來取得擷取裝置的超聲波裝置標識碼。 然後,應用程式可以使用此標識符呼叫 waveInOpen 來開啟裝置。 若要變更上述程式代碼範例,以取得指派給特定角色之音訊擷取端點裝置的超聲波裝置識別碼,請執行下列動作:

  • 將上述範例中的所有 waveOutXxx 函式呼叫取代為對應的 waveInXxx 函數調用。
  • 將句柄類型 HWAVEOUT 變更為 HWAVEIN。
  • 將 ERole 列舉常數 eRender 取代為 eCapture。

在 Windows Vista 中 ,waveOutOpenwaveInOpen 函式一律會將它們建立的音訊串流指派給預設工作階段—會話 GUID 值所識別的程式特定會話GUID_NULL。

與舊版音訊 API 的互操作性