Add support for Jack audio server.
[wine/multimedia.git] / dlls / winmm / winejack / audio.c
blob0d1c5bd5787769dfd10dba5de0d56033019a4794
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2 /*
3 * Wine Driver for jack Sound Server
4 * http://jackit.sourceforge.net
6 * Copyright 1994 Martin Ayotte
7 * Copyright 1999 Eric Pouech (async playing in waveOut/waveIn)
8 * Copyright 2000 Eric Pouech (loops in waveOut)
9 * Copyright 2002 Chris Morgan (jack version of this file)
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 * TODO:
28 * implement audio stream resampling for any arbitrary frequenty
29 * right now we use the winmm layer to do resampling although it would
30 * be nice to have a full set of algorithms to choose from based on cpu
31 * time
32 * implement wave-in support with jack
34 * FIXME:
35 * pause in waveOut during loop is not handled correctly
38 #include "config.h"
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include "windef.h"
47 #include "wingdi.h"
48 #include "winerror.h"
49 #include "wine/winuser16.h"
50 #include "mmddk.h"
51 #include "dsound.h"
52 #include "dsdriver.h"
53 #include "jack.h"
54 #include "wine/debug.h"
56 #ifdef HAVE_JACK_JACK_H
57 #include <jack/jack.h>
58 #endif
61 WINE_DEFAULT_DEBUG_CHANNEL(wave);
63 #ifdef HAVE_JACK_JACK_H
65 #define MAKE_FUNCPTR(f) static typeof(f) * fp_##f = NULL;
67 /* Function pointers for dynamic loading of libjack */
68 /* these are prefixed with "fp_", ie. "fp_jack_client_new" */
69 MAKE_FUNCPTR(jack_activate);
70 MAKE_FUNCPTR(jack_connect);
71 MAKE_FUNCPTR(jack_client_new);
72 MAKE_FUNCPTR(jack_client_close);
73 MAKE_FUNCPTR(jack_deactivate);
74 MAKE_FUNCPTR(jack_set_process_callback);
75 MAKE_FUNCPTR(jack_set_buffer_size_callback);
76 MAKE_FUNCPTR(jack_set_sample_rate_callback);
77 MAKE_FUNCPTR(jack_on_shutdown);
78 MAKE_FUNCPTR(jack_get_sample_rate);
79 MAKE_FUNCPTR(jack_port_register);
80 MAKE_FUNCPTR(jack_port_get_buffer);
81 MAKE_FUNCPTR(jack_get_ports);
82 MAKE_FUNCPTR(jack_port_name);
83 #undef MAKE_FUNCPTR
85 /* define the below to work around a bug in jack where closing a port */
86 /* takes a very long time, so to get around this we actually don't */
87 /* close the port when the device is closed but instead mark the */
88 /* corresponding device as unused */
89 #define JACK_CLOSE_HACK 1
91 typedef jack_default_audio_sample_t sample_t;
92 typedef jack_nframes_t nframes_t;
94 /* only allow 10 output devices through this driver, this ought to be adequate */
95 #define MAX_WAVEOUTDRV (10)
96 #define MAX_WAVEINDRV (1)
98 /* state diagram for waveOut writing:
100 * +---------+-------------+---------------+---------------------------------+
101 * | state | function | event | new state |
102 * +---------+-------------+---------------+---------------------------------+
103 * | | open() | | STOPPED |
104 * | PAUSED | write() | | PAUSED |
105 * | STOPPED | write() | <thrd create> | PLAYING |
106 * | PLAYING | write() | HEADER | PLAYING |
107 * | (other) | write() | <error> | |
108 * | (any) | pause() | PAUSING | PAUSED |
109 * | PAUSED | restart() | RESTARTING | PLAYING (if no thrd => STOPPED) |
110 * | (any) | reset() | RESETTING | STOPPED |
111 * | (any) | close() | CLOSING | CLOSED |
112 * +---------+-------------+---------------+---------------------------------+
115 /* states of the playing device */
116 #define WINE_WS_PLAYING 0
117 #define WINE_WS_PAUSED 1
118 #define WINE_WS_STOPPED 2
119 #define WINE_WS_CLOSED 3
121 typedef struct {
122 volatile int state; /* one of the WINE_WS_ manifest constants */
123 WAVEOPENDESC waveDesc;
124 WORD wFlags;
125 PCMWAVEFORMAT format;
126 WAVEOUTCAPSA caps;
127 WORD wDevID;
129 jack_port_t* out_port_l; /* ports for left and right channels */
130 jack_port_t* out_port_r;
131 jack_client_t* client;
132 long sample_rate; /* jack server sample rate */
134 #if JACK_CLOSE_HACK
135 BOOL in_use; /* TRUE if this device is in use */
136 #endif
138 char* sound_buffer;
139 unsigned long buffer_size;
141 DWORD volume_left;
142 DWORD volume_right;
144 LPWAVEHDR lpQueuePtr; /* start of queued WAVEHDRs (waiting to be notified) */
145 LPWAVEHDR lpPlayPtr; /* start of not yet fully played buffers */
146 DWORD dwPartialOffset; /* Offset of not yet written bytes in lpPlayPtr */
148 LPWAVEHDR lpLoopPtr; /* pointer of first buffer in loop, if any */
149 DWORD dwLoops; /* private copy of loop counter */
151 DWORD dwPlayedTotal; /* number of bytes actually played since opening */
152 DWORD dwWrittenTotal; /* number of bytes written to jack since opening */
154 DWORD bytesInJack; /* bytes that we wrote during the previous JACK_Callback() */
155 DWORD tickCountMS; /* time in MS of last JACK_Callback() */
157 /* synchronization stuff */
158 CRITICAL_SECTION access_crst;
159 } WINE_WAVEOUT;
161 typedef struct {
162 volatile int state;
163 WAVEOPENDESC waveDesc;
164 WORD wFlags;
165 PCMWAVEFORMAT format;
166 LPWAVEHDR lpQueuePtr;
167 DWORD dwTotalRecorded;
168 WAVEINCAPSA caps;
169 BOOL bTriggerSupport;
171 /* synchronization stuff */
172 CRITICAL_SECTION access_crst;
173 } WINE_WAVEIN;
175 static WINE_WAVEOUT WOutDev [MAX_WAVEOUTDRV];
176 static WINE_WAVEIN WInDev [MAX_WAVEINDRV ];
178 static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);
179 static LPWAVEHDR wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo);
180 static DWORD wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force);
182 static int JACK_OpenDevice(WINE_WAVEOUT* wwo);
184 #if JACK_CLOSE_HACK
185 static void JACK_CloseDevice(WINE_WAVEOUT* wwo, BOOL close_client);
186 #else
187 static void JACK_CloseDevice(WINE_WAVEOUT* wwo);
188 #endif
191 /*======================================================================*
192 * Low level WAVE implementation *
193 *======================================================================*/
195 #define SAMPLE_MAX_16BIT 32767.0f
197 /* Alsaplayer function that applies volume changes to a buffer */
198 /* (C) Andy Lo A Foe */
199 /* Length is in terms of 32 bit samples */
200 void volume_effect32(void *buffer, int length, int left, int right)
202 short *data = (short *)buffer;
203 int i, v;
205 if (right == -1) right = left;
207 for(i = 0; i < length; i++) {
208 v = (int) ((*(data) * left) / 100);
209 *(data++) = (v>32767) ? 32767 : ((v<-32768) ? -32768 : v);
210 v = (int) ((*(data) * right) / 100);
211 *(data++) = (v>32767) ? 32767 : ((v<-32768) ? -32768 : v);
215 /* move 16 bit mono/stereo to 16 bit stereo */
216 void sample_move_d16_d16(short *dst, short *src,
217 unsigned long nsamples, int nChannels)
219 while(nsamples--)
221 *dst = *src;
222 dst++;
224 if(nChannels == 2) src++;
226 *dst = *src;
227 dst++;
229 src++;
233 /* convert from 16 bit to floating point */
234 /* allow for copying of stereo data with alternating left/right */
235 /* channels to a buffer that will hold a single channel stream */
236 /* nsamples is in terms of 16bit samples */
237 /* src_skip is in terms of 16bit samples */
238 void sample_move_d16_s16 (sample_t *dst, short *src,
239 unsigned long nsamples, unsigned long src_skip)
241 /* ALERT: signed sign-extension portability !!! */
242 while (nsamples--)
244 *dst = (*src) / SAMPLE_MAX_16BIT;
245 dst++;
246 src += src_skip;
250 /* fill dst buffer with nsamples worth of silence */
251 void sample_silence_dS (sample_t *dst, unsigned long nsamples)
253 /* ALERT: signed sign-extension portability !!! */
254 while (nsamples--)
256 *dst = 0;
257 dst++;
261 /******************************************************************
262 * JACK_callback
264 /* everytime the jack server wants something from us it calls this
265 function, so we either deliver it some sound to play or deliver it nothing
266 to play */
267 int JACK_callback (nframes_t nframes, void *arg)
269 sample_t* out_l;
270 sample_t* out_r;
271 WINE_WAVEOUT* wwo = (WINE_WAVEOUT*)arg;
273 TRACE("wDevID: %d, nframes %ld\n", wwo->wDevID, nframes);
275 if(!wwo->client)
276 ERR("client is closed, this is weird...\n");
278 out_l = (sample_t *) fp_jack_port_get_buffer(wwo->out_port_l,
279 nframes);
280 out_r = (sample_t *) fp_jack_port_get_buffer(wwo->out_port_r,
281 nframes);
283 EnterCriticalSection(&wwo->access_crst);
285 if(wwo->state == WINE_WS_PLAYING)
287 DWORD jackBytesAvailableThisCallback = sizeof(sample_t) * nframes;
288 DWORD jackBytesLeft = sizeof(sample_t) * nframes;
290 DWORD inputBytesAvailable; /* number of bytes we have from the app, after conversion to 16bit stereo */
291 DWORD jackBytesToWrite; /* number of bytes we are going to write out, after conversion */
293 DWORD bytesInput; /* the number of bytes from the app */
294 DWORD appBytesToWrite; /* number of bytes from the app we are going to write */
296 long written = 0;
297 char* buffer;
299 #if JACK_CLOSE_HACK
300 if(wwo->in_use == FALSE)
302 /* output silence if nothing is being outputted */
303 sample_silence_dS(out_l, nframes);
304 sample_silence_dS(out_r, nframes);
306 return 0;
308 #endif
310 TRACE("wwo.state == WINE_WS_PLAYING\n");
312 /* see if our buffer is large enough for the data we are writing */
313 /* ie. Buffer_size < (bytes we already wrote + bytes we are going to write in this loop) */
314 if(wwo->buffer_size < jackBytesAvailableThisCallback)
316 ERR("for some reason JACK_BufSize() didn't allocate enough memory\n");
317 ERR("allocated %ld bytes, need %ld bytes\n", wwo->buffer_size,
318 jackBytesAvailableThisCallback);
319 LeaveCriticalSection(&wwo->access_crst);
320 return 0;
323 /* while we have jackBytesLeft and a wave header to be played */
324 while(jackBytesLeft && wwo->lpPlayPtr)
326 /* find the amount of audio to be played at this time */
327 bytesInput = wwo->lpPlayPtr->dwBufferLength - wwo->dwPartialOffset;
328 inputBytesAvailable = bytesInput;
330 /* calculate inputBytesAvailable based on audio format conversion */
331 if(wwo->format.wf.nChannels == 1)
332 inputBytesAvailable<<=1; /* multiply by two for mono->stereo conversion */
334 /* find the minimum of the inputBytesAvailable and the space available */
335 jackBytesToWrite = min(jackBytesLeft, inputBytesAvailable);
337 /* calculate appBytesToWrite based on audio format conversion */
338 appBytesToWrite = jackBytesToWrite;
339 if(wwo->format.wf.nChannels == 1)
340 appBytesToWrite>>=1; /* divide by two for stereo->mono conversion */
342 TRACE("jackBytesToWrite == %ld, appBytesToWrite == %ld\n", jackBytesToWrite, appBytesToWrite);
344 buffer = wwo->lpPlayPtr->lpData + wwo->dwPartialOffset;
346 /* convert from mono to stereo if necessary */
347 /* otherwise just memcpy to the output buffer */
348 if(wwo->format.wf.nChannels == 1)
350 sample_move_d16_d16((short*)wwo->sound_buffer +((jackBytesAvailableThisCallback - jackBytesLeft) / sizeof(short)),
351 (short*)buffer, jackBytesToWrite, wwo->format.wf.nChannels);
352 } else /* just copy the memory over */
354 memcpy(wwo->sound_buffer + (jackBytesAvailableThisCallback - jackBytesLeft),
355 buffer, jackBytesToWrite);
358 /* advance to the next wave header if possible, or advance pointer */
359 /* inside of the current header if we haven't completed it */
360 if(appBytesToWrite == bytesInput)
362 wodHelper_PlayPtrNext(wwo); /* we wrote the whole waveheader, skip to the next one*/
364 else
366 wwo->dwPartialOffset+=appBytesToWrite; /* else advance by the bytes we took in to write */
369 written+=appBytesToWrite; /* add on what we wrote */
370 jackBytesLeft-=jackBytesToWrite; /* take away what was written in terms of output bytes */
373 wwo->tickCountMS = GetTickCount(); /* record the current time */
374 wwo->dwWrittenTotal+=written; /* update states on wave device */
375 wwo->dwPlayedTotal+=wwo->bytesInJack; /* we must have finished with the last bytes or we wouldn't be back inside of this callback again... */
376 wwo->bytesInJack = written; /* record the bytes inside of jack */
378 /* Now that we have finished filling the buffer either until it is full or until */
379 /* we have run out of application sound data to process, apply volume and output */
380 /* the audio to the jack server */
382 /* apply volume to the buffer */
383 /* NOTE: buffer_size >> 2 to convert from bytes to 16 bit stereo(32bit) samples */
384 volume_effect32(wwo->sound_buffer, (jackBytesAvailableThisCallback - jackBytesLeft)>>2, wwo->volume_left,
385 wwo->volume_right);
387 /* convert from stereo 16 bit to single channel 32 bit float */
388 /* for each jack server channel */
389 /* NOTE: we skip over two sample since we want to only get either the left or right channel */
390 sample_move_d16_s16(out_l, (short*)wwo->sound_buffer, (jackBytesAvailableThisCallback - jackBytesLeft)>>2, 2);
391 sample_move_d16_s16(out_r, (short*)wwo->sound_buffer + 1,
392 (jackBytesAvailableThisCallback - jackBytesLeft)>>2, 2);
394 /* see if we still have jackBytesLeft here, if we do that means that we
395 ran out of wave data to play and had a buffer underrun, fill in
396 the rest of the space with zero bytes */
397 if(jackBytesLeft)
399 ERR("buffer underrun of %ld bytes\n", jackBytesLeft);
400 sample_silence_dS(out_l + ((jackBytesAvailableThisCallback - jackBytesLeft) / sizeof(sample_t)), jackBytesLeft / sizeof(sample_t));
401 sample_silence_dS(out_r + ((jackBytesAvailableThisCallback - jackBytesLeft) / sizeof(sample_t)), jackBytesLeft / sizeof(sample_t));
404 else if(wwo->state == WINE_WS_PAUSED ||
405 wwo->state == WINE_WS_STOPPED ||
406 wwo->state == WINE_WS_CLOSED)
408 /* output silence if nothing is being outputted */
409 sample_silence_dS(out_l, nframes);
410 sample_silence_dS(out_r, nframes);
413 /* notify the client of completed wave headers */
414 wodHelper_NotifyCompletions(wwo, FALSE);
416 LeaveCriticalSection(&wwo->access_crst);
418 TRACE("ending\n");
420 return 0;
423 /******************************************************************
424 * JACK_bufsize
426 * Called whenever the jack server changes the the max number
427 * of frames passed to JACK_callback
429 int JACK_bufsize (nframes_t nframes, void *arg)
431 WINE_WAVEOUT* wwo = (WINE_WAVEOUT*)arg;
432 DWORD buffer_required;
433 TRACE("the maximum buffer size is now %lu frames\n", nframes);
435 /* make sure the callback routine has adequate memory */
436 /* see if our buffer is large enough for the data we are writing */
437 /* ie. Buffer_size < (bytes we already wrote + bytes we are going to write in this loop) */
438 EnterCriticalSection(&wwo->access_crst);
440 buffer_required = sizeof(sample_t) * nframes;
441 if(wwo->buffer_size < buffer_required)
443 TRACE("expanding buffer from wwo->buffer_size == %ld, to %ld\n",
444 wwo->buffer_size, buffer_required);
445 TRACE("GetProcessHeap() == %p\n", GetProcessHeap());
446 wwo->buffer_size = buffer_required;
447 wwo->sound_buffer = HeapReAlloc(GetProcessHeap(), 0, wwo->sound_buffer, wwo->buffer_size);
449 /* if we don't have a buffer then error out */
450 if(!wwo->sound_buffer)
452 ERR("error allocating sound_buffer memory\n");
453 LeaveCriticalSection(&wwo->access_crst);
454 return 0;
458 LeaveCriticalSection(&wwo->access_crst);
460 TRACE("called\n");
462 return 0;
465 /******************************************************************
466 * JACK_srate
468 int JACK_srate (nframes_t nframes, void *arg)
470 TRACE("the sample rate is now %lu/sec\n", nframes);
471 return 0;
475 /******************************************************************
476 * JACK_shutdown
478 /* if this is called then jack shut down... handle this appropriately */
479 void JACK_shutdown(void* arg)
481 WINE_WAVEOUT* wwo = (WINE_WAVEOUT*)arg;
483 wwo->client = 0; /* reset client */
485 TRACE("trying to reconnect after sleeping for a short while...\n");
487 /* lets see if we can't reestablish the connection */
488 Sleep(750); /* pause for a short period of time */
489 if(!JACK_OpenDevice(wwo))
491 ERR("unable to reconnect with jack...\n");
496 /******************************************************************
497 * JACK_OpenDevice
499 static int JACK_OpenDevice(WINE_WAVEOUT* wwo)
501 const char** ports;
502 int i;
503 char client_name[64];
504 jack_port_t* out_port_l;
505 jack_port_t* out_port_r;
506 jack_client_t* client;
507 int failed = 0;
509 TRACE("creating jack client and setting up callbacks\n");
511 #if JACK_CLOSE_HACK
512 /* see if this device is already open */
513 if(wwo->client)
515 /* if this device is already in use then it is bad for us to be in here */
516 if(wwo->in_use)
517 return 0;
519 TRACE("using existing client\n");
520 wwo->in_use = TRUE;
521 return 1;
523 #endif
525 /* zero out the buffer pointer and the size of the buffer */
526 wwo->sound_buffer = 0;
527 wwo->buffer_size = 0;
529 /* try to become a client of the JACK server */
530 snprintf(client_name, sizeof(client_name), "wine_jack_client %d", wwo->wDevID);
531 TRACE("client name '%s'\n", client_name);
532 if ((client = fp_jack_client_new (client_name)) == 0)
534 /* jack has problems with shutting down clients, so lets */
535 /* wait a short while and try once more before we give up */
536 Sleep(250);
537 if ((client = fp_jack_client_new (client_name)) == 0)
539 ERR("jack server not running?\n");
540 return 0;
544 /* tell the JACK server to call `JACK_callback()' whenever
545 there is work to be done. */
546 fp_jack_set_process_callback (client, JACK_callback, wwo);
548 /* tell the JACK server to call `JACK_bufsize()' whenever
549 the maximum number of frames that will be passed
550 to `JACK_Callback()' changes */
551 fp_jack_set_buffer_size_callback (client, JACK_bufsize, wwo);
553 /* tell the JACK server to call `srate()' whenever
554 the sample rate of the system changes. */
555 fp_jack_set_sample_rate_callback (client, JACK_srate, wwo);
557 /* tell the JACK server to call `jack_shutdown()' if
558 it ever shuts down, either entirely, or if it
559 just decides to stop calling us. */
560 fp_jack_on_shutdown (client, JACK_shutdown, wwo);
562 /* display the current sample rate. once the client is activated
563 (see below), you should rely on your own sample rate
564 callback (see above) for this value. */
565 wwo->sample_rate = fp_jack_get_sample_rate(client);
566 TRACE("engine sample rate: %lu\n", wwo->sample_rate);
568 /* create the left and right channel output ports */
569 /* jack's ports are all mono so for stereo you need two */
570 out_port_l = fp_jack_port_register (client, "out_l",
571 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
573 out_port_r = fp_jack_port_register (client, "out_r",
574 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
576 /* save away important values to the WINE_WAVEOUT struct */
577 wwo->client = client;
578 wwo->out_port_l = out_port_l;
579 wwo->out_port_r = out_port_r;
581 #if JACK_CLOSE_HACK
582 wwo->in_use = TRUE; /* mark this device as in use since it now is ;-) */
583 #endif
585 /* tell the JACK server that we are ready to roll */
586 if (fp_jack_activate (client))
588 ERR( "cannot activate client\n");
589 return 0;
592 /* figure out what the ports that we want to output on are */
593 /* NOTE: we do this instead of using stuff like "alsa_pcm:playback_X" because */
594 /* this way works if names are changed */
595 ports = fp_jack_get_ports(client, NULL, NULL, JackPortIsPhysical|JackPortIsInput);
597 /* display a trace of the output ports we found */
598 for(i = 0; ports[i]; i++)
600 TRACE("ports[%d] = '%s'\n", i, ports[i]);
603 if(!ports)
605 ERR("jack_get_ports() failed to find 'JackPortIsPhysical|JackPortIsInput'\n");
608 /* connect the ports. Note: you can't do this before
609 the client is activated (this may change in the future).
611 /* we want to connect to two ports so we have stereo output ;-) */
613 if(fp_jack_connect(client, fp_jack_port_name(out_port_l), ports[0]))
615 ERR ("cannot connect to output port %d('%s')\n", 0, ports[0]);
616 failed = 1;
619 if(fp_jack_connect(client, fp_jack_port_name(out_port_r), ports[1]))
621 ERR ("cannot connect to output port %d('%s')\n", 1, ports[1]);
622 failed = 1;
625 free(ports); /* free the returned array of ports */
627 /* if something failed we need to shut the client down and return 0 */
628 if(failed)
630 JACK_CloseDevice(wwo, TRUE);
631 return 0;
634 return 1; /* return success */
637 /******************************************************************
638 * JACK_CloseDevice
640 * Close the connection to the server cleanly.
641 * If close_client is TRUE we close the client for this device instead of
642 * just marking the device as in_use(JACK_CLOSE_HACK only)
644 #if JACK_CLOSE_HACK
645 static void JACK_CloseDevice(WINE_WAVEOUT* wwo, BOOL close_client)
646 #else
647 static void JACK_CloseDevice(WINE_WAVEOUT* wwo)
648 #endif
650 #if JACK_CLOSE_HACK
651 TRACE("wDevID: %d, close_client: %d\n", wwo->wDevID, close_client);
652 #else
653 TRACE("wDevID: %d\n", wwo->wDevID);
654 #endif
656 #if JACK_CLOSE_HACK
657 if(close_client)
659 #endif
660 fp_jack_deactivate(wwo->client); /* supposed to help the jack_client_close() to succeed */
661 fp_jack_client_close (wwo->client);
663 EnterCriticalSection(&wwo->access_crst);
664 wwo->client = 0; /* reset client */
665 HeapFree(GetProcessHeap(), 0, wwo->sound_buffer); /* free buffer memory */
666 wwo->sound_buffer = 0;
667 wwo->buffer_size = 0; /* zero out size of the buffer */
668 LeaveCriticalSection(&wwo->access_crst);
669 #if JACK_CLOSE_HACK
670 } else
672 EnterCriticalSection(&wwo->access_crst);
673 TRACE("setting in_use to FALSE\n");
674 wwo->in_use = FALSE;
675 LeaveCriticalSection(&wwo->access_crst);
677 #endif
680 /******************************************************************
681 * JACK_WaveRelease
685 LONG JACK_WaveRelease(void)
687 int iDevice;
689 TRACE("closing all open devices\n");
691 /* close all open devices */
692 for(iDevice = 0; iDevice < MAX_WAVEOUTDRV; iDevice++)
694 TRACE("iDevice == %d\n", iDevice);
695 if(WOutDev[iDevice].client)
697 #if JACK_CLOSE_HACK
698 JACK_CloseDevice(&WOutDev[iDevice], TRUE); /* close the device, FORCE the client to close */
699 #else
700 JACK_CloseDevice(&WOutDev[iDevice]); /* close the device, FORCE the client to close */
701 #endif
702 DeleteCriticalSection(&(WOutDev[iDevice].access_crst)); /* delete the critical section */
706 TRACE("returning 1\n");
708 return 1;
711 /******************************************************************
712 * JACK_WaveInit
714 * Initialize internal structures from JACK server info
716 LONG JACK_WaveInit(void)
718 int i;
720 TRACE("called\n");
722 /* setup function pointers */
723 #define LOAD_FUNCPTR(f) if((fp_##f = wine_dlsym(jackhandle, #f, NULL, 0)) == NULL) goto sym_not_found;
724 LOAD_FUNCPTR(jack_activate);
725 LOAD_FUNCPTR(jack_connect);
726 LOAD_FUNCPTR(jack_client_new);
727 LOAD_FUNCPTR(jack_client_close);
728 LOAD_FUNCPTR(jack_deactivate);
729 LOAD_FUNCPTR(jack_set_process_callback);
730 LOAD_FUNCPTR(jack_set_buffer_size_callback);
731 LOAD_FUNCPTR(jack_set_sample_rate_callback);
732 LOAD_FUNCPTR(jack_on_shutdown);
733 LOAD_FUNCPTR(jack_get_sample_rate);
734 LOAD_FUNCPTR(jack_port_register);
735 LOAD_FUNCPTR(jack_port_get_buffer);
736 LOAD_FUNCPTR(jack_get_ports);
737 LOAD_FUNCPTR(jack_port_name);
738 #undef LOAD_FUNCPTR
740 /* start with output device */
742 for (i = 0; i < MAX_WAVEOUTDRV; ++i)
744 WOutDev[i].client = 0; /* initialize the client to 0 */
746 #if JACK_CLOSE_HACK
747 WOutDev[i].in_use = FALSE;
748 #endif
750 memset(&WOutDev[i].caps, 0, sizeof(WOutDev[i].caps));
752 /* FIXME: some programs compare this string against the content of the registry
753 * for MM drivers. The names have to match in order for the program to work
754 * (e.g. MS win9x mplayer.exe)
756 #ifdef EMULATE_SB16
757 WOutDev[i].caps.wMid = 0x0002;
758 WOutDev[i].caps.wPid = 0x0104;
759 strcpy(WOutDev[i].caps.szPname, "SB16 Wave Out");
760 #else
761 WOutDev[i].caps.wMid = 0x00FF; /* Manufac ID */
762 WOutDev[i].caps.wPid = 0x0001; /* Product ID */
763 /* strcpy(WOutDev[i].caps.szPname, "OpenSoundSystem WAVOUT Driver");*/
764 strcpy(WOutDev[i].caps.szPname, "CS4236/37/38");
765 #endif
766 WOutDev[i].caps.vDriverVersion = 0x0100;
767 WOutDev[i].caps.dwFormats = 0x00000000;
768 WOutDev[i].caps.dwSupport = WAVECAPS_VOLUME;
770 WOutDev[i].caps.wChannels = 2;
771 WOutDev[i].caps.dwSupport |= WAVECAPS_LRVOLUME;
773 /* NOTE: we don't support any 8 bit modes so note that */
774 /* WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;
775 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S08; */
776 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S16;
777 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M16;
778 /* WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;
779 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S08; */
780 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M16;
781 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S16;
782 /* WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;
783 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;*/
784 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M16;
785 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S16;
788 /* then do input device */
789 for (i = 0; i < MAX_WAVEINDRV; ++i)
791 /* TODO: we should initialize read stuff here */
792 memset(&WInDev[0].caps, 0, sizeof(WInDev[0].caps));
795 return 1; /* return success */
797 /* error path for function pointer loading errors */
798 sym_not_found:
799 WINE_MESSAGE(
800 "Wine cannot find certain functions that it needs inside the jack"
801 "library. To enable Wine to use the jack audio server please "
802 "install libjack\n");
803 wine_dlclose(jackhandle, NULL, 0);
804 jackhandle = NULL;
805 return FALSE;
808 /*======================================================================*
809 * Low level WAVE OUT implementation *
810 *======================================================================*/
812 /**************************************************************************
813 * wodNotifyClient [internal]
815 static DWORD wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
817 TRACE("wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX\n", wMsg, dwParam1, dwParam2);
819 switch (wMsg) {
820 case WOM_OPEN:
821 case WOM_CLOSE:
822 case WOM_DONE:
823 if (wwo->wFlags != DCB_NULL &&
824 !DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags,
825 (HDRVR)wwo->waveDesc.hWave, wMsg, wwo->waveDesc.dwInstance,
826 dwParam1, dwParam2))
828 WARN("can't notify client !\n");
829 return MMSYSERR_ERROR;
831 break;
832 default:
833 FIXME("Unknown callback message %u\n", wMsg);
834 return MMSYSERR_INVALPARAM;
836 return MMSYSERR_NOERROR;
839 /**************************************************************************
840 * wodHelper_BeginWaveHdr [internal]
842 * Makes the specified lpWaveHdr the currently playing wave header.
843 * If the specified wave header is a begin loop and we're not already in
844 * a loop, setup the loop.
846 static void wodHelper_BeginWaveHdr(WINE_WAVEOUT* wwo, LPWAVEHDR lpWaveHdr)
848 EnterCriticalSection(&wwo->access_crst);
850 wwo->lpPlayPtr = lpWaveHdr;
852 if (!lpWaveHdr)
854 LeaveCriticalSection(&wwo->access_crst);
855 return;
858 if (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)
860 if (wwo->lpLoopPtr)
862 WARN("Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);
863 TRACE("Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);
864 } else
866 TRACE("Starting loop (%ldx) with %p\n", lpWaveHdr->dwLoops, lpWaveHdr);
867 wwo->lpLoopPtr = lpWaveHdr;
868 /* Windows does not touch WAVEHDR.dwLoops,
869 * so we need to make an internal copy */
870 wwo->dwLoops = lpWaveHdr->dwLoops;
873 wwo->dwPartialOffset = 0;
875 LeaveCriticalSection(&wwo->access_crst);
879 /**************************************************************************
880 * wodHelper_PlayPtrNext [internal]
882 * Advance the play pointer to the next waveheader, looping if required.
884 static LPWAVEHDR wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo)
886 LPWAVEHDR lpWaveHdr;
888 EnterCriticalSection(&wwo->access_crst);
890 lpWaveHdr = wwo->lpPlayPtr;
892 wwo->dwPartialOffset = 0;
893 if ((lpWaveHdr->dwFlags & WHDR_ENDLOOP) && wwo->lpLoopPtr)
895 /* We're at the end of a loop, loop if required */
896 if (--wwo->dwLoops > 0)
898 wwo->lpPlayPtr = wwo->lpLoopPtr;
899 } else
901 /* Handle overlapping loops correctly */
902 if (wwo->lpLoopPtr != lpWaveHdr && (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)) {
903 FIXME("Correctly handled case ? (ending loop buffer also starts a new loop)\n");
904 /* shall we consider the END flag for the closing loop or for
905 * the opening one or for both ???
906 * code assumes for closing loop only
908 } else
910 lpWaveHdr = lpWaveHdr->lpNext;
912 wwo->lpLoopPtr = NULL;
913 wodHelper_BeginWaveHdr(wwo, lpWaveHdr);
915 } else
917 /* We're not in a loop. Advance to the next wave header */
918 TRACE("not inside of a loop, advancing to next wave header\n");
919 wodHelper_BeginWaveHdr(wwo, lpWaveHdr = lpWaveHdr->lpNext);
922 LeaveCriticalSection(&wwo->access_crst);
924 return lpWaveHdr;
927 /* if force is TRUE then notify the client that all the headers were completed */
928 static DWORD wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force)
930 LPWAVEHDR lpWaveHdr;
931 DWORD retval;
933 TRACE("called\n");
935 EnterCriticalSection(&wwo->access_crst);
937 /* Start from lpQueuePtr and keep notifying until:
938 * - we hit an unwritten wavehdr
939 * - we hit the beginning of a running loop
940 * - we hit a wavehdr which hasn't finished playing
942 while ((lpWaveHdr = wwo->lpQueuePtr) &&
943 (force ||
944 (lpWaveHdr != wwo->lpPlayPtr &&
945 lpWaveHdr != wwo->lpLoopPtr)))
947 wwo->lpQueuePtr = lpWaveHdr->lpNext;
949 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
950 lpWaveHdr->dwFlags |= WHDR_DONE;
951 TRACE("calling notify client\n");
953 wodNotifyClient(wwo, WOM_DONE, (DWORD)lpWaveHdr, 0);
956 retval = (lpWaveHdr && lpWaveHdr != wwo->lpPlayPtr && lpWaveHdr !=
957 wwo->lpLoopPtr) ? 0 : INFINITE;
959 LeaveCriticalSection(&wwo->access_crst);
961 return retval;
964 /**************************************************************************
965 * wodHelper_Reset [internal]
967 * Resets current output stream.
969 static void wodHelper_Reset(WINE_WAVEOUT* wwo, BOOL reset)
971 EnterCriticalSection(&wwo->access_crst);
973 /* updates current notify list */
974 wodHelper_NotifyCompletions(wwo, FALSE);
976 if (reset)
978 /* remove all wave headers and notify client that all headers were completed */
979 wodHelper_NotifyCompletions(wwo, TRUE);
981 wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL;
982 wwo->state = WINE_WS_STOPPED;
983 wwo->dwPlayedTotal = wwo->dwWrittenTotal = wwo->bytesInJack = 0;
985 wwo->dwPartialOffset = 0; /* Clear partial wavehdr */
986 } else
988 if (wwo->lpLoopPtr)
990 /* complicated case, not handled yet (could imply modifying the loop counter) */
991 FIXME("Pausing while in loop isn't correctly handled yet, except strange results\n");
992 wwo->lpPlayPtr = wwo->lpLoopPtr;
993 wwo->dwPartialOffset = 0;
994 wwo->dwWrittenTotal = wwo->dwPlayedTotal; /* this is wrong !!! */
995 } else
997 LPWAVEHDR ptr;
998 DWORD sz = wwo->dwPartialOffset;
1000 /* reset all the data as if we had written only up to lpPlayedTotal bytes */
1001 /* compute the max size playable from lpQueuePtr */
1002 for (ptr = wwo->lpQueuePtr; ptr != wwo->lpPlayPtr; ptr = ptr->lpNext)
1004 sz += ptr->dwBufferLength;
1007 /* because the reset lpPlayPtr will be lpQueuePtr */
1008 if (wwo->dwWrittenTotal > wwo->dwPlayedTotal + sz) ERR("doh\n");
1009 wwo->dwPartialOffset = sz - (wwo->dwWrittenTotal - wwo->dwPlayedTotal);
1010 wwo->dwWrittenTotal = wwo->dwPlayedTotal;
1011 wwo->lpPlayPtr = wwo->lpQueuePtr;
1014 wwo->state = WINE_WS_PAUSED;
1017 LeaveCriticalSection(&wwo->access_crst);
1020 /**************************************************************************
1021 * wodGetDevCaps [internal]
1023 static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSA lpCaps, DWORD dwSize)
1025 TRACE("(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
1027 if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
1029 if (wDevID >= MAX_WAVEOUTDRV)
1031 TRACE("MAX_WAVOUTDRV reached !\n");
1032 return MMSYSERR_BADDEVICEID;
1035 memcpy(lpCaps, &WOutDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));
1036 return MMSYSERR_NOERROR;
1039 /**************************************************************************
1040 * wodOpen [internal]
1042 static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
1044 WINE_WAVEOUT* wwo;
1045 DWORD retval;
1047 TRACE("(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
1048 if (lpDesc == NULL)
1050 WARN("Invalid Parameter !\n");
1051 return MMSYSERR_INVALPARAM;
1053 if (wDevID >= MAX_WAVEOUTDRV) {
1054 TRACE("MAX_WAVOUTDRV reached !\n");
1055 return MMSYSERR_BADDEVICEID;
1058 #if JACK_CLOSE_HACK
1059 if(WOutDev[wDevID].client && WOutDev[wDevID].in_use)
1060 #else
1061 if(WOutDev[wDevID].client)
1062 #endif
1064 TRACE("device %d already allocated\n", wDevID);
1065 return MMSYSERR_ALLOCATED;
1068 /* make sure we aren't being opened in 8 bit mode */
1069 if(lpDesc->lpFormat->wBitsPerSample == 8)
1071 TRACE("8bits per sample unsupported, returning WAVERR_BADFORMAT\n");
1072 return WAVERR_BADFORMAT;
1075 wwo = &WOutDev[wDevID];
1076 wwo->wDevID = wDevID;
1078 /* Set things up before we call JACK_OpenDevice because */
1079 /* we will start getting callbacks before JACK_OpenDevice */
1080 /* even returns and we want to be initialized before then */
1081 wwo->state = WINE_WS_STOPPED; /* start in a stopped state */
1082 wwo->dwPlayedTotal = 0; /* zero out these totals */
1083 wwo->dwWrittenTotal = 0;
1084 wwo->bytesInJack = 0;
1085 wwo->tickCountMS = 0;
1087 InitializeCriticalSection(&wwo->access_crst); /* initialize the critical section */
1089 /* open up jack ports for this device */
1090 if (!JACK_OpenDevice(&WOutDev[wDevID]))
1092 ERR("JACK_OpenDevice(%d) failed\n", wDevID);
1093 return MMSYSERR_ERROR; /* return unspecified error */
1096 /* only PCM format is supported so far... */
1097 if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM ||
1098 lpDesc->lpFormat->nChannels == 0 ||
1099 lpDesc->lpFormat->nSamplesPerSec == 0)
1101 WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%ld !\n",
1102 lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
1103 lpDesc->lpFormat->nSamplesPerSec);
1104 return WAVERR_BADFORMAT;
1107 if (dwFlags & WAVE_FORMAT_QUERY)
1109 TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%ld !\n",
1110 lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
1111 lpDesc->lpFormat->nSamplesPerSec);
1112 return MMSYSERR_NOERROR;
1115 dwFlags &= ~WAVE_DIRECTSOUND; /* direct sound not supported, ignore the flag */
1117 EnterCriticalSection(&wwo->access_crst);
1119 wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
1121 memcpy(&wwo->waveDesc, lpDesc, sizeof(WAVEOPENDESC));
1122 memcpy(&wwo->format, lpDesc->lpFormat, sizeof(PCMWAVEFORMAT));
1124 LeaveCriticalSection(&wwo->access_crst);
1126 /* display the current wave format */
1127 TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%lu, nSamplesPerSec=%lu, nChannels=%u nBlockAlign=%u!\n",
1128 wwo->format.wBitsPerSample, wwo->format.wf.nAvgBytesPerSec,
1129 wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels,
1130 wwo->format.wf.nBlockAlign);
1132 /* make sure that we have the same sample rate in our audio stream */
1133 /* as we do in the jack server */
1134 if(wwo->format.wf.nSamplesPerSec != wwo->sample_rate)
1136 TRACE("error: jack server sample rate is '%ld', wave sample rate is '%ld'\n",
1137 wwo->sample_rate, wwo->format.wf.nSamplesPerSec);
1139 #if JACK_CLOSE_HACK
1140 JACK_CloseDevice(wwo, FALSE); /* close this device, don't force the client to close */
1141 #else
1142 JACK_CloseDevice(wwo); /* close this device */
1143 #endif
1144 return WAVERR_BADFORMAT;
1147 /* check for an invalid number of bits per sample */
1148 if (wwo->format.wBitsPerSample == 0)
1150 WARN("Resetting zeroed wBitsPerSample to 16\n");
1151 wwo->format.wBitsPerSample = 16 *
1152 (wwo->format.wf.nAvgBytesPerSec /
1153 wwo->format.wf.nSamplesPerSec) /
1154 wwo->format.wf.nChannels;
1157 EnterCriticalSection(&wwo->access_crst);
1158 retval = wodNotifyClient(wwo, WOM_OPEN, 0L, 0L);
1159 LeaveCriticalSection(&wwo->access_crst);
1161 return retval;
1164 /**************************************************************************
1165 * wodClose [internal]
1167 static DWORD wodClose(WORD wDevID)
1169 DWORD ret = MMSYSERR_NOERROR;
1170 WINE_WAVEOUT* wwo;
1172 TRACE("(%u);\n", wDevID);
1174 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1176 WARN("bad device ID !\n");
1177 return MMSYSERR_BADDEVICEID;
1180 wwo = &WOutDev[wDevID];
1181 if (wwo->lpQueuePtr)
1183 WARN("buffers still playing !\n");
1184 ret = WAVERR_STILLPLAYING;
1185 } else
1187 /* sanity check: this should not happen since the device must have been reset before */
1188 if (wwo->lpQueuePtr || wwo->lpPlayPtr) ERR("out of sync\n");
1190 wwo->state = WINE_WS_CLOSED; /* mark the device as closed */
1192 #if JACK_CLOSE_HACK
1193 JACK_CloseDevice(wwo, FALSE); /* close the jack device, DO NOT force the client to close */
1194 #else
1195 JACK_CloseDevice(wwo); /* close the jack device */
1196 DeleteCriticalSection(&wwo->access_crst); /* delete the critical section so we can initialize it again from wodOpen() */
1197 #endif
1199 ret = wodNotifyClient(wwo, WOM_CLOSE, 0L, 0L);
1202 return ret;
1205 /**************************************************************************
1206 * wodWrite [internal]
1209 static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1211 LPWAVEHDR*wh;
1212 WINE_WAVEOUT *wwo;
1214 TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1216 /* first, do the sanity checks... */
1217 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1219 WARN("bad dev ID !\n");
1220 return MMSYSERR_BADDEVICEID;
1223 wwo = &WOutDev[wDevID];
1225 if (lpWaveHdr->lpData == NULL || !(lpWaveHdr->dwFlags & WHDR_PREPARED))
1227 TRACE("unprepared\n");
1228 return WAVERR_UNPREPARED;
1231 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1233 TRACE("still playing\n");
1234 return WAVERR_STILLPLAYING;
1237 lpWaveHdr->dwFlags &= ~WHDR_DONE;
1238 lpWaveHdr->dwFlags |= WHDR_INQUEUE;
1239 lpWaveHdr->lpNext = 0;
1241 EnterCriticalSection(&wwo->access_crst);
1243 /* insert buffer at the end of queue */
1244 for (wh = &(wwo->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
1245 *wh = lpWaveHdr;
1247 LeaveCriticalSection(&wwo->access_crst);
1249 EnterCriticalSection(&wwo->access_crst);
1250 if (!wwo->lpPlayPtr)
1251 wodHelper_BeginWaveHdr(wwo,lpWaveHdr);
1252 if (wwo->state == WINE_WS_STOPPED)
1253 wwo->state = WINE_WS_PLAYING;
1254 LeaveCriticalSection(&wwo->access_crst);
1256 return MMSYSERR_NOERROR;
1259 /**************************************************************************
1260 * wodPrepare [internal]
1262 static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1264 TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1266 if (wDevID >= MAX_WAVEOUTDRV)
1268 WARN("bad device ID !\n");
1269 return MMSYSERR_BADDEVICEID;
1272 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1273 return WAVERR_STILLPLAYING;
1275 lpWaveHdr->dwFlags |= WHDR_PREPARED;
1276 lpWaveHdr->dwFlags &= ~WHDR_DONE;
1277 return MMSYSERR_NOERROR;
1280 /**************************************************************************
1281 * wodUnprepare [internal]
1283 static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1285 TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1287 if (wDevID >= MAX_WAVEOUTDRV)
1289 WARN("bad device ID !\n");
1290 return MMSYSERR_BADDEVICEID;
1293 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1294 return WAVERR_STILLPLAYING;
1296 lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
1297 lpWaveHdr->dwFlags |= WHDR_DONE;
1299 return MMSYSERR_NOERROR;
1302 /**************************************************************************
1303 * wodPause [internal]
1305 static DWORD wodPause(WORD wDevID)
1307 TRACE("(%u);!\n", wDevID);
1309 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1311 WARN("bad device ID !\n");
1312 return MMSYSERR_BADDEVICEID;
1315 TRACE("[3-PAUSING]\n");
1317 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1318 wodHelper_Reset(&WOutDev[wDevID], FALSE);
1319 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1321 return MMSYSERR_NOERROR;
1324 /**************************************************************************
1325 * wodRestart [internal]
1327 static DWORD wodRestart(WORD wDevID)
1329 TRACE("(%u);\n", wDevID);
1331 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1333 WARN("bad device ID !\n");
1334 return MMSYSERR_BADDEVICEID;
1337 if (WOutDev[wDevID].state == WINE_WS_PAUSED)
1339 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1340 WOutDev[wDevID].state = WINE_WS_PLAYING;
1341 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1344 return MMSYSERR_NOERROR;
1347 /**************************************************************************
1348 * wodReset [internal]
1350 static DWORD wodReset(WORD wDevID)
1352 TRACE("(%u);\n", wDevID);
1354 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1356 WARN("bad device ID !\n");
1357 return MMSYSERR_BADDEVICEID;
1360 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1361 wodHelper_Reset(&WOutDev[wDevID], TRUE);
1362 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1364 return MMSYSERR_NOERROR;
1367 /**************************************************************************
1368 * wodGetPosition [internal]
1370 static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
1372 int time;
1373 DWORD val;
1374 WINE_WAVEOUT* wwo;
1375 DWORD elapsedMS;
1377 TRACE("(%u, %p, %lu);\n", wDevID, lpTime, uSize);
1379 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1381 WARN("bad device ID !\n");
1382 return MMSYSERR_BADDEVICEID;
1385 /* if null pointer to time structure return error */
1386 if (lpTime == NULL) return MMSYSERR_INVALPARAM;
1388 wwo = &WOutDev[wDevID];
1390 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1391 val = wwo->dwPlayedTotal;
1392 elapsedMS = GetTickCount() - wwo->tickCountMS;
1393 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1395 /* account for the bytes played since the last JACK_Callback() */
1396 val+=((elapsedMS * wwo->format.wf.nAvgBytesPerSec) / 1000);
1398 TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",
1399 lpTime->wType, wwo->format.wBitsPerSample,
1400 wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels,
1401 wwo->format.wf.nAvgBytesPerSec);
1402 TRACE("dwPlayedTotal=%lu\n", val);
1404 switch (lpTime->wType) {
1405 case TIME_BYTES:
1406 lpTime->u.cb = val;
1407 TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
1408 break;
1409 case TIME_SAMPLES:
1410 lpTime->u.sample = val * 8 / wwo->format.wBitsPerSample /wwo->format.wf.nChannels;
1411 TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
1412 break;
1413 case TIME_SMPTE:
1414 time = val / (wwo->format.wf.nAvgBytesPerSec / 1000);
1415 lpTime->u.smpte.hour = time / 108000;
1416 time -= lpTime->u.smpte.hour * 108000;
1417 lpTime->u.smpte.min = time / 1800;
1418 time -= lpTime->u.smpte.min * 1800;
1419 lpTime->u.smpte.sec = time / 30;
1420 time -= lpTime->u.smpte.sec * 30;
1421 lpTime->u.smpte.frame = time;
1422 lpTime->u.smpte.fps = 30;
1423 TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1424 lpTime->u.smpte.hour, lpTime->u.smpte.min,
1425 lpTime->u.smpte.sec, lpTime->u.smpte.frame);
1426 break;
1427 default:
1428 FIXME("Format %d not supported ! use TIME_MS !\n", lpTime->wType);
1429 lpTime->wType = TIME_MS;
1430 case TIME_MS:
1431 lpTime->u.ms = val / (wwo->format.wf.nAvgBytesPerSec / 1000);
1432 TRACE("TIME_MS=%lu\n", lpTime->u.ms);
1433 break;
1435 return MMSYSERR_NOERROR;
1438 /**************************************************************************
1439 * wodBreakLoop [internal]
1441 static DWORD wodBreakLoop(WORD wDevID)
1443 TRACE("(%u);\n", wDevID);
1445 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1447 WARN("bad device ID !\n");
1448 return MMSYSERR_BADDEVICEID;
1451 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1453 if (WOutDev[wDevID].state == WINE_WS_PLAYING && WOutDev[wDevID].lpLoopPtr != NULL)
1455 /* ensure exit at end of current loop */
1456 WOutDev[wDevID].dwLoops = 1;
1459 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1461 return MMSYSERR_NOERROR;
1464 /**************************************************************************
1465 * wodGetVolume [internal]
1467 static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
1469 DWORD left, right;
1471 left = WOutDev[wDevID].volume_left;
1472 right = WOutDev[wDevID].volume_right;
1474 TRACE("(%u, %p);\n", wDevID, lpdwVol);
1476 *lpdwVol = ((left * 0xFFFFl) / 100) + (((right * 0xFFFFl) / 100) <<
1477 16);
1479 return MMSYSERR_NOERROR;
1482 /**************************************************************************
1483 * wodSetVolume [internal]
1485 static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
1487 DWORD left, right;
1489 left = (LOWORD(dwParam) * 100) / 0xFFFFl;
1490 right = (HIWORD(dwParam) * 100) / 0xFFFFl;
1492 TRACE("(%u, %08lX);\n", wDevID, dwParam);
1494 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1496 WOutDev[wDevID].volume_left = left;
1497 WOutDev[wDevID].volume_right = right;
1499 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1501 return MMSYSERR_NOERROR;
1504 /**************************************************************************
1505 * wodGetNumDevs [internal]
1507 static DWORD wodGetNumDevs(void)
1509 return MAX_WAVEOUTDRV;
1512 /**************************************************************************
1513 * wodMessage (WINEJACK.7)
1515 DWORD WINAPI JACK_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
1516 DWORD dwParam1, DWORD dwParam2)
1518 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1519 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1521 switch (wMsg) {
1522 case DRVM_INIT:
1523 TRACE("DRVM_INIT\n");
1524 return JACK_WaveInit();
1525 case DRVM_EXIT:
1526 TRACE("DRVM_EXIT\n");
1527 return JACK_WaveRelease();
1528 case DRVM_ENABLE:
1529 /* FIXME: Pretend this is supported */
1530 TRACE("DRVM_ENABLE\n");
1531 return 0;
1532 case DRVM_DISABLE:
1533 /* FIXME: Pretend this is supported */
1534 TRACE("DRVM_DISABLE\n");
1535 return 0;
1536 case WODM_OPEN: return wodOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
1537 case WODM_CLOSE: return wodClose(wDevID);
1538 case WODM_WRITE: return wodWrite(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1539 case WODM_PAUSE: return wodPause(wDevID);
1540 case WODM_GETPOS: return wodGetPosition(wDevID, (LPMMTIME)dwParam1, dwParam2);
1541 case WODM_BREAKLOOP: return wodBreakLoop(wDevID);
1542 case WODM_PREPARE: return wodPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1543 case WODM_UNPREPARE: return wodUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1544 case WODM_GETDEVCAPS: return wodGetDevCaps(wDevID, (LPWAVEOUTCAPSA)dwParam1, dwParam2);
1545 case WODM_GETNUMDEVS: return wodGetNumDevs();
1546 case WODM_GETPITCH: return MMSYSERR_NOTSUPPORTED;
1547 case WODM_SETPITCH: return MMSYSERR_NOTSUPPORTED;
1548 case WODM_GETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED;
1549 case WODM_SETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED;
1550 case WODM_GETVOLUME: return wodGetVolume(wDevID, (LPDWORD)dwParam1);
1551 case WODM_SETVOLUME: return wodSetVolume(wDevID, dwParam1);
1552 case WODM_RESTART: return wodRestart(wDevID);
1553 case WODM_RESET: return wodReset(wDevID);
1555 case DRV_QUERYDSOUNDIFACE: return wodDsCreate(wDevID, (PIDSDRIVER*)dwParam1);
1556 default:
1557 FIXME("unknown message %d!\n", wMsg);
1559 return MMSYSERR_NOTSUPPORTED;
1562 /*======================================================================*
1563 * Low level DSOUND implementation *
1564 *======================================================================*/
1566 typedef struct IDsDriverImpl IDsDriverImpl;
1567 typedef struct IDsDriverBufferImpl IDsDriverBufferImpl;
1569 struct IDsDriverImpl
1571 /* IUnknown fields */
1572 ICOM_VFIELD(IDsDriver);
1573 DWORD ref;
1574 /* IDsDriverImpl fields */
1575 UINT wDevID;
1576 IDsDriverBufferImpl*primary;
1579 struct IDsDriverBufferImpl
1581 /* IUnknown fields */
1582 ICOM_VFIELD(IDsDriverBuffer);
1583 DWORD ref;
1584 /* IDsDriverBufferImpl fields */
1585 IDsDriverImpl* drv;
1586 DWORD buflen;
1589 static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv)
1591 /* we can't perform memory mapping as we don't have a file stream
1592 interface with jack like we do with oss */
1593 MESSAGE("This sound card's driver does not support direct access\n");
1594 MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
1595 return MMSYSERR_NOTSUPPORTED;
1598 /*======================================================================*
1599 * Low level WAVE IN implementation *
1600 *======================================================================*/
1602 /**************************************************************************
1603 * widMessage (WINEJACK.6)
1605 DWORD WINAPI JACK_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1606 DWORD dwParam1, DWORD dwParam2)
1608 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1609 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1611 return MMSYSERR_NOTSUPPORTED;
1614 #else /* !HAVE_JACK_JACK_H */
1616 /**************************************************************************
1617 * wodMessage (WINEJACK.7)
1619 DWORD WINAPI JACK_wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1620 DWORD dwParam1, DWORD dwParam2)
1622 FIXME("(%u, %04X, %08lX, %08lX, %08lX):jack support not compiled into wine\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
1623 return MMSYSERR_NOTENABLED;
1626 #endif /* HAVE_JACK_JACK_H */