[BACK]Return to aucat.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / aucat

Diff for /src/usr.bin/aucat/aucat.c between version 1.60 and 1.61

version 1.60, 2009/04/27 18:09:34 version 1.61, 2009/07/25 08:44:27
Line 14 
Line 14 
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */   */
 /*  
  * TODO:  
  *  
  *      (hard) use parsable encoding names instead of the lookup  
  *      table. For instance, [s|u]bits[le|be][/bytes{msb|lsb}], example  
  *      s8, s16le, s24le/3msb. This would give names that correspond to  
  *      what use most linux-centric apps, but for which we have an  
  *      algorithm to convert the name to a aparams structure.  
  *  
  *      (easy) uses {chmin-chmax} instead of chmin:chmax notation for  
  *      channels specification to match the notation used in rmix.  
  *  
  *      (easy) use comma-separated parameters syntax, example:  
  *      s24le/3msb,{3-6},48000 so we don't have to use three -e, -r, -c  
  *      flags, but only one -p flag that specify one or more parameters.  
  *  
  *      (hard) if all inputs are over, the mixer terminates and closes  
  *      the write end of the device. It should continue writing zeros  
  *      until the recording is over (or be able to stop write end of  
  *      the device)  
  *  
  *      (hard) implement -n flag (no device) to connect all inputs to  
  *      the outputs.  
  *  
  *      (hard) ignore input files that are not audible (because channels  
  *      they provide are not used on the output). Similarly ignore  
  *      outputs that are zero filled (because channels they consume are  
  *      not provided).  
  */  
   
 #include <sys/param.h>  #include <sys/param.h>
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/queue.h>  #include <sys/queue.h>
Line 67 
Line 37 
 #include "wav.h"  #include "wav.h"
 #include "listen.h"  #include "listen.h"
 #include "dev.h"  #include "dev.h"
   #include "midi.h"
   #include "opt.h"
   #include "miofile.h"
   
 #define MODE_PLAY       1  #define MODE_PLAY       1
 #define MODE_REC        2  #define MODE_REC        2
   
   #define PROG_AUCAT      "aucat"
   #define PROG_MIDICAT    "midicat"
   
 int debug_level = 0;  int debug_level = 0;
 volatile int quit_flag = 0;  volatile int quit_flag = 0;
   
Line 108 
Line 84 
 }  }
   
 void  void
 usage(void)  set_debug_level(char *envname)
 {  {
         extern char *__progname;          char *dbgenv;
           const char *errstr;
   
         fprintf(stderr,          dbgenv = getenv(envname);
             "usage: %s [-lnu] [-b nframes] [-C min:max] [-c min:max] [-e enc] "          if (dbgenv) {
             "[-f device]\n"                  debug_level = strtonum(dbgenv, 0, 4, &errstr);
             "\t[-h fmt] [-i file] [-m mode] [-o file] [-r rate] [-s socket]\n"                  if (errstr)
             "\t[-v volume] [-x policy]\n",                          errx(1, "%s is %s: %s", envname, errstr, dbgenv);
             __progname);          }
 }  }
   
 void  void
