This modifies OSS_Wave{In,Out}Init to report the exact capabilities of the OSS driver. The new code does not try to use SNDCTL_DSP_SETFMTS since some (old) cards may support 16bit or stereo audio at some sample rates but not other (higher) rates. It now also reports the 48kHz and 96kHz formats if they are supported. Changelog: Francois Gouget <fgouget@codeweavers.com> * dlls/winmm/wineoss/audio.c Modify OSS_Wave{In,Out}Init to report the exact capabilities of the OSS driver. Add support for the 48kHz and 96kHz formats. -- Francois Gouget fgouget@codeweavers.com
Index: dlls/winmm/wineoss/audio.c =================================================================== RCS file: /home/wine/wine/dlls/winmm/wineoss/audio.c,v retrieving revision 1.70 diff -u -r1.70 audio.c --- dlls/winmm/wineoss/audio.c 7 Jan 2003 23:08:05 -0000 1.70 +++ dlls/winmm/wineoss/audio.c 9 Jan 2003 08:18:33 -0000 @@ -405,24 +459,30 @@ return ret; } +const static int win_std_oss_fmts[2]={AFMT_U8,AFMT_S16_LE}; +const static int win_std_rates[5]={96000,48000,44100,22050,11025}; +const static int win_std_formats[2][2][5]= + {{{WAVE_FORMAT_96M08, WAVE_FORMAT_48M08, WAVE_FORMAT_4M08, + WAVE_FORMAT_2M08, WAVE_FORMAT_1M08}, + {WAVE_FORMAT_96S08, WAVE_FORMAT_48S08, WAVE_FORMAT_4S08, + WAVE_FORMAT_2S08, WAVE_FORMAT_1S08}}, + {{WAVE_FORMAT_96M16, WAVE_FORMAT_48M16, WAVE_FORMAT_4M16, + WAVE_FORMAT_2M16, WAVE_FORMAT_1M16}, + {WAVE_FORMAT_96S16, WAVE_FORMAT_48S16, WAVE_FORMAT_4S16, + WAVE_FORMAT_2S16, WAVE_FORMAT_1S16}}, + }; + /****************************************************************** * OSS_WaveOutInit * * */ -static BOOL OSS_WaveOutInit(OSS_DEVICE* ossdev) +static BOOL OSS_WaveOutInit(OSS_DEVICE* ossdev) { - int smplrate; - int samplesize = 16; - int dsp_stereo = 1; - int bytespersmpl; - int caps; - int mask; + int rc,arg; + int f,c,r; if (OSS_OpenDevice(ossdev, O_WRONLY, NULL, 0, 0, 0, 0) != 0) return FALSE; - - memset(&ossdev->out_caps, 0, sizeof(ossdev->out_caps)); - ioctl(ossdev->fd, SNDCTL_DSP_RESET, 0); /* FIXME: some programs compare this string against the content of the @@ -440,70 +500,68 @@ strcpy(ossdev->out_caps.szPname, "CS4236/37/38"); #endif ossdev->out_caps.vDriverVersion = 0x0100; + ossdev->out_caps.wChannels = 1; ossdev->out_caps.dwFormats = 0x00000000; + ossdev->out_caps.wReserved1 = 0; ossdev->out_caps.dwSupport = WAVECAPS_VOLUME; - ioctl(ossdev->fd, SNDCTL_DSP_GETFMTS, &mask); - TRACE("OSS dsp out mask=%08x\n", mask); - - /* First bytespersampl, then stereo */ - bytespersmpl = (ioctl(ossdev->fd, SNDCTL_DSP_SAMPLESIZE, &samplesize) != 0) ? 1 : 2; + if (WINE_TRACE_ON(wave)) { + /* Note that this only reports the formats supported by the hardware. + * The driver may support other formats and do the conversions in + * software which is why we don't use this value + */ + int oss_mask; + ioctl(ossdev->fd, SNDCTL_DSP_GETFMTS, &oss_mask); + TRACE("OSS dsp out mask=%08x\n", oss_mask); + } - ossdev->out_caps.wChannels = (ioctl(ossdev->fd, SNDCTL_DSP_STEREO, &dsp_stereo) != 0) ? 1 : 2; - if (ossdev->out_caps.wChannels > 1) ossdev->out_caps.dwSupport |= WAVECAPS_LRVOLUME; + /* We must first set the format and the stereo mode as some sound cards + * may support 44kHz mono but not 44kHz stereo. Also we must + * systematically check the return value of these ioctls as they will + * always succeed (see OSS Linux) but will modify the parameter to match + * whatever they support. The OSS specs also say we must first set the + * sample size, then the stereo and then the sample rate. + */ + for (f=0;f<2;f++) { + arg=win_std_oss_fmts[f]; + rc=ioctl(ossdev->fd, SNDCTL_DSP_SAMPLESIZE, &arg); + if (rc!=0 || arg!=win_std_oss_fmts[f]) + continue; + + for (c=0;c<2;c++) { + arg=c; + rc=ioctl(ossdev->fd, SNDCTL_DSP_STEREO, &arg); + if (rc!=0 || arg!=c) + continue; + if (c==1) { + ossdev->out_caps.wChannels=2; + ossdev->out_caps.dwSupport|=WAVECAPS_LRVOLUME; + } - smplrate = 44100; - if (ioctl(ossdev->fd, SNDCTL_DSP_SPEED, &smplrate) == 0) { - if (mask & AFMT_U8) { - ossdev->out_caps.dwFormats |= WAVE_FORMAT_4M08; - if (ossdev->out_caps.wChannels > 1) - ossdev->out_caps.dwFormats |= WAVE_FORMAT_4S08; - } - if ((mask & AFMT_S16_LE) && bytespersmpl > 1) { - ossdev->out_caps.dwFormats |= WAVE_FORMAT_4M16; - if (ossdev->out_caps.wChannels > 1) - ossdev->out_caps.dwFormats |= WAVE_FORMAT_4S16; - } - } - smplrate = 22050; - if (ioctl(ossdev->fd, SNDCTL_DSP_SPEED, &smplrate) == 0) { - if (mask & AFMT_U8) { - ossdev->out_caps.dwFormats |= WAVE_FORMAT_2M08; - if (ossdev->out_caps.wChannels > 1) - ossdev->out_caps.dwFormats |= WAVE_FORMAT_2S08; - } - if ((mask & AFMT_S16_LE) && bytespersmpl > 1) { - ossdev->out_caps.dwFormats |= WAVE_FORMAT_2M16; - if (ossdev->out_caps.wChannels > 1) - ossdev->out_caps.dwFormats |= WAVE_FORMAT_2S16; - } - } - smplrate = 11025; - if (ioctl(ossdev->fd, SNDCTL_DSP_SPEED, &smplrate) == 0) { - if (mask & AFMT_U8) { - ossdev->out_caps.dwFormats |= WAVE_FORMAT_1M08; - if (ossdev->out_caps.wChannels > 1) - ossdev->out_caps.dwFormats |= WAVE_FORMAT_1S08; - } - if ((mask & AFMT_S16_LE) && bytespersmpl > 1) { - ossdev->out_caps.dwFormats |= WAVE_FORMAT_1M16; - if (ossdev->out_caps.wChannels > 1) - ossdev->out_caps.dwFormats |= WAVE_FORMAT_1S16; - } + for (r=0;r<sizeof(win_std_rates)/sizeof(*win_std_rates);r++) { + arg=win_std_rates[r]; + rc=ioctl(ossdev->fd, SNDCTL_DSP_SPEED, &arg); + TRACE("DSP_SPEED: rc=%d returned %d for %dx%dx%d\n", + rc,arg,win_std_rates[r],win_std_oss_fmts[f],c+1); + if (rc==0 && NEAR_MATCH(arg,win_std_rates[r])) + ossdev->out_caps.dwFormats|=win_std_formats[f][c][r]; + } + } } - if (ioctl(ossdev->fd, SNDCTL_DSP_GETCAPS, &caps) == 0) { - TRACE("OSS dsp out caps=%08X\n", caps); - if ((caps & DSP_CAP_REALTIME) && !(caps & DSP_CAP_BATCH)) { - ossdev->out_caps.dwSupport |= WAVECAPS_SAMPLEACCURATE; - } - /* well, might as well use the DirectSound cap flag for something */ - if ((caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) && - !(caps & DSP_CAP_BATCH)) - ossdev->out_caps.dwSupport |= WAVECAPS_DIRECTSOUND; + + if (ioctl(ossdev->fd, SNDCTL_DSP_GETCAPS, &arg) == 0) { + TRACE("OSS dsp out caps=%08X\n", arg); + if ((arg & DSP_CAP_REALTIME) && !(arg & DSP_CAP_BATCH)) { + ossdev->out_caps.dwSupport |= WAVECAPS_SAMPLEACCURATE; + } + /* well, might as well use the DirectSound cap flag for something */ + if ((arg & DSP_CAP_TRIGGER) && (arg & DSP_CAP_MMAP) && + !(arg & DSP_CAP_BATCH)) + ossdev->out_caps.dwSupport |= WAVECAPS_DIRECTSOUND; } OSS_CloseDevice(ossdev); TRACE("out dwFormats = %08lX, dwSupport = %08lX\n", - ossdev->out_caps.dwFormats, ossdev->out_caps.dwSupport); + ossdev->out_caps.dwFormats, ossdev->out_caps.dwSupport); return TRUE; } @@ -514,80 +572,67 @@ */ static BOOL OSS_WaveInInit(OSS_DEVICE* ossdev) { - int smplrate; - int samplesize = 16; - int dsp_stereo = 1; - int bytespersmpl; - int caps; - int mask; + int rc,arg; + int f,c,r; if (OSS_OpenDevice(ossdev, O_RDONLY, NULL, 0, 0, 0, 0) != 0) return FALSE; - - memset(&ossdev->in_caps, 0, sizeof(ossdev->in_caps)); - ioctl(ossdev->fd, SNDCTL_DSP_RESET, 0); + /* See comment in OSS_WaveOutInit */ #ifdef EMULATE_SB16 ossdev->in_caps.wMid = 0x0002; ossdev->in_caps.wPid = 0x0004; strcpy(ossdev->in_caps.szPname, "SB16 Wave In"); #else - ossdev->in_caps.wMid = 0x00FF; /* Manufac ID */ - ossdev->in_caps.wPid = 0x0001; /* Product ID */ + ossdev->in_caps.wMid = 0x00FF; /* Manufac ID */ + ossdev->in_caps.wPid = 0x0001; /* Product ID */ strcpy(ossdev->in_caps.szPname, "OpenSoundSystem WAVIN Driver"); #endif ossdev->in_caps.dwFormats = 0x00000000; - ossdev->in_caps.wChannels = (ioctl(ossdev->fd, SNDCTL_DSP_STEREO, &dsp_stereo) != 0) ? 1 : 2; - + ossdev->in_caps.wChannels = 1; + ossdev->in_caps.wReserved1 = 0; ossdev->bTriggerSupport = FALSE; - if (ioctl(ossdev->fd, SNDCTL_DSP_GETCAPS, &caps) == 0) { - TRACE("OSS dsp in caps=%08X\n", caps); - if (caps & DSP_CAP_TRIGGER) - ossdev->bTriggerSupport = TRUE; - } - ioctl(ossdev->fd, SNDCTL_DSP_GETFMTS, &mask); - TRACE("OSS in dsp mask=%08x\n", mask); + if (WINE_TRACE_ON(wave)) { + /* Note that this only reports the formats supported by the hardware. + * The driver may support other formats and do the conversions in + * software which is why we don't use this value + */ + int oss_mask; + ioctl(ossdev->fd, SNDCTL_DSP_GETFMTS, &oss_mask); + TRACE("OSS dsp out mask=%08x\n", oss_mask); + } + + /* See the comment in OSS_WaveOutInit */ + for (f=0;f<2;f++) { + arg=win_std_oss_fmts[f]; + rc=ioctl(ossdev->fd, SNDCTL_DSP_SAMPLESIZE, &arg); + if (rc!=0 || arg!=win_std_oss_fmts[f]) + continue; + + for (c=0;c<2;c++) { + arg=c; + rc=ioctl(ossdev->fd, SNDCTL_DSP_STEREO, &arg); + if (rc!=0 || arg!=c) + continue; + if (c==1) { + ossdev->in_caps.wChannels=2; + } - bytespersmpl = (ioctl(ossdev->fd, SNDCTL_DSP_SAMPLESIZE, &samplesize) != 0) ? 1 : 2; - smplrate = 44100; - if (ioctl(ossdev->fd, SNDCTL_DSP_SPEED, &smplrate) == 0) { - if (mask & AFMT_U8) { - ossdev->in_caps.dwFormats |= WAVE_FORMAT_4M08; - if (ossdev->in_caps.wChannels > 1) - ossdev->in_caps.dwFormats |= WAVE_FORMAT_4S08; - } - if ((mask & AFMT_S16_LE) && bytespersmpl > 1) { - ossdev->in_caps.dwFormats |= WAVE_FORMAT_4M16; - if (ossdev->in_caps.wChannels > 1) - ossdev->in_caps.dwFormats |= WAVE_FORMAT_4S16; - } - } - smplrate = 22050; - if (ioctl(ossdev->fd, SNDCTL_DSP_SPEED, &smplrate) == 0) { - if (mask & AFMT_U8) { - ossdev->in_caps.dwFormats |= WAVE_FORMAT_2M08; - if (ossdev->in_caps.wChannels > 1) - ossdev->in_caps.dwFormats |= WAVE_FORMAT_2S08; - } - if ((mask & AFMT_S16_LE) && bytespersmpl > 1) { - ossdev->in_caps.dwFormats |= WAVE_FORMAT_2M16; - if (ossdev->in_caps.wChannels > 1) - ossdev->in_caps.dwFormats |= WAVE_FORMAT_2S16; - } + for (r=0;r<sizeof(win_std_rates)/sizeof(*win_std_rates);r++) { + arg=win_std_rates[r]; + rc=ioctl(ossdev->fd, SNDCTL_DSP_SPEED, &arg); + TRACE("DSP_SPEED: rc=%d returned %d for %dx%dx%d\n",rc,arg,win_std_rates[r],win_std_oss_fmts[f],c+1); + if (rc==0 && NEAR_MATCH(arg,win_std_rates[r])) + ossdev->in_caps.dwFormats|=win_std_formats[f][c][r]; + } + } } - smplrate = 11025; - if (ioctl(ossdev->fd, SNDCTL_DSP_SPEED, &smplrate) == 0) { - if (mask & AFMT_U8) { - ossdev->in_caps.dwFormats |= WAVE_FORMAT_1M08; - if (ossdev->in_caps.wChannels > 1) - ossdev->in_caps.dwFormats |= WAVE_FORMAT_1S08; - } - if ((mask & AFMT_S16_LE) && bytespersmpl > 1) { - ossdev->in_caps.dwFormats |= WAVE_FORMAT_1M16; - if (ossdev->in_caps.wChannels > 1) - ossdev->in_caps.dwFormats |= WAVE_FORMAT_1S16; - } + + if (ioctl(ossdev->fd, SNDCTL_DSP_GETCAPS, &arg) == 0) { + TRACE("OSS dsp in caps=%08X\n", arg); + if (arg & DSP_CAP_TRIGGER) + ossdev->bTriggerSupport = TRUE; } OSS_CloseDevice(ossdev); TRACE("in dwFormats = %08lX\n", ossdev->in_caps.dwFormats);