winealsa.drv: Implement IAudioSessionControl::GetState.
[wine/multimedia.git] / dlls / winealsa.drv / alsa.c
blobccb5064345c1c8eaeb78bb39ffef71e292a5b11e
1 /*
2 * Wine Driver for ALSA
4 * Copyright 2002 Eric Pouech
5 * Copyright 2006 Jaroslav Kysela
6 * Copyright 2007 Maarten Lankhorst
8 * This file has a few shared generic subroutines shared among the alsa
9 * implementation.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "config.h"
28 #include <stdarg.h>
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "winnls.h"
35 #include "winerror.h"
36 #include "mmddk.h"
37 #include "mmreg.h"
38 #include "dsound.h"
39 #include "dsdriver.h"
40 #include "ks.h"
41 #include "wine/library.h"
42 #include "wine/unicode.h"
43 #include "wine/debug.h"
45 #include "alsa.h"
47 #include "initguid.h"
48 #include "ksmedia.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(alsa);
51 /* unless someone makes a wineserver kernel module, Unix pipes are faster than win32 events */
52 #define USE_PIPE_SYNC
54 #ifdef USE_PIPE_SYNC
55 #define INIT_OMR(omr) do { if (pipe(omr->msg_pipe) < 0) { omr->msg_pipe[0] = omr->msg_pipe[1] = -1; } } while (0)
56 #define CLOSE_OMR(omr) do { close(omr->msg_pipe[0]); close(omr->msg_pipe[1]); } while (0)
57 #define SIGNAL_OMR(omr) do { int x = 0; write((omr)->msg_pipe[1], &x, sizeof(x)); } while (0)
58 #define CLEAR_OMR(omr) do { int x = 0; read((omr)->msg_pipe[0], &x, sizeof(x)); } while (0)
59 #define RESET_OMR(omr) do { } while (0)
60 #define WAIT_OMR(omr, sleep) \
61 do { struct pollfd pfd; pfd.fd = (omr)->msg_pipe[0]; \
62 pfd.events = POLLIN; poll(&pfd, 1, sleep); } while (0)
63 #else
64 #define INIT_OMR(omr) do { omr->msg_event = CreateEventW(NULL, FALSE, FALSE, NULL); } while (0)
65 #define CLOSE_OMR(omr) do { CloseHandle(omr->msg_event); } while (0)
66 #define SIGNAL_OMR(omr) do { SetEvent((omr)->msg_event); } while (0)
67 #define CLEAR_OMR(omr) do { } while (0)
68 #define RESET_OMR(omr) do { ResetEvent((omr)->msg_event); } while (0)
69 #define WAIT_OMR(omr, sleep) \
70 do { WaitForSingleObject((omr)->msg_event, sleep); } while (0)
71 #endif
73 #define ALSA_RING_BUFFER_INCREMENT 64
75 /******************************************************************
76 * ALSA_InitRingMessage
78 * Initialize the ring of messages for passing between driver's caller and playback/record
79 * thread
81 int ALSA_InitRingMessage(ALSA_MSG_RING* omr)
83 omr->msg_toget = 0;
84 omr->msg_tosave = 0;
85 INIT_OMR(omr);
86 omr->ring_buffer_size = ALSA_RING_BUFFER_INCREMENT;
87 omr->messages = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,omr->ring_buffer_size * sizeof(ALSA_MSG));
89 InitializeCriticalSection(&omr->msg_crst);
90 omr->msg_crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ALSA_MSG_RING.msg_crst");
91 return 0;
94 /******************************************************************
95 * ALSA_DestroyRingMessage
98 int ALSA_DestroyRingMessage(ALSA_MSG_RING* omr)
100 CLOSE_OMR(omr);
101 HeapFree(GetProcessHeap(),0,omr->messages);
102 omr->ring_buffer_size = 0;
103 omr->msg_crst.DebugInfo->Spare[0] = 0;
104 DeleteCriticalSection(&omr->msg_crst);
105 return 0;
107 /******************************************************************
108 * ALSA_ResetRingMessage
111 void ALSA_ResetRingMessage(ALSA_MSG_RING* omr)
113 RESET_OMR(omr);
116 /******************************************************************
117 * ALSA_WaitRingMessage
120 void ALSA_WaitRingMessage(ALSA_MSG_RING* omr, DWORD sleep)
122 WAIT_OMR(omr, sleep);
125 /******************************************************************
126 * ALSA_AddRingMessage
128 * Inserts a new message into the ring (should be called from DriverProc derived routines)
130 int ALSA_AddRingMessage(ALSA_MSG_RING* omr, enum win_wm_message msg, DWORD_PTR param, BOOL wait)
132 HANDLE hEvent = NULL;
134 EnterCriticalSection(&omr->msg_crst);
135 if (omr->msg_toget == ((omr->msg_tosave + 1) % omr->ring_buffer_size))
137 int old_ring_buffer_size = omr->ring_buffer_size;
138 omr->ring_buffer_size += ALSA_RING_BUFFER_INCREMENT;
139 omr->messages = HeapReAlloc(GetProcessHeap(),0,omr->messages, omr->ring_buffer_size * sizeof(ALSA_MSG));
140 /* Now we need to rearrange the ring buffer so that the new
141 buffers just allocated are in between omr->msg_tosave and
142 omr->msg_toget.
144 if (omr->msg_tosave < omr->msg_toget)
146 memmove(&(omr->messages[omr->msg_toget + ALSA_RING_BUFFER_INCREMENT]),
147 &(omr->messages[omr->msg_toget]),
148 sizeof(ALSA_MSG)*(old_ring_buffer_size - omr->msg_toget)
150 omr->msg_toget += ALSA_RING_BUFFER_INCREMENT;
153 if (wait)
155 hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
156 if (!hEvent)
158 ERR("can't create event !?\n");
159 LeaveCriticalSection(&omr->msg_crst);
160 return 0;
162 if (omr->msg_toget != omr->msg_tosave && omr->messages[omr->msg_toget].msg != WINE_WM_HEADER)
163 FIXME("two fast messages in the queue!!!! toget = %d(%s), tosave=%d(%s)\n",
164 omr->msg_toget,ALSA_getCmdString(omr->messages[omr->msg_toget].msg),
165 omr->msg_tosave,ALSA_getCmdString(omr->messages[omr->msg_tosave].msg));
167 /* fast messages have to be added at the start of the queue */
168 omr->msg_toget = (omr->msg_toget + omr->ring_buffer_size - 1) % omr->ring_buffer_size;
170 omr->messages[omr->msg_toget].msg = msg;
171 omr->messages[omr->msg_toget].param = param;
172 omr->messages[omr->msg_toget].hEvent = hEvent;
174 else
176 omr->messages[omr->msg_tosave].msg = msg;
177 omr->messages[omr->msg_tosave].param = param;
178 omr->messages[omr->msg_tosave].hEvent = NULL;
179 omr->msg_tosave = (omr->msg_tosave + 1) % omr->ring_buffer_size;
181 LeaveCriticalSection(&omr->msg_crst);
182 /* signal a new message */
183 SIGNAL_OMR(omr);
184 if (wait)
186 /* wait for playback/record thread to have processed the message */
187 WaitForSingleObject(hEvent, INFINITE);
188 CloseHandle(hEvent);
190 return 1;
193 /******************************************************************
194 * ALSA_RetrieveRingMessage
196 * Get a message from the ring. Should be called by the playback/record thread.
198 int ALSA_RetrieveRingMessage(ALSA_MSG_RING* omr, enum win_wm_message *msg,
199 DWORD_PTR *param, HANDLE *hEvent)
201 EnterCriticalSection(&omr->msg_crst);
203 if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
205 LeaveCriticalSection(&omr->msg_crst);
206 return 0;
209 *msg = omr->messages[omr->msg_toget].msg;
210 omr->messages[omr->msg_toget].msg = 0;
211 *param = omr->messages[omr->msg_toget].param;
212 *hEvent = omr->messages[omr->msg_toget].hEvent;
213 omr->msg_toget = (omr->msg_toget + 1) % omr->ring_buffer_size;
214 CLEAR_OMR(omr);
215 LeaveCriticalSection(&omr->msg_crst);
216 return 1;
219 /*======================================================================*
220 * Utility functions *
221 *======================================================================*/
223 /* These strings used only for tracing */
224 const char * ALSA_getCmdString(enum win_wm_message msg)
226 #define MSG_TO_STR(x) case x: return #x
227 switch(msg) {
228 MSG_TO_STR(WINE_WM_PAUSING);
229 MSG_TO_STR(WINE_WM_RESTARTING);
230 MSG_TO_STR(WINE_WM_RESETTING);
231 MSG_TO_STR(WINE_WM_HEADER);
232 MSG_TO_STR(WINE_WM_UPDATE);
233 MSG_TO_STR(WINE_WM_BREAKLOOP);
234 MSG_TO_STR(WINE_WM_CLOSING);
235 MSG_TO_STR(WINE_WM_STARTING);
236 MSG_TO_STR(WINE_WM_STOPPING);
238 #undef MSG_TO_STR
239 return wine_dbg_sprintf("UNKNOWN(0x%08x)", msg);
242 const char * ALSA_getMessage(UINT msg)
244 #define MSG_TO_STR(x) case x: return #x
245 switch(msg) {
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);
284 #undef MSG_TO_STR
285 return wine_dbg_sprintf("UNKNOWN(0x%04x)", msg);
288 const char * ALSA_getFormat(WORD wFormatTag)
290 #define FMT_TO_STR(x) case x: return #x
291 switch(wFormatTag) {
292 FMT_TO_STR(WAVE_FORMAT_PCM);
293 FMT_TO_STR(WAVE_FORMAT_EXTENSIBLE);
294 FMT_TO_STR(WAVE_FORMAT_MULAW);
295 FMT_TO_STR(WAVE_FORMAT_ALAW);
296 FMT_TO_STR(WAVE_FORMAT_ADPCM);
298 #undef FMT_TO_STR
299 return wine_dbg_sprintf("UNKNOWN(0x%04x)", wFormatTag);
302 /* Allow 1% deviation for sample rates (some ES137x cards) */
303 BOOL ALSA_NearMatch(int rate1, int rate2)
305 return (((100 * (rate1 - rate2)) / rate1) == 0);
308 DWORD ALSA_bytes_to_mmtime(LPMMTIME lpTime, DWORD position, WAVEFORMATPCMEX* format)
310 TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%u nChannels=%u nAvgBytesPerSec=%u\n",
311 lpTime->wType, format->Format.wBitsPerSample, format->Format.nSamplesPerSec,
312 format->Format.nChannels, format->Format.nAvgBytesPerSec);
313 TRACE("Position in bytes=%u\n", position);
315 switch (lpTime->wType) {
316 case TIME_SAMPLES:
317 lpTime->u.sample = position / (format->Format.wBitsPerSample / 8 * format->Format.nChannels);
318 TRACE("TIME_SAMPLES=%u\n", lpTime->u.sample);
319 break;
320 case TIME_MS:
321 lpTime->u.ms = 1000.0 * position / (format->Format.wBitsPerSample / 8 * format->Format.nChannels * format->Format.nSamplesPerSec);
322 TRACE("TIME_MS=%u\n", lpTime->u.ms);
323 break;
324 case TIME_SMPTE:
325 lpTime->u.smpte.fps = 30;
326 position = position / (format->Format.wBitsPerSample / 8 * format->Format.nChannels);
327 position += (format->Format.nSamplesPerSec / lpTime->u.smpte.fps) - 1; /* round up */
328 lpTime->u.smpte.sec = position / format->Format.nSamplesPerSec;
329 position -= lpTime->u.smpte.sec * format->Format.nSamplesPerSec;
330 lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
331 lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
332 lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
333 lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
334 lpTime->u.smpte.fps = 30;
335 lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->Format.nSamplesPerSec;
336 TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
337 lpTime->u.smpte.hour, lpTime->u.smpte.min,
338 lpTime->u.smpte.sec, lpTime->u.smpte.frame);
339 break;
340 default:
341 WARN("Format %d not supported, using TIME_BYTES !\n", lpTime->wType);
342 lpTime->wType = TIME_BYTES;
343 /* fall through */
344 case TIME_BYTES:
345 lpTime->u.cb = position;
346 TRACE("TIME_BYTES=%u\n", lpTime->u.cb);
347 break;
349 return MMSYSERR_NOERROR;
352 void ALSA_copyFormat(LPWAVEFORMATEX wf1, LPWAVEFORMATPCMEX wf2)
354 unsigned int iLength;
356 ZeroMemory(wf2, sizeof(*wf2));
357 if (wf1->wFormatTag == WAVE_FORMAT_PCM)
358 iLength = sizeof(PCMWAVEFORMAT);
359 else if (wf1->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
360 iLength = sizeof(WAVEFORMATPCMEX);
361 else
362 iLength = sizeof(WAVEFORMATEX) + wf1->cbSize;
363 memcpy(wf2, wf1, iLength);
366 BOOL ALSA_supportedFormat(LPWAVEFORMATEX wf)
368 TRACE("(%p)\n",wf);
370 if (wf->nSamplesPerSec<DSBFREQUENCY_MIN||wf->nSamplesPerSec>DSBFREQUENCY_MAX)
371 return FALSE;
373 if (wf->wFormatTag == WAVE_FORMAT_PCM) {
374 if (wf->nChannels==1||wf->nChannels==2) {
375 if (wf->wBitsPerSample==8||wf->wBitsPerSample==16)
376 return TRUE;
378 } else if (wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
379 WAVEFORMATEXTENSIBLE * wfex = (WAVEFORMATEXTENSIBLE *)wf;
381 if (wf->cbSize == 22 &&
382 (IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) ||
383 IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))) {
384 if (wf->nChannels>=1 && wf->nChannels<=6) {
385 if (wf->wBitsPerSample==wfex->Samples.wValidBitsPerSample) {
386 if (wf->wBitsPerSample==8||wf->wBitsPerSample==16||
387 wf->wBitsPerSample==24||wf->wBitsPerSample==32) {
388 return TRUE;
390 } else
391 WARN("wBitsPerSample != wValidBitsPerSample not supported yet\n");
393 } else
394 WARN("only KSDATAFORMAT_SUBTYPE_PCM and KSDATAFORMAT_SUBTYPE_IEEE_FLOAT "
395 "supported\n");
396 } else
397 WARN("only WAVE_FORMAT_PCM and WAVE_FORMAT_EXTENSIBLE supported\n");
399 return FALSE;
402 /*======================================================================*
403 * Low level WAVE implementation *
404 *======================================================================*/
406 /**************************************************************************
407 * ALSA_CheckSetVolume [internal]
409 * Helper function for Alsa volume queries. This tries to simplify
410 * the process of managing the volume. All parameters are optional
411 * (pass NULL to ignore or not use).
412 * Return values are MMSYSERR_NOERROR on success, or !0 on failure;
413 * error codes are normalized into the possible documented return
414 * values from waveOutGetVolume.
416 int ALSA_CheckSetVolume(snd_hctl_t *hctl, int *out_left, int *out_right,
417 int *out_min, int *out_max, int *out_step,
418 int *new_left, int *new_right)
420 int rc = MMSYSERR_NOERROR;
421 int value_count = 0;
422 snd_hctl_elem_t * elem = NULL;
423 snd_ctl_elem_info_t * eleminfop = NULL;
424 snd_ctl_elem_value_t * elemvaluep = NULL;
425 snd_ctl_elem_id_t * elemidp = NULL;
426 const char *names[] = {"PCM Playback Volume", "Line Playback Volume", NULL};
427 const char **name;
430 #define EXIT_ON_ERROR(f,txt,exitcode) do \
432 int err; \
433 if ( (err = (f) ) < 0) \
435 ERR(txt " failed: %s\n", snd_strerror(err)); \
436 rc = exitcode; \
437 goto out; \
439 } while(0)
441 if (! hctl)
442 return MMSYSERR_NOTSUPPORTED;
444 /* Allocate areas to return information about the volume */
445 EXIT_ON_ERROR(snd_ctl_elem_id_malloc(&elemidp), "snd_ctl_elem_id_malloc", MMSYSERR_NOMEM);
446 EXIT_ON_ERROR(snd_ctl_elem_value_malloc (&elemvaluep), "snd_ctl_elem_value_malloc", MMSYSERR_NOMEM);
447 EXIT_ON_ERROR(snd_ctl_elem_info_malloc (&eleminfop), "snd_ctl_elem_info_malloc", MMSYSERR_NOMEM);
448 snd_ctl_elem_id_clear(elemidp);
449 snd_ctl_elem_value_clear(elemvaluep);
450 snd_ctl_elem_info_clear(eleminfop);
452 /* Setup and find an element id that exactly matches the characteristic we want
453 ** FIXME: It is probably short sighted to hard code and fixate on PCM Playback Volume */
455 for( name = names; *name; name++ )
457 snd_ctl_elem_id_set_name(elemidp, *name);
458 snd_ctl_elem_id_set_interface(elemidp, SND_CTL_ELEM_IFACE_MIXER);
459 elem = snd_hctl_find_elem(hctl, elemidp);
460 if (elem)
462 /* Read and return volume information */
463 EXIT_ON_ERROR(snd_hctl_elem_info(elem, eleminfop), "snd_hctl_elem_info", MMSYSERR_NOTSUPPORTED);
464 value_count = snd_ctl_elem_info_get_count(eleminfop);
465 if (out_min || out_max || out_step)
467 if (!snd_ctl_elem_info_is_readable(eleminfop))
469 ERR("snd_ctl_elem_info_is_readable returned false; cannot return info\n");
470 rc = MMSYSERR_NOTSUPPORTED;
471 goto out;
474 if (out_min)
475 *out_min = snd_ctl_elem_info_get_min(eleminfop);
477 if (out_max)
478 *out_max = snd_ctl_elem_info_get_max(eleminfop);
480 if (out_step)
481 *out_step = snd_ctl_elem_info_get_step(eleminfop);
484 if (out_left || out_right)
486 EXIT_ON_ERROR(snd_hctl_elem_read(elem, elemvaluep), "snd_hctl_elem_read", MMSYSERR_NOTSUPPORTED);
488 if (out_left)
489 *out_left = snd_ctl_elem_value_get_integer(elemvaluep, 0);
491 if (out_right)
493 if (value_count == 1)
494 *out_right = snd_ctl_elem_value_get_integer(elemvaluep, 0);
495 else if (value_count == 2)
496 *out_right = snd_ctl_elem_value_get_integer(elemvaluep, 1);
497 else
499 ERR("Unexpected value count %d from snd_ctl_elem_info_get_count while getting volume info\n", value_count);
500 rc = -1;
501 goto out;
506 /* Set the volume */
507 if (new_left || new_right)
509 EXIT_ON_ERROR(snd_hctl_elem_read(elem, elemvaluep), "snd_hctl_elem_read", MMSYSERR_NOTSUPPORTED);
510 if (new_left)
511 snd_ctl_elem_value_set_integer(elemvaluep, 0, *new_left);
512 if (new_right)
514 if (value_count == 1)
515 snd_ctl_elem_value_set_integer(elemvaluep, 0, *new_right);
516 else if (value_count == 2)
517 snd_ctl_elem_value_set_integer(elemvaluep, 1, *new_right);
518 else
520 ERR("Unexpected value count %d from snd_ctl_elem_info_get_count while setting volume info\n", value_count);
521 rc = -1;
522 goto out;
526 EXIT_ON_ERROR(snd_hctl_elem_write(elem, elemvaluep), "snd_hctl_elem_write", MMSYSERR_NOTSUPPORTED);
529 break;
533 if( !*name )
535 ERR("Could not find '{PCM,Line} Playback Volume' element\n");
536 rc = MMSYSERR_NOTSUPPORTED;
540 #undef EXIT_ON_ERROR
542 out:
544 if (elemvaluep)
545 snd_ctl_elem_value_free(elemvaluep);
546 if (eleminfop)
547 snd_ctl_elem_info_free(eleminfop);
548 if (elemidp)
549 snd_ctl_elem_id_free(elemidp);
551 return rc;
555 /**************************************************************************
556 * wine_snd_pcm_recover [internal]
558 * Code slightly modified from alsa-lib v1.0.23 snd_pcm_recover implementation.
559 * used to recover from XRUN errors (buffer underflow/overflow)
561 int wine_snd_pcm_recover(snd_pcm_t *pcm, int err, int silent)
563 if (err > 0)
564 err = -err;
565 if (err == -EINTR) /* nothing to do, continue */
566 return 0;
567 if (err == -EPIPE) {
568 const char *s;
569 if (snd_pcm_stream(pcm) == SND_PCM_STREAM_PLAYBACK)
570 s = "underrun";
571 else
572 s = "overrun";
573 if (!silent)
574 ERR("%s occurred\n", s);
575 err = snd_pcm_prepare(pcm);
576 if (err < 0) {
577 ERR("cannot recover from %s, prepare failed: %s\n", s, snd_strerror(err));
578 return err;
580 return 0;
582 if (err == -ESTRPIPE) {
583 while ((err = snd_pcm_resume(pcm)) == -EAGAIN)
584 /* wait until suspend flag is released */
585 poll(NULL, 0, 1000);
586 if (err < 0) {
587 err = snd_pcm_prepare(pcm);
588 if (err < 0) {
589 ERR("cannot recover from suspend, prepare failed: %s\n", snd_strerror(err));
590 return err;
593 return 0;
595 return err;
598 /**************************************************************************
599 * ALSA_TraceParameters [internal]
601 * used to trace format changes, hw and sw parameters
603 void ALSA_TraceParameters(snd_pcm_hw_params_t * hw_params, snd_pcm_sw_params_t * sw, int full)
605 int err;
606 snd_pcm_format_t format;
607 snd_pcm_access_t access;
609 #define X(x) ((x)? "true" : "false")
610 if (full)
611 TRACE("FLAGS: sampleres=%s overrng=%s pause=%s resume=%s syncstart=%s batch=%s block=%s double=%s "
612 "halfd=%s joint=%s\n",
613 X(snd_pcm_hw_params_can_mmap_sample_resolution(hw_params)),
614 X(snd_pcm_hw_params_can_overrange(hw_params)),
615 X(snd_pcm_hw_params_can_pause(hw_params)),
616 X(snd_pcm_hw_params_can_resume(hw_params)),
617 X(snd_pcm_hw_params_can_sync_start(hw_params)),
618 X(snd_pcm_hw_params_is_batch(hw_params)),
619 X(snd_pcm_hw_params_is_block_transfer(hw_params)),
620 X(snd_pcm_hw_params_is_double(hw_params)),
621 X(snd_pcm_hw_params_is_half_duplex(hw_params)),
622 X(snd_pcm_hw_params_is_joint_duplex(hw_params)));
623 #undef X
625 err = snd_pcm_hw_params_get_access(hw_params, &access);
626 if (err >= 0)
628 TRACE("access=%s\n", snd_pcm_access_name(access));
630 else
632 snd_pcm_access_mask_t * acmask;
634 acmask = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_access_mask_sizeof());
635 snd_pcm_hw_params_get_access_mask(hw_params, acmask);
636 for ( access = SND_PCM_ACCESS_MMAP_INTERLEAVED; access <= SND_PCM_ACCESS_LAST; access++)
637 if (snd_pcm_access_mask_test(acmask, access))
638 TRACE("access=%s\n", snd_pcm_access_name(access));
639 HeapFree( GetProcessHeap(), 0, acmask );
642 err = snd_pcm_hw_params_get_format(hw_params, &format);
643 if (err >= 0)
645 TRACE("format=%s\n", snd_pcm_format_name(format));
648 else
650 snd_pcm_format_mask_t * fmask;
652 fmask = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_format_mask_sizeof());
653 snd_pcm_hw_params_get_format_mask(hw_params, fmask);
654 for ( format = SND_PCM_FORMAT_S8; format <= SND_PCM_FORMAT_LAST ; format++)
655 if ( snd_pcm_format_mask_test(fmask, format) )
656 TRACE("format=%s\n", snd_pcm_format_name(format));
657 HeapFree( GetProcessHeap(), 0, fmask );
660 do {
661 int err=0;
662 unsigned int val=0;
663 err = snd_pcm_hw_params_get_channels(hw_params, &val);
664 if (err<0) {
665 unsigned int min = 0;
666 unsigned int max = 0;
667 err = snd_pcm_hw_params_get_channels_min(hw_params, &min),
668 err = snd_pcm_hw_params_get_channels_max(hw_params, &max);
669 TRACE("channels_min=%u, channels_min_max=%u\n", min, max);
670 } else {
671 TRACE("channels=%d\n", val);
673 } while(0);
674 do {
675 int err=0;
676 snd_pcm_uframes_t val=0;
677 err = snd_pcm_hw_params_get_buffer_size(hw_params, &val);
678 if (err<0) {
679 snd_pcm_uframes_t min = 0;
680 snd_pcm_uframes_t max = 0;
681 err = snd_pcm_hw_params_get_buffer_size_min(hw_params, &min),
682 err = snd_pcm_hw_params_get_buffer_size_max(hw_params, &max);
683 TRACE("buffer_size_min=%lu, buffer_size_min_max=%lu\n", min, max);
684 } else {
685 TRACE("buffer_size=%lu\n", val);
687 } while(0);
689 #define X(x) do { \
690 int err=0; \
691 int dir=0; \
692 unsigned int val=0; \
693 err = snd_pcm_hw_params_get_##x(hw_params,&val, &dir); \
694 if (err<0) { \
695 unsigned int min = 0; \
696 unsigned int max = 0; \
697 err = snd_pcm_hw_params_get_##x##_min(hw_params, &min, &dir); \
698 err = snd_pcm_hw_params_get_##x##_max(hw_params, &max, &dir); \
699 TRACE(#x "_min=%u " #x "_max=%u\n", min, max); \
700 } else \
701 TRACE(#x "=%d\n", val); \
702 } while(0)
704 X(rate);
705 X(buffer_time);
706 X(periods);
707 do {
708 int err=0;
709 int dir=0;
710 snd_pcm_uframes_t val=0;
711 err = snd_pcm_hw_params_get_period_size(hw_params, &val, &dir);
712 if (err<0) {
713 snd_pcm_uframes_t min = 0;
714 snd_pcm_uframes_t max = 0;
715 err = snd_pcm_hw_params_get_period_size_min(hw_params, &min, &dir),
716 err = snd_pcm_hw_params_get_period_size_max(hw_params, &max, &dir);
717 TRACE("period_size_min=%lu, period_size_min_max=%lu\n", min, max);
718 } else {
719 TRACE("period_size=%lu\n", val);
721 } while(0);
723 X(period_time);
724 #undef X
726 if (!sw)
727 return;
730 /**************************************************************************
731 * DriverProc (WINEALSA.@)
733 LRESULT CALLBACK ALSA_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
734 LPARAM dwParam1, LPARAM dwParam2)
736 /* EPP TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n", */
737 /* EPP dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
739 switch(wMsg) {
740 case DRV_LOAD:
741 case DRV_FREE:
742 case DRV_OPEN:
743 case DRV_CLOSE:
744 case DRV_ENABLE:
745 case DRV_DISABLE:
746 case DRV_QUERYCONFIGURE:
747 return 1;
748 case DRV_CONFIGURE: MessageBoxA(0, "ALSA MultiMedia Driver !", "ALSA Driver", MB_OK); return 1;
749 case DRV_INSTALL:
750 case DRV_REMOVE:
751 return DRV_SUCCESS;
752 default:
753 return 0;