Line 321 
Line 298 
         dev_attach(fa->name, NULL, NULL, 0, buf, &fa->opar, fa->xrun, 0);          dev_attach(fa->name, NULL, NULL, 0, buf, &fa->opar, fa->xrun, 0);
 }  }
   
   void
   setsig(void)
   {
           struct sigaction sa;
   
           quit_flag = 0;
           sigfillset(&sa.sa_mask);
           sa.sa_flags = SA_RESTART;
           sa.sa_handler = sigint;
           if (sigaction(SIGINT, &sa, NULL) < 0)
                   DPRINTF("sigaction(int) failed\n");
           if (sigaction(SIGTERM, &sa, NULL) < 0)
                   DPRINTF("sigaction(term) failed\n");
           if (sigaction(SIGHUP, &sa, NULL) < 0)
                   DPRINTF("sigaction(hup) failed\n");
   #ifdef DEBUG
           sa.sa_handler = sigusr1;
           if (sigaction(SIGUSR1, &sa, NULL) < 0)
                   DPRINTF("sigaction(usr1) failed\n");
           sa.sa_handler = sigusr2;
           if (sigaction(SIGUSR2, &sa, NULL) < 0)
                   DPRINTF("sigaction(usr2) failed1n");
   #endif
   }
   
   void
   unsetsig(void)
   {
           struct sigaction sa;
   
           sigfillset(&sa.sa_mask);
           sa.sa_flags = SA_RESTART;
           sa.sa_handler = SIG_DFL;
   #ifdef DEBUG
           if (sigaction(SIGUSR2, &sa, NULL) < 0)
                   DPRINTF("unsetsig(usr2): sigaction failed\n");
           if (sigaction(SIGUSR1, &sa, NULL) < 0)
                   DPRINTF("unsetsig(usr1): sigaction failed\n");
   #endif
           if (sigaction(SIGHUP, &sa, NULL) < 0)
                   DPRINTF("unsetsig(hup): sigaction failed\n");
           if (sigaction(SIGTERM, &sa, NULL) < 0)
                   DPRINTF("unsetsig(term): sigaction failed\n");
           if (sigaction(SIGINT, &sa, NULL) < 0)
                   DPRINTF("unsetsig(int): sigaction failed\n");
   }
   
   void
   getbasepath(char *base, size_t size)
   {
           uid_t uid;
           struct stat sb;
   
           uid = geteuid();
           snprintf(base, PATH_MAX, "/tmp/aucat-%u", uid);
           if (mkdir(base, 0700) < 0) {
                   if (errno != EEXIST)
                           err(1, "mkdir(\"%s\")", base);
           }
           if (stat(base, &sb) < 0)
                   err(1, "stat(\"%s\")", base);
           if (sb.st_uid != uid || (sb.st_mode & 077) != 0)
                   errx(1, "%s has wrong permissions", base);
   }
   
   void
   aucat_usage(void)
   {
           (void)fputs("usage: " PROG_AUCAT " [-lnu] [-b nframes] "
               "[-C min:max] [-c min:max] [-e enc] [-f device]\n"
               "\t[-h fmt] [-i file] [-m mode] [-o file] [-r rate] [-s socket]\n"
               "\t[-U unit] [-v volume] [-x policy]\n",
               stderr);
   }
   
 int  int
 main(int argc, char **argv)  aucat_main(int argc, char **argv)
 {  {
         int c, u_flag, l_flag, n_flag, hdr, xrun, suspend = 0;          int c, u_flag, l_flag, n_flag, hdr, xrun, suspend = 0, unit;
         struct farg *fa;          struct farg *fa;
         struct farglist  ifiles, ofiles, sfiles;          struct farglist  ifiles, ofiles, sfiles;
         struct aparams ipar, opar, dipar, dopar;          struct aparams ipar, opar, dipar, dopar;
         struct sigaction sa;  
         struct stat sb;  
         char base[PATH_MAX], path[PATH_MAX];          char base[PATH_MAX], path[PATH_MAX];
         unsigned bufsz, mode;          unsigned bufsz, mode;
         char *devpath, *dbgenv;          char *devpath;
         const char *errstr;  
         unsigned volctl;          unsigned volctl;
         uid_t uid;  
   
         dbgenv = getenv("AUCAT_DEBUG");  
         if (dbgenv) {  
                 debug_level = strtonum(dbgenv, 0, 4, &errstr);  
                 if (errstr)  
                         errx(1, "AUCAT_DEBUG is %s: %s", errstr, dbgenv);  
         }  
   
         aparams_init(&ipar, 0, 1, 44100);          aparams_init(&ipar, 0, 1, 44100);
         aparams_init(&opar, 0, 1, 44100);          aparams_init(&opar, 0, 1, 44100);
         u_flag = 0;          u_flag = 0;
         l_flag = 0;          l_flag = 0;
         n_flag = 0;          n_flag = 0;
           unit = -1;
         devpath = NULL;          devpath = NULL;
         SLIST_INIT(&ifiles);          SLIST_INIT(&ifiles);
         SLIST_INIT(&ofiles);          SLIST_INIT(&ofiles);
Line 359 
Line 401 
         bufsz = 44100 * 4 / 15; /* XXX: use milliseconds, not frames */          bufsz = 44100 * 4 / 15; /* XXX: use milliseconds, not frames */
         mode = 0;          mode = 0;
   
         while ((c = getopt(argc, argv, "nb:c:C:e:r:h:x:v:i:o:f:m:lus:")) != -1) {          while ((c = getopt(argc, argv, "nb:c:C:e:r:h:x:v:i:o:f:m:lus:U:")) != -1) {
                 switch (c) {                  switch (c) {
                 case 'n':                  case 'n':
                         n_flag = 1;                          n_flag = 1;
Line 421 
Line 463 
                                 exit(1);                                  exit(1);
                         }                          }
                         break;                          break;
                   case 'U':
                           if (sscanf(optarg, "%u", &unit) != 1) {
                                   fprintf(stderr, "%s: bad device number\n", optarg);
                                   exit(1);
                           }
                           break;
                 default:                  default:
                         usage();                          aucat_usage();
                         exit(1);                          exit(1);
                 }                  }
         }          }
