[WINEOSS] multi channel support

Robert Reif reif at earthlink.net
Sun May 29 18:44:36 CDT 2005


Add support for more than 2 audio channels.

Unfortunately, the the default opening mode is RW
which means full duplex which limits playback to 2
channels.  This is to work around various bugs in linux
and OSS.  We probably need a way to disable this on
systems that work properly or detect at runtime which
systems are broken.
-------------- next part --------------
Index: dlls/winmm/wineoss/audio.c
===================================================================
RCS file: /home/wine/wine/dlls/winmm/wineoss/audio.c,v
retrieving revision 1.162
diff -p -u -r1.162 audio.c
--- dlls/winmm/wineoss/audio.c	29 May 2005 20:02:58 -0000	1.162
+++ dlls/winmm/wineoss/audio.c	29 May 2005 23:30:10 -0000
@@ -276,7 +276,7 @@ static BOOL supportedFormat(LPWAVEFORMAT
         return FALSE;
 
     if (wf->wFormatTag == WAVE_FORMAT_PCM) {
-        if (wf->nChannels==1||wf->nChannels==2) {
+        if (wf->nChannels >= 1 && wf->nChannels <= MAX_CHANNELS) {
             if (wf->wBitsPerSample==8||wf->wBitsPerSample==16)
                 return TRUE;
         }
@@ -284,7 +284,7 @@ static BOOL supportedFormat(LPWAVEFORMAT
         WAVEFORMATEXTENSIBLE * wfex = (WAVEFORMATEXTENSIBLE *)wf;
 
         if (wf->cbSize == 22 && IsEqualGUID(&wfex->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) {
-            if (wf->nChannels==1||wf->nChannels==2) {
+            if (wf->nChannels >=1 && wf->nChannels <= MAX_CHANNELS) {
                 if (wf->wBitsPerSample==wfex->Samples.wValidBitsPerSample) {
                     if (wf->wBitsPerSample==8||wf->wBitsPerSample==16)
                         return TRUE;
@@ -356,7 +356,7 @@ static DWORD      OSS_RawOpenDevice(OSS_
 	}
     }
 
-    /* First size and stereo then samplerate */
+    /* First size and channels then samplerate */
     if (ossdev->format>=0)
     {
         val = ossdev->format;
@@ -367,12 +367,12 @@ static DWORD      OSS_RawOpenDevice(OSS_
                 goto error;
         }
     }
-    if (ossdev->stereo>=0)
+    if (ossdev->channels>=0)
     {
-        val = ossdev->stereo;
-        rc = ioctl(fd, SNDCTL_DSP_STEREO, &ossdev->stereo);
-        if (rc != 0 || val != ossdev->stereo) {
-            TRACE("Can't set stereo to %u (returned %d)\n", val, ossdev->stereo);
+        val = ossdev->channels;
+        rc = ioctl(fd, SNDCTL_DSP_CHANNELS, &ossdev->channels);
+        if (rc != 0 || val != ossdev->channels) {
+            TRACE("Can't set channels to %u (returned %d)\n", val, ossdev->channels);
             if (strict_format)
                 goto error;
         }
@@ -440,11 +440,11 @@ error2:
  */
 DWORD OSS_OpenDevice(OSS_DEVICE* ossdev, unsigned req_access,
                             int* frag, int strict_format,
-                            int sample_rate, int stereo, int fmt)
+                            int sample_rate, int channels, int fmt)
 {
     DWORD       ret;
     DWORD open_access;
-    TRACE("(%p,%u,%p,%d,%d,%d,%x)\n",ossdev,req_access,frag,strict_format,sample_rate,stereo,fmt);
+    TRACE("(%p,%u,%p,%d,%d,%d,%x)\n",ossdev,req_access,frag,strict_format,sample_rate,channels,fmt);
 
     if (ossdev->full_duplex && (req_access == O_RDONLY || req_access == O_WRONLY))
     {
@@ -464,7 +464,7 @@ DWORD OSS_OpenDevice(OSS_DEVICE* ossdev,
 
         ossdev->audio_fragment = (frag) ? *frag : 0;
         ossdev->sample_rate = sample_rate;
-        ossdev->stereo = stereo;
+        ossdev->channels = channels;
         ossdev->format = fmt;
         ossdev->open_access = open_access;
         ossdev->owner_tid = GetCurrentThreadId();
@@ -495,16 +495,16 @@ DWORD OSS_OpenDevice(OSS_DEVICE* ossdev,
 
 	/* check if the audio parameters are the same */
         if (ossdev->sample_rate != sample_rate ||
-            ossdev->stereo != stereo ||
+            ossdev->channels != channels ||
             ossdev->format != fmt)
         {
 	    /* This is not a fatal error because MSACM might do the remapping */
             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",
+                 "audio_frag(%x/%x) sample_rate(%d/%d) channels(%d/%d) fmt(%d/%d)\n",
                  ossdev->audio_fragment, frag ? *frag : 0,
                  ossdev->sample_rate, sample_rate,
-                 ossdev->stereo, stereo,
+                 ossdev->channels, channels,
                  ossdev->format, fmt);
             return WAVERR_BADFORMAT;
         }
@@ -783,28 +783,29 @@ static BOOL OSS_WaveOutInit(OSS_DEVICE* 
 	else if (f == 1)
 	    ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARY16BIT;
 
-        for (c=0;c<2;c++) {
+        for (c = 1; c <= MAX_CHANNELS; c++) {
             arg=c;
-            rc=ioctl(ossdev->fd, SNDCTL_DSP_STEREO, &arg);
+            rc=ioctl(ossdev->fd, SNDCTL_DSP_CHANNELS, &arg);
             if (rc!=0 || arg!=c) {
-                TRACE("DSP_STEREO: rc=%d returned %d for %d\n",rc,arg,c);
+                TRACE("DSP_CHANNELS: rc=%d returned %d for %d\n",rc,arg,c);
                 continue;
             }
-	    if (c == 0) {
+	    if (c == 1) {
 		ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARYMONO;
-	    } else if (c==1) {
-                ossdev->out_caps.wChannels=2;
+	    } else if (c == 2) {
+                ossdev->out_caps.wChannels = 2;
                 ossdev->out_caps.dwSupport|=WAVECAPS_LRVOLUME;
 		ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARYSTEREO;
-            }
+            } else
+                ossdev->out_caps.wChannels = c;
 
             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 && arg!=0 && NEAR_MATCH(arg,win_std_rates[r]))
-                    ossdev->out_caps.dwFormats|=win_std_formats[f][c][r];
+                      rc,arg,win_std_rates[r],win_std_oss_fmts[f],c);
+                if (rc==0 && arg!=0 && NEAR_MATCH(arg,win_std_rates[r]) && c < 3)
+                    ossdev->out_caps.dwFormats|=win_std_formats[f][c-1][r];
             }
         }
     }
@@ -847,8 +848,9 @@ static BOOL OSS_WaveOutInit(OSS_DEVICE* 
 #endif
     }
     OSS_CloseDevice(ossdev);
-    TRACE("out dwFormats = %08lX, dwSupport = %08lX\n",
-          ossdev->out_caps.dwFormats, ossdev->out_caps.dwSupport);
+    TRACE("out wChannels = %d, dwFormats = %08lX, dwSupport = %08lX\n",
+          ossdev->out_caps.wChannels, ossdev->out_caps.dwFormats,
+          ossdev->out_caps.dwSupport);
     return TRUE;
 }
 
@@ -920,25 +922,25 @@ static BOOL OSS_WaveInInit(OSS_DEVICE* o
             continue;
         }
 
-        for (c=0;c<2;c++) {
+        for (c = 1; c <= MAX_CHANNELS; c++) {
             arg=c;
-            rc=ioctl(ossdev->fd, SNDCTL_DSP_STEREO, &arg);
+            rc=ioctl(ossdev->fd, SNDCTL_DSP_CHANNELS, &arg);
             if (rc!=0 || arg!=c) {
-                TRACE("DSP_STEREO: rc=%d returned %d for %d\n",rc,arg,c);
+                TRACE("DSP_CHANNELS: rc=%d returned %d for %d\n",rc,arg,c);
                 continue;
             }
-            if (c==1) {
-                ossdev->in_caps.wChannels=2;
-    		ossdev->dsc_caps.dwChannels=2;
+            if (c > 1) {
+                ossdev->in_caps.wChannels = c;
+    		ossdev->dsc_caps.dwChannels = c;
             }
 
             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];
-		    ossdev->dsc_caps.dwFormats|=win_std_formats[f][c][r];
+                TRACE("DSP_SPEED: rc=%d returned %d for %dx%dx%d\n",rc,arg,win_std_rates[r],win_std_oss_fmts[f],c);
+                if (rc==0 && NEAR_MATCH(arg,win_std_rates[r]) && c < 3)
+                    ossdev->in_caps.dwFormats|=win_std_formats[f][c-1][r];
+		    ossdev->dsc_caps.dwFormats|=win_std_formats[f][c-1][r];
             }
         }
     }
@@ -957,8 +959,8 @@ static BOOL OSS_WaveInInit(OSS_DEVICE* o
 	    ossdev->in_caps_support |= WAVECAPS_SAMPLEACCURATE;
     }
     OSS_CloseDevice(ossdev);
-    TRACE("in dwFormats = %08lX, in_caps_support = %08lX\n",
-        ossdev->in_caps.dwFormats, ossdev->in_caps_support);
+    TRACE("in wChannels = %d, dwFormats = %08lX, in_caps_support = %08lX\n",
+        ossdev->in_caps.wChannels, ossdev->in_caps.dwFormats, ossdev->in_caps_support);
     return TRUE;
 }
 
@@ -1012,28 +1014,29 @@ static void OSS_WaveFullDuplexInit(OSS_D
             continue;
         }
 
-        for (c=0;c<2;c++) {
+        for (c = 1; c <= MAX_CHANNELS; c++) {
             arg=c;
-            rc=ioctl(ossdev->fd, SNDCTL_DSP_STEREO, &arg);
+            rc=ioctl(ossdev->fd, SNDCTL_DSP_CHANNELS, &arg);
             if (rc!=0 || arg!=c) {
-                TRACE("DSP_STEREO: rc=%d returned %d for %d\n",rc,arg,c);
+                TRACE("DSP_CHANNELS: rc=%d returned %d for %d\n",rc,arg,c);
                 continue;
             }
-	    if (c == 0) {
+	    if (c == 1) {
 		ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARYMONO;
-	    } else if (c==1) {
-                ossdev->duplex_out_caps.wChannels=2;
+	    } else if (c == 2) {
+                ossdev->duplex_out_caps.wChannels = 2;
                 ossdev->duplex_out_caps.dwSupport|=WAVECAPS_LRVOLUME;
 		ossdev->ds_caps.dwFlags |= DSCAPS_PRIMARYSTEREO;
-            }
+            } else
+                ossdev->duplex_out_caps.wChannels = c;
 
             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 && arg!=0 && NEAR_MATCH(arg,win_std_rates[r]))
-                    ossdev->duplex_out_caps.dwFormats|=win_std_formats[f][c][r];
+                      rc,arg,win_std_rates[r],win_std_oss_fmts[f],c);
+                if (rc==0 && arg!=0 && NEAR_MATCH(arg,win_std_rates[r]) && c < 3)
+                    ossdev->duplex_out_caps.dwFormats|=win_std_formats[f][c-1][r];
             }
         }
     }
@@ -1049,8 +1052,10 @@ static void OSS_WaveFullDuplexInit(OSS_D
 	}
     }
     OSS_CloseDevice(ossdev);
-    TRACE("duplex dwFormats = %08lX, dwSupport = %08lX\n",
-          ossdev->duplex_out_caps.dwFormats, ossdev->duplex_out_caps.dwSupport);
+    TRACE("duplex wChannels = %d, dwFormats = %08lX, dwSupport = %08lX\n",
+          ossdev->duplex_out_caps.wChannels,
+          ossdev->duplex_out_caps.dwFormats,
+          ossdev->duplex_out_caps.dwSupport);
 }
 
 static char* StrDup(const char* str, const char* def)
@@ -1932,12 +1937,12 @@ DWORD wodOpen(WORD wDevID, LPWAVEOPENDES
                          &audio_fragment,
                          (dwFlags & WAVE_DIRECTSOUND) ? 0 : 1,
                          lpDesc->lpFormat->nSamplesPerSec,
-                         (lpDesc->lpFormat->nChannels > 1) ? 1 : 0,
+                         lpDesc->lpFormat->nChannels,
                          (lpDesc->lpFormat->wBitsPerSample == 16)
                              ? AFMT_S16_LE : AFMT_U8);
     if ((ret==MMSYSERR_NOERROR) && (dwFlags & WAVE_DIRECTSOUND)) {
         lpDesc->lpFormat->nSamplesPerSec=wwo->ossdev->sample_rate;
-        lpDesc->lpFormat->nChannels=(wwo->ossdev->stereo ? 2 : 1);
+        lpDesc->lpFormat->nChannels=wwo->ossdev->channels;
         lpDesc->lpFormat->wBitsPerSample=(wwo->ossdev->format == AFMT_U8 ? 8 : 16);
         lpDesc->lpFormat->nBlockAlign=lpDesc->lpFormat->nChannels*lpDesc->lpFormat->wBitsPerSample/8;
         lpDesc->lpFormat->nAvgBytesPerSec=lpDesc->lpFormat->nSamplesPerSec*lpDesc->lpFormat->nBlockAlign;
@@ -1971,8 +1976,7 @@ DWORD wodOpen(WORD wDevID, LPWAVEOPENDES
 
     TRACE("got %d %d byte fragments (%d ms/fragment)\n", info.fragstotal,
         info.fragsize, (info.fragsize * 1000) / (wwo->ossdev->sample_rate *
-        (wwo->ossdev->stereo ? 2 : 1) *
-        (wwo->ossdev->format == AFMT_U8 ? 1 : 2)));
+        wwo->ossdev->channels * (wwo->ossdev->format == AFMT_U8 ? 1 : 2)));
 
     /* Check that fragsize is correct per our settings above */
     if ((info.fragsize > 1024) && (LOWORD(audio_fragment) <= 10)) {
@@ -2804,7 +2808,7 @@ DWORD widOpen(WORD wDevID, LPWAVEOPENDES
     ret = OSS_OpenDevice(wwi->ossdev, O_RDONLY, &audio_fragment,
                          1,
                          lpDesc->lpFormat->nSamplesPerSec,
-                         (lpDesc->lpFormat->nChannels > 1) ? 1 : 0,
+                         lpDesc->lpFormat->nChannels,
                          (lpDesc->lpFormat->wBitsPerSample == 16)
                          ? AFMT_S16_LE : AFMT_U8);
     if (ret != 0) return ret;
@@ -2839,8 +2843,7 @@ DWORD widOpen(WORD wDevID, LPWAVEOPENDES
 
     TRACE("got %d %d byte fragments (%d ms/fragment)\n", info.fragstotal,
         info.fragsize, (info.fragsize * 1000) / (wwi->ossdev->sample_rate *
-        (wwi->ossdev->stereo ? 2 : 1) *
-        (wwi->ossdev->format == AFMT_U8 ? 1 : 2)));
+        wwi->ossdev->channels * (wwi->ossdev->format == AFMT_U8 ? 1 : 2)));
 
     wwi->dwFragmentSize = info.fragsize;
 
Index: dlls/winmm/wineoss/audio.h
===================================================================
RCS file: /home/wine/wine/dlls/winmm/wineoss/audio.h,v
retrieving revision 1.3
diff -p -u -r1.3 audio.h
--- dlls/winmm/wineoss/audio.h	23 Feb 2005 21:00:02 -0000	1.3
+++ dlls/winmm/wineoss/audio.h	29 May 2005 23:30:10 -0000
@@ -27,6 +27,7 @@
 #define USE_PIPE_SYNC
 
 #define MAX_WAVEDRV 	(6)
+#define MAX_CHANNELS	6
 
 /* states of the playing device */
 #define	WINE_WS_PLAYING		0
@@ -92,7 +93,7 @@ typedef struct tagOSS_DEVICE {
     int                         fd;
     DWORD                       owner_tid;
     int                         sample_rate;
-    int                         stereo;
+    int                         channels;
     int                         format;
     unsigned                    audio_fragment;
     BOOL                        full_duplex;


More information about the wine-patches mailing list