3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS Multimedia
5 * FILE: lib/mmdrv/wave.c
6 * PURPOSE: Multimedia User Mode Driver
7 * PROGRAMMER: Andrew Greenwood
8 * Aleksey Bragin (aleksey at studiocerebral.com)
10 * Jan 30, 2004: Imported into ReactOS tree (Greenwood)
11 * Mar 16, 2004: Implemented some funcs (Bragin)
20 /* ============================
22 * functions start here
23 * ============================
26 static MMRESULT
GetDeviceCapabilities(DWORD ID
, UINT DeviceType
,
27 LPBYTE pCaps
, DWORD Size
)
29 // FIXME: Implement :)
30 // return sndGetData(DeviceType, id, dwSize, lpCaps,
31 // IOCTL_WAVE_GET_CAPABILITIES);
33 HANDLE DeviceHandle
= NULL
;
34 MMRESULT Result
= MMSYSERR_NOERROR
;
35 DWORD BytesReturned
= 0;
37 // Open the wave device
39 Result
= OpenDevice(DeviceType
, ID
, &DeviceHandle
, GENERIC_READ
);
40 if (Result
!= MMSYSERR_NOERROR
)
46 // Setting the overlapped parameter (last) to null means we
47 // wait until the operation completes.
50 Result
= DeviceIoControl(DeviceHandle
, IOCTL_WAVE_GET_CAPABILITIES
,
51 NULL
, 0, (LPVOID
)pCaps
, Size
,
52 &BytesReturned
, NULL
) ? MMSYSERR_NOERROR
: TranslateStatus();
55 // Close the handle and return the result code
56 // CloseHandle(DeviceHandle);
61 static MMRESULT
OpenWaveDevice(UINT DeviceType
,
68 return MMSYSERR_NOERROR
;
71 //FIXME: Params are MS-specific
72 static MMRESULT
ThreadCallWaveDevice(WAVETHREADFUNCTION Function
, PWAVEALLOC pClient
)
74 return MMSYSERR_NOERROR
;
77 //FIXME: Params are MS-specific
78 static void CallbackWaveDevice(PWAVEALLOC pWave
, DWORD msg
, DWORD dw1
)
82 //FIXME: Params are MS-specific
83 static MMRESULT
WriteWaveDevice(LPWAVEHDR pHdr
, PWAVEALLOC pClient
)
85 return MMSYSERR_NOERROR
;
88 //FIXME: MS-specific code, except for name of the func!
89 MMRESULT
GetPositionWaveDevice(PWAVEALLOC pClient
, LPMMTIME lpmmt
, DWORD dwSize
)
92 WAVE_DD_POSITION PositionData;
95 if (dwSize < sizeof(MMTIME))
96 return MMSYSERR_ERROR;
99 // Get the current position from the driver
101 mErr = sndGetHandleData(pClient->hDev,
102 sizeof(PositionData),
104 IOCTL_WAVE_GET_POSITION,
107 if (mErr == MMSYSERR_NOERROR) {
108 if (lpmmt->wType == TIME_BYTES) {
109 lpmmt->u.cb = PositionData.ByteCount;
112 // default is samples.
114 lpmmt->wType = TIME_SAMPLES;
115 lpmmt->u.sample = PositionData.SampleCount;
119 return mErr;*/ return MMSYSERR_NOERROR
;
122 //FIXME: Params are MS-specific
123 MMRESULT
soundSetData(UINT DeviceType
, UINT DeviceId
, UINT Length
, PBYTE Data
,
126 return MMSYSERR_NOERROR
;
129 //FIXME: Params are MS-specific
130 MMRESULT
soundGetData(UINT DeviceType
, UINT DeviceId
, UINT Length
, PBYTE Data
,
133 return MMSYSERR_NOERROR
;
137 /* ============================
139 * functions start here
140 * ============================
146 APIENTRY DWORD
wodMessage(DWORD dwId
, DWORD dwMessage
, DWORD dwUser
, DWORD dwParam1
, DWORD dwParam2
)
149 case WODM_GETNUMDEVS
:
150 DPRINT("WODM_GETNUMDEVS");
151 return GetDeviceCount(WaveOutDevice
);
153 case WODM_GETDEVCAPS
:
154 DPRINT("WODM_GETDEVCAPS");
155 return GetDeviceCapabilities(dwId
, WaveOutDevice
, (LPBYTE
)dwParam1
,
160 return OpenWaveDevice(WaveOutDevice
, dwId
, dwUser
, dwParam1
, dwParam2
);
165 PWAVEALLOC pTask
= (PWAVEALLOC
)dwUser
;
166 DPRINT("WODM_CLOSE");
168 // 1. Check if the task is ready to complete
169 Result
= ThreadCallWaveDevice(WaveThreadClose
, pTask
);
170 if (Result
!= MMSYSERR_NOERROR
) {
174 CallbackWaveDevice(pTask
, WOM_CLOSE
, 0L);
176 // 2. Close the device
177 if (pTask
->hDev
!= INVALID_HANDLE_VALUE
) {
178 CloseHandle(pTask
->hDev
);
180 EnterCriticalSection(&CS
);
181 pTask
->hDev
= INVALID_HANDLE_VALUE
;
182 LeaveCriticalSection(&CS
);
185 return MMSYSERR_NOERROR
;
190 LPWAVEHDR pWaveHdr
= (LPWAVEHDR
)dwParam1
;
192 DPRINT("WODM_WRITE");
195 return MMSYSERR_INVALPARAM
;
197 if ((pWaveHdr
->dwFlags
& ~(WHDR_INQUEUE
|WHDR_DONE
|WHDR_PREPARED
|WHDR_BEGINLOOP
|WHDR_ENDLOOP
)))
198 return MMSYSERR_INVALPARAM
;
200 pWaveHdr
->dwFlags
&= (WHDR_INQUEUE
|WHDR_DONE
|WHDR_PREPARED
|WHDR_BEGINLOOP
|WHDR_ENDLOOP
);
202 if ((pWaveHdr
->dwFlags
& WHDR_PREPARED
) == 0)
203 return MMSYSERR_INVALPARAM
;
205 // Check, if the wave header is already prepared
206 if (!(pWaveHdr
->dwFlags
& WHDR_PREPARED
))
207 return WAVERR_UNPREPARED
;
209 // If it's already located in the queue, this op is impossible
210 if (pWaveHdr
->dwFlags
& WHDR_INQUEUE
)
211 return ( WAVERR_STILLPLAYING
);
213 // save WAVEALLOC pointer in the WaveHeader
214 pWaveHdr
->reserved
= dwUser
;
216 return WriteWaveDevice(pWaveHdr
, (PWAVEALLOC
)dwUser
);
221 DPRINT("WODM_PAUSE");
222 ((PWAVEALLOC
)dwUser
)->AuxParam
.State
= WAVE_DD_STOP
;
223 return ThreadCallWaveDevice(WaveThreadSetState
, (PWAVEALLOC
)dwUser
);
226 DPRINT("WODM_RESTART");
227 ((PWAVEALLOC
)dwUser
)->AuxParam
.State
= WAVE_DD_PLAY
;
228 return ThreadCallWaveDevice(WaveThreadSetState
, (PWAVEALLOC
)dwUser
);
231 DPRINT("WODM_RESET");
232 ((PWAVEALLOC
)dwUser
)->AuxParam
.State
= WAVE_DD_RESET
;
233 return ThreadCallWaveDevice(WaveThreadSetState
, (PWAVEALLOC
)dwUser
);
236 DPRINT("WODM_BREAKLOOP");
237 return ThreadCallWaveDevice(WaveThreadBreakLoop
, (PWAVEALLOC
)dwUser
);
240 DPRINT("WODM_GETPOS");
241 return GetPositionWaveDevice(((PWAVEALLOC
)dwUser
), (LPMMTIME
)dwParam1
, dwParam2
);
244 DPRINT("WODM_SETPITCH");
245 ((PWAVEALLOC
)dwUser
)->AuxParam
.GetSetData
.pData
= (PBYTE
)&dwParam1
;
246 ((PWAVEALLOC
)dwUser
)->AuxParam
.GetSetData
.DataLen
= sizeof(DWORD
);
247 ((PWAVEALLOC
)dwUser
)->AuxParam
.GetSetData
.Function
= IOCTL_WAVE_SET_PITCH
;
248 return ThreadCallWaveDevice(WaveThreadSetData
, ((PWAVEALLOC
)dwUser
));
251 DPRINT("WODM_SETVOLUME");
254 Vol
.Left
= LOWORD(dwParam1
) << 16;
255 Vol
.Right
= HIWORD(dwParam1
) << 16;
257 return soundSetData(WaveOutDevice
, dwId
, sizeof(Vol
),
258 (PBYTE
)&Vol
, IOCTL_WAVE_SET_VOLUME
);
261 case WODM_SETPLAYBACKRATE
:
262 DPRINT("WODM_SETPLAYBACKRATE");
263 ((PWAVEALLOC
)dwUser
)->AuxParam
.GetSetData
.pData
= (PBYTE
)&dwParam1
;
264 ((PWAVEALLOC
)dwUser
)->AuxParam
.GetSetData
.DataLen
= sizeof(DWORD
);
265 ((PWAVEALLOC
)dwUser
)->AuxParam
.GetSetData
.Function
= IOCTL_WAVE_SET_PLAYBACK_RATE
;
266 return ThreadCallWaveDevice(WaveThreadSetData
, (PWAVEALLOC
)dwUser
);
269 DPRINT("WODM_GETPITCH");
270 ((PWAVEALLOC
)dwUser
)->AuxParam
.GetSetData
.pData
= (PBYTE
)dwParam1
;
271 ((PWAVEALLOC
)dwUser
)->AuxParam
.GetSetData
.DataLen
= sizeof(DWORD
);
272 ((PWAVEALLOC
)dwUser
)->AuxParam
.GetSetData
.Function
= IOCTL_WAVE_GET_PITCH
;
273 return ThreadCallWaveDevice(WaveThreadGetData
, (PWAVEALLOC
)dwUser
);
276 DPRINT("WODM_GETVOLUME");
281 res
= soundGetData(WaveOutDevice
, dwId
, sizeof(Vol
),
282 (PBYTE
)&Vol
, IOCTL_WAVE_GET_VOLUME
);
284 if (res
== MMSYSERR_NOERROR
)
285 *(LPDWORD
)dwParam1
= (DWORD
)MAKELONG(HIWORD(Vol
.Left
), HIWORD(Vol
.Right
));
290 case WODM_GETPLAYBACKRATE
:
291 DPRINT("WODM_GETPLAYBACKRATE");
292 ((PWAVEALLOC
)dwUser
)->AuxParam
.GetSetData
.pData
= (PBYTE
)dwParam1
;
293 ((PWAVEALLOC
)dwUser
)->AuxParam
.GetSetData
.DataLen
= sizeof(DWORD
);
294 ((PWAVEALLOC
)dwUser
)->AuxParam
.GetSetData
.Function
= IOCTL_WAVE_GET_PLAYBACK_RATE
;
295 return ThreadCallWaveDevice(WaveThreadGetData
, (PWAVEALLOC
)dwUser
);
298 return MMSYSERR_NOTSUPPORTED
;
301 // This point of execution should never be reached
302 return MMSYSERR_NOTSUPPORTED
;
309 APIENTRY DWORD
widMessage(DWORD dwId
, DWORD dwMessage
, DWORD dwUser
, DWORD dwParam1
, DWORD dwParam2
)
311 DPRINT("widMessage\n");
314 case WIDM_GETNUMDEVS
:
315 return GetDeviceCount(WaveInDevice
);
317 return MMSYSERR_NOERROR
;