Closing of wave output devices is functional and terminates the sound thread
authorAndrew Greenwood <silverblade@reactos.org>
Sun, 22 Feb 2009 21:14:54 +0000 (21:14 +0000)
committerAndrew Greenwood <silverblade@reactos.org>
Sun, 22 Feb 2009 21:14:54 +0000 (21:14 +0000)
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

12 files changed:
reactos/dll/win32/sndblst/sndblst.c
reactos/dll/win32/wdmaud.drv/wdmaud.c
reactos/dll/win32/wdmaud.drv/wdmaud.rbuild
reactos/include/reactos/libs/sound/mmebuddy.h
reactos/lib/drivers/sound/mmebuddy/deviceinstance.c
reactos/lib/drivers/sound/mmebuddy/mixer/mxdMessage.c
reactos/lib/drivers/sound/mmebuddy/mmewrap.c
reactos/lib/drivers/sound/mmebuddy/readme.txt [new file with mode: 0644]
reactos/lib/drivers/sound/mmebuddy/thread.c
reactos/lib/drivers/sound/mmebuddy/wave/header.c
reactos/lib/drivers/sound/mmebuddy/wave/streaming.c
reactos/lib/drivers/sound/mmebuddy/wave/wodMessage.c

index 076e0ca..9ce2e28 100644 (file)
@@ -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;
index e6a4746..dac69c4 100644 (file)
 #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;
index 7237b59..31a636f 100644 (file)
@@ -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>
index cf75c19..94e2bea 100644 (file)
@@ -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
index 922ed1d..8722a08 100644 (file)
@@ -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
index c970281..1f330f8 100644 (file)
@@ -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);
index 1a18703..03bce22 100644 (file)
@@ -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);
+}
diff --git a/reactos/lib/drivers/sound/mmebuddy/readme.txt b/reactos/lib/drivers/sound/mmebuddy/readme.txt
new file mode 100644 (file)
index 0000000..91b52a7
--- /dev/null
@@ -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
index 3c3aac9..625cf96 100644 (file)
@@ -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;
-}
 
-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 );
+    /* Tell the thread to terminate itself */
+    TerminateSoundThread(Thread);
 
-    /* TODO: Don't call this directly? */
-    PSOUND_THREAD Thread = SoundDeviceInstance->Thread;
+    SND_TRACE(L"Sound thread terminated, performing cleanup of thread resources\n");
 
-    SND_TRACE(L"Waiting for READY event\n");
-    WaitForSingleObject(Thread->Events.Ready, INFINITE);
+    CloseHandle(Thread->Handle);    /* Is this needed? */
+    Thread->Handle = INVALID_HANDLE_VALUE;
 
-    Thread->Request.Result = MMSYSERR_NOTSUPPORTED;
-    Thread->Request.Handler = RequestHandler;
-    Thread->Request.SoundDeviceInstance = SoundDeviceInstance;
-    Thread->Request.Parameter = Parameter;
+    DestroySoundThreadEvents(Thread->Events.Ready,
+                             Thread->Events.Request,
+                             Thread->Events.Done);
 
-    /* Notify the thread it has work to do */
-    SND_TRACE(L"Setting REQUEST event\n");
-    SetEvent(Thread->Events.Request);
+    /* Wipe and free the memory used for the thread */
+    ZeroMemory(Thread, sizeof(SOUND_THREAD));
+    FreeMemory(Thread);
 
-    /* Wait for the work to be done */
-    SND_TRACE(L"Waiting for DONE event\n");
-    WaitForSingleObject(Thread->Events.Done, INFINITE);
+    SND_TRACE(L"Finished thread cleanup\n");
 
-    return Thread->Request.Result;
+    return MMSYSERR_NOERROR;
 }
+
index 0cfb553..62cf831 100644 (file)
@@ -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);
 
index b193086..ea4c4b5 100644 (file)
@@ -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);
+}
index 051f240..7c456f4 100644 (file)
@@ -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;
         }
     }