diff --git a/reactos/lib/wdmaud/README.TXT b/reactos/lib/wdmaud/README.TXT new file mode 100755 index 00000000000..6a47e889804 --- /dev/null +++ b/reactos/lib/wdmaud/README.TXT @@ -0,0 +1,97 @@ +User-mode Multimedia Driver for WDM Audio +----------------------------------------- + +USAGE +----- +This is a "drop-in" replacement for the Windows XP wdmaud.drv component. To +make use of it, you'll need to disable system file protection somehow (easy +way is to rename all *.cab files in the sub-folders of C:\WINDOWS\DRIVER CACHE +to something else, then delete or rename WDMAUD.DRV in both C:\WINDOWS\SYSTEM32 +and C:\WINDOWS\SYSTEM32\DLLCACHE.) + +Now put the ReactOS wdmaud.drv in C:\WINDOWS\SYSTEM32. At some point, you'll +be asked to insert the Windows CD as some files are missing - cancel this and +choose "yes" when asked if you're sure. This is due to the system file +protection not being able to have its own way. + +That should be all there is to it. + + +IMPLEMENTATION/DEVELOPMENT NOTES +-------------------------------- +The style of driver used here dates back to the days of Windows 3.1. Not much +has changed - the NT 4 Sound Blaster driver exported the same functions and +supported the same message codes as the traditional Windows 3.1 user-mode +drivers did. + +But in XP, something strange happens with WDMAUD (which is why you can't just +put this next to the existing WDMAUD under a different name!) + +It appears that WINMM.DLL treats WDMAUD.DRV differently to other drivers. + +Here's a summary of how things work differently: + +1) It seems DRV_ENABLE and DRV_DISABLE are the only important messages + processed by DriverProc. These open and close the kernel-mode + driver. + +2) Each message handling function (aside from DriverProc) receives a + DRVM_INIT message after the driver has been opened. The second + parameter of this is a pointer to a string containing a device + path (\\?\... format.) Returning zero seems to be the accepted + thing to do, in any case. + + The purpose of this function (in our case) is to allow WDMAUD.DRV + to let WDMAUD.SYS know which device we want to play with. + + Presumably, this is called when new devices are added to the system, + as well. I don't know if this is called once per hardware device... + +3) xxxx_GETNUMDEVS now has extra data passed to it! The first + parameter is a device path string - which will have been passed + to DRVM_INIT previously. + +4) xxxx_GETDEVCAPS is a bit hazardous. The old set of parameters were: + 1 - Pointer to a capabilities structure (eg: WAVEOUTCAPS) + 2 - Size of the above structure + + But now, the parameters are: + 1 - Pointer to a MDEVCAPSEX struct (which points to a regular + capabilities structure) + 2 - Device path string + + So anything expecting the second parameter to be a size (for copying + memory maybe) is in for a bit of a surprise there! + +The reason for the above changes is Plug and Play. It seems that the extra +functionality was added in Windows 98 (possibly 95 as well) to make it +possible to hot-swap winmm-supported devices without requiring a restart of +whatever applications are using the devices. + +That's the theory, at least. + + +TODO +---- +Our WINMM.DLL will need hacking to make sure it can take into account the +preferential treatment given to WDMAUD.DRV + +I'm not sure if it'll work with it yet as there seems to be some accomodation +for the PnP DRVM_INIT and DRVM_EXIT messages, but whether or not winmm will +function correctly with this WDMAUD.DRV replacement is something that remains +to be seen. + + +THANKS +------ +Thanks to everyone who has encouraged me to continue developing the audio +system for ReactOS. + +In particular, I'd like to thank Alex Ionescu for the many hours of assistance +he has given me in figuring out how things are done. + + +- + +Andrew Greenwood +andrew.greenwood AT silverblade DOT co DOT uk diff --git a/reactos/lib/wdmaud/control.c b/reactos/lib/wdmaud/control.c index 3c9c1018528..edc15d89e3e 100644 --- a/reactos/lib/wdmaud/control.c +++ b/reactos/lib/wdmaud/control.c @@ -13,8 +13,13 @@ #include "wdmaud.h" /* - TODO: - Make these work for the other device types! + StartDevice + + Creates a completion thread for a device, sets the "is_running" member + of the device state to "true", and tells the kernel device to start + processing audio/MIDI data. + + Wave devices always start paused. */ MMRESULT StartDevice(PWDMAUD_DEVICE_INFO device) @@ -25,21 +30,165 @@ MMRESULT StartDevice(PWDMAUD_DEVICE_INFO device) result = ValidateDeviceInfoAndState(device); if ( result != MMSYSERR_NOERROR ) + { + DPRINT1("Device info/state not valid\n"); return result; + } - ioctl_code = device == WDMAUD_WAVE_IN ? IOCTL_WDMAUD_WAVE_IN_START : - device == WDMAUD_WAVE_OUT ? IOCTL_WDMAUD_WAVE_OUT_START : - 0x0000; + ioctl_code = + IsWaveInDeviceType(device->type) ? IOCTL_WDMAUD_WAVE_IN_START : + IsWaveOutDeviceType(device->type) ? IOCTL_WDMAUD_WAVE_OUT_START : + IsMidiInDeviceType(device->type) ? IOCTL_WDMAUD_MIDI_IN_START : + 0x0000; ASSERT( ioctl_code ); + + result = CreateCompletionThread(device); + + if ( MM_FAILURE( result ) ) + { + DPRINT1("Failed to create completion thread\n"); + return result; + } + + device->state->is_running = TRUE; + + result = CallKernelDevice(device, ioctl_code, 0, 0); + + if ( MM_FAILURE( result ) ) + { + DPRINT1("Audio could not be started\n"); + return result; + } + + if ( ! IsWaveDeviceType(device->type) ) + device->state->is_paused = FALSE; + + return result; } MMRESULT StopDevice(PWDMAUD_DEVICE_INFO device) { + MMRESULT result; + DWORD ioctl_code; + + result = ValidateDeviceInfoAndState(device); + + if ( result != MMSYSERR_NOERROR ) + { + DPRINT1("Device info/state not valid\n"); + return result; + } + + ioctl_code = + IsWaveInDeviceType(device->type) ? IOCTL_WDMAUD_WAVE_IN_STOP : + IsWaveOutDeviceType(device->type) ? IOCTL_WDMAUD_WAVE_OUT_STOP : + IsMidiInDeviceType(device->type) ? IOCTL_WDMAUD_MIDI_IN_STOP : + 0x0000; + + ASSERT( ioctl_code ); + + if ( IsMidiInDeviceType(device->type) ) + { + EnterCriticalSection(device->state->device_queue_guard); + + if ( ! device->state->is_running ) + { + /* TODO: Free the MIDI data queue */ + } + else + { + device->state->is_running = FALSE; + } + + LeaveCriticalSection(device->state->device_queue_guard); + } + else /* wave device */ + { + device->state->is_paused = TRUE; + } + + result = CallKernelDevice(device, ioctl_code, 0, 0); + + if ( MM_FAILURE( result ) ) + { + DPRINT1("Audio could not be stopped\n"); + return result; + } + + if ( IsWaveDeviceType(device-type) ) + { + device->state->is_paused = TRUE; + } + else /* MIDI Device */ + { + /* TODO: Destroy completion thread etc. */ + } + + return result; } -MMRESULT PauseDevice(PWDMAUD_DEVICE_INFO device) +MMRESULT ResetDevice(PWDMAUD_DEVICE_INFO device) { + MMRESULT result; + DWORD ioctl_code; + + result = ValidateDeviceInfoAndState(device); + + if ( result != MMSYSERR_NOERROR ) + { + DPRINT1("Device info/state not valid\n"); + return result; + } + + ioctl_code = + IsWaveInDeviceType(device->type) ? IOCTL_WDMAUD_WAVE_IN_RESET : + IsWaveOutDeviceType(device->type) ? IOCTL_WDMAUD_WAVE_OUT_RESET : + IsMidiInDeviceType(device->type) ? IOCTL_WDMAUD_MIDI_IN_RESET : + 0x0000; + + ASSERT( ioctl_code ); + + if ( IsMidiInDeviceType(device->type) ) + { + EnterCriticalSection(device->state->device_queue_guard); + + if ( ! device->state->is_running ) + { + /* TODO: Free the MIDI data queue */ + } + else + { + device->state->is_running = FALSE; + } + + LeaveCriticalSection(device->state->device_queue_guard); + } + + result = CallKernelDevice(device, ioctl_code, 0, 0); + + if ( MM_FAILURE( result ) ) + { + DPRINT1("Audio could not be reset\n"); + return result; + } + + if ( IsWaveDeviceType(device->type) ) + { + if ( IsWaveInDeviceType(device->type) ) + device->state->is_paused = TRUE; + else if ( IsWaveOutDeviceType(device->type) ) + device->state->is_paused = FALSE; + + /* TODO: Destroy completion thread + check ret val */ + } + else /* MIDI input device */ + { + /* TODO: Destroy completion thread + check ret val */ + /* TODO - more stuff */ + } + + return result; } MMRESULT StopDeviceLooping(PWDMAUD_DEVICE_INFO device) diff --git a/reactos/lib/wdmaud/devices.c b/reactos/lib/wdmaud/devices.c index 63d3d4c83ef..cb542e2ceb5 100644 --- a/reactos/lib/wdmaud/devices.c +++ b/reactos/lib/wdmaud/devices.c @@ -17,9 +17,15 @@ const char WDMAUD_DEVICE_INFO_SIG[4] = "WADI"; const char WDMAUD_DEVICE_STATE_SIG[4] = "WADS"; -const char WDMAUD_NULL_SIGNATURE[4] = {0,0,0,0}; +/* + IsValidDevicePath + + Just checks to see if the string containing the path to the device path + (object) is a valid, readable string. +*/ + BOOL IsValidDevicePath(WCHAR* path) { if (IsBadReadPtr(path, 1)) /* TODO: Replace with flags */ @@ -33,43 +39,93 @@ BOOL IsValidDevicePath(WCHAR* path) return TRUE; } -MMRESULT ValidateDeviceInfo(PWDMAUD_DEVICE_INFO device_info) -{ - if ( IsBadWritePtr(device_info, sizeof(WDMAUD_DEVICE_INFO)) ) - return MMSYSERR_INVALPARAM; +/* + ValidateDeviceData - if ( *device_info->signature != *WDMAUD_DEVICE_INFO_SIG ) + Checks that the memory pointed at by the device data pointer is writable, + and that it has a valid signature. + + If the "state" member isn't NULL, the state structure is also validated + in the same way. If the "require_state" parameter is TRUE and the "state" + member is NULL, an error code is returned. Otherwise the "state" member + isn't validated and no error occurs. +*/ + +MMRESULT ValidateDeviceData( + PWDMAUD_DEVICE_INFO device, + BOOL require_state +) +{ + if ( IsBadWritePtr(device, sizeof(WDMAUD_DEVICE_INFO)) ) + { + DPRINT1("Device data structure not writable\n"); return MMSYSERR_INVALPARAM; + } + + if ( strncmp(device->signature, WDMAUD_DEVICE_INFO_SIG, 4) != 0 ) + { + DPRINT1("Device signature is invalid\n"); + return MMSYSERR_INVALPARAM; + } + + if ( ! IsValidDeviceType(device->type) ) + { + DPRINT1("Invalid device type\n"); + return MMSYSERR_INVALPARAM; + } + + if ( device->id > 100 ) + { + DPRINT1("Device ID is out of range\n"); + return MMSYSERR_INVALPARAM; + } + + /* Now we validate the device state (if present) */ + + if ( device->state ) + { + if ( IsBadWritePtr(device->state, sizeof(WDMAUD_DEVICE_INFO)) ) + { + DPRINT1("Device state structure not writable\n"); + return MMSYSERR_INVALPARAM; + } + + if ( strncmp(device->state->signature, + WDMAUD_DEVICE_STATE_SIG, + 4) != 0 ) + { + DPRINT1("Device state signature is invalid\n"); + return MMSYSERR_INVALPARAM; + } + + /* TODO: Validate state events */ + } + else if ( require_state ) + { + return MMSYSERR_INVALPARAM; + } return MMSYSERR_NOERROR; } -MMRESULT ValidateDeviceState(PWDMAUD_DEVICE_STATE state) -{ - if ( IsBadWritePtr(state, sizeof(WDMAUD_DEVICE_INFO)) ) - return MMSYSERR_INVALPARAM; - - if ( *state->signature != *WDMAUD_DEVICE_STATE_SIG ) - return MMSYSERR_INVALPARAM; - - return MMSYSERR_NOERROR; -} /* ValidateDeviceStateEvents should be used in conjunction with the standard - state validation routine. -*/ + state validation routine (NOT on its own!) + FIXME: The tests are wrong +*/ +/* MMRESULT ValidateDeviceStateEvents(PWDMAUD_DEVICE_STATE state) { - if ( ( (DWORD) state->exit_thread_event == 0x00000000 ) && + if ( ( (DWORD) state->exit_thread_event != 0x00000000 ) && ( (DWORD) state->exit_thread_event != 0x48484848 ) ) { DPRINT1("Bad exit thread event\n"); return MMSYSERR_INVALPARAM; } - if ( ( (DWORD) state->queue_event == 0x00000000 ) && + if ( ( (DWORD) state->queue_event != 0x00000000 ) && ( (DWORD) state->queue_event != 0x42424242 ) && ( (DWORD) state->queue_event != 0x43434343 ) ) { @@ -79,28 +135,32 @@ MMRESULT ValidateDeviceStateEvents(PWDMAUD_DEVICE_STATE state) return MMSYSERR_NOERROR; } +*/ -MMRESULT ValidateDeviceInfoAndState(PWDMAUD_DEVICE_INFO device_info) +/* + CreateDeviceData + + This is a glorified memory allocation routine, which acts as a primitive + constructor for a device data structure. + + It validates the device path given, allocates memory for both the device + data and the device state data, copies the signatures over and sets the + device type accordingly. + + In some cases, a state structure isn't required, so the creation of one can + be avoided by passing FALSE for the "with_state" parameter. +*/ + +PWDMAUD_DEVICE_INFO +CreateDeviceData( + CHAR device_type, + DWORD device_id, + WCHAR* device_path, + BOOL with_state +) { - MMRESULT result; - - result = ValidateDeviceInfo(device_info); - - if ( result != MMSYSERR_NOERROR ) - return result; - - result = ValidateDeviceState(device_info->state); - - if ( result != MMSYSERR_NOERROR ) - return result; - - return MMSYSERR_NOERROR; -} - -PWDMAUD_DEVICE_INFO CreateDeviceData(CHAR device_type, WCHAR* device_path) -{ - HANDLE heap = 0; - PWDMAUD_DEVICE_INFO device_data = 0; + BOOL success = FALSE; + PWDMAUD_DEVICE_INFO device = 0; int path_size = 0; DPRINT("Creating device data for device type %d\n", (int) device_type); @@ -115,121 +175,119 @@ PWDMAUD_DEVICE_INFO CreateDeviceData(CHAR device_type, WCHAR* device_path) path_size = (lstrlen(device_path) + 1) * sizeof(WCHAR); /* DPRINT("Size of path is %d\n", (int) path_size); */ - heap = GetProcessHeap(); - - if ( ! heap ) - { - DPRINT1("Couldn't get the process heap (error %d)\n", - (int) GetLastError()); - goto cleanup; - } - - DPRINT("Allocating %d bytes\n", + DPRINT("Allocating %d bytes for device data\n", path_size + sizeof(WDMAUD_DEVICE_INFO)); -/* - device_data = (PWDMAUD_DEVICE_INFO) HeapAlloc(heap, - HEAP_ZERO_MEMORY, - path_size + sizeof(WDMAUD_DEVICE_INFO)); -*/ - device_data = (PWDMAUD_DEVICE_INFO) + device = (PWDMAUD_DEVICE_INFO) AllocMem(path_size + sizeof(WDMAUD_DEVICE_INFO)); - if ( ! device_data ) + if ( ! device ) { DPRINT1("Unable to allocate memory for device data (error %d)\n", (int) GetLastError()); goto cleanup; } - DPRINT("Copying signature\n"); - memcpy(device_data->signature, WDMAUD_DEVICE_INFO_SIG, 4); + /* Copy the signature and device path */ + memcpy(device->signature, WDMAUD_DEVICE_INFO_SIG, 4); + lstrcpy(device->path, device_path); - DPRINT("Copying path (0x%x)\n", (int)device_path); - lstrcpy(device_data->path, device_path); + /* Initialize these common members */ + device->id = device_id; + device->type = device_type; - device_data->type = device_type; + if ( with_state ) + { + /* Allocate device state structure */ + device->state = AllocMem(sizeof(WDMAUD_DEVICE_STATE)); + + if ( ! device->state ) + { + DPRINT1("Couldn't allocate memory for device state (error %d)\n", + (int) GetLastError()); + goto cleanup; + } + + /* Copy the signature */ + memcpy(device->state->signature, WDMAUD_DEVICE_STATE_SIG, 4); + } + + success = TRUE; cleanup : { - /* No cleanup needed (no failures possible after allocation.) */ - DPRINT("Performing cleanup\n"); + if ( ! success ) + { + if ( device ) + { + if ( device->state ) + { + ZeroMemory(device->state->signature, 4); + FreeMem(device->state); + } - return device_data; + ZeroMemory(device->signature, 4); + FreeMem(device); + } + } + + return (success ? device : NULL); } } + /* - CloneDeviceData + DeleteDeviceData - This isn't all that great... Maybe some macros would be better: - BEGIN_CLONING_STRUCT(source, target) - CLONE_MEMBER(member) - END_CLONING_STRUCT() + Blanks out the device and device state structures, and frees the memory + associated with the structures. - The main problem is that sometimes we'll want to copy more than - the data presented here. I guess we could blindly copy EVERYTHING - but that'd be excessive. + TODO: Free critical sections / events if set? */ -PWDMAUD_DEVICE_INFO CloneDeviceData(PWDMAUD_DEVICE_INFO original) -{ - PWDMAUD_DEVICE_INFO clone = NULL; - - if ( ValidateDeviceInfo(original) != MMSYSERR_NOERROR) - { - DPRINT1("Original device data was invalid\n"); - return NULL; - } - - /* This will set the type and path, so we can forget about those */ - clone = CreateDeviceData(original->type, original->path); - - if ( ! clone ) - { - DPRINT1("Clone creation failed\n"); - return NULL; - } - - clone->id = original->id; - clone->wave_handle = original->wave_handle; /* ok? */ - - /* TODO: Maybe we should copy some more? */ - - return clone; -} - void DeleteDeviceData(PWDMAUD_DEVICE_INFO device_data) { - HANDLE heap; + DPRINT("Deleting device data\n"); ASSERT( device_data ); - /* Erase the signature to prevent any possible future mishaps */ - *device_data->signature = *WDMAUD_NULL_SIGNATURE; - - heap = GetProcessHeap(); - - if ( ! heap ) - { - DPRINT1("Couldn't get the process heap (error %d)\n", - (int) GetLastError()); - goto exit; - } - - FreeMem(device_data); - /* - { - DPRINT1("Couldn't free device data memory (error %d)\n", - (int) GetLastError()); - } - */ - - exit : - /* We just return */ + /* We don't really care if the structure is valid or not */ + if ( ! device_data ) return; + + if ( device_data->state ) + { + /* We DON'T want these to be set - should we clean up? */ + ASSERT ( ! device_data->state->device_queue_guard ); + ASSERT ( ! device_data->state->queue_event ); + ASSERT ( ! device_data->state->exit_thread_event ); + + /* Insert a cow (not sure if this is right or not) */ + device_data->state->sample_size = 0xDEADBEEF; + + /* Overwrite the structure with zeroes and free it */ + ZeroMemory(device_data->state, sizeof(WDMAUD_DEVICE_STATE)); + FreeMem(device_data->state); + } + + /* Overwrite the structure with zeroes and free it */ + ZeroMemory(device_data, sizeof(WDMAUD_DEVICE_INFO)); + FreeMem(device_data); } +/* + ModifyDevicePresence + + Use this to add or remove devices in the kernel-mode driver. If the + "adding" parameter is TRUE, the device is added, otherwise it is removed. + + "device_type" is WDMAUD_WAVE_IN, WDMAUD_WAVE_OUT, etc... + + "device_path" specifies the NT object path of the device. + + (I'm not sure what happens to devices that are added but never removed.) +*/ + MMRESULT ModifyDevicePresence( CHAR device_type, WCHAR* device_path, @@ -249,7 +307,7 @@ MMRESULT ModifyDevicePresence( ASSERT( IsValidDeviceType(device_type) ); ASSERT( device_path ); - device_data = CreateDeviceData(device_type, device_path); + device_data = CreateDeviceData(device_type, 0, device_path, FALSE); if ( ! device_data ) { @@ -292,6 +350,16 @@ MMRESULT ModifyDevicePresence( } } +/* + GetDeviceCount + + Pretty straightforward - pass the device type (WDMAUD_WAVE_IN, ...) and + a topology device (NT object path) to obtain the number of devices + present in that topology of that particular type. + + The topology path is supplied to us by winmm. +*/ + DWORD GetDeviceCount(CHAR device_type, WCHAR* topology_path) { PWDMAUD_DEVICE_INFO device_data; @@ -299,7 +367,7 @@ DWORD GetDeviceCount(CHAR device_type, WCHAR* topology_path) DPRINT("Topology path %S\n", topology_path); - device_data = CreateDeviceData(device_type, topology_path); + device_data = CreateDeviceData(device_type, 0, topology_path, FALSE); if (! device_data) { @@ -339,7 +407,8 @@ DWORD GetDeviceCount(CHAR device_type, WCHAR* topology_path) This uses a different structure to the traditional documentation, because we handle plug and play devices. - Much sleep was lost over implementing this. + Much sleep was lost over implementing this. I got the ID and type + parameters the wrong way round! */ MMRESULT GetDeviceCapabilities( @@ -363,7 +432,7 @@ MMRESULT GetDeviceCapabilities( DPRINT("Going to have to query the kernel-mode part\n"); - device = CreateDeviceData(device_type, device_path); + device = CreateDeviceData(device_type, device_id, device_path, FALSE); if ( ! device ) { @@ -372,8 +441,9 @@ MMRESULT GetDeviceCapabilities( goto cleanup; } - device->id = device_id; - device->with_critical_section = FALSE; + /* These are not needed as they're already initialized */ + ASSERT( device_id == device->id ); + ASSERT( ! device->with_critical_section ); *(LPWORD)caps->pCaps = (WORD) 0x43; @@ -400,305 +470,224 @@ MMRESULT GetDeviceCapabilities( } } -MMRESULT TryOpenDevice( + +/* + OpenDeviceViaKernel + + Internal function to rub the kernel mode part of wdmaud the right way + so it opens a device on our behalf. +*/ + +MMRESULT +OpenDeviceViaKernel( PWDMAUD_DEVICE_INFO device, LPWAVEFORMATEX format ) { - if ( device->id > 0x64 ) /* FIXME */ + DWORD format_struct_len = 0; + + DPRINT("Opening device via kernel\n"); + + if ( format->wFormatTag == 1 ) /* FIXME */ { - DPRINT1("device->id > 0x64 ! ???\n"); - return MMSYSERR_BADDEVICEID; /* OK? */ - } + /* Standard PCM format */ + DWORD sample_size; - /* We'll only have a format set for wave devices */ - if ( format ) - { - if ( format->wFormatTag == 1 ) - { - DWORD sample_size; + DPRINT("Standard (PCM) format\n"); - DPRINT("Standard (PCM) format\n"); - sample_size = format->nChannels * format->wBitsPerSample; - device->state->sample_size = sample_size; + sample_size = format->nChannels * format->wBitsPerSample; - if ( CallKernelDevice(device, - IOCTL_WDMAUD_OPEN_DEVICE, - 0x10, - (DWORD)format) - != MMSYSERR_NOERROR ) - { - DPRINT("Call failed\n"); - /* FIXME */ - return MMSYSERR_NOTSUPPORTED; /* WAVERR_BADFORMAT? */ - } - } - else - { - /* FIXME */ - DPRINT("Non-PCM format\n"); - return MMSYSERR_NOTSUPPORTED; - } - } + device->state->sample_size = sample_size; - /* If we got this far without error, the format is supported! */ - return MMSYSERR_NOERROR; -} - -MMRESULT OpenWaveDevice( - CHAR device_type, - DWORD device_id, - LPWAVEOPENDESC open_details, - DWORD flags, - DWORD user_data -) -{ - HANDLE heap = 0; - PWDMAUD_DEVICE_INFO device = NULL; - WCHAR* device_path = NULL; - MMRESULT result = MMSYSERR_ERROR; - - /* ASSERT(open_details); */ - - heap = GetProcessHeap(); - - if ( ! heap ) - { - DPRINT1("Couldn't get the process heap (error %d)\n", - (int) GetLastError()); - result = MMSYSERR_ERROR; - goto cleanup; - } - - DPRINT("OpenDevice called\n"); - - device_path = (WCHAR*) open_details->dnDevNode; - device = CreateDeviceData(device_type, device_path); - - if ( ! device ) - { - DPRINT1("Couldn't create device data\n"); - result = MMSYSERR_NOMEM; - goto cleanup; - } - - DPRINT("Allocated device data, allocating device state\n"); - - device->state = HeapAlloc(heap, - HEAP_ZERO_MEMORY, - sizeof(WDMAUD_DEVICE_STATE)); - - if ( ! device->state ) - { - DPRINT1("Couldn't allocate memory for device state (error %d)\n", - (int) GetLastError()); - result = MMSYSERR_NOMEM; - goto cleanup; - } - - /* FIXME: ok here ? */ - device->type = device_type; - device->id = device_id; - device->flags = flags; - - if ( flags & WAVE_FORMAT_QUERY ) - { - DPRINT("Do I support this format? Hmm...\n"); - - result = TryOpenDevice(device, open_details->lpFormat); - - if ( result != MMSYSERR_NOERROR ) - { - DPRINT("Format not supported\n"); - goto cleanup; - } - - DPRINT("Yes, I do support this format!\n"); + format_struct_len = 16; /* FIXME */ } else { - - DPRINT("You actually want me to open the device, huh?\n"); - - /* Allocate memory for the "queue" critical section */ - - device->state->queue_critical_section = - HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(CRITICAL_SECTION)); - - if ( ! device->state->queue_critical_section ) - { - DPRINT1("Couldn't allocate memory for queue critical section (error %d)\n", - (int) GetLastError()); - result = MMSYSERR_NOMEM; - goto cleanup; - } - - /* Initialize the critical section */ - InitializeCriticalSection(device->state->queue_critical_section); - - /* We need these so we can contact the client later */ - device->client_instance = open_details->dwInstance; - device->client_callback = open_details->dwCallback; - - /* Reset state */ - device->state->open_descriptor = NULL; - device->state->unknown_24 = 0; - - device->state->is_running = FALSE; - device->state->is_paused = - device->type == WDMAUD_WAVE_IN ? TRUE : FALSE; - - memcpy(device->state->signature, WDMAUD_DEVICE_STATE_SIG, 4); - - DPRINT("All systems are go...\n"); - - result = TryOpenDevice(device, open_details->lpFormat); - - if ( result != MMSYSERR_NOERROR ) - { - DPRINT1("Format not supported?\n"); - goto cleanup; /* no need to set result - already done */ - } - - /* Enter the critical section while updating the device list */ - EnterCriticalSection(device->state->queue_critical_section); - /* ... */ - LeaveCriticalSection(device->state->queue_critical_section); - - /* The wave device handle is actually our structure. Neat, eh? */ - open_details->hWave = (HWAVE) device; - - /* We also need to set our "user data" for winmm */ - LPVOID* ud = (LPVOID*) user_data; /* FIXME */ - *ud = device; - - if (device->client_callback) - { - DWORD message; - - message = (device->type == WDMAUD_WAVE_IN ? WIM_OPEN : - WDMAUD_WAVE_OUT ? WOM_OPEN : -1); - - DPRINT("About to call the client callback\n"); - - /* Call the callback */ - NotifyClient(device, message, 0, 0); - - DPRINT("...it is done!\n"); - } - - result = MMSYSERR_NOERROR; + /* Non-standard format */ + return MMSYSERR_NOTSUPPORTED; /* TODO */ } - /* - This cleanup may need checking for memory leakage. It's not very pretty - to look at, either... - */ - - cleanup : - { - if ( ( result != MMSYSERR_NOERROR ) && ( heap ) ) - { - if ( device ) - { - if ( device->state ) - { - if ( device->state->queue_critical_section ) - { - DeleteCriticalSection(device->state->queue_critical_section); - HeapFree(heap, 0, device->state->queue_critical_section); - } - - HeapFree(heap, 0, device->state); - } - - DeleteDeviceData(device); - } - } - - DPRINT("Returning %d\n", (int) result); - - return result; - } + return CallKernelDevice(device, + IOCTL_WDMAUD_OPEN_DEVICE, + format_struct_len, + (DWORD)format); } -MMRESULT CloseDevice( - PWDMAUD_DEVICE_INFO device + +/* MOVEME */ +LPCRITICAL_SECTION CreateCriticalSection() +{ + LPCRITICAL_SECTION cs; + + cs = AllocMem(sizeof(CRITICAL_SECTION)); + + if ( ! cs ) + return NULL; + + InitializeCriticalSection(cs); + + return cs; +} + + +/* + OpenDevice + + A generic "open device" function, which makes use of the above function + once parameters have been checked. This is capable of handling both + MIDI and wave devices, which is an improvement over the previous + implementation (which had a lot of duplicate functionality.) +*/ + +MMRESULT +OpenDevice( + CHAR device_type, + DWORD device_id, + LPVOID open_descriptor, + DWORD flags, + PWDMAUD_DEVICE_INFO* user_data ) { MMRESULT result = MMSYSERR_ERROR; + WCHAR* device_path; + PWDMAUD_DEVICE_INFO device; + LPWAVEFORMATEX format; - DPRINT("CloseDevice()\n"); + /* As we support both types */ + LPWAVEOPENDESC wave_opendesc = (LPWAVEOPENDESC) open_descriptor; + LPMIDIOPENDESC midi_opendesc = (LPMIDIOPENDESC) open_descriptor; - DUMP_WDMAUD_DEVICE_INFO(device); + /* FIXME: Does this just apply to wave, or MIDI also? */ + if ( device_id > 100 ) + return MMSYSERR_BADDEVICEID; - if ( ValidateDeviceInfo(device) != MMSYSERR_NOERROR ) + /* Copy the appropriate dnDevNode value */ + if ( IsWaveDeviceType(device_type) ) + device_path = (WCHAR*) wave_opendesc->dnDevNode; + else if ( IsMidiDeviceType(device_type) ) + device_path = (WCHAR*) midi_opendesc->dnDevNode; + else + return MMSYSERR_INVALPARAM; + + device = CreateDeviceData(device_type, device_id, device_path, TRUE); + + if ( ! device ) { - DPRINT1("Invalid device info passed to CloseDevice\n"); - result = MMSYSERR_INVALHANDLE; + DPRINT1("Couldn't allocate memory for device data\n"); + result = MMSYSERR_NOMEM; goto cleanup; } - /* TODO: Check state! */ + device->flags = flags; - if ( device->id > 0x64 ) /* FIXME ? */ + if ( ( IsWaveDeviceType(device->type) ) && + ( device->flags & WAVE_FORMAT_QUERY ) ) { - DPRINT1("??\n"); - goto cleanup; - } + result = OpenDeviceViaKernel(device, wave_opendesc->lpFormat); - switch(device->type) - { - case WDMAUD_WAVE_OUT : + if ( result != MMSYSERR_NOERROR ) { - if ( device->state->open_descriptor ) - { - DPRINT1("Device is still playing!\n"); - result = WAVERR_STILLPLAYING; - goto cleanup; - } - - /* TODO: Destroy completion thread */ - - break; + DPRINT1("Format not supported (mmsys error %d)\n", (int) result); + result = WAVERR_BADFORMAT; } - - default : + else { - DPRINT1("Sorry, device type %d not supported yet!\n", (int) device->type); + DPRINT("Format supported\n"); + result = MMSYSERR_NOERROR; + } + + goto cleanup; + } + + device->state->device_queue_guard = CreateCriticalSection(); + + if ( ! device->state->device_queue_guard ) + { + DPRINT1("Couldn't create queue cs\n"); + result = MMSYSERR_NOMEM; + goto cleanup; + } + + /* Set up the callbacks */ + device->client_instance = IsWaveDeviceType(device->type) + ? wave_opendesc->dwInstance + : midi_opendesc->dwInstance; + + device->client_callback = IsWaveDeviceType(device->type) + ? wave_opendesc->dwCallback + : midi_opendesc->dwCallback; + + /* + The device state will be stopped and unpaused already, but in some + cases this isn't the desired behaviour. + */ + + /* FIXME: What do our friends MIDI in and out need? */ + device->state->is_paused = IsWaveOutDeviceType(device->type) ? TRUE : FALSE; + + if ( IsMidiOutDeviceType(device->type) ) + { + device->state->midi_buffer = AllocMem(2048); + + if ( ! device->state->midi_buffer ) + { + DPRINT1("Couldn't allocate MIDI buffer\n"); + result = MMSYSERR_NOMEM; goto cleanup; } } - result = CallKernelDevice(device, IOCTL_WDMAUD_CLOSE_DEVICE, 0, 0); + /* Format is only for wave devices */ + format = IsWaveDeviceType(device->type) ? wave_opendesc->lpFormat : NULL; - if ( result != MMSYSERR_NOERROR ) + result = OpenDeviceViaKernel(device, format); + + if ( MM_FAILURE(result) ) { - DPRINT1("Couldn't close the device!\n"); + DPRINT1("FAILED to open device - mm error %d\n", (int) result); goto cleanup; } - if (device->client_callback) + EnterCriticalSection(device->state->device_queue_guard); + /* TODO */ + LeaveCriticalSection(device->state->device_queue_guard); + + if ( IsWaveDeviceType(device->type) ) + wave_opendesc->hWave = (HWAVE) device; + else + midi_opendesc->hMidi = (HMIDI) device; + + /* Our "user data" is actually the device information */ + *user_data = device; + + if ( device->client_callback ) { - DWORD message; + DWORD message = IsWaveInDeviceType(device->type) ? WIM_OPEN : + IsWaveOutDeviceType(device->type) ? WOM_OPEN : + IsMidiInDeviceType(device->type) ? MIM_OPEN : + MOM_OPEN; - message = (device->type == WDMAUD_WAVE_IN ? WIM_CLOSE : - WDMAUD_WAVE_OUT ? WOM_CLOSE : - WDMAUD_MIDI_IN ? MIM_CLOSE : - WDMAUD_MIDI_OUT ? MOM_CLOSE : -1); - - DPRINT("About to call the client callback\n"); - - /* Call the callback */ + DPRINT("Calling client with message %d\n", (int) message); NotifyClient(device, message, 0, 0); - - DPRINT("...it is done!\n"); } - /* Result was set earlier by CallKernelDevice */ + result = MMSYSERR_NOERROR; cleanup : - { return result; - } } + + + + + + + + + + + + + + + diff --git a/reactos/lib/wdmaud/kernel.c b/reactos/lib/wdmaud/kernel.c index e1ae043f42e..fba6d54c6ae 100644 --- a/reactos/lib/wdmaud/kernel.c +++ b/reactos/lib/wdmaud/kernel.c @@ -66,10 +66,9 @@ MMRESULT CallKernelDevice( ( ! IsAuxDeviceType(device->type) ) && ( device->with_critical_section ) ) { - /* this seems to crash under some conditions */ ASSERT(device->state); using_critical_section = TRUE; - EnterCriticalSection(device->state->queue_critical_section); + EnterCriticalSection(device->state->device_queue_guard); } DPRINT("Calling DeviceIoControl with IOCTL %x\n", (int) ioctl_code); @@ -110,7 +109,7 @@ MMRESULT CallKernelDevice( { /* Leave the critical section */ if ( using_critical_section ) - LeaveCriticalSection(device->state->queue_critical_section); + LeaveCriticalSection(device->state->device_queue_guard); if ( overlap.hEvent ) CloseHandle(overlap.hEvent); @@ -128,7 +127,7 @@ static BOOL ChangeKernelDeviceState(BOOL enable) ioctl_code = enable ? IOCTL_WDMAUD_HELLO : IOCTL_WDMAUD_GOODBYE; - device = CreateDeviceData(WDMAUD_AUX, L""); + device = CreateDeviceData(WDMAUD_AUX, 0, L"", FALSE); if ( ! device ) { @@ -136,9 +135,6 @@ static BOOL ChangeKernelDeviceState(BOOL enable) return FALSE; } - DPRINT("Setting device type and disabling critical section\n"); - - device->type = WDMAUD_AUX; device->with_critical_section = FALSE; DPRINT("Calling kernel device\n"); @@ -318,33 +314,6 @@ BOOL EnableKernelInterface() BOOL DisableKernelInterface() { return ChangeKernelDeviceState(FALSE); - -#if 0 /* OLD CODE */ - PWDMAUD_DEVICE_INFO device = NULL; - - ASSERT(kernel_device_handle); - - /* Say goodbyte to wdmaud.sys */ - device = CreateDeviceData(WDMAUD_AUX, L""); - - ASSERT(device); - - DPRINT("Setting device type and disabling critical section\n"); - - device->type = WDMAUD_AUX; - device->with_critical_section = FALSE; - - DPRINT("Calling kernel device\n"); - - ASSERT( CallKernelDevice(device, IOCTL_WDMAUD_GOODBYE, 0, 0) == MMSYSERR_NOERROR ); - ASSERT( CloseHandle(kernel_device_handle) ); - - DPRINT("Kernel interface now disabled\n"); - - kernel_device_handle = NULL; - - DeleteDeviceData(device); -#endif } diff --git a/reactos/lib/wdmaud/memtrack.c b/reactos/lib/wdmaud/memtrack.c index 52a4eeeda5b..d68283ead92 100644 --- a/reactos/lib/wdmaud/memtrack.c +++ b/reactos/lib/wdmaud/memtrack.c @@ -58,7 +58,12 @@ VOID FreeMem(LPVOID pointer) } if ( ! HeapFree(heap, 0, pointer) ) - alloc_count --; + { + DPRINT("Unable to free memory (error %d)\n", (int)GetLastError()); + return; + } + + alloc_count --; ReportMem(); } diff --git a/reactos/lib/wdmaud/midi.c b/reactos/lib/wdmaud/midi.c new file mode 100644 index 00000000000..fea2c653d94 --- /dev/null +++ b/reactos/lib/wdmaud/midi.c @@ -0,0 +1,193 @@ +/* + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS Multimedia + * FILE: lib/wdmaud/midi.c + * PURPOSE: WDM Audio Support - MIDI Device / Header Manipulation + * PROGRAMMER: Andrew Greenwood + * UPDATE HISTORY: + * Nov 29, 2005: Created + */ + +#include +#include "wdmaud.h" + +/* + OpenMidiDevice + + OBSOLETE CODE - REFERENCE ONLY +*/ + +#if 0 +MMRESULT +OpenMidiDevice( + CHAR device_type, + DWORD device_id, + LPMIDIOPENDESC open_details, + DWORD flags, + DWORD user_data +) +{ + MMRESULT result = MMSYSERR_ERROR; + WCHAR* device_path; + PWDMAUD_DEVICE_INFO device; + + ASSERT( open_details ); + + /* FIXME? Is this true for MIDI devs too then? */ + if ( device_id > 100 ) + return MMSYSERR_BADDEVICEID; /* Not sure about this */ + + /* TODO: Case statement for wave/midi selection? */ + device_path = (WCHAR*) open_details->dnDevNode; + device = CreateDeviceData(device_type, device_id, device_path, TRUE); + + if ( ! device ) + { + DPRINT1("Couldn't create device data\n"); + result = MMSYSERR_NOMEM; + goto cleanup; + } + + device->type = device_type; /* not necessary */ + device->id = device_id; + device->flags = flags; + + /* Wave devices look for format query flag here... */ + /* ... Validate Flags ? */ + + device->state->device_queue_guard = AllocMem(sizeof(CRITICAL_SECTION)); + + if ( ! device->state->device_queue_guard ) + { + DPRINT1("Couldn't allocate memory for queue critical section (error %d)\n", + (int) GetLastError()); + result = MMSYSERR_NOMEM; + goto cleanup; + } + + /* Initialize the critical section */ + InitializeCriticalSection(device->state->device_queue_guard); + + /* We need these so we can contact the client later */ + device->client_instance = open_details->dwInstance; + device->client_callback = open_details->dwCallback; + + /* Reset state */ + device->state->current_midi_header = NULL; + device->state->unknown_24 = 0; + + device->state->is_running = FALSE; + device->state->is_paused = FALSE; + + /* MIDI ONLY */ + device->state->midi_buffer = 0; + device->state->running_status = 0x00; + + /* For wave devices, we call the kernel NOW (but we're not handling wave) */ + /* MIDI devices are a little more complicated... Code follows... */ + + /* MIDI OUT */ + if ( device->type == WDMAUD_MIDI_OUT ) + { + device->state->midi_buffer = AllocMem(2048); + + if ( ! device->state->midi_buffer ) + { + DPRINT1("Couldn't allocate memory for MIDI output buffer\n"); + result = MMSYSERR_NOMEM; + goto cleanup; + } + } + + /* Fairly generic code */ + + result = OpenDeviceViaKernel(device, NULL); + + if ( result != MMSYSERR_NOERROR ) + { + DPRINT1("Couldn't open device (mmsys error %d)\n", (int) result); + goto cleanup; + } + + /* Enter the critical section while updating the device list */ + EnterCriticalSection(device->state->device_queue_guard); + /* ... update MIDI list ... */ + LeaveCriticalSection(device->state->device_queue_guard); + + /* The MIDI device handle is actually our structure. Neat, eh? */ + open_details->hMidi = (HMIDI) device; + + /* We also need to set our "user data" for winmm */ + LPVOID* ud = (LPVOID*) user_data; /* FIXME */ + *ud = device; + + /* MIDI specific code follows */ + if ( device->type == WDMAUD_MIDI_IN ) + { + /* TODO: Read MIDI data until none left? */ + } + + if ( device->client_callback ) + { + DWORD message; + + message = (device->type == WDMAUD_MIDI_IN ? MIM_OPEN : MOM_OPEN); + + DPRINT("About to call the client callback\n"); + + /* Call the callback */ + NotifyClient(device, message, 0, 0); + + DPRINT("...it is done!\n"); + } + + result = MMSYSERR_NOERROR; + + cleanup : + { + /* TODO!!!! */ + return result; + } +} +#endif + +MMRESULT +CloseMidiDevice(PWDMAUD_DEVICE_INFO device) +{ + DPRINT("CloseMidiDevice\n"); + return MMSYSERR_NOTSUPPORTED; +} + +MMRESULT +WriteMidiShort( + PWDMAUD_DEVICE_INFO device, + DWORD message +) +{ + DPRINT("WriteMidiShort\n"); + return MMSYSERR_NOTSUPPORTED; +} + +MMRESULT +WriteMidiBuffer(PWDMAUD_DEVICE_INFO device) +{ + DPRINT("WriteMidiBuffer\n"); + /* TODO - fix params too! */ + return MMSYSERR_NOTSUPPORTED; +} + +MMRESULT +ResetMidiDevice(PWDMAUD_DEVICE_INFO device) +{ + DPRINT("ResetMidiDevice\n"); + return MMSYSERR_NOTSUPPORTED; +} + +/* + TODO: + SetVolume + GetVolume + SetPreferred +*/ + diff --git a/reactos/lib/wdmaud/threads.c b/reactos/lib/wdmaud/threads.c index 1a949edc8b4..6179b74fd4b 100644 --- a/reactos/lib/wdmaud/threads.c +++ b/reactos/lib/wdmaud/threads.c @@ -21,11 +21,11 @@ DWORD WINAPI WaveCompletionThreadStart(LPVOID data) DPRINT("WaveCompletionThread started\n"); - EnterCriticalSection(device->state->queue_critical_section); + EnterCriticalSection(device->state->device_queue_guard); while ( ! quit_loop ) { - result = ValidateDeviceInfoAndState(device); + result = ValidateDeviceData(device, TRUE); if ( result != MMSYSERR_NOERROR ) { @@ -33,7 +33,8 @@ DWORD WINAPI WaveCompletionThreadStart(LPVOID data) break; } - result = ValidateDeviceStateEvents(device->state); + /* TODO: REIMPLEMENT */ + /* result = ValidateDeviceStateEvents(device->state); */ if ( result != MMSYSERR_NOERROR ) { @@ -41,13 +42,13 @@ DWORD WINAPI WaveCompletionThreadStart(LPVOID data) break; } - if ( device->state->open_descriptor ) + if ( device->state->current_wave_header ) { - DPRINT("No open descriptor found - running? %d\n", (int) device->state->is_running); + DPRINT("No current header - running? %d\n", (int) device->state->is_running); if ( ! device->state->is_running ) { - LeaveCriticalSection(device->state->queue_critical_section); + LeaveCriticalSection(device->state->device_queue_guard); DPRINT("Waiting for queue_event\n"); WaitForSingleObject(device->state->queue_event, INFINITE); @@ -76,7 +77,7 @@ DWORD WINAPI WaveCompletionThreadStart(LPVOID data) } else { - PWAVEHDR wave_header = device->state->wave_header; + PWAVEHDR wave_header = device->state->current_wave_header; DPRINT("An open descriptor or wave header was found\n"); @@ -98,7 +99,7 @@ DWORD WINAPI WaveCompletionThreadStart(LPVOID data) DPRINT("Activating the next header\n"); /* Activate the next header */ - device->state->wave_header = wave_header->lpNext; + device->state->current_wave_header = wave_header->lpNext; /* Reset this just in case */ prep_data = NULL; @@ -117,7 +118,7 @@ DWORD WINAPI WaveCompletionThreadStart(LPVOID data) } /* We do this here in case there's an error - deadlock = bad! */ - LeaveCriticalSection(device->state->queue_critical_section); + LeaveCriticalSection(device->state->device_queue_guard); if ( result != MMSYSERR_NOERROR) goto cleanup; @@ -165,7 +166,7 @@ BOOL CreateCompletionThread(PWDMAUD_DEVICE_INFO device) else { DPRINT("Thread is null\n"); - + if ( ( (DWORD) device->state->queue_event != 0 ) && ( (DWORD) device->state->queue_event != MAGIC_42) && ( (DWORD) device->state->queue_event != MAGIC_43) ) @@ -229,7 +230,7 @@ BOOL CreateCompletionThread(PWDMAUD_DEVICE_INFO device) DPRINT("Thread created! - %d\n", (int) device->state->thread); /* TODO: Set priority */ -} + } return TRUE; /* TODO / FIXME */ } diff --git a/reactos/lib/wdmaud/user.c b/reactos/lib/wdmaud/user.c index ef8ae2255ae..9193e9679f3 100644 --- a/reactos/lib/wdmaud/user.c +++ b/reactos/lib/wdmaud/user.c @@ -23,7 +23,7 @@ #include "wdmaud.h" -APIENTRY LONG DriverProc( +APIENTRY LRESULT DriverProc( DWORD DriverID, HDRVR DriverHandle, UINT Message, @@ -102,9 +102,11 @@ APIENTRY LONG DriverProc( case DRV_INSTALL : DPRINT("DRV_INSTALL\n"); - return FALSE; /* ok? */ + return TRUE; /* ok? */ - /* DRV_REMOVE */ + case DRV_REMOVE : + DPRINT("DRV_REMOVE\n"); + return TRUE; default : DPRINT("?\n"); @@ -123,7 +125,7 @@ void NotifyClient( DriverCallback(device->client_callback, HIWORD(device->flags), - (HDRVR) device->wave_handle, + (HDRVR) device->handle, message, device->client_instance, 0, @@ -199,8 +201,8 @@ APIENTRY DWORD wodMessage( /* * WODM_GETDEVCAPS - * Parameter 1 : Pointer to a WAVEOUTCAPS struct - * Parameter 2 : "Wave" device path? FIXME (NEW!) + * Parameter 1 : Pointer to a MDEVICECAPS struct + * Parameter 2 : Device path */ case WODM_GETDEVCAPS : DPRINT("WODM_GETDEVCAPS\n"); @@ -214,11 +216,14 @@ APIENTRY DWORD wodMessage( */ case WODM_OPEN : DPRINT("WODM_OPEN\n"); - return OpenWaveOut(id, (LPWAVEOPENDESC) p1, p2, user); + return OpenWaveOutDevice(id, + (LPWAVEOPENDESC) p1, + p2, + (PWDMAUD_DEVICE_INFO*) user); case WODM_CLOSE : DPRINT("WODM_CLOSE\n"); - return CloseDevice((PWDMAUD_DEVICE_INFO) user); /* ugh! */ + return CloseWaveDevice((PWDMAUD_DEVICE_INFO) user); case WODM_PREPARE : DPRINT("WODM_PREPARE\n"); @@ -299,7 +304,46 @@ APIENTRY DWORD modMessage( case MODM_GETDEVCAPS : DPRINT("MODM_GETDEVCAPS\n"); return GetMidiOutCapabilities(id, (WCHAR*) p2, (LPMDEVICECAPSEX) p1); - }; + + case MODM_OPEN : + DPRINT("MODM_OPEN\n"); + return OpenMidiOutDevice(id, + (LPMIDIOPENDESC) p1, + p2, + (PWDMAUD_DEVICE_INFO*) user); + + case MODM_CLOSE : + DPRINT("MODM_CLOSE\n"); + return CloseMidiDevice((PWDMAUD_DEVICE_INFO) user); + + case MODM_DATA : + DPRINT("MODM_DATA\n"); + return WriteMidiShort((PWDMAUD_DEVICE_INFO) user, p1); + + case MODM_LONGDATA : + DPRINT("MODM_LONGDATA\n"); + return MMSYSERR_NOTSUPPORTED; + + case MODM_RESET : + DPRINT("MODM_RESET\n"); + return ResetMidiDevice((PWDMAUD_DEVICE_INFO) user); + + case MODM_SETVOLUME : + DPRINT("MODM_SETVOLUME\n"); + return MMSYSERR_NOTSUPPORTED; + + case MODM_GETVOLUME : + DPRINT("MODM_GETVOLUME\n"); + return MMSYSERR_NOTSUPPORTED; + +/* TODO: WINE's mmddk.h needs MODM_PREFERRED to be defined (value is ??) */ +/* + case MODM_PREFERRED : + DPRINT("MODM_PREFERRED\n"); + return MMSYSERR_NOTSUPPORTED; +*/ + + }; DPRINT("* NOT IMPLEMENTED *\n"); return MMSYSERR_NOTSUPPORTED; diff --git a/reactos/lib/wdmaud/wavehdr.c b/reactos/lib/wdmaud/wave.c similarity index 56% rename from reactos/lib/wdmaud/wavehdr.c rename to reactos/lib/wdmaud/wave.c index bce45cba7f0..42ced9c1f4f 100644 --- a/reactos/lib/wdmaud/wavehdr.c +++ b/reactos/lib/wdmaud/wave.c @@ -2,8 +2,8 @@ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Multimedia - * FILE: lib/wdmaud/wavehdr.c - * PURPOSE: WDM Audio Support - Wave Header Manipulation + * FILE: lib/wdmaud/wave.c + * PURPOSE: WDM Audio Support - Wave Device / Header Manipulation * PROGRAMMER: Andrew Greenwood * UPDATE HISTORY: * Nov 18, 2005: Created @@ -14,6 +14,194 @@ const char WAVE_PREPARE_DATA_SIG[4] = "WPPD"; +/* + OBSOLETE CODE - FOR REFERENCE ONLY +*/ +#if 0 +MMRESULT OpenWaveDevice( + CHAR device_type, + DWORD device_id, + LPWAVEOPENDESC open_details, + DWORD flags, + DWORD user_data +) +{ + MMRESULT result = MMSYSERR_ERROR; + WCHAR* device_path; + PWDMAUD_DEVICE_INFO device; + + ASSERT( open_details ); + ASSERT( open_details->lpFormat ); + + if ( device_id > 100 ) + return MMSYSERR_BADDEVICEID; /* Not sure about this */ + + device_path = (WCHAR*) open_details->dnDevNode; + device = CreateDeviceData(device_type, device_id, device_path, TRUE); + + if ( ! device ) + { + DPRINT1("Couldn't create device data\n"); + result = MMSYSERR_NOMEM; + goto cleanup; + } + + device->type = device_type; + device->id = device_id; + device->flags = flags; + + /* We don't deal with this here */ + if ( flags & WAVE_FORMAT_QUERY ) + { + result = QueryWaveFormatSupport(device, open_details); + DeleteDeviceData( device ); + return result; + } + + + device->state->device_queue_guard = AllocMem(sizeof(CRITICAL_SECTION)); + + if ( ! device->state->device_queue_guard ) + { + DPRINT1("Couldn't allocate memory for queue critical section (error %d)\n", + (int) GetLastError()); + result = MMSYSERR_NOMEM; + goto cleanup; + } + + /* Initialize the critical section */ + InitializeCriticalSection(device->state->device_queue_guard); + + /* We need these so we can contact the client later */ + device->client_instance = open_details->dwInstance; + device->client_callback = open_details->dwCallback; + + /* Reset state */ + device->state->current_wave_header = NULL; + device->state->unknown_24 = 0; + + device->state->is_running = FALSE; + device->state->is_paused = + device->type == WDMAUD_WAVE_IN ? TRUE : FALSE; + + DPRINT("Opening the device\n"); + + result = OpenDeviceViaKernel(device, open_details->lpFormat); + + if ( result != MMSYSERR_NOERROR ) + { + DPRINT1("Couldn't open! mmsys error %d\n", (int) result); + /* TODO: WAVERR_BADFORMAT translation ? */ + goto cleanup; + } + + /* Enter the critical section while updating the device list */ + EnterCriticalSection(device->state->device_queue_guard); + /* ... */ + LeaveCriticalSection(device->state->device_queue_guard); + + /* The wave device handle is actually our structure. Neat, eh? */ + open_details->hWave = (HWAVE) device; + + /* We also need to set our "user data" for winmm */ + LPVOID* ud = (LPVOID*) user_data; /* FIXME */ + *ud = device; + + if ( device->client_callback ) + { + DWORD message; + + message = (device->type == WDMAUD_WAVE_IN ? WIM_OPEN : WOM_OPEN); + + DPRINT("About to call the client callback\n"); + + /* Call the callback */ + NotifyClient(device, message, 0, 0); + + DPRINT("...it is done!\n"); + } + + result = MMSYSERR_NOERROR; + + cleanup : + { + if ( result != MMSYSERR_NOERROR ) + if ( device ) + DeleteDeviceData(device); + + return result; + } +} +#endif + +MMRESULT CloseWaveDevice( + PWDMAUD_DEVICE_INFO device +) +{ + MMRESULT result = MMSYSERR_ERROR; + + result = ValidateDeviceData(device, TRUE); + + if ( result != MMSYSERR_NOERROR ) + { + DPRINT1("Device data invalid\n"); + return MMSYSERR_INVALPARAM; + } + + if ( ! IsWaveDeviceType(device->type) ) + { + DPRINT1("Invalid device type (expected a WAVE device)\n"); + return MMSYSERR_INVALPARAM; + } + + /* TODO: Perform actual close */ + if ( device->state->current_wave_header ) + { + DPRINT1("Can't close! Device is still playing\n"); + return WAVERR_STILLPLAYING; + } + + /* TODO */ + /* DestroyCompletionThread(device); - check result */ + + result = CallKernelDevice(device, IOCTL_WDMAUD_CLOSE_DEVICE, 0, 0); + + if ( result != MMSYSERR_NOERROR ) + { + DPRINT1("Close failed! mmsyserr %d\n", (int) result); + return result; /* TODO: convert? */ + } + + if ( device->client_callback ) + { + DWORD message; + + message = (device->type == WDMAUD_WAVE_IN ? WIM_CLOSE : WOM_CLOSE); + + DPRINT("About to call the client callback\n"); + + /* Call the callback */ + NotifyClient(device, message, 0, 0); + + DPRINT("...it is done!\n"); + } + + /* + TODO: + Enter critical section + Loop through device list until we reach the end or until we find a + pointer matching "device". + Leave critical section + Delete critical section + ... + */ + + DeleteDeviceData(device); + + return MMSYSERR_NOERROR; +} + + /* ValidateWaveHeaderPreparation Overview : @@ -28,22 +216,18 @@ const char WAVE_PREPARE_DATA_SIG[4] = "WPPD"; MMRESULT ValidateWavePreparationData(PWDMAUD_WAVE_PREPARATION_DATA prep_data) { + /* UNIMPLEMENTED */ return MMSYSERR_NOERROR; } /* - ValidateWaveHeader Overview : + ValidateWaveHeader - Check that the pointer is valid to write to. If not, signal invalid - parameter. + Checks that the header memory can be written to, that the flags are + valid (using the mask 0xFFFFFFE0), and that the wave preparation data + is valid. - Perform a bitwise AND on the flags & 0xFFFFFFE0. If there are no bits - set, that's good. Otherwise give error and leave. - - Check that the "reserved" member contains a valid WAVEPREPAREDATA - structure. - - Return MMSYSERR_NOERROR if all's well! + Returns MMSYSERR_NOERROR if all's well, or MMSYSERR_INVALPARAM if not. */ MMRESULT ValidateWaveHeader(PWAVEHDR header) @@ -70,31 +254,16 @@ MMRESULT ValidateWaveHeader(PWAVEHDR header) /* - PrepareWaveHeader Overview : + PrepareWaveHeader - Validate the parameters. + Checks the parameters are sane, allocates memory for a WAVEPREPAREDATA + structure and also memory for an OVERLAPPED structure. - Allocate and lock 12 bytes of global memory (fixed, zeroed) for the - WAVEPREPAREDATA structure. + After this, an un-named event is created (as hEvent of the OVERLAPPED) + structure, and the WAVEPREPAREDATA structure has its signature set + accordingly. - If that fails, return immediately. - - Otherwise, allocate 20 bytes of memory on the process heap (with no - special flags.) This is for the overlapped member of the WAVEPREPAREDATA - structure. - - If the HeapAlloc failed, free the global memory and return. - - Create an event with all parameters false, NULL or zero. This is to be - stored as the hEvent member of the OVERLAPPED structure. - - If the event creation failed, free all memory used and return. - - If it succeeded, set the WAVEPREPAREDATA signature to "WPPD", and set - the reserved member of "header" to the pointer of the WAVEPREPAREDATA - instance. - - Return MMSYSERR_NOTSUPPORTED so that winmm does further processing. + Returns MMSYSERR_NOTSUPPORTED so that winmm does further processing. */ MMRESULT PrepareWaveHeader( @@ -104,11 +273,11 @@ MMRESULT PrepareWaveHeader( { MMRESULT result = MMSYSERR_ERROR; PWDMAUD_WAVE_PREPARATION_DATA prep_data = NULL; - HANDLE heap = NULL; DPRINT("PrepareWaveHeader called\n"); - result = ValidateDeviceInfoAndState(device); + /* Check the device data is valid */ + result = ValidateDeviceData(device, TRUE); if ( result != MMSYSERR_NOERROR ) { @@ -117,42 +286,21 @@ MMRESULT PrepareWaveHeader( } /* Make sure we were actually given a header to process */ - DPRINT("Checking that a header was supplied\n"); - if ( ! header ) { DPRINT1("Bad header\n"); return MMSYSERR_INVALPARAM; } - DPRINT("Checking flags\n"); - - /* I don't think Winmm would let this happen, but ya never know */ - /* - ASSERT( ! header->dwFlags & WHDR_PREPARED ); - ASSERT( header->dwFlags & WHDR_INQUEUE ); - */ + /* NOTE: At this point, what happens if not prepared or already queued? */ header->lpNext = NULL; header->reserved = 0; - heap = GetProcessHeap(); - - if ( ! heap ) - { - DPRINT1("Couldn't obtain the process heap (error %d)\n", - (int)GetLastError()); - result = MMSYSERR_NOMEM; - goto fail; - } - - DPRINT("Allocating preparation data\n"); - + /* Allocate memory for the wave preparation data */ prep_data = (PWDMAUD_WAVE_PREPARATION_DATA) - HeapAlloc(heap, - HEAP_ZERO_MEMORY, - sizeof(WDMAUD_WAVE_PREPARATION_DATA)); + AllocMem(sizeof(WDMAUD_WAVE_PREPARATION_DATA)); if ( ! prep_data ) { @@ -162,20 +310,18 @@ MMRESULT PrepareWaveHeader( goto fail; } - DPRINT("Allocating overlapped data\n"); + /* Create an event */ - prep_data->overlapped = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(OVERLAPPED)); + prep_data->overlapped = AllocMem(sizeof(OVERLAPPED)); if ( ! prep_data->overlapped ) { - DPRINT1("Couldn't allocate heap memory for overlapped structure (error %d)\n", + DPRINT1("Couldn't allocate memory for overlapped structure (error %d)\n", (int)GetLastError()); result = MMSYSERR_NOMEM; goto fail; } - DPRINT("Creating overlapped event\n"); - prep_data->overlapped->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if ( ! prep_data->overlapped->hEvent ) @@ -187,29 +333,26 @@ MMRESULT PrepareWaveHeader( } /* Copy the signature over and tie the prepare structure to the wave header */ - DPRINT("Copying signature\n"); - *prep_data->signature = *WAVE_PREPARE_DATA_SIG; + memcpy(prep_data->signature, WAVE_PREPARE_DATA_SIG, 4); header->reserved = (DWORD) prep_data; + /* We return this so WINMM can do further processing */ result = MMSYSERR_NOTSUPPORTED; return result; fail : { - if ( heap ) + if ( prep_data ) { - if ( prep_data ) + if ( prep_data->overlapped ) { - if ( prep_data->overlapped ) - { - if ( prep_data->overlapped->hEvent ) - CloseHandle(prep_data->overlapped->hEvent); /* ok? */ - - HeapFree(heap, 0, prep_data->overlapped); - } + if ( prep_data->overlapped->hEvent ) + CloseHandle(prep_data->overlapped->hEvent); /* ok? */ - HeapFree(heap, 0, prep_data); + FreeMem(prep_data->overlapped); } + + FreeMem(prep_data); } return result; @@ -219,13 +362,15 @@ MMRESULT PrepareWaveHeader( /* UnprepareWaveHeader + Cleans up after a header has been used, by killing the event we set up + above, and freeing the preparation data. + Winmm is intelligent enough to not call this function with a header that is currently queued for playing! */ MMRESULT UnprepareWaveHeader(PWAVEHDR header) { - HANDLE heap = NULL; MMRESULT result = MMSYSERR_ERROR; PWDMAUD_WAVE_PREPARATION_DATA prep_data = NULL; @@ -248,60 +393,23 @@ MMRESULT UnprepareWaveHeader(PWAVEHDR header) return result; } - /* - Overview : - - Set "reserved" to NULL. - - Close the event handle (overlapped->hEvent) and set that - structure member to NULL (not strictly necessary.) - - Obtain the heap pointer and free the heap-allocated and global - memory allocated in PrepareWaveHeader. - */ - /* We're about to free the preparation structure, so this needs to go */ header->reserved = 0; + /* Kill the event */ CloseHandle(prep_data->overlapped->hEvent); - - heap = GetProcessHeap(); - - if ( ! heap ) - { - /* Not quite sure how we handle this */ - DPRINT1("Couldn't obtain the process heap (error %d)\n", - (int)GetLastError()); - result = MMSYSERR_ERROR; - goto cleanup; - } - - if ( ! HeapFree(heap, 0, prep_data->overlapped) ) - { - DPRINT1("Unable to free the OVERLAPPED memory (error %d)\n", - (int)GetLastError()); - /* This shouldn't happen! */ - ASSERT(FALSE); - } + FreeMem(prep_data->overlapped); /* Overwrite the signature (structure will be invalid from now on) */ ZeroMemory(prep_data->signature, 4); - - if ( ! HeapFree(heap, 0, prep_data) ) - { - DPRINT1("Unable to free the preparation structure memory (error %d)\n", - (int)GetLastError()); - /* This shouldn't happen! */ - ASSERT(FALSE); - } + FreeMem(prep_data); /* Always return like this so winmm thinks we didn't do anything */ DPRINT("Header now unprepared.\n"); result = MMSYSERR_NOTSUPPORTED; - cleanup : - return result; + return result; } /* Not sure about this */ @@ -368,6 +476,13 @@ MMRESULT CompleteWaveHeader(PWAVEHDR header) device info structure. */ +/* + ValidateWriteWaveDataParams + + This is just a helper function that shrinks WriteWaveData a little + bit. +*/ + static MMRESULT ValidateWriteWaveDataParams( PWDMAUD_DEVICE_INFO device, PWAVEHDR header @@ -401,7 +516,7 @@ static MMRESULT ValidateWriteWaveDataParams( return WAVERR_UNPREPARED; } - result = ValidateDeviceInfoAndState(device); + result = ValidateDeviceData(device, TRUE); if ( result != MMSYSERR_NOERROR ) { @@ -412,27 +527,41 @@ static MMRESULT ValidateWriteWaveDataParams( return result; } +/* + WriteWaveData + + This is the exciting (?!) bit where playback actually begins. Various + validation takes place, before the header is queued for playback. Playback + can then begin. This entails telling the kernel-mode device about the + header, then telling the device to start playback. + + It all seems pretty straightforward, but it's not all that easy... +*/ + MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header) { MMRESULT result = MMSYSERR_ERROR; DWORD io_result = 0; PWDMAUD_WAVE_PREPARATION_DATA prep_data = NULL; - PWDMAUD_DEVICE_INFO clone; + /* PWDMAUD_DEVICE_INFO clone; */ /* For the DeviceIoControl later */ DWORD ioctl_code; DWORD bytes_returned; - DPRINT("SubmitWaveHeader called\n"); + DPRINT("WriteWaveHeader called\n"); result = ValidateWriteWaveDataParams(device, header); if ( result != MMSYSERR_NOERROR ) return result; - /* - TODO: Check to see if we actually get called with bad flags! - */ + /* Check to see if we actually get called with bad flags! */ + if ( ! IS_WAVEHDR_FLAG_SET(header, WHDR_PREPARED) ) + { + DPRINT1("Not prepared!\n"); + return WAVERR_UNPREPARED; + } /* Retrieve our precious data from the reserved member */ prep_data = (PWDMAUD_WAVE_PREPARATION_DATA) header->reserved; @@ -456,17 +585,17 @@ MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header) DPRINT("Flags == 0x%x\n", (int) header->dwFlags); - EnterCriticalSection(device->state->queue_critical_section); + EnterCriticalSection(device->state->device_queue_guard); - if ( ! device->state->wave_header ) + if ( ! device->state->current_wave_header ) { DPRINT("Device state wave_header is NULL\n"); - device->state->wave_header = header; + device->state->current_wave_header = header; /* My, what pretty symmetry you have... */ - DPRINT("Queue event == %d\n", (int) device->state->queue_event); + DPRINT("Queue event == 0x%x\n", (int) device->state->queue_event); if ( ( (DWORD) device->state->queue_event != 0 ) && ( (DWORD) device->state->queue_event != MAGIC_42 ) && @@ -483,40 +612,30 @@ MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header) ASSERT(FALSE); } - LeaveCriticalSection(device->state->queue_critical_section); + LeaveCriticalSection(device->state->device_queue_guard); - /* CODE FROM SUBMITWAVEHEADER */ - - DPRINT("Now we actually perform header submission\n"); - - clone = CloneDeviceData(device); - - if ( ! clone ) - { - /* Safe to do this? */ - DPRINT1("Clone creation failed\n"); - return MMSYSERR_NOMEM; - } + /* Now we send the header to the kernel device */ if ( ! IsHeaderPrepared(header) ) { DPRINT1("Unprepared header!\n"); - DeleteDeviceData(clone); - return MMSYSERR_INVALPARAM; + result = MMSYSERR_INVALPARAM; + goto cleanup; } - /* Not sure what this is for */ - prep_data->offspring = clone; + /* + Not sure what this is for. I *think* it's used for tracking which + device a preparation belongs to. + */ + prep_data->offspring = device; /* The modern version of WODM_WRITE, I guess ;) */ - clone->ioctl_param1 = sizeof(WAVEHDR); - clone->ioctl_param2 = (DWORD) header; + device->ioctl_param1 = sizeof(WAVEHDR); + device->ioctl_param2 = (DWORD) header; - ioctl_code = clone->type == WDMAUD_WAVE_IN - ? 0x1d8150 /* FIXME */ - : IOCTL_WDMAUD_SUBMIT_WAVE_HDR; - - DPRINT("Overlapped == 0x%x\n", (int) prep_data->overlapped); + ioctl_code = device->type == WDMAUD_WAVE_IN + ? IOCTL_WDMAUD_SUBMIT_WAVE_IN_HDR /* FIXME */ + : IOCTL_WDMAUD_SUBMIT_WAVE_OUT_HDR; /* FIXME: @@ -528,9 +647,9 @@ MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header) io_result = DeviceIoControl(GetKernelInterface(), ioctl_code, - clone, - sizeof(WDMAUD_DEVICE_INFO) + (lstrlen(clone->path) * 2), - clone, + device, + sizeof(WDMAUD_DEVICE_INFO) + (lstrlen(device->path) * 2), + device, sizeof(WDMAUD_DEVICE_INFO), &bytes_returned, /* ... */ prep_data->overlapped); @@ -542,28 +661,27 @@ MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header) DPRINT1("Wave header submission FAILED! (error %d)\n", (int) io_result); CLEAR_WAVEHDR_FLAG(header, WHDR_INQUEUE); - device->state->queue_critical_section = NULL; - device->state->wave_header = NULL; + device->state->device_queue_guard = NULL; + device->state->current_wave_header = NULL; return TranslateWinError(io_result); } /* CallKernelDevice(clone, ioctl_code, 0x20, (DWORD) header); */ - DPRINT("Creating completion thread\n"); if ( ! CreateCompletionThread(device) ) { DPRINT1("Couldn't create completion thread\n"); CLEAR_WAVEHDR_FLAG(header, WHDR_INQUEUE); - device->state->queue_critical_section = NULL; - device->state->wave_header = NULL; + device->state->device_queue_guard = NULL; + device->state->current_wave_header = NULL; return MMSYSERR_ERROR; /* Care to be more specific? */ } - /* TODO */ + /* ***** FIXME ****** THIS IS NASTY HACKERY ****** */ DPRINT("applying hacks\n"); @@ -572,7 +690,7 @@ MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header) /* HACK */ DPRINT("%d\n", (int) DeviceIoControl(GetKernelInterface(), - 0x1d8104, + IOCTL_WDMAUD_WAVE_OUT_START, device, sizeof(WDMAUD_DEVICE_INFO) + (lstrlen(device->path) * 2), device, @@ -597,5 +715,9 @@ MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header) result = MMSYSERR_NOERROR; - return result; + cleanup : + { + /* TODO */ + return result; + } } diff --git a/reactos/lib/wdmaud/wdmaud.h b/reactos/lib/wdmaud/wdmaud.h index 5e4775356d4..7b538b76bd9 100755 --- a/reactos/lib/wdmaud/wdmaud.h +++ b/reactos/lib/wdmaud/wdmaud.h @@ -39,6 +39,11 @@ #define REPORT_MM_RESULT(message, success) \ DPRINT("%s %s\n", message, success == MMSYSERR_NOERROR ? "succeeded" : "failed") +#define MM_SUCCESS(value) \ + ( value == MMSYSERR_NOERROR ) + +#define MM_FAILURE(value) \ + ( value != MMSYSERR_NOERROR ) #define GOBAL_CALLBACKS_PATH L"Global\\WDMAUD_Callbacks" @@ -65,55 +70,57 @@ #define IOCTL_WDMAUD_HELLO \ CTL_CODE(FILE_DEVICE_SOUND, 0x0000, METHOD_BUFFERED, FILE_WRITE_ACCESS) -#define IOCTL_WDMAUD_ADD_DEVICE 0x1d8004 -#define IOCTL_WDMAUD_REMOVE_DEVICE 0x1d8008 -#define IOCTL_WDMAUD_GET_CAPABILITIES 0x1d800c -#define IOCTL_WDMAUD_GET_DEVICE_COUNT 0x1d8010 -#define IOCTL_WDMAUD_OPEN_DEVICE 0x1d8014 -#define IOCTL_WDMAUD_CLOSE_DEVICE 0x1d8018 -#define IOCTL_WDMAUD_AUX_GET_VOLUME 0x1d801c -#define IOCTL_WDMAUD_AUX_SET_VOLUME 0x1d8020 +#define IOCTL_WDMAUD_ADD_DEVICE 0x1d8004 +#define IOCTL_WDMAUD_REMOVE_DEVICE 0x1d8008 +#define IOCTL_WDMAUD_GET_CAPABILITIES 0x1d800c +#define IOCTL_WDMAUD_GET_DEVICE_COUNT 0x1d8010 +#define IOCTL_WDMAUD_OPEN_DEVICE 0x1d8014 +#define IOCTL_WDMAUD_CLOSE_DEVICE 0x1d8018 +#define IOCTL_WDMAUD_AUX_GET_VOLUME 0x1d801c +#define IOCTL_WDMAUD_AUX_SET_VOLUME 0x1d8020 /* 0x1d8024 */ #define IOCTL_WDMAUD_GOODBYE \ CTL_CODE(FILE_DEVICE_SOUND, 0x0009, METHOD_BUFFERED, FILE_WRITE_ACCESS) -#define IOCTL_WDMAUD_SET_PREFERRED 0x1d8028 +#define IOCTL_WDMAUD_SET_PREFERRED 0x1d8028 -#define IOCTL_WDMAUD_SET_STATE_UNKNOWN1 0x1d8100 -#define IOCTL_WDMAUD_WAVE_OUT_START 0x1d8104 /* Reset wave in? */ -#define IOCTL_WDMAUD_SET_STATE_UNKNOWN3 0x1d8108 /* Start wave in? */ +#define IOCTL_WDMAUD_WAVE_OUT_STOP 0x1d8100 +#define IOCTL_WDMAUD_WAVE_OUT_START 0x1d8104 +#define IOCTL_WDMAUD_WAVE_OUT_RESET 0x1d8108 #define IOCTL_WDMAUD_BREAK_LOOP 0x1d810c -#define IOCTL_WDMAUD_GET_WAVE_OUT_POS 0x1d8110 /* Does something funky */ -#define IOCTL_WDMAUD_SET_VOLUME 0x1d8114 /* Hasn't this already been covered? */ -#define IOCTL_WDMAUD_UNKNOWN1 0x1d8018 /* Not used by wdmaud.drv */ -#define IOCTL_WDMAUD_SUBMIT_WAVE_HDR 0x1d811c +#define IOCTL_WDMAUD_GET_WAVE_OUT_POS 0x1d8110 /* Does something funky */ +#define IOCTL_WDMAUD_SET_VOLUME 0x1d8114 /* Already been covered? */ +#define IOCTL_WDMAUD_UNKNOWN1 0x1d8118 /* Not used by wdmaud.drv */ +#define IOCTL_WDMAUD_SUBMIT_WAVE_OUT_HDR 0x1d811c -#define IOCTL_WDMAUD_SET_STATE_UNKNOWN4 0x1d8140 -#define IOCTL_WDMAUD_WAVE_IN_START 0x1d8144 /* Reset wave out? */ -#define IOCTL_WDMAUD_SET_STATE_UNKNOWN6 0x1d8148 /* Start wave out? */ +#define IOCTL_WDMAUD_WAVE_IN_STOP 0x1d8140 +#define IOCTL_WDMAUD_WAVE_IN_START 0x1d8144 +#define IOCTL_WDMAUD_WAVE_IN_RESET 0x1d8148 + +#define IOCTL_WDMAUD_SUBMIT_WAVE_IN_HDR 0x1d8150 /* FIXME: Unsure about this */ #define IOCTL_WDMAUD_MIDI_OUT_SHORT_MESSAGE \ 0x1d8204 /* Wrong description? */ -#define IOCTL_WDMAUD_UNKNOWN2 0x1d8208 +#define IOCTL_WDMAUD_UNKNOWN2 0x1d8208 #define IOCTL_WDMAUD_MIDI_OUT_LONG_MESSAGE \ 0x1d820c -#define IOCTL_WDMAUD_SUBMIT_MIDI_HDR 0x1d8210 +#define IOCTL_WDMAUD_SUBMIT_MIDI_HDR 0x1d8210 -#define IOCTL_WDMAUD_SET_STATE_UNKNOWN7 0x1d8240 -#define IOCTL_WDMAUD_SET_STATE_UNKNOWN8 0x1d8244 -#define IOCTL_WDMAUD_SET_STATE_UNKNOWN9 0x1d8248 +#define IOCTL_WDMAUD_MIDI_IN_STOP 0x1d8240 +#define IOCTL_WDMAUD_MIDI_IN_START 0x1d8244 +#define IOCTL_WDMAUD_MIDI_IN_RESET 0x1d8248 -#define IOCTL_WDMAUD_READ_MIDI_DATA 0x1d824c -#define IOCTL_WDMAUD_MIDI_MESSAGE 0x1d8300 /* Wrong description? */ +#define IOCTL_WDMAUD_READ_MIDI_DATA 0x1d824c +#define IOCTL_WDMAUD_MIDI_MESSAGE 0x1d8300 /* Wrong description? */ -#define IOCTL_WDMAUD_MIXER_UNKNOWN1 0x1d8310 -#define IOCTL_WDMAUD_MIXER_UNKNOWN2 0x1d8314 -#define IOCTL_WDMAUD_MIXER_UNKNOWN3 0x1d8318 +#define IOCTL_WDMAUD_MIXER_UNKNOWN1 0x1d8310 +#define IOCTL_WDMAUD_MIXER_UNKNOWN2 0x1d8314 +#define IOCTL_WDMAUD_MIXER_UNKNOWN3 0x1d8318 /* @@ -180,6 +187,8 @@ typedef LPVOID PWDMAUD_HEADER; There are also various "opendesc" structures, but these don't have any common members. Regardless, this typedef simply serves as a placeholder to indicate that to access the members, it should be cast accordingly. + + TODO: Maybe have a generic OPEN routine that uses this? */ typedef struct OPENDESC *LPOPENDESC; @@ -188,41 +197,56 @@ typedef struct DWORD sample_size; HANDLE thread; DWORD thread_id; + union { - LPWAVEOPENDESC open_descriptor; - LPWAVEHDR wave_header; + LPWAVEHDR current_wave_header; + LPMIDIHDR current_midi_header; }; + DWORD unknown_10; /* pointer to something */ DWORD unknown_14; - LPCRITICAL_SECTION queue_critical_section; + + LPCRITICAL_SECTION device_queue_guard; HANDLE queue_event; HANDLE exit_thread_event; + DWORD unknown_24; + DWORD is_paused; DWORD is_running; + DWORD unknown_30; - DWORD unknown_34; - DWORD unknown_38; + LPVOID midi_buffer; /* for output ? */ + DWORD running_status; + char signature[4]; } WDMAUD_DEVICE_STATE, *PWDMAUD_DEVICE_STATE; typedef struct { - DWORD unknown_00; + DWORD next_device; + DWORD id; DWORD type; - HWAVE wave_handle; + + HWAVE handle; + DWORD client_instance; DWORD client_callback; + DWORD unknown_18; + DWORD flags; DWORD ioctl_param2; DWORD ioctl_param1; DWORD with_critical_section; DWORD string_2c; + DWORD unknown_30; + DWORD playing_notes; + DWORD unknown_38; DWORD unknown_3c; DWORD unknown_40; @@ -230,6 +254,7 @@ typedef struct DWORD unknown_48; DWORD unknown_4C; DWORD unknown_50; + DWORD beef; PWDMAUD_DEVICE_STATE state; char signature[4]; @@ -317,37 +342,63 @@ MMRESULT TranslateWinError(DWORD error); /* user.c */ -void NotifyClient( + +void +NotifyClient( PWDMAUD_DEVICE_INFO device, DWORD message, DWORD p1, - DWORD p2); - -/* #define NotifyClient(device, message, p1, p2) ? */ + DWORD p2 +); /* kernel.c */ -BOOL EnableKernelInterface(); -BOOL DisableKernelInterface(); -HANDLE GetKernelInterface(); +BOOL +EnableKernelInterface(); -MMRESULT CallKernelDevice( +BOOL +DisableKernelInterface(); + +HANDLE +GetKernelInterface(); + +MMRESULT +CallKernelDevice( PWDMAUD_DEVICE_INFO device, DWORD ioctl_code, DWORD param1, DWORD param2); /* devices.c */ -BOOL IsValidDevicePath(WCHAR* path); -MMRESULT ValidateDeviceInfo(PWDMAUD_DEVICE_INFO info); + +BOOL +IsValidDevicePath(WCHAR* path); + +MMRESULT +ValidateDeviceData( + PWDMAUD_DEVICE_INFO device_data, + BOOL require_state +); +/* MMRESULT ValidateDeviceState(PWDMAUD_DEVICE_STATE state); MMRESULT ValidateDeviceStateEvents(PWDMAUD_DEVICE_STATE state); MMRESULT ValidateDeviceInfoAndState(PWDMAUD_DEVICE_INFO device_info); +*/ + +/* TODO: Add ID parameter */ + +PWDMAUD_DEVICE_INFO +CreateDeviceData( + CHAR device_type, + DWORD device_id, + WCHAR* device_path, + BOOL with_state +); + +void +DeleteDeviceData(PWDMAUD_DEVICE_INFO device_data); -PWDMAUD_DEVICE_INFO CreateDeviceData(CHAR device_type, WCHAR* device_path); -PWDMAUD_DEVICE_INFO CloneDeviceData(PWDMAUD_DEVICE_INFO original); -void DeleteDeviceData(PWDMAUD_DEVICE_INFO device_data); /* mixer ... */ MMRESULT ModifyDevicePresence( @@ -388,7 +439,9 @@ MMRESULT ModifyDevicePresence( RemoveDevice(WDMAUD_AUX, device_path) -DWORD GetDeviceCount(CHAR device_type, WCHAR* device_path); +DWORD +GetDeviceCount(CHAR device_type, WCHAR* device_path); + #define GetWaveInCount(device_path) GetDeviceCount(WDMAUD_WAVE_IN, device_path) #define GetWaveOutCount(device_path) GetDeviceCount(WDMAUD_WAVE_OUT, device_path) #define GetMidiInCount(device_path) GetDeviceCount(WDMAUD_MIDI_IN, device_path) @@ -396,11 +449,13 @@ DWORD GetDeviceCount(CHAR device_type, WCHAR* device_path); #define GetMixerCount(device_path) GetDeviceCount(WDMAUD_MIXER, device_path) #define GetAuxCount(device_path) GetDeviceCount(WDMAUD_AUX, device_path) -MMRESULT GetDeviceCapabilities( +MMRESULT +GetDeviceCapabilities( CHAR device_type, DWORD device_id, WCHAR* device_path, - LPMDEVICECAPSEX caps); + LPMDEVICECAPSEX caps +); #define GetWaveInCapabilities(id, device_path, caps) \ GetDeviceCapabilities(WDMAUD_WAVE_IN, id, device_path, caps); @@ -415,46 +470,115 @@ MMRESULT GetDeviceCapabilities( #define GetAuxCapabilities(id, device_path, caps) \ GetDeviceCapabilities(WDMAUD_AUX, id, device_path, caps); -MMRESULT OpenWaveDevice( +MMRESULT +OpenDeviceViaKernel( + PWDMAUD_DEVICE_INFO device, + LPWAVEFORMATEX format +); + +MMRESULT +OpenDevice( + CHAR device_type, + DWORD device_id, + LPVOID open_descriptor, + DWORD flags, + PWDMAUD_DEVICE_INFO* user_data +); + + +/* wave.c */ +#if 0 +MMRESULT +OpenWaveDevice( CHAR device_type, DWORD device_id, LPWAVEOPENDESC open_details, DWORD flags, - DWORD user_data); + DWORD user_data +); +#endif -#define OpenWaveOut(id, open_details, flags, user_data) \ - OpenWaveDevice(WDMAUD_WAVE_OUT, id, open_details, flags, user_data); +#define OpenWaveInDevice(id, open_details, flags, user_data) \ + OpenDevice(WDMAUD_WAVE_IN, id, open_details, flags, user_data); +#define OpenWaveOutDevice(id, open_details, flags, user_data) \ + OpenDevice(WDMAUD_WAVE_OUT, id, open_details, flags, user_data); +#define OpenMidiInDevice(id, open_details, flags, user_data) \ + OpenDevice(WDMAUD_MIDI_IN, id, open_details, flags, user_data); +#define OpenMidiOutDevice(id, open_details, flags, user_data) \ + OpenDevice(WDMAUD_MIDI_OUT, id, open_details, flags, user_data); -MMRESULT CloseDevice( + +MMRESULT +CloseWaveDevice( PWDMAUD_DEVICE_INFO device ); - -/* wavehdr.h */ - #define SET_WAVEHDR_FLAG(header, flag) \ header->dwFlags |= flag #define CLEAR_WAVEHDR_FLAG(header, flag) \ header->dwFlags &= ~flag -MMRESULT ValidateWavePreparationData(PWDMAUD_WAVE_PREPARATION_DATA prep_data); +#define IS_WAVEHDR_FLAG_SET(header, flag) \ + ( header->dwFlags & flag ) -MMRESULT ValidateWaveHeader(PWAVEHDR header); +MMRESULT +ValidateWavePreparationData(PWDMAUD_WAVE_PREPARATION_DATA prep_data); -MMRESULT PrepareWaveHeader( +MMRESULT +ValidateWaveHeader(PWAVEHDR header); + +MMRESULT +PrepareWaveHeader( PWDMAUD_DEVICE_INFO device, PWAVEHDR header ); -MMRESULT UnprepareWaveHeader(PWAVEHDR header); +MMRESULT +UnprepareWaveHeader(PWAVEHDR header); #define IsHeaderPrepared(header) \ ( header->reserved != 0 ) -MMRESULT CompleteWaveHeader(PWAVEHDR header); +MMRESULT +CompleteWaveHeader(PWAVEHDR header); + +MMRESULT +WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header); + + +/* midi.c */ + +#if 0 +MMRESULT +OpenMidiDevice( + CHAR device_type, + DWORD device_id, + LPMIDIOPENDESC open_details, + DWORD flags, + DWORD user_data +); +#endif + +MMRESULT +CloseMidiDevice( + PWDMAUD_DEVICE_INFO device +); + +MMRESULT +WriteMidiShort( + PWDMAUD_DEVICE_INFO device, + DWORD message +); + +/* FIXME: Bad params */ +MMRESULT +WriteMidiBuffer(PWDMAUD_DEVICE_INFO device); + +MMRESULT +ResetMidiDevice(PWDMAUD_DEVICE_INFO device); + -MMRESULT WriteWaveData(PWDMAUD_DEVICE_INFO device, PWAVEHDR header); /* threads.c */ diff --git a/reactos/lib/wdmaud/wdmaud.xml b/reactos/lib/wdmaud/wdmaud.xml index a81419d3550..240e163b7d2 100755 --- a/reactos/lib/wdmaud/wdmaud.xml +++ b/reactos/lib/wdmaud/wdmaud.xml @@ -13,7 +13,8 @@ user.c kernel.c devices.c - wavehdr.c + midi.c + wave.c threads.c helper.c memtrack.c