4 * Copyright 2002 Eric Pouech
5 * Copyright 2007 Maarten Lankhorst
7 * This file has a few shared generic subroutines shared among the alsa
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
43 #include "wine/library.h"
44 #include "wine/unicode.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(alsa
);
48 /* unless someone makes a wineserver kernel module, Unix pipes are faster than win32 events */
52 #define INIT_OMR(omr) do { if (pipe(omr->msg_pipe) < 0) { omr->msg_pipe[0] = omr->msg_pipe[1] = -1; } } while (0)
53 #define CLOSE_OMR(omr) do { close(omr->msg_pipe[0]); close(omr->msg_pipe[1]); } while (0)
54 #define SIGNAL_OMR(omr) do { int x = 0; write((omr)->msg_pipe[1], &x, sizeof(x)); } while (0)
55 #define CLEAR_OMR(omr) do { int x = 0; read((omr)->msg_pipe[0], &x, sizeof(x)); } while (0)
56 #define RESET_OMR(omr) do { } while (0)
57 #define WAIT_OMR(omr, sleep) \
58 do { struct pollfd pfd; pfd.fd = (omr)->msg_pipe[0]; \
59 pfd.events = POLLIN; poll(&pfd, 1, sleep); } while (0)
61 #define INIT_OMR(omr) do { omr->msg_event = CreateEventW(NULL, FALSE, FALSE, NULL); } while (0)
62 #define CLOSE_OMR(omr) do { CloseHandle(omr->msg_event); } while (0)
63 #define SIGNAL_OMR(omr) do { SetEvent((omr)->msg_event); } while (0)
64 #define CLEAR_OMR(omr) do { } while (0)
65 #define RESET_OMR(omr) do { ResetEvent((omr)->msg_event); } while (0)
66 #define WAIT_OMR(omr, sleep) \
67 do { WaitForSingleObject((omr)->msg_event, sleep); } while (0)
70 #define ALSA_RING_BUFFER_INCREMENT 64
72 /******************************************************************
73 * ALSA_InitRingMessage
75 * Initialize the ring of messages for passing between driver's caller and playback/record
78 int ALSA_InitRingMessage(ALSA_MSG_RING
* omr
)
83 omr
->ring_buffer_size
= ALSA_RING_BUFFER_INCREMENT
;
84 omr
->messages
= HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY
,omr
->ring_buffer_size
* sizeof(ALSA_MSG
));
86 InitializeCriticalSection(&omr
->msg_crst
);
87 omr
->msg_crst
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": ALSA_MSG_RING.msg_crst");
91 /******************************************************************
92 * ALSA_DestroyRingMessage
95 int ALSA_DestroyRingMessage(ALSA_MSG_RING
* omr
)
98 HeapFree(GetProcessHeap(),0,omr
->messages
);
99 omr
->ring_buffer_size
= 0;
100 omr
->msg_crst
.DebugInfo
->Spare
[0] = 0;
101 DeleteCriticalSection(&omr
->msg_crst
);
104 /******************************************************************
105 * ALSA_ResetRingMessage
108 void ALSA_ResetRingMessage(ALSA_MSG_RING
* omr
)
113 /******************************************************************
114 * ALSA_WaitRingMessage
117 void ALSA_WaitRingMessage(ALSA_MSG_RING
* omr
, DWORD sleep
)
119 WAIT_OMR(omr
, sleep
);
122 /******************************************************************
123 * ALSA_AddRingMessage
125 * Inserts a new message into the ring (should be called from DriverProc derived routines)
127 int ALSA_AddRingMessage(ALSA_MSG_RING
* omr
, enum win_wm_message msg
, DWORD_PTR param
, BOOL wait
)
129 HANDLE hEvent
= INVALID_HANDLE_VALUE
;
131 EnterCriticalSection(&omr
->msg_crst
);
132 if ((omr
->msg_toget
== ((omr
->msg_tosave
+ 1) % omr
->ring_buffer_size
)))
134 int old_ring_buffer_size
= omr
->ring_buffer_size
;
135 omr
->ring_buffer_size
+= ALSA_RING_BUFFER_INCREMENT
;
136 omr
->messages
= HeapReAlloc(GetProcessHeap(),0,omr
->messages
, omr
->ring_buffer_size
* sizeof(ALSA_MSG
));
137 /* Now we need to rearrange the ring buffer so that the new
138 buffers just allocated are in between omr->msg_tosave and
141 if (omr
->msg_tosave
< omr
->msg_toget
)
143 memmove(&(omr
->messages
[omr
->msg_toget
+ ALSA_RING_BUFFER_INCREMENT
]),
144 &(omr
->messages
[omr
->msg_toget
]),
145 sizeof(ALSA_MSG
)*(old_ring_buffer_size
- omr
->msg_toget
)
147 omr
->msg_toget
+= ALSA_RING_BUFFER_INCREMENT
;
152 hEvent
= CreateEventW(NULL
, FALSE
, FALSE
, NULL
);
153 if (hEvent
== INVALID_HANDLE_VALUE
)
155 ERR("can't create event !?\n");
156 LeaveCriticalSection(&omr
->msg_crst
);
159 if (omr
->msg_toget
!= omr
->msg_tosave
&& omr
->messages
[omr
->msg_toget
].msg
!= WINE_WM_HEADER
)
160 FIXME("two fast messages in the queue!!!! toget = %d(%s), tosave=%d(%s)\n",
161 omr
->msg_toget
,ALSA_getCmdString(omr
->messages
[omr
->msg_toget
].msg
),
162 omr
->msg_tosave
,ALSA_getCmdString(omr
->messages
[omr
->msg_tosave
].msg
));
164 /* fast messages have to be added at the start of the queue */
165 omr
->msg_toget
= (omr
->msg_toget
+ omr
->ring_buffer_size
- 1) % omr
->ring_buffer_size
;
167 omr
->messages
[omr
->msg_toget
].msg
= msg
;
168 omr
->messages
[omr
->msg_toget
].param
= param
;
169 omr
->messages
[omr
->msg_toget
].hEvent
= hEvent
;
173 omr
->messages
[omr
->msg_tosave
].msg
= msg
;
174 omr
->messages
[omr
->msg_tosave
].param
= param
;
175 omr
->messages
[omr
->msg_tosave
].hEvent
= INVALID_HANDLE_VALUE
;
176 omr
->msg_tosave
= (omr
->msg_tosave
+ 1) % omr
->ring_buffer_size
;
178 LeaveCriticalSection(&omr
->msg_crst
);
179 /* signal a new message */
183 /* wait for playback/record thread to have processed the message */
184 WaitForSingleObject(hEvent
, INFINITE
);
190 /******************************************************************
191 * ALSA_RetrieveRingMessage
193 * Get a message from the ring. Should be called by the playback/record thread.
195 int ALSA_RetrieveRingMessage(ALSA_MSG_RING
* omr
, enum win_wm_message
*msg
,
196 DWORD_PTR
*param
, HANDLE
*hEvent
)
198 EnterCriticalSection(&omr
->msg_crst
);
200 if (omr
->msg_toget
== omr
->msg_tosave
) /* buffer empty ? */
202 LeaveCriticalSection(&omr
->msg_crst
);
206 *msg
= omr
->messages
[omr
->msg_toget
].msg
;
207 omr
->messages
[omr
->msg_toget
].msg
= 0;
208 *param
= omr
->messages
[omr
->msg_toget
].param
;
209 *hEvent
= omr
->messages
[omr
->msg_toget
].hEvent
;
210 omr
->msg_toget
= (omr
->msg_toget
+ 1) % omr
->ring_buffer_size
;
212 LeaveCriticalSection(&omr
->msg_crst
);
216 /*======================================================================*
217 * Utility functions *
218 *======================================================================*/
220 /* These strings used only for tracing */
221 const char * ALSA_getCmdString(enum win_wm_message msg
)
223 static char unknown
[32];
224 #define MSG_TO_STR(x) case x: return #x
226 MSG_TO_STR(WINE_WM_PAUSING
);
227 MSG_TO_STR(WINE_WM_RESTARTING
);
228 MSG_TO_STR(WINE_WM_RESETTING
);
229 MSG_TO_STR(WINE_WM_HEADER
);
230 MSG_TO_STR(WINE_WM_UPDATE
);
231 MSG_TO_STR(WINE_WM_BREAKLOOP
);
232 MSG_TO_STR(WINE_WM_CLOSING
);
233 MSG_TO_STR(WINE_WM_STARTING
);
234 MSG_TO_STR(WINE_WM_STOPPING
);
237 sprintf(unknown
, "UNKNOWN(0x%08x)", msg
);
241 const char * ALSA_getMessage(UINT msg
)
243 static char unknown
[32];
244 #define MSG_TO_STR(x) case x: return #x
246 MSG_TO_STR(DRVM_INIT
);
247 MSG_TO_STR(DRVM_EXIT
);
248 MSG_TO_STR(DRVM_ENABLE
);
249 MSG_TO_STR(DRVM_DISABLE
);
250 MSG_TO_STR(WIDM_OPEN
);
251 MSG_TO_STR(WIDM_CLOSE
);
252 MSG_TO_STR(WIDM_ADDBUFFER
);
253 MSG_TO_STR(WIDM_PREPARE
);
254 MSG_TO_STR(WIDM_UNPREPARE
);
255 MSG_TO_STR(WIDM_GETDEVCAPS
);
256 MSG_TO_STR(WIDM_GETNUMDEVS
);
257 MSG_TO_STR(WIDM_GETPOS
);
258 MSG_TO_STR(WIDM_RESET
);
259 MSG_TO_STR(WIDM_START
);
260 MSG_TO_STR(WIDM_STOP
);
261 MSG_TO_STR(WODM_OPEN
);
262 MSG_TO_STR(WODM_CLOSE
);
263 MSG_TO_STR(WODM_WRITE
);
264 MSG_TO_STR(WODM_PAUSE
);
265 MSG_TO_STR(WODM_GETPOS
);
266 MSG_TO_STR(WODM_BREAKLOOP
);
267 MSG_TO_STR(WODM_PREPARE
);
268 MSG_TO_STR(WODM_UNPREPARE
);
269 MSG_TO_STR(WODM_GETDEVCAPS
);
270 MSG_TO_STR(WODM_GETNUMDEVS
);
271 MSG_TO_STR(WODM_GETPITCH
);
272 MSG_TO_STR(WODM_SETPITCH
);
273 MSG_TO_STR(WODM_GETPLAYBACKRATE
);
274 MSG_TO_STR(WODM_SETPLAYBACKRATE
);
275 MSG_TO_STR(WODM_GETVOLUME
);
276 MSG_TO_STR(WODM_SETVOLUME
);
277 MSG_TO_STR(WODM_RESTART
);
278 MSG_TO_STR(WODM_RESET
);
279 MSG_TO_STR(DRV_QUERYDEVICEINTERFACESIZE
);
280 MSG_TO_STR(DRV_QUERYDEVICEINTERFACE
);
281 MSG_TO_STR(DRV_QUERYDSOUNDIFACE
);
282 MSG_TO_STR(DRV_QUERYDSOUNDDESC
);
285 sprintf(unknown
, "UNKNOWN(0x%04x)", msg
);
289 const char * ALSA_getFormat(WORD wFormatTag
)
291 static char unknown
[32];
292 #define FMT_TO_STR(x) case x: return #x
294 FMT_TO_STR(WAVE_FORMAT_PCM
);
295 FMT_TO_STR(WAVE_FORMAT_EXTENSIBLE
);
296 FMT_TO_STR(WAVE_FORMAT_MULAW
);
297 FMT_TO_STR(WAVE_FORMAT_ALAW
);
298 FMT_TO_STR(WAVE_FORMAT_ADPCM
);
301 sprintf(unknown
, "UNKNOWN(0x%04x)", wFormatTag
);
305 /* Allow 1% deviation for sample rates (some ES137x cards) */
306 BOOL
ALSA_NearMatch(int rate1
, int rate2
)
308 return (((100 * (rate1
- rate2
)) / rate1
) == 0);
311 DWORD
ALSA_bytes_to_mmtime(LPMMTIME lpTime
, DWORD position
, WAVEFORMATPCMEX
* format
)
313 TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%u nChannels=%u nAvgBytesPerSec=%u\n",
314 lpTime
->wType
, format
->Format
.wBitsPerSample
, format
->Format
.nSamplesPerSec
,
315 format
->Format
.nChannels
, format
->Format
.nAvgBytesPerSec
);
316 TRACE("Position in bytes=%u\n", position
);
318 switch (lpTime
->wType
) {
320 lpTime
->u
.sample
= position
/ (format
->Format
.wBitsPerSample
/ 8 * format
->Format
.nChannels
);
321 TRACE("TIME_SAMPLES=%u\n", lpTime
->u
.sample
);
324 lpTime
->u
.ms
= 1000.0 * position
/ (format
->Format
.wBitsPerSample
/ 8 * format
->Format
.nChannels
* format
->Format
.nSamplesPerSec
);
325 TRACE("TIME_MS=%u\n", lpTime
->u
.ms
);
328 lpTime
->u
.smpte
.fps
= 30;
329 position
= position
/ (format
->Format
.wBitsPerSample
/ 8 * format
->Format
.nChannels
);
330 position
+= (format
->Format
.nSamplesPerSec
/ lpTime
->u
.smpte
.fps
) - 1; /* round up */
331 lpTime
->u
.smpte
.sec
= position
/ format
->Format
.nSamplesPerSec
;
332 position
-= lpTime
->u
.smpte
.sec
* format
->Format
.nSamplesPerSec
;
333 lpTime
->u
.smpte
.min
= lpTime
->u
.smpte
.sec
/ 60;
334 lpTime
->u
.smpte
.sec
-= 60 * lpTime
->u
.smpte
.min
;
335 lpTime
->u
.smpte
.hour
= lpTime
->u
.smpte
.min
/ 60;
336 lpTime
->u
.smpte
.min
-= 60 * lpTime
->u
.smpte
.hour
;
337 lpTime
->u
.smpte
.fps
= 30;
338 lpTime
->u
.smpte
.frame
= position
* lpTime
->u
.smpte
.fps
/ format
->Format
.nSamplesPerSec
;
339 TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
340 lpTime
->u
.smpte
.hour
, lpTime
->u
.smpte
.min
,
341 lpTime
->u
.smpte
.sec
, lpTime
->u
.smpte
.frame
);
344 WARN("Format %d not supported, using TIME_BYTES !\n", lpTime
->wType
);
345 lpTime
->wType
= TIME_BYTES
;
348 lpTime
->u
.cb
= position
;
349 TRACE("TIME_BYTES=%u\n", lpTime
->u
.cb
);
352 return MMSYSERR_NOERROR
;
355 void ALSA_copyFormat(LPWAVEFORMATEX wf1
, LPWAVEFORMATPCMEX wf2
)
357 unsigned int iLength
;
359 ZeroMemory(wf2
, sizeof(wf2
));
360 if (wf1
->wFormatTag
== WAVE_FORMAT_PCM
)
361 iLength
= sizeof(PCMWAVEFORMAT
);
362 else if (wf1
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
)
363 iLength
= sizeof(WAVEFORMATPCMEX
);
365 iLength
= sizeof(WAVEFORMATEX
) + wf1
->cbSize
;
366 if (iLength
> sizeof(WAVEFORMATPCMEX
)) {
367 ERR("calculated %u bytes, capping\n", iLength
);
368 iLength
= sizeof(WAVEFORMATPCMEX
);
370 memcpy(wf2
, wf1
, iLength
);
373 BOOL
ALSA_supportedFormat(LPWAVEFORMATEX wf
)
377 if (wf
->nSamplesPerSec
<DSBFREQUENCY_MIN
||wf
->nSamplesPerSec
>DSBFREQUENCY_MAX
)
380 if (wf
->wFormatTag
== WAVE_FORMAT_PCM
) {
381 if (wf
->nChannels
==1||wf
->nChannels
==2) {
382 if (wf
->wBitsPerSample
==8||wf
->wBitsPerSample
==16)
385 } else if (wf
->wFormatTag
== WAVE_FORMAT_EXTENSIBLE
) {
386 WAVEFORMATEXTENSIBLE
* wfex
= (WAVEFORMATEXTENSIBLE
*)wf
;
388 if (wf
->cbSize
== 22 &&
389 (IsEqualGUID(&wfex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_PCM
) ||
390 IsEqualGUID(&wfex
->SubFormat
, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT
))) {
391 if (wf
->nChannels
>=1 && wf
->nChannels
<=6) {
392 if (wf
->wBitsPerSample
==wfex
->Samples
.wValidBitsPerSample
) {
393 if (wf
->wBitsPerSample
==8||wf
->wBitsPerSample
==16||
394 wf
->wBitsPerSample
==24||wf
->wBitsPerSample
==32) {
398 WARN("wBitsPerSample != wValidBitsPerSample not supported yet\n");
401 WARN("only KSDATAFORMAT_SUBTYPE_PCM and KSDATAFORMAT_SUBTYPE_IEEE_FLOAT "
403 } else if (wf
->wFormatTag
== WAVE_FORMAT_MULAW
|| wf
->wFormatTag
== WAVE_FORMAT_ALAW
) {
404 if (wf
->wBitsPerSample
==8)
407 ERR("WAVE_FORMAT_MULAW and WAVE_FORMAT_ALAW wBitsPerSample must = 8\n");
409 } else if (wf
->wFormatTag
== WAVE_FORMAT_ADPCM
) {
410 if (wf
->wBitsPerSample
==4)
413 ERR("WAVE_FORMAT_ADPCM wBitsPerSample must = 4\n");
415 WARN("only WAVE_FORMAT_PCM and WAVE_FORMAT_EXTENSIBLE supported\n");
420 /*======================================================================*
421 * Low level WAVE implementation *
422 *======================================================================*/
424 /**************************************************************************
425 * ALSA_CheckSetVolume [internal]
427 * Helper function for Alsa volume queries. This tries to simplify
428 * the process of managing the volume. All parameters are optional
429 * (pass NULL to ignore or not use).
430 * Return values are MMSYSERR_NOERROR on success, or !0 on failure;
431 * error codes are normalized into the possible documented return
432 * values from waveOutGetVolume.
434 int ALSA_CheckSetVolume(snd_hctl_t
*hctl
, int *out_left
, int *out_right
,
435 int *out_min
, int *out_max
, int *out_step
,
436 int *new_left
, int *new_right
)
438 int rc
= MMSYSERR_NOERROR
;
440 snd_hctl_elem_t
* elem
= NULL
;
441 snd_ctl_elem_info_t
* eleminfop
= NULL
;
442 snd_ctl_elem_value_t
* elemvaluep
= NULL
;
443 snd_ctl_elem_id_t
* elemidp
= NULL
;
446 #define EXIT_ON_ERROR(f,txt,exitcode) do \
449 if ( (err = (f) ) < 0) \
451 ERR(txt " failed: %s\n", snd_strerror(err)); \
458 return MMSYSERR_NOTSUPPORTED
;
460 /* Allocate areas to return information about the volume */
461 EXIT_ON_ERROR(snd_ctl_elem_id_malloc(&elemidp
), "snd_ctl_elem_id_malloc", MMSYSERR_NOMEM
);
462 EXIT_ON_ERROR(snd_ctl_elem_value_malloc (&elemvaluep
), "snd_ctl_elem_value_malloc", MMSYSERR_NOMEM
);
463 EXIT_ON_ERROR(snd_ctl_elem_info_malloc (&eleminfop
), "snd_ctl_elem_info_malloc", MMSYSERR_NOMEM
);
464 snd_ctl_elem_id_clear(elemidp
);
465 snd_ctl_elem_value_clear(elemvaluep
);
466 snd_ctl_elem_info_clear(eleminfop
);
468 /* Setup and find an element id that exactly matches the characteristic we want
469 ** FIXME: It is probably short sighted to hard code and fixate on PCM Playback Volume */
470 snd_ctl_elem_id_set_name(elemidp
, "PCM Playback Volume");
471 snd_ctl_elem_id_set_interface(elemidp
, SND_CTL_ELEM_IFACE_MIXER
);
472 elem
= snd_hctl_find_elem(hctl
, elemidp
);
475 /* Read and return volume information */
476 EXIT_ON_ERROR(snd_hctl_elem_info(elem
, eleminfop
), "snd_hctl_elem_info", MMSYSERR_NOTSUPPORTED
);
477 value_count
= snd_ctl_elem_info_get_count(eleminfop
);
478 if (out_min
|| out_max
|| out_step
)
480 if (!snd_ctl_elem_info_is_readable(eleminfop
))
482 ERR("snd_ctl_elem_info_is_readable returned false; cannot return info\n");
483 rc
= MMSYSERR_NOTSUPPORTED
;
488 *out_min
= snd_ctl_elem_info_get_min(eleminfop
);
491 *out_max
= snd_ctl_elem_info_get_max(eleminfop
);
494 *out_step
= snd_ctl_elem_info_get_step(eleminfop
);
497 if (out_left
|| out_right
)
499 EXIT_ON_ERROR(snd_hctl_elem_read(elem
, elemvaluep
), "snd_hctl_elem_read", MMSYSERR_NOTSUPPORTED
);
502 *out_left
= snd_ctl_elem_value_get_integer(elemvaluep
, 0);
506 if (value_count
== 1)
507 *out_right
= snd_ctl_elem_value_get_integer(elemvaluep
, 0);
508 else if (value_count
== 2)
509 *out_right
= snd_ctl_elem_value_get_integer(elemvaluep
, 1);
512 ERR("Unexpected value count %d from snd_ctl_elem_info_get_count while getting volume info\n", value_count
);
520 if (new_left
|| new_right
)
522 EXIT_ON_ERROR(snd_hctl_elem_read(elem
, elemvaluep
), "snd_hctl_elem_read", MMSYSERR_NOTSUPPORTED
);
524 snd_ctl_elem_value_set_integer(elemvaluep
, 0, *new_left
);
527 if (value_count
== 1)
528 snd_ctl_elem_value_set_integer(elemvaluep
, 0, *new_right
);
529 else if (value_count
== 2)
530 snd_ctl_elem_value_set_integer(elemvaluep
, 1, *new_right
);
533 ERR("Unexpected value count %d from snd_ctl_elem_info_get_count while setting volume info\n", value_count
);
539 EXIT_ON_ERROR(snd_hctl_elem_write(elem
, elemvaluep
), "snd_hctl_elem_write", MMSYSERR_NOTSUPPORTED
);
544 ERR("Could not find 'PCM Playback Volume' element\n");
545 rc
= MMSYSERR_NOTSUPPORTED
;
554 snd_ctl_elem_value_free(elemvaluep
);
556 snd_ctl_elem_info_free(eleminfop
);
558 snd_ctl_elem_id_free(elemidp
);
564 /**************************************************************************
565 * ALSA_XRUNRecovery [internal]
567 * used to recovery from XRUN errors (buffer underflow/overflow)
569 int ALSA_XRUNRecovery(WINE_WAVEDEV
* wwo
, int err
)
571 if (err
== -EPIPE
) { /* under-run */
572 err
= snd_pcm_prepare(wwo
->pcm
);
574 ERR( "underrun recovery failed. prepare failed: %s\n", snd_strerror(err
));
576 } else if (err
== -ESTRPIPE
) {
577 while ((err
= snd_pcm_resume(wwo
->pcm
)) == -EAGAIN
)
578 sleep(1); /* wait until the suspend flag is released */
580 err
= snd_pcm_prepare(wwo
->pcm
);
582 ERR("recovery from suspend failed, prepare failed: %s\n", snd_strerror(err
));
589 /**************************************************************************
590 * ALSA_TraceParameters [internal]
592 * used to trace format changes, hw and sw parameters
594 void ALSA_TraceParameters(snd_pcm_hw_params_t
* hw_params
, snd_pcm_sw_params_t
* sw
, int full
)
597 snd_pcm_format_t format
;
598 snd_pcm_access_t access
;
600 #define X(x) ((x)? "true" : "false")
602 TRACE("FLAGS: sampleres=%s overrng=%s pause=%s resume=%s syncstart=%s batch=%s block=%s double=%s "
603 "halfd=%s joint=%s\n",
604 X(snd_pcm_hw_params_can_mmap_sample_resolution(hw_params
)),
605 X(snd_pcm_hw_params_can_overrange(hw_params
)),
606 X(snd_pcm_hw_params_can_pause(hw_params
)),
607 X(snd_pcm_hw_params_can_resume(hw_params
)),
608 X(snd_pcm_hw_params_can_sync_start(hw_params
)),
609 X(snd_pcm_hw_params_is_batch(hw_params
)),
610 X(snd_pcm_hw_params_is_block_transfer(hw_params
)),
611 X(snd_pcm_hw_params_is_double(hw_params
)),
612 X(snd_pcm_hw_params_is_half_duplex(hw_params
)),
613 X(snd_pcm_hw_params_is_joint_duplex(hw_params
)));
616 err
= snd_pcm_hw_params_get_access(hw_params
, &access
);
619 TRACE("access=%s\n", snd_pcm_access_name(access
));
623 snd_pcm_access_mask_t
* acmask
;
625 acmask
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, snd_pcm_access_mask_sizeof());
626 snd_pcm_hw_params_get_access_mask(hw_params
, acmask
);
627 for ( access
= SND_PCM_ACCESS_MMAP_INTERLEAVED
; access
<= SND_PCM_ACCESS_LAST
; access
++)
628 if (snd_pcm_access_mask_test(acmask
, access
))
629 TRACE("access=%s\n", snd_pcm_access_name(access
));
630 HeapFree( GetProcessHeap(), 0, acmask
);
633 err
= snd_pcm_hw_params_get_format(hw_params
, &format
);
636 TRACE("format=%s\n", snd_pcm_format_name(format
));
641 snd_pcm_format_mask_t
* fmask
;
643 fmask
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, snd_pcm_format_mask_sizeof());
644 snd_pcm_hw_params_get_format_mask(hw_params
, fmask
);
645 for ( format
= SND_PCM_FORMAT_S8
; format
<= SND_PCM_FORMAT_LAST
; format
++)
646 if ( snd_pcm_format_mask_test(fmask
, format
) )
647 TRACE("format=%s\n", snd_pcm_format_name(format
));
648 HeapFree( GetProcessHeap(), 0, fmask
);
654 err
= snd_pcm_hw_params_get_channels(hw_params
, &val
);
656 unsigned int min
= 0;
657 unsigned int max
= 0;
658 err
= snd_pcm_hw_params_get_channels_min(hw_params
, &min
),
659 err
= snd_pcm_hw_params_get_channels_max(hw_params
, &max
);
660 TRACE("channels_min=%u, channels_min_max=%u\n", min
, max
);
662 TRACE("channels=%d\n", val
);
667 snd_pcm_uframes_t val
=0;
668 err
= snd_pcm_hw_params_get_buffer_size(hw_params
, &val
);
670 snd_pcm_uframes_t min
= 0;
671 snd_pcm_uframes_t max
= 0;
672 err
= snd_pcm_hw_params_get_buffer_size_min(hw_params
, &min
),
673 err
= snd_pcm_hw_params_get_buffer_size_max(hw_params
, &max
);
674 TRACE("buffer_size_min=%lu, buffer_size_min_max=%lu\n", min
, max
);
676 TRACE("buffer_size=%lu\n", val
);
683 unsigned int val=0; \
684 err = snd_pcm_hw_params_get_##x(hw_params,&val, &dir); \
686 unsigned int min = 0; \
687 unsigned int max = 0; \
688 err = snd_pcm_hw_params_get_##x##_min(hw_params, &min, &dir); \
689 err = snd_pcm_hw_params_get_##x##_max(hw_params, &max, &dir); \
690 TRACE(#x "_min=%u " #x "_max=%u\n", min, max); \
692 TRACE(#x "=%d\n", val); \
701 snd_pcm_uframes_t val
=0;
702 err
= snd_pcm_hw_params_get_period_size(hw_params
, &val
, &dir
);
704 snd_pcm_uframes_t min
= 0;
705 snd_pcm_uframes_t max
= 0;
706 err
= snd_pcm_hw_params_get_period_size_min(hw_params
, &min
, &dir
),
707 err
= snd_pcm_hw_params_get_period_size_max(hw_params
, &max
, &dir
);
708 TRACE("period_size_min=%lu, period_size_min_max=%lu\n", min
, max
);
710 TRACE("period_size=%lu\n", val
);
723 /**************************************************************************
724 * DriverProc (WINEALSA.@)
726 LRESULT CALLBACK
ALSA_DriverProc(DWORD_PTR dwDevID
, HDRVR hDriv
, UINT wMsg
,
727 LPARAM dwParam1
, LPARAM dwParam2
)
729 /* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */
730 /* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
734 case DRV_LOAD
: ALSA_WaveInit();
737 case DRV_FREE
: return 1;
738 case DRV_OPEN
: return 1;
739 case DRV_CLOSE
: return 1;
740 case DRV_ENABLE
: return 1;
741 case DRV_DISABLE
: return 1;
742 case DRV_QUERYCONFIGURE
: return 1;
743 case DRV_CONFIGURE
: MessageBoxA(0, "ALSA MultiMedia Driver !", "ALSA Driver", MB_OK
); return 1;
744 case DRV_INSTALL
: return DRVCNF_RESTART
;
745 case DRV_REMOVE
: return DRVCNF_RESTART
;
748 return DefDriverProc(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);