mirror of
https://github.com/reactos/reactos.git
synced 2025-06-03 00:10:39 +00:00
Removed hooks for prepare/unprepare/stream of WAVEHDR. These are handled
internally by MME-Buddy. Instead, it simply provides a hook to do the actual streaming, complete with an OVERLAPPED structure and I/O completion routine. Also started imlpementation of wdmaud.drv to begin interaction with code janderwald is working on. svn path=/trunk/; revision=39667
This commit is contained in:
parent
c15dfd0010
commit
87dcb169be
10 changed files with 679 additions and 255 deletions
|
@ -98,9 +98,8 @@ BOOLEAN FoundDevice(
|
||||||
FuncTable.SetWaveFormat = SetNt4WaveDeviceFormat;
|
FuncTable.SetWaveFormat = SetNt4WaveDeviceFormat;
|
||||||
FuncTable.Open = OpenNt4SoundDevice;
|
FuncTable.Open = OpenNt4SoundDevice;
|
||||||
FuncTable.Close = CloseNt4SoundDevice;
|
FuncTable.Close = CloseNt4SoundDevice;
|
||||||
FuncTable.PrepareWaveHeader = NULL;
|
FuncTable.CommitWaveBuffer = WriteFileEx_Committer;
|
||||||
FuncTable.UnprepareWaveHeader = NULL;
|
//FuncTable.SubmitWaveHeaderToDevice = SubmitWaveHeaderToDevice;
|
||||||
FuncTable.SubmitWaveHeader = NULL;
|
|
||||||
|
|
||||||
SetSoundDeviceFunctionTable(SoundDevice, &FuncTable);
|
SetSoundDeviceFunctionTable(SoundDevice, &FuncTable);
|
||||||
|
|
||||||
|
|
|
@ -1,243 +1,145 @@
|
||||||
/*
|
/*
|
||||||
|
* PROJECT: ReactOS Sound System
|
||||||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
|
* FILE: dll/win32/wdmaud.drv/wdmaud.c
|
||||||
*
|
*
|
||||||
* PROJECT: ReactOS WDM Audio driver mapper
|
* PURPOSE: WDM Audio Driver (User-mode part)
|
||||||
* FILE: dll/win32/wdmaud.drv/wdmaud.c
|
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||||
* PURPOSE: wdmaud.drv
|
*
|
||||||
* PROGRAMMER: Dmitry Chapyshev (dmitry@reactos.org)
|
* NOTES: Looking for wodMessage & co? You won't find them here. Try
|
||||||
|
* the MME Buddy library, which is where these routines are
|
||||||
|
* actually implemented.
|
||||||
*
|
*
|
||||||
* UPDATE HISTORY:
|
|
||||||
* 25/05/2008 Created
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <mmsystem.h>
|
#include <ntddsnd.h>
|
||||||
|
#include <sndtypes.h>
|
||||||
#include <mmddk.h>
|
#include <mmddk.h>
|
||||||
#include <mmreg.h>
|
#include <mmebuddy.h>
|
||||||
#include <debug.h>
|
|
||||||
|
|
||||||
DWORD APIENTRY
|
#define KERNEL_DEVICE_NAME L"\\\\Device\\wdmaud"
|
||||||
mxdMessage(UINT uDevice,
|
|
||||||
UINT uMsg,
|
HANDLE KernelHandle = INVALID_HANDLE_VALUE;
|
||||||
DWORD dwUser,
|
|
||||||
DWORD dwParam1,
|
APIENTRY LONG
|
||||||
DWORD dwParam2)
|
DriverProc(
|
||||||
|
DWORD DriverId,
|
||||||
|
HANDLE DriverHandle,
|
||||||
|
UINT Message,
|
||||||
|
LONG Parameter1,
|
||||||
|
LONG Parameter2)
|
||||||
{
|
{
|
||||||
DPRINT1("mxdMessage(%04X, %04X, %08X, %08X, %08X);\n", uDevice, uMsg, dwUser, dwParam1, dwParam2);
|
MMRESULT Result;
|
||||||
|
|
||||||
switch (uMsg)
|
switch ( Message )
|
||||||
{
|
{
|
||||||
case MXDM_INIT:
|
case DRV_LOAD :
|
||||||
break;
|
{
|
||||||
|
SND_TRACE(L"DRV_LOAD\n");
|
||||||
|
|
||||||
case MXDM_GETNUMDEVS:
|
Result = InitEntrypointMutexes();
|
||||||
break;
|
|
||||||
|
|
||||||
case MXDM_GETDEVCAPS:
|
if ( ! MMSUCCESS(Result) )
|
||||||
break;
|
return 0L;
|
||||||
|
|
||||||
case MXDM_OPEN:
|
KernelHandle = CreateFile(KERNEL_DEVICE_NAME,
|
||||||
break;
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_WRITE, // ok?
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_FLAG_OVERLAPPED,
|
||||||
|
NULL);
|
||||||
|
|
||||||
case MXDM_CLOSE:
|
if ( KernelHandle == INVALID_HANDLE_VALUE )
|
||||||
break;
|
{
|
||||||
|
SND_ERR(L"Failed to open %s", KERNEL_DEVICE_NAME);
|
||||||
|
CleanupEntrypointMutexes();
|
||||||
|
|
||||||
case MXDM_GETLINEINFO:
|
UnlistAllSoundDevices();
|
||||||
break;
|
|
||||||
|
|
||||||
case MXDM_GETLINECONTROLS:
|
return 0L;
|
||||||
break;
|
}
|
||||||
|
|
||||||
case MXDM_GETCONTROLDETAILS:
|
SND_TRACE(L"Initialisation complete\n");
|
||||||
break;
|
|
||||||
|
|
||||||
case MXDM_SETCONTROLDETAILS:
|
return 1L;
|
||||||
break;
|
}
|
||||||
|
|
||||||
|
case DRV_FREE :
|
||||||
|
{
|
||||||
|
SND_TRACE(L"DRV_FREE\n");
|
||||||
|
|
||||||
|
if ( KernelHandle != INVALID_HANDLE_VALUE )
|
||||||
|
{
|
||||||
|
CloseHandle(KernelHandle);
|
||||||
|
KernelHandle = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Clean up the path names! */
|
||||||
|
UnlistAllSoundDevices();
|
||||||
|
|
||||||
|
CleanupEntrypointMutexes();
|
||||||
|
|
||||||
|
SND_TRACE(L"Unfreed memory blocks: %d\n",
|
||||||
|
GetMemoryAllocationCount());
|
||||||
|
|
||||||
|
return 1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DRV_ENABLE :
|
||||||
|
case DRV_DISABLE :
|
||||||
|
{
|
||||||
|
SND_TRACE(L"DRV_ENABLE / DRV_DISABLE\n");
|
||||||
|
return 1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DRV_OPEN :
|
||||||
|
case DRV_CLOSE :
|
||||||
|
{
|
||||||
|
SND_TRACE(L"DRV_OPEN / DRV_CLOSE\n");
|
||||||
|
return 1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DRV_QUERYCONFIGURE :
|
||||||
|
{
|
||||||
|
SND_TRACE(L"DRV_QUERYCONFIGURE");
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
case DRV_CONFIGURE :
|
||||||
|
return DRVCNF_OK;
|
||||||
|
|
||||||
|
default :
|
||||||
|
SND_TRACE(L"Unhandled message %d\n", Message);
|
||||||
|
return DefDriverProc(DriverId,
|
||||||
|
DriverHandle,
|
||||||
|
Message,
|
||||||
|
Parameter1,
|
||||||
|
Parameter2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return MMSYSERR_NOTSUPPORTED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD APIENTRY
|
|
||||||
auxMessage(UINT uDevice,
|
|
||||||
UINT uMsg,
|
|
||||||
DWORD dwUser,
|
|
||||||
DWORD dwParam1,
|
|
||||||
DWORD dwParam2)
|
|
||||||
{
|
|
||||||
DPRINT1("auxMessage(%04X, %04X, %08X, %08X, %08X);\n", uDevice, uMsg, dwUser, dwParam1, dwParam2);
|
|
||||||
|
|
||||||
switch (uMsg)
|
BOOL WINAPI DllMain(
|
||||||
|
HINSTANCE hinstDLL,
|
||||||
|
DWORD fdwReason,
|
||||||
|
LPVOID lpvReserved)
|
||||||
|
{
|
||||||
|
switch ( fdwReason )
|
||||||
{
|
{
|
||||||
case AUXDM_GETDEVCAPS:
|
case DLL_PROCESS_ATTACH :
|
||||||
|
SND_TRACE(L"WDMAUD.DRV - Process attached\n");
|
||||||
break;
|
break;
|
||||||
|
case DLL_PROCESS_DETACH :
|
||||||
case AUXDM_GETNUMDEVS:
|
SND_TRACE(L"WDMAUD.DRV - Process detached\n");
|
||||||
|
break;
|
||||||
break;
|
case DLL_THREAD_ATTACH :
|
||||||
|
SND_TRACE(L"WDMAUD.DRV - Thread attached\n");
|
||||||
case AUXDM_GETVOLUME:
|
break;
|
||||||
|
case DLL_THREAD_DETACH :
|
||||||
break;
|
SND_TRACE(L"WDMAUD.DRV - Thread detached\n");
|
||||||
|
|
||||||
case AUXDM_SETVOLUME:
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return MMSYSERR_NOTSUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MMSYSERR_NOTSUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD APIENTRY
|
|
||||||
wodMessage(UINT uDevice,
|
|
||||||
UINT uMsg,
|
|
||||||
DWORD dwUser,
|
|
||||||
DWORD dwParam1,
|
|
||||||
DWORD dwParam2)
|
|
||||||
{
|
|
||||||
DPRINT1("wodMessage(%04X, %04X, %08X, %08X, %08X);\n", uDevice, uMsg, dwUser, dwParam1, dwParam2);
|
|
||||||
|
|
||||||
switch (uMsg)
|
|
||||||
{
|
|
||||||
case WODM_GETNUMDEVS:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WODM_GETDEVCAPS:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WODM_OPEN:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WODM_CLOSE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WODM_WRITE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WODM_PAUSE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WODM_RESTART:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WODM_RESET:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WODM_BREAKLOOP:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WODM_GETPOS:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WODM_SETPITCH:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WODM_SETVOLUME:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WODM_SETPLAYBACKRATE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WODM_GETPITCH:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WODM_GETVOLUME:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WODM_GETPLAYBACKRATE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return MMSYSERR_NOTSUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MMSYSERR_NOTSUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD APIENTRY
|
|
||||||
widMessage(UINT uDevice,
|
|
||||||
UINT uMsg,
|
|
||||||
DWORD dwUser,
|
|
||||||
DWORD dwParam1,
|
|
||||||
DWORD dwParam2)
|
|
||||||
{
|
|
||||||
DPRINT1("widMessage(%04X, %04X, %08X, %08X, %08X);\n", uDevice, uMsg, dwUser, dwParam1, dwParam2);
|
|
||||||
|
|
||||||
switch (uMsg)
|
|
||||||
{
|
|
||||||
case WIDM_GETNUMDEVS:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WIDM_GETDEVCAPS:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WIDM_OPEN:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WIDM_CLOSE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WIDM_ADDBUFFER:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WIDM_STOP:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WIDM_START:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WIDM_RESET:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case WIDM_GETPOS:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return MMSYSERR_NOTSUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MMSYSERR_NOTSUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD APIENTRY
|
|
||||||
modMessage(UINT uDevice,
|
|
||||||
UINT uMsg,
|
|
||||||
DWORD dwUser,
|
|
||||||
DWORD dwParam1,
|
|
||||||
DWORD dwParam2)
|
|
||||||
{
|
|
||||||
DPRINT1("modMessage(%04X, %04X, %08X, %08X, %08X);\n", uDevice, uMsg, dwUser, dwParam1, dwParam2);
|
|
||||||
|
|
||||||
return MMSYSERR_NOTSUPPORTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
LRESULT APIENTRY
|
|
||||||
DriverProc(DWORD dwDriverID,
|
|
||||||
HDRVR hDriver,
|
|
||||||
UINT uiMessage,
|
|
||||||
LPARAM lParam1,
|
|
||||||
LPARAM lParam2)
|
|
||||||
{
|
|
||||||
return DefDriverProc(dwDriverID, hDriver, uiMessage, lParam1, lParam2);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL WINAPI
|
|
||||||
DllMain(IN HINSTANCE hinstDLL,
|
|
||||||
IN DWORD dwReason,
|
|
||||||
IN LPVOID lpvReserved)
|
|
||||||
{
|
|
||||||
switch (dwReason)
|
|
||||||
{
|
|
||||||
case DLL_PROCESS_ATTACH:
|
|
||||||
DisableThreadLibraryCalls(hinstDLL);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
<module name="wdmaud.drv" type="win32dll" baseaddress="${BASEADDRESS_WDMAUD}" installbase="system32" installname="wdmaud.drv">
|
<module name="wdmaud.drv" type="win32dll" baseaddress="${BASEADDRESS_WDMAUD}" installbase="system32" installname="wdmaud.drv" unicode="yes">
|
||||||
<importlibrary definition="wdmaud.spec" />
|
<importlibrary definition="wdmaud.spec" />
|
||||||
<include base="wdmaud.drv">.</include>
|
<include base="wdmaud.drv">.</include>
|
||||||
<define name="_DISABLE_TIDENTS" />
|
<include base="ReactOS">include/reactos/libs/sound</include>
|
||||||
<library>advapi32</library>
|
<define name="DEBUG_NT4" /><!-- Use custom debug routines -->
|
||||||
|
<library>mmebuddy</library>
|
||||||
|
<library>ntdll</library>
|
||||||
<library>kernel32</library>
|
<library>kernel32</library>
|
||||||
<library>winmm</library>
|
|
||||||
<library>user32</library>
|
<library>user32</library>
|
||||||
<library>winmm</library>
|
<library>winmm</library>
|
||||||
|
<library>advapi32</library>
|
||||||
<file>wdmaud.c</file>
|
<file>wdmaud.c</file>
|
||||||
<file>wdmaud.rc</file>
|
<file>wdmaud.rc</file>
|
||||||
</module>
|
</module>
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
MessageBox(0, dbg_popup_msg, dbg_popup_title, MB_OK | MB_TASKMODAL); \
|
MessageBox(0, dbg_popup_msg, dbg_popup_title, MB_OK | MB_TASKMODAL); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_NT4
|
#ifndef NDEBUG
|
||||||
#define SND_ERR(...) \
|
#define SND_ERR(...) \
|
||||||
{ \
|
{ \
|
||||||
WCHAR dbg_popup_msg[1024]; \
|
WCHAR dbg_popup_msg[1024]; \
|
||||||
|
@ -62,11 +62,24 @@
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DUMP_WAVEHDR_QUEUE(sound_device_instance) \
|
||||||
|
{ \
|
||||||
|
PWAVEHDR CurrDumpHdr = sound_device_instance->HeadWaveHeader; \
|
||||||
|
SND_TRACE(L"-- Current wave header list --\n"); \
|
||||||
|
while ( CurrDumpHdr ) \
|
||||||
|
{ \
|
||||||
|
SND_TRACE(L"%x | %d bytes | flags: %x\n", CurrDumpHdr->lpData, \
|
||||||
|
CurrDumpHdr->dwBufferLength, \
|
||||||
|
CurrDumpHdr->dwFlags); \
|
||||||
|
CurrDumpHdr = CurrDumpHdr->lpNext; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define SND_ERR(...) while ( 0 ) do {}
|
#define SND_ERR(...) do {} while ( 0 )
|
||||||
#define SND_WARN(...) while ( 0 ) do {}
|
#define SND_WARN(...) do {} while ( 0 )
|
||||||
#define SND_TRACE(...) while ( 0 ) do {}
|
#define SND_TRACE(...) do {} while ( 0 )
|
||||||
#define SND_ASSERT(condition) while ( 0 ) do {}
|
#define SND_ASSERT(condition) do {} while ( 0 )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -157,6 +170,28 @@ DEFINE_GETCAPS_FUNCTYPE(MMGETMIDIINCAPS_FUNC, LPMIDIINCAPS );
|
||||||
struct _SOUND_DEVICE;
|
struct _SOUND_DEVICE;
|
||||||
struct _SOUND_DEVICE_INSTANCE;
|
struct _SOUND_DEVICE_INSTANCE;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
By extending the OVERLAPPED structure, it becomes possible to provide the
|
||||||
|
I/O completion routines with additional information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct _SOUND_OVERLAPPED
|
||||||
|
{
|
||||||
|
OVERLAPPED Standard;
|
||||||
|
struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance;
|
||||||
|
PWAVEHDR Header;
|
||||||
|
} SOUND_OVERLAPPED, *PSOUND_OVERLAPPED;
|
||||||
|
|
||||||
|
typedef MMRESULT (*WAVE_COMMIT_FUNC)(
|
||||||
|
IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
|
||||||
|
IN PVOID OffsetPtr,
|
||||||
|
IN DWORD Bytes,
|
||||||
|
IN PSOUND_OVERLAPPED Overlap,
|
||||||
|
IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef MMRESULT (*MMWAVEQUERYFORMATSUPPORT_FUNC)(
|
typedef MMRESULT (*MMWAVEQUERYFORMATSUPPORT_FUNC)(
|
||||||
IN struct _SOUND_DEVICE* Device,
|
IN struct _SOUND_DEVICE* Device,
|
||||||
IN PWAVEFORMATEX WaveFormat,
|
IN PWAVEFORMATEX WaveFormat,
|
||||||
|
@ -179,6 +214,11 @@ typedef MMRESULT (*MMWAVEHEADER_FUNC)(
|
||||||
IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
|
IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
|
||||||
IN PWAVEHDR WaveHeader);
|
IN PWAVEHDR WaveHeader);
|
||||||
|
|
||||||
|
typedef MMRESULT (*MMBUFFER_FUNC)(
|
||||||
|
IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
|
||||||
|
IN PVOID Buffer,
|
||||||
|
IN DWORD Length);
|
||||||
|
|
||||||
typedef struct _MMFUNCTION_TABLE
|
typedef struct _MMFUNCTION_TABLE
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
|
@ -196,11 +236,19 @@ typedef struct _MMFUNCTION_TABLE
|
||||||
MMWAVEQUERYFORMATSUPPORT_FUNC QueryWaveFormatSupport;
|
MMWAVEQUERYFORMATSUPPORT_FUNC QueryWaveFormatSupport;
|
||||||
MMWAVESETFORMAT_FUNC SetWaveFormat;
|
MMWAVESETFORMAT_FUNC SetWaveFormat;
|
||||||
|
|
||||||
MMWAVEHEADER_FUNC PrepareWaveHeader;
|
WAVE_COMMIT_FUNC CommitWaveBuffer;
|
||||||
MMWAVEHEADER_FUNC UnprepareWaveHeader;
|
|
||||||
MMWAVEHEADER_FUNC SubmitWaveHeader;
|
// Redundant
|
||||||
|
//MMWAVEHEADER_FUNC PrepareWaveHeader;
|
||||||
|
//MMWAVEHEADER_FUNC UnprepareWaveHeader;
|
||||||
|
//MMWAVEHEADER_FUNC WriteWaveHeader;
|
||||||
|
|
||||||
|
//MMWAVEHEADER_FUNC SubmitWaveHeaderToDevice;
|
||||||
|
//MMBUFFER_FUNC CompleteBuffer;
|
||||||
} MMFUNCTION_TABLE, *PMMFUNCTION_TABLE;
|
} MMFUNCTION_TABLE, *PMMFUNCTION_TABLE;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef MMRESULT (*SOUND_THREAD_REQUEST_HANDLER)(
|
typedef MMRESULT (*SOUND_THREAD_REQUEST_HANDLER)(
|
||||||
IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
|
IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
|
||||||
IN PVOID Parameter);
|
IN PVOID Parameter);
|
||||||
|
@ -252,8 +300,32 @@ typedef struct _SOUND_DEVICE_INSTANCE
|
||||||
DWORD ClientCallback;
|
DWORD ClientCallback;
|
||||||
DWORD ClientCallbackInstanceData;
|
DWORD ClientCallbackInstanceData;
|
||||||
} WinMM;
|
} WinMM;
|
||||||
|
|
||||||
|
/* DO NOT TOUCH THESE OUTSIDE OF THE SOUND THREAD */
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
PWAVEHDR HeadWaveHeader;
|
||||||
|
};
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
PWAVEHDR TailWaveHeader;
|
||||||
|
};
|
||||||
|
|
||||||
|
PWAVEHDR WaveLoopStart;
|
||||||
|
PWAVEHDR CurrentWaveHeader;
|
||||||
|
DWORD OutstandingBuffers;
|
||||||
} SOUND_DEVICE_INSTANCE, *PSOUND_DEVICE_INSTANCE;
|
} SOUND_DEVICE_INSTANCE, *PSOUND_DEVICE_INSTANCE;
|
||||||
|
|
||||||
|
/* This lives in WAVEHDR.reserved */
|
||||||
|
typedef struct _WAVEHDR_EXTENSION
|
||||||
|
{
|
||||||
|
DWORD BytesCommitted;
|
||||||
|
DWORD BytesCompleted;
|
||||||
|
} WAVEHDR_EXTENSION, *PWAVEHDR_EXTENSION;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
reentrancy.c
|
reentrancy.c
|
||||||
*/
|
*/
|
||||||
|
@ -308,8 +380,8 @@ MmeCloseDevice(
|
||||||
#define MmeUnprepareWaveHeader(private_handle, header) \
|
#define MmeUnprepareWaveHeader(private_handle, header) \
|
||||||
UnprepareWaveHeader((PSOUND_DEVICE_INSTANCE)private_handle, (PWAVEHDR)header)
|
UnprepareWaveHeader((PSOUND_DEVICE_INSTANCE)private_handle, (PWAVEHDR)header)
|
||||||
|
|
||||||
#define MmeEnqueueWaveHeader(private_handle, header) \
|
#define MmeWriteWaveHeader(private_handle, header) \
|
||||||
EnqueueWaveHeader((PSOUND_DEVICE_INSTANCE)private_handle, (PWAVEHDR)header)
|
WriteWaveHeader((PSOUND_DEVICE_INSTANCE)private_handle, (PWAVEHDR)header)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -493,6 +565,16 @@ SetWaveDeviceFormat(
|
||||||
wave/header.c
|
wave/header.c
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
MMRESULT
|
||||||
|
EnqueueWaveHeader(
|
||||||
|
PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||||
|
IN PVOID Parameter);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
CompleteWaveHeader(
|
||||||
|
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||||
|
IN PWAVEHDR Header);
|
||||||
|
|
||||||
MMRESULT
|
MMRESULT
|
||||||
PrepareWaveHeader(
|
PrepareWaveHeader(
|
||||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||||
|
@ -504,11 +586,40 @@ UnprepareWaveHeader(
|
||||||
IN PWAVEHDR Header);
|
IN PWAVEHDR Header);
|
||||||
|
|
||||||
MMRESULT
|
MMRESULT
|
||||||
EnqueueWaveHeader(
|
WriteWaveHeader(
|
||||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||||
IN PWAVEHDR Header);
|
IN PWAVEHDR Header);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
wave/streaming.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
MMRESULT
|
||||||
|
DoWaveStreaming(
|
||||||
|
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance);
|
||||||
|
|
||||||
|
VOID CALLBACK
|
||||||
|
CompleteIO(
|
||||||
|
IN DWORD dwErrorCode,
|
||||||
|
IN DWORD dwNumberOfBytesTransferred,
|
||||||
|
IN LPOVERLAPPED lpOverlapped);
|
||||||
|
|
||||||
|
MMRESULT
|
||||||
|
CommitWaveHeaderToKernelDevice(
|
||||||
|
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||||
|
IN PWAVEHDR Header,
|
||||||
|
IN WAVE_COMMIT_FUNC CommitFunction);
|
||||||
|
|
||||||
|
MMRESULT
|
||||||
|
WriteFileEx_Committer(
|
||||||
|
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||||
|
IN PVOID OffsetPtr,
|
||||||
|
IN DWORD Length,
|
||||||
|
IN PSOUND_OVERLAPPED Overlap,
|
||||||
|
IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
kernel.c
|
kernel.c
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -186,6 +186,14 @@ CreateSoundDeviceInstance(
|
||||||
(*SoundDeviceInstance)->WinMM.ClientCallbackInstanceData = 0;
|
(*SoundDeviceInstance)->WinMM.ClientCallbackInstanceData = 0;
|
||||||
(*SoundDeviceInstance)->WinMM.Flags = 0;
|
(*SoundDeviceInstance)->WinMM.Flags = 0;
|
||||||
|
|
||||||
|
/* Initialise the members of the struct used by the sound thread */
|
||||||
|
(*SoundDeviceInstance)->HeadWaveHeader = NULL;
|
||||||
|
(*SoundDeviceInstance)->TailWaveHeader = NULL;
|
||||||
|
|
||||||
|
(*SoundDeviceInstance)->CurrentWaveHeader = NULL;
|
||||||
|
(*SoundDeviceInstance)->OutstandingBuffers = 0;
|
||||||
|
// TODO: Loop
|
||||||
|
|
||||||
/* Create the streaming thread (TODO - is this for wave only?) */
|
/* Create the streaming thread (TODO - is this for wave only?) */
|
||||||
Result = CreateSoundThread(&(*SoundDeviceInstance)->Thread);
|
Result = CreateSoundThread(&(*SoundDeviceInstance)->Thread);
|
||||||
if ( ! MMSUCCESS(Result) )
|
if ( ! MMSUCCESS(Result) )
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
<file>widMessage.c</file>
|
<file>widMessage.c</file>
|
||||||
<file>wodMessage.c</file>
|
<file>wodMessage.c</file>
|
||||||
<file>format.c</file>
|
<file>format.c</file>
|
||||||
<file>header.c</file>
|
<file>header.c</file>
|
||||||
|
<file>streaming.c</file>
|
||||||
</directory>
|
</directory>
|
||||||
<directory name="midi">
|
<directory name="midi">
|
||||||
<file>midMessage.c</file>
|
<file>midMessage.c</file>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||||
* LICENSE: GPL - See COPYING in the top level directory
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
* FILE: lib/drivers/sound/mmebuddy/header.c
|
* FILE: lib/drivers/sound/mmebuddy/wave/header.c
|
||||||
*
|
*
|
||||||
* PURPOSE: Wave header preparation routines
|
* PURPOSE: Wave header preparation and submission routines
|
||||||
*
|
*
|
||||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||||
*/
|
*/
|
||||||
|
@ -13,6 +13,7 @@
|
||||||
#include <mmddk.h>
|
#include <mmddk.h>
|
||||||
#include <ntddsnd.h>
|
#include <ntddsnd.h>
|
||||||
#include <mmebuddy.h>
|
#include <mmebuddy.h>
|
||||||
|
#include <sndtypes.h>
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -59,6 +60,25 @@ WaveHeaderOperation(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
SanitizeWaveHeader
|
||||||
|
Clean up a header / reinitialize
|
||||||
|
*/
|
||||||
|
|
||||||
|
VOID
|
||||||
|
SanitizeWaveHeader(
|
||||||
|
PWAVEHDR Header)
|
||||||
|
{
|
||||||
|
PWAVEHDR_EXTENSION Extension = (PWAVEHDR_EXTENSION) Header->reserved;
|
||||||
|
SND_ASSERT( Extension );
|
||||||
|
|
||||||
|
Header->dwBytesRecorded = 0;
|
||||||
|
|
||||||
|
Extension->BytesCommitted = 0;
|
||||||
|
Extension->BytesCompleted = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The following routines are basically handlers for:
|
The following routines are basically handlers for:
|
||||||
- WODM_PREPARE
|
- WODM_PREPARE
|
||||||
|
@ -78,6 +98,7 @@ PrepareWaveHeader(
|
||||||
MMRESULT Result;
|
MMRESULT Result;
|
||||||
PSOUND_DEVICE SoundDevice;
|
PSOUND_DEVICE SoundDevice;
|
||||||
PMMFUNCTION_TABLE FunctionTable;
|
PMMFUNCTION_TABLE FunctionTable;
|
||||||
|
PWAVEHDR_EXTENSION Extension;
|
||||||
|
|
||||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
|
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
|
||||||
VALIDATE_MMSYS_PARAMETER( Header );
|
VALIDATE_MMSYS_PARAMETER( Header );
|
||||||
|
@ -92,12 +113,18 @@ PrepareWaveHeader(
|
||||||
if ( ! MMSUCCESS(Result) )
|
if ( ! MMSUCCESS(Result) )
|
||||||
return TranslateInternalMmResult(Result);
|
return TranslateInternalMmResult(Result);
|
||||||
|
|
||||||
if ( ! FunctionTable->PrepareWaveHeader )
|
Extension = AllocateStruct(WAVEHDR_EXTENSION);
|
||||||
return MMSYSERR_NOTSUPPORTED;
|
if ( ! Extension )
|
||||||
|
return MMSYSERR_NOMEM;
|
||||||
|
|
||||||
return WaveHeaderOperation(FunctionTable->PrepareWaveHeader,
|
Header->reserved = (DWORD_PTR) Extension;
|
||||||
SoundDeviceInstance,
|
Extension->BytesCommitted = 0;
|
||||||
Header);
|
Extension->BytesCompleted = 0;
|
||||||
|
|
||||||
|
/* Configure the flags */
|
||||||
|
Header->dwFlags |= WHDR_PREPARED;
|
||||||
|
|
||||||
|
return MMSYSERR_NOERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
MMRESULT
|
MMRESULT
|
||||||
|
@ -108,6 +135,7 @@ UnprepareWaveHeader(
|
||||||
MMRESULT Result;
|
MMRESULT Result;
|
||||||
PSOUND_DEVICE SoundDevice;
|
PSOUND_DEVICE SoundDevice;
|
||||||
PMMFUNCTION_TABLE FunctionTable;
|
PMMFUNCTION_TABLE FunctionTable;
|
||||||
|
PWAVEHDR_EXTENSION Extension;
|
||||||
|
|
||||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
|
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
|
||||||
VALIDATE_MMSYS_PARAMETER( Header );
|
VALIDATE_MMSYS_PARAMETER( Header );
|
||||||
|
@ -122,16 +150,18 @@ UnprepareWaveHeader(
|
||||||
if ( ! MMSUCCESS(Result) )
|
if ( ! MMSUCCESS(Result) )
|
||||||
return TranslateInternalMmResult(Result);
|
return TranslateInternalMmResult(Result);
|
||||||
|
|
||||||
if ( ! FunctionTable->UnprepareWaveHeader )
|
SND_ASSERT( Header->reserved );
|
||||||
return MMSYSERR_NOTSUPPORTED;
|
Extension = (PWAVEHDR_EXTENSION) Header->reserved;
|
||||||
|
FreeMemory(Extension);
|
||||||
|
|
||||||
return WaveHeaderOperation(FunctionTable->UnprepareWaveHeader,
|
/* Configure the flags */
|
||||||
SoundDeviceInstance,
|
Header->dwFlags &= ~WHDR_PREPARED;
|
||||||
Header);
|
|
||||||
|
return MMSYSERR_NOERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
MMRESULT
|
MMRESULT
|
||||||
EnqueueWaveHeader(
|
WriteWaveHeader(
|
||||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||||
IN PWAVEHDR Header)
|
IN PWAVEHDR Header)
|
||||||
{
|
{
|
||||||
|
@ -152,7 +182,7 @@ EnqueueWaveHeader(
|
||||||
if ( ! MMSUCCESS(Result) )
|
if ( ! MMSUCCESS(Result) )
|
||||||
return TranslateInternalMmResult(Result);
|
return TranslateInternalMmResult(Result);
|
||||||
|
|
||||||
if ( ! FunctionTable->SubmitWaveHeader )
|
if ( ! FunctionTable->CommitWaveBuffer )
|
||||||
return MMSYSERR_NOTSUPPORTED;
|
return MMSYSERR_NOTSUPPORTED;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -164,20 +194,160 @@ EnqueueWaveHeader(
|
||||||
VALIDATE_MMSYS_PARAMETER( Header->dwFlags & WHDR_PREPARED );
|
VALIDATE_MMSYS_PARAMETER( Header->dwFlags & WHDR_PREPARED );
|
||||||
VALIDATE_MMSYS_PARAMETER( ! (Header->dwFlags & WHDR_INQUEUE) );
|
VALIDATE_MMSYS_PARAMETER( ! (Header->dwFlags & WHDR_INQUEUE) );
|
||||||
|
|
||||||
|
SanitizeWaveHeader(Header);
|
||||||
|
|
||||||
/* Clear the "done" flag for the buffer */
|
/* Clear the "done" flag for the buffer */
|
||||||
Header->dwFlags &= ~WHDR_DONE;
|
Header->dwFlags &= ~WHDR_DONE;
|
||||||
|
|
||||||
Result = WaveHeaderOperation(FunctionTable->SubmitWaveHeader,
|
Result = CallSoundThread(SoundDeviceInstance,
|
||||||
SoundDeviceInstance,
|
EnqueueWaveHeader,
|
||||||
Header);
|
Header);
|
||||||
|
|
||||||
if ( ! MMSUCCESS(Result) )
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
EnqueueWaveHeader
|
||||||
|
Put the header in the record/playback queue. This is performed within
|
||||||
|
the context of the sound thread, it must NEVER be called from another
|
||||||
|
thread.
|
||||||
|
|
||||||
|
CompleteWaveHeader
|
||||||
|
Set the header information to indicate that it has finished playing,
|
||||||
|
and return it to the client application. This again must be called
|
||||||
|
within the context of the sound thread.
|
||||||
|
*/
|
||||||
|
|
||||||
|
MMRESULT
|
||||||
|
EnqueueWaveHeader(
|
||||||
|
PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||||
|
IN PVOID Parameter)
|
||||||
|
{
|
||||||
|
VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
|
||||||
|
VALIDATE_MMSYS_PARAMETER( Parameter );
|
||||||
|
|
||||||
|
PWAVEHDR WaveHeader = (PWAVEHDR) Parameter;
|
||||||
|
|
||||||
|
/* Initialise */
|
||||||
|
WaveHeader->lpNext = NULL;
|
||||||
|
|
||||||
|
/* Set the "in queue" flag */
|
||||||
|
WaveHeader->dwFlags |= WHDR_INQUEUE;
|
||||||
|
|
||||||
|
if ( ! SoundDeviceInstance->TailWaveHeader )
|
||||||
{
|
{
|
||||||
return Result;
|
/* This is the first header in the queue */
|
||||||
|
SND_TRACE(L"Enqueued first wave header\n");
|
||||||
|
SoundDeviceInstance->HeadWaveHeader = WaveHeader;
|
||||||
|
SoundDeviceInstance->TailWaveHeader = WaveHeader;
|
||||||
|
|
||||||
|
DoWaveStreaming(SoundDeviceInstance);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* There are already queued headers - make this one the tail */
|
||||||
|
SND_TRACE(L"Enqueued next wave header\n");
|
||||||
|
SoundDeviceInstance->TailWaveHeader->lpNext = WaveHeader;
|
||||||
|
SoundDeviceInstance->TailWaveHeader = WaveHeader;
|
||||||
|
|
||||||
|
DoWaveStreaming(SoundDeviceInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the "in queue" flag if everything was OK */
|
DUMP_WAVEHDR_QUEUE(SoundDeviceInstance);
|
||||||
Header->dwFlags |= WHDR_INQUEUE;
|
|
||||||
|
|
||||||
return MMSYSERR_NOERROR;
|
return MMSYSERR_NOERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
CompleteWaveHeader(
|
||||||
|
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||||
|
IN PWAVEHDR Header)
|
||||||
|
{
|
||||||
|
PWAVEHDR PrevHdr = NULL, CurrHdr = NULL;
|
||||||
|
PWAVEHDR_EXTENSION Extension;
|
||||||
|
PSOUND_DEVICE SoundDevice;
|
||||||
|
MMDEVICE_TYPE DeviceType;
|
||||||
|
MMRESULT Result;
|
||||||
|
|
||||||
|
SND_TRACE(L"BUFFER COMPLETE :)\n");
|
||||||
|
|
||||||
|
// TODO: Set header flags?
|
||||||
|
// TODO: Call client
|
||||||
|
// TODO: Streaming
|
||||||
|
|
||||||
|
//DoWaveStreaming(SoundDeviceInstance);
|
||||||
|
|
||||||
|
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
||||||
|
SND_ASSERT( MMSUCCESS(Result) );
|
||||||
|
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
|
||||||
|
SND_ASSERT( MMSUCCESS(Result) );
|
||||||
|
|
||||||
|
Extension = (PWAVEHDR_EXTENSION)Header->reserved;
|
||||||
|
SND_ASSERT( Extension );
|
||||||
|
|
||||||
|
/* Remove the header from the queue, like so */
|
||||||
|
if ( SoundDeviceInstance->HeadWaveHeader == Header )
|
||||||
|
{
|
||||||
|
SoundDeviceInstance->HeadWaveHeader = Header->lpNext;
|
||||||
|
|
||||||
|
SND_TRACE(L"Dropping head node\n");
|
||||||
|
|
||||||
|
/* If nothing after the head, then there is no tail */
|
||||||
|
if ( Header->lpNext == NULL )
|
||||||
|
{
|
||||||
|
SND_TRACE(L"Dropping tail node\n");
|
||||||
|
SoundDeviceInstance->TailWaveHeader = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PrevHdr = NULL;
|
||||||
|
CurrHdr = SoundDeviceInstance->HeadWaveHeader;
|
||||||
|
|
||||||
|
SND_TRACE(L"Relinking nodes\n");
|
||||||
|
|
||||||
|
while ( CurrHdr != Header )
|
||||||
|
{
|
||||||
|
PrevHdr = CurrHdr;
|
||||||
|
CurrHdr = CurrHdr->lpNext;
|
||||||
|
SND_ASSERT( CurrHdr );
|
||||||
|
}
|
||||||
|
|
||||||
|
SND_ASSERT( PrevHdr );
|
||||||
|
|
||||||
|
PrevHdr->lpNext = CurrHdr->lpNext;
|
||||||
|
|
||||||
|
/* If this is the tail node, update the tail */
|
||||||
|
if ( Header->lpNext == NULL )
|
||||||
|
{
|
||||||
|
SND_TRACE(L"Updating tail node\n");
|
||||||
|
SoundDeviceInstance->TailWaveHeader = PrevHdr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure we're not using this as the current buffer any more, either! */
|
||||||
|
if ( SoundDeviceInstance->CurrentWaveHeader == Header )
|
||||||
|
{
|
||||||
|
SoundDeviceInstance->CurrentWaveHeader = Header->lpNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
DUMP_WAVEHDR_QUEUE(SoundDeviceInstance);
|
||||||
|
|
||||||
|
SND_TRACE(L"Returning buffer to client...\n");
|
||||||
|
|
||||||
|
/* Update the header */
|
||||||
|
Header->dwFlags &= ~WHDR_INQUEUE;
|
||||||
|
Header->dwFlags |= WHDR_DONE;
|
||||||
|
|
||||||
|
if ( DeviceType == WAVE_IN_DEVICE_TYPE )
|
||||||
|
{
|
||||||
|
// FIXME: We won't be called on incomplete buffer!
|
||||||
|
Header->dwBytesRecorded = Extension->BytesCompleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Safe to do this without thread protection, as we're done with the header */
|
||||||
|
NotifyMmeClient(SoundDeviceInstance,
|
||||||
|
DeviceType == WAVE_OUT_DEVICE_TYPE ? WOM_DONE : WIM_DATA,
|
||||||
|
(DWORD) Header);
|
||||||
|
}
|
||||||
|
|
229
reactos/lib/drivers/sound/mmebuddy/wave/streaming.c
Normal file
229
reactos/lib/drivers/sound/mmebuddy/wave/streaming.c
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Sound System "MME Buddy" Library
|
||||||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
|
* FILE: lib/drivers/sound/mmebuddy/wave/streaming.c
|
||||||
|
*
|
||||||
|
* PURPOSE: Wave streaming
|
||||||
|
*
|
||||||
|
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <mmsystem.h>
|
||||||
|
#include <mmddk.h>
|
||||||
|
#include <ntddsnd.h>
|
||||||
|
#include <mmebuddy.h>
|
||||||
|
#include <sndtypes.h>
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Restrain ourselves from flooding the kernel device!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SOUND_KERNEL_BUFFER_COUNT 10
|
||||||
|
#define SOUND_KERNEL_BUFFER_SIZE 200000
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
DoWaveStreaming
|
||||||
|
Check if there is streaming to be done, and if so, do it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
MMRESULT
|
||||||
|
DoWaveStreaming(
|
||||||
|
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
|
||||||
|
{
|
||||||
|
MMRESULT Result;
|
||||||
|
PSOUND_DEVICE SoundDevice;
|
||||||
|
PMMFUNCTION_TABLE FunctionTable;
|
||||||
|
|
||||||
|
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
||||||
|
SND_ASSERT( MMSUCCESS(Result) );
|
||||||
|
|
||||||
|
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
|
||||||
|
SND_ASSERT( MMSUCCESS(Result) );
|
||||||
|
SND_ASSERT( FunctionTable );
|
||||||
|
SND_ASSERT( FunctionTable->CommitWaveBuffer );
|
||||||
|
|
||||||
|
// HACK
|
||||||
|
SND_TRACE(L"Calling buffer submit routine\n");
|
||||||
|
|
||||||
|
if ( ! SoundDeviceInstance->CurrentWaveHeader )
|
||||||
|
{
|
||||||
|
/* Start from the beginning (always a good idea) */
|
||||||
|
SoundDeviceInstance->CurrentWaveHeader = SoundDeviceInstance->HeadWaveHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( SoundDeviceInstance->CurrentWaveHeader )
|
||||||
|
{
|
||||||
|
/* Stream or continue streaming this header */
|
||||||
|
|
||||||
|
Result = CommitWaveHeaderToKernelDevice(SoundDeviceInstance,
|
||||||
|
SoundDeviceInstance->CurrentWaveHeader,
|
||||||
|
FunctionTable->CommitWaveBuffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SND_TRACE(L"NOTHING TO DO - REC/PLAY STOPPED\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
CompleteIO
|
||||||
|
An APC called as a result of a call to CommitWaveHeaderToKernelDevice.
|
||||||
|
This will count up the number of bytes which have been dealt with,
|
||||||
|
and when the entire wave header has been dealt with, will call
|
||||||
|
CompleteWaveHeader to have the wave header returned to the client.
|
||||||
|
|
||||||
|
CommitWaveHeaderToKernelDevice
|
||||||
|
Sends portions of the buffer described by the wave header to a kernel
|
||||||
|
device. This must only be called from within the context of the sound
|
||||||
|
thread. The caller supplies either their own commit routine, or uses
|
||||||
|
WriteFileEx_Committer. The committer is called with portions of the
|
||||||
|
buffer specified in the wave header.
|
||||||
|
|
||||||
|
WriteFileEx_Committer
|
||||||
|
Commit buffers using the WriteFileEx API.
|
||||||
|
*/
|
||||||
|
|
||||||
|
VOID CALLBACK
|
||||||
|
CompleteIO(
|
||||||
|
IN DWORD dwErrorCode,
|
||||||
|
IN DWORD dwNumberOfBytesTransferred,
|
||||||
|
IN LPOVERLAPPED lpOverlapped)
|
||||||
|
{
|
||||||
|
PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
|
||||||
|
PSOUND_OVERLAPPED SoundOverlapped = (PSOUND_OVERLAPPED) lpOverlapped;
|
||||||
|
PWAVEHDR WaveHdr;
|
||||||
|
PWAVEHDR_EXTENSION HdrExtension;
|
||||||
|
|
||||||
|
WaveHdr = (PWAVEHDR) SoundOverlapped->Header;
|
||||||
|
SND_ASSERT( WaveHdr );
|
||||||
|
|
||||||
|
HdrExtension = (PWAVEHDR_EXTENSION) WaveHdr->reserved;
|
||||||
|
SND_ASSERT( HdrExtension );
|
||||||
|
|
||||||
|
SoundDeviceInstance = SoundOverlapped->SoundDeviceInstance;
|
||||||
|
|
||||||
|
HdrExtension->BytesCompleted += dwNumberOfBytesTransferred;
|
||||||
|
SND_TRACE(L"%d/%d bytes of wavehdr completed\n", HdrExtension->BytesCompleted, WaveHdr->dwBufferLength);
|
||||||
|
|
||||||
|
/* We have an available buffer now */
|
||||||
|
-- SoundDeviceInstance->OutstandingBuffers;
|
||||||
|
|
||||||
|
if ( HdrExtension->BytesCompleted == WaveHdr->dwBufferLength )
|
||||||
|
{
|
||||||
|
CompleteWaveHeader(SoundDeviceInstance, WaveHdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
DoWaveStreaming(SoundDeviceInstance);
|
||||||
|
|
||||||
|
//CompleteWavePortion(SoundDeviceInstance, dwNumberOfBytesTransferred);
|
||||||
|
|
||||||
|
FreeMemory(lpOverlapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
MMRESULT
|
||||||
|
CommitWaveHeaderToKernelDevice(
|
||||||
|
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||||
|
IN PWAVEHDR Header,
|
||||||
|
IN WAVE_COMMIT_FUNC CommitFunction)
|
||||||
|
{
|
||||||
|
PSOUND_OVERLAPPED Overlap;
|
||||||
|
DWORD BytesToWrite, BytesRemaining;
|
||||||
|
PWAVEHDR_EXTENSION HdrExtension;
|
||||||
|
LPVOID Offset;
|
||||||
|
|
||||||
|
VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
|
||||||
|
VALIDATE_MMSYS_PARAMETER( Header );
|
||||||
|
VALIDATE_MMSYS_PARAMETER( CommitFunction );
|
||||||
|
|
||||||
|
HdrExtension = (PWAVEHDR_EXTENSION) Header->reserved;
|
||||||
|
VALIDATE_MMSYS_PARAMETER( HdrExtension );
|
||||||
|
|
||||||
|
/* Loop whilst there is data and sufficient available buffers */
|
||||||
|
while ( ( SoundDeviceInstance->OutstandingBuffers < SOUND_KERNEL_BUFFER_COUNT ) &&
|
||||||
|
( HdrExtension->BytesCommitted < Header->dwBufferLength ) )
|
||||||
|
{
|
||||||
|
/* Is this the start of a loop? */
|
||||||
|
SoundDeviceInstance->WaveLoopStart = Header;
|
||||||
|
|
||||||
|
/* Where to start pulling the data from within the buffer */
|
||||||
|
Offset = Header->lpData + HdrExtension->BytesCommitted;
|
||||||
|
|
||||||
|
/* How much of this header is not committed? */
|
||||||
|
BytesRemaining = Header->dwBufferLength - HdrExtension->BytesCommitted;
|
||||||
|
|
||||||
|
/* We can write anything up to the buffer size limit */
|
||||||
|
BytesToWrite = BytesRemaining > SOUND_KERNEL_BUFFER_SIZE ?
|
||||||
|
SOUND_KERNEL_BUFFER_SIZE :
|
||||||
|
BytesRemaining;
|
||||||
|
|
||||||
|
/* If there's nothing left in the current header, move to the next */
|
||||||
|
if ( BytesToWrite == 0 )
|
||||||
|
{
|
||||||
|
Header = Header->lpNext;
|
||||||
|
HdrExtension = (PWAVEHDR_EXTENSION) Header->reserved;
|
||||||
|
SND_ASSERT( HdrExtension );
|
||||||
|
SND_ASSERT( HdrExtension->BytesCommitted == 0 );
|
||||||
|
SND_ASSERT( HdrExtension->BytesCompleted == 0 );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
HdrExtension->BytesCommitted += BytesToWrite;
|
||||||
|
|
||||||
|
/* We're using up a buffer so update this */
|
||||||
|
++ SoundDeviceInstance->OutstandingBuffers;
|
||||||
|
|
||||||
|
SND_TRACE(L"COMMIT: Offset 0x%x amount %d remain %d totalcommit %d",
|
||||||
|
Offset, BytesToWrite, BytesRemaining, HdrExtension->BytesCommitted);
|
||||||
|
|
||||||
|
/* We need a new overlapped info structure for each buffer */
|
||||||
|
Overlap = AllocateStruct(SOUND_OVERLAPPED);
|
||||||
|
|
||||||
|
if ( Overlap )
|
||||||
|
{
|
||||||
|
ZeroMemory(Overlap, sizeof(SOUND_OVERLAPPED));
|
||||||
|
Overlap->SoundDeviceInstance = SoundDeviceInstance;
|
||||||
|
Overlap->Header = Header;
|
||||||
|
|
||||||
|
|
||||||
|
if ( ! MMSUCCESS(CommitFunction(SoundDeviceInstance, Offset, BytesToWrite, Overlap, CompleteIO)) )
|
||||||
|
{
|
||||||
|
/* Just pretend it played if we fail... Show must go on, etc. etc. */
|
||||||
|
SND_WARN(L"FAILED\n");
|
||||||
|
HdrExtension->BytesCompleted += BytesToWrite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return MMSYSERR_NOERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
MMRESULT
|
||||||
|
WriteFileEx_Committer(
|
||||||
|
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||||
|
IN PVOID OffsetPtr,
|
||||||
|
IN DWORD Length,
|
||||||
|
IN PSOUND_OVERLAPPED Overlap,
|
||||||
|
IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine)
|
||||||
|
{
|
||||||
|
HANDLE Handle;
|
||||||
|
|
||||||
|
VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
|
||||||
|
VALIDATE_MMSYS_PARAMETER( OffsetPtr );
|
||||||
|
VALIDATE_MMSYS_PARAMETER( Overlap );
|
||||||
|
VALIDATE_MMSYS_PARAMETER( CompletionRoutine );
|
||||||
|
|
||||||
|
GetSoundDeviceInstanceHandle(SoundDeviceInstance, &Handle);
|
||||||
|
|
||||||
|
if ( ! WriteFileEx(Handle, OffsetPtr, Length, (LPOVERLAPPED)Overlap, CompletionRoutine) )
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
return MMSYSERR_NOERROR;
|
||||||
|
}
|
|
@ -94,7 +94,7 @@ wodMessage(
|
||||||
|
|
||||||
case WODM_WRITE :
|
case WODM_WRITE :
|
||||||
{
|
{
|
||||||
Result = MmeEnqueueWaveHeader(PrivateHandle, Parameter1);
|
Result = MmeWriteWaveHeader(PrivateHandle, Parameter1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
* PROGRAMMERS: Andrew Greenwood (silverblade@reactos.org)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define NDEBUG
|
||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <mmsystem.h>
|
#include <mmsystem.h>
|
||||||
#include <mmddk.h>
|
#include <mmddk.h>
|
||||||
|
|
Loading…
Reference in a new issue