hlink/tests: Comment out a test for an uninitialized return value.
[wine] / dlls / winealsa.drv / alsa.c
1 /*
2  * Wine Driver for ALSA
3  *
4  * Copyright    2002 Eric Pouech
5  * Copyright    2006 Jaroslav Kysela
6  * Copyright    2007 Maarten Lankhorst
7  *
8  * This file has a few shared generic subroutines shared among the alsa
9  * implementation.
10  *
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.
15  *
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.
20  *
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
24  */
25
26 #include "config.h"
27
28 #include <stdarg.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winuser.h"
34 #include "mmddk.h"
35
36 #include "ks.h"
37 #include "guiddef.h"
38 #include "ksmedia.h"
39
40 #include "alsa.h"
41
42 #ifdef HAVE_ALSA
43
44 #include "wine/library.h"
45 #include "wine/unicode.h"
46 #include "wine/debug.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(alsa);
49 /* unless someone makes a wineserver kernel module, Unix pipes are faster than win32 events */
50 #define USE_PIPE_SYNC
51
52 #ifdef USE_PIPE_SYNC
53 #define INIT_OMR(omr) do { if (pipe(omr->msg_pipe) < 0) { omr->msg_pipe[0] = omr->msg_pipe[1] = -1; } } while (0)
54 #define CLOSE_OMR(omr) do { close(omr->msg_pipe[0]); close(omr->msg_pipe[1]); } while (0)
55 #define SIGNAL_OMR(omr) do { int x = 0; write((omr)->msg_pipe[1], &x, sizeof(x)); } while (0)
56 #define CLEAR_OMR(omr) do { int x = 0; read((omr)->msg_pipe[0], &x, sizeof(x)); } while (0)
57 #define RESET_OMR(omr) do { } while (0)
58 #define WAIT_OMR(omr, sleep) \
59   do { struct pollfd pfd; pfd.fd = (omr)->msg_pipe[0]; \
60        pfd.events = POLLIN; poll(&pfd, 1, sleep); } while (0)
61 #else
62 #define INIT_OMR(omr) do { omr->msg_event = CreateEventW(NULL, FALSE, FALSE, NULL); } while (0)
63 #define CLOSE_OMR(omr) do { CloseHandle(omr->msg_event); } while (0)
64 #define SIGNAL_OMR(omr) do { SetEvent((omr)->msg_event); } while (0)
65 #define CLEAR_OMR(omr) do { } while (0)
66 #define RESET_OMR(omr) do { ResetEvent((omr)->msg_event); } while (0)
67 #define WAIT_OMR(omr, sleep) \
68   do { WaitForSingleObject((omr)->msg_event, sleep); } while (0)
69 #endif
70
71 #define ALSA_RING_BUFFER_INCREMENT      64
72
73 /******************************************************************
74  *              ALSA_InitRingMessage
75  *
76  * Initialize the ring of messages for passing between driver's caller and playback/record
77  * thread
78  */
79 int ALSA_InitRingMessage(ALSA_MSG_RING* omr)
80 {
81     omr->msg_toget = 0;
82     omr->msg_tosave = 0;
83     INIT_OMR(omr);
84     omr->ring_buffer_size = ALSA_RING_BUFFER_INCREMENT;
85     omr->messages = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,omr->ring_buffer_size * sizeof(ALSA_MSG));
86
87     InitializeCriticalSection(&omr->msg_crst);
88     omr->msg_crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ALSA_MSG_RING.msg_crst");
89     return 0;
90 }
91
92 /******************************************************************
93  *              ALSA_DestroyRingMessage
94  *
95  */
96 int ALSA_DestroyRingMessage(ALSA_MSG_RING* omr)
97 {
98     CLOSE_OMR(omr);
99     HeapFree(GetProcessHeap(),0,omr->messages);
100     omr->ring_buffer_size = 0;
101     omr->msg_crst.DebugInfo->Spare[0] = 0;
102     DeleteCriticalSection(&omr->msg_crst);
103     return 0;
104 }
105 /******************************************************************
106  *              ALSA_ResetRingMessage
107  *
108  */
109 void ALSA_ResetRingMessage(ALSA_MSG_RING* omr)
110 {
111     RESET_OMR(omr);
112 }
113
114 /******************************************************************
115  *              ALSA_WaitRingMessage
116  *
117  */
118 void ALSA_WaitRingMessage(ALSA_MSG_RING* omr, DWORD sleep)
119 {
120     WAIT_OMR(omr, sleep);
121 }
122
123 /******************************************************************
124  *              ALSA_AddRingMessage
125  *
126  * Inserts a new message into the ring (should be called from DriverProc derived routines)
127  */
128 int ALSA_AddRingMessage(ALSA_MSG_RING* omr, enum win_wm_message msg, DWORD_PTR param, BOOL wait)
129 {
130     HANDLE      hEvent = INVALID_HANDLE_VALUE;
131
132     EnterCriticalSection(&omr->msg_crst);
133     if ((omr->msg_toget == ((omr->msg_tosave + 1) % omr->ring_buffer_size)))
134     {
135         int old_ring_buffer_size = omr->ring_buffer_size;
136         omr->ring_buffer_size += ALSA_RING_BUFFER_INCREMENT;
137         omr->messages = HeapReAlloc(GetProcessHeap(),0,omr->messages, omr->ring_buffer_size * sizeof(ALSA_MSG));
138         /* Now we need to rearrange the ring buffer so that the new
139            buffers just allocated are in between omr->msg_tosave and
140            omr->msg_toget.
141         */
142         if (omr->msg_tosave < omr->msg_toget)
143         {
144             memmove(&(omr->messages[omr->msg_toget + ALSA_RING_BUFFER_INCREMENT]),
145                     &(omr->messages[omr->msg_toget]),
146                     sizeof(ALSA_MSG)*(old_ring_buffer_size - omr->msg_toget)
147                     );
148             omr->msg_toget += ALSA_RING_BUFFER_INCREMENT;
149         }
150     }
151     if (wait)
152     {
153         hEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
154         if (hEvent == INVALID_HANDLE_VALUE)
155         {
156             ERR("can't create event !?\n");
157             LeaveCriticalSection(&omr->msg_crst);
158             return 0;
159         }
160         if (omr->msg_toget != omr->msg_tosave && omr->messages[omr->msg_toget].msg != WINE_WM_HEADER)
161             FIXME("two fast messages in the queue!!!! toget = %d(%s), tosave=%d(%s)\n",
162                   omr->msg_toget,ALSA_getCmdString(omr->messages[omr->msg_toget].msg),
163                   omr->msg_tosave,ALSA_getCmdString(omr->messages[omr->msg_tosave].msg));
164
165         /* fast messages have to be added at the start of the queue */
166         omr->msg_toget = (omr->msg_toget + omr->ring_buffer_size - 1) % omr->ring_buffer_size;
167
168         omr->messages[omr->msg_toget].msg = msg;
169         omr->messages[omr->msg_toget].param = param;
170         omr->messages[omr->msg_toget].hEvent = hEvent;
171     }
172     else
173     {
174         omr->messages[omr->msg_tosave].msg = msg;
175         omr->messages[omr->msg_tosave].param = param;
176         omr->messages[omr->msg_tosave].hEvent = INVALID_HANDLE_VALUE;
177         omr->msg_tosave = (omr->msg_tosave + 1) % omr->ring_buffer_size;
178     }
179     LeaveCriticalSection(&omr->msg_crst);
180     /* signal a new message */
181     SIGNAL_OMR(omr);
182     if (wait)
183     {
184         /* wait for playback/record thread to have processed the message */
185         WaitForSingleObject(hEvent, INFINITE);
186         CloseHandle(hEvent);
187     }
188     return 1;
189 }
190
191 /******************************************************************
192  *              ALSA_RetrieveRingMessage
193  *
194  * Get a message from the ring. Should be called by the playback/record thread.
195  */
196 int ALSA_RetrieveRingMessage(ALSA_MSG_RING* omr, enum win_wm_message *msg,
197                              DWORD_PTR *param, HANDLE *hEvent)
198 {
199     EnterCriticalSection(&omr->msg_crst);
200
201     if (omr->msg_toget == omr->msg_tosave) /* buffer empty ? */
202     {
203         LeaveCriticalSection(&omr->msg_crst);
204         return 0;
205     }
206
207     *msg = omr->messages[omr->msg_toget].msg;
208     omr->messages[omr->msg_toget].msg = 0;
209     *param = omr->messages[omr->msg_toget].param;
210     *hEvent = omr->messages[omr->msg_toget].hEvent;
211     omr->msg_toget = (omr->msg_toget + 1) % omr->ring_buffer_size;
212     CLEAR_OMR(omr);
213     LeaveCriticalSection(&omr->msg_crst);
214     return 1;
215 }
216
217 /*======================================================================*
218  *                  Utility functions                                   *
219  *======================================================================*/
220
221 /* These strings used only for tracing */
222 const char * ALSA_getCmdString(enum win_wm_message msg)
223 {
224 #define MSG_TO_STR(x) case x: return #x
225     switch(msg) {
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);
235     }
236 #undef MSG_TO_STR
237     return wine_dbg_sprintf("UNKNOWN(0x%08x)", msg);
238 }
239
240 const char * ALSA_getMessage(UINT msg)
241 {
242 #define MSG_TO_STR(x) case x: return #x
243     switch(msg) {
244     MSG_TO_STR(DRVM_INIT);
245     MSG_TO_STR(DRVM_EXIT);
246     MSG_TO_STR(DRVM_ENABLE);
247     MSG_TO_STR(DRVM_DISABLE);
248     MSG_TO_STR(WIDM_OPEN);
249     MSG_TO_STR(WIDM_CLOSE);
250     MSG_TO_STR(WIDM_ADDBUFFER);
251     MSG_TO_STR(WIDM_PREPARE);
252     MSG_TO_STR(WIDM_UNPREPARE);
253     MSG_TO_STR(WIDM_GETDEVCAPS);
254     MSG_TO_STR(WIDM_GETNUMDEVS);
255     MSG_TO_STR(WIDM_GETPOS);
256     MSG_TO_STR(WIDM_RESET);
257     MSG_TO_STR(WIDM_START);
258     MSG_TO_STR(WIDM_STOP);
259     MSG_TO_STR(WODM_OPEN);
260     MSG_TO_STR(WODM_CLOSE);
261     MSG_TO_STR(WODM_WRITE);
262     MSG_TO_STR(WODM_PAUSE);
263     MSG_TO_STR(WODM_GETPOS);
264     MSG_TO_STR(WODM_BREAKLOOP);
265     MSG_TO_STR(WODM_PREPARE);
266     MSG_TO_STR(WODM_UNPREPARE);
267     MSG_TO_STR(WODM_GETDEVCAPS);
268     MSG_TO_STR(WODM_GETNUMDEVS);
269     MSG_TO_STR(WODM_GETPITCH);
270     MSG_TO_STR(WODM_SETPITCH);
271     MSG_TO_STR(WODM_GETPLAYBACKRATE);
272     MSG_TO_STR(WODM_SETPLAYBACKRATE);
273     MSG_TO_STR(WODM_GETVOLUME);
274     MSG_TO_STR(WODM_SETVOLUME);
275     MSG_TO_STR(WODM_RESTART);
276     MSG_TO_STR(WODM_RESET);
277     MSG_TO_STR(DRV_QUERYDEVICEINTERFACESIZE);
278     MSG_TO_STR(DRV_QUERYDEVICEINTERFACE);
279     MSG_TO_STR(DRV_QUERYDSOUNDIFACE);
280     MSG_TO_STR(DRV_QUERYDSOUNDDESC);
281     }
282 #undef MSG_TO_STR
283     return wine_dbg_sprintf("UNKNOWN(0x%04x)", msg);
284 }
285
286 const char * ALSA_getFormat(WORD wFormatTag)
287 {
288 #define FMT_TO_STR(x) case x: return #x
289     switch(wFormatTag) {
290     FMT_TO_STR(WAVE_FORMAT_PCM);
291     FMT_TO_STR(WAVE_FORMAT_EXTENSIBLE);
292     FMT_TO_STR(WAVE_FORMAT_MULAW);
293     FMT_TO_STR(WAVE_FORMAT_ALAW);
294     FMT_TO_STR(WAVE_FORMAT_ADPCM);
295     }
296 #undef FMT_TO_STR
297     return wine_dbg_sprintf("UNKNOWN(0x%04x)", wFormatTag);
298 }
299
300 /* Allow 1% deviation for sample rates (some ES137x cards) */
301 BOOL ALSA_NearMatch(int rate1, int rate2)
302 {
303     return (((100 * (rate1 - rate2)) / rate1) == 0);
304 }
305
306 DWORD ALSA_bytes_to_mmtime(LPMMTIME lpTime, DWORD position, WAVEFORMATPCMEX* format)
307 {
308     TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%u nChannels=%u nAvgBytesPerSec=%u\n",
309           lpTime->wType, format->Format.wBitsPerSample, format->Format.nSamplesPerSec,
310           format->Format.nChannels, format->Format.nAvgBytesPerSec);
311     TRACE("Position in bytes=%u\n", position);
312
313     switch (lpTime->wType) {
314     case TIME_SAMPLES:
315         lpTime->u.sample = position / (format->Format.wBitsPerSample / 8 * format->Format.nChannels);
316         TRACE("TIME_SAMPLES=%u\n", lpTime->u.sample);
317         break;
318     case TIME_MS:
319         lpTime->u.ms = 1000.0 * position / (format->Format.wBitsPerSample / 8 * format->Format.nChannels * format->Format.nSamplesPerSec);
320         TRACE("TIME_MS=%u\n", lpTime->u.ms);
321         break;
322     case TIME_SMPTE:
323         lpTime->u.smpte.fps = 30;
324         position = position / (format->Format.wBitsPerSample / 8 * format->Format.nChannels);
325         position += (format->Format.nSamplesPerSec / lpTime->u.smpte.fps) - 1; /* round up */
326         lpTime->u.smpte.sec = position / format->Format.nSamplesPerSec;
327         position -= lpTime->u.smpte.sec * format->Format.nSamplesPerSec;
328         lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
329         lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
330         lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
331         lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
332         lpTime->u.smpte.fps = 30;
333         lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->Format.nSamplesPerSec;
334         TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
335               lpTime->u.smpte.hour, lpTime->u.smpte.min,
336               lpTime->u.smpte.sec, lpTime->u.smpte.frame);
337         break;
338     default:
339         WARN("Format %d not supported, using TIME_BYTES !\n", lpTime->wType);
340         lpTime->wType = TIME_BYTES;
341         /* fall through */
342     case TIME_BYTES:
343         lpTime->u.cb = position;
344         TRACE("TIME_BYTES=%u\n", lpTime->u.cb);
345         break;
346     }
347     return MMSYSERR_NOERROR;
348 }
349
350 void ALSA_copyFormat(LPWAVEFORMATEX wf1, LPWAVEFORMATPCMEX wf2)
351 {
352     unsigned int iLength;
353
354     ZeroMemory(wf2, sizeof(wf2));
355     if (wf1->wFormatTag == WAVE_FORMAT_PCM)
356         iLength = sizeof(PCMWAVEFORMAT);
357     else if (wf1->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
358         iLength = sizeof(WAVEFORMATPCMEX);
359     else
360         iLength = sizeof(WAVEFORMATEX) + wf1->cbSize;
361     if (iLength > sizeof(WAVEFORMATPCMEX)) {
362         ERR("calculated %u bytes, capping\n", iLength);
363         iLength = sizeof(WAVEFORMATPCMEX);
364     }
365     memcpy(wf2, wf1, iLength);
366 }
367
368 BOOL ALSA_supportedFormat(LPWAVEFORMATEX wf)
369 {
370     TRACE("(%p)\n",wf);
371
372     if (wf->nSamplesPerSec<DSBFREQUENCY_MIN||wf->nSamplesPerSec>DSBFREQUENCY_MAX)
373         return FALSE;
374
375     if (wf->wFormatTag == WAVE_FORMAT_PCM) {
376         if (wf->nChannels==1||wf->nChannels==2) {
377             if (wf->wBitsPerSample==8||wf->wBitsPerSample==16)
378                 return TRUE;
379         }
380     } else if (wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
381         WAVEFORMATEXTENSIBLE    * wfex = (WAVEFORMATEXTENSIBLE *)wf;
382
383         if (wf->cbSize == 22 &&
384             (IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) ||
385              IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))) {
386             if (wf->nChannels>=1 && wf->nChannels<=6) {
387                 if (wf->wBitsPerSample==wfex->Samples.wValidBitsPerSample) {
388                     if (wf->wBitsPerSample==8||wf->wBitsPerSample==16||
389                         wf->wBitsPerSample==24||wf->wBitsPerSample==32) {
390                         return TRUE;
391                     }
392                 } else
393                     WARN("wBitsPerSample != wValidBitsPerSample not supported yet\n");
394             }
395         } else
396             WARN("only KSDATAFORMAT_SUBTYPE_PCM and KSDATAFORMAT_SUBTYPE_IEEE_FLOAT "
397                  "supported\n");
398     } else if (wf->wFormatTag == WAVE_FORMAT_MULAW || wf->wFormatTag == WAVE_FORMAT_ALAW) {
399         if (wf->wBitsPerSample==8)
400             return TRUE;
401         else
402             ERR("WAVE_FORMAT_MULAW and WAVE_FORMAT_ALAW wBitsPerSample must = 8\n");
403
404     } else if (wf->wFormatTag == WAVE_FORMAT_ADPCM) {
405         if (wf->wBitsPerSample==4)
406             return TRUE;
407         else
408             ERR("WAVE_FORMAT_ADPCM wBitsPerSample must = 4\n");
409     } else
410         WARN("only WAVE_FORMAT_PCM and WAVE_FORMAT_EXTENSIBLE supported\n");
411
412     return FALSE;
413 }
414
415 /*======================================================================*
416  *                  Low level WAVE implementation                       *
417  *======================================================================*/
418
419 /**************************************************************************
420  *                      ALSA_CheckSetVolume             [internal]
421  *
422  *  Helper function for Alsa volume queries.  This tries to simplify
423  * the process of managing the volume.  All parameters are optional
424  * (pass NULL to ignore or not use).
425  *  Return values are MMSYSERR_NOERROR on success, or !0 on failure;
426  * error codes are normalized into the possible documented return
427  * values from waveOutGetVolume.
428  */
429 int ALSA_CheckSetVolume(snd_hctl_t *hctl, int *out_left, int *out_right,
430             int *out_min, int *out_max, int *out_step,
431             int *new_left, int *new_right)
432 {
433     int rc = MMSYSERR_NOERROR;
434     int value_count = 0;
435     snd_hctl_elem_t *           elem = NULL;
436     snd_ctl_elem_info_t *       eleminfop = NULL;
437     snd_ctl_elem_value_t *      elemvaluep = NULL;
438     snd_ctl_elem_id_t *         elemidp = NULL;
439
440
441 #define EXIT_ON_ERROR(f,txt,exitcode) do \
442 { \
443     int err; \
444     if ( (err = (f) ) < 0) \
445     { \
446         ERR(txt " failed: %s\n", snd_strerror(err)); \
447         rc = exitcode; \
448         goto out; \
449     } \
450 } while(0)
451
452     if (! hctl)
453         return MMSYSERR_NOTSUPPORTED;
454
455     /* Allocate areas to return information about the volume */
456     EXIT_ON_ERROR(snd_ctl_elem_id_malloc(&elemidp), "snd_ctl_elem_id_malloc", MMSYSERR_NOMEM);
457     EXIT_ON_ERROR(snd_ctl_elem_value_malloc (&elemvaluep), "snd_ctl_elem_value_malloc", MMSYSERR_NOMEM);
458     EXIT_ON_ERROR(snd_ctl_elem_info_malloc (&eleminfop), "snd_ctl_elem_info_malloc", MMSYSERR_NOMEM);
459     snd_ctl_elem_id_clear(elemidp);
460     snd_ctl_elem_value_clear(elemvaluep);
461     snd_ctl_elem_info_clear(eleminfop);
462
463     /* Setup and find an element id that exactly matches the characteristic we want
464     ** FIXME:  It is probably short sighted to hard code and fixate on PCM Playback Volume */
465     snd_ctl_elem_id_set_name(elemidp, "PCM Playback Volume");
466     snd_ctl_elem_id_set_interface(elemidp, SND_CTL_ELEM_IFACE_MIXER);
467     elem = snd_hctl_find_elem(hctl, elemidp);
468     if (elem)
469     {
470         /* Read and return volume information */
471         EXIT_ON_ERROR(snd_hctl_elem_info(elem, eleminfop), "snd_hctl_elem_info", MMSYSERR_NOTSUPPORTED);
472         value_count = snd_ctl_elem_info_get_count(eleminfop);
473         if (out_min || out_max || out_step)
474         {
475             if (!snd_ctl_elem_info_is_readable(eleminfop))
476             {
477                 ERR("snd_ctl_elem_info_is_readable returned false; cannot return info\n");
478                 rc = MMSYSERR_NOTSUPPORTED;
479                 goto out;
480             }
481
482             if (out_min)
483                 *out_min = snd_ctl_elem_info_get_min(eleminfop);
484
485             if (out_max)
486                 *out_max = snd_ctl_elem_info_get_max(eleminfop);
487
488             if (out_step)
489                 *out_step = snd_ctl_elem_info_get_step(eleminfop);
490         }
491
492         if (out_left || out_right)
493         {
494             EXIT_ON_ERROR(snd_hctl_elem_read(elem, elemvaluep), "snd_hctl_elem_read", MMSYSERR_NOTSUPPORTED);
495
496             if (out_left)
497                 *out_left = snd_ctl_elem_value_get_integer(elemvaluep, 0);
498
499             if (out_right)
500             {
501                 if (value_count == 1)
502                     *out_right = snd_ctl_elem_value_get_integer(elemvaluep, 0);
503                 else if (value_count == 2)
504                     *out_right = snd_ctl_elem_value_get_integer(elemvaluep, 1);
505                 else
506                 {
507                     ERR("Unexpected value count %d from snd_ctl_elem_info_get_count while getting volume info\n", value_count);
508                     rc = -1;
509                     goto out;
510                 }
511             }
512         }
513
514         /* Set the volume */
515         if (new_left || new_right)
516         {
517             EXIT_ON_ERROR(snd_hctl_elem_read(elem, elemvaluep), "snd_hctl_elem_read", MMSYSERR_NOTSUPPORTED);
518             if (new_left)
519                 snd_ctl_elem_value_set_integer(elemvaluep, 0, *new_left);
520             if (new_right)
521             {
522                 if (value_count == 1)
523                     snd_ctl_elem_value_set_integer(elemvaluep, 0, *new_right);
524                 else if (value_count == 2)
525                     snd_ctl_elem_value_set_integer(elemvaluep, 1, *new_right);
526                 else
527                 {
528                     ERR("Unexpected value count %d from snd_ctl_elem_info_get_count while setting volume info\n", value_count);
529                     rc = -1;
530                     goto out;
531                 }
532             }
533
534             EXIT_ON_ERROR(snd_hctl_elem_write(elem, elemvaluep), "snd_hctl_elem_write", MMSYSERR_NOTSUPPORTED);
535         }
536     }
537     else
538     {
539         ERR("Could not find 'PCM Playback Volume' element\n");
540         rc = MMSYSERR_NOTSUPPORTED;
541     }
542
543
544 #undef EXIT_ON_ERROR
545
546 out:
547
548     if (elemvaluep)
549         snd_ctl_elem_value_free(elemvaluep);
550     if (eleminfop)
551         snd_ctl_elem_info_free(eleminfop);
552     if (elemidp)
553         snd_ctl_elem_id_free(elemidp);
554
555     return rc;
556 }
557
558
559 /**************************************************************************
560  *                      wine_snd_pcm_recover            [internal]
561  *
562  * Code slightly modified from alsa-lib v1.0.23 snd_pcm_recover implementation.
563  * used to recover from XRUN errors (buffer underflow/overflow)
564  */
565 int wine_snd_pcm_recover(snd_pcm_t *pcm, int err, int silent)
566 {
567     if (err > 0)
568         err = -err;
569     if (err == -EINTR)  /* nothing to do, continue */
570         return 0;
571     if (err == -EPIPE) {
572         const char *s;
573         if (snd_pcm_stream(pcm) == SND_PCM_STREAM_PLAYBACK)
574             s = "underrun";
575         else
576             s = "overrun";
577         if (!silent)
578             ERR("%s occurred\n", s);
579         err = snd_pcm_prepare(pcm);
580         if (err < 0) {
581             ERR("cannot recover from %s, prepare failed: %s\n", s, snd_strerror(err));
582             return err;
583         }
584         return 0;
585     }
586     if (err == -ESTRPIPE) {
587         while ((err = snd_pcm_resume(pcm)) == -EAGAIN)
588             /* wait until suspend flag is released */
589             poll(NULL, 0, 1000);
590         if (err < 0) {
591             err = snd_pcm_prepare(pcm);
592             if (err < 0) {
593                 ERR("cannot recover from suspend, prepare failed: %s\n", snd_strerror(err));
594                 return err;
595             }
596         }
597         return 0;
598     }
599     return err;
600 }
601
602 /**************************************************************************
603  *                      ALSA_TraceParameters            [internal]
604  *
605  * used to trace format changes, hw and sw parameters
606  */
607 void ALSA_TraceParameters(snd_pcm_hw_params_t * hw_params, snd_pcm_sw_params_t * sw, int full)
608 {
609     int err;
610     snd_pcm_format_t   format;
611     snd_pcm_access_t   access;
612
613 #define X(x) ((x)? "true" : "false")
614     if (full)
615         TRACE("FLAGS: sampleres=%s overrng=%s pause=%s resume=%s syncstart=%s batch=%s block=%s double=%s "
616               "halfd=%s joint=%s\n",
617               X(snd_pcm_hw_params_can_mmap_sample_resolution(hw_params)),
618               X(snd_pcm_hw_params_can_overrange(hw_params)),
619               X(snd_pcm_hw_params_can_pause(hw_params)),
620               X(snd_pcm_hw_params_can_resume(hw_params)),
621               X(snd_pcm_hw_params_can_sync_start(hw_params)),
622               X(snd_pcm_hw_params_is_batch(hw_params)),
623               X(snd_pcm_hw_params_is_block_transfer(hw_params)),
624               X(snd_pcm_hw_params_is_double(hw_params)),
625               X(snd_pcm_hw_params_is_half_duplex(hw_params)),
626               X(snd_pcm_hw_params_is_joint_duplex(hw_params)));
627 #undef X
628
629     err = snd_pcm_hw_params_get_access(hw_params, &access);
630     if (err >= 0)
631     {
632         TRACE("access=%s\n", snd_pcm_access_name(access));
633     }
634     else
635     {
636         snd_pcm_access_mask_t * acmask;
637
638         acmask = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_access_mask_sizeof());
639         snd_pcm_hw_params_get_access_mask(hw_params, acmask);
640         for ( access = SND_PCM_ACCESS_MMAP_INTERLEAVED; access <= SND_PCM_ACCESS_LAST; access++)
641             if (snd_pcm_access_mask_test(acmask, access))
642                 TRACE("access=%s\n", snd_pcm_access_name(access));
643         HeapFree( GetProcessHeap(), 0, acmask );
644     }
645
646     err = snd_pcm_hw_params_get_format(hw_params, &format);
647     if (err >= 0)
648     {
649         TRACE("format=%s\n", snd_pcm_format_name(format));
650
651     }
652     else
653     {
654         snd_pcm_format_mask_t *     fmask;
655
656         fmask = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, snd_pcm_format_mask_sizeof());
657         snd_pcm_hw_params_get_format_mask(hw_params, fmask);
658         for ( format = SND_PCM_FORMAT_S8; format <= SND_PCM_FORMAT_LAST ; format++)
659             if ( snd_pcm_format_mask_test(fmask, format) )
660                 TRACE("format=%s\n", snd_pcm_format_name(format));
661         HeapFree( GetProcessHeap(), 0, fmask );
662     }
663
664     do {
665       int err=0;
666       unsigned int val=0;
667       err = snd_pcm_hw_params_get_channels(hw_params, &val);
668       if (err<0) {
669         unsigned int min = 0;
670         unsigned int max = 0;
671         err = snd_pcm_hw_params_get_channels_min(hw_params, &min),
672         err = snd_pcm_hw_params_get_channels_max(hw_params, &max);
673         TRACE("channels_min=%u, channels_min_max=%u\n", min, max);
674       } else {
675         TRACE("channels=%d\n", val);
676       }
677     } while(0);
678     do {
679       int err=0;
680       snd_pcm_uframes_t val=0;
681       err = snd_pcm_hw_params_get_buffer_size(hw_params, &val);
682       if (err<0) {
683         snd_pcm_uframes_t min = 0;
684         snd_pcm_uframes_t max = 0;
685         err = snd_pcm_hw_params_get_buffer_size_min(hw_params, &min),
686         err = snd_pcm_hw_params_get_buffer_size_max(hw_params, &max);
687         TRACE("buffer_size_min=%lu, buffer_size_min_max=%lu\n", min, max);
688       } else {
689         TRACE("buffer_size=%lu\n", val);
690       }
691     } while(0);
692
693 #define X(x) do { \
694 int err=0; \
695 int dir=0; \
696 unsigned int val=0; \
697 err = snd_pcm_hw_params_get_##x(hw_params,&val, &dir); \
698 if (err<0) { \
699   unsigned int min = 0; \
700   unsigned int max = 0; \
701   err = snd_pcm_hw_params_get_##x##_min(hw_params, &min, &dir); \
702   err = snd_pcm_hw_params_get_##x##_max(hw_params, &max, &dir); \
703   TRACE(#x "_min=%u " #x "_max=%u\n", min, max); \
704 } else \
705     TRACE(#x "=%d\n", val); \
706 } while(0)
707
708     X(rate);
709     X(buffer_time);
710     X(periods);
711     do {
712       int err=0;
713       int dir=0;
714       snd_pcm_uframes_t val=0;
715       err = snd_pcm_hw_params_get_period_size(hw_params, &val, &dir);
716       if (err<0) {
717         snd_pcm_uframes_t min = 0;
718         snd_pcm_uframes_t max = 0;
719         err = snd_pcm_hw_params_get_period_size_min(hw_params, &min, &dir),
720         err = snd_pcm_hw_params_get_period_size_max(hw_params, &max, &dir);
721         TRACE("period_size_min=%lu, period_size_min_max=%lu\n", min, max);
722       } else {
723         TRACE("period_size=%lu\n", val);
724       }
725     } while(0);
726
727     X(period_time);
728 #undef X
729
730     if (!sw)
731         return;
732 }
733
734 #endif
735
736 /**************************************************************************
737  *                              DriverProc (WINEALSA.@)
738  */
739 LRESULT CALLBACK ALSA_DriverProc(DWORD_PTR dwDevID, HDRVR hDriv, UINT wMsg,
740                                  LPARAM dwParam1, LPARAM dwParam2)
741 {
742 /* EPP     TRACE("(%08lX, %04X, %08lX, %08lX, %08lX)\n",  */
743 /* EPP    dwDevID, hDriv, wMsg, dwParam1, dwParam2); */
744
745     switch(wMsg) {
746 #ifdef HAVE_ALSA
747     case DRV_LOAD:
748     case DRV_FREE:
749     case DRV_OPEN:
750     case DRV_CLOSE:
751     case DRV_ENABLE:
752     case DRV_DISABLE:
753     case DRV_QUERYCONFIGURE:
754         return 1;
755     case DRV_CONFIGURE:         MessageBoxA(0, "ALSA MultiMedia Driver !", "ALSA Driver", MB_OK);       return 1;
756     case DRV_INSTALL:
757     case DRV_REMOVE:
758         return DRV_SUCCESS;
759 #endif
760     default:
761         return 0;
762     }
763 }