mirror of
https://github.com/reactos/reactos.git
synced 2025-07-30 14:52:06 +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;
|
return FALSE;
|
||||||
|
|
||||||
/* Set up our function table */
|
/* Set up our function table */
|
||||||
|
ZeroMemory(&FuncTable, sizeof(MMFUNCTION_TABLE));
|
||||||
FuncTable.GetCapabilities = GetSoundBlasterDeviceCapabilities;
|
FuncTable.GetCapabilities = GetSoundBlasterDeviceCapabilities;
|
||||||
FuncTable.QueryWaveFormatSupport = QueryNt4WaveDeviceFormatSupport;
|
FuncTable.QueryWaveFormatSupport = QueryNt4WaveDeviceFormatSupport;
|
||||||
FuncTable.SetWaveFormat = SetNt4WaveDeviceFormat;
|
FuncTable.SetWaveFormat = SetNt4WaveDeviceFormat;
|
||||||
|
|
|
@ -18,9 +18,268 @@
|
||||||
#include <mmddk.h>
|
#include <mmddk.h>
|
||||||
#include <mmebuddy.h>
|
#include <mmebuddy.h>
|
||||||
|
|
||||||
|
#include <ks.h>
|
||||||
|
#include <ksmedia.h>
|
||||||
|
#include "interface.h"
|
||||||
|
|
||||||
#define KERNEL_DEVICE_NAME L"\\\\Device\\wdmaud"
|
#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;
|
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
|
APIENTRY LONG
|
||||||
DriverProc(
|
DriverProc(
|
||||||
|
@ -36,6 +295,7 @@ DriverProc(
|
||||||
{
|
{
|
||||||
case DRV_LOAD :
|
case DRV_LOAD :
|
||||||
{
|
{
|
||||||
|
HANDLE Handle;
|
||||||
SND_TRACE(L"DRV_LOAD\n");
|
SND_TRACE(L"DRV_LOAD\n");
|
||||||
|
|
||||||
Result = InitEntrypointMutexes();
|
Result = InitEntrypointMutexes();
|
||||||
|
@ -43,24 +303,29 @@ DriverProc(
|
||||||
if ( ! MMSUCCESS(Result) )
|
if ( ! MMSUCCESS(Result) )
|
||||||
return 0L;
|
return 0L;
|
||||||
|
|
||||||
KernelHandle = CreateFile(KERNEL_DEVICE_NAME,
|
OpenWdmSoundDevice(NULL, &Handle);
|
||||||
GENERIC_READ | GENERIC_WRITE,
|
|
||||||
FILE_SHARE_WRITE, // ok?
|
|
||||||
NULL,
|
|
||||||
OPEN_EXISTING,
|
|
||||||
FILE_FLAG_OVERLAPPED,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if ( KernelHandle == INVALID_HANDLE_VALUE )
|
if ( Handle == INVALID_HANDLE_VALUE )
|
||||||
{
|
{
|
||||||
SND_ERR(L"Failed to open %s\n", KERNEL_DEVICE_NAME);
|
SND_ERR(L"Failed to open %s\n", KERNEL_DEVICE_NAME);
|
||||||
CleanupEntrypointMutexes();
|
CleanupEntrypointMutexes();
|
||||||
|
|
||||||
UnlistAllSoundDevices();
|
//UnlistAllSoundDevices();
|
||||||
|
|
||||||
return 0L;
|
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");
|
SND_TRACE(L"Initialisation complete\n");
|
||||||
|
|
||||||
return 1L;
|
return 1L;
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<importlibrary definition="wdmaud.spec" />
|
<importlibrary definition="wdmaud.spec" />
|
||||||
<include base="wdmaud.drv">.</include>
|
<include base="wdmaud.drv">.</include>
|
||||||
<include base="ReactOS">include/reactos/libs/sound</include>
|
<include base="ReactOS">include/reactos/libs/sound</include>
|
||||||
|
<include base="wdmaud_kernel">.</include>
|
||||||
<define name="DEBUG_NT4" /><!-- Use custom debug routines -->
|
<define name="DEBUG_NT4" /><!-- Use custom debug routines -->
|
||||||
<library>mmebuddy</library>
|
<library>mmebuddy</library>
|
||||||
<library>ntdll</library>
|
<library>ntdll</library>
|
||||||
|
|
|
@ -181,6 +181,7 @@ typedef struct _SOUND_OVERLAPPED
|
||||||
OVERLAPPED Standard;
|
OVERLAPPED Standard;
|
||||||
struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance;
|
struct _SOUND_DEVICE_INSTANCE* SoundDeviceInstance;
|
||||||
PWAVEHDR Header;
|
PWAVEHDR Header;
|
||||||
|
BOOL PerformCompletion;
|
||||||
} SOUND_OVERLAPPED, *PSOUND_OVERLAPPED;
|
} SOUND_OVERLAPPED, *PSOUND_OVERLAPPED;
|
||||||
|
|
||||||
typedef MMRESULT (*WAVE_COMMIT_FUNC)(
|
typedef MMRESULT (*WAVE_COMMIT_FUNC)(
|
||||||
|
@ -314,8 +315,9 @@ typedef struct _SOUND_DEVICE_INSTANCE
|
||||||
};
|
};
|
||||||
|
|
||||||
PWAVEHDR WaveLoopStart;
|
PWAVEHDR WaveLoopStart;
|
||||||
PWAVEHDR CurrentWaveHeader;
|
//PWAVEHDR CurrentWaveHeader;
|
||||||
DWORD OutstandingBuffers;
|
DWORD OutstandingBuffers;
|
||||||
|
DWORD LoopsRemaining;
|
||||||
} SOUND_DEVICE_INSTANCE, *PSOUND_DEVICE_INSTANCE;
|
} SOUND_DEVICE_INSTANCE, *PSOUND_DEVICE_INSTANCE;
|
||||||
|
|
||||||
/* This lives in WAVEHDR.reserved */
|
/* This lives in WAVEHDR.reserved */
|
||||||
|
@ -383,6 +385,10 @@ MmeCloseDevice(
|
||||||
#define MmeWriteWaveHeader(private_handle, header) \
|
#define MmeWriteWaveHeader(private_handle, header) \
|
||||||
WriteWaveHeader((PSOUND_DEVICE_INSTANCE)private_handle, (PWAVEHDR)header)
|
WriteWaveHeader((PSOUND_DEVICE_INSTANCE)private_handle, (PWAVEHDR)header)
|
||||||
|
|
||||||
|
MMRESULT
|
||||||
|
MmeResetWavePlayback(
|
||||||
|
IN DWORD PrivateHandle);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
capabilities.c
|
capabilities.c
|
||||||
|
@ -619,31 +625,15 @@ WriteFileEx_Committer(
|
||||||
IN PSOUND_OVERLAPPED Overlap,
|
IN PSOUND_OVERLAPPED Overlap,
|
||||||
IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine);
|
IN LPOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine);
|
||||||
|
|
||||||
|
MMRESULT
|
||||||
|
StopStreaming(
|
||||||
|
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
kernel.c
|
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
|
MMRESULT
|
||||||
OpenKernelSoundDeviceByName(
|
OpenKernelSoundDeviceByName(
|
||||||
IN PWSTR DevicePath,
|
IN PWSTR DevicePath,
|
||||||
|
@ -671,182 +661,4 @@ SyncOverlappedDeviceIoControl(
|
||||||
OUT LPDWORD BytesTransferred OPTIONAL);
|
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
|
#endif
|
||||||
|
|
|
@ -37,8 +37,12 @@ VOID
|
||||||
FreeSoundDeviceInstance(
|
FreeSoundDeviceInstance(
|
||||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
|
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));
|
ZeroMemory(SoundDeviceInstance, sizeof(SOUND_DEVICE_INSTANCE));
|
||||||
FreeMemory(SoundDeviceInstance);
|
FreeMemory(SoundDeviceInstance);
|
||||||
}
|
}
|
||||||
|
@ -190,9 +194,9 @@ CreateSoundDeviceInstance(
|
||||||
(*SoundDeviceInstance)->HeadWaveHeader = NULL;
|
(*SoundDeviceInstance)->HeadWaveHeader = NULL;
|
||||||
(*SoundDeviceInstance)->TailWaveHeader = NULL;
|
(*SoundDeviceInstance)->TailWaveHeader = NULL;
|
||||||
|
|
||||||
(*SoundDeviceInstance)->CurrentWaveHeader = NULL;
|
|
||||||
(*SoundDeviceInstance)->OutstandingBuffers = 0;
|
(*SoundDeviceInstance)->OutstandingBuffers = 0;
|
||||||
// TODO: Loop
|
|
||||||
|
(*SoundDeviceInstance)->LoopsRemaining = 0;
|
||||||
|
|
||||||
/* 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);
|
||||||
|
@ -255,13 +259,26 @@ DestroySoundDeviceInstance(
|
||||||
return MMSYSERR_NOTSUPPORTED;
|
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 */
|
/* Try and close the device */
|
||||||
Result = FunctionTable->Close(SoundDeviceInstance, Handle);
|
Result = FunctionTable->Close(SoundDeviceInstance, Handle);
|
||||||
|
SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */
|
||||||
if ( ! MMSUCCESS(Result) )
|
if ( ! MMSUCCESS(Result) )
|
||||||
return TranslateInternalMmResult(Result);
|
return TranslateInternalMmResult(Result);
|
||||||
|
|
||||||
/* Drop it from the list */
|
/* Drop it from the list */
|
||||||
Result = UnlistSoundDeviceInstance(SoundDeviceInstance);
|
Result = UnlistSoundDeviceInstance(SoundDeviceInstance);
|
||||||
|
SND_ASSERT( MMSUCCESS(Result) ); /* It should succeed! */
|
||||||
if ( ! MMSUCCESS(Result) )
|
if ( ! MMSUCCESS(Result) )
|
||||||
return TranslateInternalMmResult(Result);
|
return TranslateInternalMmResult(Result);
|
||||||
|
|
||||||
|
@ -274,7 +291,19 @@ MMRESULT
|
||||||
DestroyAllSoundDeviceInstances(
|
DestroyAllSoundDeviceInstances(
|
||||||
IN PSOUND_DEVICE SoundDevice)
|
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
|
MMRESULT
|
||||||
|
|
|
@ -51,6 +51,41 @@ mxdMessage(
|
||||||
Parameter2);
|
Parameter2);
|
||||||
break;
|
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);
|
SND_TRACE(L"mxdMessage returning MMRESULT %d\n", Result);
|
||||||
|
|
|
@ -164,6 +164,9 @@ MmeCloseDevice(
|
||||||
VALIDATE_MMSYS_PARAMETER( PrivateHandle );
|
VALIDATE_MMSYS_PARAMETER( PrivateHandle );
|
||||||
SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
|
SoundDeviceInstance = (PSOUND_DEVICE_INSTANCE) PrivateHandle;
|
||||||
|
|
||||||
|
if ( ! IsValidSoundDeviceInstance(SoundDeviceInstance) )
|
||||||
|
return MMSYSERR_INVALHANDLE;
|
||||||
|
|
||||||
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
||||||
if ( ! MMSUCCESS(Result) )
|
if ( ! MMSUCCESS(Result) )
|
||||||
return TranslateInternalMmResult(Result);
|
return TranslateInternalMmResult(Result);
|
||||||
|
@ -172,7 +175,11 @@ MmeCloseDevice(
|
||||||
if ( ! MMSUCCESS(Result) )
|
if ( ! MMSUCCESS(Result) )
|
||||||
return TranslateInternalMmResult(Result);
|
return TranslateInternalMmResult(Result);
|
||||||
|
|
||||||
|
|
||||||
|
/* TODO: Check device is stopped! */
|
||||||
|
|
||||||
ReleaseEntrypointMutex(DeviceType);
|
ReleaseEntrypointMutex(DeviceType);
|
||||||
|
/* TODO: Work with MIDI devices too */
|
||||||
NotifyMmeClient(SoundDeviceInstance,
|
NotifyMmeClient(SoundDeviceInstance,
|
||||||
DeviceType == WAVE_OUT_DEVICE_TYPE ? WOM_CLOSE : WIM_CLOSE,
|
DeviceType == WAVE_OUT_DEVICE_TYPE ? WOM_CLOSE : WIM_CLOSE,
|
||||||
0);
|
0);
|
||||||
|
@ -182,3 +189,17 @@ MmeCloseDevice(
|
||||||
|
|
||||||
return Result;
|
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 )
|
else if ( WaitResult == WAIT_IO_COMPLETION )
|
||||||
{
|
{
|
||||||
SND_TRACE(L"SoundThread - Processing IO completion\n");
|
SND_TRACE(L"SoundThread - Processing IO completion\n");
|
||||||
/* TODO */
|
/* TODO? What do we do here? Stream stuff? */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -66,9 +66,95 @@ SoundThreadMain(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SND_TRACE(L"Sound thread terminated\n");
|
||||||
|
|
||||||
return 0;
|
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
|
MMRESULT
|
||||||
CreateSoundThreadEvents(
|
CreateSoundThreadEvents(
|
||||||
OUT HANDLE* ReadyEvent,
|
OUT HANDLE* ReadyEvent,
|
||||||
|
@ -195,39 +281,28 @@ DestroySoundThread(
|
||||||
IN PSOUND_THREAD Thread)
|
IN PSOUND_THREAD Thread)
|
||||||
{
|
{
|
||||||
VALIDATE_MMSYS_PARAMETER( Thread );
|
VALIDATE_MMSYS_PARAMETER( Thread );
|
||||||
|
SND_ASSERT( Thread->Handle != INVALID_HANDLE_VALUE );
|
||||||
|
|
||||||
SND_TRACE(L"Terminating sound thread\n");
|
SND_TRACE(L"Terminating sound thread\n");
|
||||||
Thread->Running = FALSE;
|
|
||||||
/* TODO: Implement me! Wait for thread to have finished? */
|
/* Tell the thread to terminate itself */
|
||||||
return MMSYSERR_NOTSUPPORTED;
|
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 */
|
/* Set the "in queue" flag */
|
||||||
WaveHeader->dwFlags |= WHDR_INQUEUE;
|
WaveHeader->dwFlags |= WHDR_INQUEUE;
|
||||||
|
|
||||||
if ( ! SoundDeviceInstance->TailWaveHeader )
|
if ( ! SoundDeviceInstance->HeadWaveHeader )
|
||||||
{
|
{
|
||||||
/* This is the first header in the queue */
|
/* This is the first header in the queue */
|
||||||
SND_TRACE(L"Enqueued first wave header\n");
|
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! */
|
/* Make sure we're not using this as the current buffer any more, either! */
|
||||||
|
/*
|
||||||
if ( SoundDeviceInstance->CurrentWaveHeader == Header )
|
if ( SoundDeviceInstance->CurrentWaveHeader == Header )
|
||||||
{
|
{
|
||||||
SoundDeviceInstance->CurrentWaveHeader = Header->lpNext;
|
SoundDeviceInstance->CurrentWaveHeader = Header->lpNext;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
DUMP_WAVEHDR_QUEUE(SoundDeviceInstance);
|
DUMP_WAVEHDR_QUEUE(SoundDeviceInstance);
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ DoWaveStreaming(
|
||||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
|
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance)
|
||||||
{
|
{
|
||||||
MMRESULT Result;
|
MMRESULT Result;
|
||||||
|
MMDEVICE_TYPE DeviceType;
|
||||||
PSOUND_DEVICE SoundDevice;
|
PSOUND_DEVICE SoundDevice;
|
||||||
PMMFUNCTION_TABLE FunctionTable;
|
PMMFUNCTION_TABLE FunctionTable;
|
||||||
PWAVEHDR Header;
|
PWAVEHDR Header;
|
||||||
|
@ -42,6 +43,9 @@ DoWaveStreaming(
|
||||||
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
||||||
SND_ASSERT( MMSUCCESS(Result) );
|
SND_ASSERT( MMSUCCESS(Result) );
|
||||||
|
|
||||||
|
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
|
||||||
|
SND_ASSERT( MMSUCCESS(Result) );
|
||||||
|
|
||||||
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
|
Result = GetSoundDeviceFunctionTable(SoundDevice, &FunctionTable);
|
||||||
SND_ASSERT( MMSUCCESS(Result) );
|
SND_ASSERT( MMSUCCESS(Result) );
|
||||||
SND_ASSERT( FunctionTable );
|
SND_ASSERT( FunctionTable );
|
||||||
|
@ -72,9 +76,13 @@ DoWaveStreaming(
|
||||||
/* Can never be *above* the length */
|
/* Can never be *above* the length */
|
||||||
SND_ASSERT( HeaderExtension->BytesCommitted <= Header->dwBufferLength );
|
SND_ASSERT( HeaderExtension->BytesCommitted <= Header->dwBufferLength );
|
||||||
|
|
||||||
|
/* Is this header entirely committed? */
|
||||||
if ( HeaderExtension->BytesCommitted == Header->dwBufferLength )
|
if ( HeaderExtension->BytesCommitted == Header->dwBufferLength )
|
||||||
{
|
{
|
||||||
Header = Header->lpNext;
|
{
|
||||||
|
/* Move on to the next header */
|
||||||
|
Header = Header->lpNext;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -106,6 +114,10 @@ DoWaveStreaming(
|
||||||
Overlap->SoundDeviceInstance = SoundDeviceInstance;
|
Overlap->SoundDeviceInstance = SoundDeviceInstance;
|
||||||
Overlap->Header = Header;
|
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 */
|
/* Adjust the commit-related counters */
|
||||||
HeaderExtension->BytesCommitted += BytesToCommit;
|
HeaderExtension->BytesCommitted += BytesToCommit;
|
||||||
++ SoundDeviceInstance->OutstandingBuffers;
|
++ 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 DWORD dwNumberOfBytesTransferred,
|
||||||
IN LPOVERLAPPED lpOverlapped)
|
IN LPOVERLAPPED lpOverlapped)
|
||||||
{
|
{
|
||||||
|
MMDEVICE_TYPE DeviceType;
|
||||||
|
PSOUND_DEVICE SoundDevice;
|
||||||
PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
|
PSOUND_DEVICE_INSTANCE SoundDeviceInstance;
|
||||||
PSOUND_OVERLAPPED SoundOverlapped = (PSOUND_OVERLAPPED) lpOverlapped;
|
PSOUND_OVERLAPPED SoundOverlapped = (PSOUND_OVERLAPPED) lpOverlapped;
|
||||||
PWAVEHDR WaveHdr;
|
PWAVEHDR WaveHdr;
|
||||||
PWAVEHDR_EXTENSION HdrExtension;
|
PWAVEHDR_EXTENSION HdrExtension;
|
||||||
|
MMRESULT Result;
|
||||||
|
|
||||||
WaveHdr = (PWAVEHDR) SoundOverlapped->Header;
|
WaveHdr = (PWAVEHDR) SoundOverlapped->Header;
|
||||||
SND_ASSERT( WaveHdr );
|
SND_ASSERT( WaveHdr );
|
||||||
|
@ -196,13 +183,21 @@ CompleteIO(
|
||||||
|
|
||||||
SoundDeviceInstance = SoundOverlapped->SoundDeviceInstance;
|
SoundDeviceInstance = SoundOverlapped->SoundDeviceInstance;
|
||||||
|
|
||||||
|
Result = GetSoundDeviceFromInstance(SoundDeviceInstance, &SoundDevice);
|
||||||
|
SND_ASSERT( MMSUCCESS(Result) );
|
||||||
|
|
||||||
|
Result = GetSoundDeviceType(SoundDevice, &DeviceType);
|
||||||
|
SND_ASSERT( MMSUCCESS(Result) );
|
||||||
|
|
||||||
HdrExtension->BytesCompleted += dwNumberOfBytesTransferred;
|
HdrExtension->BytesCompleted += dwNumberOfBytesTransferred;
|
||||||
SND_TRACE(L"%d/%d bytes of wavehdr completed\n", HdrExtension->BytesCompleted, WaveHdr->dwBufferLength);
|
SND_TRACE(L"%d/%d bytes of wavehdr completed\n", HdrExtension->BytesCompleted, WaveHdr->dwBufferLength);
|
||||||
|
|
||||||
/* We have an available buffer now */
|
/* We have an available buffer now */
|
||||||
-- SoundDeviceInstance->OutstandingBuffers;
|
-- 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);
|
CompleteWaveHeader(SoundDeviceInstance, WaveHdr);
|
||||||
}
|
}
|
||||||
|
@ -214,83 +209,6 @@ CompleteIO(
|
||||||
FreeMemory(lpOverlapped);
|
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
|
MMRESULT
|
||||||
WriteFileEx_Committer(
|
WriteFileEx_Committer(
|
||||||
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
IN PSOUND_DEVICE_INSTANCE SoundDeviceInstance,
|
||||||
|
@ -315,3 +233,48 @@ WriteFileEx_Committer(
|
||||||
|
|
||||||
return MMSYSERR_NOERROR;
|
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;
|
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 :
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue