[Liboss-commit] CVS: liboss/lib liboss.c,1.6,1.7
Brought to you by:
thesin
|
From: Dave V. <va...@us...> - 2002-05-10 15:00:43
|
Update of /cvsroot/liboss/liboss/lib
In directory usw-pr-cvs1:/tmp/cvs-serv29774
Modified Files:
liboss.c
Log Message:
Added lots of stuff. Some sound may come soon!
Index: liboss.c
===================================================================
RCS file: /cvsroot/liboss/liboss/lib/liboss.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- liboss.c 10 May 2002 03:32:50 -0000 1.6
+++ liboss.c 10 May 2002 14:53:29 -0000 1.7
@@ -42,15 +42,19 @@
* With some preprocessor magic it could be the same file.
*/
-#include "../config.h"
+#include "config.h"
#include <sys/param.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+/* FIXME: The whole file will need CoreAudio, not just the #include */
#ifdef HAVE_COREAUDIO
# include <CoreAudio/CoreAudio.h>
#endif
@@ -62,20 +66,36 @@
#define TO_OSSVOL(x) (((x) * 100 + 127) / 255)
#define FROM_OSSVOL(x) ((((x) > 100 ? 100 : (x)) * 255 + 50) / 100)
+#define INTARG (*(int*)argp)
-static int audio_ioctl(int, unsigned long, void *);
-static int audio_open(int flags);
-static int mixer_ioctl(int, unsigned long, void *);
-
-/* Don't think we need this */
-#if 0
-static struct audiodevinfo *getdevinfo(int);
-static int opaque_to_enum(struct audiodevinfo *di, audio_mixer_name_t *label, int opq);
-static int enum_to_ord(struct audiodevinfo *di, int enm);
-static int enum_to_mask(struct audiodevinfo *di, int enm);
-#endif
+static int oss_audio_ioctl(int, unsigned long, void *);
+static int oss_audio_open(int flags);
+static int oss_init(void);
+static int oss_mixer_ioctl(int, unsigned long, void *);
+static void *oss_start_device(void *shared);
+
+#define BUF_SIZE 1024
+
+typedef enum rw_e {
+ OSS_READ = 1,
+ OSS_WRITE = 2,
+ OSS_RW = 3,
+} rw_e;
+
+typedef struct device_shared_t {
+ pthread_mutex_t client_mut;
+ pthread_mutex_t mut;
+ rw_e rw;
+ int iosock;
+ char rbuf[BUF_SIZE]; /* FIXME: use fragments */
+ char *rend;
+ pthread_cond_t full;
+} device_shared_t;
+
+static device_shared_t sh;
-#define INTARG (*(int*)argp)
+static int initialized = 0;
+static pthread_t server;
int
oss_open(const char *path, int flags, mode_t mode)
@@ -85,8 +105,8 @@
if (realpath(path, buf) == NULL)
return open(path, flags, mode);
- if (0 == strcmp("/dev/audio", buf)) {
- return audio_open(flags);
+ if (0 == strcmp("/dev/dspW", buf)) {
+ return oss_audio_open(flags);
} else {
/* FIXME: add mixer stuff */
return open(path, flags, mode);
@@ -97,22 +117,124 @@
oss_ioctl(int fd, unsigned long com, void *argp)
{
if (IOCGROUP(com) == 'P')
- return audio_ioctl(fd, com, argp);
+ return oss_audio_ioctl(fd, com, argp);
else if (IOCGROUP(com) == 'M')
- return mixer_ioctl(fd, com, argp);
+ return oss_mixer_ioctl(fd, com, argp);
else
return ioctl(fd, com, argp);
}
static int
-audio_open(int flags)
+oss_audio_open(int flags)
{
- /* FIXME: create sockets */
+ /* FIXME: Don't forget recording!
+ Set up format defaults.
+ setsockopt()
+ Close sockets (and alert Mac side) if they're open already.
+ Apparently you can't test if a socket is closed at the other end,
+ so we have to override close() too.
+ Account for multiple, different /dev/blahs (use a table).
+ Stop abusing clients.
+ */
+ int socks[2];
+ rw_e rw;
+
+ if (!initialized) {
+ if (oss_init() == -1)
+ return -1;
+ }
+
+ switch (flags & O_ACCMODE) {
+ case O_RDONLY: rw = OSS_WRITE; break; /* If they want to read, we must write */
+ case O_WRONLY: rw = OSS_READ; break;
+ case O_RDWR: rw = OSS_RW; break;
+ default:
+ return -1;
+ }
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == -1) {
+ fprintf(stderr, "Liboss: Sockets could not be created.\n");
+ return -1;
+ }
+
+ pthread_mutex_lock(&sh.client_mut);
+ pthread_mutex_lock(&sh.mut);
+ if (sh.iosock != -1) {
+ fprintf(stderr, "Liboss: Trying to reopen a device! Naughty client!\n");
+ pthread_mutex_unlock(&sh.mut);
+ pthread_mutex_unlock(&sh.client_mut);
+ close(socks[0]);
+ close(socks[1]);
+ return -1;
+ }
+ sh.iosock = socks[0];
+ sh.rw = rw;
+ pthread_mutex_unlock(&sh.mut);
+ pthread_mutex_unlock(&sh.client_mut);
+ pthread_create(&server, NULL, &oss_start_device, &sh);
+
+ return socks[1];
+}
+
+static int
+oss_init(void)
+{
+ int err = 0;
+
+ err |= pthread_mutex_init(&sh.client_mut, NULL);
+ err |= pthread_mutex_init(&sh.mut, NULL);
+ err |= pthread_cond_init(&sh.full, NULL);
+ if (err)
+ return -1;
+
+ sh.rend = sh.rbuf;
+ sh.iosock = -1;
+
+ initialized = 1;
return 0;
}
+static void*
+oss_start_device(void *shared) {
+ device_shared_t *msh = (device_shared_t*)shared;
+
+ while (1) {
+ int iosock;
+
+ pthread_mutex_lock(&msh->client_mut);
+ pthread_mutex_lock(&msh->mut); /* Do the whole read/write atomically */
+ if ((iosock = msh->iosock) == -1) {
+ pthread_mutex_unlock(&msh->mut); /* We've been closed */
+ pthread_mutex_unlock(&msh->client_mut);
+ return NULL;
+ } else {
+ if (msh->rw | OSS_READ) {
+ char *buf = msh->rbuf, *end = msh->rend;
+ int nbytes;
+ while (end - buf == BUF_SIZE) {
+ /* Still don't let the client through */
+ pthread_cond_wait(&msh->full, &msh->mut);
+ }
+ /* FIXME: what if a client's write doesn't write everything, as expected? */
+ nbytes = read(msh->iosock, end, BUF_SIZE - (end - buf));
+ end += nbytes;
+
+ printf("%d bytes read\n", nbytes);
+ end = buf;
+ }
+ if (msh->rw | OSS_WRITE) {
+ /* FIXME: Implement this */
+ }
+ }
+ pthread_mutex_unlock(&msh->mut);
+ pthread_mutex_unlock(&msh->client_mut);
+ }
+
+ return NULL;
+}
+
static int
-audio_ioctl(int fd, unsigned long com, void *argp)
+oss_audio_ioctl(int fd, unsigned long com, void *argp)
{
int retval = 0;
@@ -420,187 +542,8 @@
return 0;
}
-/* I don't think we need any of this stuff */
-#if 0
-
-/* If the NetBSD mixer device should have more than NETBSD_MAXDEVS devices
- * some will not be available to Linux */
-#define NETBSD_MAXDEVS 64
-struct audiodevinfo {
- int done;
- dev_t dev;
- int16_t devmap[SOUND_MIXER_NRDEVICES],
- rdevmap[NETBSD_MAXDEVS];
- char names[NETBSD_MAXDEVS][MAX_AUDIO_DEV_LEN];
- int enum2opaque[NETBSD_MAXDEVS];
- u_long devmask, recmask, stereomask;
- u_long caps, source;
-};
-
-static int
-opaque_to_enum(struct audiodevinfo *di, audio_mixer_name_t *label, int opq)
-{
- int i, o;
-
- for (i = 0; i < NETBSD_MAXDEVS; i++) {
- o = di->enum2opaque[i];
- if (o == opq)
- break;
- if (o == -1 && label != NULL &&
- !strncmp(di->names[i], label->name, sizeof di->names[i])) {
- di->enum2opaque[i] = opq;
- break;
- }
- }
- if (i >= NETBSD_MAXDEVS)
- i = -1;
- /*printf("opq_to_enum %s %d -> %d\n", label->name, opq, i);*/
- return (i);
-}
-
-static int
-enum_to_ord(struct audiodevinfo *di, int enm)
-{
- if (enm >= NETBSD_MAXDEVS)
- return (-1);
-
- /*printf("enum_to_ord %d -> %d\n", enm, di->enum2opaque[enm]);*/
- return (di->enum2opaque[enm]);
-}
-
-static int
-enum_to_mask(struct audiodevinfo *di, int enm)
-{
- int m;
- if (enm >= NETBSD_MAXDEVS)
- return (0);
-
- m = di->enum2opaque[enm];
- if (m == -1)
- m = 0;
- /*printf("enum_to_mask %d -> %d\n", enm, di->enum2opaque[enm]);*/
- return (m);
-}
-
-/*
- * Collect the audio device information to allow faster
- * emulation of the Linux mixer ioctls. Cache the information
- * to eliminate the overhead of repeating all the ioctls needed
- * to collect the information.
- */
-static struct audiodevinfo *
-getdevinfo(int fd)
-{
- mixer_devinfo_t mi;
- int i, j, e;
- static struct {
- char *name;
- int code;
- } *dp, devs[] = {
- { AudioNmicrophone, SOUND_MIXER_MIC },
- { AudioNline, SOUND_MIXER_LINE },
- { AudioNcd, SOUND_MIXER_CD },
- { AudioNdac, SOUND_MIXER_PCM },
- { AudioNrecord, SOUND_MIXER_IMIX },
- { AudioNmaster, SOUND_MIXER_VOLUME },
- { AudioNtreble, SOUND_MIXER_TREBLE },
- { AudioNbass, SOUND_MIXER_BASS },
- { AudioNspeaker, SOUND_MIXER_SPEAKER },
-/* { AudioNheadphone, ?? },*/
- { AudioNoutput, SOUND_MIXER_OGAIN },
- { AudioNinput, SOUND_MIXER_IGAIN },
-/* { AudioNmaster, SOUND_MIXER_SPEAKER },*/
-/* { AudioNstereo, ?? },*/
-/* { AudioNmono, ?? },*/
- { AudioNfmsynth, SOUND_MIXER_SYNTH },
-/* { AudioNwave, SOUND_MIXER_PCM },*/
- { AudioNmidi, SOUND_MIXER_SYNTH },
-/* { AudioNmixerout, ?? },*/
- { 0, -1 }
- };
- static struct audiodevinfo devcache = { 0 };
- struct audiodevinfo *di = &devcache;
- struct stat sb;
-
- /* Figure out what device it is so we can check if the
- * cached data is valid.
- */
- if (fstat(fd, &sb) < 0)
- return 0;
- if (di->done && di->dev == sb.st_dev)
- return di;
-
- di->done = 1;
- di->dev = sb.st_dev;
- di->devmask = 0;
- di->recmask = 0;
- di->stereomask = 0;
- di->source = ~0;
- di->caps = 0;
- for(i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- di->devmap[i] = -1;
- for(i = 0; i < NETBSD_MAXDEVS; i++) {
- di->rdevmap[i] = -1;
- di->names[i][0] = '\0';
- di->enum2opaque[i] = -1;
- }
- for(i = 0; i < NETBSD_MAXDEVS; i++) {
- mi.index = i;
- if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0)
- break;
- switch(mi.type) {
- case AUDIO_MIXER_VALUE:
- for(dp = devs; dp->name; dp++)
- if (strcmp(dp->name, mi.label.name) == 0)
- break;
- if (dp->code >= 0) {
- di->devmap[dp->code] = i;
- di->rdevmap[i] = dp->code;
- di->devmask |= 1 << dp->code;
- if (mi.un.v.num_channels == 2)
- di->stereomask |= 1 << dp->code;
- strncpy(di->names[i], mi.label.name,
- sizeof di->names[i]);
- }
- break;
- }
- }
- for(i = 0; i < NETBSD_MAXDEVS; i++) {
- mi.index = i;
- if (ioctl(fd, AUDIO_MIXER_DEVINFO, &mi) < 0)
- break;
- if (strcmp(mi.label.name, AudioNsource) != 0)
- continue;
- di->source = i;
- switch(mi.type) {
- case AUDIO_MIXER_ENUM:
- for(j = 0; j < mi.un.e.num_mem; j++) {
- e = opaque_to_enum(di,
- &mi.un.e.member[j].label,
- mi.un.e.member[j].ord);
- if (e >= 0)
- di->recmask |= 1 << di->rdevmap[e];
- }
- di->caps = SOUND_CAP_EXCL_INPUT;
- break;
- case AUDIO_MIXER_SET:
- for(j = 0; j < mi.un.s.num_mem; j++) {
- e = opaque_to_enum(di,
- &mi.un.s.member[j].label,
- mi.un.s.member[j].mask);
- if (e >= 0)
- di->recmask |= 1 << di->rdevmap[e];
- }
- break;
- }
- }
- return di;
-}
-
-#endif /* Probably not needed */
-
int
-mixer_ioctl(int fd, unsigned long com, void *argp)
+oss_mixer_ioctl(int fd, unsigned long com, void *argp)
{
/* FIXME: implement */
errno = EINVAL;
|