Commit d075eff2 authored by Eric Pouech's avatar Eric Pouech Committed by Alexandre Julliard

Ensured full duplex mode is only used with same parameters in in/out

streams. Some more work towards multiple audio cards support.
parent 5ee1599d
...@@ -60,11 +60,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(wave); ...@@ -60,11 +60,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(wave);
#ifdef HAVE_OSS #ifdef HAVE_OSS
#define SOUND_DEV "/dev/dsp" #define MAX_WAVEDRV (1)
#define MIXER_DEV "/dev/mixer"
#define MAX_WAVEOUTDRV (1)
#define MAX_WAVEINDRV (1)
/* state diagram for waveOut writing: /* state diagram for waveOut writing:
* *
...@@ -121,7 +117,6 @@ typedef struct { ...@@ -121,7 +117,6 @@ typedef struct {
WAVEOPENDESC waveDesc; WAVEOPENDESC waveDesc;
WORD wFlags; WORD wFlags;
PCMWAVEFORMAT format; PCMWAVEFORMAT format;
WAVEOUTCAPSA caps;
/* OSS information */ /* OSS information */
DWORD dwFragmentSize; /* size of OSS buffer fragment */ DWORD dwFragmentSize; /* size of OSS buffer fragment */
...@@ -156,7 +151,6 @@ typedef struct { ...@@ -156,7 +151,6 @@ typedef struct {
PCMWAVEFORMAT format; PCMWAVEFORMAT format;
LPWAVEHDR lpQueuePtr; LPWAVEHDR lpQueuePtr;
DWORD dwTotalRecorded; DWORD dwTotalRecorded;
WAVEINCAPSA caps;
BOOL bTriggerSupport; BOOL bTriggerSupport;
/* synchronization stuff */ /* synchronization stuff */
...@@ -166,8 +160,10 @@ typedef struct { ...@@ -166,8 +160,10 @@ typedef struct {
OSS_MSG_RING msgRing; OSS_MSG_RING msgRing;
} WINE_WAVEIN; } WINE_WAVEIN;
static WINE_WAVEOUT WOutDev [MAX_WAVEOUTDRV]; static WINE_WAVEOUT WOutDev [MAX_WAVEDRV];
static WINE_WAVEIN WInDev [MAX_WAVEINDRV ]; static WINE_WAVEIN WInDev [MAX_WAVEDRV];
static unsigned numOutDev;
static unsigned numInDev;
static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv); static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv);
...@@ -186,13 +182,26 @@ static const char *wodPlayerCmdString[] = { ...@@ -186,13 +182,26 @@ static const char *wodPlayerCmdString[] = {
* Low level WAVE implementation * * Low level WAVE implementation *
*======================================================================*/ *======================================================================*/
#define USE_FULLDUPLEX #define USE_FULLDUPLEX
typedef struct tagOSS_DEVICE {
const char* dev_name;
const char* mixer_name;
unsigned open_count;
WAVEOUTCAPSA out_caps;
WAVEINCAPSA in_caps;
#ifdef USE_FULLDUPLEX #ifdef USE_FULLDUPLEX
static unsigned OSS_OpenCount /* = 0 */; /* number of times fd has been opened */ unsigned open_access;
static unsigned OSS_OpenAccess /* = 0 */; /* access used for opening... used to handle compat */ int fd;
static int OSS_OpenFD; DWORD owner_tid;
static DWORD OSS_OwnerThreadID /* = 0 */; unsigned sample_rate;
unsigned stereo;
unsigned format;
unsigned audio_fragment;
#endif #endif
static BOOL OSS_FullDuplex; /* set to non-zero if the device supports full duplex */ BOOL full_duplex;
} OSS_DEVICE;
OSS_DEVICE OSS_Devices[MAX_WAVEDRV];
/****************************************************************** /******************************************************************
* OSS_OpenDevice * OSS_OpenDevice
...@@ -201,50 +210,107 @@ static BOOL OSS_FullDuplex; /* set to non-zero if the device suppo ...@@ -201,50 +210,107 @@ static BOOL OSS_FullDuplex; /* set to non-zero if the device suppo
* open the device for both waveout and wavein streams... * open the device for both waveout and wavein streams...
* this is hackish, but it's the way OSS interface is done... * this is hackish, but it's the way OSS interface is done...
*/ */
static int OSS_OpenDevice(unsigned wDevID, unsigned req_access) static DWORD OSS_OpenDevice(unsigned wDevID, int* pfd, unsigned req_access,
int* frag, int sample_rate, int stereo, int fmt)
{ {
/* wDevID: is not used yet, we handle only one global device /dev/dsp */ OSS_DEVICE* ossdev;
#ifdef USE_FULLDUPLEX int val;
/* FIXME: race */ int fd = -1;
if (OSS_OpenCount == 0)
if (wDevID >= MAX_WAVEDRV) return MMSYSERR_BADDEVICEID;;
ossdev = &OSS_Devices[wDevID];
if (ossdev->full_duplex && (req_access == O_RDONLY || req_access == O_WRONLY))
req_access = O_RDWR;
/* FIXME: race with close */
if (ossdev->open_count == 0)
{ {
if (access(SOUND_DEV, 0) != 0 || if (access(ossdev->dev_name, 0) != 0) return MMSYSERR_NODRIVER;
(OSS_OpenFD = open(SOUND_DEV, req_access|O_NDELAY, 0)) == -1)
if ((fd = open(ossdev->dev_name, req_access|O_NDELAY, 0)) == -1)
{ {
WARN("Couldn't open out %s (%s)\n", SOUND_DEV, strerror(errno)); WARN("Couldn't open out %s (%s)\n", ossdev->dev_name, strerror(errno));
return -1; return (errno == EBUSY) ? MMSYSERR_ALLOCATED : MMSYSERR_ERROR;
} }
fcntl(fd, F_SETFD, 1); /* set close on exec flag */
/* turn full duplex on if it has been requested */ /* turn full duplex on if it has been requested */
if (req_access == O_RDWR && OSS_FullDuplex) if (req_access == O_RDWR && ossdev->full_duplex)
ioctl(OSS_OpenFD, SNDCTL_DSP_SETDUPLEX, 0); ioctl(fd, SNDCTL_DSP_SETDUPLEX, 0);
OSS_OpenAccess = req_access;
OSS_OwnerThreadID = GetCurrentThreadId(); if (frag) ioctl(fd, SNDCTL_DSP_SETFRAGMENT, frag);
/* First size and stereo then samplerate */
if (fmt)
{
val = fmt;
ioctl(fd, SNDCTL_DSP_SETFMT, &val);
if (val != fmt)
ERR("Can't set format to %d (%d)\n", fmt, val);
}
if (stereo)
{
val = stereo;
ioctl(fd, SNDCTL_DSP_STEREO, &val);
if (val != stereo)
ERR("Can't set stereo to %u (%d)\n", stereo, val);
}
if (sample_rate)
{
val = sample_rate;
ioctl(fd, SNDCTL_DSP_SPEED, &sample_rate);
if (!NEAR_MATCH(val, sample_rate))
ERR("Can't set sample_rate to %u (%d)\n", sample_rate, val);
}
#ifdef USE_FULLDUPLEX
ossdev->audio_fragment = (frag) ? *frag : 0;
ossdev->sample_rate = sample_rate;
ossdev->stereo = stereo;
ossdev->format = fmt;
ossdev->open_access = req_access;
ossdev->owner_tid = GetCurrentThreadId();
ossdev->fd = fd;
#endif
} }
else else
{ {
if (OSS_OpenAccess != req_access) #ifdef USE_FULLDUPLEX
/* check we really open with the same parameters */
if (ossdev->open_access != req_access)
{ {
WARN("Mismatch in access...\n"); WARN("Mismatch in access...\n");
return -1; return WAVERR_BADFORMAT;
} }
if (GetCurrentThreadId() != OSS_OwnerThreadID) /* FIXME: if really needed, we could do, in this case, on the fly
* PCM conversion (using the MSACM ad hoc driver)
*/
if (ossdev->audio_fragment != (frag ? *frag : 0) ||
ossdev->sample_rate != sample_rate ||
ossdev->stereo != stereo ||
ossdev->format != fmt)
{
WARN("FullDuplex: mismatch in PCM parameters for input and output\n"
"OSS doesn't allow us different parameters\n"
"audio_frag(%x/%x) sample_rate(%d/%d) stereo(%d/%d) fmt(%d/%d)\n",
ossdev->audio_fragment, frag ? *frag : 0,
ossdev->sample_rate, sample_rate,
ossdev->stereo, stereo,
ossdev->format, fmt);
return WAVERR_BADFORMAT;
}
if (GetCurrentThreadId() != ossdev->owner_tid)
{ {
WARN("Another thread is trying to access audio...\n"); WARN("Another thread is trying to access audio...\n");
return -1; return MMSYSERR_ERROR;
} }
#endif
} }
OSS_OpenCount++; #ifdef USE_FULLDUPLEX
return OSS_OpenFD; ossdev->open_count++;
#else
int fd;
if (access(SOUND_DEV, 0) != 0 || (fd = open(SOUND_DEV, req_access|O_NDELAY, 0)) == -1)
{
WARN("Couldn't open out %s (%s)\n", SOUND_DEV, strerror(errno));
return -1;
}
return fd;
#endif #endif
*pfd = fd;
return MMSYSERR_NOERROR;
} }
/****************************************************************** /******************************************************************
...@@ -254,47 +320,39 @@ static int OSS_OpenDevice(unsigned wDevID, unsigned req_access) ...@@ -254,47 +320,39 @@ static int OSS_OpenDevice(unsigned wDevID, unsigned req_access)
*/ */
static void OSS_CloseDevice(unsigned wDevID, int fd) static void OSS_CloseDevice(unsigned wDevID, int fd)
{ {
/* wDevID: is not used yet, we handle only one global device /dev/dsp */ OSS_DEVICE* ossdev;
if (wDevID >= MAX_WAVEDRV) return;
#ifdef USE_FULLDUPLEX #ifdef USE_FULLDUPLEX
if (fd != OSS_OpenFD) FIXME("What the heck????\n"); ossdev = &OSS_Devices[wDevID];
if (--OSS_OpenCount == 0) if (fd != ossdev->fd) FIXME("What the heck????\n");
{ if (--ossdev->open_count == 0) close(ossdev->fd);
close(OSS_OpenFD);
}
#else #else
/* wDevID: is not used yet, we handle only one global device /dev/dsp */
close(fd); close(fd);
#endif #endif
} }
/****************************************************************** /******************************************************************
* OSS_WaveInit * OSS_WaveOutInit
*
* *
* Initialize internal structures from OSS information
*/ */
LONG OSS_WaveInit(void) static void OSS_WaveOutInit(unsigned devID, OSS_DEVICE* ossdev)
{ {
int audio; int audio;
int smplrate; int smplrate;
int samplesize = 16; int samplesize = 16;
int dsp_stereo = 1; int dsp_stereo = 1;
int bytespersmpl; int bytespersmpl;
int caps; int caps;
int mask; int mask;
int i;
WOutDev[devID].unixdev = -1;
memset(&ossdev->out_caps, 0, sizeof(ossdev->out_caps));
/* start with output device */ if (OSS_OpenDevice(devID, &audio, O_WRONLY, NULL, 0, 0, 0) != 0) return;
numOutDev++;
/* initialize all device handles to -1 */
for (i = 0; i < MAX_WAVEOUTDRV; ++i)
{
WOutDev[i].unixdev = -1;
}
/* FIXME: only one device is supported */
memset(&WOutDev[0].caps, 0, sizeof(WOutDev[0].caps));
if ((audio = OSS_OpenDevice(0, O_WRONLY)) == -1) return -1;
ioctl(audio, SNDCTL_DSP_RESET, 0); ioctl(audio, SNDCTL_DSP_RESET, 0);
...@@ -303,113 +361,127 @@ LONG OSS_WaveInit(void) ...@@ -303,113 +361,127 @@ LONG OSS_WaveInit(void)
* (e.g. MS win9x mplayer.exe) * (e.g. MS win9x mplayer.exe)
*/ */
#ifdef EMULATE_SB16 #ifdef EMULATE_SB16
WOutDev[0].caps.wMid = 0x0002; ossdev->out_caps.wMid = 0x0002;
WOutDev[0].caps.wPid = 0x0104; ossdev->out_caps.wPid = 0x0104;
strcpy(WOutDev[0].caps.szPname, "SB16 Wave Out"); strcpy(ossdev->out_caps.szPname, "SB16 Wave Out");
#else #else
WOutDev[0].caps.wMid = 0x00FF; /* Manufac ID */ ossdev->out_caps.wMid = 0x00FF; /* Manufac ID */
WOutDev[0].caps.wPid = 0x0001; /* Product ID */ ossdev->out_caps.wPid = 0x0001; /* Product ID */
/* strcpy(WOutDev[0].caps.szPname, "OpenSoundSystem WAVOUT Driver");*/ /* strcpy(ossdev->out_caps.szPname, "OpenSoundSystem WAVOUT Driver");*/
strcpy(WOutDev[0].caps.szPname, "CS4236/37/38"); strcpy(ossdev->out_caps.szPname, "CS4236/37/38");
#endif #endif
WOutDev[0].caps.vDriverVersion = 0x0100; ossdev->out_caps.vDriverVersion = 0x0100;
WOutDev[0].caps.dwFormats = 0x00000000; ossdev->out_caps.dwFormats = 0x00000000;
WOutDev[0].caps.dwSupport = WAVECAPS_VOLUME; ossdev->out_caps.dwSupport = WAVECAPS_VOLUME;
ioctl(audio, SNDCTL_DSP_GETFMTS, &mask); ioctl(audio, SNDCTL_DSP_GETFMTS, &mask);
TRACE("OSS dsp out mask=%08x\n", mask); TRACE("OSS dsp out mask=%08x\n", mask);
/* First bytespersampl, then stereo */ /* First bytespersampl, then stereo */
bytespersmpl = (ioctl(audio, SNDCTL_DSP_SAMPLESIZE, &samplesize) != 0) ? 1 : 2; bytespersmpl = (ioctl(audio, SNDCTL_DSP_SAMPLESIZE, &samplesize) != 0) ? 1 : 2;
WOutDev[0].caps.wChannels = (ioctl(audio, SNDCTL_DSP_STEREO, &dsp_stereo) != 0) ? 1 : 2; ossdev->out_caps.wChannels = (ioctl(audio, SNDCTL_DSP_STEREO, &dsp_stereo) != 0) ? 1 : 2;
if (WOutDev[0].caps.wChannels > 1) WOutDev[0].caps.dwSupport |= WAVECAPS_LRVOLUME; if (ossdev->out_caps.wChannels > 1) ossdev->out_caps.dwSupport |= WAVECAPS_LRVOLUME;
smplrate = 44100; smplrate = 44100;
if (ioctl(audio, SNDCTL_DSP_SPEED, &smplrate) == 0) { if (ioctl(audio, SNDCTL_DSP_SPEED, &smplrate) == 0) {
if (mask & AFMT_U8) { if (mask & AFMT_U8) {
WOutDev[0].caps.dwFormats |= WAVE_FORMAT_4M08; ossdev->out_caps.dwFormats |= WAVE_FORMAT_4M08;
if (WOutDev[0].caps.wChannels > 1) if (ossdev->out_caps.wChannels > 1)
WOutDev[0].caps.dwFormats |= WAVE_FORMAT_4S08; ossdev->out_caps.dwFormats |= WAVE_FORMAT_4S08;
} }
if ((mask & AFMT_S16_LE) && bytespersmpl > 1) { if ((mask & AFMT_S16_LE) && bytespersmpl > 1) {
WOutDev[0].caps.dwFormats |= WAVE_FORMAT_4M16; ossdev->out_caps.dwFormats |= WAVE_FORMAT_4M16;
if (WOutDev[0].caps.wChannels > 1) if (ossdev->out_caps.wChannels > 1)
WOutDev[0].caps.dwFormats |= WAVE_FORMAT_4S16; ossdev->out_caps.dwFormats |= WAVE_FORMAT_4S16;
} }
} }
smplrate = 22050; smplrate = 22050;
if (ioctl(audio, SNDCTL_DSP_SPEED, &smplrate) == 0) { if (ioctl(audio, SNDCTL_DSP_SPEED, &smplrate) == 0) {
if (mask & AFMT_U8) { if (mask & AFMT_U8) {
WOutDev[0].caps.dwFormats |= WAVE_FORMAT_2M08; ossdev->out_caps.dwFormats |= WAVE_FORMAT_2M08;
if (WOutDev[0].caps.wChannels > 1) if (ossdev->out_caps.wChannels > 1)
WOutDev[0].caps.dwFormats |= WAVE_FORMAT_2S08; ossdev->out_caps.dwFormats |= WAVE_FORMAT_2S08;
} }
if ((mask & AFMT_S16_LE) && bytespersmpl > 1) { if ((mask & AFMT_S16_LE) && bytespersmpl > 1) {
WOutDev[0].caps.dwFormats |= WAVE_FORMAT_2M16; ossdev->out_caps.dwFormats |= WAVE_FORMAT_2M16;
if (WOutDev[0].caps.wChannels > 1) if (ossdev->out_caps.wChannels > 1)
WOutDev[0].caps.dwFormats |= WAVE_FORMAT_2S16; ossdev->out_caps.dwFormats |= WAVE_FORMAT_2S16;
} }
} }
smplrate = 11025; smplrate = 11025;
if (ioctl(audio, SNDCTL_DSP_SPEED, &smplrate) == 0) { if (ioctl(audio, SNDCTL_DSP_SPEED, &smplrate) == 0) {
if (mask & AFMT_U8) { if (mask & AFMT_U8) {
WOutDev[0].caps.dwFormats |= WAVE_FORMAT_1M08; ossdev->out_caps.dwFormats |= WAVE_FORMAT_1M08;
if (WOutDev[0].caps.wChannels > 1) if (ossdev->out_caps.wChannels > 1)
WOutDev[0].caps.dwFormats |= WAVE_FORMAT_1S08; ossdev->out_caps.dwFormats |= WAVE_FORMAT_1S08;
} }
if ((mask & AFMT_S16_LE) && bytespersmpl > 1) { if ((mask & AFMT_S16_LE) && bytespersmpl > 1) {
WOutDev[0].caps.dwFormats |= WAVE_FORMAT_1M16; ossdev->out_caps.dwFormats |= WAVE_FORMAT_1M16;
if (WOutDev[0].caps.wChannels > 1) if (ossdev->out_caps.wChannels > 1)
WOutDev[0].caps.dwFormats |= WAVE_FORMAT_1S16; ossdev->out_caps.dwFormats |= WAVE_FORMAT_1S16;
} }
} }
if (ioctl(audio, SNDCTL_DSP_GETCAPS, &caps) == 0) { if (ioctl(audio, SNDCTL_DSP_GETCAPS, &caps) == 0) {
TRACE("OSS dsp out caps=%08X\n", caps); TRACE("OSS dsp out caps=%08X\n", caps);
if ((caps & DSP_CAP_REALTIME) && !(caps & DSP_CAP_BATCH)) { if ((caps & DSP_CAP_REALTIME) && !(caps & DSP_CAP_BATCH)) {
WOutDev[0].caps.dwSupport |= WAVECAPS_SAMPLEACCURATE; ossdev->out_caps.dwSupport |= WAVECAPS_SAMPLEACCURATE;
} }
/* well, might as well use the DirectSound cap flag for something */ /* well, might as well use the DirectSound cap flag for something */
if ((caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) && if ((caps & DSP_CAP_TRIGGER) && (caps & DSP_CAP_MMAP) &&
!(caps & DSP_CAP_BATCH)) !(caps & DSP_CAP_BATCH))
WOutDev[0].caps.dwSupport |= WAVECAPS_DIRECTSOUND; ossdev->out_caps.dwSupport |= WAVECAPS_DIRECTSOUND;
} }
OSS_CloseDevice(0, audio); OSS_CloseDevice(devID, audio);
TRACE("out dwFormats = %08lX, dwSupport = %08lX\n", TRACE("out dwFormats = %08lX, dwSupport = %08lX\n",
WOutDev[0].caps.dwFormats, WOutDev[0].caps.dwSupport); ossdev->out_caps.dwFormats, ossdev->out_caps.dwSupport);
/* then do input device */ }
samplesize = 16;
dsp_stereo = 1;
for (i = 0; i < MAX_WAVEINDRV; ++i) /******************************************************************
{ * OSS_WaveInInit
WInDev[i].unixdev = -1; *
} *
*/
static void OSS_WaveInInit(unsigned devID, OSS_DEVICE* ossdev)
{
int audio;
int smplrate;
int samplesize = 16;
int dsp_stereo = 1;
int bytespersmpl;
int caps;
int mask;
memset(&WInDev[0].caps, 0, sizeof(WInDev[0].caps)); samplesize = 16;
dsp_stereo = 1;
WInDev[devID].unixdev = -1;
memset(&ossdev->in_caps, 0, sizeof(ossdev->in_caps));
if ((audio = OSS_OpenDevice(0, O_RDONLY)) == -1) return -1; if (OSS_OpenDevice(0, &audio, O_RDONLY, NULL, 0, 0, 0) != 0) return;
numInDev++;
ioctl(audio, SNDCTL_DSP_RESET, 0); ioctl(audio, SNDCTL_DSP_RESET, 0);
#ifdef EMULATE_SB16 #ifdef EMULATE_SB16
WInDev[0].caps.wMid = 0x0002; ossdev->in_caps.wMid = 0x0002;
WInDev[0].caps.wPid = 0x0004; ossdev->in_caps.wPid = 0x0004;
strcpy(WInDev[0].caps.szPname, "SB16 Wave In"); strcpy(ossdev->in_caps.szPname, "SB16 Wave In");
#else #else
WInDev[0].caps.wMid = 0x00FF; /* Manufac ID */ ossdev->in_caps.wMid = 0x00FF; /* Manufac ID */
WInDev[0].caps.wPid = 0x0001; /* Product ID */ ossdev->in_caps.wPid = 0x0001; /* Product ID */
strcpy(WInDev[0].caps.szPname, "OpenSoundSystem WAVIN Driver"); strcpy(ossdev->in_caps.szPname, "OpenSoundSystem WAVIN Driver");
#endif #endif
WInDev[0].caps.dwFormats = 0x00000000; ossdev->in_caps.dwFormats = 0x00000000;
WInDev[0].caps.wChannels = (ioctl(audio, SNDCTL_DSP_STEREO, &dsp_stereo) != 0) ? 1 : 2; ossdev->in_caps.wChannels = (ioctl(audio, SNDCTL_DSP_STEREO, &dsp_stereo) != 0) ? 1 : 2;
WInDev[0].bTriggerSupport = FALSE; WInDev[devID].bTriggerSupport = FALSE;
if (ioctl(audio, SNDCTL_DSP_GETCAPS, &caps) == 0) { if (ioctl(audio, SNDCTL_DSP_GETCAPS, &caps) == 0) {
TRACE("OSS dsp in caps=%08X\n", caps); TRACE("OSS dsp in caps=%08X\n", caps);
if (caps & DSP_CAP_TRIGGER) if (caps & DSP_CAP_TRIGGER)
WInDev[0].bTriggerSupport = TRUE; WInDev[devID].bTriggerSupport = TRUE;
} }
ioctl(audio, SNDCTL_DSP_GETFMTS, &mask); ioctl(audio, SNDCTL_DSP_GETFMTS, &mask);
...@@ -419,52 +491,91 @@ LONG OSS_WaveInit(void) ...@@ -419,52 +491,91 @@ LONG OSS_WaveInit(void)
smplrate = 44100; smplrate = 44100;
if (ioctl(audio, SNDCTL_DSP_SPEED, &smplrate) == 0) { if (ioctl(audio, SNDCTL_DSP_SPEED, &smplrate) == 0) {
if (mask & AFMT_U8) { if (mask & AFMT_U8) {
WInDev[0].caps.dwFormats |= WAVE_FORMAT_4M08; ossdev->in_caps.dwFormats |= WAVE_FORMAT_4M08;
if (WInDev[0].caps.wChannels > 1) if (ossdev->in_caps.wChannels > 1)
WInDev[0].caps.dwFormats |= WAVE_FORMAT_4S08; ossdev->in_caps.dwFormats |= WAVE_FORMAT_4S08;
} }
if ((mask & AFMT_S16_LE) && bytespersmpl > 1) { if ((mask & AFMT_S16_LE) && bytespersmpl > 1) {
WInDev[0].caps.dwFormats |= WAVE_FORMAT_4M16; ossdev->in_caps.dwFormats |= WAVE_FORMAT_4M16;
if (WInDev[0].caps.wChannels > 1) if (ossdev->in_caps.wChannels > 1)
WInDev[0].caps.dwFormats |= WAVE_FORMAT_4S16; ossdev->in_caps.dwFormats |= WAVE_FORMAT_4S16;
} }
} }
smplrate = 22050; smplrate = 22050;
if (ioctl(audio, SNDCTL_DSP_SPEED, &smplrate) == 0) { if (ioctl(audio, SNDCTL_DSP_SPEED, &smplrate) == 0) {
if (mask & AFMT_U8) { if (mask & AFMT_U8) {
WInDev[0].caps.dwFormats |= WAVE_FORMAT_2M08; ossdev->in_caps.dwFormats |= WAVE_FORMAT_2M08;
if (WInDev[0].caps.wChannels > 1) if (ossdev->in_caps.wChannels > 1)
WInDev[0].caps.dwFormats |= WAVE_FORMAT_2S08; ossdev->in_caps.dwFormats |= WAVE_FORMAT_2S08;
} }
if ((mask & AFMT_S16_LE) && bytespersmpl > 1) { if ((mask & AFMT_S16_LE) && bytespersmpl > 1) {
WInDev[0].caps.dwFormats |= WAVE_FORMAT_2M16; ossdev->in_caps.dwFormats |= WAVE_FORMAT_2M16;
if (WInDev[0].caps.wChannels > 1) if (ossdev->in_caps.wChannels > 1)
WInDev[0].caps.dwFormats |= WAVE_FORMAT_2S16; ossdev->in_caps.dwFormats |= WAVE_FORMAT_2S16;
} }
} }
smplrate = 11025; smplrate = 11025;
if (ioctl(audio, SNDCTL_DSP_SPEED, &smplrate) == 0) { if (ioctl(audio, SNDCTL_DSP_SPEED, &smplrate) == 0) {
if (mask & AFMT_U8) { if (mask & AFMT_U8) {
WInDev[0].caps.dwFormats |= WAVE_FORMAT_1M08; ossdev->in_caps.dwFormats |= WAVE_FORMAT_1M08;
if (WInDev[0].caps.wChannels > 1) if (ossdev->in_caps.wChannels > 1)
WInDev[0].caps.dwFormats |= WAVE_FORMAT_1S08; ossdev->in_caps.dwFormats |= WAVE_FORMAT_1S08;
} }
if ((mask & AFMT_S16_LE) && bytespersmpl > 1) { if ((mask & AFMT_S16_LE) && bytespersmpl > 1) {
WInDev[0].caps.dwFormats |= WAVE_FORMAT_1M16; ossdev->in_caps.dwFormats |= WAVE_FORMAT_1M16;
if (WInDev[0].caps.wChannels > 1) if (ossdev->in_caps.wChannels > 1)
WInDev[0].caps.dwFormats |= WAVE_FORMAT_1S16; ossdev->in_caps.dwFormats |= WAVE_FORMAT_1S16;
} }
} }
OSS_CloseDevice(0, audio); OSS_CloseDevice(devID, audio);
TRACE("in dwFormats = %08lX\n", WInDev[0].caps.dwFormats); TRACE("in dwFormats = %08lX\n", ossdev->in_caps.dwFormats);
}
/******************************************************************
* OSS_WaveFullDuplexInit
*
*
*/
static void OSS_WaveFullDuplexInit(unsigned devID, OSS_DEVICE* ossdev)
{
#ifdef USE_FULLDUPLEX #ifdef USE_FULLDUPLEX
if ((audio = OSS_OpenDevice(0, O_RDWR)) == -1) return -1; int audio;
if (ioctl(audio, SNDCTL_DSP_GETCAPS, &caps) == 0) { int caps;
OSS_FullDuplex = (caps & DSP_CAP_DUPLEX);
if (OSS_OpenDevice(devID, &audio, O_RDWR, NULL, 0, 0, 0) != 0) return;
if (ioctl(audio, SNDCTL_DSP_GETCAPS, &caps) == 0)
{
ossdev->full_duplex = (caps & DSP_CAP_DUPLEX);
} }
OSS_CloseDevice(0, audio); OSS_CloseDevice(devID, audio);
#endif #endif
}
/******************************************************************
* OSS_WaveInit
*
* Initialize internal structures from OSS information
*/
LONG OSS_WaveInit(void)
{
int i;
/* FIXME: only one device is supported */
memset(&OSS_Devices, 0, sizeof(OSS_Devices));
OSS_Devices[0].dev_name = "/dev/dsp";
OSS_Devices[0].mixer_name = "/dev/mixer";
/* start with output device */
for (i = 0; i < MAX_WAVEDRV; ++i)
OSS_WaveOutInit(i, &OSS_Devices[i]);
/* then do input device */
for (i = 0; i < MAX_WAVEDRV; ++i)
OSS_WaveInInit(i, &OSS_Devices[i]);
/* finish with the full duplex bits */
for (i = 0; i < MAX_WAVEDRV; i++)
OSS_WaveFullDuplexInit(i, &OSS_Devices[i]);
return 0; return 0;
} }
...@@ -1019,13 +1130,13 @@ static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSA lpCaps, DWORD dwSize) ...@@ -1019,13 +1130,13 @@ static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSA lpCaps, DWORD dwSize)
TRACE("(%u, %p, %lu);\n", wDevID, lpCaps, dwSize); TRACE("(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
if (lpCaps == NULL) return MMSYSERR_NOTENABLED; if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
if (wDevID >= MAX_WAVEOUTDRV) { if (wDevID >= MAX_WAVEDRV) {
TRACE("MAX_WAVOUTDRV reached !\n"); TRACE("MAX_WAVDRV reached !\n");
return MMSYSERR_BADDEVICEID; return MMSYSERR_BADDEVICEID;
} }
memcpy(lpCaps, &WOutDev[wDevID].caps, min(dwSize, sizeof(*lpCaps))); memcpy(lpCaps, &OSS_Devices[wDevID].out_caps, min(dwSize, sizeof(*lpCaps)));
return MMSYSERR_NOERROR; return MMSYSERR_NOERROR;
} }
...@@ -1034,19 +1145,17 @@ static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSA lpCaps, DWORD dwSize) ...@@ -1034,19 +1145,17 @@ static DWORD wodGetDevCaps(WORD wDevID, LPWAVEOUTCAPSA lpCaps, DWORD dwSize)
*/ */
static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
{ {
int format;
int sample_rate;
int dsp_stereo;
int audio_fragment; int audio_fragment;
WINE_WAVEOUT* wwo; WINE_WAVEOUT* wwo;
audio_buf_info info; audio_buf_info info;
DWORD ret;
TRACE("(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags); TRACE("(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
if (lpDesc == NULL) { if (lpDesc == NULL) {
WARN("Invalid Parameter !\n"); WARN("Invalid Parameter !\n");
return MMSYSERR_INVALPARAM; return MMSYSERR_INVALPARAM;
} }
if (wDevID >= MAX_WAVEOUTDRV) { if (wDevID >= MAX_WAVEDRV) {
TRACE("MAX_WAVOUTDRV reached !\n"); TRACE("MAX_WAVOUTDRV reached !\n");
return MMSYSERR_BADDEVICEID; return MMSYSERR_BADDEVICEID;
} }
...@@ -1070,36 +1179,12 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) ...@@ -1070,36 +1179,12 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
wwo = &WOutDev[wDevID]; wwo = &WOutDev[wDevID];
if ((dwFlags & WAVE_DIRECTSOUND) && !(wwo->caps.dwSupport & WAVECAPS_DIRECTSOUND)) if ((dwFlags & WAVE_DIRECTSOUND) && !(OSS_Devices[wDevID].out_caps.dwSupport & WAVECAPS_DIRECTSOUND))
/* not supported, ignore it */ /* not supported, ignore it */
dwFlags &= ~WAVE_DIRECTSOUND; dwFlags &= ~WAVE_DIRECTSOUND;
if (access(SOUND_DEV, 0) != 0)
return MMSYSERR_NOTENABLED;
if (wwo->unixdev != -1) return MMSYSERR_ALLOCATED;
/* we want to be able to mmap() the device, which means it must be opened readable,
* otherwise mmap() will fail (at least under Linux) */
wwo->unixdev = OSS_OpenDevice(wDevID,
((dwFlags & WAVE_DIRECTSOUND) || OSS_FullDuplex) ?
O_RDWR : O_WRONLY);
if (wwo->unixdev == -1) return MMSYSERR_ALLOCATED;
fcntl(wwo->unixdev, F_SETFD, 1); /* set close on exec flag */
wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
memcpy(&wwo->waveDesc, lpDesc, sizeof(WAVEOPENDESC));
memcpy(&wwo->format, lpDesc->lpFormat, sizeof(PCMWAVEFORMAT));
if (wwo->format.wBitsPerSample == 0) {
WARN("Resetting zeroed wBitsPerSample\n");
wwo->format.wBitsPerSample = 8 *
(wwo->format.wf.nAvgBytesPerSec /
wwo->format.wf.nSamplesPerSec) /
wwo->format.wf.nChannels;
}
if (dwFlags & WAVE_DIRECTSOUND) { if (dwFlags & WAVE_DIRECTSOUND) {
if (wwo->caps.dwSupport & WAVECAPS_SAMPLEACCURATE) if (OSS_Devices[wDevID].out_caps.dwSupport & WAVECAPS_SAMPLEACCURATE)
/* we have realtime DirectSound, fragments just waste our time, /* we have realtime DirectSound, fragments just waste our time,
* but a large buffer is good, so choose 64KB (32 * 2^11) */ * but a large buffer is good, so choose 64KB (32 * 2^11) */
audio_fragment = 0x0020000B; audio_fragment = 0x0020000B;
...@@ -1114,27 +1199,29 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) ...@@ -1114,27 +1199,29 @@ static DWORD wodOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
/* 16 fragments max, 2^10=1024 bytes per fragment */ /* 16 fragments max, 2^10=1024 bytes per fragment */
audio_fragment = 0x000F000A; audio_fragment = 0x000F000A;
} }
sample_rate = wwo->format.wf.nSamplesPerSec; if (wwo->unixdev != -1) return MMSYSERR_ALLOCATED;
dsp_stereo = (wwo->format.wf.nChannels > 1) ? 1 : 0; /* we want to be able to mmap() the device, which means it must be opened readable,
format = (wwo->format.wBitsPerSample == 16) ? AFMT_S16_LE : AFMT_U8; * otherwise mmap() will fail (at least under Linux) */
ret = OSS_OpenDevice(wDevID, &wwo->unixdev,
ioctl(wwo->unixdev, SNDCTL_DSP_SETFRAGMENT, &audio_fragment); (dwFlags & WAVE_DIRECTSOUND) ? O_RDWR : O_WRONLY,
/* First size and stereo then samplerate */ &audio_fragment, lpDesc->lpFormat->nSamplesPerSec,
ioctl(wwo->unixdev, SNDCTL_DSP_SETFMT, &format); (lpDesc->lpFormat->nChannels > 1) ? 1 : 0,
ioctl(wwo->unixdev, SNDCTL_DSP_STEREO, &dsp_stereo); (lpDesc->lpFormat->wBitsPerSample == 16)
ioctl(wwo->unixdev, SNDCTL_DSP_SPEED, &sample_rate); ? AFMT_S16_LE : AFMT_U8);
if (ret != 0) return ret;
/* paranoid checks */
if (format != ((wwo->format.wBitsPerSample == 16) ? AFMT_S16_LE : AFMT_U8)) wwo->wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
ERR("Can't set format to %d (%d)\n",
(wwo->format.wBitsPerSample == 16) ? AFMT_S16_LE : AFMT_U8, format); memcpy(&wwo->waveDesc, lpDesc, sizeof(WAVEOPENDESC));
if (dsp_stereo != (wwo->format.wf.nChannels > 1) ? 1 : 0) memcpy(&wwo->format, lpDesc->lpFormat, sizeof(PCMWAVEFORMAT));
ERR("Can't set stereo to %u (%d)\n",
(wwo->format.wf.nChannels > 1) ? 1 : 0, dsp_stereo);
if (!NEAR_MATCH(sample_rate, wwo->format.wf.nSamplesPerSec))
ERR("Can't set sample_rate to %lu (%d)\n",
wwo->format.wf.nSamplesPerSec, sample_rate);
if (wwo->format.wBitsPerSample == 0) {
WARN("Resetting zeroed wBitsPerSample\n");
wwo->format.wBitsPerSample = 8 *
(wwo->format.wf.nAvgBytesPerSec /
wwo->format.wf.nSamplesPerSec) /
wwo->format.wf.nChannels;
}
/* Read output space info for future reference */ /* Read output space info for future reference */
if (ioctl(wwo->unixdev, SNDCTL_DSP_GETOSPACE, &info) < 0) { if (ioctl(wwo->unixdev, SNDCTL_DSP_GETOSPACE, &info) < 0) {
ERR("ioctl can't 'SNDCTL_DSP_GETOSPACE' !\n"); ERR("ioctl can't 'SNDCTL_DSP_GETOSPACE' !\n");
...@@ -1192,8 +1279,8 @@ static DWORD wodClose(WORD wDevID) ...@@ -1192,8 +1279,8 @@ static DWORD wodClose(WORD wDevID)
WINE_WAVEOUT* wwo; WINE_WAVEOUT* wwo;
TRACE("(%u);\n", wDevID); TRACE("(%u);\n", wDevID);
if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].unixdev == -1) { if (wDevID >= MAX_WAVEDRV || WOutDev[wDevID].unixdev == -1) {
WARN("bad device ID !\n"); WARN("bad device ID !\n");
return MMSYSERR_BADDEVICEID; return MMSYSERR_BADDEVICEID;
} }
...@@ -1230,7 +1317,7 @@ static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) ...@@ -1230,7 +1317,7 @@ static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
/* first, do the sanity checks... */ /* first, do the sanity checks... */
if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].unixdev == -1) { if (wDevID >= MAX_WAVEDRV || WOutDev[wDevID].unixdev == -1) {
WARN("bad dev ID !\n"); WARN("bad dev ID !\n");
return MMSYSERR_BADDEVICEID; return MMSYSERR_BADDEVICEID;
} }
...@@ -1245,6 +1332,12 @@ static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) ...@@ -1245,6 +1332,12 @@ static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
lpWaveHdr->dwFlags |= WHDR_INQUEUE; lpWaveHdr->dwFlags |= WHDR_INQUEUE;
lpWaveHdr->lpNext = 0; lpWaveHdr->lpNext = 0;
if ((lpWaveHdr->dwBufferLength & ~(WOutDev[wDevID].format.wf.nBlockAlign - 1)) != 0)
{
WARN("WaveHdr length isn't a multiple of the PCM block size\n");
lpWaveHdr->dwBufferLength &= ~(WOutDev[wDevID].format.wf.nBlockAlign - 1);
}
OSS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_HEADER, (DWORD)lpWaveHdr, FALSE); OSS_AddRingMessage(&WOutDev[wDevID].msgRing, WINE_WM_HEADER, (DWORD)lpWaveHdr, FALSE);
return MMSYSERR_NOERROR; return MMSYSERR_NOERROR;
...@@ -1256,8 +1349,8 @@ static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) ...@@ -1256,8 +1349,8 @@ static DWORD wodWrite(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
{ {
TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
if (wDevID >= MAX_WAVEOUTDRV) { if (wDevID >= MAX_WAVEDRV) {
WARN("bad device ID !\n"); WARN("bad device ID !\n");
return MMSYSERR_BADDEVICEID; return MMSYSERR_BADDEVICEID;
} }
...@@ -1276,8 +1369,8 @@ static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) ...@@ -1276,8 +1369,8 @@ static DWORD wodPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
{ {
TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
if (wDevID >= MAX_WAVEOUTDRV) { if (wDevID >= MAX_WAVEDRV) {
WARN("bad device ID !\n"); WARN("bad device ID !\n");
return MMSYSERR_BADDEVICEID; return MMSYSERR_BADDEVICEID;
} }
...@@ -1297,8 +1390,8 @@ static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) ...@@ -1297,8 +1390,8 @@ static DWORD wodUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
static DWORD wodPause(WORD wDevID) static DWORD wodPause(WORD wDevID)
{ {
TRACE("(%u);!\n", wDevID); TRACE("(%u);!\n", wDevID);
if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].unixdev == -1) { if (wDevID >= MAX_WAVEDRV || WOutDev[wDevID].unixdev == -1) {
WARN("bad device ID !\n"); WARN("bad device ID !\n");
return MMSYSERR_BADDEVICEID; return MMSYSERR_BADDEVICEID;
} }
...@@ -1314,8 +1407,8 @@ static DWORD wodPause(WORD wDevID) ...@@ -1314,8 +1407,8 @@ static DWORD wodPause(WORD wDevID)
static DWORD wodRestart(WORD wDevID) static DWORD wodRestart(WORD wDevID)
{ {
TRACE("(%u);\n", wDevID); TRACE("(%u);\n", wDevID);
if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].unixdev == -1) { if (wDevID >= MAX_WAVEDRV || WOutDev[wDevID].unixdev == -1) {
WARN("bad device ID !\n"); WARN("bad device ID !\n");
return MMSYSERR_BADDEVICEID; return MMSYSERR_BADDEVICEID;
} }
...@@ -1336,8 +1429,8 @@ static DWORD wodRestart(WORD wDevID) ...@@ -1336,8 +1429,8 @@ static DWORD wodRestart(WORD wDevID)
static DWORD wodReset(WORD wDevID) static DWORD wodReset(WORD wDevID)
{ {
TRACE("(%u);\n", wDevID); TRACE("(%u);\n", wDevID);
if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].unixdev == -1) { if (wDevID >= MAX_WAVEDRV || WOutDev[wDevID].unixdev == -1) {
WARN("bad device ID !\n"); WARN("bad device ID !\n");
return MMSYSERR_BADDEVICEID; return MMSYSERR_BADDEVICEID;
} }
...@@ -1357,8 +1450,8 @@ static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize) ...@@ -1357,8 +1450,8 @@ static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
WINE_WAVEOUT* wwo; WINE_WAVEOUT* wwo;
TRACE("(%u, %p, %lu);\n", wDevID, lpTime, uSize); TRACE("(%u, %p, %lu);\n", wDevID, lpTime, uSize);
if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].unixdev == -1) { if (wDevID >= MAX_WAVEDRV || WOutDev[wDevID].unixdev == -1) {
WARN("bad device ID !\n"); WARN("bad device ID !\n");
return MMSYSERR_BADDEVICEID; return MMSYSERR_BADDEVICEID;
} }
...@@ -1415,8 +1508,8 @@ static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize) ...@@ -1415,8 +1508,8 @@ static DWORD wodGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
static DWORD wodBreakLoop(WORD wDevID) static DWORD wodBreakLoop(WORD wDevID)
{ {
TRACE("(%u);\n", wDevID); TRACE("(%u);\n", wDevID);
if (wDevID >= MAX_WAVEOUTDRV || WOutDev[wDevID].unixdev == -1) { if (wDevID >= MAX_WAVEDRV || WOutDev[wDevID].unixdev == -1) {
WARN("bad device ID !\n"); WARN("bad device ID !\n");
return MMSYSERR_BADDEVICEID; return MMSYSERR_BADDEVICEID;
} }
...@@ -1437,7 +1530,9 @@ static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol) ...@@ -1437,7 +1530,9 @@ static DWORD wodGetVolume(WORD wDevID, LPDWORD lpdwVol)
if (lpdwVol == NULL) if (lpdwVol == NULL)
return MMSYSERR_NOTENABLED; return MMSYSERR_NOTENABLED;
if ((mixer = open(MIXER_DEV, O_RDONLY|O_NDELAY)) < 0) { if (wDevID >= MAX_WAVEDRV) return MMSYSERR_INVALPARAM;
if ((mixer = open(OSS_Devices[wDevID].mixer_name, O_RDONLY|O_NDELAY)) < 0) {
WARN("mixer device not available !\n"); WARN("mixer device not available !\n");
return MMSYSERR_NOTENABLED; return MMSYSERR_NOTENABLED;
} }
...@@ -1467,8 +1562,10 @@ static DWORD wodSetVolume(WORD wDevID, DWORD dwParam) ...@@ -1467,8 +1562,10 @@ static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
left = (LOWORD(dwParam) * 100) / 0xFFFFl; left = (LOWORD(dwParam) * 100) / 0xFFFFl;
right = (HIWORD(dwParam) * 100) / 0xFFFFl; right = (HIWORD(dwParam) * 100) / 0xFFFFl;
volume = left + (right << 8); volume = left + (right << 8);
if (wDevID >= MAX_WAVEDRV) return MMSYSERR_INVALPARAM;
if ((mixer = open(MIXER_DEV, O_WRONLY|O_NDELAY)) < 0) { if ((mixer = open(OSS_Devices[wDevID].mixer_name, O_WRONLY|O_NDELAY)) < 0) {
WARN("mixer device not available !\n"); WARN("mixer device not available !\n");
return MMSYSERR_NOTENABLED; return MMSYSERR_NOTENABLED;
} }
...@@ -1483,24 +1580,6 @@ static DWORD wodSetVolume(WORD wDevID, DWORD dwParam) ...@@ -1483,24 +1580,6 @@ static DWORD wodSetVolume(WORD wDevID, DWORD dwParam)
} }
/************************************************************************** /**************************************************************************
* wodGetNumDevs [internal]
*/
static DWORD wodGetNumDevs(void)
{
DWORD ret = 1;
/* FIXME: For now, only one sound device (SOUND_DEV) is allowed */
int audio = OSS_OpenDevice(0, OSS_FullDuplex ? O_RDWR : O_WRONLY);
if (audio == -1) {
if (errno != EBUSY)
ret = 0;
} else {
OSS_CloseDevice(0, audio);
}
return ret;
}
/**************************************************************************
* wodMessage (WINEOSS.7) * wodMessage (WINEOSS.7)
*/ */
DWORD WINAPI OSS_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser, DWORD WINAPI OSS_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
...@@ -1525,7 +1604,7 @@ DWORD WINAPI OSS_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser, ...@@ -1525,7 +1604,7 @@ DWORD WINAPI OSS_wodMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
case WODM_PREPARE: return wodPrepare (wDevID, (LPWAVEHDR)dwParam1, dwParam2); case WODM_PREPARE: return wodPrepare (wDevID, (LPWAVEHDR)dwParam1, dwParam2);
case WODM_UNPREPARE: return wodUnprepare (wDevID, (LPWAVEHDR)dwParam1, dwParam2); case WODM_UNPREPARE: return wodUnprepare (wDevID, (LPWAVEHDR)dwParam1, dwParam2);
case WODM_GETDEVCAPS: return wodGetDevCaps (wDevID, (LPWAVEOUTCAPSA)dwParam1, dwParam2); case WODM_GETDEVCAPS: return wodGetDevCaps (wDevID, (LPWAVEOUTCAPSA)dwParam1, dwParam2);
case WODM_GETNUMDEVS: return wodGetNumDevs (); case WODM_GETNUMDEVS: return numOutDev;
case WODM_GETPITCH: return MMSYSERR_NOTSUPPORTED; case WODM_GETPITCH: return MMSYSERR_NOTSUPPORTED;
case WODM_SETPITCH: return MMSYSERR_NOTSUPPORTED; case WODM_SETPITCH: return MMSYSERR_NOTSUPPORTED;
case WODM_GETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED; case WODM_GETPLAYBACKRATE: return MMSYSERR_NOTSUPPORTED;
...@@ -1729,7 +1808,7 @@ static HRESULT WINAPI IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface, ...@@ -1729,7 +1808,7 @@ static HRESULT WINAPI IDsDriverBufferImpl_GetPosition(PIDSDRIVERBUFFER iface,
if (lpdwPlay) *lpdwPlay = ptr; if (lpdwPlay) *lpdwPlay = ptr;
if (lpdwWrite) { if (lpdwWrite) {
/* add some safety margin (not strictly necessary, but...) */ /* add some safety margin (not strictly necessary, but...) */
if (WOutDev[This->drv->wDevID].caps.dwSupport & WAVECAPS_SAMPLEACCURATE) if (OSS_Devices[This->drv->wDevID].out_caps.dwSupport & WAVECAPS_SAMPLEACCURATE)
*lpdwWrite = ptr + 32; *lpdwWrite = ptr + 32;
else else
*lpdwWrite = ptr + WOutDev[This->drv->wDevID].dwFragmentSize; *lpdwWrite = ptr + WOutDev[This->drv->wDevID].dwFragmentSize;
...@@ -1966,7 +2045,7 @@ static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv) ...@@ -1966,7 +2045,7 @@ static DWORD wodDsCreate(UINT wDevID, PIDSDRIVER* drv)
IDsDriverImpl** idrv = (IDsDriverImpl**)drv; IDsDriverImpl** idrv = (IDsDriverImpl**)drv;
/* the HAL isn't much better than the HEL if we can't do mmap() */ /* the HAL isn't much better than the HEL if we can't do mmap() */
if (!(WOutDev[wDevID].caps.dwSupport & WAVECAPS_DIRECTSOUND)) { if (!(OSS_Devices[wDevID].out_caps.dwSupport & WAVECAPS_DIRECTSOUND)) {
ERR("DirectSound flag not set\n"); ERR("DirectSound flag not set\n");
MESSAGE("This sound card's driver does not support direct access\n"); MESSAGE("This sound card's driver does not support direct access\n");
MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n"); MESSAGE("The (slower) DirectSound HEL mode will be used instead.\n");
...@@ -2021,13 +2100,13 @@ static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPSA lpCaps, DWORD dwSize) ...@@ -2021,13 +2100,13 @@ static DWORD widGetDevCaps(WORD wDevID, LPWAVEINCAPSA lpCaps, DWORD dwSize)
TRACE("(%u, %p, %lu);\n", wDevID, lpCaps, dwSize); TRACE("(%u, %p, %lu);\n", wDevID, lpCaps, dwSize);
if (lpCaps == NULL) return MMSYSERR_NOTENABLED; if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
if (wDevID >= MAX_WAVEINDRV) { if (wDevID >= MAX_WAVEDRV) {
TRACE("MAX_WAVINDRV reached !\n"); TRACE("MAX_WAVDRV reached !\n");
return MMSYSERR_BADDEVICEID; return MMSYSERR_BADDEVICEID;
} }
memcpy(lpCaps, &WInDev[wDevID].caps, min(dwSize, sizeof(*lpCaps))); memcpy(lpCaps, &OSS_Devices[wDevID].in_caps, min(dwSize, sizeof(*lpCaps)));
return MMSYSERR_NOERROR; return MMSYSERR_NOERROR;
} }
...@@ -2246,19 +2325,17 @@ static DWORD CALLBACK widRecorder(LPVOID pmt) ...@@ -2246,19 +2325,17 @@ static DWORD CALLBACK widRecorder(LPVOID pmt)
*/ */
static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
{ {
int fragment_size;
int sample_rate;
int format;
int dsp_stereo;
WINE_WAVEIN* wwi; WINE_WAVEIN* wwi;
int audio_fragment; int fragment_size;
int audio_fragment;
DWORD ret;
TRACE("(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags); TRACE("(%u, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
if (lpDesc == NULL) { if (lpDesc == NULL) {
WARN("Invalid Parameter !\n"); WARN("Invalid Parameter !\n");
return MMSYSERR_INVALPARAM; return MMSYSERR_INVALPARAM;
} }
if (wDevID >= MAX_WAVEINDRV) return MMSYSERR_BADDEVICEID; if (wDevID >= MAX_WAVEDRV) return MMSYSERR_BADDEVICEID;
/* only PCM format is supported so far... */ /* only PCM format is supported so far... */
if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM || if (lpDesc->lpFormat->wFormatTag != WAVE_FORMAT_PCM ||
...@@ -2278,10 +2355,22 @@ static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) ...@@ -2278,10 +2355,22 @@ static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
} }
wwi = &WInDev[wDevID]; wwi = &WInDev[wDevID];
if (wwi->unixdev != -1) return MMSYSERR_ALLOCATED; if (wwi->unixdev != -1) return MMSYSERR_ALLOCATED;
if ((wwi->unixdev = OSS_OpenDevice(wDevID, OSS_FullDuplex ? O_RDWR : O_RDONLY)) == -1) /* This is actually hand tuned to work so that my SB Live:
return MMSYSERR_ALLOCATED; * - does not skip
fcntl(wwi->unixdev, F_SETFD, 1); /* set close on exec flag */ * - does not buffer too much
* when sending with the Shoutcast winamp plugin
*/
/* 15 fragments max, 2^10 = 1024 bytes per fragment */
audio_fragment = 0x000F000A;
ret = OSS_OpenDevice(wDevID, &wwi->unixdev,
O_RDONLY, &audio_fragment,
lpDesc->lpFormat->nSamplesPerSec,
(lpDesc->lpFormat->nChannels > 1) ? 1 : 0,
(lpDesc->lpFormat->wBitsPerSample == 16)
? AFMT_S16_LE : AFMT_U8);
if (ret != 0) return ret;
if (wwi->lpQueuePtr) { if (wwi->lpQueuePtr) {
WARN("Should have an empty queue (%p)\n", wwi->lpQueuePtr); WARN("Should have an empty queue (%p)\n", wwi->lpQueuePtr);
wwi->lpQueuePtr = NULL; wwi->lpQueuePtr = NULL;
...@@ -2300,34 +2389,6 @@ static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags) ...@@ -2300,34 +2389,6 @@ static DWORD widOpen(WORD wDevID, LPWAVEOPENDESC lpDesc, DWORD dwFlags)
wwi->format.wf.nChannels; wwi->format.wf.nChannels;
} }
sample_rate = wwi->format.wf.nSamplesPerSec;
dsp_stereo = (wwi->format.wf.nChannels > 1) ? TRUE : FALSE;
format = (wwi->format.wBitsPerSample == 16) ? AFMT_S16_LE : AFMT_U8;
ioctl(wwi->unixdev, SNDCTL_DSP_SETFMT, &format);
ioctl(wwi->unixdev, SNDCTL_DSP_STEREO, &dsp_stereo);
ioctl(wwi->unixdev, SNDCTL_DSP_SPEED, &sample_rate);
/* This is actually hand tuned to work so that my SB Live:
* - does not skip
* - does not buffer too much
* when sending with the Shoutcast winamp plugin
*/
/* 7 fragments max, 2^10 = 1024 bytes per fragment */
audio_fragment = 0x0007000A;
ioctl(wwi->unixdev, SNDCTL_DSP_SETFRAGMENT, &audio_fragment);
/* paranoid checks */
if (format != ((wwi->format.wBitsPerSample == 16) ? AFMT_S16_LE : AFMT_U8))
ERR("Can't set format to %d (%d)\n",
(wwi->format.wBitsPerSample == 16) ? AFMT_S16_LE : AFMT_U8, format);
if (dsp_stereo != (wwi->format.wf.nChannels > 1) ? 1 : 0)
ERR("Can't set stereo to %u (%d)\n",
(wwi->format.wf.nChannels > 1) ? 1 : 0, dsp_stereo);
if (!NEAR_MATCH(sample_rate, wwi->format.wf.nSamplesPerSec))
ERR("Can't set sample_rate to %lu (%d)\n",
wwi->format.wf.nSamplesPerSec, sample_rate);
ioctl(wwi->unixdev, SNDCTL_DSP_GETBLKSIZE, &fragment_size); ioctl(wwi->unixdev, SNDCTL_DSP_GETBLKSIZE, &fragment_size);
if (fragment_size == -1) { if (fragment_size == -1) {
WARN("IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n"); WARN("IOCTL can't 'SNDCTL_DSP_GETBLKSIZE' !\n");
...@@ -2361,7 +2422,7 @@ static DWORD widClose(WORD wDevID) ...@@ -2361,7 +2422,7 @@ static DWORD widClose(WORD wDevID)
WINE_WAVEIN* wwi; WINE_WAVEIN* wwi;
TRACE("(%u);\n", wDevID); TRACE("(%u);\n", wDevID);
if (wDevID >= MAX_WAVEINDRV || WInDev[wDevID].unixdev == -1) { if (wDevID >= MAX_WAVEDRV || WInDev[wDevID].unixdev == -1) {
WARN("can't close !\n"); WARN("can't close !\n");
return MMSYSERR_INVALHANDLE; return MMSYSERR_INVALHANDLE;
} }
...@@ -2388,7 +2449,7 @@ static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) ...@@ -2388,7 +2449,7 @@ static DWORD widAddBuffer(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
{ {
TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
if (wDevID >= MAX_WAVEINDRV || WInDev[wDevID].unixdev == -1) { if (wDevID >= MAX_WAVEDRV || WInDev[wDevID].unixdev == -1) {
WARN("can't do it !\n"); WARN("can't do it !\n");
return MMSYSERR_INVALHANDLE; return MMSYSERR_INVALHANDLE;
} }
...@@ -2417,7 +2478,7 @@ static DWORD widPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) ...@@ -2417,7 +2478,7 @@ static DWORD widPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
{ {
TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
if (wDevID >= MAX_WAVEINDRV) return MMSYSERR_INVALHANDLE; if (wDevID >= MAX_WAVEDRV) return MMSYSERR_INVALHANDLE;
if (lpWaveHdr->dwFlags & WHDR_INQUEUE) if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
return WAVERR_STILLPLAYING; return WAVERR_STILLPLAYING;
...@@ -2435,7 +2496,7 @@ static DWORD widPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) ...@@ -2435,7 +2496,7 @@ static DWORD widPrepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
static DWORD widUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) static DWORD widUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
{ {
TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize); TRACE("(%u, %p, %08lX);\n", wDevID, lpWaveHdr, dwSize);
if (wDevID >= MAX_WAVEINDRV) return MMSYSERR_INVALHANDLE; if (wDevID >= MAX_WAVEDRV) return MMSYSERR_INVALHANDLE;
if (lpWaveHdr->dwFlags & WHDR_INQUEUE) if (lpWaveHdr->dwFlags & WHDR_INQUEUE)
return WAVERR_STILLPLAYING; return WAVERR_STILLPLAYING;
...@@ -2452,7 +2513,7 @@ static DWORD widUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize) ...@@ -2452,7 +2513,7 @@ static DWORD widUnprepare(WORD wDevID, LPWAVEHDR lpWaveHdr, DWORD dwSize)
static DWORD widStart(WORD wDevID) static DWORD widStart(WORD wDevID)
{ {
TRACE("(%u);\n", wDevID); TRACE("(%u);\n", wDevID);
if (wDevID >= MAX_WAVEINDRV || WInDev[wDevID].unixdev == -1) { if (wDevID >= MAX_WAVEDRV || WInDev[wDevID].unixdev == -1) {
WARN("can't start recording !\n"); WARN("can't start recording !\n");
return MMSYSERR_INVALHANDLE; return MMSYSERR_INVALHANDLE;
} }
...@@ -2467,7 +2528,7 @@ static DWORD widStart(WORD wDevID) ...@@ -2467,7 +2528,7 @@ static DWORD widStart(WORD wDevID)
static DWORD widStop(WORD wDevID) static DWORD widStop(WORD wDevID)
{ {
TRACE("(%u);\n", wDevID); TRACE("(%u);\n", wDevID);
if (wDevID >= MAX_WAVEINDRV || WInDev[wDevID].unixdev == -1) { if (wDevID >= MAX_WAVEDRV || WInDev[wDevID].unixdev == -1) {
WARN("can't stop !\n"); WARN("can't stop !\n");
return MMSYSERR_INVALHANDLE; return MMSYSERR_INVALHANDLE;
} }
...@@ -2483,7 +2544,7 @@ static DWORD widStop(WORD wDevID) ...@@ -2483,7 +2544,7 @@ static DWORD widStop(WORD wDevID)
static DWORD widReset(WORD wDevID) static DWORD widReset(WORD wDevID)
{ {
TRACE("(%u);\n", wDevID); TRACE("(%u);\n", wDevID);
if (wDevID >= MAX_WAVEINDRV || WInDev[wDevID].unixdev == -1) { if (wDevID >= MAX_WAVEDRV || WInDev[wDevID].unixdev == -1) {
WARN("can't reset !\n"); WARN("can't reset !\n");
return MMSYSERR_INVALHANDLE; return MMSYSERR_INVALHANDLE;
} }
...@@ -2501,7 +2562,7 @@ static DWORD widGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize) ...@@ -2501,7 +2562,7 @@ static DWORD widGetPosition(WORD wDevID, LPMMTIME lpTime, DWORD uSize)
TRACE("(%u, %p, %lu);\n", wDevID, lpTime, uSize); TRACE("(%u, %p, %lu);\n", wDevID, lpTime, uSize);
if (wDevID >= MAX_WAVEINDRV || WInDev[wDevID].unixdev == -1) { if (wDevID >= MAX_WAVEDRV || WInDev[wDevID].unixdev == -1) {
WARN("can't get pos !\n"); WARN("can't get pos !\n");
return MMSYSERR_INVALHANDLE; return MMSYSERR_INVALHANDLE;
} }
...@@ -2573,7 +2634,7 @@ DWORD WINAPI OSS_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser, ...@@ -2573,7 +2634,7 @@ DWORD WINAPI OSS_widMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
case WIDM_PREPARE: return widPrepare (wDevID, (LPWAVEHDR)dwParam1, dwParam2); case WIDM_PREPARE: return widPrepare (wDevID, (LPWAVEHDR)dwParam1, dwParam2);
case WIDM_UNPREPARE: return widUnprepare (wDevID, (LPWAVEHDR)dwParam1, dwParam2); case WIDM_UNPREPARE: return widUnprepare (wDevID, (LPWAVEHDR)dwParam1, dwParam2);
case WIDM_GETDEVCAPS: return widGetDevCaps (wDevID, (LPWAVEINCAPSA)dwParam1, dwParam2); case WIDM_GETDEVCAPS: return widGetDevCaps (wDevID, (LPWAVEINCAPSA)dwParam1, dwParam2);
case WIDM_GETNUMDEVS: return wodGetNumDevs (); /* same number of devices in output as in input */ case WIDM_GETNUMDEVS: return numInDev;
case WIDM_GETPOS: return widGetPosition(wDevID, (LPMMTIME)dwParam1, dwParam2); case WIDM_GETPOS: return widGetPosition(wDevID, (LPMMTIME)dwParam1, dwParam2);
case WIDM_RESET: return widReset (wDevID); case WIDM_RESET: return widReset (wDevID);
case WIDM_START: return widStart (wDevID); case WIDM_START: return widStart (wDevID);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment