NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

lib/46611: libossaudio: Support for OSSv4



>Number:         46611
>Category:       lib
>Synopsis:       libossaudio: Support for OSSv4
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    lib-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Sun Jun 17 12:45:00 +0000 2012
>Originator:     Nat Sloss
>Release:        NetBSD 5.0.1
>Organization:
>Environment:
NetBSD beast 5.0.1 NetBSD 5.0.1 (LOCKDEBUG) #98: Sat Jun 16 19:50:55 EST 2012  
build@beast:/usr/src/sys/arch/i386/compile/LOCKDEBUG i386

>Description:
Hi.

Wine-devel from pkgsrc requires ossv4 compatibility for sound.  So do later 
versions of wine 1.4 and 1.56 they have no support for NetBSD's audio 
subsystem.  Also I think the prerequisite for version 4 compatibility will be 
more common.
>How-To-Repeat:
Make configure on wine-devel from pkgsrc and you will receive a warning that 
there is no sound support as it requires oss v4 compatibility.
>Fix:
I implemented some of the required ioctls and redefined open and close to 
accommodate for the fact that wine devel would open an audio device and open it 
again in another function whilst it was previously open.  If that open failed 
as it would normally no sound was produced.

So here are my patches I have as yet to port them to current:

 Index: soundcard.h
===================================================================
RCS file: /cvsroot/src/lib/libossaudio/soundcard.h,v
retrieving revision 1.18
diff -u -r1.18 soundcard.h
--- soundcard.h 28 Apr 2008 20:23:01 -0000      1.18
+++ soundcard.h 17 Jun 2012 11:37:24 -0000
@@ -39,7 +39,7 @@
 #ifndef _SOUNDCARD_H_
 #define _SOUNDCARD_H_
 
-#define SOUND_VERSION  0x030001
+#define SOUND_VERSION 0x040001
 
 #define        SNDCTL_DSP_RESET                _IO  ('P', 0)
 #define        SNDCTL_DSP_SYNC                 _IO  ('P', 1)
@@ -59,6 +59,10 @@
 #define         AFMT_U16_LE                    0x00000080
 #define         AFMT_U16_BE                    0x00000100
 #define         AFMT_MPEG                      0x00000200
+#define         AFMT_S24_LE                    0x00000400
+#define         AFMT_S24_BE                    0x00000800
+#define         AFMT_S32_LE                    0x00001000
+#define         AFMT_S32_BE                    0x00002000
 #define SNDCTL_DSP_SAMPLESIZE          SNDCTL_DSP_SETFMT
 #define        SOUND_PCM_READ_BITS             _IOR ('P', 5, int)
 #define        SNDCTL_DSP_CHANNELS             _IOWR('P', 6, int)
@@ -81,6 +85,8 @@
 # define DSP_CAP_COPROC                        0x00000800
 # define DSP_CAP_TRIGGER               0x00001000
 # define DSP_CAP_MMAP                  0x00002000
+# define PCM_CAP_INPUT                 0x00004000
+# define PCM_CAP_OUTPUT                        0x00008000
 #define SNDCTL_DSP_GETTRIGGER          _IOR ('P', 16, int)
 #define SNDCTL_DSP_SETTRIGGER          _IOW ('P', 16, int)
 # define PCM_ENABLE_INPUT              0x00000001
@@ -290,6 +296,76 @@
        int size;
 } buffmem_desc;
 
