push 9bfdf186dc6a237cd7f58f0ee2ef677e81617b1d
[wine/hacks.git] / dlls / winepulse.drv / wavein.c
blob87b3c118658eae0d919380a27ba918aacd41f7b4
1 /*
2 * Wine Driver for PulseAudio - WaveOut Functionality
3 * http://pulseaudio.org/
5 * Copyright 2002 Eric Pouech
6 * 2002 Marco Pietrobono
7 * 2003 Christian Costa
8 * 2006-2007 Maarten Lankhorst
9 * 2008 Arthur Taylor (PulseAudio version)
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <string.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wingdi.h"
36 #include "winuser.h"
37 #include "winnls.h"
38 #include "winerror.h"
39 #include "mmddk.h"
40 #include "mmreg.h"
41 #include "ks.h"
42 #include "ksmedia.h"
44 #include <winepulse.h>
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(wavein);
50 #if HAVE_PULSEAUDIO
53 * - Under / Over flows not currently handled
54 * - The buffer size is massive usually
57 /*======================================================================*
58 * Low level WAVE IN implementation *
59 *======================================================================*/
61 /**************************************************************************
62 * widNotifyClient [internal]
64 static DWORD widNotifyClient(WINE_WAVEDEV* wwi, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
66 TRACE("wMsg = 0x%04x dwParm1 = %04X dwParam2 = %04X\n", wMsg, dwParam1, dwParam2);
68 switch (wMsg) {
69 case WIM_OPEN:
70 case WIM_CLOSE:
71 case WIM_DATA:
72 if (wwi->wFlags != DCB_NULL &&
73 !DriverCallback(wwi->waveDesc.dwCallback, wwi->wFlags, (HDRVR)wwi->waveDesc.hWave,
74 wMsg, wwi->waveDesc.dwInstance, dwParam1, dwParam2)) {
75 WARN("can't notify client !\n");
76 return MMSYSERR_ERROR;
78 break;
79 default:
80 FIXME("Unknown callback message %u\n", wMsg);
81 return MMSYSERR_INVALPARAM;
83 return MMSYSERR_NOERROR;
86 /**************************************************************************
87 * widRecorder [internal]
89 static DWORD CALLBACK widRecorder(LPVOID pmt) {
90 WORD uDevID = (DWORD)pmt;
91 WINE_WAVEDEV *wwi = (WINE_WAVEDEV*)&WInDev[uDevID];
92 DWORD dwSleepTime = INFINITE;
93 LPWAVEHDR lpWaveHdr;
94 enum win_wm_message msg;
95 DWORD param;
96 HANDLE ev;
97 pa_operation *o;
98 size_t toRead;
99 size_t next_record_size = 0;
100 size_t record_size = 0;
101 size_t record_data_offset = 0;
102 const void *record_data = NULL;
104 wwi->state = WINE_WS_STOPPED;
105 SetEvent(wwi->hStartUpEvent);
107 for (;;) {
108 if (wwi->state == WINE_WS_PLAYING) {
109 lpWaveHdr = wwi->lpQueuePtr;
110 dwSleepTime = INFINITE;
111 /* Fill up any Queue WaveHdrs until we run of out of them or data*/
112 while (lpWaveHdr && record_size - record_data_offset && record_data) {
113 toRead = min(lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded, record_size - record_data_offset);
115 TRACE("BL:%u\tBR:%u\t,RD:%u\tRDO%u\n",lpWaveHdr->dwBufferLength, lpWaveHdr->dwBytesRecorded, record_size, record_data_offset);
117 TRACE("Copying %u bytes to %p from %p.\n", toRead, lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded, (void*)((size_t)record_data + record_data_offset));
118 memcpy(lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded, (void*)((size_t)record_data + record_data_offset), toRead);
120 lpWaveHdr->dwBytesRecorded += toRead;
121 wwi->dwPartialOffset += toRead;
122 lpWaveHdr->reserved = wwi->dwPartialOffset;
123 record_data_offset += toRead;
125 if (lpWaveHdr->dwBufferLength <= lpWaveHdr->dwBytesRecorded) {
126 TRACE("(%p) is done.\n", lpWaveHdr);
127 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
128 lpWaveHdr->dwFlags |= WHDR_DONE;
129 wwi->lpQueuePtr = lpWaveHdr->lpNext;
130 widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0);
131 lpWaveHdr = wwi->lpQueuePtr;
132 dwSleepTime = pa_bytes_to_usec(toRead, &wwi->sample_spec)/1000;
133 break;
137 /* If we have run out of data, ask for more */
138 if (record_size - record_data_offset == 0 || !record_data) {
139 pa_stream_drop(wwi->stream);
140 if (next_record_size) {
141 if (pa_stream_peek(wwi->stream, &record_data, &record_size) < 0 || record_data == NULL)
142 printf("Failure!\n");
144 record_data_offset = 0;
145 next_record_size = 0;
150 TRACE("Waiting %u ms\n", dwSleepTime);
151 PULSE_WaitRingMessage(&wwi->msgRing, dwSleepTime);
153 while (PULSE_RetrieveRingMessage(&wwi->msgRing, &msg, &param, &ev)) {
154 TRACE("Received %s %x\n", PULSE_getCmdString(msg), param);
155 switch (msg) {
156 case WINE_WM_FEED:
157 next_record_size = (size_t)param;
158 SetEvent(ev);
159 break;
161 case WINE_WM_STARTING:
162 wwi->state = WINE_WS_PLAYING;
163 if (pa_stream_is_corked(wwi->stream) && (o = pa_stream_cork(wwi->stream, 0, PULSE_stream_success_callback, wwi)))
164 PULSE_wait_for_operation(wwi->stream, o);
165 SetEvent(ev);
166 break;
168 case WINE_WM_STOPPING:
169 if (wwi->state != WINE_WS_STOPPED) {
170 if (!pa_stream_is_corked(wwi->stream) && (o = pa_stream_cork(wwi->stream, 1, PULSE_stream_success_callback, wwi)))
171 PULSE_wait_for_operation(wwi->stream, o);
173 pa_stream_drop(wwi->stream);
175 /* return current buffer to app */
176 lpWaveHdr = wwi->lpQueuePtr;
177 if (lpWaveHdr) {
178 LPWAVEHDR lpNext = lpWaveHdr->lpNext;
180 TRACE("stop %p %p\n", lpWaveHdr, lpWaveHdr->lpNext);
182 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
183 lpWaveHdr->dwFlags |= WHDR_DONE;
185 wwi->lpQueuePtr = lpNext;
186 widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0);
189 wwi->state = WINE_WS_STOPPED;
191 SetEvent(ev);
192 break;
194 case WINE_WM_HEADER:
195 lpWaveHdr = (LPWAVEHDR)param;
196 lpWaveHdr->lpNext = 0;
197 lpWaveHdr->dwBytesRecorded = 0;
199 /* insert buffer at the end of queue */
201 LPWAVEHDR* wh;
202 for (wh = &(wwi->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
203 *wh = lpWaveHdr;
205 SetEvent(ev);
206 break;
208 case WINE_WM_RESETTING:
209 if (wwi->state != WINE_WS_STOPPED) {
211 if (!pa_stream_is_corked(wwi->stream) &&
212 (o = pa_stream_cork(wwi->stream, 1, PULSE_stream_success_callback, wwi)))
213 PULSE_wait_for_operation(wwi->stream, o);
215 if ((o = pa_stream_update_timing_info(wwi->stream, PULSE_stream_success_callback, wwi)))
216 PULSE_wait_for_operation(wwi->stream, o);
218 wwi->state = WINE_WS_STOPPED;
221 /* return all buffers to the app */
222 for (lpWaveHdr = wwi->lpQueuePtr; lpWaveHdr;) {
223 TRACE("reset %p %p\n", lpWaveHdr, lpWaveHdr->lpNext);
224 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
225 lpWaveHdr->dwFlags |= WHDR_DONE;
226 lpWaveHdr = lpWaveHdr->lpNext;
227 widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0);
230 wwi->dwPartialOffset = 0;
231 wwi->lpQueuePtr = NULL;
232 SetEvent(ev);
233 break;
235 case WINE_WM_CLOSING:
236 wwi->hThread = 0;
237 wwi->state = WINE_WS_CLOSED;
238 SetEvent(ev);
239 ExitThread(0);
240 /* shouldn't go here */
241 default:
242 FIXME("unknown message %d\n", msg);
243 break;
249 /**************************************************************************
250 * widOpen [internal]
252 static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) {
253 WINE_WAVEDEV *wwi;
254 pa_operation *o;
256 TRACE("(%u, %p, %08X);\n", wDevID, lpDesc, dwFlags);
257 if (lpDesc == NULL) {
258 WARN("Invalid Parameter !\n");
259 return MMSYSERR_INVALPARAM;
262 if (wDevID >= PULSE_WidNumDevs) {
263 TRACE("Requested device %d, but only %d are known!\n", wDevID, PULSE_WidNumDevs);
264 return MMSYSERR_BADDEVICEID;
267 wwi = &WInDev[wDevID];
269 if (!PULSE_setupFormat(lpDesc->lpFormat, &wwi->sample_spec) &&
270 !pa_sample_spec_valid(&wwi->sample_spec)) {
271 WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
272 lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
273 lpDesc->lpFormat->nSamplesPerSec);
274 return WAVERR_BADFORMAT;
278 char t[PA_SAMPLE_SPEC_SNPRINT_MAX];
279 pa_sample_spec_snprint(t, sizeof(t), &wwi->sample_spec);
280 TRACE("Device opened using sample spec '%s'\n", t);
283 if (dwFlags & WAVE_FORMAT_QUERY) {
284 TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%d !\n",
285 lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
286 lpDesc->lpFormat->nSamplesPerSec);
287 return MMSYSERR_NOERROR;
290 if (wwi->stream != NULL) {
291 WARN("%d already allocated\n", wDevID);
292 return MMSYSERR_ALLOCATED;
295 wwi->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
296 wwi->waveDesc = *lpDesc;
298 wwi->timing_info = NULL;
299 wwi->lpQueuePtr = NULL;
300 wwi->dwPartialOffset = 0;
302 PULSE_InitRingMessage(&wwi->msgRing);
304 wwi->stream = pa_stream_new(PULSE_context, "Wine Recording", &wwi->sample_spec, NULL);
305 assert(wwi->stream);
307 /* setup callbacks */
308 pa_stream_set_state_callback(wwi->stream, PULSE_stream_state_callback, wwi);
309 pa_stream_set_read_callback(wwi->stream, PULSE_stream_request_callback, wwi);
311 pa_threaded_mainloop_lock(PULSE_ml);
313 pa_stream_connect_record(wwi->stream, wwi->device_name, NULL, PA_STREAM_START_CORKED);
315 for (;;) {
316 pa_context_state_t cstate = pa_context_get_state(PULSE_context);
317 pa_stream_state_t sstate = pa_stream_get_state(wwi->stream);
319 if (cstate == PA_CONTEXT_FAILED || cstate == PA_CONTEXT_TERMINATED ||
320 sstate == PA_STREAM_FAILED || sstate == PA_STREAM_TERMINATED) {
321 WARN("failed to connect context object: %s\n", pa_strerror(pa_context_errno(PULSE_context)));
322 pa_threaded_mainloop_unlock(PULSE_ml);
323 pa_stream_unref(wwi->stream);
324 return MMSYSERR_NODRIVER;
327 if (sstate == PA_STREAM_READY)
328 break;
330 pa_threaded_mainloop_wait(PULSE_ml);
333 if ((o = pa_stream_update_timing_info(wwi->stream, PULSE_stream_success_callback, wwi)))
334 PULSE_wait_for_operation(wwi->stream, o);
336 wwi->timing_info = pa_stream_get_timing_info(wwi->stream);
337 assert(wwi->timing_info);
339 pa_threaded_mainloop_unlock(PULSE_ml);
341 wwi->hStartUpEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
342 wwi->hThread = CreateThread(NULL, 0, widRecorder, (LPVOID)(DWORD)wDevID, 0, &(wwi->dwThreadID));
343 if (wwi->hThread)
344 SetThreadPriority(wwi->hThread, THREAD_PRIORITY_TIME_CRITICAL);
345 else {
346 ERR("Thread creation for the widRecorder failed!\n");
347 CloseHandle(wwi->hStartUpEvent);
348 if (wwi->msgRing.ring_buffer_size > 0)
349 PULSE_DestroyRingMessage(&wwi->msgRing);
350 pa_stream_disconnect(wwi->stream);
351 pa_stream_unref(wwi->stream);
352 return MMSYSERR_NOMEM;
354 WaitForSingleObject(wwi->hStartUpEvent, INFINITE);
355 CloseHandle(wwi->hStartUpEvent);
356 wwi->hStartUpEvent = INVALID_HANDLE_VALUE;
358 return widNotifyClient(wwi, WIM_OPEN, 0L, 0L);
361 /**************************************************************************
362 * widClose [internal]
364 static DWORD widClose(WORD wDevID) {
365 WINE_WAVEDEV* wwi;
367 TRACE("(%u);\n", wDevID);
369 if (wDevID >= PULSE_WidNumDevs) {
370 TRACE("Requested device %d, but only %d are known!\n", wDevID, PULSE_WidNumDevs);
371 return MMSYSERR_BADDEVICEID;
374 if (WInDev[wDevID].stream == NULL) {
375 WARN("Requested to close already closed device %d!\n", wDevID);
376 return MMSYSERR_BADDEVICEID;
379 wwi = &WInDev[wDevID];
380 if (wwi->lpQueuePtr) {
381 WARN("buffers still playing !\n");
382 return WAVERR_STILLPLAYING;
385 if (wwi->hThread != INVALID_HANDLE_VALUE) {
386 PULSE_AddRingMessage(&wwi->msgRing, WINE_WM_CLOSING, 0, TRUE);
389 PULSE_DestroyRingMessage(&wwi->msgRing);
391 pa_threaded_mainloop_lock(PULSE_ml);
392 pa_stream_disconnect(wwi->stream);
393 pa_stream_unref(wwi->stream);
394 pa_threaded_mainloop_unlock(PULSE_ml);
396 wwi->stream = NULL;
397 wwi->state = WINE_WS_CLOSED;
399 return widNotifyClient(wwi, WIM_CLOSE, 0L, 0L);
402 /**************************************************************************
403 * widAddBuffer [internal]
406 static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) {
407 TRACE("(%u, %p, %08X);\n", wDevID, lpWaveHdr, dwSize);
409 /* first, do the sanity checks... */
410 if (wDevID >= PULSE_WidNumDevs) {
411 TRACE("Requested device %d, but only %d are known!\n", wDevID, PULSE_WidNumDevs);
412 return MMSYSERR_BADDEVICEID;
415 if (WInDev[wDevID].stream == NULL) {
416 WARN("Requested to add buffer to already closed device %d!\n", wDevID);
417 return MMSYSERR_BADDEVICEID;
420 if (lpWaveHdr->lpData == NULL || !(lpWaveHdr->dwFlags & WHDR_PREPARED))
421 return WAVERR_UNPREPARED;
423 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
424 return WAVERR_STILLPLAYING;
426 lpWaveHdr->dwFlags &= ~WHDR_DONE;
427 lpWaveHdr->dwFlags |= WHDR_INQUEUE;
428 lpWaveHdr->dwBytesRecorded = 0;
429 lpWaveHdr->lpNext = 0;
431 PULSE_AddRingMessage(&WInDev[wDevID].msgRing, WINE_WM_HEADER, (DWORD)lpWaveHdr, FALSE);
433 return MMSYSERR_NOERROR;
436 /**************************************************************************
437 * widStart [internal]
440 static DWORD widStart(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) {
441 TRACE("(%u, %p, %08X);\n", wDevID, lpWaveHdr, dwSize);
443 /* first, do the sanity checks... */
444 if (wDevID >= PULSE_WidNumDevs) {
445 TRACE("Requested device %d, but only %d are known!\n", wDevID, PULSE_WidNumDevs);
446 return MMSYSERR_BADDEVICEID;
449 if (WInDev[wDevID].stream == NULL) {
450 WARN("Requested to start closed device %d!\n", wDevID);
451 return MMSYSERR_BADDEVICEID;
454 PULSE_AddRingMessage(&WInDev[wDevID].msgRing, WINE_WM_STARTING, 0, TRUE);
456 return MMSYSERR_NOERROR;
459 /**************************************************************************
460 * widStop [internal]
463 static DWORD widStop(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) {
464 TRACE("(%u, %p, %08X);\n", wDevID, lpWaveHdr, dwSize);
466 /* first, do the sanity checks... */
467 if (wDevID >= PULSE_WidNumDevs) {
468 TRACE("Requested device %d, but only %d are known!\n", wDevID, PULSE_WidNumDevs);
469 return MMSYSERR_BADDEVICEID;
472 if (WInDev[wDevID].stream == NULL) {
473 WARN("Requested to stop closed device %d!\n", wDevID);
474 return MMSYSERR_BADDEVICEID;
477 PULSE_AddRingMessage(&WInDev[wDevID].msgRing, WINE_WM_STOPPING, 0, TRUE);
479 return MMSYSERR_NOERROR;
482 /**************************************************************************
483 * widReset [internal]
485 static DWORD widReset(WORD wDevID) {
486 TRACE("(%u);\n", wDevID);
488 if (wDevID >= PULSE_WidNumDevs) {
489 TRACE("Requested device %d, but only %d are known!\n", wDevID, PULSE_WidNumDevs);
490 return MMSYSERR_BADDEVICEID;
493 if (WInDev[wDevID].stream == NULL) {
494 WARN("Requested to reset closed device %d!\n", wDevID);
495 return MMSYSERR_BADDEVICEID;
498 PULSE_AddRingMessage(&WInDev[wDevID].msgRing, WINE_WM_RESETTING, 0, TRUE);
499 return MMSYSERR_NOERROR;
502 /**************************************************************************
503 * widGetDevCaps [internal]
505 static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPSW lpCaps, DWORD dwSize) {
506 TRACE("(%u, %p, %u);\n", wDevID, lpCaps, dwSize);
508 if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
510 if (wDevID >= PULSE_WidNumDevs) {
511 TRACE("Requested device %d, but only %d are known!\n", wDevID, PULSE_WidNumDevs);
512 return MMSYSERR_BADDEVICEID;
515 memcpy(lpCaps, &WInDev[wDevID].caps.in, min(dwSize, sizeof(*lpCaps)));
516 return MMSYSERR_NOERROR;
519 /**************************************************************************
520 * widGetNumDevs [internal]
522 static DWORD widGetNumDevs(void) {
523 return PULSE_WidNumDevs;
526 /**************************************************************************
527 * widGetPosition [internal]
529 static DWORD widGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize) {
530 WINE_WAVEDEV* wwi;
531 pa_usec_t time;
533 TRACE("(%u, %p, %u);\n", wDevID, lpTime, uSize);
535 if (wDevID >= PULSE_WidNumDevs) {
536 TRACE("Requested device %d, but only %d are known!\n", wDevID, PULSE_WidNumDevs);
537 return MMSYSERR_BADDEVICEID;
540 if (WInDev[wDevID].state == WINE_WS_CLOSED || !WInDev[wDevID].stream) {
541 WARN("Requested position of closed device %d!\n", wDevID);
542 return MMSYSERR_BADDEVICEID;
545 if (lpTime == NULL) {
546 WARN("invalid parameter: lpTime = NULL\n");
547 return MMSYSERR_INVALPARAM;
550 wwi = &WInDev[wDevID];
551 time = pa_bytes_to_usec(wwi->dwPartialOffset, &wwi->sample_spec); //wwi->timing_info->read_index, &wwi->sample_spec);
553 switch (lpTime->wType) {
554 case TIME_SAMPLES:
555 lpTime->u.sample = wwi->timing_info->read_index / pa_frame_size(&wwi->sample_spec);
556 break;
557 case TIME_MS:
558 lpTime->u.ms = time;
559 break;
560 case TIME_SMPTE:
561 lpTime->u.smpte.fps = 30;
562 lpTime->u.smpte.sec = time/1000;
563 lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
564 lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
565 lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
566 lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
567 lpTime->u.smpte.fps = 30;
568 lpTime->u.smpte.frame = time / lpTime->u.smpte.fps * 1000;
569 TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
570 lpTime->u.smpte.hour, lpTime->u.smpte.min,
571 lpTime->u.smpte.sec, lpTime->u.smpte.frame);
572 break;
573 default:
574 WARN("Format %d not supported, using TIME_BYTES !\n", lpTime->wType);
575 lpTime->wType = TIME_BYTES;
576 /* fall through */
577 case TIME_BYTES:
578 lpTime->u.cb = wwi->timing_info->read_index;
579 TRACE("TIME_BYTES=%u\n", lpTime->u.cb);
580 break;
583 return MMSYSERR_NOERROR;
586 /**************************************************************************
587 * widDevInterfaceSize [internal]
589 static DWORD widDevInterfaceSize(UINT wDevID, LPDWORD dwParam1) {
590 TRACE("(%u, %p)\n", wDevID, dwParam1);
592 *dwParam1 = MultiByteToWideChar(CP_UNIXCP, 0, WInDev[wDevID].interface_name, -1,
593 NULL, 0 ) * sizeof(WCHAR);
594 return MMSYSERR_NOERROR;
597 /**************************************************************************
598 * widDevInterface [internal]
600 static DWORD widDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2) {
601 if (dwParam2 >= MultiByteToWideChar(CP_UNIXCP, 0, WInDev[wDevID].interface_name, -1,
602 NULL, 0 ) * sizeof(WCHAR))
604 MultiByteToWideChar(CP_UNIXCP, 0, WInDev[wDevID].interface_name, -1,
605 dwParam1, dwParam2 / sizeof(WCHAR));
606 return MMSYSERR_NOERROR;
608 return MMSYSERR_INVALPARAM;
611 /*======================================================================*
612 * Low level DSOUND implementation *
613 *======================================================================*/
614 static DWORD widDsCreate(UINT wDevID, PIDSCDRIVER* drv) {
615 /* Is this possible ?*/
616 return MMSYSERR_NOTSUPPORTED;
619 static DWORD widDsDesc(UINT wDevID, PDSDRIVERDESC desc) {
620 memset(desc, 0, sizeof(*desc));
621 strcpy(desc->szDesc, "Wine PulseAudio DirectSound Driver");
622 strcpy(desc->szDrvname, "winepulse.drv");
623 return MMSYSERR_NOERROR;
626 /**************************************************************************
627 * widMessage (WINEPULSE.@)
629 DWORD WINAPI PULSE_widMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
630 DWORD dwParam1, DWORD dwParam2)
632 switch (wMsg) {
633 case DRVM_INIT:
634 case DRVM_EXIT:
635 case DRVM_ENABLE:
636 case DRVM_DISABLE:
637 /* FIXME: Pretend this is supported */
638 return 0;
639 case WIDM_OPEN: return widOpen (wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
640 case WIDM_CLOSE: return widClose (wDevID);
641 case WIDM_ADDBUFFER: return widAddBuffer (wDevID, (LPWAVEHDR)dwParam1, dwParam2);
642 case WIDM_PREPARE: return MMSYSERR_NOTSUPPORTED;
643 case WIDM_UNPREPARE: return MMSYSERR_NOTSUPPORTED;
644 case WIDM_GETDEVCAPS: return widGetDevCaps (wDevID, (LPWAVEINCAPSW)dwParam1, dwParam2);
645 case WIDM_GETNUMDEVS: return widGetNumDevs ();
646 case WIDM_GETPOS: return widGetPosition (wDevID, (LPMMTIME)dwParam1, dwParam2);
647 case WIDM_RESET: return widReset (wDevID);
648 case WIDM_START: return widStart (wDevID, (LPWAVEHDR)dwParam1, dwParam2);
649 case WIDM_STOP: return widStop (wDevID, (LPWAVEHDR)dwParam1, dwParam2);
650 case DRV_QUERYDEVICEINTERFACESIZE: return widDevInterfaceSize (wDevID, (LPDWORD)dwParam1);
651 case DRV_QUERYDEVICEINTERFACE: return widDevInterface (wDevID, (PWCHAR)dwParam1, dwParam2);
652 case DRV_QUERYDSOUNDIFACE: return widDsCreate (wDevID, (PIDSCDRIVER*)dwParam1);
653 case DRV_QUERYDSOUNDDESC: return widDsDesc (wDevID, (PDSDRIVERDESC)dwParam1);
654 default:
655 FIXME("unknown message %d!\n", wMsg);
657 return MMSYSERR_NOTSUPPORTED;
660 #else /* HAVE_PULSEAUDIO */
662 /**************************************************************************
663 * widMessage (WINEPULSE.@)
665 DWORD WINAPI PULSE_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
666 DWORD dwParam1, DWORD dwParam2)
668 FIXME("(%u, %04X, %08X, %08X, %08X):stub\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
669 return MMSYSERR_NOTENABLED;
672 #endif /* HAVE_PULSEAUDIO */