Line 433 
Line 481 
                 dopar = ipar;                  dopar = ipar;
                 dipar = opar;                  dipar = opar;
         }          }
   
         if (!l_flag && SLIST_EMPTY(&ifiles) &&          if (!l_flag && SLIST_EMPTY(&ifiles) &&
             SLIST_EMPTY(&ofiles) && argc > 0) {              SLIST_EMPTY(&ofiles) && argc > 0) {
                 /*                  /*
Line 447 
Line 494 
                         }                          }
                 exit(0);                  exit(0);
         } else if (argc > 0) {          } else if (argc > 0) {
                 usage();                  aucat_usage();
                 exit(1);                  exit(1);
         }          }
   
         if (!l_flag && !SLIST_EMPTY(&sfiles))          if (!l_flag && (!SLIST_EMPTY(&sfiles) || unit >= 0))
                 errx(1, "can't use -s without -l");                  errx(1, "can't use -s or -U without -l");
         if ((l_flag || mode != 0) &&          if ((l_flag || mode != 0) &&
             (!SLIST_EMPTY(&ofiles) || !SLIST_EMPTY(&ifiles)))              (!SLIST_EMPTY(&ofiles) || !SLIST_EMPTY(&ifiles)))
                 errx(1, "can't use -l, -m and -s with -o or -i");                  errx(1, "can't use -l, -m and -s with -o or -i");
Line 461 
Line 508 
                         mode |= MODE_PLAY;                          mode |= MODE_PLAY;
                 if (l_flag || !SLIST_EMPTY(&ofiles))                  if (l_flag || !SLIST_EMPTY(&ofiles))
                         mode |= MODE_REC;                          mode |= MODE_REC;
                 if (!mode)                  if (!mode) {
                         errx(1, "nothing to play or record");                          aucat_usage();
                           exit(1);
                   }
         }          }
         if (n_flag) {          if (n_flag) {
                 if (devpath != NULL || l_flag)                  if (devpath != NULL || l_flag)
Line 476 
Line 525 
          */           */
         if (l_flag && SLIST_EMPTY(&sfiles)) {          if (l_flag && SLIST_EMPTY(&sfiles)) {
                 farg_add(&sfiles, &dopar, &dipar,                  farg_add(&sfiles, &dopar, &dipar,
                     volctl, HDR_RAW, XRUN_IGNORE, DEFAULT_SOCKET);                      volctl, HDR_RAW, XRUN_IGNORE, DEFAULT_OPT);
         }          }
   
         if (!u_flag) {          if (!u_flag) {
Line 500 
Line 549 
         }          }
   
         if (l_flag) {          if (l_flag) {
                 uid = geteuid();                  getbasepath(base, sizeof(base));
                 snprintf(base, PATH_MAX, "/tmp/aucat-%u", uid);                  if (unit < 0)
                 if (mkdir(base, 0700) < 0) {                          unit = 0;
                         if (errno != EEXIST)  
                                 err(1, "mkdir(\"%s\")", base);  
                 }  
                 if (stat(base, &sb) < 0)  
                         err(1, "stat(\"%s\")", base);  
                 if (sb.st_uid != uid || (sb.st_mode & 077) != 0)  
                         errx(1, "%s has wrong permissions", base);  
         }          }
         quit_flag = 0;          setsig();
         sigfillset(&sa.sa_mask);  
         sa.sa_flags = SA_RESTART;  
         sa.sa_handler = sigint;  
         if (sigaction(SIGINT, &sa, NULL) < 0)  
                 DPRINTF("sigaction(int) failed\n");  
         if (sigaction(SIGTERM, &sa, NULL) < 0)  
                 DPRINTF("sigaction(term) failed\n");  
         if (sigaction(SIGHUP, &sa, NULL) < 0)  
                 DPRINTF("sigaction(hup) failed\n");  
 #ifdef DEBUG  
         sa.sa_handler = sigusr1;  
         if (sigaction(SIGUSR1, &sa, NULL) < 0)  
                 DPRINTF("sigaction(usr1) failed\n");  
         sa.sa_handler = sigusr2;  
         if (sigaction(SIGUSR2, &sa, NULL) < 0)  
                 DPRINTF("sigaction(usr2) failed1n");  
 #endif  
         filelist_init();          filelist_init();
   
         /*          /*
Line 565 
Line 590 
         while (!SLIST_EMPTY(&sfiles)) {          while (!SLIST_EMPTY(&sfiles)) {
                 fa = SLIST_FIRST(&sfiles);                  fa = SLIST_FIRST(&sfiles);
                 SLIST_REMOVE_HEAD(&sfiles, entry);                  SLIST_REMOVE_HEAD(&sfiles, entry);
                 if (strchr(fa->name, '/') != NULL)                  opt_new(fa->name, &fa->opar, &fa->ipar, MIDI_TO_ADATA(fa->vol));
                         errx(1, "socket names must not contain '/'");  
                 snprintf(path, PATH_MAX, "%s/%s", base, fa->name);  
                 listen_new(&listen_ops, path, &fa->opar, &fa->ipar,  
                     MIDI_TO_ADATA(fa->vol));  
                 free(fa);                  free(fa);
         }          }
         if (l_flag && debug_level == 0) {          if (l_flag) {
                 if (daemon(0, 0) < 0)                  snprintf(path, sizeof(path), "%s/%s%u", base,
                       DEFAULT_SOFTAUDIO, unit);
                   listen_new(&listen_ops, path);
                   if (debug_level == 0 && daemon(0, 0) < 0)
                         err(1, "daemon");                          err(1, "daemon");
         }          }
   
Line 626 
Line 650 
         } else          } else
                 dev_done();                  dev_done();
         filelist_done();          filelist_done();
           unsetsig();
           return 0;
   }
   
         sigfillset(&sa.sa_mask);  void
         sa.sa_flags = SA_RESTART;  midicat_usage(void)
         sa.sa_handler = SIG_DFL;  {
         if (sigaction(SIGINT, &sa, NULL) < 0)          (void)fputs("usage: " PROG_MIDICAT " [-l] [-f device] "
                 DPRINTF("dev_done: sigaction failed\n");              "[-i file] [-o file] [-U unit]\n",
               stderr);
   }
   int
   midicat_main(int argc, char **argv)
   {
           static struct aparams noparams = { 1, 0, 0, 0, 0, 0, 0, 0 };
           int c, l_flag, unit, fd;
           char base[PATH_MAX], path[PATH_MAX];
           char *input, *output, *devpath;
           struct file *dev, *stdx, *f;
           struct aproc *p, *send, *recv;
           struct abuf *buf;
   
           l_flag = 0;
           unit = -1;
           devpath = NULL;
           output = NULL;
           input = NULL;
   
           while ((c = getopt(argc, argv, "i:o:lf:U:")) != -1) {
                   switch (c) {
                   case 'i':
                           if (input != NULL)
                                   errx(1, "only one -i allowed");
                           input = optarg;
                           break;
                   case 'o':
                           if (output != NULL)
                                   errx(1, "only one -o allowed");
                           output = optarg;
                           break;
                   case 'f':
                           devpath = optarg;
                           break;
                   case 'l':
                           l_flag = 1;
                           break;
                   case 'U':
                           if (sscanf(optarg, "%u", &unit) != 1) {
                                   fprintf(stderr, "%s: bad device number\n", optarg);
                                   exit(1);
                           }
                           break;
                   default:
                           midicat_usage();
                           exit(1);
                   }
           }
           argc -= optind;
           argv += optind;
   
           if (argc > 0 || (!input && !output && !l_flag)) {
                   midicat_usage();
                   exit(1);
           }
           if (!l_flag && unit >= 0)
                   errx(1, "can't use -U without -l");
           if (l_flag) {
                   if (input || output)
                           errx(1, "can't use -i or -o with -l");
                   getbasepath(base, sizeof(path));
                   if (unit < 0)
                           unit = 0;
           }
           setsig();
           filelist_init();
   
           if (l_flag) {
                   thrubox = thru_new("thru");
                   thrubox->refs++;
                   snprintf(path, sizeof(path), "%s/%s%u", base,
                       DEFAULT_MIDITHRU, unit);
                   listen_new(&listen_ops, path);
                   if (debug_level == 0 && daemon(0, 0) < 0)
                           err(1, "daemon");
           }
           if (input || output) {
                   dev = (struct file *)miofile_new(&miofile_ops, devpath,
                        output ? 1 : 0, input ? 1 : 0);
                   if (dev == NULL)
                           errx(1, "%s: can't open device",
                               devpath ? devpath : "<default>");
           } else
                   dev = NULL;
           if (input) {
                   send = wpipe_new(dev);
                   send->refs++;
                   if (strcmp(input, "-") == 0) {
                           fd = STDIN_FILENO;
                           if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                                   warn("stdin");
                   } else {
                           fd = open(input, O_RDONLY | O_NONBLOCK, 0666);
                           if (fd < 0)
                                   err(1, "%s", input);
                   }
                   stdx = (struct file *)pipe_new(&pipe_ops, fd, "stdin");
                   p = rpipe_new(stdx);
                   buf = abuf_new(3125, &noparams);
                   aproc_setout(p, buf);
                   aproc_setin(send, buf);
           } else
                   send = NULL;
           if (output) {
                   recv = rpipe_new(dev);
                   recv->refs++;
                   if (strcmp(output, "-") == 0) {
                           fd = STDOUT_FILENO;
                           if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                                   warn("stdout");
                   } else {
                           fd = open(output,
                               O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666);
                           if (fd < 0)
                                   err(1, "%s", output);
                   }
                   stdx = (struct file *)pipe_new(&pipe_ops, fd, "stdout");
                   p = wpipe_new(stdx);
                   buf = abuf_new(3125, &noparams);
                   aproc_setin(p, buf);
                   aproc_setout(recv, buf);
           } else
                   recv = NULL;
   
           /*
            * loop, start processing
            */
           for (;;) {
                   if (quit_flag) {
                           break;
                   }
                   if (!file_poll())
                           break;
           }
           if (l_flag) {
                   filelist_unlisten();
                   if (rmdir(base) < 0)
                           warn("rmdir(\"%s\")", base);
           }
           if (thrubox) {
           restart_thrubox:
                   LIST_FOREACH(f, &file_list, entry) {
                           if (f->rproc && aproc_depend(thrubox, f->rproc)) {
                                   file_eof(f);
                                   goto restart_thrubox;
                           }
                   }
                   while (!LIST_EMPTY(&thrubox->ibuflist)) {
                           if (!file_poll())
                                   break;
                   }
                   thrubox->refs--;
                   aproc_del(thrubox);
                   thrubox = NULL;
                   while (file_poll())
                           ; /* nothing */
           }
           if (send) {
           restart_send:
                   LIST_FOREACH(f, &file_list, entry) {
                           if (f->rproc && aproc_depend(send, f->rproc)) {
                                   file_eof(f);
                                   goto restart_send;
                           }
                   }
                   while (!LIST_EMPTY(&send->ibuflist)) {
                           if (!file_poll())
                                   break;
                   }
                   send->refs--;
                   aproc_del(send);
                   send = NULL;
           }
           if (recv) {
                   if (recv->u.io.file)
                           file_eof(recv->u.io.file);
                   while (!LIST_EMPTY(&recv->obuflist)) {
                           if (!file_poll())
                                   break;
                   }
                   recv->refs--;
                   aproc_del(recv);
                   recv = NULL;
           }
           filelist_done();
           unsetsig();
         return 0;          return 0;
   }
   
   
   int
   main(int argc, char **argv)
   {
           char *prog;
   
           prog = strrchr(argv[0], '/');
           if (prog == NULL)
                   prog = argv[0];
           else
                   prog++;
           if (strcmp(prog, PROG_AUCAT) == 0) {
                   set_debug_level("AUCAT_DEBUG");
                   return aucat_main(argc, argv);
           } else if (strcmp(prog, PROG_MIDICAT) == 0) {
                   set_debug_level("MIDICAT_DEBUG");
                   return midicat_main(argc, argv);
           } else {
                   fprintf(stderr, "%s: can't determine program to run\n", prog);
           }
           return 1;
 }  }

Legend:
Removed from v.1.60  
changed lines
  Added in v.1.61