+/* Some OSSv4 calls. */
+
+#define OSS_DEVNODE_SIZE               32
+#define OSS_LABEL_SIZE                 16
+#define OSS_LONGNAME_SIZE              64
+#define OSS_MAX_AUDIO_DEVS             64
+
+#define SNDCTL_SYSINFO                 _IOR ('P',24, struct oss_sysinfo)
+#define SNDCTL_AUDIOINFO               _IOWR ('P',25, struct oss_audioinfo)
+#define SNDCTL_ENGINEINFO              _IOWR ('P',26, struct oss_audioinfo)
+#define SNDCTL_DSP_GETPLAYVOL          _IOR ('P',27, uint)
+#define SNDCTL_DSP_SETPLAYVOL          _IOW ('P',28, uint)
+#define SNDCTL_DSP_GETRECVOL           _IOR ('P',29, uint)
+#define SNDCTL_DSP_SETRECVOL           _IOW ('P',30, uint)
+#define SNDCTL_DSP_SKIP                        _IO ('P',31)
+
+typedef struct oss_sysinfo {
+       char product[32];
+       char version[32];
+       int versionnum;
+       char options[128];              /* Future use */
+       int numaudios;
+       int openedaudio[8];             /* Obsolete */
+       int numsynths;                  /* Obsolete */
+       int nummidis;
+       int numtimers;
+       int nummixers;
+       int openedmidi[8];
+       int numcards;
+       int numaudioengines;
+       char license[16];
+       char revision_info[256];        /* Internal Use */
+       int filler[172];                /* For expansion */
+} oss_sysinfo;
+
+typedef struct oss_audioinfo {
+       int dev;                /* Set by caller */
+       char name[OSS_LONGNAME_SIZE];
+       int busy;
+       int pid;
+       int caps;
+       int iformats;
+       int oformats;
+       int magic;              /* Unused */
+       char cmd[OSS_LONGNAME_SIZE];
+       int card_number;
+       int port_number;
+       int mixer_dev;
+       int legacy_device;      /* Obsolete */
+       int enabled;
+       int flags;              /* Reserved */
+       int min_rate;
+       int max_rate;
+       int min_channels;
+       int max_channels;
+       int binding;            /* Reserved */
+       int rate_source;
+       char handle[32];
+#define OSS_MAX_SAMPLE_RATES   20
+       int nrates;
+       int rates[OSS_MAX_SAMPLE_RATES];
+       char song_name[OSS_LONGNAME_SIZE];
+       char label[OSS_LABEL_SIZE];
+       int latency;                            /* In usecs -1 = unknown */
+       char devnode[OSS_DEVNODE_SIZE];         /* device file name without 
/dev */
+       int next_play_engine;
+       int next_rec_engine;
+       int filler[184];                        /* For expansion */
+} oss_audioinfo;
+
 #if 0
 /* This is what we'd like to have, but it causes prototype conflicts. */
 #define ioctl _oss_ioctl
@@ -302,12 +378,18 @@
  */
 #include <sys/ioctl.h>
 #define ioctl(x,y,z) _oss_ioctl(x,y,z)
+#include <fcntl.h>
+#include <unistd.h>
+#define open(x,y,...) _oss_open(x,y,##__VA_ARGS__) 
+#define close(x) _oss_close(x)
 #endif
 
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
 int _oss_ioctl(int fd, unsigned long com, void *argp);
+int _oss_open(char *path, int flags, ...);
+int _oss_close(int fd);
 __END_DECLS
 
 #endif /* !_SOUNDCARD_H_ */
Index: ossaudio.c
===================================================================
RCS file: /cvsroot/src/lib/libossaudio/ossaudio.c,v
retrieving revision 1.24
diff -u -r1.24 ossaudio.c
--- ossaudio.c  28 Apr 2008 20:23:01 -0000      1.24
+++ ossaudio.c  17 Jun 2012 11:37:40 -0000
@@ -44,17 +44,33 @@
 #include <sys/audioio.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdarg.h>
 
 #include "soundcard.h"
 #undef ioctl
+#undef open
+#undef close
 
 #define GET_DEV(com) ((com) & 0xff)
 
 #define TO_OSSVOL(x)   (((x) * 100 + 127) / 255)
 #define FROM_OSSVOL(x) ((((x) > 100 ? 100 : (x)) * 255 + 50) / 100)
 
+static int initialised = 0;
+typedef struct openaudiofds {
+       int read;
+       int write;
+       int readwrite;
+       int count;
+} openaudiofds_t;
+
+static openaudiofds_t openedfds[64];
 static struct audiodevinfo *getdevinfo(int);
 
+static void audioopeninit(void);               /* Initialises fd structure */
 static void setblocksize(int, struct audio_info *);
 
 static int audio_ioctl(int, unsigned long, void *);
@@ -65,6 +81,134 @@
 
 #define INTARG (*(int*)argp)
 
