~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/wineoss.drv/audio.c

Version: ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * Sample Wine Driver for Open Sound System (featured in Linux and FreeBSD)
  3  *
  4  * Copyright 1994 Martin Ayotte
  5  *           1999 Eric Pouech (async playing in waveOut/waveIn)
  6  *           2000 Eric Pouech (loops in waveOut)
  7  *           2002 Eric Pouech (full duplex)
  8  *
  9  * This library is free software; you can redistribute it and/or
 10  * modify it under the terms of the GNU Lesser General Public
 11  * License as published by the Free Software Foundation; either
 12  * version 2.1 of the License, or (at your option) any later version.
 13  *
 14  * This library is distributed in the hope that it will be useful,
 15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17  * Lesser General Public License for more details.
 18  *
 19  * You should have received a copy of the GNU Lesser General Public
 20  * License along with this library; if not, write to the Free Software
 21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 22  */
 23 /*
 24  * FIXME:
 25  *      pause in waveOut does not work correctly in loop mode
 26  *      Direct Sound Capture driver does not work (not complete yet)
 27  */
 28 
 29 /* an exact wodGetPosition is usually not worth the extra context switches,
 30  * as we're going to have near fragment accuracy anyway */
 31 #define EXACT_WODPOSITION
 32 #define EXACT_WIDPOSITION
 33 
 34 #include "config.h"
 35 #include "wine/port.h"
 36 
 37 #include <stdlib.h>
 38 #include <stdarg.h>
 39 #include <stdio.h>
 40 #include <string.h>
 41 #ifdef HAVE_UNISTD_H
 42 # include <unistd.h>
 43 #endif
 44 #include <errno.h>
 45 #include <fcntl.h>
 46 #ifdef HAVE_SYS_IOCTL_H
 47 # include <sys/ioctl.h>
 48 #endif
 49 #ifdef HAVE_SYS_MMAN_H
 50 # include <sys/mman.h>
 51 #endif
 52 #ifdef HAVE_POLL_H
 53 #include <poll.h>
 54 #endif
 55 #ifdef HAVE_SYS_POLL_H
 56 # include <sys/poll.h>
 57 #endif
 58 
 59 #include "windef.h"
 60 #include "winbase.h"
 61 #include "wingdi.h"
 62 #include "winuser.h"
 63 #include "winnls.h"
 64 #include "winerror.h"
 65 #include "mmddk.h"
 66 #include "mmreg.h"
 67 #include "dsound.h"
 68 #include "ks.h"
 69 #include "ksguid.h"
 70 #include "ksmedia.h"
 71 #include "initguid.h"
 72 #include "dsdriver.h"
 73 #include "oss.h"
 74 #include "wine/debug.h"
 75 
 76 #include "audio.h"
 77 
 78 WINE_DEFAULT_DEBUG_CHANNEL(wave);
 79 
 80 /* Allow 1% deviation for sample rates (some ES137x cards) */
 81 #define NEAR_MATCH(rate1,rate2) (((100*((int)(rate1)-(int)(rate2)))/(rate1))==0)
 82 
 83 #ifdef HAVE_OSS
 84 
 85 WINE_WAVEOUT    WOutDev[MAX_WAVEDRV];
 86 WINE_WAVEIN     WInDev[MAX_WAVEDRV];
 87 unsigned        numOutDev;
 88 unsigned        numInDev;
 89 
 90 /* state diagram for waveOut writing:
 91  *
 92  * +---------+-------------+---------------+---------------------------------+
 93  * |  state  |  function   |     event     |            new state            |
 94  * +---------+-------------+---------------+---------------------------------+
 95  * |         | open()      |               | STOPPED                         |
 96  * | PAUSED  | write()     |               | PAUSED                          |
 97  * | STOPPED | write()     | <thrd create> | PLAYING                         |
 98  * | PLAYING | write()     | HEADER        | PLAYING                         |
 99  * | (other) | write()     | <error>       |                                 |
100  * | (any)   | pause()     | PAUSING       | PAUSED                          |
101  * | PAUSED  | restart()   | RESTARTING    | PLAYING (if no thrd => STOPPED) |
102  * | (any)   | reset()     | RESETTING     | STOPPED                         |
103  * | (any)   | close()     | CLOSING       | CLOSED                          |
104  * +---------+-------------+---------------+---------------------------------+
105  */
106 
107 /* These strings used only for tracing */
108 static const char * getCmdString(enum win_wm_message msg)
109 {
110     static char unknown[32];
111 #define MSG_TO_STR(x) case x: return #x
112     switch(msg) {
113     MSG_TO_STR(WINE_WM_PAUSING);
114     MSG_TO_STR(WINE_WM_RESTARTING);
115     MSG_TO_STR(WINE_WM_RESETTING);
116     MSG_TO_STR(WINE_WM_HEADER);
117     MSG_TO_STR(WINE_WM_UPDATE);
118     MSG_TO_STR(WINE_WM_BREAKLOOP);
119     MSG_TO_STR(WINE_WM_CLOSING);
120     MSG_TO_STR(WINE_WM_STARTING);
121     MSG_TO_STR(WINE_WM_STOPPING);
122     }
123 #undef MSG_TO_STR
124     sprintf(unknown, "UNKNOWN(0x%08x)", msg);
125     return unknown;
126 }
127 
128 int getEnables(OSS_DEVICE *ossdev)
129 {
130     return ( (ossdev->bOutputEnabled ? PCM_ENABLE_OUTPUT : 0) |
131              (ossdev->bInputEnabled  ? PCM_ENABLE_INPUT  : 0) );
132 }
133 
134 static const char * getMessage(UINT msg)
135 {
136     static char unknown[32];
137 #define MSG_TO_STR(x) case x: return #x
138     switch(msg) {
139     MSG_TO_STR(DRVM_INIT);
140     MSG_TO_STR(DRVM_EXIT);
141     MSG_TO_STR(DRVM_ENABLE);
142     MSG_TO_STR(DRVM_DISABLE);
143     MSG_TO_STR(WIDM_OPEN);
144     MSG_TO_STR(WIDM_CLOSE);
145     MSG_TO_STR(WIDM_ADDBUFFER);
146     MSG_TO_STR(WIDM_PREPARE);
147     MSG_TO_STR(WIDM_UNPREPARE);
148     MSG_TO_STR(WIDM_GETDEVCAPS);
149     MSG_TO_STR(WIDM_GETNUMDEVS);
150     MSG_TO_STR(WIDM_GETPOS);
151     MSG_TO_STR(WIDM_RESET);
152     MSG_TO_STR(WIDM_START);
153     MSG_TO_STR(WIDM_STOP);
154     MSG_TO_STR(WODM_OPEN);
155     MSG_TO_STR(WODM_CLOSE);
156     MSG_TO_STR(WODM_WRITE);
157     MSG_TO_STR(WODM_PAUSE);
158     MSG_TO_STR(WODM_GETPOS);
159     MSG_TO_STR(WODM_BREAKLOOP);
160     MSG_TO_STR(WODM_PREPARE);
161     MSG_TO_STR(WODM_UNPREPARE);
162     MSG_TO_STR(WODM_GETDEVCAPS);
163     MSG_TO_STR(WODM_GETNUMDEVS);
164     MSG_TO_STR(WODM_GETPITCH);
165     MSG_TO_STR(WODM_SETPITCH);
166     MSG_TO_STR(WODM_GETPLAYBACKRATE);
167     MSG_TO_STR(WODM_SETPLAYBACKRATE);
168     MSG_TO_STR(WODM_GETVOLUME);
169     MSG_TO_STR(WODM_SETVOLUME);
170     MSG_TO_STR(WODM_RESTART);
171     MSG_TO_STR(WODM_RESET);
172     MSG_TO_STR(DRV_QUERYDEVICEINTERFACESIZE);
173     MSG_TO_STR(DRV_QUERYDEVICEINTERFACE);
174     MSG_TO_STR(DRV_QUERYDSOUNDIFACE);
175     MSG_TO_STR(DRV_QUERYDSOUNDDESC);
176     }
177 #undef MSG_TO_STR
178     sprintf(unknown, "UNKNOWN(0x%04x)", msg);
179     return unknown;
180 }
181 
182 static DWORD wodDevInterfaceSize(UINT wDevID, LPDWORD dwParam1)
183 {
184     TRACE("(%u, %p)\n", wDevID, dwParam1);
185 
186     *dwParam1 = MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].ossdev.interface_name, -1,
187                                     NULL, 0 ) * sizeof(WCHAR);
188     return MMSYSERR_NOERROR;
189 }
190 
191 static DWORD wodDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2)
192 {
193     if (dwParam2 >= MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].ossdev.interface_name, -1,
194                                         NULL, 0 ) * sizeof(WCHAR))
195     {
196         MultiByteToWideChar(CP_ACP, 0, WOutDev[wDevID].ossdev.interface_name, -1,
197                             dwParam1, dwParam2 / sizeof(WCHAR));
198         return MMSYSERR_NOERROR;
199     }
200 
201     return MMSYSERR_INVALPARAM;
202 }
203 
204 static DWORD widDevInterfaceSize(UINT wDevID, LPDWORD dwParam1)
205 {
206     TRACE("(%u, %p)\n", wDevID, dwParam1);
207 
208     *dwParam1 = MultiByteToWideChar(CP_ACP, 0, WInDev[wDevID].ossdev.interface_name, -1,
209                                     NULL, 0 ) * sizeof(WCHAR);
210     return MMSYSERR_NOERROR;
211 }
212 
213 static DWORD widDevInterface(UINT wDevID, PWCHAR dwParam1, DWORD dwParam2)
214 {
215     if (dwParam2 >= MultiByteToWideChar(CP_ACP, 0, WInDev[wDevID].ossdev.interface_name, -1,
216                                         NULL, 0 ) * sizeof(WCHAR))
217     {
218         MultiByteToWideChar(CP_ACP, 0, WInDev[wDevID].ossdev.interface_name, -1,
219                             dwParam1, dwParam2 / sizeof(WCHAR));
220         return MMSYSERR_NOERROR;
221     }
222 
223     return MMSYSERR_INVALPARAM;
224 }
225 
226 static DWORD bytes_to_mmtime(LPMMTIME lpTime, DWORD position,
227                              WAVEFORMATPCMEX* format)
228 {
229     TRACE("wType=%04X wBitsPerSample=%u nSamplesPerSec=%u nChannels=%u nAvgBytesPerSec=%u\n",
230           lpTime->wType, format->Format.wBitsPerSample, format->Format.nSamplesPerSec,
231           format->Format.nChannels, format->Format.nAvgBytesPerSec);
232     TRACE("Position in bytes=%u\n", position);
233 
234     switch (lpTime->wType) {
235     case TIME_SAMPLES:
236         lpTime->u.sample = position / (format->Format.wBitsPerSample / 8 * format->Format.nChannels);
237         TRACE("TIME_SAMPLES=%u\n", lpTime->u.sample);
238         break;
239     case TIME_MS:
240         lpTime->u.ms = 1000.0 * position / (format->Format.wBitsPerSample / 8 * format->Format.nChannels * format->Format.nSamplesPerSec);
241         TRACE("TIME_MS=%u\n", lpTime->u.ms);
242         break;
243     case TIME_SMPTE:
244         lpTime->u.smpte.fps = 30;
245         position = position / (format->Format.wBitsPerSample / 8 * format->Format.nChannels);
246         position += (format->Format.nSamplesPerSec / lpTime->u.smpte.fps) - 1; /* round up */
247         lpTime->u.smpte.sec = position / format->Format.nSamplesPerSec;
248         position -= lpTime->u.smpte.sec * format->Format.nSamplesPerSec;
249         lpTime->u.smpte.min = lpTime->u.smpte.sec / 60;
250         lpTime->u.smpte.sec -= 60 * lpTime->u.smpte.min;
251         lpTime->u.smpte.hour = lpTime->u.smpte.min / 60;
252         lpTime->u.smpte.min -= 60 * lpTime->u.smpte.hour;
253         lpTime->u.smpte.fps = 30;
254         lpTime->u.smpte.frame = position * lpTime->u.smpte.fps / format->Format.nSamplesPerSec;
255         TRACE("TIME_SMPTE=%02u:%02u:%02u:%02u\n",
256               lpTime->u.smpte.hour, lpTime->u.smpte.min,
257               lpTime->u.smpte.sec, lpTime->u.smpte.frame);
258         break;
259     default:
260         WARN("Format %d not supported, using TIME_BYTES !\n", lpTime->wType);
261         lpTime->wType = TIME_BYTES;
262         /* fall through */
263     case TIME_BYTES:
264         lpTime->u.cb = position;
265         TRACE("TIME_BYTES=%u\n", lpTime->u.cb);
266         break;
267     }
268     return MMSYSERR_NOERROR;
269 }
270 
271 static BOOL supportedFormat(LPWAVEFORMATEX wf)
272 {
273     TRACE("(%p)\n",wf);
274 
275     if (wf->nSamplesPerSec<DSBFREQUENCY_MIN||wf->nSamplesPerSec>DSBFREQUENCY_MAX)
276         return FALSE;
277 
278     if (wf->wFormatTag == WAVE_FORMAT_PCM) {
279         if (wf->nChannels >= 1 && wf->nChannels <= MAX_CHANNELS) {
280             if (wf->wBitsPerSample==8||wf->wBitsPerSample==16)
281                 return TRUE;
282         }
283     } else if (wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
284         WAVEFORMATEXTENSIBLE * wfex = (WAVEFORMATEXTENSIBLE *)wf;
285 
286         if (wf->cbSize == 22 && IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) {
287             if (wf->nChannels >=1 && wf->nChannels <= MAX_CHANNELS) {
288                 if (wf->wBitsPerSample==wfex->Samples.wValidBitsPerSample) {
289                     if (wf->wBitsPerSample==8||wf->wBitsPerSample==16)
290                         return TRUE;
291                 } else
292                     WARN("wBitsPerSample != wValidBitsPerSample not supported yet\n");
293             }
294         } else
295             WARN("only KSDATAFORMAT_SUBTYPE_PCM supported\n");
296     } else
297         WARN("only WAVE_FORMAT_PCM and WAVE_FORMAT_EXTENSIBLE supported\n");
298 
299     return FALSE;
300 }
301 
302 void copy_format(LPWAVEFORMATEX wf1, LPWAVEFORMATPCMEX wf2)
303 {
304     ZeroMemory(wf2, sizeof(wf2));
305     if (wf1->wFormatTag == WAVE_FORMAT_PCM)
306         memcpy(wf2, wf1, sizeof(PCMWAVEFORMAT));
307     else if (wf1->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
308         memcpy(wf2, wf1, sizeof(WAVEFORMATPCMEX));
309     else
310         memcpy(wf2, wf1, sizeof(WAVEFORMATEX) + wf1->cbSize);
311 }
312 
313 /*======================================================================*
314  *                  Low level WAVE implementation                       *
315  *======================================================================*/
316 
317 /******************************************************************
318  *              OSS_RawOpenDevice
319  *
320  * Low level device opening (from values stored in ossdev)
321  */
322 static DWORD      OSS_RawOpenDevice(OSS_DEVICE* ossdev, int strict_format)
323 {
324     int fd, val, rc;
325     TRACE("(%p,%d)\n",ossdev,strict_format);
326 
327     TRACE("open_access=%s\n",
328         ossdev->open_access == O_RDONLY ? "O_RDONLY" :
329         ossdev->open_access == O_WRONLY ? "O_WRONLY" :
330         ossdev->open_access == O_RDWR ? "O_RDWR" : "Unknown");
331 
332     if ((fd = open(ossdev->dev_name, ossdev->open_access|O_NDELAY, 0)) == -1)
333     {
334         WARN("Couldn't open %s (%s)\n", ossdev->dev_name, strerror(errno));
335         return (errno == EBUSY) ? MMSYSERR_ALLOCATED : MMSYSERR_ERROR;
336     }
337     fcntl(fd, F_SETFD, 1); /* set close on exec flag */
338     /* turn full duplex on if it has been requested */
339     if (ossdev->open_access == O_RDWR && ossdev->full_duplex) {
340         rc = ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
341         /* on *BSD, as full duplex is always enabled by default, this ioctl
342          * will fail with EINVAL
343          * so, we don't consider EINVAL an error here
344          */
345         if (rc != 0 && errno != EINVAL) {
346             WARN("ioctl(%s, SNDCTL_DSP_SETDUPLEX) failed (%s)\n", ossdev->dev_name, strerror(errno));
347             goto error2;
348         }
349     }
350 
351     if (ossdev->audio_fragment) {
352         rc = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &ossdev->audio_fragment);
353         if (rc != 0) {
354             ERR("ioctl(%s, SNDCTL_DSP_SETFRAGMENT) failed (%s)\n", ossdev->dev_name, strerror(errno));
355             goto error2;
356         }
357     }
358 
359     /* First size and channels then samplerate */
360     if (ossdev->format>=0)
361     {
362         val = ossdev->format;
363         rc = ioctl(fd, SNDCTL_DSP_SETFMT, &ossdev->format);
364         if (rc != 0 || val != ossdev->format) {
365             TRACE("Can't set format to %d (returned %d)\n", val, ossdev->format);
366             if (strict_format)
367                 goto error;
368         }
369     }
370     if (ossdev->channels>=0)
371     {
372         val = ossdev->channels;
373         rc = ioctl(fd, SNDCTL_DSP_CHANNELS, &ossdev->channels);
374         if (rc != 0 || val != ossdev->channels) {
375             TRACE("Can't set channels to %u (returned %d)\n", val, ossdev->channels);
376             if (strict_format)
377                 goto error;
378         }
379     }
380     if (ossdev->sample_rate>=0)
381     {
382         val = ossdev->sample_rate;
383         rc = ioctl(fd, SNDCTL_DSP_SPEED, &ossdev->sample_rate);
384         if (rc != 0 || !NEAR_MATCH(val, ossdev->sample_rate)) {
385             TRACE("Can't set sample_rate to %u (returned %d)\n", val, ossdev->sample_rate);
386             if (strict_format)
387                 goto error;
388         }
389     }
390     ossdev->fd = fd;
391 
392     ossdev->bOutputEnabled = TRUE;      /* OSS enables by default */
393     ossdev->bInputEnabled  = TRUE;      /* OSS enables by default */
394     if (ossdev->open_access == O_RDONLY)
395         ossdev->bOutputEnabled = FALSE;
396     if (ossdev->open_access == O_WRONLY)
397         ossdev->bInputEnabled = FALSE;
398 
399     if (ossdev->bTriggerSupport) {
400         int trigger;
401         trigger = getEnables(ossdev);
402         /* If we do not have full duplex, but they opened RDWR 
403         ** (as you have to in order for an mmap to succeed)
404         ** then we start out with input off
405         */
406         if (ossdev->open_access == O_RDWR && !ossdev->full_duplex && 
407             ossdev->bInputEnabled && ossdev->bOutputEnabled) {
408             ossdev->bInputEnabled  = FALSE;
409             trigger &= ~PCM_ENABLE_INPUT;
410             ioctl(fd, SNDCTL_DSP_SETTRIGGER, &trigger);
411         }
412     }
413 
414     return MMSYSERR_NOERROR;
415 
416 error:
417     close(fd);
418     return WAVERR_BADFORMAT;
419 error2:
420     close(fd);
421     return MMSYSERR_ERROR;
422 }
423 
424 /******************************************************************
425  *              OSS_OpenDevice
426  *
427  * since OSS has poor capabilities in full duplex, we try here to let a program
428  * open the device for both waveout and wavein streams...
429  * this is hackish, but it's the way OSS interface is done...
430  */
431 DWORD OSS_OpenDevice(OSS_DEVICE* ossdev, unsigned req_access,
432                             int* frag, int strict_format,
433                             int sample_rate, int channels, int fmt)
434 {
435     DWORD       ret;
436     DWORD open_access;
437     TRACE("(%p,%u,%p,%d,%d,%d,%x)\n",ossdev,req_access,frag,strict_format,sample_rate,channels,fmt);
438 
439     if (ossdev->full_duplex && (req_access == O_RDONLY || req_access == O_WRONLY))
440     {
441         TRACE("Opening RDWR because full_duplex=%d and req_access=%d\n",
442               ossdev->full_duplex,req_access);
443         open_access = O_RDWR;
444     }
445     else
446     {
447         open_access=req_access;
448     }
449 
450     /* FIXME: this should be protected, and it also contains a race with OSS_CloseDevice */
451     if (ossdev->open_count == 0)
452     {
453         if (access(ossdev->dev_name, 0) != 0) return MMSYSERR_NODRIVER;
454 
455         ossdev->audio_fragment = (frag) ? *frag : 0;
456         ossdev->sample_rate = sample_rate;
457         ossdev->channels = channels;
458         ossdev->format = fmt;
459         ossdev->open_access = open_access;
460         ossdev->owner_tid = GetCurrentThreadId();
461 
462         if ((ret = OSS_RawOpenDevice(ossdev,strict_format)) != MMSYSERR_NOERROR) return ret;
463         if (ossdev->full_duplex && ossdev->bTriggerSupport &&
464             (req_access == O_RDONLY || req_access == O_WRONLY))
465         {
466             int enable;
467             if (req_access == O_WRONLY)
468                 ossdev->bInputEnabled=0;
469             else
470                 ossdev->bOutputEnabled=0;
471             enable = getEnables(ossdev);
472             TRACE("Calling SNDCTL_DSP_SETTRIGGER with %x\n",enable);
473             if (ioctl(ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0)
474                 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER, %d) failed (%s)\n",ossdev->dev_name, enable, strerror(errno));
475         }
476     }
477     else
478     {
479         /* check we really open with the same parameters */
480         if (ossdev->open_access != open_access)
481         {
482             ERR("FullDuplex: Mismatch in access. Your sound device is not full duplex capable.\n");
483             return WAVERR_BADFORMAT;
484         }
485 
486         /* check if the audio parameters are the same */
487         if (ossdev->sample_rate != sample_rate ||
488             ossdev->channels != channels ||
489             ossdev->format != fmt)
490         {
491             /* This is not a fatal error because MSACM might do the remapping */
492             WARN("FullDuplex: mismatch in PCM parameters for input and output\n"
493                  "OSS doesn't allow us different parameters\n"
494                  "audio_frag(%x/%x) sample_rate(%d/%d) channels(%d/%d) fmt(%d/%d)\n",
495                  ossdev->audio_fragment, frag ? *frag : 0,
496                  ossdev->sample_rate, sample_rate,
497                  ossdev->channels, channels,
498                  ossdev->format, fmt);
499             return WAVERR_BADFORMAT;
500         }
501         /* check if the fragment sizes are the same */
502         if (ossdev->audio_fragment != (frag ? *frag : 0) )
503         {
504             ERR("FullDuplex: Playback and Capture hardware acceleration levels are different.\n"
505                 "Please run winecfg, open \"Audio\" page and set\n"
506                 "\"Hardware Acceleration\" to \"Emulation\".\n");
507             return WAVERR_BADFORMAT;
508         }
509         if (GetCurrentThreadId() != ossdev->owner_tid)
510         {
511             WARN("Another thread is trying to access audio...\n");
512             return MMSYSERR_ERROR;
513         }
514         if (ossdev->full_duplex && ossdev->bTriggerSupport &&
515             (req_access == O_RDONLY || req_access == O_WRONLY))
516         {
517             int enable;
518             if (req_access == O_WRONLY)
519                 ossdev->bOutputEnabled=1;
520             else
521                 ossdev->bInputEnabled=1;
522             enable = getEnables(ossdev);
523             TRACE("Calling SNDCTL_DSP_SETTRIGGER with %x\n",enable);
524             if (ioctl(ossdev->fd, SNDCTL_DSP_SETTRIGGER, &enable) < 0)
525                 ERR("ioctl(%s, SNDCTL_DSP_SETTRIGGER, %d) failed (%s)\n",ossdev->dev_name, enable, strerror(errno));
526         }
527     }
528 
529     ossdev->open_count++;
530 
531     return MMSYSERR_NOERROR;
532 }
533 
534 /******************************************************************
535  *              OSS_CloseDevice
536  *
537  *
538  */
539 void    OSS_CloseDevice(OSS_DEVICE* ossdev)
540 {
541     TRACE("(%p)\n",ossdev);
542     if (ossdev->open_count>0) {
543         ossdev->open_count--;
544     } else {
545         WARN("OSS_CloseDevice called too many times\n");
546     }
547     if (ossdev->open_count == 0)
548     {
549         fcntl(ossdev->fd, F_SETFL, fcntl(ossdev->fd, F_GETFL) & ~O_NDELAY);
550         /* reset the device before we close it in case it is in a bad state */
551         ioctl(ossdev->fd, SNDCTL_DSP_RESET, 0);
552         if (close(ossdev->fd) != 0) FIXME("Cannot close %d: %s\n", ossdev->fd, strerror(errno));
553     }
554 }
555 
556 /******************************************************************
557  *              OSS_ResetDevice
558  *
559  * Resets the device. OSS Commercial requires the device to be closed
560  * after a SNDCTL_DSP_RESET ioctl call... this function implements
561  * this behavior...
562  * FIXME: This causes problems when doing full duplex so we really
563  * only reset when not doing full duplex. We need to do this better
564  * someday.
565  */
566 static DWORD     OSS_ResetDevice(OSS_DEVICE* ossdev)
567 {
568     DWORD       ret = MMSYSERR_NOERROR;
569     int         old_fd = ossdev->fd;
570     TRACE("(%p)\n", ossdev);
571 
572     if (ossdev->open_count == 1) {
573         if (ioctl(ossdev->fd, SNDCTL_DSP_RESET, NULL) == -1)
574         {
575             perror("ioctl SNDCTL_DSP_RESET");
576             return -1;
577         }
578         close(ossdev->fd);
579         ret = OSS_RawOpenDevice(ossdev, 1);
580         TRACE("Changing fd from %d to %d\n", old_fd, ossdev->fd);
581     } else
582         WARN("Not resetting device because it is in full duplex mode!\n");
583 
584     return ret;
585 }
586 
587 static const int win_std_oss_fmts[2]={AFMT_U8,AFMT_S16_LE};
588 static const int win_std_rates[5]={96000,48000,44100,22050,11025};
589 static const int win_std_formats[2][2][5]=
590     {{{WAVE_FORMAT_96M08, WAVE_FORMAT_48M08, WAVE_FORMAT_4M08,
591        WAVE_FORMAT_2M08,  WAVE_FORMAT_1M08},
592       {WAVE_FORMAT_96S08, WAVE_FORMAT_48S08, WAVE_FORMAT_4S08,
593        WAVE_FORMAT_2S08,  WAVE_FORMAT_1S08}},
594      {{WAVE_FORMAT_96M16, WAVE_FORMAT_48M16, WAVE_FORMAT_4M16,
595        WAVE_FORMAT_2M16,  WAVE_FORMAT_1M16},
596       {WAVE_FORMAT_96S16, WAVE_FORMAT_48S16, WAVE_FORMAT_4S16,
597        WAVE_FORMAT_2S16,  WAVE_FORMAT_1S16}},
598     };
599 
600 static void OSS_Info(int fd)
601 {
602     /* Note that this only reports the formats supported by the hardware.
603      * The driver may support other formats and do the conversions in
604      * software which is why we don't use this value
605      */
606     int oss_mask, oss_caps;
607     if (ioctl(fd, SNDCTL_DSP_GETFMTS, &oss_mask) >= 0) {
608         TRACE("Formats=%08x ( ", oss_mask);
609         if (oss_mask & AFMT_MU_LAW) TRACE("AFMT_MU_LAW ");
610         if (oss_mask & AFMT_A_LAW) TRACE("AFMT_A_LAW ");
611         if (oss_mask & AFMT_IMA_ADPCM) TRACE("AFMT_IMA_ADPCM ");
612         if (oss_mask & AFMT_U8) TRACE("AFMT_U8 ");
613         if (oss_mask & AFMT_S16_LE) TRACE("AFMT_S16_LE ");
614         if (oss_mask & AFMT_S16_BE) TRACE("AFMT_S16_BE ");
615         if (oss_mask & AFMT_S8) TRACE("AFMT_S8 ");
616         if (oss_mask & AFMT_U16_LE) TRACE("AFMT_U16_LE ");
617         if (oss_mask & AFMT_U16_BE) TRACE("AFMT_U16_BE ");
618         if (oss_mask & AFMT_MPEG) TRACE("AFMT_MPEG ");
619 #ifdef AFMT_AC3
620         if (oss_mask & AFMT_AC3) TRACE("AFMT_AC3 ");
621 #endif
622 #ifdef AFMT_VORBIS
623         if (oss_mask & AFMT_VORBIS) TRACE("AFMT_VORBIS ");
624 #endif
625 #ifdef AFMT_S32_LE
626         if (oss_mask & AFMT_S32_LE) TRACE("AFMT_S32_LE ");
627 #endif
628 #ifdef AFMT_S32_BE
629         if (oss_mask & AFMT_S32_BE) TRACE("AFMT_S32_BE ");
630 #endif
631 #ifdef AFMT_FLOAT
632         if (oss_mask & AFMT_FLOAT) TRACE("AFMT_FLOAT ");
633 #endif
634 #ifdef AFMT_S24_LE
635         if (oss_mask & AFMT_S24_LE) TRACE("AFMT_S24_LE ");
636 #endif
637 #ifdef AFMT_S24_BE
638         if (oss_mask & AFMT_S24_BE) TRACE("AFMT_S24_BE ");
639 #endif
640 #ifdef AFMT_SPDIF_RAW
641         if (oss_mask & AFMT_SPDIF_RAW) TRACE("AFMT_SPDIF_RAW ");
642 #endif
643         TRACE(")\n");
644     }
645     if (ioctl(fd, SNDCTL_DSP_GETCAPS, &oss_caps) >= 0) {
646         TRACE("Caps=%08x\n",oss_caps);
647         TRACE("\tRevision: %d\n", oss_caps&DSP_CAP_REVISION);
648         TRACE("\tDuplex: %s\n", oss_caps & DSP_CAP_DUPLEX ? "true" : "false");
649         TRACE("\tRealtime: %s\n", oss_caps & DSP_CAP_REALTIME ? "true" : "false");
650         TRACE("\tBatch: %s\n", oss_caps & DSP_CAP_BATCH ? "true" : "false");
651         TRACE("\tCoproc: %s\n", oss_caps & DSP_CAP_COPROC ? "true" : "false");
652         TRACE("\tTrigger: %s\n", oss_caps & DSP_CAP_TRIGGER ? "true" : "false");
653         TRACE("\tMmap: %s\n", oss_caps & DSP_CAP_MMAP ? "true" : "false");
654 #ifdef DSP_CAP_MULTI
655         TRACE("\tMulti: %s\n", oss_caps & DSP_CAP_MULTI ? "true" : "false");
656 #endif
657 #ifdef DSP_CAP_BIND
658         TRACE("\tBind: %s\n", oss_caps & DSP_CAP_BIND ? "true" : "false");
659 #endif
660 #ifdef DSP_CAP_INPUT
661         TRACE("\tInput: %s\n", oss_caps & DSP_CAP_INPUT ? "true" : "false");
662 #endif
663 #ifdef DSP_CAP_OUTPUT
664         TRACE("\tOutput: %s\n", oss_caps & DSP_CAP_OUTPUT ? "true" : "false");
665 #endif
666 #ifdef DSP_CAP_VIRTUAL
667         TRACE("\tVirtual: %s\n", oss_caps & DSP_CAP_VIRTUAL ? "true" : "false");
668 #endif
669 #ifdef DSP_CAP_ANALOGOUT
670         TRACE("\tAnalog Out: %s\n", oss_caps & DSP_CAP_ANALOGOUT ? "true" : "false");
671 #endif
672 #ifdef DSP_CAP_ANALOGIN
673         TRACE("\tAnalog In: %s\n", oss_caps & DSP_CAP_ANALOGIN ? "true" : "false");
674 #endif
675 #ifdef DSP_CAP_DIGITALOUT
676         TRACE("\tDigital Out: %s\n", oss_caps & DSP_CAP_DIGITALOUT ? "true" : "false");
677 #endif
678 #ifdef DSP_CAP_DIGITALIN
679         TRACE("\tDigital In: %s\n", oss_caps & DSP_CAP_DIGITALIN ? "true" : "false");
680 #endif
681 #ifdef DSP_CAP_ADMASK
682         TRACE("\tA/D Mask: %s\n", oss_caps & DSP_CAP_ADMASK ? "true" : "false");
683 #endif
684 #ifdef DSP_CAP_SHADOW
685         TRACE("\tShadow: %s\n", oss_caps & DSP_CAP_SHADOW ? "true" : "false");
686 #endif
687 #ifdef DSP_CH_MASK
688         TRACE("\tChannel Mask: %x\n", oss_caps & DSP_CH_MASK);
689 #endif
690 #ifdef DSP_CAP_SLAVE
691         TRACE("\tSlave: %s\n", oss_caps & DSP_CAP_SLAVE ? "true" : "false");
692 #endif
693     }
694 }
695 
696 /******************************************************************
697  *              OSS_WaveOutInit
698  *
699  *
700  */
701 static BOOL OSS_WaveOutInit(OSS_DEVICE* ossdev)
702 {
703     int rc,arg;
704     int f,c,r;
705     BOOL has_mixer = FALSE;
706     TRACE("(%p) %s\n", ossdev, ossdev->dev_name);
707 
708     if (OSS_OpenDevice(ossdev, O_WRONLY, NULL, 0,-1,-1,-1) != 0)
709         return FALSE;
710 
711     ioctl(ossdev->fd, SNDCTL_DSP_RESET, 0);
712 
713 #if defined(SNDCTL_MIXERINFO)
714     {
715         int mixer;
716         if ((mixer = open(ossdev->mixer_name, O_RDONLY|O_NDELAY)) >= 0) {
717             oss_mixerinfo info;
718             info.dev = 0;
719             if (ioctl(mixer, SNDCTL_MIXERINFO, &info) >= 0) {
720                 lstrcpynA(ossdev->ds_desc.szDesc, info.name, sizeof(info.name));
721                 strcpy(ossdev->ds_desc.szDrvname, "wineoss.drv");
722                 MultiByteToWideChar(CP_ACP, 0, info.name, sizeof(info.name),
723                                     ossdev->out_caps.szPname,
724                                     sizeof(ossdev->out_caps.szPname) / sizeof(WCHAR));
725                 TRACE("%s: %s\n", ossdev->mixer_name, ossdev->ds_desc.szDesc);
726                 has_mixer = TRUE;
727             } else {
728                 WARN("%s: cannot read SNDCTL_MIXERINFO!\n", ossdev->mixer_name);
729             }
730             close(mixer);
731         } else {
732             WARN("open(%s) failed (%s)\n", ossdev->mixer_name , strerror(errno));
733         }
734     }
735 #elif defined(SOUND_MIXER_INFO)
736     {
737         int mixer;
738         if ((mixer = open(ossdev->mixer_name, O_RDONLY|O_NDELAY)) >= 0) {
739             mixer_info info;
740             if (ioctl(mixer, SOUND_MIXER_INFO, &info) >= 0) {
741                 lstrcpynA(ossdev->ds_desc.szDesc, info.name, sizeof(info.name));
742                 strcpy(ossdev->ds_desc.szDrvname, "wineoss.drv");
743                 MultiByteToWideChar(CP_ACP, 0, info.name, sizeof(info.name), 
744                                     ossdev->out_caps.szPname, 
745                                     sizeof(ossdev->out_caps.szPname) / sizeof(WCHAR));
746                 TRACE("%s: %s\n", ossdev->mixer_name, ossdev->ds_desc.szDesc);
747                 has_mixer = TRUE;
748             } else {
749                 /* FreeBSD up to at least 5.2 provides this ioctl, but does not
750                  * implement it properly, and there are probably similar issues
751                  * on other platforms, so we warn but try to go ahead.
752                  */
753                 WARN("%s: cannot read SOUND_MIXER_INFO!\n", ossdev->mixer_name);
754             }
755             close(mixer);
756         } else {
757             WARN("open(%s) failed (%s)\n", ossdev->mixer_name , strerror(errno));
758         }
759     }
760 #endif /* SOUND_MIXER_INFO */
761 
762     if (WINE_TRACE_ON(wave))
763         OSS_Info(ossdev->fd);
764 
765     ossdev->out_caps.wMid = 0x00FF; /* Manufac ID */
766     ossdev->out_caps.wPid = 0x0001; /* Product ID */
767 
768     ossdev->out_caps.vDriverVersion = 0x0100;
769     ossdev->out_caps.wChannels = 1;
770     ossdev->out_caps.dwFormats = 0x00000000;
771     ossdev->out_caps.wReserved1 = 0;
772     ossdev->out_caps.dwSupport = has_mixer ? WAVECAPS_VOLUME : 0;
773 
774     /* direct sound caps */
775     ossdev->ds_caps.dwFlags = DSCAPS_CERTIFIED;
776     ossdev->ds_caps.dwFlags |= DSCAPS_SECONDARY8BIT;
777     ossdev->ds_caps.dwFlags |= DSCAPS_SECONDARY16BIT;
778     ossdev->ds_caps.dwFlags |= DSCAPS_SECONDARYMONO;
779     ossdev->ds_caps.dwFlags |= DSCAPS_SECONDARYSTEREO;
780     ossdev->ds_caps.dwFlags |= DSCAPS_CONTINUOUSRATE;
781 
782     ossdev->ds_caps.dwPrimaryBuffers = 1;
783     ossdev->ds_caps.dwMinSecondarySampleRate = DSBFREQUENCY_MIN;
784     ossdev->ds_caps.dwMaxSecondarySampleRate = DSBFREQUENCY_MAX;
785 
786     /* We must first set the format and the stereo mode as some sound cards
787      * may support 44kHz mono but not 44kHz stereo. Also we must
788      * systematically check the return value of these ioctls as they will
789      * always succeed (see OSS Linux) but will modify the parameter to match
790      * whatever they support. The OSS specs also say we must first set the
791      * sample size, then the stereo and then the sample rate.
792      */
793     for (f=0;f<2;f++) {
794         arg=win_std_oss_fmts[f];
795         rc=ioctl(ossdev->fd, SNDCTL_DSP_SAMPLESIZE, &arg);
796         if (rc!=0 || arg!=win_std_oss_fmts[f]) {
797             TRACE("DSP_SAMPLESIZE: rc=%d returned %d for %d\n",
798                   rc,arg,win_std_oss_fmts[f]);
799             continue;
800         }
801         if (f == 0)
802             ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARY8BIT;
803         else if (f == 1)
804             ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARY16BIT;
805 
806         for (c = 1; c <= MAX_CHANNELS; c++) {
807             arg=c;
808             rc=ioctl(ossdev->fd, SNDCTL_DSP_CHANNELS, &arg);
809             if( rc == -1) break;
810             if (rc!=0 || arg!=c) {
811                 TRACE("DSP_CHANNELS: rc=%d returned %d for %d\n",rc,arg,c);
812                 continue;
813             }
814             if (c == 1) {
815                 ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARYMONO;
816             } else if (c == 2) {
817                 ossdev->out_caps.wChannels = 2;
818                 if (has_mixer)
819                     ossdev->out_caps.dwSupport|=WAVECAPS_LRVOLUME;
820                 ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARYSTEREO;
821             } else
822                 ossdev->out_caps.wChannels = c;
823 
824             for (r=0;r<sizeof(win_std_rates)/sizeof(*win_std_rates);r++) {
825                 arg=win_std_rates[r];
826                 rc=ioctl(ossdev->fd, SNDCTL_DSP_SPEED, &arg);
827                 TRACE("DSP_SPEED: rc=%d returned %d for %dx%dx%d\n",
828                       rc,arg,win_std_rates[r],win_std_oss_fmts[f],c);
829                 if (rc==0 && arg!=0 && NEAR_MATCH(arg,win_std_rates[r]) && c < 3)
830                     ossdev->out_caps.dwFormats|=win_std_formats[f][c-1][r];
831             }
832         }
833     }
834 
835     if (ioctl(ossdev->fd, SNDCTL_DSP_GETCAPS, &arg) == 0) {
836         if (arg & DSP_CAP_TRIGGER)
837             ossdev->bTriggerSupport = TRUE;
838         if ((arg & DSP_CAP_REALTIME) && !(arg & DSP_CAP_BATCH)) {
839             ossdev->out_caps.dwSupport |= WAVECAPS_SAMPLEACCURATE;
840         }
841         /* well, might as well use the DirectSound cap flag for something */
842         if ((arg & DSP_CAP_TRIGGER) && (arg & DSP_CAP_MMAP) &&
843             !(arg & DSP_CAP_BATCH)) {
844             ossdev->out_caps.dwSupport |= WAVECAPS_DIRECTSOUND;
845         } else {
846             ossdev->ds_caps.dwFlags |= DSCAPS_EMULDRIVER;
847         }
848 #ifdef DSP_CAP_MULTI    /* not every oss has this */
849         /* check for hardware secondary buffer support (multi open) */
850         if ((arg & DSP_CAP_MULTI) &&
851             (ossdev->out_caps.dwSupport & WAVECAPS_DIRECTSOUND)) {
852             TRACE("hardware secondary buffer support available\n");
853 
854             ossdev->ds_caps.dwMaxHwMixingAllBuffers = 16;
855             ossdev->ds_caps.dwMaxHwMixingStaticBuffers = 0;
856             ossdev->ds_caps.dwMaxHwMixingStreamingBuffers = 16;
857 
858             ossdev->ds_caps.dwFreeHwMixingAllBuffers = 16;
859             ossdev->ds_caps.dwFreeHwMixingStaticBuffers = 0;
860             ossdev->ds_caps.dwFreeHwMixingStreamingBuffers = 16;
861         }
862 #endif
863     }
864     OSS_CloseDevice(ossdev);
865     TRACE("out wChannels = %d, dwFormats = %08X, dwSupport = %08X\n",
866           ossdev->out_caps.wChannels, ossdev->out_caps.dwFormats,
867           ossdev->out_caps.dwSupport);
868     return TRUE;
869 }
870 
871 /******************************************************************
872  *              OSS_WaveInInit
873  *
874  *
875  */
876 static BOOL OSS_WaveInInit(OSS_DEVICE* ossdev)
877 {
878     int rc,arg;
879     int f,c,r;
880     TRACE("(%p) %s\n", ossdev, ossdev->dev_name);
881 
882     if (OSS_OpenDevice(ossdev, O_RDONLY, NULL, 0,-1,-1,-1) != 0)
883         return FALSE;
884 
885     ioctl(ossdev->fd, SNDCTL_DSP_RESET, 0);
886