1 /* -*- tab-width: 8; c-basic-offset: 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
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
34 * pause in waveOut during loop is not handled correctly
51 #include "wine/winuser16.h"
56 #include "wine/debug.h"
58 #ifdef HAVE_JACK_JACK_H
59 #include <jack/jack.h>
63 WINE_DEFAULT_DEBUG_CHANNEL(wave
);
65 #ifdef HAVE_JACK_JACK_H
67 #define MAKE_FUNCPTR(f) static typeof(f) * fp_##f = NULL;
69 /* Function pointers for dynamic loading of libjack */
70 /* these are prefixed with "fp_", ie. "fp_jack_client_new" */
71 MAKE_FUNCPTR(jack_activate
);
72 MAKE_FUNCPTR(jack_connect
);
73 MAKE_FUNCPTR(jack_client_new
);
74 MAKE_FUNCPTR(jack_client_close
);
75 MAKE_FUNCPTR(jack_deactivate
);
76 MAKE_FUNCPTR(jack_set_process_callback
);
77 MAKE_FUNCPTR(jack_set_buffer_size_callback
);
78 MAKE_FUNCPTR(jack_set_sample_rate_callback
);
79 MAKE_FUNCPTR(jack_on_shutdown
);
80 MAKE_FUNCPTR(jack_get_sample_rate
);
81 MAKE_FUNCPTR(jack_port_register
);
82 MAKE_FUNCPTR(jack_port_get_buffer
);
83 MAKE_FUNCPTR(jack_get_ports
);
84 MAKE_FUNCPTR(jack_port_name
);
85 MAKE_FUNCPTR(jack_get_buffer_size
);
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 (10)
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
125 volatile int state
; /* one of the WINE_WS_ manifest constants */
126 WAVEOPENDESC waveDesc
;
128 PCMWAVEFORMAT format
;
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 */
138 BOOL in_use
; /* TRUE if this device is in use */
142 unsigned long buffer_size
;
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
;
166 WAVEOPENDESC waveDesc
;
168 PCMWAVEFORMAT format
;
169 LPWAVEHDR lpQueuePtr
;
170 DWORD dwTotalRecorded
;
172 BOOL bTriggerSupport
;
175 jack_port_t
* in_port_l
; /* ports for left and right channels */
176 jack_port_t
* in_port_r
;
177 jack_client_t
* client
;
178 long sample_rate
; /* jack server sample rate */
181 BOOL in_use
; /* TRUE if this device is in use */
185 unsigned long buffer_size
;
187 /* synchronization stuff */
188 CRITICAL_SECTION access_crst
;
191 static WINE_WAVEOUT WOutDev
[MAX_WAVEOUTDRV
];
192 static WINE_WAVEIN WInDev
[MAX_WAVEINDRV
];
194 static DWORD
wodDsCreate(UINT wDevID
, PIDSDRIVER
* drv
);
195 static DWORD
wodDsDesc(UINT wDevID
, PDSDRIVERDESC desc
);
196 static DWORD
wodDsGuid(UINT wDevID
, LPGUID pGuid
);
198 static LPWAVEHDR
wodHelper_PlayPtrNext(WINE_WAVEOUT
* wwo
);
199 static DWORD
wodHelper_NotifyCompletions(WINE_WAVEOUT
* wwo
, BOOL force
);
201 static int JACK_OpenWaveOutDevice(WINE_WAVEOUT
* wwo
);
202 static int JACK_OpenWaveInDevice(WINE_WAVEIN
* wwi
, WORD nChannels
);
205 static void JACK_CloseWaveOutDevice(WINE_WAVEOUT
* wwo
, BOOL close_client
);
207 static void JACK_CloseWaveOutDevice(WINE_WAVEOUT
* wwo
);
211 static void JACK_CloseWaveInDevice(WINE_WAVEIN
* wwi
, BOOL close_client
);
213 static void JACK_CloseWaveInDevice(WINE_WAVEIN
* wwi
);
217 /*======================================================================*
218 * Low level WAVE implementation *
219 *======================================================================*/
221 #define SAMPLE_MAX_16BIT 32767.0f
223 /* Alsaplayer function that applies volume changes to a buffer */
224 /* (C) Andy Lo A Foe */
225 /* Length is in terms of 32 bit samples */
226 void volume_effect32(void *buffer
, int length
, int left
, int right
)
228 short *data
= (short *)buffer
;
231 if (right
== -1) right
= left
;
233 for(i
= 0; i
< length
; i
++) {
234 v
= (int) ((*(data
) * left
) / 100);
235 *(data
++) = (v
>32767) ? 32767 : ((v
<-32768) ? -32768 : v
);
236 v
= (int) ((*(data
) * right
) / 100);
237 *(data
++) = (v
>32767) ? 32767 : ((v
<-32768) ? -32768 : v
);
241 /* move 16 bit mono/stereo to 16 bit stereo */
242 void sample_move_d16_d16(short *dst
, short *src
,
243 unsigned long nsamples
, int nChannels
)
250 if(nChannels
== 2) src
++;
259 /* convert from 16 bit to floating point */
260 /* allow for copying of stereo data with alternating left/right */
261 /* channels to a buffer that will hold a single channel stream */
262 /* nsamples is in terms of 16bit samples */
263 /* src_skip is in terms of 16bit samples */
264 void sample_move_d16_s16 (sample_t
*dst
, short *src
,
265 unsigned long nsamples
, unsigned long src_skip
)
267 /* ALERT: signed sign-extension portability !!! */
270 *dst
= (*src
) / SAMPLE_MAX_16BIT
;
276 /* convert from floating point to 16 bit */
277 /* allow for copying of a buffer that will hold a single channel stream */
278 /* to stereo data with alternating left/right channels */
279 /* nsamples is in terms of float samples */
280 /* dst_skip is in terms of 16bit samples */
281 void sample_move_s16_d16 (short *dst
, sample_t
*src
,
282 unsigned long nsamples
, unsigned long dst_skip
)
284 /* ALERT: signed sign-extension portability !!! */
287 *dst
= (*src
) * SAMPLE_MAX_16BIT
;
288 /* TRACE("src=(%.8f,%p) dst=(%d,%p)\n",*src,src,*dst,dst); */
295 /* fill dst buffer with nsamples worth of silence */
296 void sample_silence_dS (sample_t
*dst
, unsigned long nsamples
)
298 /* ALERT: signed sign-extension portability !!! */
306 /******************************************************************
309 /* everytime the jack server wants something from us it calls this
310 function, so we either deliver it some sound to play or deliver it nothing
312 int JACK_callback_wwo (nframes_t nframes
, void *arg
)
316 WINE_WAVEOUT
* wwo
= (WINE_WAVEOUT
*)arg
;
318 TRACE("wDevID: %u, nframes %u state=%u\n", wwo
->wDevID
, nframes
,wwo
->state
);
321 ERR("client is closed, this is weird...\n");
323 out_l
= (sample_t
*) fp_jack_port_get_buffer(wwo
->out_port_l
, nframes
);
324 out_r
= (sample_t
*) fp_jack_port_get_buffer(wwo
->out_port_r
, nframes
);
326 if(wwo
->state
== WINE_WS_PLAYING
)
328 DWORD jackFramesAvailable
= nframes
;
329 DWORD outputFramesAvailable
;
330 DWORD numFramesToWrite
;
336 if(wwo
->in_use
== FALSE
)
338 /* output silence if nothing is being outputted */
339 sample_silence_dS(out_l
, nframes
);
340 sample_silence_dS(out_r
, nframes
);
346 TRACE("wwo.state == WINE_WS_PLAYING\n");
348 /* see if our sound_buffer is large enough to hold the number of frames jack requested */
349 /* Note: sound_buffer is always filled with 16-bit stereo data, even for mono mode */
350 if(wwo
->buffer_size
< (nframes
* sizeof(short) * 2))
352 ERR("for some reason JACK_BufSize() didn't allocate enough memory\n");
353 ERR("allocated %ld bytes, need %d bytes\n", wwo
->buffer_size
, (nframes
* sizeof(short) * 2));
357 /* while we have jackFramesAvailable and a wave header to be played */
358 while(jackFramesAvailable
&& wwo
->lpPlayPtr
)
360 /* find the amount of audio to be played at this time */
361 outputFramesAvailable
= (wwo
->lpPlayPtr
->dwBufferLength
- wwo
->dwPartialOffset
) / wwo
->format
.wf
.nBlockAlign
;
363 numFramesToWrite
= min(jackFramesAvailable
, outputFramesAvailable
);
364 TRACE("dwBufferLength=(%ld) dwPartialOffset=(%ld)\n",wwo
->lpPlayPtr
->dwBufferLength
,wwo
->dwPartialOffset
);
365 TRACE("outputFramesAvailable == %ld, jackFramesAvailable == %ld\n", outputFramesAvailable
, jackFramesAvailable
);
367 buffer
= wwo
->lpPlayPtr
->lpData
+ wwo
->dwPartialOffset
;
369 /* convert from mono to stereo if necessary */
370 /* otherwise just memcpy to the output buffer */
372 if(wwo
->format
.wf
.nChannels
== 1)
374 sample_move_d16_d16((short*)wwo
->sound_buffer
+ ((nframes
- jackFramesAvailable
) * sizeof(short)),
375 (short*)buffer
, numFramesToWrite
, wwo
->format
.wf
.nChannels
);
376 } else /* just copy the memory over */
378 memcpy(wwo
->sound_buffer
+ ((nframes
- jackFramesAvailable
) * wwo
->format
.wf
.nBlockAlign
),
379 buffer
, numFramesToWrite
* wwo
->format
.wf
.nBlockAlign
);
382 /* advance to the next wave header if possible, or advance pointer */
383 /* inside of the current header if we haven't completed it */
384 if(numFramesToWrite
== outputFramesAvailable
)
386 wodHelper_PlayPtrNext(wwo
); /* we wrote the whole waveheader, skip to the next one*/
390 wwo
->dwPartialOffset
+=(numFramesToWrite
* wwo
->format
.wf
.nBlockAlign
); /* else advance by the bytes we took in to write */
393 written
+=(numFramesToWrite
* wwo
->format
.wf
.nBlockAlign
); /* add on what we wrote */
394 jackFramesAvailable
-=numFramesToWrite
; /* take away what was written in terms of output bytes */
397 wwo
->tickCountMS
= GetTickCount(); /* record the current time */
398 wwo
->dwWrittenTotal
+=written
; /* update states on wave device */
399 wwo
->dwPlayedTotal
+=wwo
->bytesInJack
; /* we must have finished with the last bytes or we wouldn't be back inside of this callback again... */
400 wwo
->bytesInJack
= written
; /* record the bytes inside of jack */
402 /* Now that we have finished filling the buffer either until it is full or until */
403 /* we have run out of application sound data to process, apply volume and output */
404 /* the audio to the jack server */
406 /* apply volume to the buffer */
407 volume_effect32(wwo
->sound_buffer
, (nframes
- jackFramesAvailable
), wwo
->volume_left
, wwo
->volume_right
);
409 /* convert from stereo 16 bit to single channel 32 bit float */
410 /* for each jack server channel */
411 /* NOTE: we skip over two sample since we want to only get either the left or right channel */
412 sample_move_d16_s16(out_l
, (short*)wwo
->sound_buffer
, (nframes
- jackFramesAvailable
), 2);
413 sample_move_d16_s16(out_r
, (short*)wwo
->sound_buffer
+ 1, (nframes
- jackFramesAvailable
), 2);
415 /* see if we still have jackBytesLeft here, if we do that means that we
416 ran out of wave data to play and had a buffer underrun, fill in
417 the rest of the space with zero bytes */
418 if(jackFramesAvailable
)
420 ERR("buffer underrun of %ld frames\n", jackFramesAvailable
);
421 sample_silence_dS(out_l
+ (nframes
- jackFramesAvailable
), jackFramesAvailable
);
422 sample_silence_dS(out_r
+ (nframes
- jackFramesAvailable
), jackFramesAvailable
);
425 else if(wwo
->state
== WINE_WS_PAUSED
||
426 wwo
->state
== WINE_WS_STOPPED
||
427 wwo
->state
== WINE_WS_CLOSED
)
429 /* output silence if nothing is being outputted */
430 sample_silence_dS(out_l
, nframes
);
431 sample_silence_dS(out_r
, nframes
);
434 /* notify the client of completed wave headers */
435 EnterCriticalSection(&wwo
->access_crst
);
436 wodHelper_NotifyCompletions(wwo
, FALSE
);
437 LeaveCriticalSection(&wwo
->access_crst
);
442 /******************************************************************
445 * Called whenever the jack server changes the the max number
446 * of frames passed to JACK_callback
448 int JACK_bufsize_wwo (nframes_t nframes
, void *arg
)
450 WINE_WAVEOUT
* wwo
= (WINE_WAVEOUT
*)arg
;
451 DWORD buffer_required
;
452 TRACE("wDevID=%d\n",wwo
->wDevID
);
453 TRACE("the maximum buffer size is now %u frames\n", nframes
);
455 /* make sure the callback routine has adequate memory */
456 /* see if our buffer is large enough for the data we are writing */
457 /* ie. Buffer_size < (bytes we already wrote + bytes we are going to write in this loop) */
458 EnterCriticalSection(&wwo
->access_crst
);
460 /* wwo->sound_buffer is always filled with 16-bit stereo data, even for mono streams */
461 buffer_required
= nframes
* sizeof(short) * 2;
462 TRACE("wwo->buffer_size (%ld) buffer_required (%ld).\n", wwo
->buffer_size
,buffer_required
);
463 if(wwo
->buffer_size
< buffer_required
)
465 TRACE("expanding buffer from wwo->buffer_size == %ld, to %ld\n",
466 wwo
->buffer_size
, buffer_required
);
467 TRACE("GetProcessHeap() == %p\n", GetProcessHeap());
468 wwo
->buffer_size
= buffer_required
;
470 if (wwo
->sound_buffer
)
471 wwo
->sound_buffer
= HeapReAlloc(GetProcessHeap(), 0, wwo
->sound_buffer
, wwo
->buffer_size
);
473 wwo
->sound_buffer
= HeapAlloc(GetProcessHeap(), 0, wwo
->buffer_size
);
475 /* if we don't have a buffer then error out */
476 if(!wwo
->sound_buffer
)
478 ERR("error allocating sound_buffer memory\n");
479 LeaveCriticalSection(&wwo
->access_crst
);
484 LeaveCriticalSection(&wwo
->access_crst
);
490 /******************************************************************
493 * Called whenever the jack server changes the the max number
494 * of frames passed to JACK_callback
496 int JACK_bufsize_wwi (nframes_t nframes
, void *arg
)
498 TRACE("the maximum buffer size is now %u frames\n", nframes
);
502 /******************************************************************
505 int JACK_srate (nframes_t nframes
, void *arg
)
507 TRACE("the sample rate is now %u/sec\n", nframes
);
512 /******************************************************************
515 /* if this is called then jack shut down... handle this appropriately */
516 void JACK_shutdown_wwo(void* arg
)
518 WINE_WAVEOUT
* wwo
= (WINE_WAVEOUT
*)arg
;
520 wwo
->client
= 0; /* reset client */
522 TRACE("trying to reconnect after sleeping for a short while...\n");
524 /* lets see if we can't reestablish the connection */
525 Sleep(750); /* pause for a short period of time */
526 if(!JACK_OpenWaveOutDevice(wwo
))
528 ERR("unable to reconnect with jack...\n");
532 /******************************************************************
535 /* if this is called then jack shut down... handle this appropriately */
536 void JACK_shutdown_wwi(void* arg
)
538 WINE_WAVEIN
* wwi
= (WINE_WAVEIN
*)arg
;
540 wwi
->client
= 0; /* reset client */
542 TRACE("trying to reconnect after sleeping for a short while...\n");
544 /* lets see if we can't reestablish the connection */
545 Sleep(750); /* pause for a short period of time */
546 if(!JACK_OpenWaveInDevice(wwi
,wwi
->format
.wf
.nChannels
))
548 ERR("unable to reconnect with jack...\n");
553 /******************************************************************
554 * JACK_OpenWaveOutDevice
556 static int JACK_OpenWaveOutDevice(WINE_WAVEOUT
* wwo
)
560 char client_name
[64];
561 jack_port_t
* out_port_l
;
562 jack_port_t
* out_port_r
;
563 jack_client_t
* client
;
566 TRACE("creating jack client and setting up callbacks\n");
569 /* see if this device is already open */
572 /* if this device is already in use then it is bad for us to be in here */
576 TRACE("using existing client\n");
582 /* zero out the buffer pointer and the size of the buffer */
583 wwo
->sound_buffer
= 0;
584 wwo
->buffer_size
= 0;
586 /* try to become a client of the JACK server */
587 snprintf(client_name
, sizeof(client_name
), "wine_jack_out_%d", wwo
->wDevID
);
588 TRACE("client name '%s'\n", client_name
);
589 if ((client
= fp_jack_client_new (client_name
)) == 0)
591 /* jack has problems with shutting down clients, so lets */
592 /* wait a short while and try once more before we give up */
594 if ((client
= fp_jack_client_new (client_name
)) == 0)
596 ERR("jack server not running?\n");
601 /* tell the JACK server to call `JACK_callback_wwo()' whenever
602 there is work to be done. */
603 fp_jack_set_process_callback (client
, JACK_callback_wwo
, wwo
);
605 /* tell the JACK server to call `JACK_bufsize_wwo()' whenever
606 the maximum number of frames that will be passed
607 to `JACK_Callback()' changes */
608 fp_jack_set_buffer_size_callback (client
, JACK_bufsize_wwo
, wwo
);
610 /* tell the JACK server to call `srate()' whenever
611 the sample rate of the system changes. */
612 fp_jack_set_sample_rate_callback (client
, JACK_srate
, wwo
);
614 /* tell the JACK server to call `jack_shutdown()' if
615 it ever shuts down, either entirely, or if it
616 just decides to stop calling us. */
617 fp_jack_on_shutdown (client
, JACK_shutdown_wwo
, wwo
);
619 /* display the current sample rate. once the client is activated
620 (see below), you should rely on your own sample rate
621 callback (see above) for this value. */
622 wwo
->sample_rate
= fp_jack_get_sample_rate(client
);
623 TRACE("engine sample rate: %lu\n", wwo
->sample_rate
);
625 /* create the left and right channel output ports */
626 /* jack's ports are all mono so for stereo you need two */
627 out_port_l
= fp_jack_port_register (client
, "out_l",
628 JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0);
630 out_port_r
= fp_jack_port_register (client
, "out_r",
631 JACK_DEFAULT_AUDIO_TYPE
, JackPortIsOutput
, 0);
633 TRACE("Created ports. (%p) (%p)\n",out_port_l
, out_port_r
);
635 /* save away important values to the WINE_WAVEOUT struct */
636 wwo
->client
= client
;
637 wwo
->out_port_l
= out_port_l
;
638 wwo
->out_port_r
= out_port_r
;
641 wwo
->in_use
= TRUE
; /* mark this device as in use since it now is ;-) */
644 /* set initial buffer size */
645 JACK_bufsize_wwo (fp_jack_get_buffer_size(client
),wwo
);
647 /* tell the JACK server that we are ready to roll */
648 if (fp_jack_activate (client
))
650 ERR( "cannot activate client\n");
654 TRACE("jack activate.\n");
655 /* figure out what the ports that we want to output on are */
656 /* NOTE: we do this instead of using stuff like "alsa_pcm:playback_X" because */
657 /* this way works if names are changed */
658 ports
= fp_jack_get_ports(client
, NULL
, NULL
, JackPortIsPhysical
|JackPortIsInput
);
660 /* display a trace of the output ports we found */
661 for(i
= 0; ports
[i
]; i
++)
663 TRACE("ports[%d] = '%s'\n", i
, ports
[i
]);
668 ERR("jack_get_ports() failed to find 'JackPortIsPhysical|JackPortIsInput'\n");
671 /* connect the ports. Note: you can't do this before
672 the client is activated (this may change in the future).
674 /* we want to connect to two ports so we have stereo output ;-) */
676 if(fp_jack_connect(client
, fp_jack_port_name(out_port_l
), ports
[0]))
678 ERR ("cannot connect to output port %d('%s')\n", 0, ports
[0]);
682 if(fp_jack_connect(client
, fp_jack_port_name(out_port_r
), ports
[1]))
684 ERR ("cannot connect to output port %d('%s')\n", 1, ports
[1]);
688 free(ports
); /* free the returned array of ports */
690 /* if something failed we need to shut the client down and return 0 */
694 JACK_CloseWaveOutDevice(wwo
, TRUE
);
696 JACK_CloseWaveOutDevice(wwo
);
701 return 1; /* return success */
704 /******************************************************************
705 * JACK_CloseWaveOutDevice
707 * Close the connection to the server cleanly.
708 * If close_client is TRUE we close the client for this device instead of
709 * just marking the device as in_use(JACK_CLOSE_HACK only)
712 static void JACK_CloseWaveOutDevice(WINE_WAVEOUT
* wwo
, BOOL close_client
)
714 static void JACK_CloseWaveOutDevice(WINE_WAVEOUT
* wwo
)
718 TRACE("wDevID: %d, close_client (wwo): %d\n", wwo
->wDevID
, close_client
);
720 TRACE("wDevID: %d\n", wwo
->wDevID
);
727 fp_jack_deactivate(wwo
->client
); /* supposed to help the jack_client_close() to succeed */
728 fp_jack_client_close (wwo
->client
);
730 EnterCriticalSection(&wwo
->access_crst
);
731 wwo
->client
= 0; /* reset client */
732 HeapFree(GetProcessHeap(), 0, wwo
->sound_buffer
); /* free buffer memory */
733 wwo
->sound_buffer
= 0;
734 wwo
->buffer_size
= 0; /* zero out size of the buffer */
735 LeaveCriticalSection(&wwo
->access_crst
);
739 EnterCriticalSection(&wwo
->access_crst
);
740 TRACE("setting in_use to FALSE\n");
742 LeaveCriticalSection(&wwo
->access_crst
);
747 /******************************************************************
748 * JACK_CloseWaveInDevice
750 * Close the connection to the server cleanly.
751 * If close_client is TRUE we close the client for this device instead of
752 * just marking the device as in_use(JACK_CLOSE_HACK only)
755 static void JACK_CloseWaveInDevice(WINE_WAVEIN
* wwi
, BOOL close_client
)
757 static void JACK_CloseWaveInDevice(WINE_WAVEIN
* wwi
)
761 TRACE("wDevID: %d, close_client (wwi): %d\n", wwi
->wDevID
, close_client
);
763 TRACE("wDevID: %d\n", wwi
->wDevID
);
770 fp_jack_deactivate(wwi
->client
); /* supposed to help the jack_client_close() to succeed */
771 fp_jack_client_close (wwi
->client
);
773 EnterCriticalSection(&wwi
->access_crst
);
774 wwi
->client
= 0; /* reset client */
775 HeapFree(GetProcessHeap(), 0, wwi
->sound_buffer
); /* free buffer memory */
776 wwi
->sound_buffer
= 0;
777 wwi
->buffer_size
= 0; /* zero out size of the buffer */
778 LeaveCriticalSection(&wwi
->access_crst
);
782 EnterCriticalSection(&wwi
->access_crst
);
783 TRACE("setting in_use to FALSE\n");
785 LeaveCriticalSection(&wwi
->access_crst
);
790 /******************************************************************
795 LONG
JACK_WaveRelease(void)
799 TRACE("closing all open waveout devices\n");
801 /* close all open output devices */
802 for(iDevice
= 0; iDevice
< MAX_WAVEOUTDRV
; iDevice
++)
804 TRACE("iDevice == %d\n", iDevice
);
805 if(WOutDev
[iDevice
].client
)
808 JACK_CloseWaveOutDevice(&WOutDev
[iDevice
], TRUE
); /* close the device, FORCE the client to close */
810 JACK_CloseWaveOutDevice(&WOutDev
[iDevice
]); /* close the device, FORCE the client to close */
812 DeleteCriticalSection(&(WOutDev
[iDevice
].access_crst
)); /* delete the critical section */
816 TRACE("closing all open wavein devices\n");
818 /* close all open input devices */
819 for(iDevice
= 0; iDevice
< MAX_WAVEINDRV
; iDevice
++)
821 TRACE("iDevice == %d\n", iDevice
);
822 if(WInDev
[iDevice
].client
)
825 JACK_CloseWaveInDevice(&WInDev
[iDevice
], TRUE
); /* close the device, FORCE the client to close */
827 JACK_CloseWaveInDevice(&WInDev
[iDevice
]); /* close the device, FORCE the client to close */
829 DeleteCriticalSection(&(WInDev
[iDevice
].access_crst
)); /* delete the critical section */
833 TRACE("returning 1\n");
838 /******************************************************************
841 * Initialize internal structures from JACK server info
843 LONG
JACK_WaveInit(void)
849 /* setup function pointers */
850 #define LOAD_FUNCPTR(f) if((fp_##f = wine_dlsym(jackhandle, #f, NULL, 0)) == NULL) goto sym_not_found;
851 LOAD_FUNCPTR(jack_activate
);
852 LOAD_FUNCPTR(jack_connect
);
853 LOAD_FUNCPTR(jack_client_new
);
854 LOAD_FUNCPTR(jack_client_close
);
855 LOAD_FUNCPTR(jack_deactivate
);
856 LOAD_FUNCPTR(jack_set_process_callback
);
857 LOAD_FUNCPTR(jack_set_buffer_size_callback
);
858 LOAD_FUNCPTR(jack_set_sample_rate_callback
);
859 LOAD_FUNCPTR(jack_on_shutdown
);
860 LOAD_FUNCPTR(jack_get_sample_rate
);
861 LOAD_FUNCPTR(jack_port_register
);
862 LOAD_FUNCPTR(jack_port_get_buffer
);
863 LOAD_FUNCPTR(jack_get_ports
);
864 LOAD_FUNCPTR(jack_port_name
);
865 LOAD_FUNCPTR(jack_get_buffer_size
);
868 /* start with output device */
870 for (i
= 0; i
< MAX_WAVEOUTDRV
; ++i
)
872 WOutDev
[i
].client
= 0; /* initialize the client to 0 */
875 WOutDev
[i
].in_use
= FALSE
;
876 WInDev
[i
].in_use
= FALSE
;
879 memset(&WOutDev
[i
].caps
, 0, sizeof(WOutDev
[i
].caps
));
881 /* FIXME: some programs compare this string against the content of the registry
882 * for MM drivers. The names have to match in order for the program to work
883 * (e.g. MS win9x mplayer.exe)
886 WOutDev
[i
].caps
.wMid
= 0x0002;
887 WOutDev
[i
].caps
.wPid
= 0x0104;
888 strcpy(WOutDev
[i
].caps
.szPname
, "SB16 Wave Out");
890 WOutDev
[i
].caps
.wMid
= 0x00FF; /* Manufac ID */
891 WOutDev
[i
].caps
.wPid
= 0x0001; /* Product ID */
892 /* strcpy(WOutDev[i].caps.szPname, "OpenSoundSystem WAVOUT Driver");*/
893 strcpy(WOutDev
[i
].caps
.szPname
, "CS4236/37/38");
895 WOutDev
[i
].caps
.vDriverVersion
= 0x0100;
896 WOutDev
[i
].caps
.dwFormats
= 0x00000000;
897 WOutDev
[i
].caps
.dwSupport
= WAVECAPS_VOLUME
;
899 WOutDev
[i
].caps
.wChannels
= 2;
900 WOutDev
[i
].caps
.dwSupport
|= WAVECAPS_LRVOLUME
;
902 /* NOTE: we don't support any 8 bit modes so note that */
903 /* WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;
904 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_4S08; */
905 WOutDev
[i
].caps
.dwFormats
|= WAVE_FORMAT_4S16
;
906 WOutDev
[i
].caps
.dwFormats
|= WAVE_FORMAT_4M16
;
907 /* WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;
908 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_2S08; */
909 WOutDev
[i
].caps
.dwFormats
|= WAVE_FORMAT_2M16
;
910 WOutDev
[i
].caps
.dwFormats
|= WAVE_FORMAT_2S16
;
911 /* WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;
912 WOutDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;*/
913 WOutDev
[i
].caps
.dwFormats
|= WAVE_FORMAT_1M16
;
914 WOutDev
[i
].caps
.dwFormats
|= WAVE_FORMAT_1S16
;
917 /* then do input device */
918 for (i
= 0; i
< MAX_WAVEINDRV
; ++i
)
920 /* TODO: we should initialize read stuff here */
921 memset(&WInDev
[0].caps
, 0, sizeof(WInDev
[0].caps
));
923 /* FIXME: some programs compare this string against the content of the registry
924 * for MM drivers. The names have to match in order for the program to work
925 * (e.g. MS win9x mplayer.exe)
928 WInDev
[i
].caps
.wMid
= 0x0002;
929 WInDev
[i
].caps
.wPid
= 0x0104;
930 strcpy(WInDev
[i
].caps
.szPname
, "SB16 Wave In");
932 WInDev
[i
].caps
.wMid
= 0x00FF;
933 WInDev
[i
].caps
.wPid
= 0x0001;
934 strcpy(WInDev
[i
].caps
.szPname
,"CS4236/37/38");
936 WInDev
[i
].caps
.vDriverVersion
= 0x0100;
938 WInDev
[i
].caps
.wChannels
= 0x2;
939 /* NOTE: we don't support any 8 bit modes so note that */
940 /* WInDev[i].caps.dwFormats |= WAVE_FORMAT_4M08;
941 WInDev[i].caps.dwFormats |= WAVE_FORMAT_4S08; */
942 WInDev
[i
].caps
.dwFormats
|= WAVE_FORMAT_4S16
;
943 WInDev
[i
].caps
.dwFormats
|= WAVE_FORMAT_4M16
;
944 /* WInDev[i].caps.dwFormats |= WAVE_FORMAT_2M08;
945 WInDev[i].caps.dwFormats |= WAVE_FORMAT_2S08; */
946 WInDev
[i
].caps
.dwFormats
|= WAVE_FORMAT_2M16
;
947 WInDev
[i
].caps
.dwFormats
|= WAVE_FORMAT_2S16
;
948 /* WInDev[i].caps.dwFormats |= WAVE_FORMAT_1M08;
949 WInDev[i].caps.dwFormats |= WAVE_FORMAT_1S08;*/
950 WInDev
[i
].caps
.dwFormats
|= WAVE_FORMAT_1M16
;
951 WInDev
[i
].caps
.dwFormats
|= WAVE_FORMAT_1S16
;
952 WInDev
[i
].caps
.wReserved1
= 0;
955 return 1; /* return success */
957 /* error path for function pointer loading errors */
960 "Wine cannot find certain functions that it needs inside the jack"
961 "library. To enable Wine to use the jack audio server please "
962 "install libjack\n");
963 wine_dlclose(jackhandle
, NULL
, 0);
968 /*======================================================================*
969 * Low level WAVE OUT implementation *
970 *======================================================================*/
972 /**************************************************************************
973 * wodNotifyClient [internal]
975 static DWORD
wodNotifyClient(WINE_WAVEOUT
* wwo
, WORD wMsg
, DWORD dwParam1
, DWORD dwParam2
)
977 TRACE("wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX\n", wMsg
, dwParam1
, dwParam2
);
983 if (wwo
->wFlags
!= DCB_NULL
&&
984 !DriverCallback(wwo
->waveDesc
.dwCallback
, wwo
->wFlags
,
985 (HDRVR
)wwo
->waveDesc
.hWave
, wMsg
, wwo
->waveDesc
.dwInstance
,
988 WARN("can't notify client !\n");
989 return MMSYSERR_ERROR
;
993 FIXME("Unknown callback message %u\n", wMsg
);
994 return MMSYSERR_INVALPARAM
;
996 return MMSYSERR_NOERROR
;
999 /**************************************************************************
1000 * wodHelper_BeginWaveHdr [internal]
1002 * Makes the specified lpWaveHdr the currently playing wave header.
1003 * If the specified wave header is a begin loop and we're not already in
1004 * a loop, setup the loop.
1006 static void wodHelper_BeginWaveHdr(WINE_WAVEOUT
* wwo
, LPWAVEHDR lpWaveHdr
)
1008 EnterCriticalSection(&wwo
->access_crst
);
1010 wwo
->lpPlayPtr
= lpWaveHdr
;
1014 LeaveCriticalSection(&wwo
->access_crst
);
1018 if (lpWaveHdr
->dwFlags
& WHDR_BEGINLOOP
)
1022 WARN("Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr
);
1023 TRACE("Already in a loop. Discarding loop on this header (%p)\n", lpWaveHdr
);
1026 TRACE("Starting loop (%ldx) with %p\n", lpWaveHdr
->dwLoops
, lpWaveHdr
);
1027 wwo
->lpLoopPtr
= lpWaveHdr
;
1028 /* Windows does not touch WAVEHDR.dwLoops,
1029 * so we need to make an internal copy */
1030 wwo
->dwLoops
= lpWaveHdr
->dwLoops
;
1033 wwo
->dwPartialOffset
= 0;
1035 LeaveCriticalSection(&wwo
->access_crst
);
1039 /**************************************************************************
1040 * wodHelper_PlayPtrNext [internal]
1042 * Advance the play pointer to the next waveheader, looping if required.
1044 static LPWAVEHDR
wodHelper_PlayPtrNext(WINE_WAVEOUT
* wwo
)
1046 LPWAVEHDR lpWaveHdr
;
1048 EnterCriticalSection(&wwo
->access_crst
);
1050 lpWaveHdr
= wwo
->lpPlayPtr
;
1052 wwo
->dwPartialOffset
= 0;
1053 if ((lpWaveHdr
->dwFlags
& WHDR_ENDLOOP
) && wwo
->lpLoopPtr
)
1055 /* We're at the end of a loop, loop if required */
1056 if (--wwo
->dwLoops
> 0)
1058 wwo
->lpPlayPtr
= wwo
->lpLoopPtr
;
1061 /* Handle overlapping loops correctly */
1062 if (wwo
->lpLoopPtr
!= lpWaveHdr
&& (lpWaveHdr
->dwFlags
& WHDR_BEGINLOOP
)) {
1063 FIXME("Correctly handled case ? (ending loop buffer also starts a new loop)\n");
1064 /* shall we consider the END flag for the closing loop or for
1065 * the opening one or for both ???
1066 * code assumes for closing loop only
1070 lpWaveHdr
= lpWaveHdr
->lpNext
;
1072 wwo
->lpLoopPtr
= NULL
;
1073 wodHelper_BeginWaveHdr(wwo
, lpWaveHdr
);
1077 /* We're not in a loop. Advance to the next wave header */
1078 TRACE("not inside of a loop, advancing to next wave header\n");
1079 wodHelper_BeginWaveHdr(wwo
, lpWaveHdr
= lpWaveHdr
->lpNext
);
1082 LeaveCriticalSection(&wwo
->access_crst
);
1087 /* if force is TRUE then notify the client that all the headers were completed */
1088 static DWORD
wodHelper_NotifyCompletions(WINE_WAVEOUT
* wwo
, BOOL force
)
1090 LPWAVEHDR lpWaveHdr
;
1095 EnterCriticalSection(&wwo
->access_crst
);
1097 /* Start from lpQueuePtr and keep notifying until:
1098 * - we hit an unwritten wavehdr
1099 * - we hit the beginning of a running loop
1100 * - we hit a wavehdr which hasn't finished playing
1102 while ((lpWaveHdr
= wwo
->lpQueuePtr
) &&
1104 (lpWaveHdr
!= wwo
->lpPlayPtr
&&
1105 lpWaveHdr
!= wwo
->lpLoopPtr
)))
1107 wwo
->lpQueuePtr
= lpWaveHdr
->lpNext
;
1109 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
1110 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
1111 TRACE("notifying client: lpWaveHdr=(%p) lpPlayPtr=(%p) dwFlags=(%ld)\n",
1112 lpWaveHdr
, wwo
->lpPlayPtr
, lpWaveHdr
->dwFlags
);
1114 wodNotifyClient(wwo
, WOM_DONE
, (DWORD
)lpWaveHdr
, 0);
1116 TRACE("Not notifying client: lpWaveHdr=(%p) lpPlayPtr=(%p) lpLoopPtr=(%p)\n",
1117 lpWaveHdr
, wwo
->lpPlayPtr
, wwo
->lpLoopPtr
);
1118 retval
= (lpWaveHdr
&& lpWaveHdr
!= wwo
->lpPlayPtr
&& lpWaveHdr
!=
1119 wwo
->lpLoopPtr
) ? 0 : INFINITE
;
1121 LeaveCriticalSection(&wwo
->access_crst
);
1126 /**************************************************************************
1127 * wodHelper_Reset [internal]
1129 * Resets current output stream.
1131 static void wodHelper_Reset(WINE_WAVEOUT
* wwo
, BOOL reset
)
1133 EnterCriticalSection(&wwo
->access_crst
);
1135 /* updates current notify list */
1136 wodHelper_NotifyCompletions(wwo
, FALSE
);
1140 /* remove all wave headers and notify client that all headers were completed */
1141 wodHelper_NotifyCompletions(wwo
, TRUE
);
1143 wwo
->lpPlayPtr
= wwo
->lpQueuePtr
= wwo
->lpLoopPtr
= NULL
;
1144 wwo
->state
= WINE_WS_STOPPED
;
1145 wwo
->dwPlayedTotal
= wwo
->dwWrittenTotal
= wwo
->bytesInJack
= 0;
1147 wwo
->dwPartialOffset
= 0; /* Clear partial wavehdr */
1152 /* complicated case, not handled yet (could imply modifying the loop counter) */
1153 FIXME("Pausing while in loop isn't correctly handled yet, except strange results\n");
1154 wwo
->lpPlayPtr
= wwo
->lpLoopPtr
;
1155 wwo
->dwPartialOffset
= 0;
1156 wwo
->dwWrittenTotal
= wwo
->dwPlayedTotal
; /* this is wrong !!! */
1160 DWORD sz
= wwo
->dwPartialOffset
;
1162 /* reset all the data as if we had written only up to lpPlayedTotal bytes */
1163 /* compute the max size playable from lpQueuePtr */
1164 for (ptr
= wwo
->lpQueuePtr
; ptr
!= wwo
->lpPlayPtr
; ptr
= ptr
->lpNext
)
1166 sz
+= ptr
->dwBufferLength
;
1169 /* because the reset lpPlayPtr will be lpQueuePtr */
1170 if (wwo
->dwWrittenTotal
> wwo
->dwPlayedTotal
+ sz
) ERR("doh\n");
1171 wwo
->dwPartialOffset
= sz
- (wwo
->dwWrittenTotal
- wwo
->dwPlayedTotal
);
1172 wwo
->dwWrittenTotal
= wwo
->dwPlayedTotal
;
1173 wwo
->lpPlayPtr
= wwo
->lpQueuePtr
;
1176 wwo
->state
= WINE_WS_PAUSED
;
1179 LeaveCriticalSection(&wwo
->access_crst
);
1182 /**************************************************************************
1183 * wodGetDevCaps [internal]
1185 static DWORD
wodGetDevCaps(WORD wDevID
, LPWAVEOUTCAPSA lpCaps
, DWORD dwSize
)
1187 TRACE("(%u, %p, %lu);\n", wDevID
, lpCaps
, dwSize
);
1189 if (lpCaps
== NULL
) return MMSYSERR_NOTENABLED
;
1191 if (wDevID
>= MAX_WAVEOUTDRV
)
1193 TRACE("MAX_WAVOUTDRV reached !\n");
1194 return MMSYSERR_BADDEVICEID
;
1197 TRACE("dwSupport=(0x%lx), dwFormats=(0x%lx)\n", WOutDev
[wDevID
].caps
.dwSupport
, WOutDev
[wDevID
].caps
.dwFormats
);
1198 memcpy(lpCaps
, &WOutDev
[wDevID
].caps
, min(dwSize
, sizeof(*lpCaps
)));
1199 return MMSYSERR_NOERROR
;
1202 /**************************************************************************
1203 * wodOpen [internal]
1205 * NOTE: doesn't it seem like there is a race condition if you try to open
1206 * the same device twice?
1208 static DWORD
wodOpen(WORD wDevID
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
1213 TRACE("(%u, %p, %08lX);\n", wDevID
, lpDesc
, dwFlags
);
1216 WARN("Invalid Parameter !\n");
1217 return MMSYSERR_INVALPARAM
;
1219 if (wDevID
>= MAX_WAVEOUTDRV
) {
1220 TRACE("MAX_WAVOUTDRV reached !\n");
1221 return MMSYSERR_BADDEVICEID
;
1225 if(WOutDev
[wDevID
].client
&& WOutDev
[wDevID
].in_use
)
1227 if(WOutDev
[wDevID
].client
)
1230 TRACE("device %d already allocated\n", wDevID
);
1231 return MMSYSERR_ALLOCATED
;
1234 /* make sure we aren't being opened in 8 bit mode */
1235 if(lpDesc
->lpFormat
->wBitsPerSample
== 8)
1237 TRACE("8bits per sample unsupported, returning WAVERR_BADFORMAT\n");
1238 return WAVERR_BADFORMAT
;
1241 /* only PCM format is supported so far... */
1242 if (lpDesc
->lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
||
1243 lpDesc
->lpFormat
->nChannels
== 0 ||
1244 lpDesc
->lpFormat
->nSamplesPerSec
== 0)
1246 WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%ld !\n",
1247 lpDesc
->lpFormat
->wFormatTag
, lpDesc
->lpFormat
->nChannels
,
1248 lpDesc
->lpFormat
->nSamplesPerSec
);
1249 return WAVERR_BADFORMAT
;
1252 if (dwFlags
& WAVE_FORMAT_QUERY
)
1254 TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%ld !\n",
1255 lpDesc
->lpFormat
->wFormatTag
, lpDesc
->lpFormat
->nChannels
,
1256 lpDesc
->lpFormat
->nSamplesPerSec
);
1257 return MMSYSERR_NOERROR
;
1260 wwo
= &WOutDev
[wDevID
];
1261 wwo
->wDevID
= wDevID
;
1263 /* Set things up before we call JACK_OpenWaveOutDevice because */
1264 /* we will start getting callbacks before JACK_OpenWaveOutDevice */
1265 /* even returns and we want to be initialized before then */
1266 wwo
->state
= WINE_WS_STOPPED
; /* start in a stopped state */
1267 wwo
->dwPlayedTotal
= 0; /* zero out these totals */
1268 wwo
->dwWrittenTotal
= 0;
1269 wwo
->bytesInJack
= 0;
1270 wwo
->tickCountMS
= 0;
1272 /* Initialize volume to full level */
1273 wwo
->volume_left
= 100;
1274 wwo
->volume_right
= 100;
1276 InitializeCriticalSection(&wwo
->access_crst
); /* initialize the critical section */
1277 EnterCriticalSection(&wwo
->access_crst
);
1279 dwFlags
&= ~WAVE_DIRECTSOUND
; /* direct sound not supported, ignore the flag */
1281 wwo
->wFlags
= HIWORD(dwFlags
& CALLBACK_TYPEMASK
);
1283 memcpy(&wwo
->waveDesc
, lpDesc
, sizeof(WAVEOPENDESC
));
1284 memcpy(&wwo
->format
, lpDesc
->lpFormat
, sizeof(PCMWAVEFORMAT
));
1286 /* open up jack ports for this device */
1287 if (!JACK_OpenWaveOutDevice(&WOutDev
[wDevID
]))
1289 ERR("JACK_OpenWaveOutDevice(%d) failed\n", wDevID
);
1290 LeaveCriticalSection(&wwo
->access_crst
);
1291 DeleteCriticalSection(&wwo
->access_crst
); /* delete the critical section so we can initialize it again from wodOpen() */
1292 return MMSYSERR_ERROR
; /* return unspecified error */
1295 LeaveCriticalSection(&wwo
->access_crst
);
1297 /* display the current wave format */
1298 TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%lu, nSamplesPerSec=%lu, nChannels=%u nBlockAlign=%u!\n",
1299 wwo
->format
.wBitsPerSample
, wwo
->format
.wf
.nAvgBytesPerSec
,
1300 wwo
->format
.wf
.nSamplesPerSec
, wwo
->format
.wf
.nChannels
,
1301 wwo
->format
.wf
.nBlockAlign
);
1303 /* make sure that we have the same sample rate in our audio stream */
1304 /* as we do in the jack server */
1305 if(wwo
->format
.wf
.nSamplesPerSec
!= wwo
->sample_rate
)
1307 TRACE("error: jack server sample rate is '%ld', wave sample rate is '%ld'\n",
1308 wwo
->sample_rate
, wwo
->format
.wf
.nSamplesPerSec
);
1311 JACK_CloseWaveOutDevice(wwo
, FALSE
); /* close this device, don't force the client to close */
1313 JACK_CloseWaveOutDevice(wwo
); /* close this device */
1315 DeleteCriticalSection(&wwo
->access_crst
); /* delete the critical section so we can initialize it again from wodOpen() */
1316 return WAVERR_BADFORMAT
;
1319 /* check for an invalid number of bits per sample */
1320 if (wwo
->format
.wBitsPerSample
== 0)
1322 WARN("Resetting zeroed wBitsPerSample to 16\n");
1323 wwo
->format
.wBitsPerSample
= 16 *
1324 (wwo
->format
.wf
.nAvgBytesPerSec
/
1325 wwo
->format
.wf
.nSamplesPerSec
) /
1326 wwo
->format
.wf
.nChannels
;
1329 EnterCriticalSection(&wwo
->access_crst
);
1330 retval
= wodNotifyClient(wwo
, WOM_OPEN
, 0L, 0L);
1331 LeaveCriticalSection(&wwo
->access_crst
);
1336 /**************************************************************************
1337 * wodClose [internal]
1339 static DWORD
wodClose(WORD wDevID
)
1341 DWORD ret
= MMSYSERR_NOERROR
;
1344 TRACE("(%u);\n", wDevID
);
1346 if (wDevID
>= MAX_WAVEOUTDRV
|| !WOutDev
[wDevID
].client
)
1348 WARN("bad device ID !\n");
1349 return MMSYSERR_BADDEVICEID
;
1352 wwo
= &WOutDev
[wDevID
];
1353 if (wwo
->lpQueuePtr
)
1355 WARN("buffers still playing !\n");
1356 ret
= WAVERR_STILLPLAYING
;
1359 /* sanity check: this should not happen since the device must have been reset before */
1360 if (wwo
->lpQueuePtr
|| wwo
->lpPlayPtr
) ERR("out of sync\n");
1362 wwo
->state
= WINE_WS_CLOSED
; /* mark the device as closed */
1365 JACK_CloseWaveOutDevice(wwo
, FALSE
); /* close the jack device, DO NOT force the client to close */
1367 JACK_CloseWaveOutDevice(wwo
); /* close the jack device */
1369 DeleteCriticalSection(&wwo
->access_crst
); /* delete the critical section so we can initialize it again from wodOpen() */
1371 ret
= wodNotifyClient(wwo
, WOM_CLOSE
, 0L, 0L);
1378 /**************************************************************************
1379 * wodWrite [internal]
1382 static DWORD
wodWrite(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
1387 TRACE("(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
1389 /* first, do the sanity checks... */
1390 if (wDevID
>= MAX_WAVEOUTDRV
|| !WOutDev
[wDevID
].client
)
1392 WARN("bad dev ID !\n");
1393 return MMSYSERR_BADDEVICEID
;
1396 wwo
= &WOutDev
[wDevID
];
1398 if (lpWaveHdr
->lpData
== NULL
|| !(lpWaveHdr
->dwFlags
& WHDR_PREPARED
))
1400 TRACE("unprepared\n");
1401 return WAVERR_UNPREPARED
;
1404 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
1406 TRACE("still playing\n");
1407 return WAVERR_STILLPLAYING
;
1410 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
1411 lpWaveHdr
->dwFlags
|= WHDR_INQUEUE
;
1412 lpWaveHdr
->lpNext
= 0;
1414 EnterCriticalSection(&wwo
->access_crst
);
1416 /* insert buffer at the end of queue */
1417 for (wh
= &(wwo
->lpQueuePtr
); *wh
; wh
= &((*wh
)->lpNext
));
1420 if (!wwo
->lpPlayPtr
)
1421 wodHelper_BeginWaveHdr(wwo
,lpWaveHdr
);
1422 if (wwo
->state
== WINE_WS_STOPPED
)
1423 wwo
->state
= WINE_WS_PLAYING
;
1424 LeaveCriticalSection(&wwo
->access_crst
);
1426 return MMSYSERR_NOERROR
;
1429 /**************************************************************************
1430 * wodPrepare [internal]
1432 static DWORD
wodPrepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
1434 TRACE("(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
1436 if (wDevID
>= MAX_WAVEOUTDRV
)
1438 WARN("bad device ID !\n");
1439 return MMSYSERR_BADDEVICEID
;
1442 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
1443 return WAVERR_STILLPLAYING
;
1445 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
1446 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
1447 return MMSYSERR_NOERROR
;
1450 /**************************************************************************
1451 * wodUnprepare [internal]
1453 static DWORD
wodUnprepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
1455 TRACE("(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
1457 if (wDevID
>= MAX_WAVEOUTDRV
)
1459 WARN("bad device ID !\n");
1460 return MMSYSERR_BADDEVICEID
;
1463 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
1464 return WAVERR_STILLPLAYING
;
1466 lpWaveHdr
->dwFlags
&= ~WHDR_PREPARED
;
1467 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
1469 return MMSYSERR_NOERROR
;
1472 /**************************************************************************
1473 * wodPause [internal]
1475 static DWORD
wodPause(WORD wDevID
)
1477 TRACE("(%u);!\n", wDevID
);
1479 if (wDevID
>= MAX_WAVEOUTDRV
|| !WOutDev
[wDevID
].client
)
1481 WARN("bad device ID !\n");
1482 return MMSYSERR_BADDEVICEID
;
1485 TRACE("[3-PAUSING]\n");
1487 EnterCriticalSection(&(WOutDev
[wDevID
].access_crst
));
1488 wodHelper_Reset(&WOutDev
[wDevID
], FALSE
);
1489 LeaveCriticalSection(&(WOutDev
[wDevID
].access_crst
));
1491 return MMSYSERR_NOERROR
;
1494 /**************************************************************************
1495 * wodRestart [internal]
1497 static DWORD
wodRestart(WORD wDevID
)
1499 TRACE("(%u);\n", wDevID
);
1501 if (wDevID
>= MAX_WAVEOUTDRV
|| !WOutDev
[wDevID
].client
)
1503 WARN("bad device ID !\n");
1504 return MMSYSERR_BADDEVICEID
;
1507 if (WOutDev
[wDevID
].state
== WINE_WS_PAUSED
)
1509 EnterCriticalSection(&(WOutDev
[wDevID
].access_crst
));
1510 WOutDev
[wDevID
].state
= WINE_WS_PLAYING
;
1511 LeaveCriticalSection(&(WOutDev
[wDevID
].access_crst
));
1514 return MMSYSERR_NOERROR
;
1517 /**************************************************************************
1518 * wodReset [internal]
1520 static DWORD
wodReset(WORD wDevID
)
1522 TRACE("(%u);\n", wDevID
);
1524 if (wDevID
>= MAX_WAVEOUTDRV
|| !WOutDev
[wDevID
].client
)
1526 WARN("bad device ID !\n");
1527 return MMSYSERR_BADDEVICEID
;
1530 EnterCriticalSection(&(WOutDev
[wDevID
].access_crst
));
1531 wodHelper_Reset(&WOutDev
[wDevID
], TRUE
);
1532 LeaveCriticalSection(&(WOutDev
[wDevID
].access_crst
));
1534 return MMSYSERR_NOERROR
;
1537 /**************************************************************************
1538 * wodGetPosition [internal]
1540 static DWORD
wodGetPosition(WORD wDevID
, LPMMTIME lpTime
, DWORD uSize
)
1547 TRACE("(%u, %p, %lu);\n", wDevID
, lpTime
, uSize
);
1549 if (wDevID
>= MAX_WAVEOUTDRV
|| !WOutDev
[wDevID
].client
)
1551 WARN("bad device ID !\n");
1552 return MMSYSERR_BADDEVICEID
;
1555 /* if null pointer to time structure return error */
1556 if (lpTime
== NULL
) return MMSYSERR_INVALPARAM
;
1558 wwo
= &WOutDev
[wDevID
];
1560 EnterCriticalSection(&(WOutDev
[wDevID
].access_crst
));
1561 val
= wwo
->dwPlayedTotal
;
1562 elapsedMS
= GetTickCount() - wwo
->tickCountMS
;
1563 LeaveCriticalSection(&(WOutDev
[wDevID
].access_crst
));
1565 /* account for the bytes played since the last JACK_Callback() */
1566 val
+=((elapsedMS
* wwo
->format
.wf
.nAvgBytesPerSec
) / 1000);
1568 TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%lu nChannels=%u nAvgBytesPerSec=%lu\n",
1569 lpTime
->wType
, wwo
->format
.wBitsPerSample
,
1570 wwo
->format
.wf
.nSamplesPerSec
, wwo
->format
.wf
.nChannels
,
1571 wwo
->format
.wf
.nAvgBytesPerSec
);
1572 TRACE("dwPlayedTotal=%lu\n", val
);
1574 switch (lpTime
->wType
) {
1577 TRACE("TIME_BYTES=%lu\n", lpTime
->u
.cb
);
1580 lpTime
->u
.sample
= val
* 8 / wwo
->format
.wBitsPerSample
/wwo
->format
.wf
.nChannels
;
1581 TRACE("TIME_SAMPLES=%lu\n", lpTime
->u
.sample
);
1584 time
= val
/ (wwo
->format
.wf
.nAvgBytesPerSec
/ 1000);
1585 lpTime
->u
.smpte
.hour
= time
/ 108000;
1586 time
-= lpTime
->u
.smpte
.hour
* 108000;
1587 lpTime
->u
.smpte
.min
= time
/ 1800;
1588 time
-= lpTime
->u
.smpte
.min
* 1800;
1589 lpTime
->u
.smpte
.sec
= time
/ 30;
1590 time
-= lpTime
->u
.smpte
.sec
* 30;
1591 lpTime
->u
.smpte
.frame
= time
;
1592 lpTime
->u
.smpte
.fps
= 30;
1593 TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
1594 lpTime
->u
.smpte
.hour
, lpTime
->u
.smpte
.min
,
1595 lpTime
->u
.smpte
.sec
, lpTime
->u
.smpte
.frame
);
1598 FIXME("Format %d not supported ! use TIME_MS !\n", lpTime
->wType
);
1599 lpTime
->wType
= TIME_MS
;
1601 lpTime
->u
.ms
= val
/ (wwo
->format
.wf
.nAvgBytesPerSec
/ 1000);
1602 TRACE("TIME_MS=%lu\n", lpTime
->u
.ms
);
1605 return MMSYSERR_NOERROR
;
1608 /**************************************************************************
1609 * wodBreakLoop [internal]
1611 static DWORD
wodBreakLoop(WORD wDevID
)
1613 TRACE("(%u);\n", wDevID
);
1615 if (wDevID
>= MAX_WAVEOUTDRV
|| !WOutDev
[wDevID
].client
)
1617 WARN("bad device ID !\n");
1618 return MMSYSERR_BADDEVICEID
;
1621 EnterCriticalSection(&(WOutDev
[wDevID
].access_crst
));
1623 if (WOutDev
[wDevID
].state
== WINE_WS_PLAYING
&& WOutDev
[wDevID
].lpLoopPtr
!= NULL
)
1625 /* ensure exit at end of current loop */
1626 WOutDev
[wDevID
].dwLoops
= 1;
1629 LeaveCriticalSection(&(WOutDev
[wDevID
].access_crst
));
1631 return MMSYSERR_NOERROR
;
1634 /**************************************************************************
1635 * wodGetVolume [internal]
1637 static DWORD
wodGetVolume(WORD wDevID
, LPDWORD lpdwVol
)
1641 left
= WOutDev
[wDevID
].volume_left
;
1642 right
= WOutDev
[wDevID
].volume_right
;
1644 TRACE("(%u, %p);\n", wDevID
, lpdwVol
);
1646 *lpdwVol
= ((left
* 0xFFFFl
) / 100) + (((right
* 0xFFFFl
) / 100) <<
1649 return MMSYSERR_NOERROR
;
1652 /**************************************************************************
1653 * wodSetVolume [internal]
1655 static DWORD
wodSetVolume(WORD wDevID
, DWORD dwParam
)
1659 left
= (LOWORD(dwParam
) * 100) / 0xFFFFl
;
1660 right
= (HIWORD(dwParam
) * 100) / 0xFFFFl
;
1662 TRACE("(%u, %08lX);\n", wDevID
, dwParam
);
1664 EnterCriticalSection(&(WOutDev
[wDevID
].access_crst
));
1666 WOutDev
[wDevID
].volume_left
= left
;
1667 WOutDev
[wDevID
].volume_right
= right
;
1669 LeaveCriticalSection(&(WOutDev
[wDevID
].access_crst
));
1671 return MMSYSERR_NOERROR
;
1674 /**************************************************************************
1675 * wodGetNumDevs [internal]
1677 static DWORD
wodGetNumDevs(void)
1679 return MAX_WAVEOUTDRV
;
1682 /**************************************************************************
1683 * wodMessage (WINEJACK.7)
1685 DWORD WINAPI
JACK_wodMessage(UINT wDevID
, UINT wMsg
, DWORD dwUser
,
1686 DWORD dwParam1
, DWORD dwParam2
)
1688 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
1689 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1693 TRACE("DRVM_INIT\n");
1694 return JACK_WaveInit();
1696 TRACE("DRVM_EXIT\n");
1697 return JACK_WaveRelease();
1699 /* FIXME: Pretend this is supported */
1700 TRACE("DRVM_ENABLE\n");
1703 /* FIXME: Pretend this is supported */
1704 TRACE("DRVM_DISABLE\n");
1706 case WODM_OPEN
: return wodOpen(wDevID
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
1707 case WODM_CLOSE
: return wodClose(wDevID
);
1708 case WODM_WRITE
: return wodWrite(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1709 case WODM_PAUSE
: return wodPause(wDevID
);
1710 case WODM_GETPOS
: return wodGetPosition(wDevID
, (LPMMTIME
)dwParam1
, dwParam2
);
1711 case WODM_BREAKLOOP
: return wodBreakLoop(wDevID
);
1712 case WODM_PREPARE
: return wodPrepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1713 case WODM_UNPREPARE
: return wodUnprepare(wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
1714 case WODM_GETDEVCAPS
: return wodGetDevCaps(wDevID
, (LPWAVEOUTCAPSA
)dwParam1
, dwParam2
);
1715 case WODM_GETNUMDEVS
: return wodGetNumDevs();
1716 case WODM_GETPITCH
: return MMSYSERR_NOTSUPPORTED
;
1717 case WODM_SETPITCH
: return MMSYSERR_NOTSUPPORTED
;
1718 case WODM_GETPLAYBACKRATE
: return MMSYSERR_NOTSUPPORTED
;
1719 case WODM_SETPLAYBACKRATE
: return MMSYSERR_NOTSUPPORTED
;
1720 case WODM_GETVOLUME
: return wodGetVolume(wDevID
, (LPDWORD
)dwParam1
);
1721 case WODM_SETVOLUME
: return wodSetVolume(wDevID
, dwParam1
);
1722 case WODM_RESTART
: return wodRestart(wDevID
);
1723 case WODM_RESET
: return wodReset(wDevID
);
1725 case DRV_QUERYDSOUNDIFACE
: return wodDsCreate(wDevID
, (PIDSDRIVER
*)dwParam1
);
1726 case DRV_QUERYDSOUNDDESC
: return wodDsDesc(wDevID
, (PDSDRIVERDESC
)dwParam1
);
1727 case DRV_QUERYDSOUNDGUID
: return wodDsGuid(wDevID
, (LPGUID
)dwParam1
);
1729 FIXME("unknown message %d!\n", wMsg
);
1731 return MMSYSERR_NOTSUPPORTED
;
1734 /*======================================================================*
1735 * Low level DSOUND implementation *
1736 *======================================================================*/
1738 typedef struct IDsDriverImpl IDsDriverImpl
;
1739 typedef struct IDsDriverBufferImpl IDsDriverBufferImpl
;
1741 struct IDsDriverImpl
1743 /* IUnknown fields */
1744 ICOM_VFIELD(IDsDriver
);
1746 /* IDsDriverImpl fields */
1748 IDsDriverBufferImpl
*primary
;
1751 struct IDsDriverBufferImpl
1753 /* IUnknown fields */
1754 ICOM_VFIELD(IDsDriverBuffer
);
1756 /* IDsDriverBufferImpl fields */
1761 static DWORD
wodDsCreate(UINT wDevID
, PIDSDRIVER
* drv
)
1763 /* we can't perform memory mapping as we don't have a file stream
1764 interface with jack like we do with oss */
1765 MESSAGE("This sound card's driver does not support direct access\n");
1766 MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
1767 return MMSYSERR_NOTSUPPORTED
;
1770 static DWORD
wodDsDesc(UINT wDevID
, PDSDRIVERDESC desc
)
1772 memset(desc
, 0, sizeof(*desc
));
1773 strcpy(desc
->szDesc
, "Wine jack DirectSound Driver");
1774 strcpy(desc
->szDrvName
, "winejack.drv");
1775 return MMSYSERR_NOERROR
;
1778 static DWORD
wodDsGuid(UINT wDevID
, LPGUID pGuid
)
1780 memcpy(pGuid
, &DSDEVID_DefaultPlayback
, sizeof(GUID
));
1781 return MMSYSERR_NOERROR
;
1784 /*======================================================================*
1785 * Low level WAVE IN implementation *
1786 *======================================================================*/
1788 /**************************************************************************
1789 * widNotifyClient [internal]
1791 static DWORD
widNotifyClient(WINE_WAVEIN
* wwi
, WORD wMsg
, DWORD dwParam1
, DWORD dwParam2
)
1793 TRACE("wMsg = 0x%04x dwParm1 = %04lX dwParam2 = %04lX\n", wMsg
, dwParam1
, dwParam2
);
1799 if (wwi
->wFlags
!= DCB_NULL
&&
1800 !DriverCallback(wwi
->waveDesc
.dwCallback
, wwi
->wFlags
,
1801 (HDRVR
)wwi
->waveDesc
.hWave
, wMsg
, wwi
->waveDesc
.dwInstance
,
1802 dwParam1
, dwParam2
))
1804 WARN("can't notify client !\n");
1805 return MMSYSERR_ERROR
;
1809 FIXME("Unknown callback message %u\n", wMsg
);
1810 return MMSYSERR_INVALPARAM
;
1812 return MMSYSERR_NOERROR
;
1815 /******************************************************************
1818 /* everytime the jack server wants something from us it calls this
1820 int JACK_callback_wwi (nframes_t nframes
, void *arg
)
1824 WINE_WAVEIN
* wwi
= (WINE_WAVEIN
*)arg
;
1826 TRACE("wDevID: %u, nframes %u\n", wwi
->wDevID
, nframes
);
1829 ERR("client is closed, this is weird...\n");
1831 in_l
= (sample_t
*) fp_jack_port_get_buffer(wwi
->in_port_l
, nframes
);
1834 in_r
= (sample_t
*) fp_jack_port_get_buffer(wwi
->in_port_r
, nframes
);
1836 EnterCriticalSection(&wwi
->access_crst
);
1838 if((wwi
->lpQueuePtr
!= NULL
) && (wwi
->state
== WINE_WS_PLAYING
))
1840 LPWAVEHDR lpWaveHdr
= wwi
->lpQueuePtr
;
1841 nframes_t jackFramesLeft
= nframes
;
1844 if(wwi
->in_use
== FALSE
)
1846 /* do nothing if nothing is being recorded */
1851 TRACE("wwi.state == WINE_WS_PLAYING\n");
1853 while (lpWaveHdr
&& jackFramesLeft
)
1855 DWORD waveHdrFramesLeft
= (lpWaveHdr
->dwBufferLength
- lpWaveHdr
->dwBytesRecorded
) / (sizeof(short) * wwi
->format
.wf
.nChannels
);
1856 DWORD numFrames
= min (jackFramesLeft
, waveHdrFramesLeft
);
1858 TRACE ("dwBufferLength=(%lu) dwBytesRecorded=(%ld)\n", lpWaveHdr
->dwBufferLength
, lpWaveHdr
->dwBytesRecorded
);
1859 TRACE ("jackFramesLeft=(%u) waveHdrFramesLeft=(%lu)\n", jackFramesLeft
, waveHdrFramesLeft
);
1863 sample_move_s16_d16((short *)((char *)lpWaveHdr
->lpData
+ lpWaveHdr
->dwBytesRecorded
), in_l
+(nframes
-jackFramesLeft
), numFrames
, 1);
1866 sample_move_s16_d16((short *)((char *)lpWaveHdr
->lpData
+ lpWaveHdr
->dwBytesRecorded
),
1867 in_l
+(nframes
-jackFramesLeft
), numFrames
, 2);
1868 sample_move_s16_d16((short *)((char *)lpWaveHdr
->lpData
+ lpWaveHdr
->dwBytesRecorded
+ sizeof(short)),
1869 in_r
+(nframes
-jackFramesLeft
), numFrames
, 2);
1872 lpWaveHdr
->dwBytesRecorded
+= (numFrames
* sizeof(short) * wwi
->format
.wf
.nChannels
);
1873 jackFramesLeft
-= numFrames
;
1875 if (lpWaveHdr
->dwBytesRecorded
>= lpWaveHdr
->dwBufferLength
)
1877 /* must copy the value of next waveHdr, because we have no idea of what
1878 * will be done with the content of lpWaveHdr in callback
1880 LPWAVEHDR lpNext
= lpWaveHdr
->lpNext
;
1882 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
1883 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
1885 TRACE("WaveHdr full. dwBytesRecorded=(%lu) dwFlags=(0x%lx)\n",lpWaveHdr
->dwBytesRecorded
,lpWaveHdr
->dwFlags
);
1887 widNotifyClient(wwi
, WIM_DATA
, (DWORD
)lpWaveHdr
, 0);
1889 lpWaveHdr
= wwi
->lpQueuePtr
= lpNext
;
1892 TRACE ("jackFramesLeft=(%u) lpWaveHdr=(%p)\n", jackFramesLeft
, lpWaveHdr
);
1893 if (jackFramesLeft
> 0) { WARN("Record buffer ran out of WaveHdrs\n"); }
1896 LeaveCriticalSection(&wwi
->access_crst
);
1901 /******************************************************************
1902 * JACK_OpenWaveInDevice
1904 static int JACK_OpenWaveInDevice(WINE_WAVEIN
* wwi
, WORD nChannels
)
1908 char client_name
[64];
1909 jack_port_t
* in_port_l
;
1910 jack_port_t
* in_port_r
= 0;
1911 jack_client_t
* client
;
1914 TRACE("creating jack client and setting up callbacks\n");
1916 if ((nChannels
== 0) || (nChannels
> 2)) {
1917 ERR ("nChannels = (%d), but we only support mono or stereo.\n", nChannels
);
1922 /* see if this device is already open */
1925 /* if this device is already in use then it is bad for us to be in here */
1929 TRACE("using existing client\n");
1935 /* zero out the buffer pointer and the size of the buffer */
1936 wwi
->sound_buffer
= 0;
1937 wwi
->buffer_size
= 0;
1939 /* try to become a client of the JACK server */
1940 snprintf(client_name
, sizeof(client_name
), "wine_jack_in_%d", wwi
->wDevID
);
1941 TRACE("client name '%s'\n", client_name
);
1942 if ((client
= fp_jack_client_new (client_name
)) == 0)
1944 /* jack has problems with shutting down clients, so lets */
1945 /* wait a short while and try once more before we give up */
1947 if ((client
= fp_jack_client_new (client_name
)) == 0)
1949 ERR("jack server not running?\n");
1953 wwi
->client
= client
;
1955 /* tell the JACK server to call `JACK_wwi_callback()' whenever
1956 there is work to be done. */
1957 fp_jack_set_process_callback (client
, JACK_callback_wwi
, wwi
);
1959 /* tell the JACK server to call `JACK_bufsize_wwi()' whenever
1960 the maximum number of frames that will be passed
1961 to `JACK_Callback()' changes */
1962 fp_jack_set_buffer_size_callback (client
, JACK_bufsize_wwi
, wwi
);
1964 /* tell the JACK server to call `srate()' whenever
1965 the sample rate of the system changes. */
1966 fp_jack_set_sample_rate_callback (client
, JACK_srate
, wwi
);
1968 /* tell the JACK server to call `jack_shutdown()' if
1969 it ever shuts down, either entirely, or if it
1970 just decides to stop calling us. */
1971 fp_jack_on_shutdown (client
, JACK_shutdown_wwi
, wwi
);
1973 /* display the current sample rate. once the client is activated
1974 (see below), you should rely on your own sample rate
1975 callback (see above) for this value. */
1976 wwi
->sample_rate
= fp_jack_get_sample_rate(client
);
1977 TRACE("engine sample rate: %lu\n", wwi
->sample_rate
);
1979 /* create the left and right channel output ports */
1980 /* jack's ports are all mono so for stereo you need two */
1981 in_port_l
= fp_jack_port_register (client
, "in_l",
1982 JACK_DEFAULT_AUDIO_TYPE
, JackPortIsInput
, 0);
1983 wwi
->in_port_l
= in_port_l
;
1984 TRACE("Created port. (%p)\n", in_port_l
);
1988 in_port_r
= fp_jack_port_register (client
, "in_r",
1989 JACK_DEFAULT_AUDIO_TYPE
, JackPortIsInput
, 0);
1990 TRACE("Created port. (%p)\n", in_port_r
);
1992 wwi
->in_port_r
= in_port_r
;
1995 wwi
->in_use
= TRUE
; /* mark this device as in use since it now is ;-) */
1998 TRACE("activating client.\n");
1999 /* tell the JACK server that we are ready to roll */
2000 if (fp_jack_activate (client
))
2002 ERR( "cannot activate client\n");
2005 TRACE("activated client.\n");
2006 /* figure out what the ports that we want to output on are */
2007 /* NOTE: we do this instead of using stuff like "alsa_pcm:playback_X" because */
2008 /* this way works if names are changed */
2009 ports
= fp_jack_get_ports(client
, NULL
, NULL
, JackPortIsPhysical
|JackPortIsOutput
);
2011 /* display a trace of the output ports we found */
2012 for(i
= 0; ports
[i
]; i
++)
2014 TRACE("ports[%d] = '%s'\n", i
, ports
[i
]);
2019 ERR("jack_get_ports() failed to find 'JackPortIsPhysical|JackPortIsOutput'\n");
2022 /* connect the ports. Note: you can't do this before
2023 the client is activated (this may change in the future).
2025 /* we want to connect to two ports so we have stereo input ;-) */
2027 if(fp_jack_connect(client
, ports
[0], fp_jack_port_name(in_port_l
)))
2029 ERR ("cannot connect to input port %d('%s')\n", 0, ports
[0]);
2032 TRACE("Connected (%s)<->(%s)\n",ports
[0],fp_jack_port_name(in_port_l
));
2034 if ((nChannels
== 2) && in_port_r
) {
2035 if(fp_jack_connect(client
, ports
[1], fp_jack_port_name(in_port_r
)))
2037 ERR ("cannot connect to input port %d('%s')\n", 1, ports
[1]);
2040 TRACE("Connected (%s)<->(%s)\n",ports
[1],fp_jack_port_name(in_port_r
));
2042 free(ports
); /* free the returned array of ports */
2044 /* if something failed we need to shut the client down and return 0 */
2048 JACK_CloseWaveInDevice(wwi
, TRUE
);
2050 JACK_CloseWaveInDevice(wwi
);
2055 TRACE("return success.\n");
2056 return 1; /* return success */
2059 /**************************************************************************
2060 * widGetDevCaps [internal]
2062 static DWORD
widGetDevCaps(WORD wDevID
, LPWAVEINCAPSA lpCaps
, DWORD dwSize
)
2064 TRACE("(%u, %p, %lu);\n", wDevID
, lpCaps
, dwSize
);
2066 if (lpCaps
== NULL
) return MMSYSERR_NOTENABLED
;
2068 if (wDevID
>= MAX_WAVEINDRV
) {
2069 TRACE("MAX_WAVEINDRV reached !\n");
2070 return MMSYSERR_BADDEVICEID
;
2073 memcpy(lpCaps
, &WInDev
[wDevID
].caps
, min(dwSize
, sizeof(*lpCaps
)));
2074 return MMSYSERR_NOERROR
;
2077 /**************************************************************************
2078 * widOpen [internal]
2080 static DWORD
widOpen(WORD wDevID
, LPWAVEOPENDESC lpDesc
, DWORD dwFlags
)
2085 TRACE("(%u, %p, %08lX);\n", wDevID
, lpDesc
, dwFlags
);
2088 WARN("Invalid Parameter !\n");
2089 return MMSYSERR_INVALPARAM
;
2091 if (wDevID
>= MAX_WAVEINDRV
) {
2092 TRACE ("MAX_WAVEINDRV reached !\n");
2093 return MMSYSERR_BADDEVICEID
;
2097 if(WInDev
[wDevID
].client
&& WOutDev
[wDevID
].in_use
)
2099 if(WInDev
[wDevID
].client
)
2102 TRACE("device %d already allocated\n", wDevID
);
2103 return MMSYSERR_ALLOCATED
;
2106 /* make sure we aren't being opened in 8 bit mode */
2107 if(lpDesc
->lpFormat
->wBitsPerSample
== 8)
2109 TRACE("8bits per sample unsupported, returning WAVERR_BADFORMAT\n");
2110 return WAVERR_BADFORMAT
;
2113 /* only PCM format is supported so far... */
2114 if (lpDesc
->lpFormat
->wFormatTag
!= WAVE_FORMAT_PCM
||
2115 lpDesc
->lpFormat
->nChannels
== 0 ||
2116 lpDesc
->lpFormat
->nSamplesPerSec
== 0)
2118 WARN("Bad format: tag=%04X nChannels=%d nSamplesPerSec=%ld !\n",
2119 lpDesc
->lpFormat
->wFormatTag
, lpDesc
->lpFormat
->nChannels
,
2120 lpDesc
->lpFormat
->nSamplesPerSec
);
2121 return WAVERR_BADFORMAT
;
2124 if (dwFlags
& WAVE_FORMAT_QUERY
)
2126 TRACE("Query format: tag=%04X nChannels=%d nSamplesPerSec=%ld !\n",
2127 lpDesc
->lpFormat
->wFormatTag
, lpDesc
->lpFormat
->nChannels
,
2128 lpDesc
->lpFormat
->nSamplesPerSec
);
2129 return MMSYSERR_NOERROR
;
2132 wwi
= &WInDev
[wDevID
];
2133 wwi
->wDevID
= wDevID
;
2135 /* Set things up before we call JACK_OpenWaveOutDevice because */
2136 /* we will start getting callbacks before JACK_OpenWaveOutDevice */
2137 /* even returns and we want to be initialized before then */
2138 wwi
->state
= WINE_WS_STOPPED
; /* start in a stopped state */
2140 InitializeCriticalSection(&wwi
->access_crst
); /* initialize the critical section */
2141 EnterCriticalSection(&wwi
->access_crst
);
2143 /* open up jack ports for this device */
2144 if (!JACK_OpenWaveInDevice(&WInDev
[wDevID
], lpDesc
->lpFormat
->nChannels
))
2146 ERR("JACK_OpenWaveInDevice(%d) failed\n", wDevID
);
2147 LeaveCriticalSection(&wwi
->access_crst
);
2148 DeleteCriticalSection(&wwi
->access_crst
);
2149 return MMSYSERR_ERROR
; /* return unspecified error */
2152 dwFlags
&= ~WAVE_DIRECTSOUND
; /* direct sound not supported, ignore the flag */
2154 wwi
->wFlags
= HIWORD(dwFlags
& CALLBACK_TYPEMASK
);
2156 memcpy(&wwi
->waveDesc
, lpDesc
, sizeof(WAVEOPENDESC
));
2157 memcpy(&wwi
->format
, lpDesc
->lpFormat
, sizeof(PCMWAVEFORMAT
));
2159 LeaveCriticalSection(&wwi
->access_crst
);
2161 /* display the current wave format */
2162 TRACE("wBitsPerSample=%u, nAvgBytesPerSec=%lu, nSamplesPerSec=%lu, nChannels=%u nBlockAlign=%u!\n",
2163 wwi
->format
.wBitsPerSample
, wwi
->format
.wf
.nAvgBytesPerSec
,
2164 wwi
->format
.wf
.nSamplesPerSec
, wwi
->format
.wf
.nChannels
,
2165 wwi
->format
.wf
.nBlockAlign
);
2167 /* make sure that we have the same sample rate in our audio stream */
2168 /* as we do in the jack server */
2169 if(wwi
->format
.wf
.nSamplesPerSec
!= wwi
->sample_rate
)
2171 TRACE("error: jack server sample rate is '%ld', wave sample rate is '%ld'\n",
2172 wwi
->sample_rate
, wwi
->format
.wf
.nSamplesPerSec
);
2175 JACK_CloseWaveInDevice(wwi
, FALSE
); /* close this device, don't force the client to close */
2177 JACK_CloseWaveInDevice(wwi
); /* close this device */
2179 DeleteCriticalSection(&wwi
->access_crst
);
2180 return WAVERR_BADFORMAT
;
2183 /* check for an invalid number of bits per sample */
2184 if (wwi
->format
.wBitsPerSample
== 0)
2186 WARN("Resetting zeroed wBitsPerSample to 16\n");
2187 wwi
->format
.wBitsPerSample
= 16 *
2188 (wwi
->format
.wf
.nAvgBytesPerSec
/
2189 wwi
->format
.wf
.nSamplesPerSec
) /
2190 wwi
->format
.wf
.nChannels
;
2193 TRACE("notify client.\n");
2194 EnterCriticalSection(&wwi
->access_crst
);
2195 retval
= widNotifyClient(wwi
, WIM_OPEN
, 0L, 0L);
2196 LeaveCriticalSection(&wwi
->access_crst
);
2200 /**************************************************************************
2201 * widClose [internal]
2203 static DWORD
widClose(WORD wDevID
)
2205 DWORD ret
= MMSYSERR_NOERROR
;
2208 TRACE("(%u);\n", wDevID
);
2210 if (wDevID
>= MAX_WAVEINDRV
|| !WInDev
[wDevID
].client
)
2212 WARN("bad device ID !\n");
2213 return MMSYSERR_BADDEVICEID
;
2216 wwi
= &WInDev
[wDevID
];
2217 if (wwi
->lpQueuePtr
)
2219 WARN("buffers still playing !\n");
2220 ret
= WAVERR_STILLPLAYING
;
2223 /* sanity check: this should not happen since the device must have been reset before */
2224 if (wwi
->lpQueuePtr
) ERR("out of sync\n");
2226 wwi
->state
= WINE_WS_CLOSED
; /* mark the device as closed */
2229 JACK_CloseWaveInDevice(wwi
, FALSE
); /* close the jack device, DO NOT force the client to close */
2231 JACK_CloseWaveInDevice(wwi
); /* close the jack device */
2233 DeleteCriticalSection(&wwi
->access_crst
); /* delete the critical section so we can initialize it again from wodOpen() */
2235 ret
= widNotifyClient(wwi
, WIM_CLOSE
, 0L, 0L);
2241 /**************************************************************************
2242 * widAddBuffer [internal]
2244 static DWORD
widAddBuffer(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
2246 WINE_WAVEIN
* wwi
= &WInDev
[wDevID
];
2248 TRACE("(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
2250 if (wDevID
>= MAX_WAVEINDRV
|| WInDev
[wDevID
].state
== WINE_WS_CLOSED
) {
2251 WARN("can't do it !\n");
2252 return MMSYSERR_INVALHANDLE
;
2254 if (!(lpWaveHdr
->dwFlags
& WHDR_PREPARED
)) {
2255 TRACE("never been prepared !\n");
2256 return WAVERR_UNPREPARED
;
2258 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
) {
2259 TRACE("header already in use !\n");
2260 return WAVERR_STILLPLAYING
;
2263 lpWaveHdr
->dwFlags
|= WHDR_INQUEUE
;
2264 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
2265 lpWaveHdr
->dwBytesRecorded
= 0;
2266 lpWaveHdr
->lpNext
= NULL
;
2268 EnterCriticalSection(&wwi
->access_crst
);
2269 /* insert buffer at end of queue */
2272 for (wh
= &(wwi
->lpQueuePtr
); *wh
; wh
= &((*wh
)->lpNext
));
2275 LeaveCriticalSection(&wwi
->access_crst
);
2277 return MMSYSERR_NOERROR
;
2280 /**************************************************************************
2281 * widPrepare [internal]
2283 static DWORD
widPrepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
2285 TRACE("(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
2287 if (wDevID
>= MAX_WAVEINDRV
) return MMSYSERR_INVALHANDLE
;
2289 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
)
2290 return WAVERR_STILLPLAYING
;
2292 lpWaveHdr
->dwFlags
|= WHDR_PREPARED
;
2293 lpWaveHdr
->dwFlags
&= ~WHDR_DONE
;
2294 lpWaveHdr
->dwBytesRecorded
= 0;
2295 lpWaveHdr
->lpNext
= NULL
;
2297 return MMSYSERR_NOERROR
;
2300 /**************************************************************************
2301 * widUnprepare [internal]
2303 static DWORD
widUnprepare(WORD wDevID
, LPWAVEHDR lpWaveHdr
, DWORD dwSize
)
2305 TRACE("(%u, %p, %08lX);\n", wDevID
, lpWaveHdr
, dwSize
);
2306 if (wDevID
>= MAX_WAVEINDRV
) {
2307 WARN("bad device ID !\n");
2308 return MMSYSERR_INVALHANDLE
;
2311 if (lpWaveHdr
->dwFlags
& WHDR_INQUEUE
) {
2312 TRACE("Still playing...\n");
2313 return WAVERR_STILLPLAYING
;
2316 lpWaveHdr
->dwFlags
&= ~WHDR_PREPARED
;
2317 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
2319 return MMSYSERR_NOERROR
;
2322 /**************************************************************************
2323 * widStart [internal]
2325 static DWORD
widStart(WORD wDevID
)
2327 TRACE("(%u);\n", wDevID
);
2328 if (wDevID
>= MAX_WAVEINDRV
|| WInDev
[wDevID
].state
== WINE_WS_CLOSED
) {
2329 WARN("can't start recording !\n");
2330 return MMSYSERR_INVALHANDLE
;
2333 WInDev
[wDevID
].state
= WINE_WS_PLAYING
;
2334 return MMSYSERR_NOERROR
;
2337 /**************************************************************************
2338 * widStop [internal]
2340 static DWORD
widStop(WORD wDevID
)
2342 WINE_WAVEIN
* wwi
= &WInDev
[wDevID
];
2344 TRACE("(%u);\n", wDevID
);
2345 if (wDevID
>= MAX_WAVEINDRV
|| WInDev
[wDevID
].state
== WINE_WS_CLOSED
) {
2346 WARN("can't stop !\n");
2347 return MMSYSERR_INVALHANDLE
;
2350 if (wwi
->state
!= WINE_WS_STOPPED
)
2353 /* do something here to stop recording ??? */
2355 /* return current buffer to app */
2356 lpWaveHdr
= wwi
->lpQueuePtr
;
2359 LPWAVEHDR lpNext
= lpWaveHdr
->lpNext
;
2360 TRACE("stop %p %p\n", lpWaveHdr
, lpWaveHdr
->lpNext
);
2361 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
2362 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
2363 widNotifyClient(wwi
, WIM_DATA
, (DWORD
)lpWaveHdr
, 0);
2364 wwi
->lpQueuePtr
= lpNext
;
2367 wwi
->state
= WINE_WS_STOPPED
;
2369 return MMSYSERR_NOERROR
;
2372 /**************************************************************************
2373 * widReset [internal]
2375 static DWORD
widReset(WORD wDevID
)
2377 WINE_WAVEIN
* wwi
= &WInDev
[wDevID
];
2380 TRACE("(%u);\n", wDevID
);
2381 if (wDevID
>= MAX_WAVEINDRV
|| WInDev
[wDevID
].state
== WINE_WS_CLOSED
) {
2382 WARN("can't reset !\n");
2383 return MMSYSERR_INVALHANDLE
;
2386 wwi
->state
= WINE_WS_STOPPED
;
2388 /* return all buffers to the app */
2389 for (lpWaveHdr
= wwi
->lpQueuePtr
; lpWaveHdr
; lpWaveHdr
= lpWaveHdr
->lpNext
) {
2390 TRACE("reset %p %p\n", lpWaveHdr
, lpWaveHdr
->lpNext
);
2391 lpWaveHdr
->dwFlags
&= ~WHDR_INQUEUE
;
2392 lpWaveHdr
->dwFlags
|= WHDR_DONE
;
2394 widNotifyClient(wwi
, WIM_DATA
, (DWORD
)lpWaveHdr
, 0);
2396 wwi
->lpQueuePtr
= NULL
;
2398 return MMSYSERR_NOERROR
;
2401 /**************************************************************************
2402 * widMessage (WINEJACK.6)
2404 DWORD WINAPI
JACK_widMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
2405 DWORD dwParam1
, DWORD dwParam2
)
2407 TRACE("(%u, %04X, %08lX, %08lX, %08lX);\n",
2408 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
2415 /* FIXME: Pretend this is supported */
2417 case WIDM_OPEN
: return widOpen (wDevID
, (LPWAVEOPENDESC
)dwParam1
, dwParam2
);
2418 case WIDM_CLOSE
: return widClose (wDevID
);
2419 case WIDM_ADDBUFFER
: return widAddBuffer (wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
2420 case WIDM_PREPARE
: return widPrepare (wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
2421 case WIDM_UNPREPARE
: return widUnprepare (wDevID
, (LPWAVEHDR
)dwParam1
, dwParam2
);
2422 case WIDM_GETDEVCAPS
: return widGetDevCaps (wDevID
, (LPWAVEINCAPSA
)dwParam1
, dwParam2
);
2423 case WIDM_GETNUMDEVS
: return MAX_WAVEINDRV
;
2424 case WIDM_RESET
: return widReset (wDevID
);
2425 case WIDM_START
: return widStart (wDevID
);
2426 case WIDM_STOP
: return widStop (wDevID
);
2428 FIXME("unknown message %d!\n", wMsg
);
2431 return MMSYSERR_NOTSUPPORTED
;
2434 #else /* !HAVE_JACK_JACK_H */
2436 DWORD WINAPI
JACK_widMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
2437 DWORD dwParam1
, DWORD dwParam2
)
2439 FIXME("(%u, %04X, %08lX, %08lX, %08lX):jack support not compiled into wine\n", wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
2440 return MMSYSERR_NOTENABLED
;
2443 /**************************************************************************
2444 * wodMessage (WINEJACK.7)
2446 DWORD WINAPI
JACK_wodMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
2447 DWORD dwParam1
, DWORD dwParam2
)
2449 FIXME("(%u, %04X, %08lX, %08lX, %08lX):jack support not compiled into wine\n", wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
2450 return MMSYSERR_NOTENABLED
;
2453 #endif /* HAVE_JACK_JACK_H */