mirror of
https://github.com/reactos/reactos.git
synced 2025-04-04 04:26:32 +00:00
Closing of wave output devices is functional and terminates the sound thread
cleanly. Started writing code to support pause/restart (nonfunctional yet.) Stubbed mixer messages, added a readme.txt to give an overview of functions supported. Also includes partial rewrite of wdmaud.drv. Currently I am listening to DI.FM in ReactOS using an NT4 sndblst.sys along with ReactOS' sndblst.dll svn path=/trunk/; revision=39716
This commit is contained in:
parent
0fb477e07a
commit
141ec3a682
12 changed files with 662 additions and 361 deletions
|
@ -93,6 +93,7 @@ BOOLEAN FoundDevice(
|
|||
return FALSE;
|
||||
|
||||
/* Set up our function table */
|
||||
ZeroMemory(&FuncTable, sizeof(MMFUNCTION_TABLE));
|
||||
FuncTable.GetCapabilities = GetSoundBlasterDeviceCapabilities;
|
||||
FuncTable.QueryWaveFormatSupport = QueryNt4WaveDeviceFormatSupport;
|
||||
FuncTable.SetWaveFormat = SetNt4WaveDeviceFormat;
|
||||
|
|
|
@ -18,9 +18,268 @@
|
|||
#include <mmddk.h>
|
||||
#include <mmebuddy.h>
|
||||
|
||||
#include <ks.h>
|
||||
#include <ksmedia.h>
|
||||
#include "interface.h"
|
||||
|
||||
#define KERNEL_DEVICE_NAME L"\\\\Device\\wdmaud"
|
||||
|
||||
PWSTR UnknownWaveIn = L"Wave Input";
|
||||
PWSTR UnknownWaveOut = L"Wave Output";
|
||||
PWSTR UnknownMidiIn = L"Midi Input";
|
||||
PWSTR UnknownMidiOut = L"Midi Output";
|
||||
|
||||
HANDLE KernelHandle = INVALID_HANDLE_VALUE;
|
||||
DWORD OpenCount = 0;
|
||||
|
||||
|
||||
MMRESULT
|
||||
GetNumWdmDevs(
|
||||
IN HANDLE Handle,
|
||||
IN MMDEVICE_TYPE DeviceType,
|
||||
OUT DWORD* DeviceCount)
|
||||
{
|
||||
MMRESULT Result;
|
||||
WDMAUD_DEVICE_INFO DeviceInfo;
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( Handle != INVALID_HANDLE_VALUE );
|
||||
VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
|
||||
VALIDATE_MMSYS_PARAMETER( DeviceCount );
|
||||
|
||||
ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
|
||||
DeviceInfo.DeviceType = DeviceType;
|
||||
|
||||
Result = SyncOverlappedDeviceIoControl(Handle,
|
||||
IOCTL_GETNUMDEVS_TYPE,
|
||||
(LPVOID) &DeviceInfo,
|
||||
sizeof(WDMAUD_DEVICE_INFO),
|
||||
(LPVOID) &DeviceInfo,
|
||||
sizeof(WDMAUD_DEVICE_INFO),
|
||||
NULL);
|
||||
|
||||
if ( ! Result )
|
||||
{
|
||||
*DeviceCount = 0;
|
||||
return TranslateInternalMmResult(Result);
|
||||
}
|
||||
|
||||
*DeviceCount = DeviceInfo.DeviceCount;
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
GetWdmDeviceCapabilities(
|
||||
IN PSOUND_DEVICE SoundDevice,
|
||||
OUT PVOID Capabilities,
|
||||
IN DWORD CapabilitiesSize)
|
||||
{
|
||||
/* NOTE - At this time, WDMAUD does not support this properly */
|
||||
|
||||
MMRESULT Result;
|
||||
MMDEVICE_TYPE DeviceType;
|
||||
|
||||
SND_ASSERT( SoundDevice );
|
||||
SND_ASSERT( Capabilities );
|
||||
|
||||
SND_TRACE(L"WDMAUD - GetWdmDeviceCapabilities\n");
|
||||
|
||||
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
|
||||
SND_ASSERT( Result == MMSYSERR_NOERROR );
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return Result;
|
||||
|
||||
/* This is pretty much a big hack right now */
|
||||
switch ( DeviceType )
|
||||
{
|
||||
case WAVE_OUT_DEVICE_TYPE :
|
||||
{
|
||||
LPWAVEOUTCAPS WaveOutCaps = (LPWAVEOUTCAPS) Capabilities;
|
||||
WaveOutCaps->wMid = 0;
|
||||
WaveOutCaps->wPid = 0;
|
||||
WaveOutCaps->vDriverVersion = 0x0001;
|
||||
CopyWideString(WaveOutCaps->szPname, UnknownWaveOut);
|
||||
|
||||
/* HACK: We may not really support all formats! */
|
||||
WaveOutCaps->dwFormats = 0xffffffff;
|
||||
WaveOutCaps->wChannels = 2;
|
||||
WaveOutCaps->dwSupport = 0;
|
||||
break;
|
||||
}
|
||||
case WAVE_IN_DEVICE_TYPE :
|
||||
{
|
||||
LPWAVEINCAPS WaveInCaps = (LPWAVEINCAPS) Capabilities;
|
||||
CopyWideString(WaveInCaps->szPname, UnknownWaveIn);
|
||||
/* TODO... other fields */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
|
||||
MMRESULT
|
||||
OpenWdmSoundDevice(
|
||||
IN struct _SOUND_DEVICE* SoundDevice, /* NOT USED */
|
||||
OUT PVOID* Handle)
|
||||
{
|
||||
/* Only open this if it's not already open */
|
||||
if ( KernelHandle == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
KernelHandle = CreateFile(KERNEL_DEVICE_NAME,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_OVERLAPPED,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if ( KernelHandle == INVALID_HANDLE_VALUE )
|
||||
return MMSYSERR_ERROR;
|
||||
|
||||
SND_ASSERT( Handle );
|
||||
|
||||
*Handle = KernelHandle;
|
||||
++ OpenCount;
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
CloseWdmSoundDevice(
|
||||
IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance, /* NOT USED */
|
||||
IN PVOID Handle)
|
||||
{
|
||||
SND_ASSERT( OpenCount > 0 );
|
||||
SND_ASSERT( KernelHandle != INVALID_HANDLE_VALUE );
|
||||
|
||||
-- OpenCount;
|
||||
|
||||
if ( OpenCount < 1 )
|
||||
{
|
||||
CloseHandle(KernelHandle);
|
||||
KernelHandle = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
|
||||
MMRESULT
|
||||
QueryWdmWaveDeviceFormatSupport(
|
||||
IN PSOUND_DEVICE Device,
|
||||
IN PWAVEFORMATEX WaveFormat,
|
||||
IN DWORD WaveFormatSize)
|
||||
{
|
||||
/* Whatever... */
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
SetWdmWaveDeviceFormat(
|
||||
IN PSOUND_DEVICE_INSTANCE Instance,
|
||||
IN PWAVEFORMATEX WaveFormat,
|
||||
IN DWORD WaveFormatSize)
|
||||
{
|
||||
MMRESULT Result;
|
||||
PSOUND_DEVICE SoundDevice;
|
||||
PVOID Identifier;
|
||||
WDMAUD_DEVICE_INFO DeviceInfo;
|
||||
|
||||
Result = GetSoundDeviceFromInstance(Instance, &SoundDevice);
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
{
|
||||
return TranslateInternalMmResult(Result);
|
||||
}
|
||||
|
||||
Result = GetSoundDeviceIdentifier(SoundDevice, &Identifier);
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
{
|
||||
return TranslateInternalMmResult(Result);
|
||||
}
|
||||
|
||||
ZeroMemory(&DeviceInfo, sizeof(WDMAUD_DEVICE_INFO));
|
||||
DeviceInfo.u.WaveFormatEx.cbSize = WaveFormat->cbSize;
|
||||
DeviceInfo.u.WaveFormatEx.wFormatTag = WaveFormat->wFormatTag;
|
||||
DeviceInfo.u.WaveFormatEx.nChannels = WaveFormat->nChannels;
|
||||
DeviceInfo.u.WaveFormatEx.nSamplesPerSec = WaveFormat->nSamplesPerSec;
|
||||
DeviceInfo.u.WaveFormatEx.nBlockAlign = WaveFormat->nBlockAlign;
|
||||
DeviceInfo.u.WaveFormatEx.nAvgBytesPerSec = WaveFormat->nAvgBytesPerSec;
|
||||
DeviceInfo.u.WaveFormatEx.wBitsPerSample = WaveFormat->wBitsPerSample;
|
||||
|
||||
Result = SyncOverlappedDeviceIoControl(KernelHandle,
|
||||
IOCTL_OPEN_WDMAUD,
|
||||
(LPVOID) &DeviceInfo,
|
||||
sizeof(WDMAUD_DEVICE_INFO),
|
||||
(LPVOID) &DeviceInfo,
|
||||
sizeof(WDMAUD_DEVICE_INFO),
|
||||
NULL);
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
{
|
||||
return TranslateInternalMmResult(Result);
|
||||
}
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
|
||||
MMRESULT
|
||||
PopulateWdmDeviceList(
|
||||
HANDLE Handle,
|
||||
MMDEVICE_TYPE DeviceType)
|
||||
{
|
||||
MMRESULT Result;
|
||||
DWORD DeviceCount = 0;
|
||||
PSOUND_DEVICE SoundDevice = NULL;
|
||||
MMFUNCTION_TABLE FuncTable;
|
||||
DWORD i;
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( Handle != INVALID_HANDLE_VALUE );
|
||||
VALIDATE_MMSYS_PARAMETER( IS_VALID_SOUND_DEVICE_TYPE(DeviceType) );
|
||||
|
||||
Result = GetNumWdmDevs(Handle, DeviceType, &DeviceCount);
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
{
|
||||
SND_ERR(L"Error %d while obtaining number of devices\n", Result);
|
||||
return TranslateInternalMmResult(Result);
|
||||
}
|
||||
|
||||
SND_TRACE(L"%d devices of type %d found\n", DeviceCount, DeviceType);
|
||||
|
||||
|
||||
for ( i = 0; i < DeviceCount; ++ i )
|
||||
{
|
||||
Result = ListSoundDevice(DeviceType, (PVOID) i, &SoundDevice);
|
||||
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
{
|
||||
SND_ERR(L"Failed to list sound device - error %d\n", Result);
|
||||
return TranslateInternalMmResult(Result);
|
||||
}
|
||||
|
||||
/* Set up our function table */
|
||||
ZeroMemory(&FuncTable, sizeof(MMFUNCTION_TABLE));
|
||||
FuncTable.GetCapabilities = GetWdmDeviceCapabilities;
|
||||
FuncTable.QueryWaveFormatSupport = QueryWdmWaveDeviceFormatSupport;
|
||||
FuncTable.SetWaveFormat = SetWdmWaveDeviceFormat;
|
||||
FuncTable.Open = OpenWdmSoundDevice;
|
||||
FuncTable.Close = CloseWdmSoundDevice;
|
||||
//FuncTable.CommitWaveBuffer = WriteFileEx_Committer;
|
||||
|
||||
SetSoundDeviceFunctionTable(SoundDevice, &FuncTable);
|
||||
}
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
|
||||
|
||||
APIENTRY LONG
|
||||
DriverProc(
|
||||
|
@ -36,6 +295,7 @@ DriverProc(
|
|||
{
|
||||
case DRV_LOAD :
|
||||
{
|
||||
HANDLE Handle;
|
||||
SND_TRACE(L"DRV_LOAD\n");
|
||||
|
||||
Result = InitEntrypointMutexes();
|
||||
|
@ -43,24 +303,29 @@ DriverProc(
|
|||
if ( ! MMSUCCESS(Result) )
|
||||
return 0L;
|
||||
|
||||
KernelHandle = CreateFile(KERNEL_DEVICE_NAME,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_WRITE, // ok?
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_OVERLAPPED,
|
||||
NULL);
|
||||
OpenWdmSoundDevice(NULL, &Handle);
|
||||
|
||||
if ( KernelHandle == INVALID_HANDLE_VALUE )
|
||||
if ( Handle == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
SND_ERR(L"Failed to open %s\n", KERNEL_DEVICE_NAME);
|
||||
CleanupEntrypointMutexes();
|
||||
|
||||
UnlistAllSoundDevices();
|
||||
//UnlistAllSoundDevices();
|
||||
|
||||
return 0L;
|
||||
}
|
||||
|
||||
/* Populate the device lists */
|
||||
SND_TRACE(L"Populating device lists\n");
|
||||
PopulateWdmDeviceList(KernelHandle, WAVE_OUT_DEVICE_TYPE);
|
||||
PopulateWdmDeviceList(KernelHandle, WAVE_IN_DEVICE_TYPE);
|
||||
PopulateWdmDeviceList(KernelHandle, MIDI_OUT_DEVICE_TYPE);
|
||||
PopulateWdmDeviceList(KernelHandle, MIDI_IN_DEVICE_TYPE);
|
||||
PopulateWdmDeviceList(KernelHandle, AUX_DEVICE_TYPE);
|
||||
PopulateWdmDeviceList(KernelHandle, MIXER_DEVICE_TYPE);
|
||||
|
||||
CloseWdmSoundDevice(NULL, Handle);
|
||||
|
||||
SND_TRACE(L"Initialisation complete\n");
|
||||
|
||||
return 1L;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<importlibrary definition="wdmaud.spec" />
|
||||
<include base="wdmaud.drv">.</include>
|
||||
<include base="ReactOS">include/reactos/libs/sound</include>
|
||||
<include base="wdmaud_kernel">.</include>
|
||||
<define name="DEBUG_NT4" /><!-- Use custom debug routines -->
|
||||
<library>mmebuddy</library>
|
||||
<library>ntdll</library>
|
||||
|
|
|
@ -181,6 +181,7 @@ typedef struct _SOUND_OVERLAPPED
|
|||
OVERLAPPED Standard;
|
||||
struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance;
|
||||
PWAVEHDR Header;
|
||||
BOOL PerformCompletion;
|
||||
} SOUND_OVERLAPPED, *PSOUND_OVERLAPPED;
|
||||
|
||||
typedef MMRESULT (*WAVE_COMMIT_FUNC)(
|
||||
|
@ -314,8 +315,9 @@ typedef struct _SOUND_DEVICE_INSTANCE
|
|||
};
|
||||
|
||||
PWAVEHDR WaveLoopStart;
|
||||
PWAVEHDR CurrentWaveHeader;
|
||||
//PWAVEHDR CurrentWaveHeader;
|
||||
DWORD OutstandingBuffers;
|
||||
DWORD LoopsRemaining;
|
||||
} SOUND_DEVICE_INSTANCE, *PSOUND_DEVICE_INSTANCE;
|
||||
|
||||
/* This lives in WAVEHDR.reserved */
|
||||
|
@ -383,6 +385,10 @@ MmeCloseDevice(
|
|||
#define MmeWriteWaveHeader(private_handle, header) \
|
||||
WriteWaveHeader((PSOUND_DEVICE_INSTANCE)private_handle, (PWAVEHDR)header)
|
||||
|
||||
MMRESULT
|
||||
MmeResetWavePlayback(
|
||||
IN DWORD PrivateHandle);
|
||||
|
||||
|
||||
/*
|
||||
capabilities.c
|
||||
|
@ -619,31 +625,15 @@ WriteFileEx_Committer(
|
|||
IN PSOUND_OVERLAPPED Overlap,
|
||||
IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine);
|
||||
|
||||
MMRESULT
|
||||
StopStreaming(
|
||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance);
|
||||
|
||||
|
||||
/*
|
||||
kernel.c
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#define QueryDevice(h, ctl, o, o_size, xfer, ovl) \
|
||||
Win32ErrorToMmResult( \
|
||||
DeviceIoControl(h, ctl, NULL, 0, o, o_size, xfer, ovl) != 0 \
|
||||
? ERROR_SUCCESS : GetLastError() \
|
||||
)
|
||||
|
||||
#define ControlDevice(h, ctl, i, i_size, xfer, ovl) \
|
||||
Win32ErrorToMmResult( \
|
||||
DeviceIoControl(h, ctl, i, i_size, NULL, 0, xfer, ovl) != 0 \
|
||||
? ERROR_SUCCESS : GetLastError() \
|
||||
)
|
||||
|
||||
#define QuerySoundDevice(sd, ctl, o, o_size, xfer) \
|
||||
SoundDeviceIoControl(sd, ctl, NULL, 0, o, o_size, xfer)
|
||||
|
||||
#define ControlSoundDevice(sd, ctl, i, i_size, xfer) \
|
||||
SoundDeviceIoControl(sd, ctl, i, i_size, NULL, 0, xfer)
|
||||
#endif
|
||||
|
||||
MMRESULT
|
||||
OpenKernelSoundDeviceByName(
|
||||
IN PWSTR DevicePath,
|
||||
|
@ -671,182 +661,4 @@ SyncOverlappedDeviceIoControl(
|
|||
OUT LPDWORD BytesTransferred OPTIONAL);
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
typedef UCHAR MMDEVICE_TYPE, *PMMDEVICE_TYPE;
|
||||
|
||||
struct _SOUND_DEVICE;
|
||||
struct _SOUND_DEVICE_INSTANCE;
|
||||
|
||||
|
||||
/*
|
||||
Rather than pass caps structures around as a PVOID, this can be
|
||||
used instead.
|
||||
*/
|
||||
|
||||
typedef union _UNIVERSAL_CAPS
|
||||
{
|
||||
WAVEOUTCAPS WaveOut;
|
||||
WAVEINCAPS WaveIn;
|
||||
MIDIOUTCAPS MidiOut;
|
||||
MIDIINCAPS MidiIn;
|
||||
} UNIVERSAL_CAPS, *PUNIVERSAL_CAPS;
|
||||
|
||||
|
||||
|
||||
/* New sound thread code */
|
||||
|
||||
typedef MMRESULT (*SOUND_THREAD_REQUEST_HANDLER)(
|
||||
IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
|
||||
IN OPTIONAL PVOID Parameter);
|
||||
|
||||
typedef struct _SOUND_THREAD_REQUEST
|
||||
{
|
||||
/* The sound device instance this request relates to */
|
||||
struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance;
|
||||
/* What function to call */
|
||||
SOUND_THREAD_REQUEST_HANDLER RequestHandler;
|
||||
/* Caller-defined parameter */
|
||||
PVOID Parameter;
|
||||
/* This will contain the return code of the request function */
|
||||
MMRESULT ReturnValue;
|
||||
} SOUND_THREAD_REQUEST, *PSOUND_THREAD_REQUEST;
|
||||
|
||||
typedef VOID (*SOUND_THREAD_IO_COMPLETION_HANDLER)(
|
||||
IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance,
|
||||
IN PVOID Parameter OPTIONAL,
|
||||
IN DWORD BytesWritten);
|
||||
|
||||
typedef struct _SOUND_THREAD_COMPLETED_IO
|
||||
{
|
||||
struct _SOUND_THREAD_COMPLETED_IO* Previous;
|
||||
struct _SOUND_THREAD_COMPLETED_IO* Next;
|
||||
|
||||
struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance;
|
||||
SOUND_THREAD_IO_COMPLETION_HANDLER CompletionHandler;
|
||||
PVOID Parameter;
|
||||
DWORD BytesTransferred;
|
||||
} SOUND_THREAD_COMPLETED_IO, *PSOUND_THREAD_COMPLETED_IO;
|
||||
|
||||
typedef struct _SOUND_THREAD_OVERLAPPED
|
||||
{
|
||||
OVERLAPPED General;
|
||||
|
||||
/* Pointer to structure to fill with completion data */
|
||||
PSOUND_THREAD_COMPLETED_IO CompletionData;
|
||||
} SOUND_THREAD_OVERLAPPED, *PSOUND_THREAD_OVERLAPPED;
|
||||
|
||||
/*
|
||||
Audio device function table
|
||||
*/
|
||||
|
||||
typedef MMRESULT (*MMCREATEINSTANCE_FUNC)(
|
||||
IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance);
|
||||
|
||||
typedef VOID (*MMDESTROYINSTANCE_FUNC)(
|
||||
IN struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance);
|
||||
|
||||
typedef MMRESULT (*MMGETCAPS_FUNC)(
|
||||
IN struct _SOUND_DEVICE* Device,
|
||||
OUT PUNIVERSAL_CAPS Capabilities);
|
||||
|
||||
typedef MMRESULT (*MMWAVEQUERYFORMAT_FUNC)(
|
||||
IN struct _SOUND_DEVICE* Device,
|
||||
IN PWAVEFORMATEX WaveFormat,
|
||||
IN DWORD WaveFormatSize);
|
||||
|
||||
typedef MMRESULT (*MMWAVESETFORMAT_FUNC)(
|
||||
IN struct _SOUND_DEVICE_INSTANCE* Instance,
|
||||
IN PWAVEFORMATEX WaveFormat,
|
||||
IN DWORD WaveFormatSize);
|
||||
|
||||
typedef MMRESULT (*MMWAVEQUEUEBUFFER_FUNC)(
|
||||
IN struct _SOUND_DEVICE_INSTANCE* Instance,
|
||||
IN PWAVEHDR WaveHeader);
|
||||
|
||||
typedef MMRESULT (*MMGETWAVESTATE_FUNC)(
|
||||
IN struct _SOUND_DEVICE_INSTANCE* Instance,
|
||||
OUT PULONG State);
|
||||
|
||||
typedef MMRESULT (*MMSETWAVESTATE_FUNC)(
|
||||
IN struct _SOUND_DEVICE_INSTANCE* Instance);
|
||||
|
||||
typedef struct _MMFUNCTION_TABLE
|
||||
{
|
||||
MMCREATEINSTANCE_FUNC Constructor;
|
||||
MMDESTROYINSTANCE_FUNC Destructor;
|
||||
MMGETCAPS_FUNC GetCapabilities;
|
||||
|
||||
MMWAVEQUERYFORMAT_FUNC QueryWaveFormat;
|
||||
MMWAVESETFORMAT_FUNC SetWaveFormat;
|
||||
MMWAVEQUEUEBUFFER_FUNC QueueWaveBuffer;
|
||||
|
||||
MMGETWAVESTATE_FUNC GetWaveDeviceState;
|
||||
MMSETWAVESTATE_FUNC PauseWaveDevice;
|
||||
MMSETWAVESTATE_FUNC RestartWaveDevice;
|
||||
MMSETWAVESTATE_FUNC ResetWaveDevice;
|
||||
MMSETWAVESTATE_FUNC BreakWaveDeviceLoop;
|
||||
} MMFUNCTION_TABLE, *PMMFUNCTION_TABLE;
|
||||
|
||||
|
||||
/*
|
||||
Represents an audio device
|
||||
*/
|
||||
|
||||
#define SOUND_DEVICE_TAG "SndD"
|
||||
|
||||
typedef struct _SOUND_DEVICE
|
||||
{
|
||||
struct _SOUND_DEVICE* Next;
|
||||
struct _SOUND_DEVICE_INSTANCE* FirstInstance;
|
||||
UCHAR DeviceType;
|
||||
LPWSTR DevicePath;
|
||||
MMFUNCTION_TABLE Functions;
|
||||
} SOUND_DEVICE, *PSOUND_DEVICE;
|
||||
|
||||
|
||||
/*
|
||||
Represents an individual instance of an audio device
|
||||
*/
|
||||
|
||||
#define WAVE_STREAM_INFO_TAG "WavS"
|
||||
|
||||
typedef struct _WAVE_STREAM_INFO
|
||||
{
|
||||
/* Buffer queue head and tail */
|
||||
PWAVEHDR BufferQueueHead;
|
||||
PWAVEHDR BufferQueueTail;
|
||||
/* The buffer currently being processed */
|
||||
PWAVEHDR CurrentBuffer;
|
||||
/* How far into the current buffer we've gone */
|
||||
DWORD BufferOffset;
|
||||
/* How many I/O operations have been submitted */
|
||||
DWORD BuffersOutstanding;
|
||||
/* Looping */
|
||||
PWAVEHDR LoopHead;
|
||||
DWORD LoopsRemaining;
|
||||
} WAVE_STREAM_INFO, *PWAVE_STREAM_INFO;
|
||||
|
||||
|
||||
#define SOUND_DEVICE_INSTANCE_TAG "SndI"
|
||||
|
||||
typedef struct _SOUND_DEVICE_INSTANCE
|
||||
{
|
||||
struct _SOUND_DEVICE_INSTANCE* Next;
|
||||
PSOUND_DEVICE Device;
|
||||
|
||||
/* The currently opened handle to the device */
|
||||
HANDLE Handle;
|
||||
/* PSOUND_THREAD Thread;*/
|
||||
|
||||
|
||||
/* Device-specific parameters */
|
||||
union
|
||||
{
|
||||
WAVE_STREAM_INFO Wave;
|
||||
} Streaming;
|
||||
} SOUND_DEVICE_INSTANCE, *PSOUND_DEVICE_INSTANCE;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -37,8 +37,12 @@ VOID
|
|||
FreeSoundDeviceInstance(
|
||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
|
||||
{
|
||||
/* This won't work as the device is no longer valid by this point! */
|
||||
/*SND_ASSERT( IsValidSoundDeviceInstance(SoundDeviceInstance) );*/
|
||||
/*
|
||||
Device is marked as invalid by now, but we can still do some sanity
|
||||
checking.
|
||||
*/
|
||||
SND_ASSERT( SoundDeviceInstance->Thread == NULL );
|
||||
|
||||
ZeroMemory(SoundDeviceInstance, sizeof(SOUND_DEVICE_INSTANCE));
|
||||
FreeMemory(SoundDeviceInstance);
|
||||
}
|
||||
|
@ -190,9 +194,9 @@ CreateSoundDeviceInstance(
|
|||
(*SoundDeviceInstance)->HeadWaveHeader = NULL;
|
||||
(*SoundDeviceInstance)->TailWaveHeader = NULL;
|
||||
|
||||
(*SoundDeviceInstance)->CurrentWaveHeader = NULL;
|
||||
(*SoundDeviceInstance)->OutstandingBuffers = 0;
|
||||
// TODO: Loop
|
||||
|
||||
(*SoundDeviceInstance)->LoopsRemaining = 0;
|
||||
|
||||
/* Create the streaming thread (TODO - is this for wave only?) */
|
||||
Result = CreateSoundThread(&(*SoundDeviceInstance)->Thread);
|
||||
|
@ -255,13 +259,26 @@ DestroySoundDeviceInstance(
|
|||
return MMSYSERR_NOTSUPPORTED;
|
||||
}
|
||||
|
||||
/* Stop the streaming thread (TODO - is this for wave only?) */
|
||||
Result = DestroySoundThread(SoundDeviceInstance->Thread);
|
||||
SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */
|
||||
if ( ! MMSUCCESS(Result ) )
|
||||
{
|
||||
return TranslateInternalMmResult(Result);
|
||||
}
|
||||
|
||||
/* Blank this out here */
|
||||
SoundDeviceInstance->Thread = NULL;
|
||||
|
||||
/* Try and close the device */
|
||||
Result = FunctionTable->Close(SoundDeviceInstance, Handle);
|
||||
SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
/* Drop it from the list */
|
||||
Result = UnlistSoundDeviceInstance(SoundDeviceInstance);
|
||||
SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
|
@ -274,7 +291,19 @@ MMRESULT
|
|||
DestroyAllSoundDeviceInstances(
|
||||
IN PSOUND_DEVICE SoundDevice)
|
||||
{
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
MMRESULT Result;
|
||||
PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
|
||||
|
||||
SoundDeviceInstance = SoundDevice->HeadInstance;
|
||||
|
||||
while ( SoundDeviceInstance )
|
||||
{
|
||||
Result = DestroySoundDeviceInstance(SoundDeviceInstance);
|
||||
SND_ASSERT( MMSUCCESS(Result) );
|
||||
SoundDeviceInstance = SoundDeviceInstance->Next;
|
||||
}
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
|
|
|
@ -51,6 +51,41 @@ mxdMessage(
|
|||
Parameter2);
|
||||
break;
|
||||
}
|
||||
|
||||
case MXDM_INIT :
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case MXDM_OPEN :
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case MXDM_CLOSE :
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case MXDM_GETCONTROLDETAILS :
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case MXDM_SETCONTROLDETAILS :
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case MXDM_GETLINECONTROLS :
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
case MXDM_GETLINEINFO :
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SND_TRACE(L"mxdMessage returning MMRESULT %d\n", Result);
|
||||
|
|
|
@ -164,6 +164,9 @@ MmeCloseDevice(
|
|||
VALIDATE_MMSYS_PARAMETER( PrivateHandle );
|
||||
SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
|
||||
|
||||
if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) )
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
|
||||
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
@ -172,7 +175,11 @@ MmeCloseDevice(
|
|||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
|
||||
/* TODO: Check device is stopped! */
|
||||
|
||||
ReleaseEntrypointMutex(DeviceType);
|
||||
/* TODO: Work with MIDI devices too */
|
||||
NotifyMmeClient(SoundDeviceInstance,
|
||||
DeviceType == WAVE_OUT_DEVICE_TYPE ? WOM_CLOSE : WIM_CLOSE,
|
||||
0);
|
||||
|
@ -182,3 +189,17 @@ MmeCloseDevice(
|
|||
|
||||
return Result;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
MmeResetWavePlayback(
|
||||
IN DWORD PrivateHandle)
|
||||
{
|
||||
PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
|
||||
|
||||
SND_TRACE(L"Resetting wave device (WODM_RESET)\n");
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( PrivateHandle );
|
||||
SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
|
||||
|
||||
return StopStreaming(SoundDeviceInstance);
|
||||
}
|
||||
|
|
90
reactos/lib/drivers/sound/mmebuddy/readme.txt
Normal file
90
reactos/lib/drivers/sound/mmebuddy/readme.txt
Normal file
|
@ -0,0 +1,90 @@
|
|||
MME BUDDY
|
||||
|
||||
This library currently is capable of maintaining lists of devices for all of
|
||||
the MME types, it will provide the appropriate entrypoints for each device
|
||||
type, and code using this library simply needs to inform the MME Buddy
|
||||
library of the devices that exist, and provide callback routines to be used
|
||||
when opening/closing/playing, etc.
|
||||
|
||||
Code using this library needs to provide its own DriverProc entrypoint (this
|
||||
may be refactored in future so that simply an init/cleanup routine need be
|
||||
provided.)
|
||||
|
||||
|
||||
WAVE OUTPUT
|
||||
===========
|
||||
Supported MME messages:
|
||||
* WODM_GETNUMDEVS (Get number of devices)
|
||||
* WODM_GETDEVCAPS (Get device capabilities)
|
||||
* WODM_OPEN (Open a device, query supported formats)
|
||||
* WODM_CLOSE (Close a device)
|
||||
* WODM_PREPARE (Prepare a wave header)
|
||||
* WODM_UNPREPARE (Unprepare a wave header)
|
||||
* WODM_WRITE (Submit a prepared header to be played)
|
||||
|
||||
Unsupported MME messages:
|
||||
* Any not mentioned above
|
||||
|
||||
Notes/Bugs:
|
||||
* WHDR_BEGINLOOP and WHDR_ENDLOOP are ignored
|
||||
* Not possible to pause/restart playback
|
||||
|
||||
|
||||
WAVE INPUT
|
||||
==========
|
||||
Supported MME messages:
|
||||
* WIDM_GETNUMDEVS (Get number of devices)
|
||||
|
||||
Unsupported MME messages:
|
||||
* Any not mentioned above
|
||||
|
||||
Notes/Bugs:
|
||||
* Mostly unimplemented
|
||||
|
||||
|
||||
MIDI OUTPUT
|
||||
===========
|
||||
Supported MME messages:
|
||||
* MODM_GETNUMDEVS (Get number of devices)
|
||||
|
||||
Unsupported MME messages:
|
||||
* Any not mentioned above
|
||||
|
||||
Notes/Bugs:
|
||||
* Mostly unimplemented
|
||||
|
||||
|
||||
MIDI INPUT
|
||||
==========
|
||||
Supported MME messages:
|
||||
* MIDM_GETNUMDEVS (Get number of devices)
|
||||
|
||||
Unsupported MME messages:
|
||||
* Any not mentioned above
|
||||
|
||||
Notes/Bugs:
|
||||
* Mostly unimplemented
|
||||
|
||||
|
||||
AUXILIARY
|
||||
=========
|
||||
Supported MME messages:
|
||||
* AUXM_GETNUMDEVS (Get number of devices)
|
||||
|
||||
Unsupported MME messages:
|
||||
* Any not mentioned above
|
||||
|
||||
Notes/Bugs:
|
||||
* Mostly unimplemented
|
||||
|
||||
|
||||
MIXER
|
||||
=====
|
||||
Supported MME messages:
|
||||
* MXDM_GETNUMDEVS (Get number of devices)
|
||||
|
||||
Unsupported MME messages:
|
||||
* Any not mentioned above
|
||||
|
||||
Notes/Bugs:
|
||||
* Mostly unimplemented
|
|
@ -56,7 +56,7 @@ SoundThreadMain(
|
|||
else if ( WaitResult == WAIT_IO_COMPLETION )
|
||||
{
|
||||
SND_TRACE(L"SoundThread - Processing IO completion\n");
|
||||
/* TODO */
|
||||
/* TODO? What do we do here? Stream stuff? */
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -66,9 +66,95 @@ SoundThreadMain(
|
|||
|
||||
}
|
||||
|
||||
SND_TRACE(L"Sound thread terminated\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
CallSoundThread(
|
||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||
IN SOUND_THREAD_REQUEST_HANDLER RequestHandler,
|
||||
IN PVOID Parameter OPTIONAL)
|
||||
{
|
||||
PSOUND_THREAD Thread;
|
||||
|
||||
VALIDATE_MMSYS_PARAMETER( IsValidSoundDeviceInstance(SoundDeviceInstance) );
|
||||
VALIDATE_MMSYS_PARAMETER( RequestHandler );
|
||||
|
||||
Thread = SoundDeviceInstance->Thread;
|
||||
|
||||
SND_TRACE(L"Waiting for READY event\n");
|
||||
WaitForSingleObject(Thread->Events.Ready, INFINITE);
|
||||
|
||||
Thread->Request.Result = MMSYSERR_NOTSUPPORTED;
|
||||
Thread->Request.Handler = RequestHandler;
|
||||
Thread->Request.SoundDeviceInstance = SoundDeviceInstance;
|
||||
Thread->Request.Parameter = Parameter;
|
||||
|
||||
/* Notify the thread it has work to do */
|
||||
SND_TRACE(L"Setting REQUEST event\n");
|
||||
SetEvent(Thread->Events.Request);
|
||||
|
||||
/* Wait for the work to be done */
|
||||
SND_TRACE(L"Waiting for DONE event\n");
|
||||
WaitForSingleObject(Thread->Events.Done, INFINITE);
|
||||
|
||||
return Thread->Request.Result;
|
||||
}
|
||||
|
||||
|
||||
MMRESULT
|
||||
SoundThreadTerminator(
|
||||
IN PSOUND_DEVICE_INSTANCE Instance,
|
||||
IN PVOID Parameter)
|
||||
{
|
||||
PSOUND_THREAD Thread = (PSOUND_THREAD) Parameter;
|
||||
|
||||
SND_TRACE(L"Sound thread terminator routine called\n");
|
||||
SND_ASSERT( Thread );
|
||||
|
||||
Thread->Running = FALSE;
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
TerminateSoundThread(
|
||||
IN PSOUND_THREAD Thread)
|
||||
{
|
||||
DWORD WaitResult;
|
||||
|
||||
SND_ASSERT( Thread );
|
||||
|
||||
SND_TRACE(L"Waiting for READY event\n");
|
||||
WaitForSingleObject(Thread->Events.Ready, INFINITE);
|
||||
|
||||
Thread->Request.Result = MMSYSERR_NOTSUPPORTED;
|
||||
Thread->Request.Handler = SoundThreadTerminator;
|
||||
Thread->Request.SoundDeviceInstance = NULL;
|
||||
Thread->Request.Parameter = (PVOID) Thread;
|
||||
|
||||
/* Notify the thread it has work to do */
|
||||
SND_TRACE(L"Setting REQUEST event\n");
|
||||
SetEvent(Thread->Events.Request);
|
||||
|
||||
/* Wait for the work to be done */
|
||||
SND_TRACE(L"Waiting for DONE event\n");
|
||||
WaitForSingleObject(Thread->Events.Done, INFINITE);
|
||||
|
||||
/* Wait for the thread to actually end */
|
||||
WaitResult = WaitForSingleObject(Thread->Handle, INFINITE);
|
||||
SND_ASSERT( WaitResult == WAIT_OBJECT_0 );
|
||||
|
||||
/* Close the thread and invalidate the handle */
|
||||
CloseHandle(Thread->Handle); /* Is this needed? */
|
||||
Thread->Handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
|
||||
MMRESULT
|
||||
CreateSoundThreadEvents(
|
||||
OUT HANDLE* ReadyEvent,
|
||||
|
@ -195,39 +281,28 @@ DestroySoundThread(
|
|||
IN PSOUND_THREAD Thread)
|
||||
{
|
||||
VALIDATE_MMSYS_PARAMETER( Thread );
|
||||
SND_ASSERT( Thread->Handle != INVALID_HANDLE_VALUE );
|
||||
|
||||
SND_TRACE(L"Terminating sound thread\n");
|
||||
Thread->Running = FALSE;
|
||||
/* TODO: Implement me! Wait for thread to have finished? */
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
/* Tell the thread to terminate itself */
|
||||
TerminateSoundThread(Thread);
|
||||
|
||||
SND_TRACE(L"Sound thread terminated, performing cleanup of thread resources\n");
|
||||
|
||||
CloseHandle(Thread->Handle); /* Is this needed? */
|
||||
Thread->Handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
DestroySoundThreadEvents(Thread->Events.Ready,
|
||||
Thread->Events.Request,
|
||||
Thread->Events.Done);
|
||||
|
||||
/* Wipe and free the memory used for the thread */
|
||||
ZeroMemory(Thread, sizeof(SOUND_THREAD));
|
||||
FreeMemory(Thread);
|
||||
|
||||
SND_TRACE(L"Finished thread cleanup\n");
|
||||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
CallSoundThread(
|
||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||
IN SOUND_THREAD_REQUEST_HANDLER RequestHandler,
|
||||
IN PVOID Parameter OPTIONAL)
|
||||
{
|
||||
VALIDATE_MMSYS_PARAMETER( SoundDeviceInstance );
|
||||
VALIDATE_MMSYS_PARAMETER( RequestHandler );
|
||||
|
||||
/* TODO: Don't call this directly? */
|
||||
PSOUND_THREAD Thread = SoundDeviceInstance->Thread;
|
||||
|
||||
SND_TRACE(L"Waiting for READY event\n");
|
||||
WaitForSingleObject(Thread->Events.Ready, INFINITE);
|
||||
|
||||
Thread->Request.Result = MMSYSERR_NOTSUPPORTED;
|
||||
Thread->Request.Handler = RequestHandler;
|
||||
Thread->Request.SoundDeviceInstance = SoundDeviceInstance;
|
||||
Thread->Request.Parameter = Parameter;
|
||||
|
||||
/* Notify the thread it has work to do */
|
||||
SND_TRACE(L"Setting REQUEST event\n");
|
||||
SetEvent(Thread->Events.Request);
|
||||
|
||||
/* Wait for the work to be done */
|
||||
SND_TRACE(L"Waiting for DONE event\n");
|
||||
WaitForSingleObject(Thread->Events.Done, INFINITE);
|
||||
|
||||
return Thread->Request.Result;
|
||||
}
|
||||
|
|
|
@ -235,7 +235,7 @@ EnqueueWaveHeader(
|
|||
/* Set the "in queue" flag */
|
||||
WaveHeader->dwFlags |= WHDR_INQUEUE;
|
||||
|
||||
if ( ! SoundDeviceInstance->TailWaveHeader )
|
||||
if ( ! SoundDeviceInstance->HeadWaveHeader )
|
||||
{
|
||||
/* This is the first header in the queue */
|
||||
SND_TRACE(L"Enqueued first wave header\n");
|
||||
|
@ -327,10 +327,12 @@ CompleteWaveHeader(
|
|||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ DoWaveStreaming(
|
|||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
|
||||
{
|
||||
MMRESULT Result;
|
||||
MMDEVICE_TYPE DeviceType;
|
||||
PSOUND_DEVICE SoundDevice;
|
||||
PMMFUNCTION_TABLE FunctionTable;
|
||||
PWAVEHDR Header;
|
||||
|
@ -42,6 +43,9 @@ DoWaveStreaming(
|
|||
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
||||
SND_ASSERT( MMSUCCESS(Result) );
|
||||
|
||||
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
|
||||
SND_ASSERT( MMSUCCESS(Result) );
|
||||
|
||||
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
|
||||
SND_ASSERT( MMSUCCESS(Result) );
|
||||
SND_ASSERT( FunctionTable );
|
||||
|
@ -72,9 +76,13 @@ DoWaveStreaming(
|
|||
/* Can never be *above* the length */
|
||||
SND_ASSERT( HeaderExtension->BytesCommitted <= Header->dwBufferLength );
|
||||
|
||||
/* Is this header entirely committed? */
|
||||
if ( HeaderExtension->BytesCommitted == Header->dwBufferLength )
|
||||
{
|
||||
Header = Header->lpNext;
|
||||
{
|
||||
/* Move on to the next header */
|
||||
Header = Header->lpNext;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -106,6 +114,10 @@ DoWaveStreaming(
|
|||
Overlap->SoundDeviceInstance = SoundDeviceInstance;
|
||||
Overlap->Header = Header;
|
||||
|
||||
/* Don't complete this header if it's part of a loop */
|
||||
Overlap->PerformCompletion = TRUE;
|
||||
// ( SoundDeviceInstance->LoopsRemaining > 0 );
|
||||
|
||||
/* Adjust the commit-related counters */
|
||||
HeaderExtension->BytesCommitted += BytesToCommit;
|
||||
++ SoundDeviceInstance->OutstandingBuffers;
|
||||
|
@ -128,34 +140,6 @@ DoWaveStreaming(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
// 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;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -183,10 +167,13 @@ CompleteIO(
|
|||
IN DWORD dwNumberOfBytesTransferred,
|
||||
IN LPOVERLAPPED lpOverlapped)
|
||||
{
|
||||
MMDEVICE_TYPE DeviceType;
|
||||
PSOUND_DEVICE SoundDevice;
|
||||
PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
|
||||
PSOUND_OVERLAPPED SoundOverlapped = (PSOUND_OVERLAPPED) lpOverlapped;
|
||||
PWAVEHDR WaveHdr;
|
||||
PWAVEHDR_EXTENSION HdrExtension;
|
||||
MMRESULT Result;
|
||||
|
||||
WaveHdr = (PWAVEHDR) SoundOverlapped->Header;
|
||||
SND_ASSERT( WaveHdr );
|
||||
|
@ -196,13 +183,21 @@ CompleteIO(
|
|||
|
||||
SoundDeviceInstance = SoundOverlapped->SoundDeviceInstance;
|
||||
|
||||
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
||||
SND_ASSERT( MMSUCCESS(Result) );
|
||||
|
||||
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
|
||||
SND_ASSERT( MMSUCCESS(Result) );
|
||||
|
||||
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 )
|
||||
/* Did we finish a WAVEHDR and aren't looping? */
|
||||
if ( HdrExtension->BytesCompleted == WaveHdr->dwBufferLength &&
|
||||
SoundOverlapped->PerformCompletion )
|
||||
{
|
||||
CompleteWaveHeader(SoundDeviceInstance, WaveHdr);
|
||||
}
|
||||
|
@ -214,83 +209,6 @@ CompleteIO(
|
|||
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,
|
||||
|
@ -315,3 +233,48 @@ WriteFileEx_Committer(
|
|||
|
||||
return MMSYSERR_NOERROR;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Stream control functions
|
||||
(External/internal thread pairs)
|
||||
|
||||
TODO - Move elsewhere as these shouldn't be wave specific!
|
||||
*/
|
||||
|
||||
MMRESULT
|
||||
StopStreamingInSoundThread(
|
||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||
IN PVOID Parameter)
|
||||
{
|
||||
/* TODO */
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
}
|
||||
|
||||
MMRESULT
|
||||
StopStreaming(
|
||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
|
||||
{
|
||||
MMRESULT Result;
|
||||
PSOUND_DEVICE SoundDevice;
|
||||
MMDEVICE_TYPE DeviceType;
|
||||
|
||||
if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) )
|
||||
return MMSYSERR_INVALHANDLE;
|
||||
|
||||
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
|
||||
if ( ! MMSUCCESS(Result) )
|
||||
return TranslateInternalMmResult(Result);
|
||||
|
||||
/* FIXME: What about wave input? */
|
||||
if ( DeviceType != WAVE_OUT_DEVICE_TYPE )
|
||||
return MMSYSERR_NOTSUPPORTED;
|
||||
|
||||
return CallSoundThread(SoundDeviceInstance,
|
||||
StopStreamingInSoundThread,
|
||||
NULL);
|
||||
}
|
||||
|
|
|
@ -98,14 +98,21 @@ wodMessage(
|
|||
break;
|
||||
}
|
||||
|
||||
case WODM_RESET :
|
||||
{
|
||||
/* Stop playback, reset position to zero */
|
||||
Result = MmeResetWavePlayback(PrivateHandle);
|
||||
break;
|
||||
}
|
||||
|
||||
case WODM_RESTART :
|
||||
{
|
||||
/* Continue playback when paused */
|
||||
break;
|
||||
}
|
||||
|
||||
case WODM_GETPOS :
|
||||
{
|
||||
#if 0
|
||||
/* Hacky code to test the threading */
|
||||
PSOUND_DEVICE_INSTANCE Instance = (PSOUND_DEVICE_INSTANCE)PrivateHandle;
|
||||
CallSoundThread(Instance->Thread, HelloWorld, Instance, L"Hello World!");
|
||||
CallSoundThread(Instance->Thread, HelloWorld, Instance, L"Hello Universe!");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue