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