+static void
+audioopeninit()
+{
+       int i;
+
+       for (i = 0; i < 64; i++) {
+               openedfds[i].readwrite = -1;
+               openedfds[i].write = -1;
+               openedfds[i].read = -1;
+               openedfds[i].count = -1;
+       }
+       initialised = 1;
+
+       return;
+}
+
+int
+_oss_open(char *path, int flags, ...)
+{
+       int i, fd;
+       char checkpath[255];
+
+       va_list ap;
+       mode_t mode;
+
+       va_start(ap, flags);
+       mode = va_arg(ap, mode_t);
+       va_end(ap);
+
+       fd = -1;
+
+       if (initialised == 0)
+               audioopeninit();
+       if (strncmp("/dev/audio", path, 10) == 0) {
+               for (i=0; i < OSS_MAX_AUDIO_DEVS; i++) {
+                       snprintf(checkpath, 255, "/dev/audio%d", i);
+                       if (strcmp(checkpath, path) == 0)
+                               break;
+               }
+
+               if (i == OSS_MAX_AUDIO_DEVS)
+                       return -1;
+               if ((flags & O_ACCMODE) == O_RDWR) {
+                       if (openedfds[i].readwrite == -1) {
+                               fd = open(path, flags, mode);
+                               if (fd < 0)
+                                       return fd;
+                               else {
+                                       openedfds[i].readwrite = fd;
+                                       openedfds[i].count++;
+                               }
+                       } else {
+                               fd = openedfds[i].readwrite;
+                               openedfds[i].count++;
+                       }
+               } else if ((flags & O_ACCMODE) == O_WRONLY) {
+                       if (openedfds[i].write == -1) {
+                               fd = open(path, flags, mode);
+                               if (fd < 0)
+                                       return fd;
+                               else {
+                                       openedfds[i].write = fd;
+                                       openedfds[i].count++;
+                               }
+                       } else {
+                               fd = openedfds[i].write;
+                               openedfds[i].count++;
+                       }
+               } else if ((flags & O_ACCMODE) == O_RDONLY) {
+                       if (openedfds[i].read == -1) {
+                               fd = open(path, flags, mode);
+                               if (fd < 0)
+                                       return fd;
+                               else {
+                                       openedfds[i].read = fd;
+                                       openedfds[i].count++;
+                               }
+                       } else {
+                               fd = openedfds[i].read;
+                               openedfds[i].count++;
+                       }
+               }
+               errno = 0;
+               /*printf("fd = %d openedcount[%d]: %d\n", fd, i,
+                *    openedfds[i].count);
+                */
+       } else
+               fd = open(path, flags, mode);
+       
+       return fd;
+}
+
+int
+_oss_close(int fd)
+{
+       int i;
+       for (i = 0; i < OSS_MAX_AUDIO_DEVS; i++) {
+               if (fd == openedfds[i].readwrite)
+                       break;
+               if (fd == openedfds[i].write)
+                       break;
+               if (fd == openedfds[i].read)
+                       break;
+       }
+
+       if (i < OSS_MAX_AUDIO_DEVS) {
+               openedfds[i].count--;
+               if (openedfds[i].count < 0) {
+                       if (openedfds[i].readwrite >= 0) {
+                               close(openedfds[i].readwrite);
+                               openedfds[i].readwrite = -1;
+                       }
+                       if (openedfds[i].write >= 0) {
+                               close(openedfds[i].write);
+                               openedfds[i].write = -1;
+                       }
+                       if (openedfds[i].read >= 0) {
+                               close(openedfds[i].read);
+                               openedfds[i].read = -1;
+                       }
+               }
+               /*printf("oss_close count[%d]: %d\n",i, openedfds[i].count);*/
+
+               return 0;
+       } else
+               return (close(fd));
+}
+
 int
 _oss_ioctl(int fd, unsigned long com, void *argp)
 {
@@ -85,9 +229,18 @@
        struct audio_buf_info bufinfo;
        struct count_info cntinfo;
        struct audio_encoding tmpenc;
+       struct oss_sysinfo tmpsysinfo;
+       struct oss_audioinfo *tmpaudioinfo;
+       audio_device_t tmpaudiodev;
+       char audiodevpath[255];
+       struct stat tmpstat;
+       dev_t devno;
+       char version[32] = "4.01";
+       char license[16] = "NetBSD";
        u_int u;
        int idat, idata;
        int retval;
+       int i, audiofd;
 
        idat = 0;
 
@@ -299,13 +452,21 @@
                                idat |= AFMT_S8;
                                break;
                        case AUDIO_ENCODING_SLINEAR_LE:
-                               if (tmpenc.precision == 16)
+                               if (tmpenc.precision == 32)
+                                       idat |= AFMT_S32_LE;
+                               else if (tmpenc.precision == 24)
+                                       idat |= AFMT_S24_LE;
+                               else if (tmpenc.precision == 16)
                                        idat |= AFMT_S16_LE;
                                else
                                        idat |= AFMT_S8;
                                break;
                        case AUDIO_ENCODING_SLINEAR_BE:
-                               if (tmpenc.precision == 16)
+                               if (tmpenc.precision == 32)
+                                       idat |= AFMT_S32_BE;
+                               else if (tmpenc.precision == 24)
+                                       idat |= AFMT_S24_BE;
+                               else if (tmpenc.precision == 16)
                                        idat |= AFMT_S16_BE;
                                else
                                        idat |= AFMT_S8;
@@ -423,6 +584,133 @@
                cntinfo.ptr = tmpoffs.offset;
                *(struct count_info *)argp = cntinfo;
                break;
+       case SNDCTL_SYSINFO:
+               strncpy(tmpsysinfo.product, "OSS/NetBSD", 31);
+               tmpsysinfo.product[31] = 0; 
+               strncpy(tmpsysinfo.version, version, 31); 
+               tmpsysinfo.version[31] = 0; 
+               strncpy(tmpsysinfo.license, license, 15);
+               tmpsysinfo.license[15] = 0; 
+               tmpsysinfo.versionnum = SOUND_VERSION;
+               memset(tmpsysinfo.options, 0, 8);
+               tmpsysinfo.numaudios = OSS_MAX_AUDIO_DEVS;
+               tmpsysinfo.numaudioengines = 1;
+               memset(tmpsysinfo.openedaudio, 0, 8);
+               tmpsysinfo.numsynths = 1;
+               tmpsysinfo.nummidis = -1;
+               tmpsysinfo.numtimers = -1;
+               tmpsysinfo.nummixers = 1;
+               tmpsysinfo.numcards = 1;
+               memset(tmpsysinfo.openedmidi, 0, 8);
+               *(struct oss_sysinfo *)argp = tmpsysinfo;
+               break;
+       case SNDCTL_ENGINEINFO:
+       case SNDCTL_AUDIOINFO:
+               devno = 0;
+               tmpaudioinfo = (struct oss_audioinfo*)argp;
+               if (tmpaudioinfo == NULL)
+                       return EINVAL;
+               if (tmpaudioinfo->dev < 0) {
+                       fstat(fd, &tmpstat);
+                       if ((tmpstat.st_rdev & 0xff00) == 0x2a00)
+                               devno = tmpstat.st_rdev & 0xff;
+                       if (devno >= 0x80)
+                               tmpaudioinfo->dev = devno & 0x7f;
+               }
+               if (tmpaudioinfo->dev < 0)
+                       tmpaudioinfo->dev = 0;
+
+               snprintf(tmpaudioinfo->devnode, OSS_DEVNODE_SIZE,
+                   "/dev/audio%d", tmpaudioinfo->dev); 
+
+               snprintf(audiodevpath, 255, "%s", tmpaudioinfo->devnode);
+               audiofd = _oss_open(&audiodevpath[0], O_WRONLY);
+
+               retval = ioctl(audiofd, AUDIO_GETDEV, &tmpaudiodev);
+               if (retval < 0)
+                       return retval;
+               retval = ioctl(audiofd, AUDIO_GETINFO, &tmpinfo);
+               if (retval < 0)
+                       return retval;
+               retval = ioctl(audiofd, AUDIO_GETPROPS, &idata);
+               if (retval < 0)
+                       return retval;
+               idat = DSP_CAP_TRIGGER; /* pretend we have trigger */
+               if (idata & AUDIO_PROP_FULLDUPLEX)
+                       idat |= DSP_CAP_DUPLEX;
+               if (idata & AUDIO_PROP_MMAP)
+                       idat |= DSP_CAP_MMAP;
+               idat = PCM_CAP_INPUT | PCM_CAP_OUTPUT;
+               strncpy(tmpaudioinfo->name, tmpaudiodev.name, 64);
+               tmpaudioinfo->name[63] = 0;
+               tmpaudioinfo->busy = tmpinfo.play.open;
+               tmpaudioinfo->pid = -1;
+               tmpaudioinfo->caps = idat;
+               ioctl(audiofd, SNDCTL_DSP_GETFMTS, &tmpaudioinfo->iformats);
+               tmpaudioinfo->oformats = tmpaudioinfo->iformats;
+               tmpaudioinfo->magic = -1;
+               memset(tmpaudioinfo->cmd, 0, 64);
+               tmpaudioinfo->card_number = -1;
+               memset(tmpaudioinfo->song_name, 0, 64);
+               memset(tmpaudioinfo->label, 0, 16);
+               tmpaudioinfo->port_number = tmpinfo.play.port;
+               tmpaudioinfo->mixer_dev = tmpaudioinfo->dev;
+               tmpaudioinfo->legacy_device = -1;
+               tmpaudioinfo->enabled = 1;
+               tmpaudioinfo->flags = -1;
+               tmpaudioinfo->min_rate = tmpinfo.play.sample_rate;
+               tmpaudioinfo->max_rate = tmpinfo.play.sample_rate;
+               tmpaudioinfo->nrates = 2;
+               for (i = 0; i < tmpaudioinfo->nrates; i++)
+                       tmpaudioinfo->rates[i] = tmpinfo.play.sample_rate;
+               tmpaudioinfo->min_channels = tmpinfo.play.channels;
+               tmpaudioinfo->max_channels = tmpinfo.play.channels;
+               tmpaudioinfo->binding = -1;
+               tmpaudioinfo->rate_source = -1;
+               memset(tmpaudioinfo->handle, 0, 16);
+               tmpaudioinfo->next_play_engine = 0;
+               tmpaudioinfo->next_rec_engine = 0;
+               argp = tmpaudioinfo;
+               _oss_close(audiofd);
+               break;
+       case SNDCTL_DSP_GETPLAYVOL:
+               retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
+               if (retval < 0)
+                       return retval;
+               *(uint *)argp = tmpinfo.play.gain;
+               break;
+       case SNDCTL_DSP_SETPLAYVOL:
+               retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
+               if (retval < 0)
+                       return retval;
+               if (*(uint *)argp > 255)
+                       tmpinfo.play.gain = 255;
+               else
+                       tmpinfo.play.gain = *(uint *)argp;
+               retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
+               if (retval < 0)
+                       return retval;
+               break;
+       case SNDCTL_DSP_GETRECVOL:
+               retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
+               if (retval < 0)
+                       return retval;
+               *(uint *)argp = tmpinfo.record.gain;
+               break;
+       case SNDCTL_DSP_SETRECVOL:
+               retval = ioctl(fd, AUDIO_GETBUFINFO, &tmpinfo);
+               if (retval < 0)
+                       return retval;
+               if (*(uint *)argp > 255)
+                       tmpinfo.record.gain = 255;
+               else
+                       tmpinfo.record.gain = *(uint *)argp;
+               retval = ioctl(fd, AUDIO_SETINFO, &tmpinfo);
+               if (retval < 0)
+                       return retval;
+               break;
+       case SNDCTL_DSP_SKIP:
+               return EINVAL;
        case SNDCTL_DSP_SETDUPLEX:
                idat = 1;
                retval = ioctl(fd, AUDIO_SETFD, &idat);


Note: These patches are  mostly my own work.  The structures and ioctl 
definitions are from freebsd's soundcard.h as well as the OSS v4 api 
documentation.  The implementation of the ioctls is my own work which I submit 
under the NetBSD license.

BUGS/TODO: The ioctl numbers for the ones I have implemented are probably not 
compatible with linux or oss v4 in general (I didn't look at ossv4 code from 
the ossv4 people due to concerns about their license).  Also additional ioctls 
are missing.

However having said that these changes allow one to compile and run wine devel 
and later versions with sound support.

Regards,

Nat.



Home | Main Index | Thread Index | Old Index