summaryrefslogtreecommitdiffstats
path: root/sys/oss/gstosshelper.c
diff options
context:
space:
mode:
authorThomas Vander Stichele <thomas@apestaart.org>2001-12-17 19:03:13 +0000
committerThomas Vander Stichele <thomas@apestaart.org>2001-12-17 19:03:13 +0000
commitf0bb7eef82576f581bdd205f2c9eb4278223fcc7 (patch)
tree530e9dea1ad3117141c1682318e74811d1fcb86a /sys/oss/gstosshelper.c
parent754313ab71cd4cb046191b3459842a063fd3642b (diff)
first batch
Original commit message from CVS: first batch
Diffstat (limited to 'sys/oss/gstosshelper.c')
-rw-r--r--sys/oss/gstosshelper.c401
1 files changed, 401 insertions, 0 deletions
diff --git a/sys/oss/gstosshelper.c b/sys/oss/gstosshelper.c
new file mode 100644
index 00000000..a47840a5
--- /dev/null
+++ b/sys/oss/gstosshelper.c
@@ -0,0 +1,401 @@
+/* Evil evil evil hack to get OSS apps to cooperate with esd
+ * Copyright (C) 1998, 1999 Manish Singh <yosh@gimp.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+//#define DSP_DEBUG
+
+/* This lets you run multiple instances of x11amp by setting the X11AMPNUM
+ environment variable. Only works on glibc2.
+ */
+/* #define MULTIPLE_X11AMP */
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+
+#ifdef DSP_DEBUG
+#define DPRINTF(format, args...) printf(format, ## args)
+#else
+#define DPRINTF(format, args...)
+#endif
+
+
+#include "config.h"
+
+#include <dlfcn.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+
+#include <errno.h>
+
+#ifdef HAVE_MACHINE_SOUNDCARD_H
+# include <machine/soundcard.h>
+#else
+# ifdef HAVE_SOUNDCARD_H
+# include <soundcard.h>
+# else
+# include <sys/soundcard.h>
+# endif
+#endif
+
+#include "gstosshelper.h"
+
+/* BSDI has this functionality, but not define :() */
+#if defined(RTLD_NEXT)
+#define REAL_LIBC RTLD_NEXT
+#else
+#define REAL_LIBC ((void *) -1L)
+#endif
+
+#if defined(__FreeBSD__) || defined(__bsdi__)
+typedef unsigned long request_t;
+#else
+typedef int request_t;
+#endif
+
+static int sndfd = -1;
+static int new_format = 1;
+static int fmt = AFMT_S16_LE;
+static int speed = 44100;
+static int stereo = 1;
+
+int
+open (const char *pathname, int flags, ...)
+{
+ static int (*func) (const char *, int, mode_t) = NULL;
+ va_list args;
+ mode_t mode;
+
+ if (!func)
+ func = (int (*) (const char *, int, mode_t)) dlsym (REAL_LIBC, "open");
+
+ va_start (args, flags);
+ mode = va_arg (args, mode_t);
+ va_end (args);
+
+ if (!strcmp (pathname, "/dev/dsp")) {
+ DPRINTF ("hijacking /dev/dsp open, and taking it to GStreamer...\n");
+ return (sndfd = HELPER_MAGIC_SNDFD);
+ }
+ return (sndfd = (*func) (pathname, flags, mode));
+}
+
+static int
+dspctl (int fd, request_t request, void *argp)
+{
+ int *arg = (int *) argp;
+
+ DPRINTF ("hijacking /dev/dsp ioctl, and sending it to GStreamer "
+ "(%d : %x - %p)\n", fd, request, argp);
+
+ switch (request)
+ {
+ case SNDCTL_DSP_RESET:
+ case SNDCTL_DSP_POST:
+ break;
+
+ case SNDCTL_DSP_SETFMT:
+ fmt = *arg;
+ new_format = 1;
+ break;
+
+ case SNDCTL_DSP_SPEED:
+ speed = *arg;
+ new_format = 1;
+ break;
+
+ case SNDCTL_DSP_STEREO:
+ stereo = *arg;
+ new_format = 1;
+ break;
+
+ case SNDCTL_DSP_GETBLKSIZE:
+ *arg = 4096;
+ break;
+
+ case SNDCTL_DSP_GETFMTS:
+ *arg = 0x38;
+ break;
+
+#ifdef SNDCTL_DSP_GETCAPS
+ case SNDCTL_DSP_GETCAPS:
+ *arg = 0;
+ break;
+#endif
+
+ case SNDCTL_DSP_GETOSPACE:
+ {
+ audio_buf_info *bufinfo = (audio_buf_info *) argp;
+ bufinfo->bytes = 4096;
+ }
+ break;
+
+
+ default:
+ DPRINTF ("unhandled /dev/dsp ioctl (%x - %p)\n", request, argp);
+ break;
+ }
+
+ return 0;
+}
+
+void *
+mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset)
+{
+ static void * (*func) (void *, size_t, int, int, int, off_t) = NULL;
+
+ if (!func)
+ func = (void * (*) (void *, size_t, int, int, int, off_t)) dlsym (REAL_LIBC, "mmap");
+
+ if ((fd == sndfd) && (sndfd != -1))
+ {
+ DPRINTF("MMAP: oops... we're in trouble here. /dev/dsp mmap()ed. Not supported yet.\n");
+ errno = EACCES;
+ return (void *)-1; /* Better causing an error than silently not working, in this case */
+ }
+
+ return (*func) (start, length, prot, flags, fd, offset);
+}
+
+ssize_t
+write (int fd, const void *buf, size_t len)
+{
+ static int (*func) (int, const void *, size_t) = NULL;
+ command cmd;
+
+ if (!func)
+ func = (int (*) (int, const void *, size_t)) dlsym (REAL_LIBC, "write");
+
+ if ((fd != sndfd) || (sndfd == -1))
+ {
+ return (*func) (fd, buf, len);
+ }
+
+ DPRINTF("WRITE: called for %d bytes\n", len);
+
+ if (new_format) {
+ new_format = 0;
+
+ cmd.id = CMD_FORMAT;
+ cmd.cmd.format.format = fmt;
+ cmd.cmd.format.stereo = stereo;
+ cmd.cmd.format.rate = speed;
+
+ (*func) (HELPER_MAGIC_OUT, &cmd, sizeof(command));
+ }
+ cmd.id = CMD_DATA;
+ cmd.cmd.length = len;
+
+ (*func) (HELPER_MAGIC_OUT, &cmd, sizeof(command));
+ (*func) (HELPER_MAGIC_OUT, buf, len);
+
+ //return (*func) (fd, buf, len);
+
+ return len;
+}
+
+int
+select (int n, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, struct timeval *timeout)
+{
+ static int (*func) (int, fd_set *, fd_set *, fd_set *, struct timeval *) = NULL;
+
+ if (!func)
+ func = (int (*) (int, fd_set *, fd_set *, fd_set *, struct timeval *)) dlsym (REAL_LIBC, "select");
+
+ if (n == sndfd) {
+ DPRINTF ("audiooss: hijacking /dev/dsp select() [output]\n");
+ }
+
+ return (*func) (n, readfds, writefds, exceptfds, timeout);
+}
+
+int
+dup2 (int oldfd, int newfd)
+{
+ static int (*func) (int, int) = NULL;
+
+ if (!func)
+ func = (int (*) (int, int)) dlsym (REAL_LIBC, "dup2");
+
+ if ((oldfd == sndfd) && (oldfd != -1) && (newfd != -1))
+ {
+ DPRINTF("dup2(%d,%d) (oldfd == sndfd) called\n", oldfd, newfd);
+
+ /* Do not close(newfd) as that would mark it available for reuse by the system -
+ * just tell the program that yes, we got the fd you asked for. Hackish. */
+ sndfd = newfd;
+ return newfd;
+ }
+ return (*func) (oldfd, newfd);
+}
+
+int
+ioctl (int fd, request_t request, ...)
+{
+ static int (*func) (int, request_t, void *) = NULL;
+ va_list args;
+ void *argp;
+
+ if (!func)
+ func = (int (*) (int, request_t, void *)) dlsym (REAL_LIBC, "ioctl");
+
+ va_start (args, request);
+ argp = va_arg (args, void *);
+ va_end (args);
+
+ if (fd == sndfd)
+ return dspctl (fd, request, argp);
+
+ return (*func) (fd, request, argp);
+}
+
+int
+fcntl(int fd, int cmd, ...)
+{
+ static int (*func) (int, int, void *) = NULL;
+ va_list args;
+ void *argp;
+
+ if (!func)
+ func = (int (*) (int, int, void *)) dlsym (REAL_LIBC, "fcntl");
+
+ va_start (args, cmd);
+ argp = va_arg (args, void *);
+ va_end (args);
+
+ if ((fd != -1) && (fd == sndfd))
+ {
+ DPRINTF ("hijacking /dev/dsp fcntl() "
+ "(%d : %x - %p)\n", fd, cmd, argp);
+ if (cmd == F_GETFL) return O_RDWR;
+ if (cmd == F_GETFD) return sndfd;
+ return 0;
+ }
+ else
+ {
+ return (*func) (fd, cmd, argp);
+ }
+ return 0;
+}
+
+int
+close (int fd)
+{
+ static int (*func) (int) = NULL;
+
+ if (!func)
+ func = (int (*) (int)) dlsym (REAL_LIBC, "close");
+
+ if (fd == sndfd)
+ sndfd = -1;
+
+ return (*func) (fd);
+}
+
+#ifdef MULTIPLE_X11AMP
+
+#include <socketbits.h>
+#include <sys/param.h>
+#include <sys/un.h>
+
+#define ENVSET "X11AMPNUM"
+
+int
+unlink (const char *filename)
+{
+ static int (*func) (const char *) = NULL;
+ char *num;
+
+ if (!func)
+ func = (int (*) (const char *)) dlsym (REAL_LIBC, "unlink");
+
+ if (!strcmp (filename, "/tmp/X11Amp_CTRL") && (num = getenv (ENVSET)))
+ {
+ char buf[PATH_MAX] = "/tmp/X11Amp_CTRL";
+ strcat (buf, num);
+ return (*func) (buf);
+ }
+ else
+ return (*func) (filename);
+}
+
+typedef int (*sa_func_t) (int, struct sockaddr *, int);
+
+static int
+sockaddr_mangle (sa_func_t func, int fd, struct sockaddr *addr, int len)
+{
+ char *num;
+
+ if (!strcmp (((struct sockaddr_un *) addr)->sun_path, "/tmp/X11Amp_CTRL")
+ && (num = getenv(ENVSET)))
+ {
+ int ret;
+ char buf[PATH_MAX] = "/tmp/X11Amp_CTRL";
+
+ struct sockaddr_un *new_addr = malloc (len);
+
+ strcat (buf, num);
+ memcpy (new_addr, addr, len);
+ strcpy (new_addr->sun_path, buf);
+
+ ret = (*func) (fd, (struct sockaddr *) new_addr, len);
+
+ free (new_addr);
+ return ret;
+ }
+ else
+ return (*func) (fd, addr, len);
+}
+
+int
+bind (int fd, struct sockaddr *addr, int len)
+{
+ static sa_func_t func = NULL;
+
+ if (!func)
+ func = (sa_func_t) dlsym (REAL_LIBC, "bind");
+ return sockaddr_mangle (func, fd, addr, len);
+}
+
+int
+connect (int fd, struct sockaddr *addr, int len)
+{
+ static sa_func_t func = NULL;
+
+ if (!func)
+ func = (sa_func_t) dlsym (REAL_LIBC, "connect");
+ return sockaddr_mangle (func, fd, addr, len);
+}
+
+#endif /* MULTIPLE_X11AMP */
+
+#else /* __GNUC__ */
+static char *ident = NULL;
+
+void
+nogcc (void)
+{
+ ident = NULL;
+}
+
+#endif /* __GNUC__ */