Implement COM local servers using table marshaling to avoid doing the
[wine/multimedia.git] / dlls / winmm / winejack / audio.c
blob5e931a8493a9f5c3bdfa75341660129f334e2d28
1 /*
2 * Wine Driver for jack Sound Server
3 * http://jackit.sourceforge.net
5 * Copyright 1994 Martin Ayotte
6 * Copyright 1999 Eric Pouech (async playing in waveOut/waveIn)
7 * Copyright 2000 Eric Pouech (loops in waveOut)
8 * Copyright 2002 Chris Morgan (jack version of this file)
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 * TODO:
27 * implement audio stream resampling for any arbitrary frequenty
28 * right now we use the winmm layer to do resampling although it would
29 * be nice to have a full set of algorithms to choose from based on cpu
30 * time
32 * FIXME:
33 * pause in waveOut during loop is not handled correctly
36 #include "config.h"
38 #include <stdlib.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <string.h>
42 #ifdef HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #include <fcntl.h>
46 #include "windef.h"
47 #include "winbase.h"
48 #include "winnls.h"
49 #include "wingdi.h"
50 #include "winerror.h"
51 #include "mmddk.h"
52 #include "dsound.h"
53 #include "dsdriver.h"
54 #include "jack.h"
55 #include "wine/unicode.h"
56 #include "wine/library.h"
57 #include "wine/debug.h"
59 #ifdef HAVE_JACK_JACK_H
60 #include <jack/jack.h>
61 #endif
64 WINE_DEFAULT_DEBUG_CHANNEL(wave);
66 #ifdef HAVE_JACK_JACK_H
68 #define MAKE_FUNCPTR(f) static typeof(f) * fp_##f = NULL;
70 /* Function pointers for dynamic loading of libjack */
71 /* these are prefixed with "fp_", ie. "fp_jack_client_new" */
72 MAKE_FUNCPTR(jack_activate);
73 MAKE_FUNCPTR(jack_connect);
74 MAKE_FUNCPTR(jack_client_new);
75 MAKE_FUNCPTR(jack_client_close);
76 MAKE_FUNCPTR(jack_deactivate);
77 MAKE_FUNCPTR(jack_set_process_callback);
78 MAKE_FUNCPTR(jack_set_buffer_size_callback);
79 MAKE_FUNCPTR(jack_set_sample_rate_callback);
80 MAKE_FUNCPTR(jack_on_shutdown);
81 MAKE_FUNCPTR(jack_get_sample_rate);
82 MAKE_FUNCPTR(jack_port_register);
83 MAKE_FUNCPTR(jack_port_get_buffer);
84 MAKE_FUNCPTR(jack_get_ports);
85 MAKE_FUNCPTR(jack_port_name);
86 MAKE_FUNCPTR(jack_get_buffer_size);
87 #undef MAKE_FUNCPTR
89 /* define the below to work around a bug in jack where closing a port */
90 /* takes a very long time, so to get around this we actually don't */
91 /* close the port when the device is closed but instead mark the */
92 /* corresponding device as unused */
93 #define JACK_CLOSE_HACK 1
95 typedef jack_default_audio_sample_t sample_t;
96 typedef jack_nframes_t nframes_t;
98 /* only allow 10 output devices through this driver, this ought to be adequate */
99 #define MAX_WAVEOUTDRV (10)
100 #define MAX_WAVEINDRV (10)
102 /* state diagram for waveOut writing:
104 * +---------+-------------+---------------+---------------------------------+
105 * | state | function | event | new state |
106 * +---------+-------------+---------------+---------------------------------+
107 * | | open() | | STOPPED |
108 * | PAUSED | write() | | PAUSED |
109 * | STOPPED | write() | <thrd create> | PLAYING |
110 * | PLAYING | write() | HEADER | PLAYING |
111 * | (other) | write() | <error> | |
112 * | (any) | pause() | PAUSING | PAUSED |
113 * | PAUSED | restart() | RESTARTING | PLAYING (if no thrd => STOPPED) |
114 * | (any) | reset() | RESETTING | STOPPED |
115 * | (any) | close() | CLOSING | CLOSED |
116 * +---------+-------------+---------------+---------------------------------+
119 /* states of the playing device */
120 #define WINE_WS_PLAYING 0
121 #define WINE_WS_PAUSED 1
122 #define WINE_WS_STOPPED 2
123 #define WINE_WS_CLOSED 3
125 typedef struct {
126 volatile int state; /* one of the WINE_WS_ manifest constants */
127 WAVEOPENDESC waveDesc;
128 WORD wFlags;
129 PCMWAVEFORMAT format;
130 WAVEOUTCAPSW caps;
131 WORD wDevID;
132 char interface_name[32];
134 jack_port_t* out_port_l; /* ports for left and right channels */
135 jack_port_t* out_port_r;
136 jack_client_t* client;
137 long sample_rate; /* jack server sample rate */
139 #if JACK_CLOSE_HACK
140 BOOL in_use; /* TRUE if this device is in use */
141 #endif
143 char* sound_buffer;
144 unsigned long buffer_size;
146 DWORD volume_left;
147 DWORD volume_right;
149 LPWAVEHDR lpQueuePtr; /* start of queued WAVEHDRs (waiting to be notified) */
150 LPWAVEHDR lpPlayPtr; /* start of not yet fully played buffers */
151 DWORD dwPartialOffset; /* Offset of not yet written bytes in lpPlayPtr */
153 LPWAVEHDR lpLoopPtr; /* pointer of first buffer in loop, if any */
154 DWORD dwLoops; /* private copy of loop counter */
156 DWORD dwPlayedTotal; /* number of bytes actually played since opening */
157 DWORD dwWrittenTotal; /* number of bytes written to jack since opening */
159 DWORD bytesInJack; /* bytes that we wrote during the previous JACK_Callback() */
160 DWORD tickCountMS; /* time in MS of last JACK_Callback() */
162 /* synchronization stuff */
163 CRITICAL_SECTION access_crst;
164 } WINE_WAVEOUT;
166 typedef struct {
167 volatile int state;
168 WAVEOPENDESC waveDesc;
169 WORD wFlags;
170 PCMWAVEFORMAT format;
171 LPWAVEHDR lpQueuePtr;
172 DWORD dwTotalRecorded;
173 WAVEINCAPSW caps;
174 BOOL bTriggerSupport;
175 WORD wDevID;
176 char interface_name[32];
178 jack_port_t* in_port_l; /* ports for left and right channels */
179 jack_port_t* in_port_r;
180 jack_client_t* client;
181 long sample_rate; /* jack server sample rate */
183 #if JACK_CLOSE_HACK
184 BOOL in_use; /* TRUE if this device is in use */
185 #endif
187 char* sound_buffer;
188 unsigned long buffer_size;
190 /* synchronization stuff */
191 CRITICAL_SECTION access_crst;
192 } WINE_WAVEIN;
194 static WINE_WAVEOUT WOutDev [MAX_WAVEOUTDRV];
195 static WINE_WAVEIN WInDev [MAX_WAVEINDRV ];
197 static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);
198 static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc);
200 static LPWAVEHDR wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo);
201 static DWORD wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force);
203 static int JACK_OpenWaveOutDevice(WINE_WAVEOUT* wwo);
204 static int JACK_OpenWaveInDevice(WINE_WAVEIN* wwi, WORD nChannels);
206 #if JACK_CLOSE_HACK
207 static void JACK_CloseWaveOutDevice(WINE_WAVEOUT* wwo, BOOL close_client);
208 #else
209 static void JACK_CloseWaveOutDevice(WINE_WAVEOUT* wwo);
210 #endif
212 #if JACK_CLOSE_HACK
213 static void JACK_CloseWaveInDevice(WINE_WAVEIN* wwi, BOOL close_client);
214 #else
215 static void JACK_CloseWaveInDevice(WINE_WAVEIN* wwi);
216 #endif
218 static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
219 PCMWAVEFORMAT* format)
221 TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",
222 lpTime->wType, format->wBitsPerSample, format->wf.nSamplesPerSec,
223 format->wf.nChannels, format->wf.nAvgBytesPerSec);
224 TRACE("Position in bytes=%lu\n", position);
226 switch (lpTime->wType) {
227 case TIME_SAMPLES:
228 lpTime->u.sample = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
229 TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
230 break;
231 case TIME_MS:
232 lpTime->u.ms = 1000.0 * position / (format->wBitsPerSample / 8 * format->wf.nChannels * format->wf.nSamplesPerSec);
233 TRACE("TIME_MS=%lu\n", lpTime->u.ms);
234 break;
235 case TIME_SMPTE:
236 position = position / (format->wBitsPerSample / 8 * format->wf.nChannels);
237 lpTime->u.smpte.sec = position / format->wf.nSamplesPerSec;
238 position -= lpTime->u.smpte.sec * format->wf.nSamplesPerSec;
239 lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
240 lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
241 lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
242 lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
243 lpTime->u.smpte.fps = 30;
244 lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->wf.nSamplesPerSec;
245 position -= lpTime->u.smpte.frame * format->wf.nSamplesPerSec / lpTime->u.smpte.fps;
246 if (position != 0)
248 /* Round up */
249 lpTime->u.smpte.frame++;
251 TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
252 lpTime->u.smpte.hour, lpTime->u.smpte.min,
253 lpTime->u.smpte.sec, lpTime->u.smpte.frame);
254 break;
255 default:
256 WARN("Format %d not supported, using TIME_BYTES !\n", lpTime->wType);
257 lpTime->wType = TIME_BYTES;
258 /* fall through */
259 case TIME_BYTES:
260 lpTime->u.cb = position;
261 TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
262 break;
264 return MMSYSERR_NOERROR;
268 /*======================================================================*
269 * Low level WAVE implementation *
270 *======================================================================*/
272 #define SAMPLE_MAX_16BIT 32767.0f
274 /* Alsaplayer function that applies volume changes to a buffer */
275 /* (C) Andy Lo A Foe */
276 /* Length is in terms of 32 bit samples */
277 void volume_effect32(void *buffer, int length, int left, int right)
279 short *data = (short *)buffer;
280 int i, v;
282 if (right == -1) right = left;
284 for(i = 0; i < length; i++) {
285 v = (int) ((*(data) * left) / 100);
286 *(data++) = (v>32767) ? 32767 : ((v<-32768) ? -32768 : v);
287 v = (int) ((*(data) * right) / 100);
288 *(data++) = (v>32767) ? 32767 : ((v<-32768) ? -32768 : v);
292 /* move 16 bit mono/stereo to 16 bit stereo */
293 void sample_move_d16_d16(short *dst, short *src,
294 unsigned long nsamples, int nChannels)
296 while(nsamples--)
298 *dst = *src;
299 dst++;
301 if(nChannels == 2) src++;
303 *dst = *src;
304 dst++;
306 src++;
310 /* convert from 16 bit to floating point */
311 /* allow for copying of stereo data with alternating left/right */
312 /* channels to a buffer that will hold a single channel stream */
313 /* nsamples is in terms of 16bit samples */
314 /* src_skip is in terms of 16bit samples */
315 void sample_move_d16_s16 (sample_t *dst, short *src,
316 unsigned long nsamples, unsigned long src_skip)
318 /* ALERT: signed sign-extension portability !!! */
319 while (nsamples--)
321 *dst = (*src) / SAMPLE_MAX_16BIT;
322 dst++;
323 src += src_skip;
327 /* convert from floating point to 16 bit */
328 /* allow for copying of a buffer that will hold a single channel stream */
329 /* to stereo data with alternating left/right channels */
330 /* nsamples is in terms of float samples */
331 /* dst_skip is in terms of 16bit samples */
332 void sample_move_s16_d16 (short *dst, sample_t *src,
333 unsigned long nsamples, unsigned long dst_skip)
335 /* ALERT: signed sign-extension portability !!! */
336 while (nsamples--)
338 *dst = (*src) * SAMPLE_MAX_16BIT;
339 /* TRACE("src=(%.8f,%p) dst=(%d,%p)\n",*src,src,*dst,dst); */
340 dst += dst_skip;
341 src++;
346 /* fill dst buffer with nsamples worth of silence */
347 void sample_silence_dS (sample_t *dst, unsigned long nsamples)
349 /* ALERT: signed sign-extension portability !!! */
350 while (nsamples--)
352 *dst = 0;
353 dst++;
357 /******************************************************************
358 * JACK_callback_wwo
360 /* everytime the jack server wants something from us it calls this
361 function, so we either deliver it some sound to play or deliver it nothing
362 to play */
363 int JACK_callback_wwo (nframes_t nframes, void *arg)
365 sample_t* out_l;
366 sample_t* out_r;
367 WINE_WAVEOUT* wwo = (WINE_WAVEOUT*)arg;
369 TRACE("wDevID: %u, nframes %u state=%u\n", wwo->wDevID, nframes,wwo->state);
371 if(!wwo->client)
372 ERR("client is closed, this is weird...\n");
374 out_l = (sample_t *) fp_jack_port_get_buffer(wwo->out_port_l, nframes);
375 out_r = (sample_t *) fp_jack_port_get_buffer(wwo->out_port_r, nframes);
377 if(wwo->state == WINE_WS_PLAYING)
379 DWORD jackFramesAvailable = nframes;
380 DWORD outputFramesAvailable;
381 DWORD numFramesToWrite;
383 long written = 0;
384 char* buffer;
386 #if JACK_CLOSE_HACK
387 if(wwo->in_use == FALSE)
389 /* output silence if nothing is being outputted */
390 sample_silence_dS(out_l, nframes);
391 sample_silence_dS(out_r, nframes);
393 return 0;
395 #endif
397 TRACE("wwo.state == WINE_WS_PLAYING\n");
399 /* see if our sound_buffer is large enough to hold the number of frames jack requested */
400 /* Note: sound_buffer is always filled with 16-bit stereo data, even for mono mode */
401 if(wwo->buffer_size < (nframes * sizeof(short) * 2))
403 ERR("for some reason JACK_BufSize() didn't allocate enough memory\n");
404 ERR("allocated %ld bytes, need %d bytes\n", wwo->buffer_size, (nframes * sizeof(short) * 2));
405 return 0;
408 /* while we have jackFramesAvailable and a wave header to be played */
409 while(jackFramesAvailable && wwo->lpPlayPtr)
411 /* find the amount of audio to be played at this time */
412 outputFramesAvailable = (wwo->lpPlayPtr->dwBufferLength - wwo->dwPartialOffset) / wwo->format.wf.nBlockAlign;
414 numFramesToWrite = min(jackFramesAvailable, outputFramesAvailable);
415 TRACE("dwBufferLength=(%ld) dwPartialOffset=(%ld)\n",wwo->lpPlayPtr->dwBufferLength,wwo->dwPartialOffset);
416 TRACE("outputFramesAvailable == %ld, jackFramesAvailable == %ld\n", outputFramesAvailable, jackFramesAvailable);
418 buffer = wwo->lpPlayPtr->lpData + wwo->dwPartialOffset;
420 /* convert from mono to stereo if necessary */
421 /* otherwise just memcpy to the output buffer */
423 if(wwo->format.wf.nChannels == 1)
425 sample_move_d16_d16((short*)wwo->sound_buffer + ((nframes - jackFramesAvailable) * sizeof(short)),
426 (short*)buffer, numFramesToWrite, wwo->format.wf.nChannels);
427 } else /* just copy the memory over */
429 memcpy(wwo->sound_buffer + ((nframes - jackFramesAvailable) * wwo->format.wf.nBlockAlign),
430 buffer, numFramesToWrite * wwo->format.wf.nBlockAlign);
433 /* advance to the next wave header if possible, or advance pointer */
434 /* inside of the current header if we haven't completed it */
435 if(numFramesToWrite == outputFramesAvailable)
437 wodHelper_PlayPtrNext(wwo); /* we wrote the whole waveheader, skip to the next one*/
439 else
441 wwo->dwPartialOffset+=(numFramesToWrite * wwo->format.wf.nBlockAlign); /* else advance by the bytes we took in to write */
444 written+=(numFramesToWrite * wwo->format.wf.nBlockAlign); /* add on what we wrote */
445 jackFramesAvailable-=numFramesToWrite; /* take away what was written in terms of output bytes */
448 wwo->tickCountMS = GetTickCount(); /* record the current time */
449 wwo->dwWrittenTotal+=written; /* update states on wave device */
450 wwo->dwPlayedTotal+=wwo->bytesInJack; /* we must have finished with the last bytes or we wouldn't be back inside of this callback again... */
451 wwo->bytesInJack = written; /* record the bytes inside of jack */
453 /* Now that we have finished filling the buffer either until it is full or until */
454 /* we have run out of application sound data to process, apply volume and output */
455 /* the audio to the jack server */
457 /* apply volume to the buffer */
458 volume_effect32(wwo->sound_buffer, (nframes - jackFramesAvailable), wwo->volume_left, wwo->volume_right);
460 /* convert from stereo 16 bit to single channel 32 bit float */
461 /* for each jack server channel */
462 /* NOTE: we skip over two sample since we want to only get either the left or right channel */
463 sample_move_d16_s16(out_l, (short*)wwo->sound_buffer, (nframes - jackFramesAvailable), 2);
464 sample_move_d16_s16(out_r, (short*)wwo->sound_buffer + 1, (nframes - jackFramesAvailable), 2);
466 /* see if we still have jackBytesLeft here, if we do that means that we
467 ran out of wave data to play and had a buffer underrun, fill in
468 the rest of the space with zero bytes */
469 if(jackFramesAvailable)
471 ERR("buffer underrun of %ld frames\n", jackFramesAvailable);
472 sample_silence_dS(out_l + (nframes - jackFramesAvailable), jackFramesAvailable);
473 sample_silence_dS(out_r + (nframes - jackFramesAvailable), jackFramesAvailable);
476 else if(wwo->state == WINE_WS_PAUSED ||
477 wwo->state == WINE_WS_STOPPED ||
478 wwo->state == WINE_WS_CLOSED)
480 /* output silence if nothing is being outputted */
481 sample_silence_dS(out_l, nframes);
482 sample_silence_dS(out_r, nframes);
485 /* notify the client of completed wave headers */
486 EnterCriticalSection(&wwo->access_crst);
487 wodHelper_NotifyCompletions(wwo, FALSE);
488 LeaveCriticalSection(&wwo->access_crst);
490 return 0;
493 /******************************************************************
494 * JACK_bufsize_wwo
496 * Called whenever the jack server changes the the max number
497 * of frames passed to JACK_callback
499 int JACK_bufsize_wwo (nframes_t nframes, void *arg)
501 WINE_WAVEOUT* wwo = (WINE_WAVEOUT*)arg;
502 DWORD buffer_required;
503 TRACE("wDevID=%d\n",wwo->wDevID);
504 TRACE("the maximum buffer size is now %u frames\n", nframes);
506 /* make sure the callback routine has adequate memory */
507 /* see if our buffer is large enough for the data we are writing */
508 /* ie. Buffer_size < (bytes we already wrote + bytes we are going to write in this loop) */
509 EnterCriticalSection(&wwo->access_crst);
511 /* wwo->sound_buffer is always filled with 16-bit stereo data, even for mono streams */
512 buffer_required = nframes * sizeof(short) * 2;
513 TRACE("wwo->buffer_size (%ld) buffer_required (%ld).\n", wwo->buffer_size,buffer_required);
514 if(wwo->buffer_size < buffer_required)
516 TRACE("expanding buffer from wwo->buffer_size == %ld, to %ld\n",
517 wwo->buffer_size, buffer_required);
518 TRACE("GetProcessHeap() == %p\n", GetProcessHeap());
519 wwo->buffer_size = buffer_required;
521 if (wwo->sound_buffer)
522 wwo->sound_buffer = HeapReAlloc(GetProcessHeap(), 0, wwo->sound_buffer, wwo->buffer_size);
523 else
524 wwo->sound_buffer = HeapAlloc(GetProcessHeap(), 0, wwo->buffer_size);
526 /* if we don't have a buffer then error out */
527 if(!wwo->sound_buffer)
529 ERR("error allocating sound_buffer memory\n");
530 LeaveCriticalSection(&wwo->access_crst);
531 return 0;
535 LeaveCriticalSection(&wwo->access_crst);
537 TRACE("ending\n");
539 return 0;
541 /******************************************************************
542 * JACK_bufsize_wwi
544 * Called whenever the jack server changes the the max number
545 * of frames passed to JACK_callback
547 int JACK_bufsize_wwi (nframes_t nframes, void *arg)
549 TRACE("the maximum buffer size is now %u frames\n", nframes);
550 return 0;
553 /******************************************************************
554 * JACK_srate
556 int JACK_srate (nframes_t nframes, void *arg)
558 TRACE("the sample rate is now %u/sec\n", nframes);
559 return 0;
563 /******************************************************************
564 * JACK_shutdown_wwo
566 /* if this is called then jack shut down... handle this appropriately */
567 void JACK_shutdown_wwo(void* arg)
569 WINE_WAVEOUT* wwo = (WINE_WAVEOUT*)arg;
571 wwo->client = 0; /* reset client */
573 TRACE("trying to reconnect after sleeping for a short while...\n");
575 /* lets see if we can't reestablish the connection */
576 Sleep(750); /* pause for a short period of time */
577 if(!JACK_OpenWaveOutDevice(wwo))
579 ERR("unable to reconnect with jack...\n");
583 /******************************************************************
584 * JACK_shutdown_wwi
586 /* if this is called then jack shut down... handle this appropriately */
587 void JACK_shutdown_wwi(void* arg)
589 WINE_WAVEIN* wwi = (WINE_WAVEIN*)arg;
591 wwi->client = 0; /* reset client */
593 TRACE("trying to reconnect after sleeping for a short while...\n");
595 /* lets see if we can't reestablish the connection */
596 Sleep(750); /* pause for a short period of time */
597 if(!JACK_OpenWaveInDevice(wwi,wwi->format.wf.nChannels))
599 ERR("unable to reconnect with jack...\n");
604 /******************************************************************
605 * JACK_OpenWaveOutDevice
607 static int JACK_OpenWaveOutDevice(WINE_WAVEOUT* wwo)
609 const char** ports;
610 int i;
611 char client_name[64];
612 jack_port_t* out_port_l;
613 jack_port_t* out_port_r;
614 jack_client_t* client;
615 int failed = 0;
617 TRACE("creating jack client and setting up callbacks\n");
619 #if JACK_CLOSE_HACK
620 /* see if this device is already open */
621 if(wwo->client)
623 /* if this device is already in use then it is bad for us to be in here */
624 if(wwo->in_use)
625 return 0;
627 TRACE("using existing client\n");
628 wwo->in_use = TRUE;
629 return 1;
631 #endif
633 /* zero out the buffer pointer and the size of the buffer */
634 wwo->sound_buffer = 0;
635 wwo->buffer_size = 0;
637 /* try to become a client of the JACK server */
638 snprintf(client_name, sizeof(client_name), "wine_jack_out_%d", wwo->wDevID);
639 TRACE("client name '%s'\n", client_name);
640 if ((client = fp_jack_client_new (client_name)) == 0)
642 /* jack has problems with shutting down clients, so lets */
643 /* wait a short while and try once more before we give up */
644 Sleep(250);
645 if ((client = fp_jack_client_new (client_name)) == 0)
647 ERR("jack server not running?\n");
648 return 0;
652 /* tell the JACK server to call `JACK_callback_wwo()' whenever
653 there is work to be done. */
654 fp_jack_set_process_callback (client, JACK_callback_wwo, wwo);
656 /* tell the JACK server to call `JACK_bufsize_wwo()' whenever
657 the maximum number of frames that will be passed
658 to `JACK_Callback()' changes */
659 fp_jack_set_buffer_size_callback (client, JACK_bufsize_wwo, wwo);
661 /* tell the JACK server to call `srate()' whenever
662 the sample rate of the system changes. */
663 fp_jack_set_sample_rate_callback (client, JACK_srate, wwo);
665 /* tell the JACK server to call `jack_shutdown()' if
666 it ever shuts down, either entirely, or if it
667 just decides to stop calling us. */
668 fp_jack_on_shutdown (client, JACK_shutdown_wwo, wwo);
670 /* display the current sample rate. once the client is activated
671 (see below), you should rely on your own sample rate
672 callback (see above) for this value. */
673 wwo->sample_rate = fp_jack_get_sample_rate(client);
674 TRACE("engine sample rate: %lu\n", wwo->sample_rate);
676 /* create the left and right channel output ports */
677 /* jack's ports are all mono so for stereo you need two */
678 out_port_l = fp_jack_port_register (client, "out_l",
679 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
681 out_port_r = fp_jack_port_register (client, "out_r",
682 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
684 TRACE("Created ports. (%p) (%p)\n",out_port_l, out_port_r);
686 /* save away important values to the WINE_WAVEOUT struct */
687 wwo->client = client;
688 wwo->out_port_l = out_port_l;
689 wwo->out_port_r = out_port_r;
691 #if JACK_CLOSE_HACK
692 wwo->in_use = TRUE; /* mark this device as in use since it now is ;-) */
693 #endif
695 /* set initial buffer size */
696 JACK_bufsize_wwo (fp_jack_get_buffer_size(client),wwo);
698 /* tell the JACK server that we are ready to roll */
699 if (fp_jack_activate (client))
701 ERR( "cannot activate client\n");
702 return 0;
705 TRACE("jack activate.\n");
706 /* figure out what the ports that we want to output on are */
707 /* NOTE: we do this instead of using stuff like "alsa_pcm:playback_X" because */
708 /* this way works if names are changed */
709 ports = fp_jack_get_ports(client, NULL, NULL, JackPortIsPhysical|JackPortIsInput);
711 /* display a trace of the output ports we found */
712 for(i = 0; ports[i]; i++)
714 TRACE("ports[%d] = '%s'\n", i, ports[i]);
717 if(!ports)
719 ERR("jack_get_ports() failed to find 'JackPortIsPhysical|JackPortIsInput'\n");
722 /* connect the ports. Note: you can't do this before
723 the client is activated (this may change in the future).
725 /* we want to connect to two ports so we have stereo output ;-) */
727 if(fp_jack_connect(client, fp_jack_port_name(out_port_l), ports[0]))
729 ERR ("cannot connect to output port %d('%s')\n", 0, ports[0]);
730 failed = 1;
733 if(fp_jack_connect(client, fp_jack_port_name(out_port_r), ports[1]))
735 ERR ("cannot connect to output port %d('%s')\n", 1, ports[1]);
736 failed = 1;
739 free(ports); /* free the returned array of ports */
741 /* if something failed we need to shut the client down and return 0 */
742 if(failed)
744 #if JACK_CLOSE_HACK
745 JACK_CloseWaveOutDevice(wwo, TRUE);
746 #else
747 JACK_CloseWaveOutDevice(wwo);
748 #endif
749 return 0;
752 return 1; /* return success */
755 /******************************************************************
756 * JACK_CloseWaveOutDevice
758 * Close the connection to the server cleanly.
759 * If close_client is TRUE we close the client for this device instead of
760 * just marking the device as in_use(JACK_CLOSE_HACK only)
762 #if JACK_CLOSE_HACK
763 static void JACK_CloseWaveOutDevice(WINE_WAVEOUT* wwo, BOOL close_client)
764 #else
765 static void JACK_CloseWaveOutDevice(WINE_WAVEOUT* wwo)
766 #endif
768 #if JACK_CLOSE_HACK
769 TRACE("wDevID: %d, close_client (wwo): %d\n", wwo->wDevID, close_client);
770 #else
771 TRACE("wDevID: %d\n", wwo->wDevID);
772 #endif
774 #if JACK_CLOSE_HACK
775 if(close_client)
777 #endif
778 fp_jack_deactivate(wwo->client); /* supposed to help the jack_client_close() to succeed */
779 fp_jack_client_close (wwo->client);
781 EnterCriticalSection(&wwo->access_crst);
782 wwo->client = 0; /* reset client */
783 HeapFree(GetProcessHeap(), 0, wwo->sound_buffer); /* free buffer memory */
784 wwo->sound_buffer = 0;
785 wwo->buffer_size = 0; /* zero out size of the buffer */
786 LeaveCriticalSection(&wwo->access_crst);
787 #if JACK_CLOSE_HACK
788 } else
790 EnterCriticalSection(&wwo->access_crst);
791 TRACE("setting in_use to FALSE\n");
792 wwo->in_use = FALSE;
793 LeaveCriticalSection(&wwo->access_crst);
795 #endif
798 /******************************************************************
799 * JACK_CloseWaveInDevice
801 * Close the connection to the server cleanly.
802 * If close_client is TRUE we close the client for this device instead of
803 * just marking the device as in_use(JACK_CLOSE_HACK only)
805 #if JACK_CLOSE_HACK
806 static void JACK_CloseWaveInDevice(WINE_WAVEIN* wwi, BOOL close_client)
807 #else
808 static void JACK_CloseWaveInDevice(WINE_WAVEIN* wwi)
809 #endif
811 #if JACK_CLOSE_HACK
812 TRACE("wDevID: %d, close_client (wwi): %d\n", wwi->wDevID, close_client);
813 #else
814 TRACE("wDevID: %d\n", wwi->wDevID);
815 #endif
817 #if JACK_CLOSE_HACK
818 if(close_client)
820 #endif
821 fp_jack_deactivate(wwi->client); /* supposed to help the jack_client_close() to succeed */
822 fp_jack_client_close (wwi->client);
824 EnterCriticalSection(&wwi->access_crst);
825 wwi->client = 0; /* reset client */
826 HeapFree(GetProcessHeap(), 0, wwi->sound_buffer); /* free buffer memory */
827 wwi->sound_buffer = 0;
828 wwi->buffer_size = 0; /* zero out size of the buffer */
829 LeaveCriticalSection(&wwi->access_crst);
830 #if JACK_CLOSE_HACK
831 } else
833 EnterCriticalSection(&wwi->access_crst);
834 TRACE("setting in_use to FALSE\n");
835 wwi->in_use = FALSE;
836 LeaveCriticalSection(&wwi->access_crst);
838 #endif
841 /******************************************************************
842 * JACK_WaveRelease
846 LONG JACK_WaveRelease(void)
848 int iDevice;
850 TRACE("closing all open waveout devices\n");
852 /* close all open output devices */
853 for(iDevice = 0; iDevice < MAX_WAVEOUTDRV; iDevice++)
855 TRACE("iDevice == %d\n", iDevice);
856 if(WOutDev[iDevice].client)
858 #if JACK_CLOSE_HACK
859 JACK_CloseWaveOutDevice(&WOutDev[iDevice], TRUE); /* close the device, FORCE the client to close */
860 #else
861 JACK_CloseWaveOutDevice(&WOutDev[iDevice]); /* close the device, FORCE the client to close */
862 #endif
863 DeleteCriticalSection(&(WOutDev[iDevice].access_crst)); /* delete the critical section */
867 TRACE("closing all open wavein devices\n");
869 /* close all open input devices */
870 for(iDevice = 0; iDevice < MAX_WAVEINDRV; iDevice++)
872 TRACE("iDevice == %d\n", iDevice);
873 if(WInDev[iDevice].client)
875 #if JACK_CLOSE_HACK
876 JACK_CloseWaveInDevice(&WInDev[iDevice], TRUE); /* close the device, FORCE the client to close */
877 #else
878 JACK_CloseWaveInDevice(&WInDev[iDevice]); /* close the device, FORCE the client to close */
879 #endif
880 DeleteCriticalSection(&(WInDev[iDevice].access_crst)); /* delete the critical section */
884 TRACE("returning 1\n");
886 return 1;
889 /******************************************************************
890 * JACK_WaveInit
892 * Initialize internal structures from JACK server info
894 LONG JACK_WaveInit(void)
896 int i;
898 static const WCHAR ini_out[] = {'J','A','C','K',' ','W','a','v','e','O','u','t',' ','D','r','i','v','e','r',0};
899 static const WCHAR ini_in [] = {'J','A','C','K',' ','W','a','v','e','I','n',' ',' ','D','r','i','v','e','r',0};
901 TRACE("called\n");
903 /* setup function pointers */
904 #define LOAD_FUNCPTR(f) if((fp_##f = wine_dlsym(jackhandle, #f, NULL, 0)) == NULL) goto sym_not_found;
905 LOAD_FUNCPTR(jack_activate);
906 LOAD_FUNCPTR(jack_connect);
907 LOAD_FUNCPTR(jack_client_new);
908 LOAD_FUNCPTR(jack_client_close);
909 LOAD_FUNCPTR(jack_deactivate);
910 LOAD_FUNCPTR(jack_set_process_callback);
911 LOAD_FUNCPTR(jack_set_buffer_size_callback);
912 LOAD_FUNCPTR(jack_set_sample_rate_callback);
913 LOAD_FUNCPTR(jack_on_shutdown);
914 LOAD_FUNCPTR(jack_get_sample_rate);
915 LOAD_FUNCPTR(jack_port_register);
916 LOAD_FUNCPTR(jack_port_get_buffer);
917 LOAD_FUNCPTR(jack_get_ports);
918 LOAD_FUNCPTR(jack_port_name);
919 LOAD_FUNCPTR(jack_get_buffer_size);
920 #undef LOAD_FUNCPTR
922 /* start with output device */
924 for (i = 0; i < MAX_WAVEOUTDRV; ++i)
926 WOutDev[i].client = 0; /* initialize the client to 0 */
928 #if JACK_CLOSE_HACK
929 WOutDev[i].in_use = FALSE;
930 WInDev[i].in_use = FALSE;
931 #endif
933 memset(&WOutDev[i].caps, 0, sizeof(WOutDev[i].caps));
935 WOutDev[i].caps.wMid = 0x00FF; /* Manufac ID */
936 WOutDev[i].caps.wPid = 0x0001; /* Product ID */
937 strcpyW(WOutDev[i].caps.szPname, ini_out);
939 snprintf(WOutDev[i].interface_name, sizeof(WOutDev[i].interface_name), "winejack: %d", i);
941 WOutDev[i].caps.vDriverVersion = 0x0100;
942 WOutDev[i].caps.dwFormats = 0x00000000;
943 WOutDev[i].caps.dwSupport = WAVECAPS_VOLUME;
945 WOutDev[i].caps.wChannels = 2;
946 WOutDev[i].caps.dwSupport |= WAVECAPS_LRVOLUME;
948 /* NOTE: we don't support any 8 bit modes so note that */
949 /* WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;
950 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S08; */
951 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S16;
952 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M16;
953 /* WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;
954 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S08; */
955 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M16;
956 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S16;
957 /* WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;
958 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;*/
959 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M16;
960 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S16;
963 /* then do input device */
964 for (i = 0; i < MAX_WAVEINDRV; ++i)
966 /* TODO: we should initialize read stuff here */
967 memset(&WInDev[0].caps, 0, sizeof(WInDev[0].caps));
969 WInDev[i].caps.wMid = 0x00FF;
970 WInDev[i].caps.wPid = 0x0001;
971 strcpyW(WInDev[i].caps.szPname, ini_in);
972 snprintf(WInDev[i].interface_name, sizeof(WInDev[i].interface_name), "winejack: %d", i);
974 WInDev[i].caps.vDriverVersion = 0x0100;
976 WInDev[i].caps.wChannels = 0x2;
977 /* NOTE: we don't support any 8 bit modes so note that */
978 /* WInDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;
979 WInDev[i].caps.dwFormats |= WAVE_FORMAT_4S08; */
980 WInDev[i].caps.dwFormats |= WAVE_FORMAT_4S16;
981 WInDev[i].caps.dwFormats |= WAVE_FORMAT_4M16;
982 /* WInDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;
983 WInDev[i].caps.dwFormats |= WAVE_FORMAT_2S08; */
984 WInDev[i].caps.dwFormats |= WAVE_FORMAT_2M16;
985 WInDev[i].caps.dwFormats |= WAVE_FORMAT_2S16;
986 /* WInDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;
987 WInDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;*/
988 WInDev[i].caps.dwFormats |= WAVE_FORMAT_1M16;
989 WInDev[i].caps.dwFormats |= WAVE_FORMAT_1S16;
990 WInDev[i].caps.wReserved1 = 0;
993 return 1; /* return success */
995 /* error path for function pointer loading errors */
996 sym_not_found:
997 WINE_MESSAGE(
998 "Wine cannot find certain functions that it needs inside the jack"
999 "library. To enable Wine to use the jack audio server please "
1000 "install libjack\n");
1001 wine_dlclose(jackhandle, NULL, 0);
1002 jackhandle = NULL;
1003 return FALSE;
1006 /*======================================================================*
1007 * Low level WAVE OUT implementation *
1008 *======================================================================*/
1010 /**************************************************************************
1011 * wodNotifyClient [internal]
1013 static DWORD wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
1015 TRACE("wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX\n", wMsg, dwParam1, dwParam2);
1017 switch (wMsg) {
1018 case WOM_OPEN:
1019 case WOM_CLOSE:
1020 case WOM_DONE:
1021 if (wwo->wFlags != DCB_NULL &&
1022 !DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags,
1023 (HDRVR)wwo->waveDesc.hWave, wMsg, wwo->waveDesc.dwInstance,
1024 dwParam1, dwParam2))
1026 WARN("can't notify client !\n");
1027 return MMSYSERR_ERROR;
1029 break;
1030 default:
1031 FIXME("Unknown callback message %u\n", wMsg);
1032 return MMSYSERR_INVALPARAM;
1034 return MMSYSERR_NOERROR;
1037 /**************************************************************************
1038 * wodHelper_BeginWaveHdr [internal]
1040 * Makes the specified lpWaveHdr the currently playing wave header.
1041 * If the specified wave header is a begin loop and we're not already in
1042 * a loop, setup the loop.
1044 static void wodHelper_BeginWaveHdr(WINE_WAVEOUT* wwo, LPWAVEHDR lpWaveHdr)
1046 EnterCriticalSection(&wwo->access_crst);
1048 wwo->lpPlayPtr = lpWaveHdr;
1050 if (!lpWaveHdr)
1052 LeaveCriticalSection(&wwo->access_crst);
1053 return;
1056 if (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)
1058 if (wwo->lpLoopPtr)
1060 WARN("Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);
1061 TRACE("Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);
1062 } else
1064 TRACE("Starting loop (%ldx) with %p\n", lpWaveHdr->dwLoops, lpWaveHdr);
1065 wwo->lpLoopPtr = lpWaveHdr;
1066 /* Windows does not touch WAVEHDR.dwLoops,
1067 * so we need to make an internal copy */
1068 wwo->dwLoops = lpWaveHdr->dwLoops;
1071 wwo->dwPartialOffset = 0;
1073 LeaveCriticalSection(&wwo->access_crst);
1077 /**************************************************************************
1078 * wodHelper_PlayPtrNext [internal]
1080 * Advance the play pointer to the next waveheader, looping if required.
1082 static LPWAVEHDR wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo)
1084 LPWAVEHDR lpWaveHdr;
1086 EnterCriticalSection(&wwo->access_crst);
1088 lpWaveHdr = wwo->lpPlayPtr;
1090 wwo->dwPartialOffset = 0;
1091 if ((lpWaveHdr->dwFlags & WHDR_ENDLOOP) && wwo->lpLoopPtr)
1093 /* We're at the end of a loop, loop if required */
1094 if (--wwo->dwLoops > 0)
1096 wwo->lpPlayPtr = wwo->lpLoopPtr;
1097 } else
1099 /* Handle overlapping loops correctly */
1100 if (wwo->lpLoopPtr != lpWaveHdr && (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)) {
1101 FIXME("Correctly handled case ? (ending loop buffer also starts a new loop)\n");
1102 /* shall we consider the END flag for the closing loop or for
1103 * the opening one or for both ???
1104 * code assumes for closing loop only
1106 } else
1108 lpWaveHdr = lpWaveHdr->lpNext;
1110 wwo->lpLoopPtr = NULL;
1111 wodHelper_BeginWaveHdr(wwo, lpWaveHdr);
1113 } else
1115 /* We're not in a loop. Advance to the next wave header */
1116 TRACE("not inside of a loop, advancing to next wave header\n");
1117 wodHelper_BeginWaveHdr(wwo, lpWaveHdr = lpWaveHdr->lpNext);
1120 LeaveCriticalSection(&wwo->access_crst);
1122 return lpWaveHdr;
1125 /* if force is TRUE then notify the client that all the headers were completed */
1126 static DWORD wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force)
1128 LPWAVEHDR lpWaveHdr;
1129 DWORD retval;
1131 TRACE("called\n");
1133 EnterCriticalSection(&wwo->access_crst);
1135 /* Start from lpQueuePtr and keep notifying until:
1136 * - we hit an unwritten wavehdr
1137 * - we hit the beginning of a running loop
1138 * - we hit a wavehdr which hasn't finished playing
1140 while ((lpWaveHdr = wwo->lpQueuePtr) &&
1141 (force ||
1142 (lpWaveHdr != wwo->lpPlayPtr &&
1143 lpWaveHdr != wwo->lpLoopPtr)))
1145 wwo->lpQueuePtr = lpWaveHdr->lpNext;
1147 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1148 lpWaveHdr->dwFlags |= WHDR_DONE;
1149 TRACE("notifying client: lpWaveHdr=(%p) lpPlayPtr=(%p) dwFlags=(%ld)\n",
1150 lpWaveHdr, wwo->lpPlayPtr, lpWaveHdr->dwFlags);
1152 wodNotifyClient(wwo, WOM_DONE, (DWORD)lpWaveHdr, 0);
1154 TRACE("Not notifying client: lpWaveHdr=(%p) lpPlayPtr=(%p) lpLoopPtr=(%p)\n",
1155 lpWaveHdr, wwo->lpPlayPtr, wwo->lpLoopPtr);
1156 retval = (lpWaveHdr && lpWaveHdr != wwo->lpPlayPtr && lpWaveHdr !=
1157 wwo->lpLoopPtr) ? 0 : INFINITE;
1159 LeaveCriticalSection(&wwo->access_crst);
1161 return retval;
1164 /**************************************************************************
1165 * wodHelper_Reset [internal]
1167 * Resets current output stream.
1169 static void wodHelper_Reset(WINE_WAVEOUT* wwo, BOOL reset)
1171 EnterCriticalSection(&wwo->access_crst);
1173 /* updates current notify list */
1174 wodHelper_NotifyCompletions(wwo, FALSE);
1176 if (reset)
1178 /* remove all wave headers and notify client that all headers were completed */
1179 wodHelper_NotifyCompletions(wwo, TRUE);
1181 wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL;
1182 wwo->state = WINE_WS_STOPPED;
1183 wwo->dwPlayedTotal = wwo->dwWrittenTotal = wwo->bytesInJack = 0;
1185 wwo->dwPartialOffset = 0; /* Clear partial wavehdr */
1186 } else
1188 if (wwo->lpLoopPtr)
1190 /* complicated case, not handled yet (could imply modifying the loop counter) */
1191 FIXME("Pausing while in loop isn't correctly handled yet, except strange results\n");
1192 wwo->lpPlayPtr = wwo->lpLoopPtr;
1193 wwo->dwPartialOffset = 0;
1194 wwo->dwWrittenTotal = wwo->dwPlayedTotal; /* this is wrong !!! */
1195 } else
1197 LPWAVEHDR ptr;
1198 DWORD sz = wwo->dwPartialOffset;
1200 /* reset all the data as if we had written only up to lpPlayedTotal bytes */
1201 /* compute the max size playable from lpQueuePtr */
1202 for (ptr = wwo->lpQueuePtr; ptr != wwo->lpPlayPtr; ptr = ptr->lpNext)
1204 sz += ptr->dwBufferLength;
1207 /* because the reset lpPlayPtr will be lpQueuePtr */
1208 if (wwo->dwWrittenTotal > wwo->dwPlayedTotal + sz) ERR("doh\n");
1209 wwo->dwPartialOffset = sz - (wwo->dwWrittenTotal - wwo->dwPlayedTotal);
1210 wwo->dwWrittenTotal = wwo->dwPlayedTotal;
1211 wwo->lpPlayPtr = wwo->lpQueuePtr;
1214 wwo->state = WINE_WS_PAUSED;
1217 LeaveCriticalSection(&wwo->access_crst);
1220 /**************************************************************************
1221 * wodGetDevCaps [internal]
1223 static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSW lpCaps, DWORD dwSize)
1225 TRACE("(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
1227 if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
1229 if (wDevID >= MAX_WAVEOUTDRV)
1231 TRACE("MAX_WAVOUTDRV reached !\n");
1232 return MMSYSERR_BADDEVICEID;
1235 TRACE("dwSupport=(0x%lx), dwFormats=(0x%lx)\n", WOutDev[wDevID].caps.dwSupport, WOutDev[wDevID].caps.dwFormats);
1236 memcpy(lpCaps, &WOutDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));
1237 return MMSYSERR_NOERROR;
1240 /**************************************************************************
1241 * wodOpen [internal]
1243 * NOTE: doesn't it seem like there is a race condition if you try to open
1244 * the same device twice?
1246 static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
1248 WINE_WAVEOUT* wwo;
1249 DWORD retval;
1251 TRACE("(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
1252 if (lpDesc == NULL)
1254 WARN("Invalid Parameter !\n");
1255 return MMSYSERR_INVALPARAM;
1257 if (wDevID >= MAX_WAVEOUTDRV) {
1258 TRACE("MAX_WAVOUTDRV reached !\n");
1259 return MMSYSERR_BADDEVICEID;
1262 #if JACK_CLOSE_HACK
1263 if(WOutDev[wDevID].client && WOutDev[wDevID].in_use)
1264 #else
1265 if(WOutDev[wDevID].client)
1266 #endif
1268 TRACE("device %d already allocated\n", wDevID);
1269 return MMSYSERR_ALLOCATED;
1272 /* Only the PCM format is supported so far...
1273 * Also we only support 16 bit mode.
1275 if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM ||
1276 lpDesc->lpFormat->nChannels == 0 ||
1277 lpDesc->lpFormat->nSamplesPerSec == 0 ||
1278 lpDesc->lpFormat->wBitsPerSample != 16)
1280 WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%ld wBitsPerSample=%d !\n",
1281 lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
1282 lpDesc->lpFormat->nSamplesPerSec, lpDesc->lpFormat->wBitsPerSample);
1283 return WAVERR_BADFORMAT;
1286 if (dwFlags & WAVE_FORMAT_QUERY)
1288 TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%ld !\n",
1289 lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
1290 lpDesc->lpFormat->nSamplesPerSec);
1291 return MMSYSERR_NOERROR;
1294 wwo = &WOutDev[wDevID];
1295 wwo->wDevID = wDevID;
1297 /* Set things up before we call JACK_OpenWaveOutDevice because */
1298 /* we will start getting callbacks before JACK_OpenWaveOutDevice */
1299 /* even returns and we want to be initialized before then */
1300 wwo->state = WINE_WS_STOPPED; /* start in a stopped state */
1301 wwo->dwPlayedTotal = 0; /* zero out these totals */
1302 wwo->dwWrittenTotal = 0;
1303 wwo->bytesInJack = 0;
1304 wwo->tickCountMS = 0;
1306 /* Initialize volume to full level */
1307 wwo->volume_left = 100;
1308 wwo->volume_right = 100;
1310 InitializeCriticalSection(&wwo->access_crst); /* initialize the critical section */
1311 EnterCriticalSection(&wwo->access_crst);
1313 dwFlags &= ~WAVE_DIRECTSOUND; /* direct sound not supported, ignore the flag */
1315 wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
1317 memcpy(&wwo->waveDesc, lpDesc, sizeof(WAVEOPENDESC));
1318 memcpy(&wwo->format, lpDesc->lpFormat, sizeof(PCMWAVEFORMAT));
1320 /* open up jack ports for this device */
1321 if (!JACK_OpenWaveOutDevice(&WOutDev[wDevID]))
1323 ERR("JACK_OpenWaveOutDevice(%d) failed\n", wDevID);
1324 LeaveCriticalSection(&wwo->access_crst);
1325 DeleteCriticalSection(&wwo->access_crst); /* delete the critical section so we can initialize it again from wodOpen() */
1326 return MMSYSERR_ERROR; /* return unspecified error */
1329 LeaveCriticalSection(&wwo->access_crst);
1331 /* display the current wave format */
1332 TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%lu, nSamplesPerSec=%lu, nChannels=%u nBlockAlign=%u!\n",
1333 wwo->format.wBitsPerSample, wwo->format.wf.nAvgBytesPerSec,
1334 wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels,
1335 wwo->format.wf.nBlockAlign);
1337 /* make sure that we have the same sample rate in our audio stream */
1338 /* as we do in the jack server */
1339 if(wwo->format.wf.nSamplesPerSec != wwo->sample_rate)
1341 TRACE("error: jack server sample rate is '%ld', wave sample rate is '%ld'\n",
1342 wwo->sample_rate, wwo->format.wf.nSamplesPerSec);
1344 #if JACK_CLOSE_HACK
1345 JACK_CloseWaveOutDevice(wwo, FALSE); /* close this device, don't force the client to close */
1346 #else
1347 JACK_CloseWaveOutDevice(wwo); /* close this device */
1348 #endif
1349 DeleteCriticalSection(&wwo->access_crst); /* delete the critical section so we can initialize it again from wodOpen() */
1350 return WAVERR_BADFORMAT;
1353 /* check for an invalid number of bits per sample */
1354 if (wwo->format.wBitsPerSample == 0)
1356 WARN("Resetting zeroed wBitsPerSample\n");
1357 wwo->format.wBitsPerSample = 8 *
1358 (wwo->format.wf.nAvgBytesPerSec /
1359 wwo->format.wf.nSamplesPerSec) /
1360 wwo->format.wf.nChannels;
1363 EnterCriticalSection(&wwo->access_crst);
1364 retval = wodNotifyClient(wwo, WOM_OPEN, 0L, 0L);
1365 LeaveCriticalSection(&wwo->access_crst);
1367 return retval;
1370 /**************************************************************************
1371 * wodClose [internal]
1373 static DWORD wodClose(WORD wDevID)
1375 DWORD ret = MMSYSERR_NOERROR;
1376 WINE_WAVEOUT* wwo;
1378 TRACE("(%u);\n", wDevID);
1380 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1382 WARN("bad device ID !\n");
1383 return MMSYSERR_BADDEVICEID;
1386 wwo = &WOutDev[wDevID];
1387 if (wwo->lpQueuePtr)
1389 WARN("buffers still playing !\n");
1390 ret = WAVERR_STILLPLAYING;
1391 } else
1393 /* sanity check: this should not happen since the device must have been reset before */
1394 if (wwo->lpQueuePtr || wwo->lpPlayPtr) ERR("out of sync\n");
1396 wwo->state = WINE_WS_CLOSED; /* mark the device as closed */
1398 #if JACK_CLOSE_HACK
1399 JACK_CloseWaveOutDevice(wwo, FALSE); /* close the jack device, DO NOT force the client to close */
1400 #else
1401 JACK_CloseWaveOutDevice(wwo); /* close the jack device */
1402 #endif
1403 DeleteCriticalSection(&wwo->access_crst); /* delete the critical section so we can initialize it again from wodOpen() */
1405 ret = wodNotifyClient(wwo, WOM_CLOSE, 0L, 0L);
1408 return ret;
1412 /**************************************************************************
1413 * wodWrite [internal]
1416 static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1418 LPWAVEHDR*wh;
1419 WINE_WAVEOUT *wwo;
1421 TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1423 /* first, do the sanity checks... */
1424 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1426 WARN("bad dev ID !\n");
1427 return MMSYSERR_BADDEVICEID;
1430 wwo = &WOutDev[wDevID];
1432 if (lpWaveHdr->lpData == NULL || !(lpWaveHdr->dwFlags & WHDR_PREPARED))
1434 TRACE("unprepared\n");
1435 return WAVERR_UNPREPARED;
1438 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1440 TRACE("still playing\n");
1441 return WAVERR_STILLPLAYING;
1444 lpWaveHdr->dwFlags &= ~WHDR_DONE;
1445 lpWaveHdr->dwFlags |= WHDR_INQUEUE;
1446 lpWaveHdr->lpNext = 0;
1448 EnterCriticalSection(&wwo->access_crst);
1450 /* insert buffer at the end of queue */
1451 for (wh = &(wwo->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
1452 *wh = lpWaveHdr;
1454 if (!wwo->lpPlayPtr)
1455 wodHelper_BeginWaveHdr(wwo,lpWaveHdr);
1456 if (wwo->state == WINE_WS_STOPPED)
1457 wwo->state = WINE_WS_PLAYING;
1458 LeaveCriticalSection(&wwo->access_crst);
1460 return MMSYSERR_NOERROR;
1463 /**************************************************************************
1464 * wodPrepare [internal]
1466 static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1468 TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1470 if (wDevID >= MAX_WAVEOUTDRV)
1472 WARN("bad device ID !\n");
1473 return MMSYSERR_BADDEVICEID;
1476 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1477 return WAVERR_STILLPLAYING;
1479 lpWaveHdr->dwFlags |= WHDR_PREPARED;
1480 lpWaveHdr->dwFlags &= ~WHDR_DONE;
1481 return MMSYSERR_NOERROR;
1484 /**************************************************************************
1485 * wodUnprepare [internal]
1487 static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1489 TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1491 if (wDevID >= MAX_WAVEOUTDRV)
1493 WARN("bad device ID !\n");
1494 return MMSYSERR_BADDEVICEID;
1497 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1498 return WAVERR_STILLPLAYING;
1500 lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
1501 lpWaveHdr->dwFlags |= WHDR_DONE;
1503 return MMSYSERR_NOERROR;
1506 /**************************************************************************
1507 * wodPause [internal]
1509 static DWORD wodPause(WORD wDevID)
1511 TRACE("(%u);!\n", wDevID);
1513 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1515 WARN("bad device ID !\n");
1516 return MMSYSERR_BADDEVICEID;
1519 TRACE("[3-PAUSING]\n");
1521 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1522 wodHelper_Reset(&WOutDev[wDevID], FALSE);
1523 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1525 return MMSYSERR_NOERROR;
1528 /**************************************************************************
1529 * wodRestart [internal]
1531 static DWORD wodRestart(WORD wDevID)
1533 TRACE("(%u);\n", wDevID);
1535 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1537 WARN("bad device ID !\n");
1538 return MMSYSERR_BADDEVICEID;
1541 if (WOutDev[wDevID].state == WINE_WS_PAUSED)
1543 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1544 WOutDev[wDevID].state = WINE_WS_PLAYING;
1545 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1548 return MMSYSERR_NOERROR;
1551 /**************************************************************************
1552 * wodReset [internal]
1554 static DWORD wodReset(WORD wDevID)
1556 TRACE("(%u);\n", wDevID);
1558 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1560 WARN("bad device ID !\n");
1561 return MMSYSERR_BADDEVICEID;
1564 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1565 wodHelper_Reset(&WOutDev[wDevID], TRUE);
1566 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1568 return MMSYSERR_NOERROR;
1571 /**************************************************************************
1572 * wodGetPosition [internal]
1574 static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
1576 DWORD val;
1577 WINE_WAVEOUT* wwo;
1578 DWORD elapsedMS;
1580 TRACE("(%u, %p, %lu);\n", wDevID, lpTime, uSize);
1582 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1584 WARN("bad device ID !\n");
1585 return MMSYSERR_BADDEVICEID;
1588 /* if null pointer to time structure return error */
1589 if (lpTime == NULL) return MMSYSERR_INVALPARAM;
1591 wwo = &WOutDev[wDevID];
1593 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1594 val = wwo->dwPlayedTotal;
1595 elapsedMS = GetTickCount() - wwo->tickCountMS;
1596 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1598 /* account for the bytes played since the last JACK_Callback() */
1599 val+=((elapsedMS * wwo->format.wf.nAvgBytesPerSec) / 1000);
1601 return bytes_to_mmtime(lpTime, val, &wwo->format);
1604 /**************************************************************************
1605 * wodBreakLoop [internal]
1607 static DWORD wodBreakLoop(WORD wDevID)
1609 TRACE("(%u);\n", wDevID);
1611 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1613 WARN("bad device ID !\n");
1614 return MMSYSERR_BADDEVICEID;
1617 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1619 if (WOutDev[wDevID].state == WINE_WS_PLAYING && WOutDev[wDevID].lpLoopPtr != NULL)
1621 /* ensure exit at end of current loop */
1622 WOutDev[wDevID].dwLoops = 1;
1625 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1627 return MMSYSERR_NOERROR;
1630 /**************************************************************************
1631 * wodGetVolume [internal]
1633 static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
1635 DWORD left, right;
1637 left = WOutDev[wDevID].volume_left;
1638 right = WOutDev[wDevID].volume_right;
1640 TRACE("(%u, %p);\n", wDevID, lpdwVol);
1642 *lpdwVol = ((left * 0xFFFFl) / 100) + (((right * 0xFFFFl) / 100) <<
1643 16);
1645 return MMSYSERR_NOERROR;
1648 /**************************************************************************
1649 * wodSetVolume [internal]
1651 static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
1653 DWORD left, right;
1655 left = (LOWORD(dwParam) * 100) / 0xFFFFl;
1656 right = (HIWORD(dwParam) * 100) / 0xFFFFl;
1658 TRACE("(%u, %08lX);\n", wDevID, dwParam);
1660 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1662 WOutDev[wDevID].volume_left = left;
1663 WOutDev[wDevID].volume_right = right;
1665 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1667 return MMSYSERR_NOERROR;
1670 /**************************************************************************
1671 * wodGetNumDevs [internal]
1673 static DWORD wodGetNumDevs(void)
1675 return MAX_WAVEOUTDRV;
1678 /**************************************************************************
1679 * wodDevInterfaceSize [internal]
1681 static DWORD wodDevInterfaceSize(UINT wDevID, LPDWORD dwParam1)
1683 TRACE("(%u, %p)\n", wDevID, dwParam1);
1685 *dwParam1 = MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].interface_name, -1,
1686 NULL, 0 ) * sizeof(WCHAR);
1687 return MMSYSERR_NOERROR;
1690 /**************************************************************************
1691 * wodDevInterface [internal]
1693 static DWORD wodDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2)
1695 if (dwParam2 >= MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].interface_name, -1,
1696 NULL, 0 ) * sizeof(WCHAR))
1698 MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].interface_name, -1,
1699 dwParam1, dwParam2 / sizeof(WCHAR));
1700 return MMSYSERR_NOERROR;
1702 return MMSYSERR_INVALPARAM;
1705 /**************************************************************************
1706 * wodMessage (WINEJACK.7)
1708 DWORD WINAPI JACK_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
1709 DWORD dwParam1, DWORD dwParam2)
1711 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1712 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1714 switch (wMsg) {
1715 case DRVM_INIT:
1716 TRACE("DRVM_INIT\n");
1717 return JACK_WaveInit();
1718 case DRVM_EXIT:
1719 TRACE("DRVM_EXIT\n");
1720 return JACK_WaveRelease();
1721 case DRVM_ENABLE:
1722 /* FIXME: Pretend this is supported */
1723 TRACE("DRVM_ENABLE\n");
1724 return 0;
1725 case DRVM_DISABLE:
1726 /* FIXME: Pretend this is supported */
1727 TRACE("DRVM_DISABLE\n");
1728 return 0;
1729 case WODM_OPEN: return wodOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
1730 case WODM_CLOSE: return wodClose(wDevID);
1731 case WODM_WRITE: return wodWrite(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1732 case WODM_PAUSE: return wodPause(wDevID);
1733 case WODM_GETPOS: return wodGetPosition(wDevID, (LPMMTIME)dwParam1, dwParam2);
1734 case WODM_BREAKLOOP: return wodBreakLoop(wDevID);
1735 case WODM_PREPARE: return wodPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1736 case WODM_UNPREPARE: return wodUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1737 case WODM_GETDEVCAPS: return wodGetDevCaps(wDevID, (LPWAVEOUTCAPSW)dwParam1, dwParam2);
1738 case WODM_GETNUMDEVS: return wodGetNumDevs();
1739 case WODM_GETPITCH: return MMSYSERR_NOTSUPPORTED;
1740 case WODM_SETPITCH: return MMSYSERR_NOTSUPPORTED;
1741 case WODM_GETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED;
1742 case WODM_SETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED;
1743 case WODM_GETVOLUME: return wodGetVolume(wDevID, (LPDWORD)dwParam1);
1744 case WODM_SETVOLUME: return wodSetVolume(wDevID, dwParam1);
1745 case WODM_RESTART: return wodRestart(wDevID);
1746 case WODM_RESET: return wodReset(wDevID);
1748 case DRV_QUERYDEVICEINTERFACESIZE: return wodDevInterfaceSize (wDevID, (LPDWORD)dwParam1);
1749 case DRV_QUERYDEVICEINTERFACE: return wodDevInterface (wDevID, (PWCHAR)dwParam1, dwParam2);
1750 case DRV_QUERYDSOUNDIFACE: return wodDsCreate(wDevID, (PIDSDRIVER*)dwParam1);
1751 case DRV_QUERYDSOUNDDESC: return wodDsDesc(wDevID, (PDSDRIVERDESC)dwParam1);
1752 default:
1753 FIXME("unknown message %d!\n", wMsg);
1755 return MMSYSERR_NOTSUPPORTED;
1758 /*======================================================================*
1759 * Low level DSOUND implementation *
1760 *======================================================================*/
1762 typedef struct IDsDriverImpl IDsDriverImpl;
1763 typedef struct IDsDriverBufferImpl IDsDriverBufferImpl;
1765 struct IDsDriverImpl
1767 /* IUnknown fields */
1768 IDsDriverVtbl *lpVtbl;
1769 DWORD ref;
1770 /* IDsDriverImpl fields */
1771 UINT wDevID;
1772 IDsDriverBufferImpl*primary;
1775 struct IDsDriverBufferImpl
1777 /* IUnknown fields */
1778 IDsDriverBufferVtbl *lpVtbl;
1779 DWORD ref;
1780 /* IDsDriverBufferImpl fields */
1781 IDsDriverImpl* drv;
1782 DWORD buflen;
1785 static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv)
1787 /* we can't perform memory mapping as we don't have a file stream
1788 interface with jack like we do with oss */
1789 MESSAGE("This sound card's driver does not support direct access\n");
1790 MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
1791 return MMSYSERR_NOTSUPPORTED;
1794 static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc)
1796 memset(desc, 0, sizeof(*desc));
1797 strcpy(desc->szDesc, "Wine jack DirectSound Driver");
1798 strcpy(desc->szDrvName, "winejack.drv");
1799 return MMSYSERR_NOERROR;
1802 /*======================================================================*
1803 * Low level WAVE IN implementation *
1804 *======================================================================*/
1806 /**************************************************************************
1807 * widNotifyClient [internal]
1809 static DWORD widNotifyClient(WINE_WAVEIN* wwi, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
1811 TRACE("wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX\n", wMsg, dwParam1, dwParam2);
1813 switch (wMsg) {
1814 case WIM_OPEN:
1815 case WIM_CLOSE:
1816 case WIM_DATA:
1817 if (wwi->wFlags != DCB_NULL &&
1818 !DriverCallback(wwi->waveDesc.dwCallback, wwi->wFlags,
1819 (HDRVR)wwi->waveDesc.hWave, wMsg, wwi->waveDesc.dwInstance,
1820 dwParam1, dwParam2))
1822 WARN("can't notify client !\n");
1823 return MMSYSERR_ERROR;
1825 break;
1826 default:
1827 FIXME("Unknown callback message %u\n", wMsg);
1828 return MMSYSERR_INVALPARAM;
1830 return MMSYSERR_NOERROR;
1833 /******************************************************************
1834 * JACK_callback_wwi
1836 /* everytime the jack server wants something from us it calls this
1837 function */
1838 int JACK_callback_wwi (nframes_t nframes, void *arg)
1840 sample_t* in_l;
1841 sample_t* in_r = 0;
1842 WINE_WAVEIN* wwi = (WINE_WAVEIN*)arg;
1844 TRACE("wDevID: %u, nframes %u\n", wwi->wDevID, nframes);
1846 if(!wwi->client)
1847 ERR("client is closed, this is weird...\n");
1849 in_l = (sample_t *) fp_jack_port_get_buffer(wwi->in_port_l, nframes);
1851 if (wwi->in_port_r)
1852 in_r = (sample_t *) fp_jack_port_get_buffer(wwi->in_port_r, nframes);
1854 EnterCriticalSection(&wwi->access_crst);
1856 if((wwi->lpQueuePtr != NULL) && (wwi->state == WINE_WS_PLAYING))
1858 LPWAVEHDR lpWaveHdr = wwi->lpQueuePtr;
1859 nframes_t jackFramesLeft = nframes;
1861 #if JACK_CLOSE_HACK
1862 if(wwi->in_use == FALSE)
1864 /* do nothing if nothing is being recorded */
1865 return 0;
1867 #endif
1869 TRACE("wwi.state == WINE_WS_PLAYING\n");
1871 while (lpWaveHdr && jackFramesLeft)
1873 DWORD waveHdrFramesLeft = (lpWaveHdr->dwBufferLength - lpWaveHdr->dwBytesRecorded) / (sizeof(short) * wwi->format.wf.nChannels);
1874 DWORD numFrames = min (jackFramesLeft, waveHdrFramesLeft);
1876 TRACE ("dwBufferLength=(%lu) dwBytesRecorded=(%ld)\n", lpWaveHdr->dwBufferLength, lpWaveHdr->dwBytesRecorded);
1877 TRACE ("jackFramesLeft=(%u) waveHdrFramesLeft=(%lu)\n", jackFramesLeft, waveHdrFramesLeft);
1879 if (!in_r) {
1880 /* mono */
1881 sample_move_s16_d16((short *)((char *)lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded), in_l+(nframes-jackFramesLeft), numFrames, 1);
1882 } else {
1883 /* stereo */
1884 sample_move_s16_d16((short *)((char *)lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded),
1885 in_l+(nframes-jackFramesLeft), numFrames, 2);
1886 sample_move_s16_d16((short *)((char *)lpWaveHdr->lpData + lpWaveHdr->dwBytesRecorded + sizeof(short)),
1887 in_r+(nframes-jackFramesLeft), numFrames, 2);
1890 lpWaveHdr->dwBytesRecorded += (numFrames * sizeof(short) * wwi->format.wf.nChannels );
1891 jackFramesLeft -= numFrames;
1893 if (lpWaveHdr->dwBytesRecorded >= lpWaveHdr->dwBufferLength)
1895 /* must copy the value of next waveHdr, because we have no idea of what
1896 * will be done with the content of lpWaveHdr in callback
1898 LPWAVEHDR lpNext = lpWaveHdr->lpNext;
1900 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
1901 lpWaveHdr->dwFlags |= WHDR_DONE;
1903 TRACE("WaveHdr full. dwBytesRecorded=(%lu) dwFlags=(0x%lx)\n",lpWaveHdr->dwBytesRecorded,lpWaveHdr->dwFlags);
1905 widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0);
1907 lpWaveHdr = wwi->lpQueuePtr = lpNext;
1910 TRACE ("jackFramesLeft=(%u) lpWaveHdr=(%p)\n", jackFramesLeft, lpWaveHdr);
1911 if (jackFramesLeft > 0) { WARN("Record buffer ran out of WaveHdrs\n"); }
1914 LeaveCriticalSection(&wwi->access_crst);
1916 return 0;
1919 /******************************************************************
1920 * JACK_OpenWaveInDevice
1922 static int JACK_OpenWaveInDevice(WINE_WAVEIN* wwi, WORD nChannels)
1924 const char** ports;
1925 int i;
1926 char client_name[64];
1927 jack_port_t* in_port_l;
1928 jack_port_t* in_port_r = 0;
1929 jack_client_t* client;
1930 int failed = 0;
1932 TRACE("creating jack client and setting up callbacks\n");
1934 if ((nChannels == 0) || (nChannels > 2)) {
1935 ERR ("nChannels = (%d), but we only support mono or stereo.\n", nChannels);
1936 return 0;
1939 #if JACK_CLOSE_HACK
1940 /* see if this device is already open */
1941 if(wwi->client)
1943 /* if this device is already in use then it is bad for us to be in here */
1944 if(wwi->in_use)
1945 return 0;
1947 TRACE("using existing client\n");
1948 wwi->in_use = TRUE;
1949 return 1;
1951 #endif
1953 /* zero out the buffer pointer and the size of the buffer */
1954 wwi->sound_buffer = 0;
1955 wwi->buffer_size = 0;
1957 /* try to become a client of the JACK server */
1958 snprintf(client_name, sizeof(client_name), "wine_jack_in_%d", wwi->wDevID);
1959 TRACE("client name '%s'\n", client_name);
1960 if ((client = fp_jack_client_new (client_name)) == 0)
1962 /* jack has problems with shutting down clients, so lets */
1963 /* wait a short while and try once more before we give up */
1964 Sleep(250);
1965 if ((client = fp_jack_client_new (client_name)) == 0)
1967 ERR("jack server not running?\n");
1968 return 0;
1971 wwi->client = client;
1973 /* tell the JACK server to call `JACK_wwi_callback()' whenever
1974 there is work to be done. */
1975 fp_jack_set_process_callback (client, JACK_callback_wwi, wwi);
1977 /* tell the JACK server to call `JACK_bufsize_wwi()' whenever
1978 the maximum number of frames that will be passed
1979 to `JACK_Callback()' changes */
1980 fp_jack_set_buffer_size_callback (client, JACK_bufsize_wwi, wwi);
1982 /* tell the JACK server to call `srate()' whenever
1983 the sample rate of the system changes. */
1984 fp_jack_set_sample_rate_callback (client, JACK_srate, wwi);
1986 /* tell the JACK server to call `jack_shutdown()' if
1987 it ever shuts down, either entirely, or if it
1988 just decides to stop calling us. */
1989 fp_jack_on_shutdown (client, JACK_shutdown_wwi, wwi);
1991 /* display the current sample rate. once the client is activated
1992 (see below), you should rely on your own sample rate
1993 callback (see above) for this value. */
1994 wwi->sample_rate = fp_jack_get_sample_rate(client);
1995 TRACE("engine sample rate: %lu\n", wwi->sample_rate);
1997 /* create the left and right channel output ports */
1998 /* jack's ports are all mono so for stereo you need two */
1999 in_port_l = fp_jack_port_register (client, "in_l",
2000 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
2001 wwi->in_port_l = in_port_l;
2002 TRACE("Created port. (%p)\n", in_port_l);
2004 if (nChannels == 2)
2006 in_port_r = fp_jack_port_register (client, "in_r",
2007 JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
2008 TRACE("Created port. (%p)\n", in_port_r);
2010 wwi->in_port_r = in_port_r;
2012 #if JACK_CLOSE_HACK
2013 wwi->in_use = TRUE; /* mark this device as in use since it now is ;-) */
2014 #endif
2016 TRACE("activating client.\n");
2017 /* tell the JACK server that we are ready to roll */
2018 if (fp_jack_activate (client))
2020 ERR( "cannot activate client\n");
2021 return 0;
2023 TRACE("activated client.\n");
2024 /* figure out what the ports that we want to output on are */
2025 /* NOTE: we do this instead of using stuff like "alsa_pcm:playback_X" because */
2026 /* this way works if names are changed */
2027 ports = fp_jack_get_ports(client, NULL, NULL, JackPortIsPhysical|JackPortIsOutput);
2029 /* display a trace of the output ports we found */
2030 for(i = 0; ports[i]; i++)
2032 TRACE("ports[%d] = '%s'\n", i, ports[i]);
2035 if(!ports)
2037 ERR("jack_get_ports() failed to find 'JackPortIsPhysical|JackPortIsOutput'\n");
2040 /* connect the ports. Note: you can't do this before
2041 the client is activated (this may change in the future).
2043 /* we want to connect to two ports so we have stereo input ;-) */
2045 if(fp_jack_connect(client, ports[0], fp_jack_port_name(in_port_l)))
2047 ERR ("cannot connect to input port %d('%s')\n", 0, ports[0]);
2048 failed = 1;
2050 TRACE("Connected (%s)<->(%s)\n",ports[0],fp_jack_port_name(in_port_l));
2052 if ((nChannels == 2) && in_port_r) {
2053 if(fp_jack_connect(client, ports[1], fp_jack_port_name(in_port_r)))
2055 ERR ("cannot connect to input port %d('%s')\n", 1, ports[1]);
2056 failed = 1;
2058 TRACE("Connected (%s)<->(%s)\n",ports[1],fp_jack_port_name(in_port_r));
2060 free(ports); /* free the returned array of ports */
2062 /* if something failed we need to shut the client down and return 0 */
2063 if(failed)
2065 #if JACK_CLOSE_HACK
2066 JACK_CloseWaveInDevice(wwi, TRUE);
2067 #else
2068 JACK_CloseWaveInDevice(wwi);
2069 #endif
2070 return 0;
2073 TRACE("return success.\n");
2074 return 1; /* return success */
2077 /**************************************************************************
2078 * widGetDevCaps [internal]
2080 static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPSW lpCaps, DWORD dwSize)
2082 TRACE("(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
2084 if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
2086 if (wDevID >= MAX_WAVEINDRV) {
2087 TRACE("MAX_WAVEINDRV reached !\n");
2088 return MMSYSERR_BADDEVICEID;
2091 memcpy(lpCaps, &WInDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));
2092 return MMSYSERR_NOERROR;
2095 /**************************************************************************
2096 * widOpen [internal]
2098 static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
2100 WINE_WAVEIN* wwi;
2101 DWORD retval;
2103 TRACE("(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
2104 if (lpDesc == NULL)
2106 WARN("Invalid Parameter !\n");
2107 return MMSYSERR_INVALPARAM;
2109 if (wDevID >= MAX_WAVEINDRV) {
2110 TRACE ("MAX_WAVEINDRV reached !\n");
2111 return MMSYSERR_BADDEVICEID;
2114 #if JACK_CLOSE_HACK
2115 if(WInDev[wDevID].client && WOutDev[wDevID].in_use)
2116 #else
2117 if(WInDev[wDevID].client)
2118 #endif
2120 TRACE("device %d already allocated\n", wDevID);
2121 return MMSYSERR_ALLOCATED;
2124 /* Only the PCM format is supported so far...
2125 * Also we only support 16 bit mode.
2127 if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM ||
2128 lpDesc->lpFormat->nChannels == 0 ||
2129 lpDesc->lpFormat->nSamplesPerSec == 0 ||
2130 lpDesc->lpFormat->wBitsPerSample!=16)
2132 WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%ld wBitsPerSample=%d !\n",
2133 lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
2134 lpDesc->lpFormat->nSamplesPerSec, lpDesc->lpFormat->wBitsPerSample);
2135 return WAVERR_BADFORMAT;
2138 if (dwFlags & WAVE_FORMAT_QUERY)
2140 TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%ld !\n",
2141 lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
2142 lpDesc->lpFormat->nSamplesPerSec);
2143 return MMSYSERR_NOERROR;
2146 wwi = &WInDev[wDevID];
2147 wwi->wDevID = wDevID;
2149 /* Set things up before we call JACK_OpenWaveOutDevice because */
2150 /* we will start getting callbacks before JACK_OpenWaveOutDevice */
2151 /* even returns and we want to be initialized before then */
2152 wwi->state = WINE_WS_STOPPED; /* start in a stopped state */
2154 InitializeCriticalSection(&wwi->access_crst); /* initialize the critical section */
2155 EnterCriticalSection(&wwi->access_crst);
2157 /* open up jack ports for this device */
2158 if (!JACK_OpenWaveInDevice(&WInDev[wDevID], lpDesc->lpFormat->nChannels))
2160 ERR("JACK_OpenWaveInDevice(%d) failed\n", wDevID);
2161 LeaveCriticalSection(&wwi->access_crst);
2162 DeleteCriticalSection(&wwi->access_crst);
2163 return MMSYSERR_ERROR; /* return unspecified error */
2166 dwFlags &= ~WAVE_DIRECTSOUND; /* direct sound not supported, ignore the flag */
2168 wwi->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
2170 memcpy(&wwi->waveDesc, lpDesc, sizeof(WAVEOPENDESC));
2171 memcpy(&wwi->format, lpDesc->lpFormat, sizeof(PCMWAVEFORMAT));
2173 LeaveCriticalSection(&wwi->access_crst);
2175 /* display the current wave format */
2176 TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%lu, nSamplesPerSec=%lu, nChannels=%u nBlockAlign=%u!\n",
2177 wwi->format.wBitsPerSample, wwi->format.wf.nAvgBytesPerSec,
2178 wwi->format.wf.nSamplesPerSec, wwi->format.wf.nChannels,
2179 wwi->format.wf.nBlockAlign);
2181 /* make sure that we have the same sample rate in our audio stream */
2182 /* as we do in the jack server */
2183 if(wwi->format.wf.nSamplesPerSec != wwi->sample_rate)
2185 TRACE("error: jack server sample rate is '%ld', wave sample rate is '%ld'\n",
2186 wwi->sample_rate, wwi->format.wf.nSamplesPerSec);
2188 #if JACK_CLOSE_HACK
2189 JACK_CloseWaveInDevice(wwi, FALSE); /* close this device, don't force the client to close */
2190 #else
2191 JACK_CloseWaveInDevice(wwi); /* close this device */
2192 #endif
2193 DeleteCriticalSection(&wwi->access_crst);
2194 return WAVERR_BADFORMAT;
2197 /* check for an invalid number of bits per sample */
2198 if (wwi->format.wBitsPerSample == 0)
2200 WARN("Resetting zeroed wBitsPerSample\n");
2201 wwi->format.wBitsPerSample = 8 *
2202 (wwi->format.wf.nAvgBytesPerSec /
2203 wwi->format.wf.nSamplesPerSec) /
2204 wwi->format.wf.nChannels;
2207 TRACE("notify client.\n");
2208 EnterCriticalSection(&wwi->access_crst);
2209 retval = widNotifyClient(wwi, WIM_OPEN, 0L, 0L);
2210 LeaveCriticalSection(&wwi->access_crst);
2212 return retval;
2214 /**************************************************************************
2215 * widClose [internal]
2217 static DWORD widClose(WORD wDevID)
2219 DWORD ret = MMSYSERR_NOERROR;
2220 WINE_WAVEIN* wwi;
2222 TRACE("(%u);\n", wDevID);
2224 if (wDevID >= MAX_WAVEINDRV || !WInDev[wDevID].client)
2226 WARN("bad device ID !\n");
2227 return MMSYSERR_BADDEVICEID;
2230 wwi = &WInDev[wDevID];
2231 if (wwi->lpQueuePtr)
2233 WARN("buffers still playing !\n");
2234 ret = WAVERR_STILLPLAYING;
2235 } else
2237 /* sanity check: this should not happen since the device must have been reset before */
2238 if (wwi->lpQueuePtr) ERR("out of sync\n");
2240 wwi->state = WINE_WS_CLOSED; /* mark the device as closed */
2242 #if JACK_CLOSE_HACK
2243 JACK_CloseWaveInDevice(wwi, FALSE); /* close the jack device, DO NOT force the client to close */
2244 #else
2245 JACK_CloseWaveInDevice(wwi); /* close the jack device */
2246 #endif
2247 DeleteCriticalSection(&wwi->access_crst); /* delete the critical section so we can initialize it again from wodOpen() */
2249 ret = widNotifyClient(wwi, WIM_CLOSE, 0L, 0L);
2252 return ret;
2255 /**************************************************************************
2256 * widAddBuffer [internal]
2258 static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
2260 WINE_WAVEIN* wwi = &WInDev[wDevID];
2262 TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
2264 if (wDevID >= MAX_WAVEINDRV || WInDev[wDevID].state == WINE_WS_CLOSED) {
2265 WARN("can't do it !\n");
2266 return MMSYSERR_INVALHANDLE;
2268 if (!(lpWaveHdr->dwFlags & WHDR_PREPARED)) {
2269 TRACE("never been prepared !\n");
2270 return WAVERR_UNPREPARED;
2272 if (lpWaveHdr->dwFlags & WHDR_INQUEUE) {
2273 TRACE("header already in use !\n");
2274 return WAVERR_STILLPLAYING;
2277 lpWaveHdr->dwFlags |= WHDR_INQUEUE;
2278 lpWaveHdr->dwFlags &= ~WHDR_DONE;
2279 lpWaveHdr->dwBytesRecorded = 0;
2280 lpWaveHdr->lpNext = NULL;
2282 EnterCriticalSection(&wwi->access_crst);
2283 /* insert buffer at end of queue */
2285 LPWAVEHDR* wh;
2286 for (wh = &(wwi->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
2287 *wh=lpWaveHdr;
2289 LeaveCriticalSection(&wwi->access_crst);
2291 return MMSYSERR_NOERROR;
2294 /**************************************************************************
2295 * widPrepare [internal]
2297 static DWORD widPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
2299 TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
2301 if (wDevID >= MAX_WAVEINDRV) return MMSYSERR_INVALHANDLE;
2303 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
2304 return WAVERR_STILLPLAYING;
2306 lpWaveHdr->dwFlags |= WHDR_PREPARED;
2307 lpWaveHdr->dwFlags &= ~WHDR_DONE;
2308 lpWaveHdr->dwBytesRecorded = 0;
2309 lpWaveHdr->lpNext = NULL;
2311 return MMSYSERR_NOERROR;
2314 /**************************************************************************
2315 * widUnprepare [internal]
2317 static DWORD widUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
2319 TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
2320 if (wDevID >= MAX_WAVEINDRV) {
2321 WARN("bad device ID !\n");
2322 return MMSYSERR_INVALHANDLE;
2325 if (lpWaveHdr->dwFlags & WHDR_INQUEUE) {
2326 TRACE("Still playing...\n");
2327 return WAVERR_STILLPLAYING;
2330 lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
2331 lpWaveHdr->dwFlags |= WHDR_DONE;
2333 return MMSYSERR_NOERROR;
2336 /**************************************************************************
2337 * widStart [internal]
2339 static DWORD widStart(WORD wDevID)
2341 TRACE("(%u);\n", wDevID);
2342 if (wDevID >= MAX_WAVEINDRV || WInDev[wDevID].state == WINE_WS_CLOSED) {
2343 WARN("can't start recording !\n");
2344 return MMSYSERR_INVALHANDLE;
2347 WInDev[wDevID].state = WINE_WS_PLAYING;
2348 return MMSYSERR_NOERROR;
2351 /**************************************************************************
2352 * widStop [internal]
2354 static DWORD widStop(WORD wDevID)
2356 WINE_WAVEIN* wwi = &WInDev[wDevID];
2358 TRACE("(%u);\n", wDevID);
2359 if (wDevID >= MAX_WAVEINDRV || WInDev[wDevID].state == WINE_WS_CLOSED) {
2360 WARN("can't stop !\n");
2361 return MMSYSERR_INVALHANDLE;
2364 if (wwi->state != WINE_WS_STOPPED)
2366 WAVEHDR* lpWaveHdr;
2367 /* do something here to stop recording ??? */
2369 /* return current buffer to app */
2370 lpWaveHdr = wwi->lpQueuePtr;
2371 if (lpWaveHdr)
2373 LPWAVEHDR lpNext = lpWaveHdr->lpNext;
2374 TRACE("stop %p %p\n", lpWaveHdr, lpWaveHdr->lpNext);
2375 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
2376 lpWaveHdr->dwFlags |= WHDR_DONE;
2377 widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0);
2378 wwi->lpQueuePtr = lpNext;
2381 wwi->state = WINE_WS_STOPPED;
2383 return MMSYSERR_NOERROR;
2386 /**************************************************************************
2387 * widReset [internal]
2389 static DWORD widReset(WORD wDevID)
2391 WINE_WAVEIN* wwi = &WInDev[wDevID];
2392 WAVEHDR* lpWaveHdr;
2394 TRACE("(%u);\n", wDevID);
2395 if (wDevID >= MAX_WAVEINDRV || WInDev[wDevID].state == WINE_WS_CLOSED) {
2396 WARN("can't reset !\n");
2397 return MMSYSERR_INVALHANDLE;
2400 wwi->state = WINE_WS_STOPPED;
2402 /* return all buffers to the app */
2403 for (lpWaveHdr = wwi->lpQueuePtr; lpWaveHdr; lpWaveHdr = lpWaveHdr->lpNext) {
2404 TRACE("reset %p %p\n", lpWaveHdr, lpWaveHdr->lpNext);
2405 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
2406 lpWaveHdr->dwFlags |= WHDR_DONE;
2408 widNotifyClient(wwi, WIM_DATA, (DWORD)lpWaveHdr, 0);
2410 wwi->lpQueuePtr = NULL;
2412 return MMSYSERR_NOERROR;
2415 /**************************************************************************
2416 * widGetNumDevs [internal]
2418 static DWORD widGetNumDevs(void)
2420 return MAX_WAVEINDRV;
2423 /**************************************************************************
2424 * widDevInterfaceSize [internal]
2426 static DWORD widDevInterfaceSize(UINT wDevID, LPDWORD dwParam1)
2428 TRACE("(%u, %p)\n", wDevID, dwParam1);
2431 *dwParam1 = MultiByteToWideChar(CP_ACP, 0, WInDev[wDevID].interface_name, -1,
2432 NULL, 0 ) * sizeof(WCHAR);
2433 return MMSYSERR_NOERROR;
2436 /**************************************************************************
2437 * widDevInterface [internal]
2439 static DWORD widDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2)
2441 if (dwParam2 >= MultiByteToWideChar(CP_ACP, 0, WInDev[wDevID].interface_name, -1,
2442 NULL, 0 ) * sizeof(WCHAR))
2444 MultiByteToWideChar(CP_ACP, 0, WInDev[wDevID].interface_name, -1,
2445 dwParam1, dwParam2 / sizeof(WCHAR));
2446 return MMSYSERR_NOERROR;
2448 return MMSYSERR_INVALPARAM;
2451 /**************************************************************************
2452 * widMessage (WINEJACK.6)
2454 DWORD WINAPI JACK_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
2455 DWORD dwParam1, DWORD dwParam2)
2457 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
2458 wDevID, wMsg, dwUser, dwParam1, dwParam2);
2460 switch (wMsg) {
2461 case DRVM_INIT:
2462 case DRVM_EXIT:
2463 case DRVM_ENABLE:
2464 case DRVM_DISABLE:
2465 /* FIXME: Pretend this is supported */
2466 return 0;
2467 case WIDM_OPEN: return widOpen (wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
2468 case WIDM_CLOSE: return widClose (wDevID);
2469 case WIDM_ADDBUFFER: return widAddBuffer (wDevID, (LPWAVEHDR)dwParam1, dwParam2);
2470 case WIDM_PREPARE: return widPrepare (wDevID, (LPWAVEHDR)dwParam1, dwParam2);
2471 case WIDM_UNPREPARE: return widUnprepare (wDevID, (LPWAVEHDR)dwParam1, dwParam2);
2472 case WIDM_GETDEVCAPS: return widGetDevCaps (wDevID, (LPWAVEINCAPSW)dwParam1, dwParam2);
2473 case WIDM_GETNUMDEVS: return widGetNumDevs();
2474 case WIDM_RESET: return widReset (wDevID);
2475 case WIDM_START: return widStart (wDevID);
2476 case WIDM_STOP: return widStop (wDevID);
2477 case DRV_QUERYDEVICEINTERFACESIZE: return widDevInterfaceSize (wDevID, (LPDWORD)dwParam1);
2478 case DRV_QUERYDEVICEINTERFACE: return widDevInterface (wDevID, (PWCHAR)dwParam1, dwParam2);
2479 default:
2480 FIXME("unknown message %d!\n", wMsg);
2483 return MMSYSERR_NOTSUPPORTED;
2486 #else /* !HAVE_JACK_JACK_H */
2488 /**************************************************************************
2489 * widMessage (WINEJACK.6)
2491 DWORD WINAPI JACK_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
2492 DWORD dwParam1, DWORD dwParam2)
2494 FIXME("(%u, %04X, %08lX, %08lX, %08lX):jack support not compiled into wine\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
2495 return MMSYSERR_NOTENABLED;
2498 /**************************************************************************
2499 * wodMessage (WINEJACK.7)
2501 DWORD WINAPI JACK_wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
2502 DWORD dwParam1, DWORD dwParam2)
2504 FIXME("(%u, %04X, %08lX, %08lX, %08lX):jack support not compiled into wine\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
2505 return MMSYSERR_NOTENABLED;
2508 #endif /* HAVE_JACK_JACK_H */