MMRESULT WdmAudGetNumWdmDevsByLegacy( IN MMDEVICE_TYPE DeviceType, OUT DWORD* DeviceCount) { MMRESULT Result; WDMAUD_DEVICE_INFO DeviceInfo; VALIDATE_MMSYS_PARAMETER( KernelHandle != INVALID_HANDLE_VALUE ); VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) ); VALIDATE_MMSYS_PARAMETER( DeviceCount ); ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO)); DeviceInfo.DeviceType = DeviceType; Result = SyncOverlappedDeviceIoControl(KernelHandle, IOCTL_GETNUMDEVS_TYPE, (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), (LPVOID) &DeviceInfo, sizeof(WDMAUD_DEVICE_INFO), NULL); if ( ! MMSUCCESS( Result ) ) { SND_ERR(L"Call to IOCTL_GETNUMDEVS_TYPE failed\n"); *DeviceCount = 0; return TranslateInternalMmResult(Result); } *DeviceCount = DeviceInfo.DeviceCount; return MMSYSERR_NOERROR; }
/* Querying/setting the format of a wave device. Querying format support requires us to first open the device, whereas setting format is done on an already opened device. */ MMRESULT QueryNt4WaveDeviceFormatSupport( IN PSOUND_DEVICE SoundDevice, IN LPWAVEFORMATEX Format, IN DWORD FormatSize) { MMRESULT Result; HANDLE Handle; SND_TRACE(L"NT4 wave format support querying routine called\n"); VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) ); VALIDATE_MMSYS_PARAMETER( Format ); VALIDATE_MMSYS_PARAMETER( FormatSize >= sizeof(WAVEFORMATEX) ); /* Get the device path */ Result = OpenNt4KernelSoundDevice(SoundDevice, FALSE, &Handle); if ( ! MMSUCCESS(Result) ) { SND_ERR(L"Unable to open kernel sound device\n"); return TranslateInternalMmResult(Result); } Result = SyncOverlappedDeviceIoControl(Handle, IOCTL_WAVE_QUERY_FORMAT, (LPVOID) Format, FormatSize, NULL, 0, NULL); if ( ! MMSUCCESS(Result) ) { SND_ERR(L"Sync overlapped I/O failed - MMSYS_ERROR %d\n", Result); Result = TranslateInternalMmResult(Result); } CloseKernelSoundDevice(Handle); return MMSYSERR_NOERROR; }
/* Open the parameters key of a sound driver. NT4 only. */ MMRESULT OpenSoundDriverParametersRegKey( IN LPWSTR ServiceName, OUT PHKEY KeyHandle) { SIZE_T KeyLength; PWCHAR ParametersKeyName; VALIDATE_MMSYS_PARAMETER( ServiceName ); VALIDATE_MMSYS_PARAMETER( KeyHandle ); /* Work out how long the string will be */ KeyLength = wcslen(REG_SERVICES_KEY_NAME_U) + 1 + wcslen(ServiceName) + 1 + wcslen(REG_PARAMETERS_KEY_NAME_U); /* Allocate memory for the string */ ParametersKeyName = AllocateWideString(KeyLength); if ( ! ParametersKeyName ) return MMSYSERR_NOMEM; /* Construct the registry path */ wsprintf(ParametersKeyName, L"%s\\%s\\%s", REG_SERVICES_KEY_NAME_U, ServiceName, REG_PARAMETERS_KEY_NAME_U); SND_TRACE(L"Opening reg key: %wS\n", ParametersKeyName); /* Perform the open */ if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, ParametersKeyName, 0, KEY_READ, KeyHandle) != ERROR_SUCCESS ) { /* Couldn't open the key */ SND_ERR(L"Failed to open reg key: %wS\n", ParametersKeyName); FreeMemory(ParametersKeyName); return MMSYSERR_ERROR; } FreeMemory(ParametersKeyName); return MMSYSERR_NOERROR; }
/* Convenience routine for getting the path of a device and opening it. */ MMRESULT OpenNt4KernelSoundDevice( IN PSOUND_DEVICE SoundDevice, IN BOOLEAN ReadOnly, OUT PHANDLE Handle) { PWSTR Path; MMRESULT Result; VALIDATE_MMSYS_PARAMETER( IsValidSoundDevice(SoundDevice) ); VALIDATE_MMSYS_PARAMETER( Handle ); Result = GetSoundDeviceIdentifier(SoundDevice, (PVOID*) &Path); if ( ! MMSUCCESS(Result) ) { SND_ERR(L"Unable to get sound device path"); return TranslateInternalMmResult(Result); } SND_ASSERT( Path ); return OpenKernelSoundDeviceByName(Path, ReadOnly, Handle); }
MMRESULT CreateSoundThread( OUT PSOUND_THREAD* Thread) { MMRESULT Result; PSOUND_THREAD NewThread; VALIDATE_MMSYS_PARAMETER( Thread ); NewThread = AllocateStruct(SOUND_THREAD); if ( ! NewThread ) return MMSYSERR_NOMEM; /* Prepare the events we'll be using to sync. everything */ Result = CreateSoundThreadEvents(&NewThread->Events.Ready, &NewThread->Events.Request, &NewThread->Events.Done); if ( ! MMSUCCESS(Result) ) { FreeMemory(NewThread); return TranslateInternalMmResult(Result); } SND_TRACE(L"Creating a sound thread\n"); NewThread->Handle = CreateThread(NULL, 0, &SoundThreadMain, (LPVOID) NewThread, CREATE_SUSPENDED, NULL); /* Something went wrong, bail out! */ if ( NewThread->Handle == INVALID_HANDLE_VALUE ) { SND_ERR(L"Sound thread creation failed!\n"); DestroySoundThreadEvents(NewThread->Events.Ready, NewThread->Events.Request, NewThread->Events.Done); FreeMemory(NewThread); return Win32ErrorToMmResult(GetLastError()); } /* Wake the thread up */ if ( ResumeThread(NewThread->Handle) == -1 ) { SND_ERR(L"Failed to resume thread!\n"); CloseHandle(NewThread->Handle); DestroySoundThreadEvents(NewThread->Events.Ready, NewThread->Events.Request, NewThread->Events.Done); FreeMemory(NewThread); return Win32ErrorToMmResult(GetLastError()); } /* If all is well we can now give the thread to the caller */ *Thread = NewThread; return MMSYSERR_NOERROR; }
/* This is the "nice" way to discover audio devices in NT4 - go into the service registry key and enumerate the Parameters\Device*\Devices values. The value names represent the device name, whereas the data assigned to them identifies the type of device. */ MMRESULT EnumerateNt4ServiceSoundDevices( IN LPWSTR ServiceName, IN MMDEVICE_TYPE DeviceType, IN SOUND_DEVICE_DETECTED_PROC SoundDeviceDetectedProc) { HKEY Key; DWORD KeyIndex = 0; VALIDATE_MMSYS_PARAMETER( ServiceName ); /* Device type zero means "all" */ VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceType(DeviceType) || DeviceType == 0 ); while ( OpenSoundDeviceRegKey(ServiceName, KeyIndex, &Key) == MMSYSERR_NOERROR ) { HKEY DevicesKey; DWORD ValueType = REG_NONE, ValueIndex = 0; DWORD MaxNameLength = 0, ValueNameLength = 0; PWSTR DevicePath = NULL, ValueName = NULL; DWORD ValueDataLength = sizeof(DWORD); DWORD ValueData; if ( RegOpenKeyEx(Key, REG_DEVICES_KEY_NAME_U, 0, KEY_READ, &DevicesKey) == ERROR_SUCCESS ) { /* Find out how much memory is needed for the key name */ if ( RegQueryInfoKey(DevicesKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &MaxNameLength, NULL, NULL, NULL) != ERROR_SUCCESS ) { SND_ERR(L"Failed to query registry key information\n"); RegCloseKey(DevicesKey); RegCloseKey(Key); return MMSYSERR_ERROR; } DevicePath = AllocateWideString(MaxNameLength + strlen("\\\\.\\")); /* Check that the memory allocation was successful */ if ( ! DevicePath ) { /* There's no point in going further */ RegCloseKey(DevicesKey); RegCloseKey(Key); return MMSYSERR_NOMEM; } /* Insert the device path prefix */ wsprintf(DevicePath, L"\\\\.\\"); /* The offset of the string following this prefix */ ValueName = DevicePath + strlen("\\\\.\\"); /* Copy this so that it may be overwritten - include NULL */ ValueNameLength = MaxNameLength + sizeof(WCHAR); SND_TRACE(L"Interested in devices beginning with %wS\n", DevicePath); while ( RegEnumValue(DevicesKey, ValueIndex, ValueName, &ValueNameLength, NULL, &ValueType, (LPBYTE) &ValueData, &ValueDataLength) == ERROR_SUCCESS ) { /* Device types are stored as DWORDs */ if ( ( ValueType == REG_DWORD ) && ( ValueDataLength == sizeof(DWORD) ) ) { if ( ( DeviceType == 0 ) || ( DeviceType == ValueData ) ) { SND_TRACE(L"Found device: %wS\n", DevicePath); SoundDeviceDetectedProc(ValueData, DevicePath); } } /* Reset variables for the next iteration */ ValueNameLength = MaxNameLength + sizeof(WCHAR); ZeroMemory(ValueName, (MaxNameLength+1)*sizeof(WCHAR)); /*ZeroWideString(ValueName);*/ ValueDataLength = sizeof(DWORD); ValueData = 0; ValueType = REG_NONE; ++ ValueIndex; } FreeMemory(DevicePath); RegCloseKey(DevicesKey); } else { SND_WARN(L"Unable to open the Devices key!\n"); } ++ KeyIndex; RegCloseKey(Key); } return MMSYSERR_NOERROR; }
/* Open one of the Device sub-keys belonging to the sound driver. NT4 only. */ MMRESULT OpenSoundDeviceRegKey( IN LPWSTR ServiceName, IN DWORD DeviceIndex, OUT PHKEY KeyHandle) { SIZE_T PathLength; PWCHAR RegPath; VALIDATE_MMSYS_PARAMETER( ServiceName ); VALIDATE_MMSYS_PARAMETER( KeyHandle ); /* Work out the space required to hold the path: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ sndblst\ Parameters\ Device123\ */ PathLength = wcslen(REG_SERVICES_KEY_NAME_U) + 1 + wcslen(ServiceName) + 1 + wcslen(REG_PARAMETERS_KEY_NAME_U) + 1 + wcslen(REG_DEVICE_KEY_NAME_U) + GetDigitCount(DeviceIndex); /* Allocate storage for the string */ RegPath = AllocateWideString(PathLength); if ( ! RegPath ) { return MMSYSERR_NOMEM; } /* Write the path */ wsprintf(RegPath, L"%ls\\%ls\\%ls\\%ls%d", REG_SERVICES_KEY_NAME_U, ServiceName, REG_PARAMETERS_KEY_NAME_U, REG_DEVICE_KEY_NAME_U, DeviceIndex); SND_TRACE(L"Opening reg key: %wS\n", RegPath); /* Perform the open */ if ( RegOpenKeyEx(HKEY_LOCAL_MACHINE, RegPath, 0, KEY_READ, KeyHandle) != ERROR_SUCCESS ) { /* Couldn't open the key */ SND_ERR(L"Failed to open reg key: %wS\n", RegPath); FreeMemory(RegPath); return MMSYSERR_ERROR; } FreeMemory(RegPath); return MMSYSERR_NOERROR; }
/* Provides an implementation for the "get capabilities" request, using the standard IOCTLs used by NT4 sound drivers. */ MMRESULT GetNt4SoundDeviceCapabilities( IN PSOUND_DEVICE SoundDevice, OUT PVOID Capabilities, IN DWORD CapabilitiesSize) { MMRESULT Result; MMDEVICE_TYPE DeviceType; DWORD IoCtl; HANDLE DeviceHandle; /* If these are bad there's an internal error with MME-Buddy! */ SND_ASSERT( SoundDevice ); SND_ASSERT( Capabilities ); SND_ASSERT( CapabilitiesSize > 0 ); SND_TRACE(L"NT4 get-capabilities routine called\n"); /* Get the device type */ Result = GetSoundDeviceType(SoundDevice, &DeviceType); SND_ASSERT( Result == MMSYSERR_NOERROR ); if ( ! MMSUCCESS(Result) ) return TranslateInternalMmResult(Result); /* Choose the appropriate IOCTL */ if ( IS_WAVE_DEVICE_TYPE(DeviceType) ) { IoCtl = IOCTL_WAVE_GET_CAPABILITIES; } else if ( IS_MIDI_DEVICE_TYPE(DeviceType) ) { IoCtl = IOCTL_MIDI_GET_CAPABILITIES; } else { /* FIXME - need to support AUX and mixer devices */ SND_ASSERT( FALSE ); IoCtl = 0; } /* Get the capabilities information from the driver */ Result = OpenNt4KernelSoundDevice(SoundDevice, TRUE, &DeviceHandle); if ( ! MMSUCCESS(Result) ) { SND_ERR(L"Failed to open device"); return TranslateInternalMmResult(Result); } Result = SyncOverlappedDeviceIoControl(DeviceHandle, IoCtl, Capabilities, CapabilitiesSize, NULL, 0, NULL); CloseKernelSoundDevice(DeviceHandle); if ( ! MMSUCCESS(Result) ) { SND_ERR(L"Retrieval of capabilities information failed\n"); Result = TranslateInternalMmResult(Result); } return Result; }