mirror of
https://github.com/reactos/reactos.git
synced 2024-11-01 12:26:32 +00:00
9393fc320e
Excluded: 3rd-party code (incl. wine) and most of the win32ss.
496 lines
12 KiB
C
496 lines
12 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Configuration of network devices
|
|
* FILE: dll/directx/dsound_new/devicelist.c
|
|
* PURPOSE: Enumeration of audio devices
|
|
*
|
|
* PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
ULONG
|
|
GetPinIdFromFilter(
|
|
LPFILTERINFO Filter,
|
|
BOOL bCapture,
|
|
ULONG Offset)
|
|
{
|
|
ULONG Index;
|
|
|
|
for(Index = Offset; Index < Filter->PinCount; Index++)
|
|
{
|
|
if (Filter->Pin[Index] == PIN_TYPE_PLAYBACK && !bCapture)
|
|
return Index;
|
|
|
|
if (Filter->Pin[Index] == PIN_TYPE_RECORDING && bCapture)
|
|
return Index;
|
|
}
|
|
return ULONG_MAX;
|
|
}
|
|
|
|
|
|
DWORD
|
|
OpenDeviceList(
|
|
IN LPGUID InterfaceGuid,
|
|
OUT HDEVINFO * OutHandle)
|
|
{
|
|
HDEVINFO DeviceHandle;
|
|
|
|
DeviceHandle = SetupDiGetClassDevs(InterfaceGuid,
|
|
NULL,
|
|
NULL,
|
|
DIGCF_DEVICEINTERFACE); //DIGCF_PRESENT
|
|
|
|
/* check for success */
|
|
if (DeviceHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
/* failed to create device list */
|
|
return GetLastError();
|
|
}
|
|
|
|
/* store result */
|
|
*OutHandle = DeviceHandle;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
BOOL
|
|
CloseDeviceList(
|
|
HDEVINFO Handle)
|
|
{
|
|
return SetupDiDestroyDeviceInfoList(Handle);
|
|
}
|
|
|
|
BOOL
|
|
GetDeviceListInterfaces(
|
|
HDEVINFO DeviceHandle,
|
|
IN LPGUID InterfaceGuid,
|
|
LPFILTERINFO *OutPath)
|
|
{
|
|
ULONG Length, Index = 0;
|
|
SP_DEVICE_INTERFACE_DATA InterfaceData;
|
|
PSP_DEVICE_INTERFACE_DETAIL_DATA_W DetailData;
|
|
SP_DEVINFO_DATA DeviceData;
|
|
LPFILTERINFO LastDevice = NULL, RootDevice = NULL, CurDevice;
|
|
BOOL Result;
|
|
|
|
|
|
do
|
|
{
|
|
InterfaceData.cbSize = sizeof(InterfaceData);
|
|
InterfaceData.Reserved = 0;
|
|
|
|
/* query device interface */
|
|
Result = SetupDiEnumDeviceInterfaces(DeviceHandle,
|
|
NULL,
|
|
InterfaceGuid,
|
|
Index,
|
|
&InterfaceData);
|
|
|
|
if (!Result)
|
|
{
|
|
/* failed */
|
|
DPRINT("SetupDiEnumDeviceInterfaces Index %u failed with %lx\n", Index, GetLastError());
|
|
break;
|
|
}
|
|
|
|
/* allocate device interface struct */
|
|
Length = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR);
|
|
DetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA_W)HeapAlloc(GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
Length);
|
|
|
|
if (!DetailData)
|
|
{
|
|
/* insufficient memory */
|
|
break;
|
|
}
|
|
|
|
/* initialize device interface detail struct */
|
|
DetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W);
|
|
|
|
DeviceData.cbSize = sizeof(DeviceData);
|
|
DeviceData.Reserved = 0;
|
|
|
|
Result = SetupDiGetDeviceInterfaceDetailW(DeviceHandle,
|
|
&InterfaceData,
|
|
DetailData,
|
|
Length,
|
|
NULL,
|
|
&DeviceData);
|
|
|
|
if (!Result)
|
|
{
|
|
/* failed */
|
|
DPRINT("SetupDiGetDeviceInterfaceDetail failed with %x\n", GetLastError());
|
|
HeapFree(GetProcessHeap(), 0, DetailData);
|
|
|
|
break;
|
|
}
|
|
|
|
/* allocate device path struct */
|
|
CurDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILTERINFO));
|
|
if (!CurDevice)
|
|
{
|
|
/* no memory */
|
|
HeapFree(GetProcessHeap(), 0, DetailData);
|
|
break;
|
|
}
|
|
|
|
/* store device path */
|
|
CopyMemory(&CurDevice->DeviceData, &DeviceData, sizeof(SP_DEVINFO_DATA));
|
|
wcscpy(CurDevice->DevicePath, DetailData->DevicePath);
|
|
CurDevice->MappedId[0] = ULONG_MAX;
|
|
CurDevice->MappedId[1] = ULONG_MAX;
|
|
|
|
DPRINT("DevicePath %S\n", CurDevice->DevicePath);
|
|
|
|
if (!RootDevice)
|
|
RootDevice = CurDevice;
|
|
|
|
if (LastDevice)
|
|
{
|
|
LastDevice->lpNext = CurDevice;
|
|
}
|
|
|
|
/* set as last device */
|
|
LastDevice = CurDevice;
|
|
|
|
/* free device interface struct */
|
|
HeapFree(GetProcessHeap(), 0, DetailData);
|
|
|
|
/* increment device interface index */
|
|
Index++;
|
|
}while(TRUE);
|
|
|
|
/* store result */
|
|
*OutPath = RootDevice;
|
|
|
|
if (!RootDevice)
|
|
return FALSE;
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD
|
|
OpenDeviceKey(
|
|
HDEVINFO Handle,
|
|
PSP_DEVINFO_DATA FILTERINFOData,
|
|
DWORD KeyType,
|
|
REGSAM DesiredAccess,
|
|
OUT HKEY * OutKey)
|
|
{
|
|
HKEY hKey;
|
|
|
|
/* try open device registry key */
|
|
hKey = SetupDiOpenDevRegKey(Handle, FILTERINFOData, DICS_FLAG_CONFIGSPECIFIC, 0, KeyType, DesiredAccess);
|
|
|
|
if (hKey == INVALID_HANDLE_VALUE)
|
|
return GetLastError();
|
|
|
|
/* store result */
|
|
*OutKey = hKey;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
FindAudioFilterPins(
|
|
LPFILTERINFO CurInfo,
|
|
OUT PULONG WaveInPins,
|
|
OUT PULONG WaveOutPins)
|
|
{
|
|
ULONG Index;
|
|
KSPIN_COMMUNICATION Communication;
|
|
KSPIN_DATAFLOW DataFlow;
|
|
|
|
*WaveInPins = 0;
|
|
*WaveOutPins = 0;
|
|
|
|
/* traverse all pins */
|
|
for(Index = 0; Index < CurInfo->PinCount; Index++)
|
|
{
|
|
if (GetFilterPinCommunication(CurInfo->hFilter, Index, &Communication) == ERROR_SUCCESS &&
|
|
GetFilterPinDataFlow(CurInfo->hFilter, Index, &DataFlow) == ERROR_SUCCESS)
|
|
{
|
|
if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_IN)
|
|
{
|
|
/* found a wave out device */
|
|
CurInfo->Pin[Index] = PIN_TYPE_PLAYBACK;
|
|
(*WaveOutPins)++;
|
|
}
|
|
else if (Communication == KSPIN_COMMUNICATION_SINK && DataFlow == KSPIN_DATAFLOW_OUT)
|
|
{
|
|
/* found a wave in device */
|
|
CurInfo->Pin[Index] = PIN_TYPE_RECORDING;
|
|
(*WaveInPins)++;
|
|
}
|
|
else
|
|
{
|
|
/* bridge pin / topology pin etc */
|
|
CurInfo->Pin[Index] = PIN_TYPE_NONE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* bridge pin / topology pin etc */
|
|
CurInfo->Pin[Index] = PIN_TYPE_NONE;
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
FindWinMMDeviceIndex(
|
|
LPFILTERINFO CurInfo,
|
|
BOOL bRecord)
|
|
{
|
|
ULONG DeviceCount, Index;
|
|
WCHAR Buffer[MAX_PATH];
|
|
DWORD Size, dwResult;
|
|
|
|
if (bRecord)
|
|
DeviceCount = waveInGetNumDevs();
|
|
else
|
|
DeviceCount = waveOutGetNumDevs();
|
|
|
|
/* sanity check */
|
|
//ASSERT(DeviceCount);
|
|
|
|
for(Index = 0; Index < DeviceCount; Index++)
|
|
{
|
|
Size = 0;
|
|
|
|
/* query device interface size */
|
|
if (bRecord)
|
|
dwResult = waveInMessage(UlongToHandle(Index), DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&Size, 0);
|
|
else
|
|
dwResult = waveOutMessage(UlongToHandle(Index), DRV_QUERYDEVICEINTERFACESIZE, (DWORD_PTR)&Size, 0);
|
|
|
|
if (dwResult != MMSYSERR_NOERROR)
|
|
{
|
|
DPRINT("Failed DRV_QUERYDEVICEINTERFACESIZE with %lx bRecord %u Index %u\n", dwResult, bRecord, Index);
|
|
continue;
|
|
}
|
|
|
|
/* sanity check */
|
|
ASSERT(Size < MAX_PATH);
|
|
|
|
/* now get the device interface string */
|
|
if (bRecord)
|
|
dwResult = waveInMessage(UlongToHandle(Index), DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)Buffer, MAX_PATH);
|
|
else
|
|
dwResult = waveOutMessage(UlongToHandle(Index), DRV_QUERYDEVICEINTERFACE, (DWORD_PTR)Buffer, MAX_PATH);
|
|
|
|
if (dwResult != MMSYSERR_NOERROR)
|
|
{
|
|
DPRINT("Failed DRV_QUERYDEVICEINTERFACE with %lx bRecord %u Index %u\n", dwResult, bRecord, Index);
|
|
continue;
|
|
}
|
|
|
|
if (!wcsicmp(CurInfo->DevicePath, Buffer))
|
|
{
|
|
if (bRecord)
|
|
CurInfo->MappedId[0] = Index;
|
|
else
|
|
CurInfo->MappedId[1] = Index;
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
DPRINT1("Failed to find device %ws bRecord %u Count %u\n", CurInfo->DevicePath, bRecord, DeviceCount);
|
|
|
|
// HACK
|
|
if (bRecord)
|
|
CurInfo->MappedId[0] = 0;
|
|
else
|
|
CurInfo->MappedId[1] = 0;
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
HRESULT
|
|
EnumerateAudioFilter(
|
|
LPFILTERINFO CurInfo,
|
|
OUT PULONG WaveInCount,
|
|
OUT PULONG WaveOutCount)
|
|
{
|
|
DWORD Status;
|
|
ULONG PinCount, WaveInPins, WaveOutPins;
|
|
|
|
/* first step open filter */
|
|
Status = OpenFilter((LPCWSTR)CurInfo->DevicePath, &CurInfo->hFilter);
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("Failed to open filter with %lx Path %ws\n", Status, CurInfo->DevicePath);
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* get filter pin count */
|
|
Status = GetFilterPinCount(CurInfo->hFilter, &PinCount);
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
DPRINT("Failed to get pin count with %lx\n", Status);
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* sanity check */
|
|
ASSERT(PinCount);
|
|
|
|
/* store pin count */
|
|
CurInfo->PinCount = PinCount;
|
|
|
|
/* now allocate an pin array */
|
|
CurInfo->Pin = HeapAlloc(GetProcessHeap(), 0, PinCount * sizeof(ULONG));
|
|
if (!CurInfo->Pin)
|
|
{
|
|
/* no memory */
|
|
return E_FAIL;
|
|
}
|
|
|
|
/* no try to find playback / recording pins */
|
|
FindAudioFilterPins(CurInfo, &WaveInPins, &WaveOutPins);
|
|
|
|
DPRINT("WaveInPins %u WaveOutPins %u %S\n", WaveInPins, WaveOutPins, CurInfo->DevicePath);
|
|
|
|
if (WaveOutPins)
|
|
{
|
|
/* create a unique guid for this playback device */
|
|
if (FindWinMMDeviceIndex(CurInfo, TRUE))
|
|
{
|
|
(*WaveOutCount)++;
|
|
INIT_GUID(CurInfo->DeviceGuid[0], 0xbd6dd71a, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + *WaveInCount);
|
|
}
|
|
}
|
|
|
|
|
|
if (WaveInPins)
|
|
{
|
|
if (FindWinMMDeviceIndex(CurInfo, FALSE))
|
|
{
|
|
/* create a unique guid for this record device */
|
|
(*WaveInCount)++;
|
|
INIT_GUID(CurInfo->DeviceGuid[1], 0xbd6dd71b, 0x3deb, 0x11d1, 0xb1, 0x71, 0x00, 0xc0, 0x4f, 0xc2, 0x00, 0x00 + *WaveOutCount);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT
|
|
EnumAudioDeviceInterfaces(
|
|
LPFILTERINFO *OutRootInfo)
|
|
{
|
|
HDEVINFO hList;
|
|
DWORD Status;
|
|
HRESULT hResult;
|
|
ULONG WaveOutCount, WaveInCount;
|
|
GUID AudioDeviceGuid = {STATIC_KSCATEGORY_AUDIO};
|
|
LPFILTERINFO CurInfo;
|
|
|
|
/* try open the device list */
|
|
Status = OpenDeviceList(&AudioDeviceGuid, &hList);
|
|
|
|
if (Status != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("OpenDeviceList failed with %lx\n", Status);
|
|
return E_FAIL;
|
|
}
|
|
|
|
if (!GetDeviceListInterfaces(hList, &AudioDeviceGuid, OutRootInfo))
|
|
{
|
|
DPRINT1("No devices found\n");
|
|
CloseDeviceList(hList);
|
|
return S_FALSE;
|
|
}
|
|
|
|
/* sanity check */
|
|
ASSERT(*OutRootInfo);
|
|
|
|
CurInfo = *OutRootInfo;
|
|
|
|
WaveOutCount = 0;
|
|
WaveInCount = 0;
|
|
|
|
/* now check all audio filters */
|
|
while(CurInfo)
|
|
{
|
|
/* now check details of the audio filter */
|
|
hResult = EnumerateAudioFilter(CurInfo, &WaveInCount, &WaveOutCount);
|
|
|
|
if (hResult != S_OK)
|
|
{
|
|
DPRINT1("EnumerateAudioFilter failed with %lx\n", Status);
|
|
break;
|
|
}
|
|
|
|
/* move to next filter */
|
|
CurInfo = CurInfo->lpNext;
|
|
}
|
|
|
|
/* close device list */
|
|
CloseDeviceList(hList);
|
|
|
|
/* done */
|
|
return hResult;
|
|
}
|
|
|
|
BOOL
|
|
FindDeviceByMappedId(
|
|
IN ULONG DeviceID,
|
|
LPFILTERINFO *Filter,
|
|
BOOL bPlayback)
|
|
{
|
|
LPFILTERINFO CurInfo;
|
|
if (!RootInfo)
|
|
return FALSE;
|
|
|
|
/* get first entry */
|
|
CurInfo = RootInfo;
|
|
|
|
while(CurInfo)
|
|
{
|
|
if ((bPlayback && CurInfo->MappedId[1] == DeviceID) ||
|
|
(!bPlayback && CurInfo->MappedId[0] == DeviceID))
|
|
{
|
|
/* found filter */
|
|
*Filter = CurInfo;
|
|
return TRUE;
|
|
}
|
|
|
|
CurInfo = CurInfo->lpNext;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL
|
|
FindDeviceByGuid(
|
|
LPCGUID pGuidSrc,
|
|
LPFILTERINFO *Filter)
|
|
{
|
|
LPFILTERINFO CurInfo;
|
|
if (!RootInfo)
|
|
return FALSE;
|
|
|
|
/* get first entry */
|
|
CurInfo = RootInfo;
|
|
|
|
while(CurInfo)
|
|
{
|
|
if (IsEqualGUID(&CurInfo->DeviceGuid[0], pGuidSrc) ||
|
|
IsEqualGUID(&CurInfo->DeviceGuid[1], pGuidSrc))
|
|
{
|
|
/* found filter */
|
|
*Filter = CurInfo;
|
|
return TRUE;
|
|
}
|
|
|
|
CurInfo = CurInfo->lpNext;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|