Author: silverblade
Date: Wed Jul 4 14:17:48 2007
New Revision: 27384
URL:
http://svn.reactos.org/svn/reactos?rev=27384&view=rev
Log:
Removing WDMAUD until I figure out how it can be implemented properly
(this will not have any adverse effects as it doesn't actually work
yet.) Also replacing MMDRV with a rewritten version as it appears to
contain big chunks copied directly from NT4 DDK examples!
Added:
trunk/reactos/dll/win32/mmdrv/TODO
trunk/reactos/dll/win32/mmdrv/common.c
trunk/reactos/dll/win32/mmdrv/kernel.c
trunk/reactos/dll/win32/mmdrv/mme.c
trunk/reactos/dll/win32/mmdrv/mmioctl.h
trunk/reactos/dll/win32/mmdrv/session.c
trunk/reactos/dll/win32/mmdrv/wave_io.c
Removed:
trunk/reactos/dll/win32/wdmaud/
Modified:
trunk/reactos/dll/win32/mmdrv/entry.c
trunk/reactos/dll/win32/mmdrv/mmdrv.def
trunk/reactos/dll/win32/mmdrv/mmdrv.h
trunk/reactos/dll/win32/mmdrv/mmdrv.rbuild
trunk/reactos/dll/win32/mmdrv/wave.c
Added: trunk/reactos/dll/win32/mmdrv/TODO
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/TODO?rev=2…
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/TODO (added)
+++ trunk/reactos/dll/win32/mmdrv/TODO Wed Jul 4 14:17:48 2007
@@ -1,0 +1,4 @@
+Jan 2007 TODO list
+
+* Set WHDR_COMPLETE when WriteFileEx APC is called
+* Check for WHDR_COMPLETE flag when completing buffers outside APC
Added: trunk/reactos/dll/win32/mmdrv/common.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/common.c?r…
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/common.c (added)
+++ trunk/reactos/dll/win32/mmdrv/common.c Wed Jul 4 14:17:48 2007
@@ -1,0 +1,258 @@
+/*
+ *
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Multimedia
+ * FILE: dll/win32/mmdrv/common.c
+ * PURPOSE: Multimedia User Mode Driver (Common functions)
+ * PROGRAMMER: Andrew Greenwood
+ * UPDATE HISTORY:
+ * Jan 14, 2007: Created
+ */
+
+#include <mmdrv.h>
+
+/*
+ Translates errors to MMRESULT codes.
+*/
+
+MMRESULT
+ErrorToMmResult(UINT error_code)
+{
+ switch ( error_code )
+ {
+ case NO_ERROR :
+ case ERROR_IO_PENDING :
+ return MMSYSERR_NOERROR;
+
+ case ERROR_BUSY :
+ return MMSYSERR_ALLOCATED;
+
+ case ERROR_NOT_SUPPORTED :
+ case ERROR_INVALID_FUNCTION :
+ return MMSYSERR_NOTSUPPORTED;
+
+ case ERROR_NOT_ENOUGH_MEMORY :
+ return MMSYSERR_NOMEM;
+
+ case ERROR_ACCESS_DENIED :
+ return MMSYSERR_BADDEVICEID;
+
+ case ERROR_INSUFFICIENT_BUFFER :
+ return MMSYSERR_INVALPARAM;
+ };
+
+ /* If all else fails, it's just a plain old error */
+
+ return MMSYSERR_ERROR;
+}
+
+
+/*
+ Obtains a device count for a specific kind of device.
+*/
+
+DWORD
+GetDeviceCount(DeviceType device_type)
+{
+ UINT index = 0;
+ HANDLE handle;
+
+ /* Cycle through devices until an error occurs */
+
+ while ( OpenKernelDevice(device_type, index, GENERIC_READ, &handle) ==
MMSYSERR_NOERROR )
+ {
+ CloseHandle(handle);
+ index ++;
+ }
+
+ DPRINT("Found %d devices of type %d\n", index, device_type);
+
+ return index;
+}
+
+
+/*
+ Obtains device capabilities. This could either be done as individual
+ functions for wave, MIDI and aux, or like this. I chose this method as
+ it centralizes everything.
+*/
+
+DWORD
+GetDeviceCapabilities(
+ DeviceType device_type,
+ DWORD device_id,
+ PVOID capabilities,
+ DWORD capabilities_size)
+{
+ MMRESULT result;
+ DWORD ioctl;
+ HANDLE handle;
+ DWORD bytes_returned;
+ BOOL device_io_result;
+
+ ASSERT(capabilities);
+
+ /* Choose the right IOCTL for the job */
+
+ if ( IsWaveDevice(device_type) )
+ ioctl = IOCTL_WAVE_GET_CAPABILITIES;
+ else if ( IsMidiDevice(device_type) )
+ ioctl = IOCTL_MIDI_GET_CAPABILITIES;
+ else if ( IsAuxDevice(device_type) )
+ return MMSYSERR_NOTSUPPORTED; /* TODO */
+ else
+ return MMSYSERR_NOTSUPPORTED;
+
+ result = OpenKernelDevice(device_type,
+ device_id,
+ GENERIC_READ,
+ &handle);
+
+ if ( result != MMSYSERR_NOERROR )
+ {
+ DPRINT("Failed to open kernel device\n");
+ return result;
+ }
+
+ device_io_result = DeviceIoControl(handle,
+ ioctl,
+ NULL,
+ 0,
+ (LPVOID) capabilities,
+ capabilities_size,
+ &bytes_returned,
+ NULL);
+
+ /* Translate result */
+
+ if ( device_io_result )
+ result = MMSYSERR_NOERROR;
+ else
+ result = ErrorToMmResult(GetLastError());
+
+ /* Clean up and return */
+
+ CloseKernelDevice(handle);
+
+ return result;
+}
+
+
+/*
+ A wrapper around OpenKernelDevice that creates a session,
+ opens the kernel device, initializes session data and notifies
+ the client (application) that the device has been opened. Again,
+ this supports any device type and the only real difference is
+ the open descriptor.
+*/
+
+DWORD
+OpenDevice(
+ DeviceType device_type,
+ DWORD device_id,
+ PVOID open_descriptor,
+ DWORD flags,
+ DWORD private_handle)
+{
+ SessionInfo* session_info;
+ MMRESULT result;
+ DWORD message;
+
+ /* This will automatically check for duplicate sessions */
+ result = CreateSession(device_type, device_id, &session_info);
+
+ if ( result != MMSYSERR_NOERROR )
+ {
+ DPRINT("Couldn't allocate session info\n");
+ return result;
+ }
+
+ result = OpenKernelDevice(device_type,
+ device_id,
+ GENERIC_READ,
+ &session_info->kernel_device_handle);
+
+ if ( result != MMSYSERR_NOERROR )
+ {
+ DPRINT("Failed to open kernel device\n");
+ DestroySession(session_info);
+ return result;
+ }
+
+ /* Set common session data */
+
+ session_info->flags = flags;
+
+ /* Set wave/MIDI specific data */
+
+ if ( IsWaveDevice(device_type) )
+ {
+ LPWAVEOPENDESC wave_open_desc = (LPWAVEOPENDESC) open_descriptor;
+ session_info->callback = wave_open_desc->dwCallback;
+ session_info->mme_wave_handle = wave_open_desc->hWave;
+ session_info->app_user_data = wave_open_desc->dwInstance;
+ }
+ else
+ {
+ DPRINT("Only wave devices are supported at present!\n");
+ DestroySession(session_info);
+ return MMSYSERR_NOTSUPPORTED;
+ }
+
+ /* Start the processing thread */
+
+ result = StartSessionThread(session_info);
+
+ if ( result != MMSYSERR_NOERROR )
+ {
+ DestroySession(session_info);
+ return result;
+ }
+
+ /* Store the session info */
+
+ *((SessionInfo**)private_handle) = session_info;
+
+ /* Send the right message */
+
+ message = (device_type == WaveOutDevice) ? WOM_OPEN :
+ (device_type == WaveInDevice) ? WIM_OPEN :
+ (device_type == MidiOutDevice) ? MOM_OPEN :
+ (device_type == MidiInDevice) ? MIM_OPEN : 0xFFFFFFFF;
+
+ NotifyClient(session_info, message, 0, 0);
+
+ return MMSYSERR_NOERROR;
+}
+
+
+/*
+ Attempts to close a device. This can fail if playback/recording has
+ not been stopped. We need to make sure it's safe to destroy the
+ session as well (mainly by killing the session thread.)
+*/
+
+DWORD
+CloseDevice(
+ DWORD private_handle)
+{
+ MMRESULT result;
+ SessionInfo* session_info = (SessionInfo*) private_handle;
+ /* TODO: Maybe this is best off inside the playback thread? */
+
+ ASSERT(session_info);
+
+ result = CallSessionThread(session_info, WODM_CLOSE, 0);
+
+ if ( result == MMSYSERR_NOERROR )
+ {
+ /* TODO: Wait for it to be safe to terminate */
+
+ CloseKernelDevice(session_info->kernel_device_handle);
+
+ DestroySession(session_info);
+ }
+
+ return result;
+}
+
Modified: trunk/reactos/dll/win32/mmdrv/entry.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/entry.c?re…
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/entry.c (original)
+++ trunk/reactos/dll/win32/mmdrv/entry.c Wed Jul 4 14:17:48 2007
@@ -2,68 +2,42 @@
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
- * FILE: lib/mmdrv/entry.c
- * PURPOSE: Multimedia User Mode Driver
+ * FILE: dll/win32/mmdrv/entry.c
+ * PURPOSE: Multimedia User Mode Driver (DriverProc)
* PROGRAMMER: Andrew Greenwood
- * Aleksey Bragin
* UPDATE HISTORY:
- * Jan 30, 2004: Imported into ReactOS tree (Greenwood)
- * Mar 16, 2004: Cleaned up a bit (Bragin)
+ * Jan 14, 2007: Created
*/
+#include <mmdrv.h>
-#include "mmdrv.h"
-#define NDEBUG
-#include <debug.h>
+/*
+ Nothing particularly special happens here.
-#define EXPORT __declspec(dllexport)
+ Back in the days of Windows 3.1, we would do something more useful here,
+ as this is effectively the old-style equivalent of NT's "DriverEntry",
+ though far more primitive.
-CRITICAL_SECTION DriverSection;
+ In summary, we just implement to satisfy the MME API (winmm) requirements.
+*/
-APIENTRY LONG DriverProc(DWORD DriverID, HANDLE DriverHandle, UINT Message,
- LONG Param1, LONG Param2)
+LONG
+DriverProc(
+ DWORD driver_id,
+ HANDLE driver_handle,
+ UINT message,
+ LONG parameter1,
+ LONG parameter2)
{
- DPRINT("DriverProc\n");
-
-// HINSTANCE Module;
-
- switch(Message)
+ switch ( message )
{
case DRV_LOAD :
DPRINT("DRV_LOAD\n");
- return TRUE; // dont need to do any more
-/*
- Module = GetDriverModuleHandle(DriverHandle);
-
- // Create our process heap
- Heap = GetProcessHeap();
- if (Heap == NULL)
- return FALSE;
-
- DisableThreadLibraryCalls(Module);
- InitializeCriticalSection(&CS);
-
- //
- // Load our device list
- //
-
-// if (sndFindDevices() != MMSYSERR_NOERROR) {
-// DeleteCriticalSection(&mmDrvCritSec);
-// return FALSE;
-// }
-
- return TRUE;
-*/
-// return 1L;
+ return 1L;
case DRV_FREE :
DPRINT("DRV_FREE\n");
-
-// TerminateMidi();
-// TerminateWave();
-
-// DeleteCriticalSection(&CS);
return 1L;
case DRV_OPEN :
@@ -82,6 +56,11 @@
DPRINT("DRV_DISABLE\n");
return 1L;
+ /*
+ We don't provide configuration capabilities. This used to be
+ for things like I/O port, IRQ, DMA settings, etc.
+ */
+
case DRV_QUERYCONFIGURE :
DPRINT("DRV_QUERYCONFIGURE\n");
return 0L;
@@ -93,44 +72,11 @@
case DRV_INSTALL :
DPRINT("DRV_INSTALL\n");
return DRVCNF_RESTART;
+ };
- default :
- DPRINT("?\n");
- return DefDriverProc(DriverID, DriverHandle, Message, Param1, Param2);
- };
+ return DefDriverProc(driver_id,
+ driver_handle,
+ message,
+ parameter1,
+ parameter2);
}
-
-
-BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD Reason, LPVOID Reserved)
-{
- DPRINT("DllMain called!\n");
-
- if (Reason == DLL_PROCESS_ATTACH)
- {
- DisableThreadLibraryCalls(hInstance);
-
- // Create our heap
- Heap = HeapCreate(0, 800, 0);
- if (Heap == NULL)
- return FALSE;
-
- InitializeCriticalSection(&CS);
-
- // OK to do this now??
- FindDevices();
-
- }
- else if (Reason == DLL_PROCESS_DETACH)
- {
- // We need to do cleanup here...
-// TerminateMidi();
-// TerminateWave();
-
- DeleteCriticalSection(&CS);
- HeapDestroy(Heap);
- }
-
- return TRUE;
-}
-
-/* EOF */
Added: trunk/reactos/dll/win32/mmdrv/kernel.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/kernel.c?r…
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/kernel.c (added)
+++ trunk/reactos/dll/win32/mmdrv/kernel.c Wed Jul 4 14:17:48 2007
@@ -1,0 +1,206 @@
+/*
+ *
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Multimedia
+ * FILE: dll/win32/mmdrv/kernel.c
+ * PURPOSE: Multimedia User Mode Driver (kernel interface)
+ * PROGRAMMER: Andrew Greenwood
+ * UPDATE HISTORY:
+ * Jan 14, 2007: Created
+ */
+
+#include <mmdrv.h>
+
+/*
+ Devices that we provide access to follow a standard naming convention.
+ The first wave output, for example, appears as \Device\WaveOut0
+
+ I'm not entirely certain how drivers find a free name to use, or why
+ we need to strip the leading \Device from it when opening, but hey...
+*/
+
+MMRESULT
+CobbleDeviceName(
+ DeviceType device_type,
+ DWORD device_id,
+ PWCHAR out_device_name)
+{
+ WCHAR base_device_name[MAX_DEVICE_NAME_LENGTH];
+
+ /* Work out the base name from the device type */
+
+ switch ( device_type )
+ {
+ case WaveOutDevice :
+ wsprintf(base_device_name, L"%ls", WAVE_OUT_DEVICE_NAME);
+ break;
+
+ case WaveInDevice :
+ wsprintf(base_device_name, L"%ls", WAVE_IN_DEVICE_NAME);
+ break;
+
+ case MidiOutDevice :
+ wsprintf(base_device_name, L"%ls", MIDI_OUT_DEVICE_NAME);
+ break;
+
+ case MidiInDevice :
+ wsprintf(base_device_name, L"%ls", MIDI_IN_DEVICE_NAME);
+ break;
+
+ case AuxDevice :
+ wsprintf(base_device_name, L"%ls", AUX_DEVICE_NAME);
+ break;
+
+ default :
+ return MMSYSERR_BADDEVICEID;
+ };
+
+ /* Now append the device number, removing the leading \Device */
+
+ wsprintf(out_device_name,
+ L"\\\\.%ls%d",
+ base_device_name + strlen("\\Device"),
+ device_id);
+
+ return MMSYSERR_NOERROR;
+}
+
+
+/*
+ Takes a device type (eg: WaveOutDevice), a device ID, desired access and
+ a pointer to a location that will store the handle of the opened "file" if
+ the function succeeds.
+
+ The device type and ID are converted into a device name using the above
+ function.
+*/
+
+MMRESULT
+OpenKernelDevice(
+ DeviceType device_type,
+ DWORD device_id,
+ DWORD access,
+ HANDLE* handle)
+{
+ MMRESULT result;
+ WCHAR device_name[MAX_DEVICE_NAME_LENGTH];
+ DWORD open_flags = 0;
+
+ ASSERT(handle);
+
+ /* Glue the base device name and the ID together */
+
+ result = CobbleDeviceName(device_type, device_id, device_name);
+
+ DPRINT("Opening kernel device %ls\n", device_name);
+
+ if ( result != MMSYSERR_NOERROR )
+ return result;
+
+ /* We want overlapped I/O when writing */
+
+ if ( access != GENERIC_READ )
+ open_flags = FILE_FLAG_OVERLAPPED;
+
+ /* Now try opening... */
+
+ *handle = CreateFile(device_name,
+ access,
+ FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ open_flags,
+ NULL);
+
+ if ( *handle == INVALID_HANDLE_VALUE )
+ return ErrorToMmResult(GetLastError());
+
+ return MMSYSERR_NOERROR;
+}
+
+
+/*
+ Just an alias for the benefit of having a pair of functions ;)
+*/
+
+void
+CloseKernelDevice(HANDLE device_handle)
+{
+ CloseHandle(device_handle);
+}
+
+
+MMRESULT
+SetDeviceData(
+ HANDLE device_handle,
+ DWORD ioctl,
+ PBYTE input_buffer,
+ DWORD buffer_size)
+{
+ DPRINT("SetDeviceData\n");
+ /* TODO */
+ return 0;
+}
+
+
+MMRESULT
+GetDeviceData(
+ HANDLE device_handle,
+ DWORD ioctl,
+ PBYTE output_buffer,
+ DWORD buffer_size)
+{
+ OVERLAPPED overlap;
+ DWORD bytes_returned;
+ BOOL success;
+ DWORD transfer;
+
+ DPRINT("GetDeviceData\n");
+
+ memset(&overlap, 0, sizeof(overlap));
+
+ overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ if ( ! overlap.hEvent )
+ return MMSYSERR_NOMEM;
+
+ success = DeviceIoControl(device_handle,
+ ioctl,
+ NULL,
+ 0,
+ output_buffer,
+ buffer_size,
+ &bytes_returned,
+ &overlap);
+
+ if ( ! success )
+ {
+ if ( GetLastError() == ERROR_IO_PENDING )
+ {
+ if ( ! GetOverlappedResult(device_handle, &overlap, &transfer, TRUE)
)
+ {
+ CloseHandle(overlap.hEvent);
+ return ErrorToMmResult(GetLastError());
+ }
+ }
+ else
+ {
+ CloseHandle(overlap.hEvent);
+ return ErrorToMmResult(GetLastError());
+ }
+ }
+
+ while ( TRUE )
+ {
+ SetEvent(overlap.hEvent);
+
+ if ( WaitForSingleObjectEx(overlap.hEvent, 0, TRUE) != WAIT_IO_COMPLETION )
+ {
+ break;
+ }
+ }
+
+ CloseHandle(overlap.hEvent);
+
+ return MMSYSERR_NOERROR;
+}
Modified: trunk/reactos/dll/win32/mmdrv/mmdrv.def
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/mmdrv.def?…
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/mmdrv.def (original)
+++ trunk/reactos/dll/win32/mmdrv/mmdrv.def Wed Jul 4 14:17:48 2007
@@ -7,8 +7,8 @@
LIBRARY mmdrv.dll
EXPORTS
DriverProc@20
-widMessage@20
+;widMessage@20
wodMessage@20
-midMessage@20
-modMessage@20
-auxMessage@20
+;midMessage@20
+;modMessage@20
+;auxMessage@20
Modified: trunk/reactos/dll/win32/mmdrv/mmdrv.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/mmdrv.h?re…
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/mmdrv.h (original)
+++ trunk/reactos/dll/win32/mmdrv/mmdrv.h Wed Jul 4 14:17:48 2007
@@ -2,117 +2,337 @@
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
- * FILE: lib/mmdrv/mmdrv.h
+ * FILE: dll/win32/mmdrv/mmdrv.h
* PURPOSE: Multimedia User Mode Driver (header)
* PROGRAMMER: Andrew Greenwood
* Aleksey Bragin
* UPDATE HISTORY:
* Jan 30, 2004: Imported into ReactOS tree
+ * Jan 10, 2007: Rewritten and tidied up
*/
-#ifndef __INCLUDES_MMDRV_H__
-#define __INCLUDES_MMDRV_H__
-
-//#define UNICODE
-
-#define EXPORT __declspec(dllexport)
-
+#ifndef MMDRV_H
+#define MMDRV_H
+
+#include <mmioctl.h>
+#include <mmddk.h>
#include <stdio.h>
-#include <windows.h>
-#include <mmsystem.h>
-#include <mmddk.h>
-
-// This needs to be done to get winioctl.h to work:
-//typedef unsigned __int64 DWORD64, *PDWORD64;
-
-#include <winioctl.h>
-//#include "mmddk.h"
-
-#include "mmdef.h"
-
-ULONG DbgPrint(PCCH Format, ...);
-
-/*
-#define SOUND_MAX_DEVICE_NAME 1024 // GUESSWORK
-#define SOUND_MAX_DEVICES 256 // GUESSWORK
-*/
-
-// If the root is \Device and the Device type is
-// WaveIn and the device number is 2, the full name is \Device\WaveIn2
-
-#define WAVE_IN_DEVICE_NAME "\\Device\\WaveIn"
-#define WAVE_IN_DEVICE_NAME_U L"\\Device\\WaveIn"
-#define WAVE_OUT_DEVICE_NAME "\\Device\\WaveOut"
-#define WAVE_OUT_DEVICE_NAME_U L"\\Device\\WaveOut"
-
-#define MIDI_IN_DEVICE_NAME "\\Device\\MidiIn"
-#define MIDI_IN_DEVICE_NAME_U L"\\Device\\MidiIn"
-#define MIDI_OUT_DEVICE_NAME "\\Device\\MidiOut"
-#define MIDI_OUT_DEVICE_NAME_U L"\\Device\\MidiOut"
-
-#define AUX_DEVICE_NAME "\\Device\\MMAux"
-#define AUX_DEVICE_NAME_U L"\\Device\\MMAux"
-
-/*
-#define IOCTL_SOUND_BASE FILE_DEVICE_SOUND
-#define IOCTL_WAVE_BASE 0x0000
-#define IOCTL_MIDI_BASE 0x0080
-
-// Wave device driver IOCTLs
-
-#define IOCTL_WAVE_QUERY_FORMAT CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE +
0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
-#define IOCTL_WAVE_SET_FORMAT CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE +
0x0002, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_GET_CAPABILITIES CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE +
0x0003, METHOD_BUFFERED, FILE_READ_ACCESS)
-#define IOCTL_WAVE_SET_STATE CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE +
0x0004, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_GET_STATE CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE +
0x0005, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_GET_POSITION CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE +
0x0006, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_SET_VOLUME CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE +
0x0007, METHOD_BUFFERED, FILE_READ_ACCESS)
-#define IOCTL_WAVE_GET_VOLUME CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE +
0x0008, METHOD_BUFFERED, FILE_READ_ACCESS)
-#define IOCTL_WAVE_SET_PITCH CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE +
0x0009, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_GET_PITCH CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE +
0x000A, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_SET_PLAYBACK_RATE CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE +
0x000B, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_GET_PLAYBACK_RATE CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE +
0x000C, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_PLAY CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE +
0x000D, METHOD_IN_DIRECT, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_RECORD CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE +
0x000E, METHOD_OUT_DIRECT, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_BREAK_LOOP CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE +
0x000F, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_WAVE_SET_LOW_PRIORITY CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE +
0x0010, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-
-// MIDI device driver IOCTLs
-
-#define IOCTL_MIDI_GET_CAPABILITIES CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE +
0x0001, METHOD_BUFFERED, FILE_READ_ACCESS)
-#define IOCTL_MIDI_SET_STATE CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE +
0x0002, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_MIDI_GET_STATE CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE +
0x0003, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_MIDI_SET_VOLUME CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE +
0x0004, METHOD_BUFFERED, FILE_READ_ACCESS)
-#define IOCTL_MIDI_GET_VOLUME CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE +
0x0005, METHOD_BUFFERED, FILE_READ_ACCESS)
-#define IOCTL_MIDI_PLAY CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE +
0x0006, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_MIDI_RECORD CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE +
0x0007, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_MIDI_CACHE_PATCHES CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE +
0x0008, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-#define IOCTL_MIDI_CACHE_DRUM_PATCHES CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE +
0x0009, METHOD_BUFFERED, FILE_WRITE_ACCESS)
-*/
-
-
-CRITICAL_SECTION CS; // Serialize access to device lists
-
-HANDLE Heap;
-
- enum {
- InvalidDevice,
- WaveInDevice,
- WaveOutDevice,
- MidiInDevice,
- MidiOutDevice,
- AuxDevice
-};
-
-MMRESULT OpenDevice(UINT DeviceType, DWORD ID, PHANDLE pDeviceHandle,
- DWORD Access);
-
-MMRESULT FindDevices();
-
-DWORD GetDeviceCount(UINT DeviceType);
-
-DWORD TranslateStatus(void);
+#define DPRINT printf
+
+
+/* Need to check these */
+#define MAX_DEVICES 256
+#define MAX_DEVICE_NAME_LENGTH 256
+#define MAX_BUFFER_SIZE 1048576
+#define MAX_WAVE_BYTES 1048576
+
+/* Custom flag set when overlapped I/O is done */
+#define WHDR_COMPLETE 0x80000000
+
+
+/*
+ The kinds of devices which MMSYSTEM/WINMM may request from us.
+*/
+
+typedef enum
+{
+ WaveOutDevice,
+ WaveInDevice,
+ MidiOutDevice,
+ MidiInDevice,
+ AuxDevice
+} DeviceType;
+
+#define IsWaveDevice(devicetype) \
+ ( ( devicetype == WaveOutDevice ) || ( devicetype == WaveInDevice ) )
+
+#define IsMidiDevice(devicetype) \
+ ( ( devicetype == MidiOutDevice ) || ( devicetype == MidiInDevice ) )
+
+#define IsAuxDevice(devicetype) \
+ ( devicetype == AuxDevice )
+
+
+/*
+ We use these structures to store information regarding open devices. Since
+ the main structure gets destroyed when a device is closed, I call this a
+ "session".
+*/
+
+typedef struct
+{
+ OVERLAPPED overlap;
+ LPWAVEHDR header;
+} WaveOverlapInfo;
+
+/*
+typedef enum
+{
+ WaveAddBuffer,
+ WaveClose,
+ WaveReset,
+ WaveRestart,
+ SessionThreadTerminate,
+ InvalidFunction
+} ThreadFunction;
+*/
+
+/* Our own values, used with the session threads */
+typedef DWORD ThreadFunction;
+#define DRVM_TERMINATE 0xFFFFFFFE
+#define DRVM_INVALID 0xFFFFFFFF
+
+typedef enum
+{
+ WavePlaying,
+ WaveStopped,
+ WaveReset,
+ WaveRestart
+} WaveState;
+
+typedef union
+{
+ PWAVEHDR wave_header;
+ PMIDIHDR midi_header;
+} MediaHeader;
+
+/*
+typedef union
+{
+ MediaHeader header;
+} ThreadParameter;
+*/
+
+typedef struct _ThreadInfo
+{
+ HANDLE handle;
+ HANDLE ready_event;
+ HANDLE go_event;
+
+ /*ThreadFunction function;*/
+ DWORD function;
+ PVOID parameter;
+
+ MMRESULT result;
+} ThreadInfo;
+
+typedef struct _LoopInfo
+{
+ PWAVEHDR head;
+ DWORD iterations;
+} LoopInfo;
+
+typedef struct _SessionInfo
+{
+ struct _SessionInfo* next;
+
+ DeviceType device_type;
+ DWORD device_id;
+
+ HANDLE kernel_device_handle;
+
+ /* These are all the same */
+ union
+ {
+ HDRVR mme_handle;
+ HWAVE mme_wave_handle;
+ HMIDI mme_midi_handle;
+ };
+
+ /* If playback is paused or not */
+ BOOL is_paused;
+
+ /* Stuff passed to us from winmm */
+ DWORD app_user_data;
+ DWORD callback;
+
+ DWORD flags;
+
+ /* Can only be one or the other */
+ union
+ {
+ PWAVEHDR wave_queue;
+ PMIDIHDR midi_queue;
+ };
+
+ /* Current playback point */
+ //PWAVEHDR next_buffer;
+
+ /* Where in the current buffer we are */
+ DWORD buffer_position;
+
+// DWORD remaining_bytes;
+
+ LoopInfo loop;
+
+ ThreadInfo thread;
+} SessionInfo;
+
+#undef ASSERT
+#define ASSERT(condition) \
+ if ( ! (condition) ) \
+ DPRINT("ASSERT FAILED: %s\n", #condition);
+
+/*
+ MME interface
+*/
+
+BOOL
+NotifyClient(
+ SessionInfo* session_info,
+ DWORD message,
+ DWORD parameter1,
+ DWORD parameter2);
+
+
+/*
+ Helpers
+*/
+
+MMRESULT
+ErrorToMmResult(UINT error_code);
+
+
+/* Kernel interface */
+
+MMRESULT
+CobbleDeviceName(
+ DeviceType device_type,
+ DWORD device_id,
+ PWCHAR out_device_name);
+
+MMRESULT
+OpenKernelDevice(
+ DeviceType device_type,
+ DWORD device_id,
+ DWORD access,
+ HANDLE* handle);
+
+VOID
+CloseKernelDevice(HANDLE device_handle);
+
+MMRESULT
+SetDeviceData(
+ HANDLE device_handle,
+ DWORD ioctl,
+ PBYTE input_buffer,
+ DWORD buffer_size);
+
+MMRESULT
+GetDeviceData(
+ HANDLE device_handle,
+ DWORD ioctl,
+ PBYTE output_buffer,
+ DWORD buffer_size);
+
+
+/* Session management */
+
+MMRESULT
+CreateSession(
+ DeviceType device_type,
+ DWORD device_id,
+ SessionInfo** session_info);
+
+VOID
+DestroySession(SessionInfo* session);
+
+SessionInfo*
+GetSession(
+ DeviceType device_type,
+ DWORD device_id);
+
+MMRESULT
+StartSessionThread(SessionInfo* session_info);
+
+MMRESULT
+CallSessionThread(
+ SessionInfo* session_info,
+ ThreadFunction function,
+ PVOID thread_parameter);
+
+DWORD
+HandleBySessionThread(
+ DWORD private_handle,
+ DWORD message,
+ DWORD parameter);
+
+
+/* General */
+
+DWORD
+GetDeviceCount(DeviceType device_type);
+
+DWORD
+GetDeviceCapabilities(
+ DeviceType device_type,
+ DWORD device_id,
+ PVOID capabilities,
+ DWORD capabilities_size);
+
+DWORD
+OpenDevice(
+ DeviceType device_type,
+ DWORD device_id,
+ PVOID open_descriptor,
+ DWORD flags,
+ DWORD private_handle);
+
+DWORD
+CloseDevice(
+ DWORD private_handle);
+
+DWORD
+PauseDevice(
+ DWORD private_handle);
+
+DWORD
+RestartDevice(
+ DWORD private_handle);
+
+DWORD
+ResetDevice(
+ DWORD private_handle);
+
+DWORD
+GetPosition(
+ DWORD private_handle,
+ PMMTIME time,
+ DWORD time_size);
+
+DWORD
+BreakLoop(DWORD private_handle);
+
+DWORD
+QueryWaveFormat(
+ DeviceType device_type,
+ PVOID lpFormat);
+
+DWORD
+WriteWaveBuffer(
+ DWORD private_handle,
+ PWAVEHDR wave_header,
+ DWORD wave_header_size);
+
+
+
+
+
+/* wave thread */
+
+DWORD
+WaveThread(LPVOID parameter);
+
+
+/* Wave I/O */
+
+VOID
+PerformWaveIO(SessionInfo* session_info);
+
+
+CRITICAL_SECTION critical_section;
+
#endif
Modified: trunk/reactos/dll/win32/mmdrv/mmdrv.rbuild
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/mmdrv.rbui…
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/mmdrv.rbuild (original)
+++ trunk/reactos/dll/win32/mmdrv/mmdrv.rbuild Wed Jul 4 14:17:48 2007
@@ -8,9 +8,11 @@
<library>kernel32</library>
<library>user32</library>
<library>winmm</library>
- <file>auxil.c</file>
<file>entry.c</file>
- <file>midi.c</file>
- <file>utils.c</file>
+ <file>mme.c</file>
+ <file>kernel.c</file>
+ <file>session.c</file>
+ <file>common.c</file>
<file>wave.c</file>
+ <file>wave_io.c</file>
</module>
Added: trunk/reactos/dll/win32/mmdrv/mme.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/mme.c?rev=…
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/mme.c (added)
+++ trunk/reactos/dll/win32/mmdrv/mme.c Wed Jul 4 14:17:48 2007
@@ -1,0 +1,143 @@
+/*
+ *
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Multimedia
+ * FILE: dll/win32/mmdrv/mme.c
+ * PURPOSE: Multimedia User Mode Driver (MME Interface)
+ * PROGRAMMER: Andrew Greenwood
+ * Aleksey Bragin
+ * UPDATE HISTORY:
+ * Jan 14, 2007: Rewritten and tidied up
+ */
+
+#include <mmdrv.h>
+
+/*
+ Sends a message to the client (application), such as WOM_DONE. This
+ is just a wrapper around DriverCallback which translates the
+ parameters appropriately.
+*/
+
+BOOL
+NotifyClient(
+ SessionInfo* session_info,
+ DWORD message,
+ DWORD parameter1,
+ DWORD parameter2)
+{
+ return DriverCallback(session_info->callback,
+ HIWORD(session_info->flags),
+ session_info->mme_handle,
+ message,
+ session_info->app_user_data,
+ parameter1,
+ parameter2);
+}
+
+
+
+/*
+ MME Driver Entrypoint
+ Wave Output
+*/
+
+APIENTRY DWORD
+wodMessage(
+ DWORD device_id,
+ DWORD message,
+ DWORD private_handle,
+ DWORD parameter1,
+ DWORD parameter2)
+{
+ switch ( message )
+ {
+ /*
http://www.osronline.com/ddkx/w98ddk/mmedia_4p80.htm */
+ case WODM_GETNUMDEVS :
+ DPRINT("WODM_GETNUMDEVS\n");
+ return GetDeviceCount(WaveOutDevice);
+
+ /*
http://www.osronline.com/ddkx/w98ddk/mmedia_4p6h.htm */
+ case WODM_GETDEVCAPS :
+ DPRINT("WODM_GETDEVCAPS\n");
+ return GetDeviceCapabilities(WaveOutDevice,
+ device_id,
+ (PVOID) parameter1,
+ parameter2);
+
+ /*
http://www.osronline.com/ddkx/w98ddk/mmedia_4p85.htm */
+ case WODM_OPEN :
+ {
+ WAVEOPENDESC* open_desc = (WAVEOPENDESC*) parameter1;
+ DPRINT("WODM_OPEN\n");
+
+ if ( parameter2 && WAVE_FORMAT_QUERY )
+ return QueryWaveFormat(WaveOutDevice, open_desc->lpFormat);
+ else
+ return OpenDevice(WaveOutDevice,
+ device_id,
+ open_desc,
+ parameter2,
+ private_handle);
+ }
+
+ /*
http://www.osronline.com/ddkx/w98ddk/mmedia_4p6g.htm */
+ case WODM_CLOSE :
+ {
+ DPRINT("WODM_CLOSE\n");
+ return CloseDevice(private_handle);
+ }
+
+ /*
http://www.osronline.com/ddkx/w98ddk/mmedia_4p9w.htm */
+ case WODM_WRITE :
+ {
+ DPRINT("WODM_WRITE\n");
+ return WriteWaveBuffer(private_handle,
+ (PWAVEHDR) parameter1,
+ parameter2);
+ }
+
+ /*
http://www.osronline.com/ddkx/w98ddk/mmedia_4p86.htm */
+ case WODM_PAUSE :
+ {
+ DPRINT("WODM_PAUSE\n");
+ return HandleBySessionThread(private_handle, message, 0);
+ }
+
+ /*
http://www.osronline.com/ddkx/w98ddk/mmedia_4p89.htm */
+ case WODM_RESTART :
+ {
+ DPRINT("WODM_RESTART\n");
+ return HandleBySessionThread(private_handle, message, 0);
+ }
+
+ /*
http://www.osronline.com/ddkx/w98ddk/mmedia_4p88.htm */
+ case WODM_RESET :
+ {
+ DPRINT("WODM_RESET\n");
+ return HandleBySessionThread(private_handle, message, 0);
+ }
+
+ /*
http://www.osronline.com/ddkx/w98ddk/mmedia_4p83.htm */
+#if 0
+ case WODM_GETPOS :
+ {
+ DPRINT("WODM_GETPOS\n");
+ return GetPosition(private_handle,
+ (PMMTIME) parameter1,
+ parameter2);
+ }
+#endif
+
+ /*
http://www.osronline.com/ddkx/w98ddk/mmedia_4p6f.htm */
+ case WODM_BREAKLOOP :
+ {
+ DPRINT("WODM_BREAKLOOP\n");
+ return HandleBySessionThread(private_handle, message, 0);
+ }
+
+ /* TODO: Others */
+ }
+
+ DPRINT("Unsupported message\n");
+ return MMSYSERR_NOTSUPPORTED;
+}
Added: trunk/reactos/dll/win32/mmdrv/mmioctl.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/mmioctl.h?…
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/mmioctl.h (added)
+++ trunk/reactos/dll/win32/mmdrv/mmioctl.h Wed Jul 4 14:17:48 2007
@@ -1,0 +1,147 @@
+/*
+ *
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Multimedia
+ * FILE: dll/win32/mmdrv/mmioctl.h
+ * PURPOSE: Multimedia system NT4 compatibility
+ * PROGRAMMER: Andrew Greenwood
+ * UPDATE HISTORY:
+ * Jan 13, 2007: Split from mmdrv.h
+ */
+
+#ifndef MMDRV_IOCTLS
+#define MMDRV_IOCTLS
+
+
+#include <windows.h>
+#include <mmsystem.h>
+#include <mmddk.h>
+#include <winioctl.h>
+
+
+/*
+ Base names of the supported devices, as provided by drivers running in
+ kernel mode.
+
+ \Device\WaveIn0 etc.
+*/
+
+#define WAVE_OUT_DEVICE_NAME L"\\Device\\WaveOut"
+#define WAVE_IN_DEVICE_NAME L"\\Device\\WaveIn"
+#define MIDI_OUT_DEVICE_NAME L"\\Device\\MidiOut"
+#define MIDI_IN_DEVICE_NAME L"\\Device\\MidiIn"
+#define AUX_DEVICE_NAME L"\\Device\\MMAux"
+
+
+/*
+ Base IOCTL codes
+*/
+
+#define IOCTL_SOUND_BASE FILE_DEVICE_SOUND
+#define IOCTL_WAVE_BASE 0x0000
+#define IOCTL_MIDI_BASE 0x0080
+#define IOCTL_AUX_BASE 0x0100
+
+
+/*
+ Wave IOCTLs
+*/
+
+#define IOCTL_WAVE_QUERY_FORMAT \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0001, METHOD_BUFFERED,
FILE_READ_ACCESS)
+
+#define IOCTL_WAVE_SET_FORMAT \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0002, METHOD_BUFFERED,
FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_GET_CAPABILITIES \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0003, METHOD_BUFFERED,
FILE_READ_ACCESS)
+
+#define IOCTL_WAVE_SET_STATE \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0004, METHOD_BUFFERED,
FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_GET_STATE \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0005, METHOD_BUFFERED,
FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_GET_POSITION \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0006, METHOD_BUFFERED,
FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_SET_VOLUME \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0007, METHOD_BUFFERED,
FILE_READ_ACCESS)
+
+#define IOCTL_WAVE_GET_VOLUME \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0008, METHOD_BUFFERED,
FILE_READ_ACCESS)
+
+#define IOCTL_WAVE_SET_PITCH \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0009, METHOD_BUFFERED,
FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_GET_PITCH \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000A, METHOD_BUFFERED,
FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_SET_PLAYBACK_RATE \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000B, METHOD_BUFFERED,
FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_GET_PLAYBACK_RATE \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000C, METHOD_BUFFERED,
FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_PLAY \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000D, METHOD_IN_DIRECT,
FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_RECORD \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000E, METHOD_OUT_DIRECT,
FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_BREAK_LOOP \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x000F, METHOD_BUFFERED,
FILE_WRITE_ACCESS)
+
+#define IOCTL_WAVE_SET_LOW_PRIORITY \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_WAVE_BASE + 0x0010, METHOD_BUFFERED,
FILE_WRITE_ACCESS)
+
+
+/*
+ MIDI IOCTLs
+*/
+
+#define IOCTL_MIDI_GET_CAPABILITIES \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0001, METHOD_BUFFERED,
FILE_READ_ACCESS)
+
+#define IOCTL_MIDI_SET_STATE \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0002, METHOD_BUFFERED,
FILE_WRITE_ACCESS)
+
+#define IOCTL_MIDI_GET_STATE \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0003, METHOD_BUFFERED,
FILE_WRITE_ACCESS)
+
+#define IOCTL_MIDI_SET_VOLUME \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0004, METHOD_BUFFERED,
FILE_READ_ACCESS)
+
+#define IOCTL_MIDI_GET_VOLUME \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0005, METHOD_BUFFERED,
FILE_READ_ACCESS)
+
+#define IOCTL_MIDI_PLAY \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0006, METHOD_BUFFERED,
FILE_WRITE_ACCESS)
+
+#define IOCTL_MIDI_RECORD \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0007, METHOD_BUFFERED,
FILE_WRITE_ACCESS)
+
+#define IOCTL_MIDI_CACHE_PATCHES \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0008, METHOD_BUFFERED,
FILE_WRITE_ACCESS)
+
+#define IOCTL_MIDI_CACHE_DRUM_PATCHES \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_MIDI_BASE + 0x0009, METHOD_BUFFERED,
FILE_WRITE_ACCESS)
+
+
+/*
+ Aux IOCTLs
+*/
+
+#define IOCTL_AUX_GET_CAPABILITIES \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_AUX_BASE + 0x0001, METHOD_BUFFERED,
FILE_READ_ACCESS)
+
+#define IOCTL_AUX_SET_VOLUME \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_AUX_BASE + 0x0002, METHOD_BUFFERED,
FILE_READ_ACCESS)
+
+#define IOCTL_AUX_GET_VOLUME \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_AUX_BASE + 0x0003, METHOD_BUFFERED,
FILE_READ_ACCESS)
+
+#define IOCTL_SOUND_GET_CHANGED_VOLUME \
+ CTL_CODE(IOCTL_SOUND_BASE, IOCTL_AUX_BASE + 0x0004, METHOD_BUFFERED,
FILE_READ_ACCESS)
+
+#endif
Added: trunk/reactos/dll/win32/mmdrv/session.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/session.c?…
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/session.c (added)
+++ trunk/reactos/dll/win32/mmdrv/session.c Wed Jul 4 14:17:48 2007
@@ -1,0 +1,245 @@
+/*
+ *
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Multimedia
+ * FILE: dll/win32/mmdrv/session.c
+ * PURPOSE: Multimedia User Mode Driver (session management)
+ * PROGRAMMER: Andrew Greenwood
+ * UPDATE HISTORY:
+ * Jan 14, 2007: Created
+ */
+
+#include <mmdrv.h>
+
+/* Each session is tracked, but the list must be locked when in use */
+
+SessionInfo* session_list = NULL;
+CRITICAL_SECTION session_lock;
+
+
+/*
+ Obtains a pointer to the session associated with a device type and ID.
+ If no session exists, returns NULL. This is mainly used to see if a
+ session already exists prior to creating a new one.
+*/
+
+SessionInfo*
+GetSession(
+ DeviceType device_type,
+ DWORD device_id)
+{
+ SessionInfo* session_info;
+
+ EnterCriticalSection(&session_lock);
+ session_info = session_list;
+
+ while ( session_info )
+ {
+ if ( ( session_info->device_type == device_type ) &&
+ ( session_info->device_id == device_id ) )
+ {
+ LeaveCriticalSection(&session_lock);
+ return session_info;
+ }
+
+ session_info = session_info->next;
+ }
+
+ LeaveCriticalSection(&session_lock);
+ return NULL;
+}
+
+
+/*
+ Creates a new session, associated with the specified device type and ID.
+ Whilst the session list is locked, this also checks to see if an existing
+ session is associated with the device.
+*/
+
+MMRESULT
+CreateSession(
+ DeviceType device_type,
+ DWORD device_id,
+ SessionInfo** session_info)
+{
+ HANDLE heap = GetProcessHeap();
+
+ ASSERT(session_info);
+
+ EnterCriticalSection(&session_lock);
+
+ /* Ensure we're not creating a duplicate session */
+
+ if ( GetSession(device_type, device_id) )
+ {
+ DPRINT("Already allocated session\n");
+ LeaveCriticalSection(&session_lock);
+ return MMSYSERR_ALLOCATED;
+ }
+
+ *session_info = HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(SessionInfo));
+
+ if ( ! *session_info )
+ {
+ DPRINT("Failed to allocate mem for session info\n");
+ LeaveCriticalSection(&session_lock);
+ return MMSYSERR_NOMEM;
+ }
+
+ (*session_info)->device_type = device_type;
+ (*session_info)->device_id = device_id;
+
+ /* Add to the list */
+
+ (*session_info)->next = session_list;
+ session_list = *session_info;
+
+ LeaveCriticalSection(&session_lock);
+
+ return MMSYSERR_NOERROR;
+}
+
+
+/*
+ Removes a session from the list and destroys it. This function does NOT
+ perform any additional cleanup. Think of it as a slightly more advanced
+ free()
+*/
+
+VOID
+DestroySession(SessionInfo* session)
+{
+ HANDLE heap = GetProcessHeap();
+ SessionInfo* session_node;
+ SessionInfo* session_prev;
+
+ /* TODO: More cleanup stuff */
+
+ /* Remove from the list */
+
+ EnterCriticalSection(&session_lock);
+
+ session_node = session_list;
+ session_prev = NULL;
+
+ while ( session_node )
+ {
+ if ( session_node == session )
+ {
+ /* Bridge the gap for when we go */
+ session_prev->next = session->next;
+ break;
+ }
+
+ /* Save the previous node, fetch the next */
+ session_prev = session_node;
+ session_node = session_node->next;
+ }
+
+ LeaveCriticalSection(&session_lock);
+
+ HeapFree(heap, 0, session);
+}
+
+
+/*
+ Allocates events and other resources for the session thread, starts it,
+ and waits for it to announce that it is ready to work for us.
+*/
+
+MMRESULT
+StartSessionThread(SessionInfo* session_info)
+{
+ LPTASKCALLBACK task;
+ MMRESULT result;
+
+ ASSERT(session_info);
+
+ /* This is our "ready" event, sent when the thread is idle */
+
+ session_info->thread.ready_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ if ( ! session_info->thread.ready_event )
+ {
+ DPRINT("Couldn't create thread_ready event\n");
+ return MMSYSERR_NOMEM;
+ }
+
+ /* This is our "go" event, sent when we want the thread to do something */
+
+ session_info->thread.go_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+ if ( ! session_info->thread.go_event )
+ {
+ DPRINT("Couldn't create thread_go event\n");
+ CloseHandle(session_info->thread.ready_event);
+ return MMSYSERR_NOMEM;
+ }
+
+ /* TODO - other kinds of devices need attention, too */
+ task = ( session_info->device_type == WaveOutDevice )
+ ? (LPTASKCALLBACK) WaveThread : NULL;
+
+ ASSERT(task);
+
+ /* Effectively, this is a beefed-up CreateThread */
+
+ result = mmTaskCreate(task,
+ &session_info->thread.handle,
+ (DWORD) session_info);
+
+ if ( result != MMSYSERR_NOERROR )
+ {
+ DPRINT("Task creation failed\n");
+ CloseHandle(session_info->thread.ready_event);
+ CloseHandle(session_info->thread.go_event);
+ return result;
+ }
+
+ /* Wait for the thread to be ready before completing */
+
+ WaitForSingleObject(session_info->thread.ready_event, INFINITE);
+
+ return MMSYSERR_NOERROR;
+}
+
+
+/*
+ The session thread is pretty simple. Upon creation, it announces that it
+ is ready to do stuff for us. When we want it to perform an action, we use
+ CallSessionThread with an appropriate function and parameter, then tell
+ the thread we want it to do something. When it's finished, it announces
+ that it is ready once again.
+*/
+
+MMRESULT
+CallSessionThread(
+ SessionInfo* session_info,
+ ThreadFunction function,
+ PVOID thread_parameter)
+{
+ ASSERT(session_info);
+
+ session_info->thread.function = function;
+ session_info->thread.parameter = thread_parameter;
+
+ DPRINT("Calling session thread\n");
+ SetEvent(session_info->thread.go_event);
+
+ DPRINT("Waiting for thread response\n");
+ WaitForSingleObject(session_info->thread.ready_event, INFINITE);
+
+ return session_info->thread.result;
+}
+
+
+DWORD
+HandleBySessionThread(
+ DWORD private_handle,
+ DWORD message,
+ DWORD parameter)
+{
+ return CallSessionThread((SessionInfo*) private_handle,
+ message,
+ (PVOID) parameter);
+}
Modified: trunk/reactos/dll/win32/mmdrv/wave.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/wave.c?rev…
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/wave.c (original)
+++ trunk/reactos/dll/win32/mmdrv/wave.c Wed Jul 4 14:17:48 2007
@@ -2,1047 +2,380 @@
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Multimedia
- * FILE: lib/mmdrv/wave.c
- * PURPOSE: Multimedia User Mode Driver
+ * FILE: dll/win32/mmdrv/wave.c
+ * PURPOSE: Multimedia User Mode Driver (Wave Audio)
* PROGRAMMER: Andrew Greenwood
- * Aleksey Bragin (aleksey at
studiocerebral.com)
* UPDATE HISTORY:
- * Jan 30, 2004: Imported into ReactOS tree (Greenwood)
- * Mar 16, 2004: Implemented some funcs (Bragin)
+ * Jan 30, 2004: Imported into ReactOS tree
+ * Jan 14, 2007: Rewritten and tidied up
*/
-#include "mmdrv.h"
-#include "wave.h"
-
-#define NDEBUG
-#include <debug.h>
-
-#define WHDR_COMPLETE 0x80000000
-#define MAX_BUFFER_SIZE 8192
-#define MAX_WAVE_BYTES 5*MAX_BUFFER_SIZE
-
-PWAVEALLOC WaveLists;
-
-static MMRESULT waveReadWrite(PWAVEALLOC pClient);
-void wavePartialOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED
pOverlapped);
-void waveOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped);
-void waveLoopOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped);
-void waveBreakOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped);
-static MMRESULT waveSetState(PWAVEALLOC pClient, ULONG State);
-
-/* ============================
- * INTERNAL
- * functions start here
- * ============================
- */
-
-MMRESULT GetDeviceCapabilities(DWORD ID, UINT DeviceType,
- LPBYTE pCaps, DWORD Size)
-{
- HANDLE DeviceHandle = NULL;
- MMRESULT Result = MMSYSERR_NOERROR;
- DWORD BytesReturned = 0;
-
- // Open the wave device
-
- Result = OpenDevice(DeviceType, ID, &DeviceHandle, GENERIC_READ);
- if (Result != MMSYSERR_NOERROR)
- return Result;
-
- if ((DeviceType == WaveOutDevice) || (DeviceType == WaveInDevice))
- {
- Result = DeviceIoControl(DeviceHandle, IOCTL_WAVE_GET_CAPABILITIES,
- NULL, 0, (LPVOID)pCaps, Size,
- &BytesReturned, NULL) ? MMSYSERR_NOERROR : TranslateStatus();
- }
-
- else if ((DeviceType == MidiInDevice) || (DeviceType == MidiOutDevice))
- {
- Result = DeviceIoControl(DeviceHandle, IOCTL_MIDI_GET_CAPABILITIES,
- NULL, 0, (LPVOID)pCaps, Size,
- &BytesReturned, NULL) ? MMSYSERR_NOERROR : TranslateStatus();
- }
-
- else if (DeviceType == AuxDevice)
- {
- Result = DeviceIoControl(DeviceHandle, IOCTL_AUX_GET_CAPABILITIES,
- NULL, 0, (LPVOID)pCaps, Size,
- &BytesReturned, NULL) ? MMSYSERR_NOERROR : TranslateStatus();
- }
-
- // Close the handle and return the result code
- CloseHandle(DeviceHandle);
-
- return Result;
-}
-
-static DWORD waveThread(LPVOID lpParameter)
-{
-
- PWAVEALLOC pClient = (PWAVEALLOC)lpParameter;
- BOOL Terminate = FALSE;
-
+#include <mmdrv.h>
+
+
+#define MAX_WAVE_BUFFER_SIZE 65536
+
+
+MMRESULT
+QueueWaveBuffer(
+ SessionInfo* session_info,
+ LPWAVEHDR wave_header)
+{
+ PWAVEHDR queue_node, previous_node;
+ DPRINT("Queueing wave buffer\n");
+
+ if ( ! wave_header )
+ {
+ return MMSYSERR_INVALPARAM;
+ }
+
+ if ( ! wave_header->lpData )
+ {
+ return MMSYSERR_INVALPARAM;
+ }
+
+ /* Headers must be prepared first */
+ if ( ! ( wave_header->dwFlags & WHDR_PREPARED ) )
+ {
+ DPRINT("I was given a header which hasn't been prepared yet!\n");
+ return WAVERR_UNPREPARED;
+ }
+
+ /* ...and they must not already be in the playing queue! */
+ if ( wave_header->dwFlags & WHDR_INQUEUE )
+ {
+ DPRINT("I was given a header for a buffer which is already
playing\n");
+ return WAVERR_STILLPLAYING;
+ }
+
+ /* Initialize */
+ wave_header->dwBytesRecorded = 0;
+
+ /* Clear the DONE bit, and mark the buffer as queued */
+ wave_header->dwFlags &= ~WHDR_DONE;
+ wave_header->dwFlags |= WHDR_INQUEUE;
+
+ /* Save our handle in the header */
+ wave_header->reserved = (DWORD) session_info;
+
+ /* Locate the end of the queue */
+ previous_node = NULL;
+ queue_node = session_info->wave_queue;
+
+ while ( queue_node )
+ {
+ previous_node = queue_node;
+ queue_node = queue_node->lpNext;
+ }
+
+ /* Go back a step to obtain the previous node (non-NULL) */
+ queue_node = previous_node;
+
+ /* Append our buffer here, and terminate the queue */
+ queue_node->lpNext = wave_header;
+ wave_header->lpNext = NULL;
+
+ /* When no buffers are playing there's no play queue so we start one */
+#if 0
+ if ( ! session_info->next_buffer )
+ {
+ session_info->buffer_position = 0;
+ session_info->next_buffer = wave_header;
+ }
+#endif
+
+ /* Pass to the driver - happens automatically during playback */
+// return PerformWaveIO(session_info);
+ return MMSYSERR_NOERROR;
+}
+
+VOID
+ReturnCompletedBuffers(SessionInfo* session_info)
+{
+ PWAVEHDR header = NULL;
+
+ /* Set the current header and test to ensure it's not NULL */
+ while ( ( header = session_info->wave_queue ) )
+ {
+ if ( header->dwFlags & WHDR_DONE )
+ {
+ DWORD message;
+
+ /* Mark as done, and unqueued */
+ header->dwFlags &= ~WHDR_INQUEUE;
+ header->dwFlags |= WHDR_DONE;
+
+ /* Trim it from the start of the queue */
+ session_info->wave_queue = header->lpNext;
+
+ /* Choose appropriate notification */
+ message = (session_info->device_type == WaveOutDevice) ? WOM_DONE :
+ WIM_DATA;
+
+ DPRINT("Notifying client that buffer 0x%x is done\n", (int)
header);
+
+ /* Notify the client */
+ NotifyClient(session_info, message, (DWORD) header, 0);
+ }
+ }
+
+ /* TODO: Perform I/O as a new buffer may have arrived */
+}
+
+
+/*
+ Each thread function/request is packed into the SessionInfo structure
+ using a function ID and a parameter (in some cases.) When the function
+ completes, the function code is set to an "invalid" value. This is,
+ effectively, a hub for operations where sound driver I/O is concerned.
+ It handles MME message codes so is a form of deferred wodMessage().
+*/
+
+DWORD
+ProcessSessionThreadRequest(SessionInfo* session_info)
+{
+ MMRESULT result = MMSYSERR_NOERROR;
+
+ switch ( session_info->thread.function )
+ {
+ case WODM_WRITE :
+ {
+ result = QueueWaveBuffer(session_info,
+ (LPWAVEHDR) session_info->thread.parameter);
+ break;
+ }
+
+ case WODM_RESET :
+ {
+ /* TODO */
+ break;
+ }
+
+ case WODM_PAUSE :
+ {
+ /* TODO */
+ break;
+ }
+
+ case WODM_RESTART :
+ {
+ /* TODO */
+ break;
+ }
+
+ case WODM_GETPOS :
+ {
+ /* TODO */
+ break;
+ }
+
+ case WODM_SETPITCH :
+ {
+ result = SetDeviceData(session_info->kernel_device_handle,
+ IOCTL_WAVE_SET_PITCH,
+ (PBYTE) session_info->thread.parameter,
+ sizeof(DWORD));
+ break;
+ }
+
+ case WODM_GETPITCH :
+ {
+ result = GetDeviceData(session_info->kernel_device_handle,
+ IOCTL_WAVE_GET_PITCH,
+ (PBYTE) session_info->thread.parameter,
+ sizeof(DWORD));
+ break;
+ }
+
+ case WODM_SETVOLUME :
+ {
+ break;
+ }
+
+ case WODM_GETVOLUME :
+ {
+#if 0
+ result = GetDeviceData(session_info->kernel_device_handle,
+ IOCTL_WAVE_GET_VOLUME,
+ (PBYTE) session_info->thread.parameter,);
+#endif
+ break;
+ }
+
+ case WODM_SETPLAYBACKRATE :
+ {
+ result = SetDeviceData(session_info->kernel_device_handle,
+ IOCTL_WAVE_SET_PLAYBACK_RATE,
+ (PBYTE) session_info->thread.parameter,
+ sizeof(DWORD));
+ break;
+ }
+
+ case WODM_GETPLAYBACKRATE :
+ {
+ result = GetDeviceData(session_info->kernel_device_handle,
+ IOCTL_WAVE_GET_PLAYBACK_RATE,
+ (PBYTE) session_info->thread.parameter,
+ sizeof(DWORD));
+ break;
+ }
+
+ case WODM_CLOSE :
+ {
+ DPRINT("Thread was asked if OK to close device\n");
+
+ if ( session_info->wave_queue != NULL )
+ result = WAVERR_STILLPLAYING;
+ else
+ result = MMSYSERR_NOERROR;
+
+ break;
+ }
+
+ case DRVM_TERMINATE :
+ {
+ DPRINT("Terminating thread...\n");
+ result = MMSYSERR_NOERROR;
+ break;
+ }
+
+ default :
+ {
+ DPRINT("INVALID FUNCTION\n");
+ result = MMSYSERR_ERROR;
+ break;
+ }
+ }
+
+ /* We're done with the function now */
+
+ return result;
+}
+
+
+/*
+ The wave "session". This starts, sets itself as high priority, then waits
+ for the "go" event. When this occurs, it processes the requested function,
+ tidies up any buffers that have finished playing, sends new buffers to the
+ sound driver, then continues handing finished buffers back to the calling
+ application until it's asked to do something else.
+*/
+
+DWORD
+WaveThread(LPVOID parameter)
+{
+ MMRESULT result = MMSYSERR_ERROR;
+ SessionInfo* session_info = (SessionInfo*) parameter;
+ BOOL terminate = FALSE;
+
+ /* All your CPU time are belong to us */
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
- SetEvent(pClient->AuxEvent2);
- WaitForSingleObject(pClient->AuxEvent1, INFINITE);
-
- for (;;)
- {
- switch (pClient->AuxFunction)
- {
- case WaveThreadAddBuffer:
- {
- LPWAVEHDR *pHdrSearching;
-
- if (pClient->DeviceType == WaveInDevice)
- pClient->AuxParam.pHdr->dwBytesRecorded = 0;
-
- pHdrSearching = &pClient->DeviceQueue;
- pClient->AuxParam.pHdr->lpNext = NULL;
-
- while (*pHdrSearching)
- {
- pHdrSearching = &(*pHdrSearching)->lpNext;
- }
-
- if (pClient->NextBuffer == NULL)
- {
- pClient->BufferPosition = 0;
- pClient->NextBuffer = pClient->AuxParam.pHdr;
-
- }
-
- *pHdrSearching = pClient->AuxParam.pHdr;
-
- pClient->AuxReturnCode = waveReadWrite(pClient);
- }
- break;
-
- case WaveThreadSetState:
- pClient->AuxReturnCode = waveSetState(pClient,
pClient->AuxParam.State);
-
- if (pClient->AuxParam.State == WAVE_DD_RESET)
- {
- PWAVEHDR pHdr;
-
- pClient->LoopHead = NULL;
- pClient->AuxReturnCode = MMSYSERR_NOERROR;
- for (pHdr = pClient->DeviceQueue; pHdr != NULL; pHdr =
pHdr->lpNext)
- {
- pHdr->dwFlags |= WHDR_COMPLETE;
- }
-
- pClient->BufferPosition = 0;
- pClient->NextBuffer = NULL;
- }
- else
- {
- if (pClient->DeviceType == WaveInDevice &&
pClient->AuxReturnCode == MMSYSERR_NOERROR)
- {
- if (pClient->AuxParam.State == WAVE_DD_STOP)
- {
- if (pClient->DeviceQueue)
- {
- while (!(pClient->DeviceQueue->dwFlags &
WHDR_COMPLETE) &&
- pClient->BytesOutstanding != 0)
- {
- waveSetState(pClient, WAVE_DD_RECORD);
- pClient->AuxReturnCode = waveSetState(pClient,
WAVE_DD_STOP);
- if (pClient->AuxReturnCode != MMSYSERR_NOERROR)
- break;
-
- }
- if (pClient->AuxReturnCode == MMSYSERR_NOERROR)
- {
- pClient->DeviceQueue->dwFlags |=
WHDR_COMPLETE;
- if (pClient->NextBuffer ==
pClient->DeviceQueue)
- {
- pClient->NextBuffer =
pClient->DeviceQueue->lpNext;
- pClient->BufferPosition = 0;
- }
- }
- }
- }
- else
- {
- if (pClient->AuxParam.State == WAVE_DD_RECORD)
- pClient->AuxReturnCode = waveReadWrite(pClient);
- }
- }
- }
-
- break;
-
- case WaveThreadGetData:
- {
- OVERLAPPED Overlap;
- DWORD BytesReturned;
-
- // FIXME
- // Assert(hDev != NULL);
-
- memset(&Overlap, 0, sizeof(Overlap));
-
- Overlap.hEvent = pClient->Event;
-
- if (!DeviceIoControl(pClient->hDev,
pClient->AuxParam.GetSetData.Function, NULL, 0,
- pClient->AuxParam.GetSetData.pData,
pClient->AuxParam.GetSetData.DataLen,
- &BytesReturned, &Overlap))
- {
- DWORD cbTransfer;
-
- if (GetLastError() != ERROR_IO_PENDING)
- pClient->AuxReturnCode = TranslateStatus();
- else
- {
-
- if (!GetOverlappedResult(pClient->hDev, &Overlap,
&cbTransfer, TRUE))
- pClient->AuxReturnCode = TranslateStatus();
- }
- }
- else
- {
- while (SetEvent(pClient->Event) &&
WaitForSingleObjectEx(pClient->Event, 0, TRUE) ==
- WAIT_IO_COMPLETION) {}
-
- pClient->AuxReturnCode = MMSYSERR_NOERROR;
- }
- }
- break;
-
- case WaveThreadSetData:
- {
- OVERLAPPED Overlap;
- DWORD BytesReturned;
- memset((PVOID)&Overlap, 0, sizeof(Overlap));
- Overlap.hEvent = pClient->Event;
-
- if (!DeviceIoControl(pClient->hDev,
pClient->AuxParam.GetSetData.Function,
- pClient->AuxParam.GetSetData.pData,
pClient->AuxParam.GetSetData.DataLen,
- NULL, 0, &BytesReturned, &Overlap))
- {
- DWORD cbTransfer;
- if (GetLastError() == ERROR_IO_PENDING)
- {
- if (!GetOverlappedResult(pClient->hDev, &Overlap,
&cbTransfer, TRUE))
- pClient->AuxReturnCode = TranslateStatus();
- }
- else
- pClient->AuxReturnCode = TranslateStatus();
-
- }
- else
- {
- while (SleepEx(0, TRUE) == WAIT_IO_COMPLETION) {}
-
- pClient->AuxReturnCode = MMSYSERR_NOERROR;
- }
- }
- break;
-
- case WaveThreadBreakLoop:
- pClient->AuxReturnCode = MMSYSERR_NOERROR;
- if (pClient->LoopHead)
- pClient->LoopCount = 0;
- break;
-
- case WaveThreadClose:
- if (pClient->DeviceQueue != NULL)
- pClient->AuxReturnCode = WAVERR_STILLPLAYING;
- else
- pClient->AuxReturnCode = MMSYSERR_NOERROR;
- break;
-
- case WaveThreadTerminate:
- Terminate = TRUE;
- break;
-
- default:
- DPRINT("WaveThread Error");
- break;
-
- }
-
- pClient->AuxFunction = WaveThreadInvalid;
-
- while (pClient->DeviceQueue && (pClient->DeviceQueue->dwFlags
& WHDR_COMPLETE))
- {
- PWAVEHDR pHdr;
- PWAVEALLOC pWav;
-
- pHdr = pClient->DeviceQueue;
- pClient->DeviceQueue = pHdr->lpNext;
-
- pHdr->dwFlags &= ~WHDR_COMPLETE;
- pHdr->dwFlags &= ~WHDR_INQUEUE;
- pHdr->lpNext = NULL;
- pHdr->dwFlags |= WHDR_DONE;
-
- pWav = (PWAVEALLOC)pHdr->reserved;
-
- if (pWav->dwCallback)
- {
- DriverCallback(pWav->dwCallback, HIWORD(pWav->dwFlags),
(HDRVR)pWav->hWave,
- pClient->DeviceType == WaveOutDevice ? WOM_DONE : WIM_DATA,
- pWav->dwInstance, (DWORD)pHdr, 0L);
- }
- }
-
- waveReadWrite(pClient);
-
- if (Terminate) return 1;
- SetEvent(pClient->AuxEvent2);
- while (WaitForSingleObjectEx(pClient->AuxEvent1, INFINITE, TRUE) ==
WAIT_IO_COMPLETION)
- {
- while (pClient->DeviceQueue && (pClient->DeviceQueue->dwFlags
& WHDR_COMPLETE))
- {
- PWAVEHDR pHdr;
- PWAVEALLOC pWav;
-
- pHdr = pClient->DeviceQueue;
- pClient->DeviceQueue = pHdr->lpNext;
-
- pHdr->dwFlags &= ~WHDR_COMPLETE;
- pHdr->dwFlags &= ~WHDR_INQUEUE;
- pHdr->lpNext = NULL;
- pHdr->dwFlags |= WHDR_DONE;
-
- pWav = (PWAVEALLOC)pHdr->reserved;
-
- if (pWav->dwCallback)
- {
- DriverCallback(pWav->dwCallback, HIWORD(pWav->dwFlags),
(HDRVR)pWav->hWave,
- pClient->DeviceType == WaveOutDevice ? WOM_DONE : WIM_DATA,
- pWav->dwInstance, (DWORD)pHdr, 0L);
- }
- }
-
- waveReadWrite(pClient);
- }
- }
-
-
- return MMSYSERR_NOERROR;
-}
-
-
-static MMRESULT waveReadWrite(PWAVEALLOC pClient)
-{
- DWORD dwSize;
- BOOL Result = FALSE;
-
-
- while (pClient->NextBuffer)
- {
- PWAVEHDR pHdr;
-
- pHdr = pClient->NextBuffer;
-
- //FIXME
- //assert(!(pHdr->dwFlags & (WHDR_DONE | WHDR_COMPLETE)));
- //assert(pClient->DeviceQueue != NULL);
-
-
- dwSize = pHdr->dwBufferLength - pClient->BufferPosition;
- if (dwSize > MAX_BUFFER_SIZE)
- dwSize = MAX_BUFFER_SIZE;
-
-
- if (dwSize + pClient->BytesOutstanding <= MAX_WAVE_BYTES)
- {
- PWAVEOVL pWaveOvl;
-
- if (pClient->BufferPosition == 0)
- {
- if (pClient->NextBuffer && (pClient->NextBuffer->dwFlags
& WHDR_BEGINLOOP) &&
- pClient->NextBuffer != pClient->LoopHead)
- {
- pClient->LoopCount = pClient->NextBuffer->dwLoops;
- pClient->LoopHead = pClient->NextBuffer;
- if (pClient->LoopCount > 0)
- pClient->LoopCount--;
- }
-
- if (pClient->LoopCount == 0)
- pClient->LoopHead = NULL;
- }
-
- pWaveOvl = (PWAVEOVL)HeapAlloc(Heap, HEAP_ZERO_MEMORY, sizeof(*pWaveOvl));
-
- if (pWaveOvl == NULL)
- return MMSYSERR_NOMEM;
-
- pWaveOvl->WaveHdr = pHdr;
-
- if (pClient->DeviceType == WaveOutDevice)
- {
- Result = WriteFileEx(pClient->hDev,
- (PBYTE)pHdr->lpData +
pClient->BufferPosition,
- dwSize,
- (LPOVERLAPPED)pWaveOvl,
- (LPOVERLAPPED_COMPLETION_ROUTINE)
- (pHdr->dwBufferLength !=
- pClient->BufferPosition + dwSize ?
wavePartialOvl : NULL != pClient->LoopHead ?
- waveLoopOvl : waveOvl));
- }
- else if (pClient->DeviceType == WaveInDevice)
- {
- Result = ReadFileEx(pClient->hDev, (PBYTE)pHdr->lpData +
pClient->BufferPosition,
- dwSize, (LPOVERLAPPED)pWaveOvl,
- (LPOVERLAPPED_COMPLETION_ROUTINE)
- (pHdr->dwBufferLength !=
- pClient->BufferPosition + dwSize ? wavePartialOvl
: NULL != pClient->LoopHead ?
- waveLoopOvl : waveOvl));
- }
-
-
- if (!Result && GetLastError() != ERROR_IO_PENDING)
- {
- HeapFree(Heap, 0, (LPSTR)pWaveOvl);
-
- if (pClient->BytesOutstanding == 0)
- {
- PWAVEHDR pHdr;
- for (pHdr = pClient->DeviceQueue; pHdr != NULL; pHdr =
pHdr->lpNext)
- {
- pHdr->dwFlags |= WHDR_COMPLETE;
- }
-
- pClient->NextBuffer = NULL;
- pClient->BufferPosition = 0;
-
- }
- return TranslateStatus();
-
- }
- else
- {
- pClient->BufferPosition += dwSize;
- pClient->BytesOutstanding += dwSize;
- if (pClient->BufferPosition == pHdr->dwBufferLength)
- {
-
- if (!pClient->LoopHead || !(pHdr->dwFlags & WHDR_ENDLOOP))
- pClient->NextBuffer = pHdr->lpNext;
- else
- {
- if (pClient->LoopCount != 0)
- {
- pClient->NextBuffer = pClient->LoopHead;
- pClient->LoopCount--;
- }
- else
- {
- pClient->DummyWaveOvl.WaveHdr = pClient->LoopHead;
-
- Result = WriteFileEx(pClient->hDev,
(PVOID)pHdr->lpData, 0,
- &pClient->DummyWaveOvl.Ovl,
-
(LPOVERLAPPED_COMPLETION_ROUTINE)waveBreakOvl);
-
- if (Result || GetLastError() == ERROR_IO_PENDING)
- {
- pClient->NextBuffer = pHdr->lpNext;
- pClient->LoopHead = NULL;
-
- }
- }
- }
- pClient->BufferPosition = 0;
- }
- }
-
-
- }
- else
- break;
- }
- return MMSYSERR_NOERROR;
-}
-static MMRESULT waveSetState(PWAVEALLOC pClient, ULONG State)
-{
- OVERLAPPED Overlap;
- DWORD BytesReturned;
-
- memset((PVOID)&Overlap, 0, sizeof(Overlap));
-
- Overlap.hEvent = pClient->Event;
-
- if (!DeviceIoControl(pClient->hDev, IOCTL_WAVE_SET_STATE,
- &State, sizeof(State), NULL, 0, &BytesReturned,
&Overlap))
- {
- DWORD cbTransfer;
- if (GetLastError() == ERROR_IO_PENDING)
- {
- if (!GetOverlappedResult(pClient->hDev, &Overlap, &cbTransfer,
TRUE))
- return TranslateStatus();
- }
- else
- return TranslateStatus();
-
- }
-
- while (SleepEx(0, TRUE) == WAIT_IO_COMPLETION) {}
- return MMSYSERR_NOERROR;
-}
-
-void wavePartialOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped)
-{
- LPWAVEHDR pHdr;
- PWAVEALLOC pClient;
-
- pHdr = ((PWAVEOVL)pOverlapped)->WaveHdr;
- pClient = (PWAVEALLOC)pHdr->reserved;
-
-
- /* FIXME
- Assert(pHdr->dwFlags & WHDR_INQUEUE);
- Assert(!(pHdr->dwFlags & WHDR_COMPLETE));
- */
-
- pClient->BytesOutstanding -= MAX_BUFFER_SIZE;
-
- if (pClient->DeviceType == WaveInDevice)
- pHdr->dwBytesRecorded += BytesTransferred;
- HeapFree(Heap, 0, (LPSTR)pOverlapped);
-}
-
-void waveBreakOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped)
-{
- ((PWAVEOVL)pOverlapped)->WaveHdr->dwFlags |= WHDR_COMPLETE;
-}
-
-void waveLoopOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped)
-{
- DWORD dwFlags;
- PWAVEHDR pHdr;
-
- pHdr = ((PWAVEOVL)pOverlapped)->WaveHdr;
- dwFlags = pHdr->dwFlags;
- waveOvl(dwErrorCode, BytesTransferred, pOverlapped);
- pHdr->dwFlags = dwFlags;
-}
-
-void waveOvl(DWORD dwErrorCode, DWORD BytesTransferred, LPOVERLAPPED pOverlapped)
-{
- PWAVEHDR pHdr;
- PWAVEALLOC pClient;
-
- pHdr = ((PWAVEOVL)pOverlapped)->WaveHdr;
- pClient = (PWAVEALLOC)pHdr->reserved;
-
- /* FIXME
- Assert(pHdr->dwFlags & WHDR_INQUEUE);
- Assert(!(pHdr->dwFlags & WHDR_COMPLETE));
- */
-
- pHdr->dwFlags |= WHDR_COMPLETE;
-
- if (pHdr->dwFlags & WHDR_BEGINLOOP)
- {
- PWAVEHDR pHdrSearch;
- for (pHdrSearch = pClient->DeviceQueue ; pHdrSearch != pHdr ; pHdrSearch =
pHdrSearch->lpNext)
- {
- //Assert(pHdrSearch != NULL);
- pHdrSearch->dwFlags |= WHDR_COMPLETE;
- }
- }
-
- if (pHdr->dwBufferLength)
- pClient->BytesOutstanding -= (pHdr->dwBufferLength - 1) % MAX_BUFFER_SIZE +
1;
-
- if (pClient->DeviceType == WaveInDevice)
- pHdr->dwBytesRecorded += BytesTransferred;
-
- HeapFree(Heap, 0, (LPSTR)pOverlapped);
-
-}
-
-
-
-
-
-static MMRESULT OpenWaveDevice(UINT DeviceType,
- DWORD id,
- DWORD dwUser,
- DWORD dwParam1,
- DWORD dwParam2)
-{
- // TODO: Implement
- PWAVEALLOC pClient = (PWAVEALLOC)dwUser;
- MMRESULT mResult;
- BOOL Result;
- DWORD BytesReturned;
- LPWAVEFORMATEX pFormats;
- PWAVEALLOC *pUserHandle = NULL;
- HANDLE hDevice;
-
- pFormats = (LPWAVEFORMATEX)((LPWAVEOPENDESC)dwParam1)->lpFormat;
-
- if (dwParam2 & WAVE_FORMAT_QUERY)
- {
- mResult = OpenDevice(DeviceType, id, &hDevice, GENERIC_READ);
- if (mResult != MMSYSERR_NOERROR)
- return mResult;
-
- Result = DeviceIoControl(hDevice, IOCTL_WAVE_QUERY_FORMAT, (PVOID)pFormats,
- pFormats->wFormatTag == WAVE_FORMAT_PCM ?
- sizeof(PCMWAVEFORMAT) : sizeof(WAVEFORMATEX) +
pFormats->cbSize,
- NULL, 0, &BytesReturned, NULL);
- CloseHandle(hDevice);
- return Result ? MMSYSERR_NOERROR : GetLastError() == ERROR_NOT_SUPPORTED ?
WAVERR_BADFORMAT : TranslateStatus();
- }
-
- EnterCriticalSection(&CS);
-
- for (pClient = WaveLists; pClient != NULL; pClient = pClient->Next)
- {
- if (pClient->DeviceNumber == id && pClient->DeviceType ==
DeviceType)
- {
- if (pClient->hDev != INVALID_HANDLE_VALUE)
- {
- LeaveCriticalSection(&CS);
- return MMSYSERR_ALLOCATED;
- }
- break;
- }
- }
-
- if (pClient == NULL)
- {
- pClient = (PWAVEALLOC)HeapAlloc(Heap, HEAP_ZERO_MEMORY, sizeof(WAVEALLOC));
- if (pClient == NULL)
- {
- LeaveCriticalSection(&CS);
- return MMSYSERR_NOMEM;
- }
-
- pClient->DeviceNumber = id;
- pClient->Next = WaveLists;
- pClient->DeviceType = DeviceType;
-
- WaveLists = pClient;
- }
-
- pClient->hWave = ((LPWAVEOPENDESC)dwParam1)->hWave;
- pClient->dwInstance = ((LPWAVEOPENDESC)dwParam1)->dwInstance;
- pClient->dwFlags = dwParam2;
- pClient->dwCallback = ((LPWAVEOPENDESC)dwParam1)->dwCallback;
- pClient->hDev = INVALID_HANDLE_VALUE;
- pClient->NextBuffer = NULL;
- pClient->DeviceQueue = NULL;
- pClient->LoopHead = NULL;
- pClient->LoopCount = 0;
- pClient->BytesOutstanding = 0;
- pClient->BufferPosition = 0;
-
-
-
-
- mResult = OpenDevice(DeviceType, id, &pClient->hDev, (GENERIC_READ |
GENERIC_WRITE));
-
- if (mResult != MMSYSERR_NOERROR)
- {
- LeaveCriticalSection(&CS);
- return mResult;
- }
-
- if (!DeviceIoControl(pClient->hDev,IOCTL_WAVE_SET_FORMAT, (PVOID)pFormats,
- pFormats->wFormatTag == WAVE_FORMAT_PCM ?
- sizeof(PCMWAVEFORMAT) : sizeof(WAVEFORMATEX) +
pFormats->cbSize,
- NULL, 0, &BytesReturned, NULL))
- {
- CloseHandle(pClient->hDev);
- pClient->hDev = INVALID_HANDLE_VALUE;
- LeaveCriticalSection(&CS);
- return GetLastError() == ERROR_NOT_SUPPORTED ? WAVERR_BADFORMAT :
TranslateStatus();
- }
-
- LeaveCriticalSection(&CS);
-
- if (!pClient->Event)
- {
- pClient->Event = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (pClient->Event == NULL)
- {
- // Cleanup
- return MMSYSERR_NOMEM;
- }
-
- pClient->AuxEvent1 = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!pClient->AuxEvent1)
- {
- // Cleanup
- return MMSYSERR_NOMEM;
- }
-
- pClient->AuxEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!pClient->AuxEvent2)
- {
- // Cleanup
- return MMSYSERR_NOMEM;
- }
-
-
- mResult = mmTaskCreate((LPTASKCALLBACK)waveThread, &pClient->ThreadHandle,
(DWORD)pClient);
- if ( mResult != MMSYSERR_NOERROR)
- {
- // Cleanup
- return MMSYSERR_NOMEM;
- }
-
- WaitForSingleObject(pClient->AuxEvent2, INFINITE);
- }
-
- *pUserHandle = pClient;
- pUserHandle = (PWAVEALLOC *)dwUser;
-
-
- if (pClient->dwCallback)
- {
- DriverCallback(pClient->dwCallback, HIWORD(pClient->dwFlags),
- (HDRVR)pClient->hWave, DeviceType == WaveOutDevice ? WOM_OPEN
: WIM_OPEN,
- pClient->dwInstance, 0L, 0L);
- }
-
- return MMSYSERR_NOERROR;
-}
-
-
-//FIXME: MS-specific code, except for name of the func!
-MMRESULT GetPositionWaveDevice(PWAVEALLOC pClient, LPMMTIME lpmmt, DWORD dwSize)
-{
- /*
- WAVE_DD_POSITION PositionData;
- MMRESULT mErr;
-
- if (dwSize < sizeof(MMTIME))
- return MMSYSERR_ERROR;
-
- //
- // Get the current position from the driver
- //
- mErr = sndGetHandleData(pClient->hDev,
- sizeof(PositionData),
- &PositionData,
- IOCTL_WAVE_GET_POSITION,
- pClient->Event);
-
- if (mErr == MMSYSERR_NOERROR) {
- if (lpmmt->wType == TIME_BYTES) {
- lpmmt->u.cb = PositionData.ByteCount;
- }
-
- // default is samples.
- else {
- lpmmt->wType = TIME_SAMPLES;
- lpmmt->u.sample = PositionData.SampleCount;
- }
- }
-
- return mErr;*/ return MMSYSERR_NOERROR;
-}
-
-
-
-MMRESULT soundSetData(UINT DeviceType, UINT DeviceId, UINT Length, PBYTE Data,
- ULONG Ioctl)
-{
- HANDLE hDevcie;
- MMRESULT Result;
- DWORD BytesReturned;
-
- Result = OpenDevice(DeviceType, DeviceId, &hDevcie, GENERIC_READ);
- if (Result != MMSYSERR_NOERROR)
- return Result;
-
- Result = DeviceIoControl(hDevcie, Ioctl, Data, Length, NULL, 0, &BytesReturned,
NULL) ?
- MMSYSERR_NOERROR : TranslateStatus();
- CloseHandle(hDevcie);
-
- return Result;
-}
-
-MMRESULT soundGetData(UINT DeviceType, UINT DeviceId, UINT Length, PBYTE Data,
- ULONG Ioctl)
-{
- HANDLE hDevice;
- MMRESULT Result;
- DWORD BytesReturned;
-
- Result = OpenDevice(DeviceType, DeviceId, &hDevice, GENERIC_READ);
- if (Result != MMSYSERR_NOERROR)
- return Result;
-
- Result = DeviceIoControl(hDevice, Ioctl, NULL, 0, (LPVOID)Data, Length,
- &BytesReturned, NULL) ? MMSYSERR_NOERROR :
TranslateStatus();
- CloseHandle(hDevice);
- return Result;
-}
-
-
-/* ============================
- * EXPORT
- * functions start here
- * ============================
- */
-
-/*
- * @implemented
- */
-APIENTRY DWORD wodMessage(DWORD dwId, DWORD dwMessage, DWORD dwUser, DWORD dwParam1,
DWORD dwParam2)
-{
- PWAVEALLOC pTask = (PWAVEALLOC)dwUser;
-
- switch (dwMessage) {
- case WODM_GETNUMDEVS:
- DPRINT("WODM_GETNUMDEVS");
- return GetDeviceCount(WaveOutDevice);
-
- case WODM_GETDEVCAPS:
- DPRINT("WODM_GETDEVCAPS");
- return GetDeviceCapabilities(dwId, WaveOutDevice, (LPBYTE)dwParam1,
- (DWORD)dwParam2);
-
- case WODM_OPEN:
- DPRINT("WODM_OPEN");
- return OpenWaveDevice(WaveOutDevice, dwId, dwUser, dwParam1, dwParam2);
-
- case WODM_CLOSE:
- {
- DPRINT("WODM_CLOSE");
-
- // 1. Check if the task is ready to complete
- pTask->AuxFunction = WaveThreadClose;
- SetEvent(pTask->AuxEvent1);
- WaitForSingleObject(pTask->AuxEvent2, INFINITE);
-
- if ( pTask->AuxReturnCode != MMSYSERR_NOERROR)
- {
- return pTask->AuxReturnCode;
- }
- else
-
- {
- if (pTask->dwCallback)
- {
- DriverCallback(pTask->dwCallback, HIWORD(pTask->dwFlags),
(HDRVR)pTask->hWave,
- WOM_CLOSE, pTask->dwInstance, 0L, 0L);
- }
- }
-
-
- // 2. Close the device
- if (pTask->hDev != INVALID_HANDLE_VALUE) {
- CloseHandle(pTask->hDev);
-
- EnterCriticalSection(&CS);
- pTask->hDev = INVALID_HANDLE_VALUE;
- LeaveCriticalSection(&CS);
- }
-
- return MMSYSERR_NOERROR;
- };
-
- case WODM_WRITE:
- {
- LPWAVEHDR pWaveHdr = (LPWAVEHDR)dwParam1;
-
- DPRINT("WODM_WRITE");
-
- if (dwParam1 != 0)
- return MMSYSERR_INVALPARAM;
-
- if ((pWaveHdr->dwFlags &
~(WHDR_INQUEUE|WHDR_DONE|WHDR_PREPARED|WHDR_BEGINLOOP|WHDR_ENDLOOP)))
- return MMSYSERR_INVALPARAM;
-
- pWaveHdr->dwFlags &=
(WHDR_INQUEUE|WHDR_DONE|WHDR_PREPARED|WHDR_BEGINLOOP|WHDR_ENDLOOP);
-
- if ((pWaveHdr->dwFlags & WHDR_PREPARED) == 0)
- return MMSYSERR_INVALPARAM;
-
- // Check, if the wave header is already prepared
- if (!(pWaveHdr->dwFlags & WHDR_PREPARED))
- return WAVERR_UNPREPARED;
-
- // If it's already located in the queue, this op is impossible
- if (pWaveHdr->dwFlags & WHDR_INQUEUE )
- return ( WAVERR_STILLPLAYING );
-
- // save WAVEALLOC pointer in the WaveHeader
- pWaveHdr->reserved = dwUser;
-
-
- pWaveHdr->dwFlags |= WHDR_INQUEUE;
- pWaveHdr->dwFlags &= ~WHDR_DONE;
- pTask->AuxParam.pHdr = pWaveHdr;
-
- pTask->AuxFunction = WaveThreadAddBuffer;
- SetEvent(pTask->AuxEvent1);
- WaitForSingleObject(pTask->AuxEvent2, INFINITE);
- return pTask->AuxReturnCode;
- }
-
- case WODM_PAUSE:
- DPRINT("WODM_PAUSE");
- pTask->AuxParam.State = WAVE_DD_STOP;
-
- pTask->AuxFunction = WaveThreadSetState;
- SetEvent(pTask->AuxEvent1);
- WaitForSingleObject(pTask->AuxEvent2, INFINITE);
- return pTask->AuxReturnCode;
-
- case WODM_RESTART:
- DPRINT("WODM_RESTART");
- pTask->AuxParam.State = WAVE_DD_PLAY;
-
- pTask->AuxFunction = WaveThreadSetState;
- SetEvent(pTask->AuxEvent1);
- WaitForSingleObject(pTask->AuxEvent2, INFINITE);
- return pTask->AuxReturnCode;
-
- case WODM_RESET:
- DPRINT("WODM_RESET");
- pTask->AuxParam.State = WAVE_DD_RESET;
-
- pTask->AuxFunction = WaveThreadSetState;
- SetEvent(pTask->AuxEvent1);
- WaitForSingleObject(pTask->AuxEvent2, INFINITE);
- return pTask->AuxReturnCode;
-
- case WODM_BREAKLOOP:
- DPRINT("WODM_BREAKLOOP");
-
- pTask->AuxFunction = WaveThreadBreakLoop;
- SetEvent(pTask->AuxEvent1);
- WaitForSingleObject(pTask->AuxEvent2, INFINITE);
- return pTask->AuxReturnCode;
-
- case WODM_GETPOS:
- DPRINT("WODM_GETPOS");
- return GetPositionWaveDevice(pTask, (LPMMTIME)dwParam1, dwParam2);
-
- case WODM_SETPITCH:
- DPRINT("WODM_SETPITCH");
- pTask->AuxParam.GetSetData.pData = (PBYTE)&dwParam1;
- pTask->AuxParam.GetSetData.DataLen = sizeof(DWORD);
- pTask->AuxParam.GetSetData.Function = IOCTL_WAVE_SET_PITCH;
-
- pTask->AuxFunction = WaveThreadSetData;
- SetEvent(pTask->AuxEvent1);
- WaitForSingleObject(pTask->AuxEvent2, INFINITE);
- return pTask->AuxReturnCode;
-
- case WODM_SETVOLUME:
- DPRINT("WODM_SETVOLUME");
- {
- WAVE_DD_VOLUME Vol;
- Vol.Left = LOWORD(dwParam1) << 16;
- Vol.Right = HIWORD(dwParam1) << 16;
-
- return soundSetData(WaveOutDevice, dwId, sizeof(Vol),
- (PBYTE)&Vol, IOCTL_WAVE_SET_VOLUME);
- }
-
- case WODM_SETPLAYBACKRATE:
- DPRINT("WODM_SETPLAYBACKRATE");
- pTask->AuxParam.GetSetData.pData = (PBYTE)&dwParam1;
- pTask->AuxParam.GetSetData.DataLen = sizeof(DWORD);
- pTask->AuxParam.GetSetData.Function = IOCTL_WAVE_SET_PLAYBACK_RATE;
-
- pTask->AuxFunction = WaveThreadSetData;
- SetEvent(pTask->AuxEvent1);
- WaitForSingleObject(pTask->AuxEvent2, INFINITE);
- return pTask->AuxReturnCode;
-
-
- case WODM_GETPITCH:
- DPRINT("WODM_GETPITCH");
- pTask->AuxParam.GetSetData.pData = (PBYTE)dwParam1;
- pTask->AuxParam.GetSetData.DataLen = sizeof(DWORD);
- pTask->AuxParam.GetSetData.Function = IOCTL_WAVE_GET_PITCH;
-
- pTask->AuxFunction = WaveThreadGetData;
- SetEvent(pTask->AuxEvent1);
- WaitForSingleObject(pTask->AuxEvent2, INFINITE);
- return pTask->AuxReturnCode;
-
- case WODM_GETVOLUME:
- DPRINT("WODM_GETVOLUME");
- {
- WAVE_DD_VOLUME Vol = {};
- DWORD res;
-
- res = soundGetData(WaveOutDevice, dwId, sizeof(Vol),
- (PBYTE)&Vol, IOCTL_WAVE_GET_VOLUME);
-
- if (res == MMSYSERR_NOERROR)
- *(LPDWORD)dwParam1 = (DWORD)MAKELONG(HIWORD(Vol.Left),
HIWORD(Vol.Right));
-
- return res;
- }
-
- case WODM_GETPLAYBACKRATE:
- DPRINT("WODM_GETPLAYBACKRATE");
- pTask->AuxParam.GetSetData.pData = (PBYTE)dwParam1;
- pTask->AuxParam.GetSetData.DataLen = sizeof(DWORD);
- pTask->AuxParam.GetSetData.Function = IOCTL_WAVE_GET_PLAYBACK_RATE;
-
- pTask->AuxFunction = WaveThreadGetData;
- SetEvent(pTask->AuxEvent1);
- WaitForSingleObject(pTask->AuxEvent2, INFINITE);
- return pTask->AuxReturnCode;
-
- default:
- return MMSYSERR_NOTSUPPORTED;
- }
-
- // This point of execution should never be reached
- return MMSYSERR_NOTSUPPORTED;
-}
-
-
-/*
- * @implemented
- */
-APIENTRY DWORD widMessage(DWORD dwId, DWORD dwMessage, DWORD dwUser, DWORD dwParam1,
DWORD dwParam2)
-{
- DPRINT("widMessage\n");
-
- switch (dwMessage)
- {
- case WIDM_GETNUMDEVS:
- DPRINT("WIDM_GETNUMDEVS");
- return GetDeviceCount(WaveInDevice);
-
- case WIDM_GETDEVCAPS:
- DPRINT("WODM_GETDEVCAPS");
- return GetDeviceCapabilities(dwId, WaveInDevice, (LPBYTE)dwParam1,
(DWORD)dwParam2);
-
- case WIDM_OPEN:
- DPRINT("WIDM_OPEN");
- return OpenWaveDevice(WaveInDevice, dwId, dwUser, dwParam1, dwParam2);
-
- case WIDM_CLOSE:
- return MMSYSERR_NOERROR;
-
- case WIDM_ADDBUFFER:
- return MMSYSERR_NOERROR;
-
- case WIDM_STOP:
- return MMSYSERR_NOERROR;
-
- case WIDM_START:
- return MMSYSERR_NOERROR;
-
- case WIDM_RESET:
- return MMSYSERR_NOERROR;
-
- case WIDM_GETPOS:
- return MMSYSERR_NOERROR;
-
-
- default :
- return MMSYSERR_NOTSUPPORTED;
- }
-}
-
+
+ DPRINT("Wave processing thread setting ready state\n");
+
+ SetEvent(session_info->thread.ready_event);
+
+ while ( ! terminate )
+ {
+ /* Wait for GO event, or IO completion notification */
+ while ( WaitForSingleObjectEx(session_info->thread.go_event,
+ INFINITE,
+ TRUE) == WAIT_IO_COMPLETION )
+ {
+ /* A buffer has been finished with - pass back to the client */
+ ReturnCompletedBuffers(session_info);
+ }
+
+ DPRINT("Wave processing thread woken up\n");
+
+ /* Set the terminate flag if that's what the caller wants */
+ terminate = (session_info->thread.function == DRVM_TERMINATE);
+
+ /* Process the request */
+ DPRINT("Processing thread request\n");
+ result = ProcessSessionThreadRequest(session_info);
+
+ /* Store the result code */
+ session_info->thread.result = result;
+
+ /* Submit new buffers and continue existing ones */
+ DPRINT("Performing wave I/O\n");
+ PerformWaveIO(session_info);
+
+ /* Now we're ready for more action */
+ DPRINT("Wave processing thread sleeping\n");
+ SetEvent(session_info->thread.ready_event);
+ }
+
+ return 0;
+}
+
+
+/*
+ Convenience function for calculating the size of the WAVEFORMATEX struct.
+*/
+
+DWORD
+GetWaveFormatExSize(PWAVEFORMATEX format)
+{
+ if ( format->wFormatTag == WAVE_FORMAT_PCM )
+ return sizeof(PCMWAVEFORMAT);
+ else
+ return sizeof(WAVEFORMATEX) + format->cbSize;
+}
+
+
+/*
+ Query if the driver/device is capable of handling a format. This is called
+ if the device is a wave device, and the QUERYFORMAT flag is set.
+*/
+
+DWORD
+QueryWaveFormat(
+ DeviceType device_type,
+ PVOID lpFormat)
+{
+ /* TODO */
+ return WAVERR_BADFORMAT;
+}
+
+
+/*
+ Set the format to be used.
+*/
+
+BOOL
+SetWaveFormat(
+ HANDLE device_handle,
+ PWAVEFORMATEX format)
+{
+ DWORD bytes_returned;
+ DWORD size;
+
+ size = GetWaveFormatExSize(format);
+
+ DPRINT("SetWaveFormat\n");
+
+ return DeviceIoControl(device_handle,
+ IOCTL_WAVE_SET_FORMAT,
+ (PVOID) format,
+ size,
+ NULL,
+ 0,
+ &bytes_returned,
+ NULL);
+}
+
+
+DWORD
+WriteWaveBuffer(
+ DWORD private_handle,
+ PWAVEHDR wave_header,
+ DWORD wave_header_size)
+{
+ SessionInfo* session_info = (SessionInfo*) private_handle;
+ ASSERT(session_info);
+
+ /* Let the processing thread know that it has work to do */
+ return CallSessionThread(session_info, WODM_WRITE, wave_header);
+}
Added: trunk/reactos/dll/win32/mmdrv/wave_io.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/mmdrv/wave_io.c?…
==============================================================================
--- trunk/reactos/dll/win32/mmdrv/wave_io.c (added)
+++ trunk/reactos/dll/win32/mmdrv/wave_io.c Wed Jul 4 14:17:48 2007
@@ -1,0 +1,40 @@
+/*
+ Don't use this.
+*/
+
+#include <mmdrv.h>
+
+/*
+ Complete a partial wave buffer transaction
+*/
+
+void
+CompleteWaveOverlap(
+ DWORD error_code,
+ DWORD bytes_transferred,
+ LPOVERLAPPED overlapped)
+{
+ DPRINT("Complete partial wave overlap\n");
+}
+
+/*
+ Helper function to set up loops
+*/
+
+VOID
+UpdateWaveLoop(SessionInfo* session_info)
+{
+}
+
+
+/*
+ The hub of all wave I/O. This ensures a constant stream of buffers are
+ passed between the land of usermode and kernelmode.
+*/
+
+VOID
+PerformWaveIO(
+ SessionInfo* session_info)
+{
+
+}