Fixed header dependencies to be fully compatible with the Windows
[wine/multimedia.git] / dlls / winmm / winejack / audio.c
blob9488f59eea340fd7a0d41b88e9c772015f809f69
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 <stdarg.h>
42 #include <stdio.h>
43 #include <string.h>
44 #ifdef HAVE_UNISTD_H
45 # include <unistd.h>
46 #endif
47 #include <fcntl.h>
48 #include "windef.h"
49 #include "winbase.h"
50 #include "wingdi.h"
51 #include "winerror.h"
52 #include "wine/winuser16.h"
53 #include "mmddk.h"
54 #include "dsound.h"
55 #include "dsdriver.h"
56 #include "jack.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 #undef MAKE_FUNCPTR
88 /* define the below to work around a bug in jack where closing a port */
89 /* takes a very long time, so to get around this we actually don't */
90 /* close the port when the device is closed but instead mark the */
91 /* corresponding device as unused */
92 #define JACK_CLOSE_HACK 1
94 typedef jack_default_audio_sample_t sample_t;
95 typedef jack_nframes_t nframes_t;
97 /* only allow 10 output devices through this driver, this ought to be adequate */
98 #define MAX_WAVEOUTDRV (10)
99 #define MAX_WAVEINDRV (1)
101 /* state diagram for waveOut writing:
103 * +---------+-------------+---------------+---------------------------------+
104 * | state | function | event | new state |
105 * +---------+-------------+---------------+---------------------------------+
106 * | | open() | | STOPPED |
107 * | PAUSED | write() | | PAUSED |
108 * | STOPPED | write() | <thrd create> | PLAYING |
109 * | PLAYING | write() | HEADER | PLAYING |
110 * | (other) | write() | <error> | |
111 * | (any) | pause() | PAUSING | PAUSED |
112 * | PAUSED | restart() | RESTARTING | PLAYING (if no thrd => STOPPED) |
113 * | (any) | reset() | RESETTING | STOPPED |
114 * | (any) | close() | CLOSING | CLOSED |
115 * +---------+-------------+---------------+---------------------------------+
118 /* states of the playing device */
119 #define WINE_WS_PLAYING 0
120 #define WINE_WS_PAUSED 1
121 #define WINE_WS_STOPPED 2
122 #define WINE_WS_CLOSED 3
124 typedef struct {
125 volatile int state; /* one of the WINE_WS_ manifest constants */
126 WAVEOPENDESC waveDesc;
127 WORD wFlags;
128 PCMWAVEFORMAT format;
129 WAVEOUTCAPSA caps;
130 WORD wDevID;
132 jack_port_t* out_port_l; /* ports for left and right channels */
133 jack_port_t* out_port_r;
134 jack_client_t* client;
135 long sample_rate; /* jack server sample rate */
137 #if JACK_CLOSE_HACK
138 BOOL in_use; /* TRUE if this device is in use */
139 #endif
141 char* sound_buffer;
142 unsigned long buffer_size;
144 DWORD volume_left;
145 DWORD volume_right;
147 LPWAVEHDR lpQueuePtr; /* start of queued WAVEHDRs (waiting to be notified) */
148 LPWAVEHDR lpPlayPtr; /* start of not yet fully played buffers */
149 DWORD dwPartialOffset; /* Offset of not yet written bytes in lpPlayPtr */
151 LPWAVEHDR lpLoopPtr; /* pointer of first buffer in loop, if any */
152 DWORD dwLoops; /* private copy of loop counter */
154 DWORD dwPlayedTotal; /* number of bytes actually played since opening */
155 DWORD dwWrittenTotal; /* number of bytes written to jack since opening */
157 DWORD bytesInJack; /* bytes that we wrote during the previous JACK_Callback() */
158 DWORD tickCountMS; /* time in MS of last JACK_Callback() */
160 /* synchronization stuff */
161 CRITICAL_SECTION access_crst;
162 } WINE_WAVEOUT;
164 typedef struct {
165 volatile int state;
166 WAVEOPENDESC waveDesc;
167 WORD wFlags;
168 PCMWAVEFORMAT format;
169 LPWAVEHDR lpQueuePtr;
170 DWORD dwTotalRecorded;
171 WAVEINCAPSA caps;
172 BOOL bTriggerSupport;
174 /* synchronization stuff */
175 CRITICAL_SECTION access_crst;
176 } WINE_WAVEIN;
178 static WINE_WAVEOUT WOutDev [MAX_WAVEOUTDRV];
179 static WINE_WAVEIN WInDev [MAX_WAVEINDRV ];
181 static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);
182 static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc);
183 static DWORD wodDsGuid(UINT wDevID, LPGUID pGuid);
185 static LPWAVEHDR wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo);
186 static DWORD wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force);
188 static int JACK_OpenDevice(WINE_WAVEOUT* wwo);
190 #if JACK_CLOSE_HACK
191 static void JACK_CloseDevice(WINE_WAVEOUT* wwo, BOOL close_client);
192 #else
193 static void JACK_CloseDevice(WINE_WAVEOUT* wwo);
194 #endif
197 /*======================================================================*
198 * Low level WAVE implementation *
199 *======================================================================*/
201 #define SAMPLE_MAX_16BIT 32767.0f
203 /* Alsaplayer function that applies volume changes to a buffer */
204 /* (C) Andy Lo A Foe */
205 /* Length is in terms of 32 bit samples */
206 void volume_effect32(void *buffer, int length, int left, int right)
208 short *data = (short *)buffer;
209 int i, v;
211 if (right == -1) right = left;
213 for(i = 0; i < length; i++) {
214 v = (int) ((*(data) * left) / 100);
215 *(data++) = (v>32767) ? 32767 : ((v<-32768) ? -32768 : v);
216 v = (int) ((*(data) * right) / 100);
217 *(data++) = (v>32767) ? 32767 : ((v<-32768) ? -32768 : v);
221 /* move 16 bit mono/stereo to 16 bit stereo */
222 void sample_move_d16_d16(short *dst, short *src,
223 unsigned long nsamples, int nChannels)
225 while(nsamples--)
227 *dst = *src;
228 dst++;
230 if(nChannels == 2) src++;
232 *dst = *src;
233 dst++;
235 src++;
239 /* convert from 16 bit to floating point */
240 /* allow for copying of stereo data with alternating left/right */
241 /* channels to a buffer that will hold a single channel stream */
242 /* nsamples is in terms of 16bit samples */
243 /* src_skip is in terms of 16bit samples */
244 void sample_move_d16_s16 (sample_t *dst, short *src,
245 unsigned long nsamples, unsigned long src_skip)
247 /* ALERT: signed sign-extension portability !!! */
248 while (nsamples--)
250 *dst = (*src) / SAMPLE_MAX_16BIT;
251 dst++;
252 src += src_skip;
256 /* fill dst buffer with nsamples worth of silence */
257 void sample_silence_dS (sample_t *dst, unsigned long nsamples)
259 /* ALERT: signed sign-extension portability !!! */
260 while (nsamples--)
262 *dst = 0;
263 dst++;
267 /******************************************************************
268 * JACK_callback
270 /* everytime the jack server wants something from us it calls this
271 function, so we either deliver it some sound to play or deliver it nothing
272 to play */
273 int JACK_callback (nframes_t nframes, void *arg)
275 sample_t* out_l;
276 sample_t* out_r;
277 WINE_WAVEOUT* wwo = (WINE_WAVEOUT*)arg;
279 TRACE("wDevID: %d, nframes %ld\n", wwo->wDevID, nframes);
281 if(!wwo->client)
282 ERR("client is closed, this is weird...\n");
284 out_l = (sample_t *) fp_jack_port_get_buffer(wwo->out_port_l,
285 nframes);
286 out_r = (sample_t *) fp_jack_port_get_buffer(wwo->out_port_r,
287 nframes);
289 EnterCriticalSection(&wwo->access_crst);
291 if(wwo->state == WINE_WS_PLAYING)
293 DWORD jackBytesAvailableThisCallback = sizeof(sample_t) * nframes;
294 DWORD jackBytesLeft = sizeof(sample_t) * nframes;
296 DWORD inputBytesAvailable; /* number of bytes we have from the app, after conversion to 16bit stereo */
297 DWORD jackBytesToWrite; /* number of bytes we are going to write out, after conversion */
299 DWORD bytesInput; /* the number of bytes from the app */
300 DWORD appBytesToWrite; /* number of bytes from the app we are going to write */
302 long written = 0;
303 char* buffer;
305 #if JACK_CLOSE_HACK
306 if(wwo->in_use == FALSE)
308 /* output silence if nothing is being outputted */
309 sample_silence_dS(out_l, nframes);
310 sample_silence_dS(out_r, nframes);
312 return 0;
314 #endif
316 TRACE("wwo.state == WINE_WS_PLAYING\n");
318 /* see if our buffer is large enough for the data we are writing */
319 /* ie. Buffer_size < (bytes we already wrote + bytes we are going to write in this loop) */
320 if(wwo->buffer_size < jackBytesAvailableThisCallback)
322 ERR("for some reason JACK_BufSize() didn't allocate enough memory\n");
323 ERR("allocated %ld bytes, need %ld bytes\n", wwo->buffer_size,
324 jackBytesAvailableThisCallback);
325 LeaveCriticalSection(&wwo->access_crst);
326 return 0;
329 /* while we have jackBytesLeft and a wave header to be played */
330 while(jackBytesLeft && wwo->lpPlayPtr)
332 /* find the amount of audio to be played at this time */
333 bytesInput = wwo->lpPlayPtr->dwBufferLength - wwo->dwPartialOffset;
334 inputBytesAvailable = bytesInput;
336 /* calculate inputBytesAvailable based on audio format conversion */
337 if(wwo->format.wf.nChannels == 1)
338 inputBytesAvailable<<=1; /* multiply by two for mono->stereo conversion */
340 /* find the minimum of the inputBytesAvailable and the space available */
341 jackBytesToWrite = min(jackBytesLeft, inputBytesAvailable);
343 /* calculate appBytesToWrite based on audio format conversion */
344 appBytesToWrite = jackBytesToWrite;
345 if(wwo->format.wf.nChannels == 1)
346 appBytesToWrite>>=1; /* divide by two for stereo->mono conversion */
348 TRACE("jackBytesToWrite == %ld, appBytesToWrite == %ld\n", jackBytesToWrite, appBytesToWrite);
350 buffer = wwo->lpPlayPtr->lpData + wwo->dwPartialOffset;
352 /* convert from mono to stereo if necessary */
353 /* otherwise just memcpy to the output buffer */
354 if(wwo->format.wf.nChannels == 1)
356 sample_move_d16_d16((short*)wwo->sound_buffer +((jackBytesAvailableThisCallback - jackBytesLeft) / sizeof(short)),
357 (short*)buffer, jackBytesToWrite, wwo->format.wf.nChannels);
358 } else /* just copy the memory over */
360 memcpy(wwo->sound_buffer + (jackBytesAvailableThisCallback - jackBytesLeft),
361 buffer, jackBytesToWrite);
364 /* advance to the next wave header if possible, or advance pointer */
365 /* inside of the current header if we haven't completed it */
366 if(appBytesToWrite == bytesInput)
368 wodHelper_PlayPtrNext(wwo); /* we wrote the whole waveheader, skip to the next one*/
370 else
372 wwo->dwPartialOffset+=appBytesToWrite; /* else advance by the bytes we took in to write */
375 written+=appBytesToWrite; /* add on what we wrote */
376 jackBytesLeft-=jackBytesToWrite; /* take away what was written in terms of output bytes */
379 wwo->tickCountMS = GetTickCount(); /* record the current time */
380 wwo->dwWrittenTotal+=written; /* update states on wave device */
381 wwo->dwPlayedTotal+=wwo->bytesInJack; /* we must have finished with the last bytes or we wouldn't be back inside of this callback again... */
382 wwo->bytesInJack = written; /* record the bytes inside of jack */
384 /* Now that we have finished filling the buffer either until it is full or until */
385 /* we have run out of application sound data to process, apply volume and output */
386 /* the audio to the jack server */
388 /* apply volume to the buffer */
389 /* NOTE: buffer_size >> 2 to convert from bytes to 16 bit stereo(32bit) samples */
390 volume_effect32(wwo->sound_buffer, (jackBytesAvailableThisCallback - jackBytesLeft)>>2, wwo->volume_left,
391 wwo->volume_right);
393 /* convert from stereo 16 bit to single channel 32 bit float */
394 /* for each jack server channel */
395 /* NOTE: we skip over two sample since we want to only get either the left or right channel */
396 sample_move_d16_s16(out_l, (short*)wwo->sound_buffer, (jackBytesAvailableThisCallback - jackBytesLeft)>>2, 2);
397 sample_move_d16_s16(out_r, (short*)wwo->sound_buffer + 1,
398 (jackBytesAvailableThisCallback - jackBytesLeft)>>2, 2);
400 /* see if we still have jackBytesLeft here, if we do that means that we
401 ran out of wave data to play and had a buffer underrun, fill in
402 the rest of the space with zero bytes */
403 if(jackBytesLeft)
405 ERR("buffer underrun of %ld bytes\n", jackBytesLeft);
406 sample_silence_dS(out_l + ((jackBytesAvailableThisCallback - jackBytesLeft) / sizeof(sample_t)), jackBytesLeft / sizeof(sample_t));
407 sample_silence_dS(out_r + ((jackBytesAvailableThisCallback - jackBytesLeft) / sizeof(sample_t)), jackBytesLeft / sizeof(sample_t));
410 else if(wwo->state == WINE_WS_PAUSED ||
411 wwo->state == WINE_WS_STOPPED ||
412 wwo->state == WINE_WS_CLOSED)
414 /* output silence if nothing is being outputted */
415 sample_silence_dS(out_l, nframes);
416 sample_silence_dS(out_r, nframes);
419 /* notify the client of completed wave headers */
420 wodHelper_NotifyCompletions(wwo, FALSE);
422 LeaveCriticalSection(&wwo->access_crst);
424 TRACE("ending\n");
426 return 0;
429 /******************************************************************
430 * JACK_bufsize
432 * Called whenever the jack server changes the the max number
433 * of frames passed to JACK_callback
435 int JACK_bufsize (nframes_t nframes, void *arg)
437 WINE_WAVEOUT* wwo = (WINE_WAVEOUT*)arg;
438 DWORD buffer_required;
439 TRACE("the maximum buffer size is now %lu frames\n", nframes);
441 /* make sure the callback routine has adequate memory */
442 /* see if our buffer is large enough for the data we are writing */
443 /* ie. Buffer_size < (bytes we already wrote + bytes we are going to write in this loop) */
444 EnterCriticalSection(&wwo->access_crst);
446 buffer_required = sizeof(sample_t) * nframes;
447 if(wwo->buffer_size < buffer_required)
449 TRACE("expanding buffer from wwo->buffer_size == %ld, to %ld\n",
450 wwo->buffer_size, buffer_required);
451 TRACE("GetProcessHeap() == %p\n", GetProcessHeap());
452 wwo->buffer_size = buffer_required;
453 wwo->sound_buffer = HeapReAlloc(GetProcessHeap(), 0, wwo->sound_buffer, wwo->buffer_size);
455 /* if we don't have a buffer then error out */
456 if(!wwo->sound_buffer)
458 ERR("error allocating sound_buffer memory\n");
459 LeaveCriticalSection(&wwo->access_crst);
460 return 0;
464 LeaveCriticalSection(&wwo->access_crst);
466 TRACE("called\n");
468 return 0;
471 /******************************************************************
472 * JACK_srate
474 int JACK_srate (nframes_t nframes, void *arg)
476 TRACE("the sample rate is now %lu/sec\n", nframes);
477 return 0;
481 /******************************************************************
482 * JACK_shutdown
484 /* if this is called then jack shut down... handle this appropriately */
485 void JACK_shutdown(void* arg)
487 WINE_WAVEOUT* wwo = (WINE_WAVEOUT*)arg;
489 wwo->client = 0; /* reset client */
491 TRACE("trying to reconnect after sleeping for a short while...\n");
493 /* lets see if we can't reestablish the connection */
494 Sleep(750); /* pause for a short period of time */
495 if(!JACK_OpenDevice(wwo))
497 ERR("unable to reconnect with jack...\n");
502 /******************************************************************
503 * JACK_OpenDevice
505 static int JACK_OpenDevice(WINE_WAVEOUT* wwo)
507 const char** ports;
508 int i;
509 char client_name[64];
510 jack_port_t* out_port_l;
511 jack_port_t* out_port_r;
512 jack_client_t* client;
513 int failed = 0;
515 TRACE("creating jack client and setting up callbacks\n");
517 #if JACK_CLOSE_HACK
518 /* see if this device is already open */
519 if(wwo->client)
521 /* if this device is already in use then it is bad for us to be in here */
522 if(wwo->in_use)
523 return 0;
525 TRACE("using existing client\n");
526 wwo->in_use = TRUE;
527 return 1;
529 #endif
531 /* zero out the buffer pointer and the size of the buffer */
532 wwo->sound_buffer = 0;
533 wwo->buffer_size = 0;
535 /* try to become a client of the JACK server */
536 snprintf(client_name, sizeof(client_name), "wine_jack_client %d", wwo->wDevID);
537 TRACE("client name '%s'\n", client_name);
538 if ((client = fp_jack_client_new (client_name)) == 0)
540 /* jack has problems with shutting down clients, so lets */
541 /* wait a short while and try once more before we give up */
542 Sleep(250);
543 if ((client = fp_jack_client_new (client_name)) == 0)
545 ERR("jack server not running?\n");
546 return 0;
550 /* tell the JACK server to call `JACK_callback()' whenever
551 there is work to be done. */
552 fp_jack_set_process_callback (client, JACK_callback, wwo);
554 /* tell the JACK server to call `JACK_bufsize()' whenever
555 the maximum number of frames that will be passed
556 to `JACK_Callback()' changes */
557 fp_jack_set_buffer_size_callback (client, JACK_bufsize, wwo);
559 /* tell the JACK server to call `srate()' whenever
560 the sample rate of the system changes. */
561 fp_jack_set_sample_rate_callback (client, JACK_srate, wwo);
563 /* tell the JACK server to call `jack_shutdown()' if
564 it ever shuts down, either entirely, or if it
565 just decides to stop calling us. */
566 fp_jack_on_shutdown (client, JACK_shutdown, wwo);
568 /* display the current sample rate. once the client is activated
569 (see below), you should rely on your own sample rate
570 callback (see above) for this value. */
571 wwo->sample_rate = fp_jack_get_sample_rate(client);
572 TRACE("engine sample rate: %lu\n", wwo->sample_rate);
574 /* create the left and right channel output ports */
575 /* jack's ports are all mono so for stereo you need two */
576 out_port_l = fp_jack_port_register (client, "out_l",
577 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
579 out_port_r = fp_jack_port_register (client, "out_r",
580 JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
582 /* save away important values to the WINE_WAVEOUT struct */
583 wwo->client = client;
584 wwo->out_port_l = out_port_l;
585 wwo->out_port_r = out_port_r;
587 #if JACK_CLOSE_HACK
588 wwo->in_use = TRUE; /* mark this device as in use since it now is ;-) */
589 #endif
591 /* tell the JACK server that we are ready to roll */
592 if (fp_jack_activate (client))
594 ERR( "cannot activate client\n");
595 return 0;
598 /* figure out what the ports that we want to output on are */
599 /* NOTE: we do this instead of using stuff like "alsa_pcm:playback_X" because */
600 /* this way works if names are changed */
601 ports = fp_jack_get_ports(client, NULL, NULL, JackPortIsPhysical|JackPortIsInput);
603 /* display a trace of the output ports we found */
604 for(i = 0; ports[i]; i++)
606 TRACE("ports[%d] = '%s'\n", i, ports[i]);
609 if(!ports)
611 ERR("jack_get_ports() failed to find 'JackPortIsPhysical|JackPortIsInput'\n");
614 /* connect the ports. Note: you can't do this before
615 the client is activated (this may change in the future).
617 /* we want to connect to two ports so we have stereo output ;-) */
619 if(fp_jack_connect(client, fp_jack_port_name(out_port_l), ports[0]))
621 ERR ("cannot connect to output port %d('%s')\n", 0, ports[0]);
622 failed = 1;
625 if(fp_jack_connect(client, fp_jack_port_name(out_port_r), ports[1]))
627 ERR ("cannot connect to output port %d('%s')\n", 1, ports[1]);
628 failed = 1;
631 free(ports); /* free the returned array of ports */
633 /* if something failed we need to shut the client down and return 0 */
634 if(failed)
636 JACK_CloseDevice(wwo, TRUE);
637 return 0;
640 return 1; /* return success */
643 /******************************************************************
644 * JACK_CloseDevice
646 * Close the connection to the server cleanly.
647 * If close_client is TRUE we close the client for this device instead of
648 * just marking the device as in_use(JACK_CLOSE_HACK only)
650 #if JACK_CLOSE_HACK
651 static void JACK_CloseDevice(WINE_WAVEOUT* wwo, BOOL close_client)
652 #else
653 static void JACK_CloseDevice(WINE_WAVEOUT* wwo)
654 #endif
656 #if JACK_CLOSE_HACK
657 TRACE("wDevID: %d, close_client: %d\n", wwo->wDevID, close_client);
658 #else
659 TRACE("wDevID: %d\n", wwo->wDevID);
660 #endif
662 #if JACK_CLOSE_HACK
663 if(close_client)
665 #endif
666 fp_jack_deactivate(wwo->client); /* supposed to help the jack_client_close() to succeed */
667 fp_jack_client_close (wwo->client);
669 EnterCriticalSection(&wwo->access_crst);
670 wwo->client = 0; /* reset client */
671 HeapFree(GetProcessHeap(), 0, wwo->sound_buffer); /* free buffer memory */
672 wwo->sound_buffer = 0;
673 wwo->buffer_size = 0; /* zero out size of the buffer */
674 LeaveCriticalSection(&wwo->access_crst);
675 #if JACK_CLOSE_HACK
676 } else
678 EnterCriticalSection(&wwo->access_crst);
679 TRACE("setting in_use to FALSE\n");
680 wwo->in_use = FALSE;
681 LeaveCriticalSection(&wwo->access_crst);
683 #endif
686 /******************************************************************
687 * JACK_WaveRelease
691 LONG JACK_WaveRelease(void)
693 int iDevice;
695 TRACE("closing all open devices\n");
697 /* close all open devices */
698 for(iDevice = 0; iDevice < MAX_WAVEOUTDRV; iDevice++)
700 TRACE("iDevice == %d\n", iDevice);
701 if(WOutDev[iDevice].client)
703 #if JACK_CLOSE_HACK
704 JACK_CloseDevice(&WOutDev[iDevice], TRUE); /* close the device, FORCE the client to close */
705 #else
706 JACK_CloseDevice(&WOutDev[iDevice]); /* close the device, FORCE the client to close */
707 #endif
708 DeleteCriticalSection(&(WOutDev[iDevice].access_crst)); /* delete the critical section */
712 TRACE("returning 1\n");
714 return 1;
717 /******************************************************************
718 * JACK_WaveInit
720 * Initialize internal structures from JACK server info
722 LONG JACK_WaveInit(void)
724 int i;
726 TRACE("called\n");
728 /* setup function pointers */
729 #define LOAD_FUNCPTR(f) if((fp_##f = wine_dlsym(jackhandle, #f, NULL, 0)) == NULL) goto sym_not_found;
730 LOAD_FUNCPTR(jack_activate);
731 LOAD_FUNCPTR(jack_connect);
732 LOAD_FUNCPTR(jack_client_new);
733 LOAD_FUNCPTR(jack_client_close);
734 LOAD_FUNCPTR(jack_deactivate);
735 LOAD_FUNCPTR(jack_set_process_callback);
736 LOAD_FUNCPTR(jack_set_buffer_size_callback);
737 LOAD_FUNCPTR(jack_set_sample_rate_callback);
738 LOAD_FUNCPTR(jack_on_shutdown);
739 LOAD_FUNCPTR(jack_get_sample_rate);
740 LOAD_FUNCPTR(jack_port_register);
741 LOAD_FUNCPTR(jack_port_get_buffer);
742 LOAD_FUNCPTR(jack_get_ports);
743 LOAD_FUNCPTR(jack_port_name);
744 #undef LOAD_FUNCPTR
746 /* start with output device */
748 for (i = 0; i < MAX_WAVEOUTDRV; ++i)
750 WOutDev[i].client = 0; /* initialize the client to 0 */
752 #if JACK_CLOSE_HACK
753 WOutDev[i].in_use = FALSE;
754 #endif
756 memset(&WOutDev[i].caps, 0, sizeof(WOutDev[i].caps));
758 /* FIXME: some programs compare this string against the content of the registry
759 * for MM drivers. The names have to match in order for the program to work
760 * (e.g. MS win9x mplayer.exe)
762 #ifdef EMULATE_SB16
763 WOutDev[i].caps.wMid = 0x0002;
764 WOutDev[i].caps.wPid = 0x0104;
765 strcpy(WOutDev[i].caps.szPname, "SB16 Wave Out");
766 #else
767 WOutDev[i].caps.wMid = 0x00FF; /* Manufac ID */
768 WOutDev[i].caps.wPid = 0x0001; /* Product ID */
769 /* strcpy(WOutDev[i].caps.szPname, "OpenSoundSystem WAVOUT Driver");*/
770 strcpy(WOutDev[i].caps.szPname, "CS4236/37/38");
771 #endif
772 WOutDev[i].caps.vDriverVersion = 0x0100;
773 WOutDev[i].caps.dwFormats = 0x00000000;
774 WOutDev[i].caps.dwSupport = WAVECAPS_VOLUME;
776 WOutDev[i].caps.wChannels = 2;
777 WOutDev[i].caps.dwSupport |= WAVECAPS_LRVOLUME;
779 /* NOTE: we don't support any 8 bit modes so note that */
780 /* WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;
781 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S08; */
782 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S16;
783 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M16;
784 /* WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;
785 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S08; */
786 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M16;
787 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S16;
788 /* WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;
789 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;*/
790 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M16;
791 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S16;
794 /* then do input device */
795 for (i = 0; i < MAX_WAVEINDRV; ++i)
797 /* TODO: we should initialize read stuff here */
798 memset(&WInDev[0].caps, 0, sizeof(WInDev[0].caps));
801 return 1; /* return success */
803 /* error path for function pointer loading errors */
804 sym_not_found:
805 WINE_MESSAGE(
806 "Wine cannot find certain functions that it needs inside the jack"
807 "library. To enable Wine to use the jack audio server please "
808 "install libjack\n");
809 wine_dlclose(jackhandle, NULL, 0);
810 jackhandle = NULL;
811 return FALSE;
814 /*======================================================================*
815 * Low level WAVE OUT implementation *
816 *======================================================================*/
818 /**************************************************************************
819 * wodNotifyClient [internal]
821 static DWORD wodNotifyClient(WINE_WAVEOUT* wwo, WORD wMsg, DWORD dwParam1, DWORD dwParam2)
823 TRACE("wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX\n", wMsg, dwParam1, dwParam2);
825 switch (wMsg) {
826 case WOM_OPEN:
827 case WOM_CLOSE:
828 case WOM_DONE:
829 if (wwo->wFlags != DCB_NULL &&
830 !DriverCallback(wwo->waveDesc.dwCallback, wwo->wFlags,
831 (HDRVR)wwo->waveDesc.hWave, wMsg, wwo->waveDesc.dwInstance,
832 dwParam1, dwParam2))
834 WARN("can't notify client !\n");
835 return MMSYSERR_ERROR;
837 break;
838 default:
839 FIXME("Unknown callback message %u\n", wMsg);
840 return MMSYSERR_INVALPARAM;
842 return MMSYSERR_NOERROR;
845 /**************************************************************************
846 * wodHelper_BeginWaveHdr [internal]
848 * Makes the specified lpWaveHdr the currently playing wave header.
849 * If the specified wave header is a begin loop and we're not already in
850 * a loop, setup the loop.
852 static void wodHelper_BeginWaveHdr(WINE_WAVEOUT* wwo, LPWAVEHDR lpWaveHdr)
854 EnterCriticalSection(&wwo->access_crst);
856 wwo->lpPlayPtr = lpWaveHdr;
858 if (!lpWaveHdr)
860 LeaveCriticalSection(&wwo->access_crst);
861 return;
864 if (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)
866 if (wwo->lpLoopPtr)
868 WARN("Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);
869 TRACE("Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr);
870 } else
872 TRACE("Starting loop (%ldx) with %p\n", lpWaveHdr->dwLoops, lpWaveHdr);
873 wwo->lpLoopPtr = lpWaveHdr;
874 /* Windows does not touch WAVEHDR.dwLoops,
875 * so we need to make an internal copy */
876 wwo->dwLoops = lpWaveHdr->dwLoops;
879 wwo->dwPartialOffset = 0;
881 LeaveCriticalSection(&wwo->access_crst);
885 /**************************************************************************
886 * wodHelper_PlayPtrNext [internal]
888 * Advance the play pointer to the next waveheader, looping if required.
890 static LPWAVEHDR wodHelper_PlayPtrNext(WINE_WAVEOUT* wwo)
892 LPWAVEHDR lpWaveHdr;
894 EnterCriticalSection(&wwo->access_crst);
896 lpWaveHdr = wwo->lpPlayPtr;
898 wwo->dwPartialOffset = 0;
899 if ((lpWaveHdr->dwFlags & WHDR_ENDLOOP) && wwo->lpLoopPtr)
901 /* We're at the end of a loop, loop if required */
902 if (--wwo->dwLoops > 0)
904 wwo->lpPlayPtr = wwo->lpLoopPtr;
905 } else
907 /* Handle overlapping loops correctly */
908 if (wwo->lpLoopPtr != lpWaveHdr && (lpWaveHdr->dwFlags & WHDR_BEGINLOOP)) {
909 FIXME("Correctly handled case ? (ending loop buffer also starts a new loop)\n");
910 /* shall we consider the END flag for the closing loop or for
911 * the opening one or for both ???
912 * code assumes for closing loop only
914 } else
916 lpWaveHdr = lpWaveHdr->lpNext;
918 wwo->lpLoopPtr = NULL;
919 wodHelper_BeginWaveHdr(wwo, lpWaveHdr);
921 } else
923 /* We're not in a loop. Advance to the next wave header */
924 TRACE("not inside of a loop, advancing to next wave header\n");
925 wodHelper_BeginWaveHdr(wwo, lpWaveHdr = lpWaveHdr->lpNext);
928 LeaveCriticalSection(&wwo->access_crst);
930 return lpWaveHdr;
933 /* if force is TRUE then notify the client that all the headers were completed */
934 static DWORD wodHelper_NotifyCompletions(WINE_WAVEOUT* wwo, BOOL force)
936 LPWAVEHDR lpWaveHdr;
937 DWORD retval;
939 TRACE("called\n");
941 EnterCriticalSection(&wwo->access_crst);
943 /* Start from lpQueuePtr and keep notifying until:
944 * - we hit an unwritten wavehdr
945 * - we hit the beginning of a running loop
946 * - we hit a wavehdr which hasn't finished playing
948 while ((lpWaveHdr = wwo->lpQueuePtr) &&
949 (force ||
950 (lpWaveHdr != wwo->lpPlayPtr &&
951 lpWaveHdr != wwo->lpLoopPtr)))
953 wwo->lpQueuePtr = lpWaveHdr->lpNext;
955 lpWaveHdr->dwFlags &= ~WHDR_INQUEUE;
956 lpWaveHdr->dwFlags |= WHDR_DONE;
957 TRACE("calling notify client\n");
959 wodNotifyClient(wwo, WOM_DONE, (DWORD)lpWaveHdr, 0);
962 retval = (lpWaveHdr && lpWaveHdr != wwo->lpPlayPtr && lpWaveHdr !=
963 wwo->lpLoopPtr) ? 0 : INFINITE;
965 LeaveCriticalSection(&wwo->access_crst);
967 return retval;
970 /**************************************************************************
971 * wodHelper_Reset [internal]
973 * Resets current output stream.
975 static void wodHelper_Reset(WINE_WAVEOUT* wwo, BOOL reset)
977 EnterCriticalSection(&wwo->access_crst);
979 /* updates current notify list */
980 wodHelper_NotifyCompletions(wwo, FALSE);
982 if (reset)
984 /* remove all wave headers and notify client that all headers were completed */
985 wodHelper_NotifyCompletions(wwo, TRUE);
987 wwo->lpPlayPtr = wwo->lpQueuePtr = wwo->lpLoopPtr = NULL;
988 wwo->state = WINE_WS_STOPPED;
989 wwo->dwPlayedTotal = wwo->dwWrittenTotal = wwo->bytesInJack = 0;
991 wwo->dwPartialOffset = 0; /* Clear partial wavehdr */
992 } else
994 if (wwo->lpLoopPtr)
996 /* complicated case, not handled yet (could imply modifying the loop counter) */
997 FIXME("Pausing while in loop isn't correctly handled yet, except strange results\n");
998 wwo->lpPlayPtr = wwo->lpLoopPtr;
999 wwo->dwPartialOffset = 0;
1000 wwo->dwWrittenTotal = wwo->dwPlayedTotal; /* this is wrong !!! */
1001 } else
1003 LPWAVEHDR ptr;
1004 DWORD sz = wwo->dwPartialOffset;
1006 /* reset all the data as if we had written only up to lpPlayedTotal bytes */
1007 /* compute the max size playable from lpQueuePtr */
1008 for (ptr = wwo->lpQueuePtr; ptr != wwo->lpPlayPtr; ptr = ptr->lpNext)
1010 sz += ptr->dwBufferLength;
1013 /* because the reset lpPlayPtr will be lpQueuePtr */
1014 if (wwo->dwWrittenTotal > wwo->dwPlayedTotal + sz) ERR("doh\n");
1015 wwo->dwPartialOffset = sz - (wwo->dwWrittenTotal - wwo->dwPlayedTotal);
1016 wwo->dwWrittenTotal = wwo->dwPlayedTotal;
1017 wwo->lpPlayPtr = wwo->lpQueuePtr;
1020 wwo->state = WINE_WS_PAUSED;
1023 LeaveCriticalSection(&wwo->access_crst);
1026 /**************************************************************************
1027 * wodGetDevCaps [internal]
1029 static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSA lpCaps, DWORD dwSize)
1031 TRACE("(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
1033 if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
1035 if (wDevID >= MAX_WAVEOUTDRV)
1037 TRACE("MAX_WAVOUTDRV reached !\n");
1038 return MMSYSERR_BADDEVICEID;
1041 memcpy(lpCaps, &WOutDev[wDevID].caps, min(dwSize, sizeof(*lpCaps)));
1042 return MMSYSERR_NOERROR;
1045 /**************************************************************************
1046 * wodOpen [internal]
1048 static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
1050 WINE_WAVEOUT* wwo;
1051 DWORD retval;
1053 TRACE("(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
1054 if (lpDesc == NULL)
1056 WARN("Invalid Parameter !\n");
1057 return MMSYSERR_INVALPARAM;
1059 if (wDevID >= MAX_WAVEOUTDRV) {
1060 TRACE("MAX_WAVOUTDRV reached !\n");
1061 return MMSYSERR_BADDEVICEID;
1064 #if JACK_CLOSE_HACK
1065 if(WOutDev[wDevID].client && WOutDev[wDevID].in_use)
1066 #else
1067 if(WOutDev[wDevID].client)
1068 #endif
1070 TRACE("device %d already allocated\n", wDevID);
1071 return MMSYSERR_ALLOCATED;
1074 /* make sure we aren't being opened in 8 bit mode */
1075 if(lpDesc->lpFormat->wBitsPerSample == 8)
1077 TRACE("8bits per sample unsupported, returning WAVERR_BADFORMAT\n");
1078 return WAVERR_BADFORMAT;
1081 wwo = &WOutDev[wDevID];
1082 wwo->wDevID = wDevID;
1084 /* Set things up before we call JACK_OpenDevice because */
1085 /* we will start getting callbacks before JACK_OpenDevice */
1086 /* even returns and we want to be initialized before then */
1087 wwo->state = WINE_WS_STOPPED; /* start in a stopped state */
1088 wwo->dwPlayedTotal = 0; /* zero out these totals */
1089 wwo->dwWrittenTotal = 0;
1090 wwo->bytesInJack = 0;
1091 wwo->tickCountMS = 0;
1093 InitializeCriticalSection(&wwo->access_crst); /* initialize the critical section */
1095 /* open up jack ports for this device */
1096 if (!JACK_OpenDevice(&WOutDev[wDevID]))
1098 ERR("JACK_OpenDevice(%d) failed\n", wDevID);
1099 return MMSYSERR_ERROR; /* return unspecified error */
1102 /* only PCM format is supported so far... */
1103 if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM ||
1104 lpDesc->lpFormat->nChannels == 0 ||
1105 lpDesc->lpFormat->nSamplesPerSec == 0)
1107 WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%ld !\n",
1108 lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
1109 lpDesc->lpFormat->nSamplesPerSec);
1110 return WAVERR_BADFORMAT;
1113 if (dwFlags & WAVE_FORMAT_QUERY)
1115 TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%ld !\n",
1116 lpDesc->lpFormat->wFormatTag, lpDesc->lpFormat->nChannels,
1117 lpDesc->lpFormat->nSamplesPerSec);
1118 return MMSYSERR_NOERROR;
1121 dwFlags &= ~WAVE_DIRECTSOUND; /* direct sound not supported, ignore the flag */
1123 EnterCriticalSection(&wwo->access_crst);
1125 wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
1127 memcpy(&wwo->waveDesc, lpDesc, sizeof(WAVEOPENDESC));
1128 memcpy(&wwo->format, lpDesc->lpFormat, sizeof(PCMWAVEFORMAT));
1130 LeaveCriticalSection(&wwo->access_crst);
1132 /* display the current wave format */
1133 TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%lu, nSamplesPerSec=%lu, nChannels=%u nBlockAlign=%u!\n",
1134 wwo->format.wBitsPerSample, wwo->format.wf.nAvgBytesPerSec,
1135 wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels,
1136 wwo->format.wf.nBlockAlign);
1138 /* make sure that we have the same sample rate in our audio stream */
1139 /* as we do in the jack server */
1140 if(wwo->format.wf.nSamplesPerSec != wwo->sample_rate)
1142 TRACE("error: jack server sample rate is '%ld', wave sample rate is '%ld'\n",
1143 wwo->sample_rate, wwo->format.wf.nSamplesPerSec);
1145 #if JACK_CLOSE_HACK
1146 JACK_CloseDevice(wwo, FALSE); /* close this device, don't force the client to close */
1147 #else
1148 JACK_CloseDevice(wwo); /* close this device */
1149 #endif
1150 return WAVERR_BADFORMAT;
1153 /* check for an invalid number of bits per sample */
1154 if (wwo->format.wBitsPerSample == 0)
1156 WARN("Resetting zeroed wBitsPerSample to 16\n");
1157 wwo->format.wBitsPerSample = 16 *
1158 (wwo->format.wf.nAvgBytesPerSec /
1159 wwo->format.wf.nSamplesPerSec) /
1160 wwo->format.wf.nChannels;
1163 EnterCriticalSection(&wwo->access_crst);
1164 retval = wodNotifyClient(wwo, WOM_OPEN, 0L, 0L);
1165 LeaveCriticalSection(&wwo->access_crst);
1167 return retval;
1170 /**************************************************************************
1171 * wodClose [internal]
1173 static DWORD wodClose(WORD wDevID)
1175 DWORD ret = MMSYSERR_NOERROR;
1176 WINE_WAVEOUT* wwo;
1178 TRACE("(%u);\n", wDevID);
1180 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1182 WARN("bad device ID !\n");
1183 return MMSYSERR_BADDEVICEID;
1186 wwo = &WOutDev[wDevID];
1187 if (wwo->lpQueuePtr)
1189 WARN("buffers still playing !\n");
1190 ret = WAVERR_STILLPLAYING;
1191 } else
1193 /* sanity check: this should not happen since the device must have been reset before */
1194 if (wwo->lpQueuePtr || wwo->lpPlayPtr) ERR("out of sync\n");
1196 wwo->state = WINE_WS_CLOSED; /* mark the device as closed */
1198 #if JACK_CLOSE_HACK
1199 JACK_CloseDevice(wwo, FALSE); /* close the jack device, DO NOT force the client to close */
1200 #else
1201 JACK_CloseDevice(wwo); /* close the jack device */
1202 DeleteCriticalSection(&wwo->access_crst); /* delete the critical section so we can initialize it again from wodOpen() */
1203 #endif
1205 ret = wodNotifyClient(wwo, WOM_CLOSE, 0L, 0L);
1208 return ret;
1211 /**************************************************************************
1212 * wodWrite [internal]
1215 static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1217 LPWAVEHDR*wh;
1218 WINE_WAVEOUT *wwo;
1220 TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1222 /* first, do the sanity checks... */
1223 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1225 WARN("bad dev ID !\n");
1226 return MMSYSERR_BADDEVICEID;
1229 wwo = &WOutDev[wDevID];
1231 if (lpWaveHdr->lpData == NULL || !(lpWaveHdr->dwFlags & WHDR_PREPARED))
1233 TRACE("unprepared\n");
1234 return WAVERR_UNPREPARED;
1237 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1239 TRACE("still playing\n");
1240 return WAVERR_STILLPLAYING;
1243 lpWaveHdr->dwFlags &= ~WHDR_DONE;
1244 lpWaveHdr->dwFlags |= WHDR_INQUEUE;
1245 lpWaveHdr->lpNext = 0;
1247 EnterCriticalSection(&wwo->access_crst);
1249 /* insert buffer at the end of queue */
1250 for (wh = &(wwo->lpQueuePtr); *wh; wh = &((*wh)->lpNext));
1251 *wh = lpWaveHdr;
1253 LeaveCriticalSection(&wwo->access_crst);
1255 EnterCriticalSection(&wwo->access_crst);
1256 if (!wwo->lpPlayPtr)
1257 wodHelper_BeginWaveHdr(wwo,lpWaveHdr);
1258 if (wwo->state == WINE_WS_STOPPED)
1259 wwo->state = WINE_WS_PLAYING;
1260 LeaveCriticalSection(&wwo->access_crst);
1262 return MMSYSERR_NOERROR;
1265 /**************************************************************************
1266 * wodPrepare [internal]
1268 static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1270 TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1272 if (wDevID >= MAX_WAVEOUTDRV)
1274 WARN("bad device ID !\n");
1275 return MMSYSERR_BADDEVICEID;
1278 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1279 return WAVERR_STILLPLAYING;
1281 lpWaveHdr->dwFlags |= WHDR_PREPARED;
1282 lpWaveHdr->dwFlags &= ~WHDR_DONE;
1283 return MMSYSERR_NOERROR;
1286 /**************************************************************************
1287 * wodUnprepare [internal]
1289 static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
1291 TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
1293 if (wDevID >= MAX_WAVEOUTDRV)
1295 WARN("bad device ID !\n");
1296 return MMSYSERR_BADDEVICEID;
1299 if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
1300 return WAVERR_STILLPLAYING;
1302 lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
1303 lpWaveHdr->dwFlags |= WHDR_DONE;
1305 return MMSYSERR_NOERROR;
1308 /**************************************************************************
1309 * wodPause [internal]
1311 static DWORD wodPause(WORD wDevID)
1313 TRACE("(%u);!\n", wDevID);
1315 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1317 WARN("bad device ID !\n");
1318 return MMSYSERR_BADDEVICEID;
1321 TRACE("[3-PAUSING]\n");
1323 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1324 wodHelper_Reset(&WOutDev[wDevID], FALSE);
1325 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1327 return MMSYSERR_NOERROR;
1330 /**************************************************************************
1331 * wodRestart [internal]
1333 static DWORD wodRestart(WORD wDevID)
1335 TRACE("(%u);\n", wDevID);
1337 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1339 WARN("bad device ID !\n");
1340 return MMSYSERR_BADDEVICEID;
1343 if (WOutDev[wDevID].state == WINE_WS_PAUSED)
1345 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1346 WOutDev[wDevID].state = WINE_WS_PLAYING;
1347 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1350 return MMSYSERR_NOERROR;
1353 /**************************************************************************
1354 * wodReset [internal]
1356 static DWORD wodReset(WORD wDevID)
1358 TRACE("(%u);\n", wDevID);
1360 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1362 WARN("bad device ID !\n");
1363 return MMSYSERR_BADDEVICEID;
1366 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1367 wodHelper_Reset(&WOutDev[wDevID], TRUE);
1368 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1370 return MMSYSERR_NOERROR;
1373 /**************************************************************************
1374 * wodGetPosition [internal]
1376 static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
1378 int time;
1379 DWORD val;
1380 WINE_WAVEOUT* wwo;
1381 DWORD elapsedMS;
1383 TRACE("(%u, %p, %lu);\n", wDevID, lpTime, uSize);
1385 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1387 WARN("bad device ID !\n");
1388 return MMSYSERR_BADDEVICEID;
1391 /* if null pointer to time structure return error */
1392 if (lpTime == NULL) return MMSYSERR_INVALPARAM;
1394 wwo = &WOutDev[wDevID];
1396 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1397 val = wwo->dwPlayedTotal;
1398 elapsedMS = GetTickCount() - wwo->tickCountMS;
1399 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1401 /* account for the bytes played since the last JACK_Callback() */
1402 val+=((elapsedMS * wwo->format.wf.nAvgBytesPerSec) / 1000);
1404 TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",
1405 lpTime->wType, wwo->format.wBitsPerSample,
1406 wwo->format.wf.nSamplesPerSec, wwo->format.wf.nChannels,
1407 wwo->format.wf.nAvgBytesPerSec);
1408 TRACE("dwPlayedTotal=%lu\n", val);
1410 switch (lpTime->wType) {
1411 case TIME_BYTES:
1412 lpTime->u.cb = val;
1413 TRACE("TIME_BYTES=%lu\n", lpTime->u.cb);
1414 break;
1415 case TIME_SAMPLES:
1416 lpTime->u.sample = val * 8 / wwo->format.wBitsPerSample /wwo->format.wf.nChannels;
1417 TRACE("TIME_SAMPLES=%lu\n", lpTime->u.sample);
1418 break;
1419 case TIME_SMPTE:
1420 time = val / (wwo->format.wf.nAvgBytesPerSec / 1000);
1421 lpTime->u.smpte.hour = time / 108000;
1422 time -= lpTime->u.smpte.hour * 108000;
1423 lpTime->u.smpte.min = time / 1800;
1424 time -= lpTime->u.smpte.min * 1800;
1425 lpTime->u.smpte.sec = time / 30;
1426 time -= lpTime->u.smpte.sec * 30;
1427 lpTime->u.smpte.frame = time;
1428 lpTime->u.smpte.fps = 30;
1429 TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1430 lpTime->u.smpte.hour, lpTime->u.smpte.min,
1431 lpTime->u.smpte.sec, lpTime->u.smpte.frame);
1432 break;
1433 default:
1434 FIXME("Format %d not supported ! use TIME_MS !\n", lpTime->wType);
1435 lpTime->wType = TIME_MS;
1436 case TIME_MS:
1437 lpTime->u.ms = val / (wwo->format.wf.nAvgBytesPerSec / 1000);
1438 TRACE("TIME_MS=%lu\n", lpTime->u.ms);
1439 break;
1441 return MMSYSERR_NOERROR;
1444 /**************************************************************************
1445 * wodBreakLoop [internal]
1447 static DWORD wodBreakLoop(WORD wDevID)
1449 TRACE("(%u);\n", wDevID);
1451 if (wDevID >= MAX_WAVEOUTDRV || !WOutDev[wDevID].client)
1453 WARN("bad device ID !\n");
1454 return MMSYSERR_BADDEVICEID;
1457 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1459 if (WOutDev[wDevID].state == WINE_WS_PLAYING && WOutDev[wDevID].lpLoopPtr != NULL)
1461 /* ensure exit at end of current loop */
1462 WOutDev[wDevID].dwLoops = 1;
1465 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1467 return MMSYSERR_NOERROR;
1470 /**************************************************************************
1471 * wodGetVolume [internal]
1473 static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
1475 DWORD left, right;
1477 left = WOutDev[wDevID].volume_left;
1478 right = WOutDev[wDevID].volume_right;
1480 TRACE("(%u, %p);\n", wDevID, lpdwVol);
1482 *lpdwVol = ((left * 0xFFFFl) / 100) + (((right * 0xFFFFl) / 100) <<
1483 16);
1485 return MMSYSERR_NOERROR;
1488 /**************************************************************************
1489 * wodSetVolume [internal]
1491 static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
1493 DWORD left, right;
1495 left = (LOWORD(dwParam) * 100) / 0xFFFFl;
1496 right = (HIWORD(dwParam) * 100) / 0xFFFFl;
1498 TRACE("(%u, %08lX);\n", wDevID, dwParam);
1500 EnterCriticalSection(&(WOutDev[wDevID].access_crst));
1502 WOutDev[wDevID].volume_left = left;
1503 WOutDev[wDevID].volume_right = right;
1505 LeaveCriticalSection(&(WOutDev[wDevID].access_crst));
1507 return MMSYSERR_NOERROR;
1510 /**************************************************************************
1511 * wodGetNumDevs [internal]
1513 static DWORD wodGetNumDevs(void)
1515 return MAX_WAVEOUTDRV;
1518 /**************************************************************************
1519 * wodMessage (WINEJACK.7)
1521 DWORD WINAPI JACK_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
1522 DWORD dwParam1, DWORD dwParam2)
1524 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1525 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1527 switch (wMsg) {
1528 case DRVM_INIT:
1529 TRACE("DRVM_INIT\n");
1530 return JACK_WaveInit();
1531 case DRVM_EXIT:
1532 TRACE("DRVM_EXIT\n");
1533 return JACK_WaveRelease();
1534 case DRVM_ENABLE:
1535 /* FIXME: Pretend this is supported */
1536 TRACE("DRVM_ENABLE\n");
1537 return 0;
1538 case DRVM_DISABLE:
1539 /* FIXME: Pretend this is supported */
1540 TRACE("DRVM_DISABLE\n");
1541 return 0;
1542 case WODM_OPEN: return wodOpen(wDevID, (LPWAVEOPENDESC)dwParam1, dwParam2);
1543 case WODM_CLOSE: return wodClose(wDevID);
1544 case WODM_WRITE: return wodWrite(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1545 case WODM_PAUSE: return wodPause(wDevID);
1546 case WODM_GETPOS: return wodGetPosition(wDevID, (LPMMTIME)dwParam1, dwParam2);
1547 case WODM_BREAKLOOP: return wodBreakLoop(wDevID);
1548 case WODM_PREPARE: return wodPrepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1549 case WODM_UNPREPARE: return wodUnprepare(wDevID, (LPWAVEHDR)dwParam1, dwParam2);
1550 case WODM_GETDEVCAPS: return wodGetDevCaps(wDevID, (LPWAVEOUTCAPSA)dwParam1, dwParam2);
1551 case WODM_GETNUMDEVS: return wodGetNumDevs();
1552 case WODM_GETPITCH: return MMSYSERR_NOTSUPPORTED;
1553 case WODM_SETPITCH: return MMSYSERR_NOTSUPPORTED;
1554 case WODM_GETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED;
1555 case WODM_SETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED;
1556 case WODM_GETVOLUME: return wodGetVolume(wDevID, (LPDWORD)dwParam1);
1557 case WODM_SETVOLUME: return wodSetVolume(wDevID, dwParam1);
1558 case WODM_RESTART: return wodRestart(wDevID);
1559 case WODM_RESET: return wodReset(wDevID);
1561 case DRV_QUERYDSOUNDIFACE: return wodDsCreate(wDevID, (PIDSDRIVER*)dwParam1);
1562 case DRV_QUERYDSOUNDDESC: return wodDsDesc(wDevID, (PDSDRIVERDESC)dwParam1);
1563 case DRV_QUERYDSOUNDGUID: return wodDsGuid(wDevID, (LPGUID)dwParam1);
1564 default:
1565 FIXME("unknown message %d!\n", wMsg);
1567 return MMSYSERR_NOTSUPPORTED;
1570 /*======================================================================*
1571 * Low level DSOUND implementation *
1572 *======================================================================*/
1574 typedef struct IDsDriverImpl IDsDriverImpl;
1575 typedef struct IDsDriverBufferImpl IDsDriverBufferImpl;
1577 struct IDsDriverImpl
1579 /* IUnknown fields */
1580 ICOM_VFIELD(IDsDriver);
1581 DWORD ref;
1582 /* IDsDriverImpl fields */
1583 UINT wDevID;
1584 IDsDriverBufferImpl*primary;
1587 struct IDsDriverBufferImpl
1589 /* IUnknown fields */
1590 ICOM_VFIELD(IDsDriverBuffer);
1591 DWORD ref;
1592 /* IDsDriverBufferImpl fields */
1593 IDsDriverImpl* drv;
1594 DWORD buflen;
1597 static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv)
1599 /* we can't perform memory mapping as we don't have a file stream
1600 interface with jack like we do with oss */
1601 MESSAGE("This sound card's driver does not support direct access\n");
1602 MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
1603 return MMSYSERR_NOTSUPPORTED;
1606 static DWORD wodDsDesc(UINT wDevID, PDSDRIVERDESC desc)
1608 memset(desc, 0, sizeof(*desc));
1609 strcpy(desc->szDesc, "Wine jack DirectSound Driver");
1610 strcpy(desc->szDrvName, "winejack.drv");
1611 return MMSYSERR_NOERROR;
1614 static DWORD wodDsGuid(UINT wDevID, LPGUID pGuid)
1616 memcpy(pGuid, &DSDEVID_DefaultPlayback, sizeof(GUID));
1617 return MMSYSERR_NOERROR;
1620 /*======================================================================*
1621 * Low level WAVE IN implementation *
1622 *======================================================================*/
1624 /**************************************************************************
1625 * widMessage (WINEJACK.6)
1627 DWORD WINAPI JACK_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1628 DWORD dwParam1, DWORD dwParam2)
1630 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1631 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1633 return MMSYSERR_NOTSUPPORTED;
1636 #else /* !HAVE_JACK_JACK_H */
1638 /**************************************************************************
1639 * wodMessage (WINEJACK.7)
1641 DWORD WINAPI JACK_wodMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1642 DWORD dwParam1, DWORD dwParam2)
1644 FIXME("(%u, %04X, %08lX, %08lX, %08lX):jack support not compiled into wine\n", wDevID, wMsg, dwUser, dwParam1, dwParam2);
1645 return MMSYSERR_NOTENABLED;
1648 #endif /* HAVE_JACK_JACK_H */