esddsp.c

来自「Windows NT声卡驱动VXD」· C语言 代码 · 共 488 行

C
488
字号
/* 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>#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 "esd.h"#define REAL_LIBC RTLD_NEXT#ifdef __FreeBSD__typedef unsigned long request_t;#elsetypedef int request_t;#endifstatic int sndfd = -1, mixfd = -1;static int settings = 0, done = 0;static char *ident = NULL, *mixer = NULL;static int use_mixer = 0;#define OSS_VOLUME_BASE 50#define ESD_VOL_TO_OSS(left, right) (short int)			\    (((OSS_VOLUME_BASE * (right) / ESD_VOLUME_BASE) << 8) |	\      (OSS_VOLUME_BASE * (left)  / ESD_VOLUME_BASE))#define OSS_VOL_TO_ESD_LEFT(vol) 				\    (ESD_VOLUME_BASE * (vol & 0xff) / OSS_VOLUME_BASE)#define OSS_VOL_TO_ESD_RIGHT(vol) 				\    (ESD_VOLUME_BASE * ((vol >> 8) & 0xff) / OSS_VOLUME_BASE)static voidget_volume (int *left, int *right){  int vol;  if (read (mixfd, &vol, sizeof (vol)) != sizeof (vol))    *left = *right = ESD_VOLUME_BASE;  else    {      *left  = OSS_VOL_TO_ESD_LEFT  (vol);      *right = OSS_VOL_TO_ESD_RIGHT (vol);    }}static voidset_volume (int left, int right){  int vol = ESD_VOL_TO_OSS (left, right);  write (mixfd, &vol, sizeof (vol));}static voiddsp_init (void){  if (!ident)    {      char *str = getenv ("ESDDSP_NAME");      ident = malloc (ESD_NAME_MAX);      strncpy (ident, (str ? str : "esddsp"), ESD_NAME_MAX);      if (getenv ("ESDDSP_MIXER"))	{	  use_mixer = 1;	  str = getenv ("HOME");	  if (str) 	    {	      mixer = malloc (strlen (str) + strlen (ident) + 10);	      sprintf (mixer, "%s/.esddsp_%s", str, ident);	    }	  else	    {	      fprintf (stderr, "esddsp: can't get home directory\n");	      exit (1);	    }	  DPRINTF ("mixer settings file: %s\n", mixer);	}    }}static voidmix_init (int *esd, int *player){  esd_info_t *all_info;  esd_player_info_t *player_info;  if (*esd < 0 && (*esd = esd_open_sound (NULL)) < 0)    return;      if (*player < 0)    {      if (all_info = esd_get_all_info (*esd))	{	  for (player_info = all_info->player_list; player_info;	       player_info = player_info->next)	    if (!strcmp(player_info->name, ident))	      {		*player = player_info->source_id;		break;	      }	  esd_free_all_info (all_info);	}    }}intopen (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");  dsp_init ();  va_start (args, flags);  mode = va_arg (args, mode_t);  va_end (args);  if (!strcmp (pathname, "/dev/dsp"))    {      if (!getenv ("ESPEAKER"))	{          int ret;	  flags |= O_NONBLOCK;	  if ((ret = (*func) (pathname, flags, mode)) >= 0)	    return ret;	}      DPRINTF ("hijacking /dev/dsp open, and taking it to esd...\n");      settings = done = 0;      return (sndfd = esd_open_sound (NULL));    }  else if (use_mixer && !strcmp (pathname, "/dev/mixer"))    {      DPRINTF ("hijacking /dev/mixer open, and taking it to esd...\n");      return (mixfd = (*func) (mixer, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR));    }  else    return (*func) (pathname, flags, mode);}static intdspctl (int fd, request_t request, void *argp){  static esd_format_t fmt = ESD_STREAM | ESD_PLAY | ESD_MONO;  static int speed;  int *arg = (int *) argp;  DPRINTF ("hijacking /dev/dsp ioctl, and sending it to esd "	   "(%d : %x - %p)\n", fd, request, argp);    switch (request)    {    case SNDCTL_DSP_SETFMT:      fmt |= (*arg & 0x30) ? ESD_BITS16 : ESD_BITS8;      settings |= 1;      break;    case SNDCTL_DSP_SPEED:      speed = *arg;      settings |= 2;      break;    case SNDCTL_DSP_STEREO:      fmt &= ~ESD_MONO;      fmt |= (*arg) ? ESD_STEREO : ESD_MONO;      break;    case SNDCTL_DSP_GETBLKSIZE:      *arg = ESD_BUF_SIZE;      break;    case SNDCTL_DSP_GETFMTS:      *arg = 0x38;      break;    case SNDCTL_DSP_GETCAPS:      *arg = 0;      break;    case SNDCTL_DSP_GETOSPACE:      {	audio_buf_info *bufinfo = (audio_buf_info *) argp;	bufinfo->bytes = 100000;      }      break;    default:      DPRINTF ("unhandled /dev/dsp ioctl (%x - %p)\n", request, argp);      break;    }  if (settings == 3 && !done)    {      int proto = ESD_PROTO_STREAM_PLAY;      done = 1;      if (write (sndfd, &proto, sizeof (proto)) != sizeof (proto))        return -1;      if (write (sndfd, &fmt, sizeof (fmt)) != sizeof (fmt))        return -1;      if (write (sndfd, &speed, sizeof (speed)) != sizeof (speed))        return -1;      if (write (sndfd, ident, ESD_NAME_MAX) != ESD_NAME_MAX)        return -1;      fmt = ESD_STREAM | ESD_PLAY | ESD_MONO;      speed = 0;      if (use_mixer)	{  	  int esd = -1, player = -1;	  int left, right;	  while (player < 0)	    mix_init (&esd, &player);	  get_volume (&left, &right);	  DPRINTF ("panning %d - %d %d\n", player, left, right);	  esd_set_stream_pan (esd, player, left, right);	}    }  return 0;}intmixctl (int fd, request_t request, void *argp){  static int esd = -1, player = -1;  static int left, right;  int *arg = (int *) argp;  DPRINTF ("hijacking /dev/mixer ioctl, and sending it to esd "	   "(%d : %x - %p)\n", fd, request, argp);  switch (request)    {    case SOUND_MIXER_READ_DEVMASK:      *arg = 5113;      break;    case SOUND_MIXER_READ_PCM:      mix_init (&esd, &player);      if (player > 0)	{	  esd_info_t *all_info;	  esd_player_info_t *player_info;	  if (all_info = esd_get_all_info (esd))	    {	      for (player_info = all_info->player_list; player_info;		   player_info = player_info->next)		if (player_info->source_id == player)		  {		    *arg = ESD_VOL_TO_OSS (player_info->left_vol_scale,					   player_info->right_vol_scale);		  }	      esd_free_all_info (all_info);	    }	  else	    return -1;	}      else	{          get_volume (&left, &right);	  *arg = ESD_VOL_TO_OSS (left, right);	}      break;    case SOUND_MIXER_WRITE_PCM:      mix_init (&esd, &player);      left  = OSS_VOL_TO_ESD_LEFT  (*arg);      right = OSS_VOL_TO_ESD_RIGHT (*arg);      set_volume (left, right);      if (player > 0)	{	  DPRINTF ("panning %d - %d %d\n", player, left, right);	  esd_set_stream_pan (esd, player, left, right);	}      break;    default:      DPRINTF ("unhandled /dev/mixer ioctl (%x - %p)\n", request, argp);      break;    }  return 0;}intioctl (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 && fd != mixfd)    return (*func) (fd, request, argp);  else if (fd == sndfd)    return dspctl (fd, request, argp);  else if (use_mixer)    return mixctl (fd, request, argp);}intclose (int fd){  static int (*func) (int) = NULL;  if (!func)    func = (int (*) (int)) dlsym (REAL_LIBC, "close");  if (fd == sndfd)    sndfd = -1;  else if (fd == mixfd)    mixfd = -1;   return (*func) (fd);}#ifdef MULTIPLE_X11AMP#include <socketbits.h>#include <sys/param.h>#include <sys/un.h>#define ENVSET "X11AMPNUM"intunlink (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 intsockaddr_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);}intbind (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);}intconnect (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__ */voidnogcc (void){  ident = NULL;}#endif /* __GNUC__ */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?