Роли устройств для устаревших приложений Мультимедиа Windows
Примечание.
API MMDevice поддерживает роли устройств. Однако пользовательский интерфейс в Windows Vista не реализует поддержку этой функции. Поддержка пользовательского интерфейса для ролей устройств может быть реализована в будущей версии Windows. Дополнительные сведения см. в статье "Роли устройств" в Windows Vista.
Устаревшие функции Windows мультимедиа waveOutXx и waveInXxx не позволяют приложению выбрать устройство аудио конечной точки, назначенное пользователю определенной роли устройства. Однако в Windows Vista основные API аудио можно использовать в сочетании с мультимедийным приложением Windows для включения выбора устройств на основе роли устройства. Например, с помощью API MMDevice приложение waveOutXxx может определить устройство конечной точки звука, назначенное роли, определить соответствующее устройство вывода волн и вызвать функцию waveOutOpen, чтобы открыть экземпляр устройства. Дополнительные сведения о waveOutXxx и waveInXxx см. в документации по пакету SDK для Windows.
В следующем примере кода показано, как получить идентификатор устройства волны для устройства отрисовки конечной точки, назначенной определенной роли устройства:
//-----------------------------------------------------------
// 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 с этим идентификатором, чтобы открыть устройство.
Основной цикл в предыдущем примере кода содержит два вызова функции 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 функции waveOutOpen и waveInOpen всегда назначают звуковые потоки, создаваемые сеансом по умолчанию, — сеанс, определенный по значению GUID сеанса, GUID_NULL.
См. также