[xiph-commits] r18782 - trunk/postfish

xiphmont at svn.xiph.org xiphmont at svn.xiph.org
Tue Jan 22 02:29:03 PST 2013


Author: xiphmont
Date: 2013-01-22 02:29:03 -0800 (Tue, 22 Jan 2013)
New Revision: 18782

Modified:
   trunk/postfish/Makefile
   trunk/postfish/config.c
   trunk/postfish/main.c
   trunk/postfish/outpanel.c
   trunk/postfish/output.c
   trunk/postfish/output.h
   trunk/postfish/version.h
Log:
Add libao support to Postfish (requires libao 1.2, which is not yet released)
Does automatic device discovery for OSS, ALSA and Pulse



Modified: trunk/postfish/Makefile
===================================================================
--- trunk/postfish/Makefile	2013-01-22 10:26:45 UTC (rev 18781)
+++ trunk/postfish/Makefile	2013-01-22 10:29:03 UTC (rev 18782)
@@ -37,7 +37,7 @@
 	limit.o limitpanel.o mute.o mixpanel.o mix.o freeverb.o reverbpanel.o \
 	outpanel.o config.o window.o follower.o linkage.o
 
-GCF = -DETCDIR=\\\"$(ETCDIR)\\\" `pkg-config --cflags gtk+-2.0`
+GCF = -DETCDIR=\\\"$(ETCDIR)\\\" `pkg-config --cflags gtk+-2.0 ao \> 1.2`
 
 all:	
 	$(MAKE) target CFLAGS="-O2 -ffast-math -fomit-frame-pointer $(GCF) $(ADD_DEF)"
@@ -46,7 +46,7 @@
 	$(MAKE) target CFLAGS="-g -Wall -W -Wno-unused-parameter -D__NO_MATH_INLINES $(GCF) $(ADD_DEF)"
 
 profile:
-	$(MAKE) target CFLAGS="-pg -g -O2 -ffast-math $(GCF) $(ADD_DEF)" LIBS="-lgprof-helper "
+	$(MAKE) target CFLAGS="-pg -g -O2 -ffast-math $(GCF) $(ADD_DEF)" 
 
 clean:
 	rm -f $(OBJ) *.d *.d.* gmon.out postfish
@@ -76,7 +76,7 @@
 
 target:  $(OBJ) postfish-wisdomrc
 	./touch-version
-	$(LD) $(OBJ) $(CFLAGS) -o postfish $(LIBS) `pkg-config --libs gtk+-2.0` -lpthread -lfftw3f -lm
+	$(LD) $(OBJ) $(CFLAGS) -o postfish $(LIBS) `pkg-config --libs gtk+-2.0 ao \> 1.2` -lpthread -lfftw3f -lm
 
 install: target
 	$(INSTALL) -d -m 0755 $(BINDIR)

Modified: trunk/postfish/config.c
===================================================================
--- trunk/postfish/config.c	2013-01-22 10:26:45 UTC (rev 18781)
+++ trunk/postfish/config.c	2013-01-22 10:29:03 UTC (rev 18782)
@@ -248,7 +248,7 @@
     configentry *c=config_list+i;
     if(c->string)
       fprintf(f,"(%s bank%d A%d B%d C%d l%d \"%s\" )\n",
-	      c->key,c->bank,c->A,c->B,c->C,strlen(c->string),c->string);
+	      c->key,c->bank,c->A,c->B,c->C,(int)strlen(c->string),c->string);
     if(c->vec){
       fprintf(f,"[%s bank%d A%d B%d C%d v%d ",
 	      c->key,c->bank,c->A,c->B,c->C,c->vals);

Modified: trunk/postfish/main.c
===================================================================
--- trunk/postfish/main.c	2013-01-22 10:26:45 UTC (rev 18781)
+++ trunk/postfish/main.c	2013-01-22 10:29:03 UTC (rev 18782)
@@ -26,13 +26,13 @@
    reusable code.  It's monolithic, inflexible, and designed that way
    on purpose. */
 
-/* sound playback code is OSS-specific for now */
 #include "postfish.h"
 #include <signal.h>
 #include <getopt.h>
 #include <fenv.h>  // Thank you C99!
 #include <fftw3.h>
 #include <gtk/gtk.h>
+#include <ao/ao.h>
 #include "input.h"
 #include "output.h"
 #include "declip.h"
@@ -76,6 +76,7 @@
       main_looping=0;
       gtk_main_quit();
     }
+    ao_shutdown();
     exit(0);
 
   }
@@ -331,6 +332,7 @@
   }
 
   /* probe outputs */
+  ao_initialize();
   if(setvbuf(stdout, NULL, _IONBF , 0))
     fprintf(stderr,"Unable to remove block buffering on stdout; continuing\n");
   
@@ -338,10 +340,16 @@
   if(!batch) output_probe_monitor();
 
   /* open all the input files */
-  if(input_load())exit(1);
+  if(input_load()){
+    ao_shutdown();
+    exit(1);
+  }
 
   /* load config file */
-  if(config_load(configfile))exit(1);
+  if(config_load(configfile)){
+    ao_shutdown();
+    exit(1);
+  }
 
   /* set up filter chains */
   if(declip_load())exit(1);
@@ -359,7 +367,7 @@
   if(pipe(eventpipe)){
     fprintf(stderr,"Unable to open event pipe:\n"
             "  %s\n",strerror(errno));
-    
+    ao_shutdown();
     exit(1);
   }
 
@@ -378,6 +386,7 @@
   }else
     mainpanel_go(argc,argv,input_ch);
 
+  ao_shutdown();
   return(0);
 }
 

Modified: trunk/postfish/outpanel.c
===================================================================
--- trunk/postfish/outpanel.c	2013-01-22 10:26:45 UTC (rev 18781)
+++ trunk/postfish/outpanel.c	2013-01-22 10:29:03 UTC (rev 18782)
@@ -297,7 +297,7 @@
 					     &state.monitor);
   GtkWidget *stdout_panel=outpanel_subpanel(mp,panel,&outset.stdout,
 					    " standard output ",
-					    output_stdout_device,
+					    output_stdout_ao,
 					    output_stdout_available,
 					    &state.stdout);
   

Modified: trunk/postfish/output.c
===================================================================
--- trunk/postfish/output.c	2013-01-22 10:26:45 UTC (rev 18781)
+++ trunk/postfish/output.c	2013-01-22 10:29:03 UTC (rev 18782)
@@ -2,7 +2,7 @@
  *
  *  postfish
  *    
- *      Copyright (C) 2002-2005 Monty
+ *      Copyright (C) 2002-2012 Monty
  *
  *  Postfish is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -21,9 +21,12 @@
  * 
  */
 
-/* sound playback code is OSS-specific for now */
-#include <linux/soundcard.h>
+/* sound playback now uses AO, but device detection only looks for OSS/ALSA/PULSE + the AO default*/
 #include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <ao/ao.h>
 #include "postfish.h"
 #include "feedback.h"
 #include "input.h"
@@ -47,6 +50,16 @@
 sig_atomic_t playback_seeking=0;
 sig_atomic_t master_att;
 
+static inline int host_is_big_endian() {
+  union {
+    int32_t pattern;
+    unsigned char bytewise[4];
+  } m;
+  m.pattern = 0xfeedface; /* deadbeef */
+  if (m.bytewise[0] == 0xfe) return 1;
+  return 0;
+}
+
 void output_reset(void){
   /* empty feedback queues */
   while(pull_output_feedback(NULL,NULL));
@@ -267,26 +280,73 @@
   return 0;
 }
 
-static int ilog(long x){
-  int ret=-1;
+output_monitor_entry *monitor_list;
+int monitor_entries;
 
-  while(x>0){
-    x>>=1;
-    ret++;
+/* look for sound devices that actually exist */
+
+static void add_monitor(char *file, char *name,int driver){
+  monitor_entries++;
+  if(monitor_list){
+    monitor_list=realloc(monitor_list,
+			 monitor_entries*sizeof(*monitor_list));
+  }else
+    monitor_list=malloc(monitor_entries*sizeof(*monitor_list));
+
+  monitor_list[monitor_entries-1].file=file?strdup(file):NULL;
+  monitor_list[monitor_entries-1].name=strdup(name);
+  monitor_list[monitor_entries-1].driver=driver;
+}
+
+char *search_for_major_minor(char *dir,int major,int minor){
+  /* open the directory, stat entries one by one */
+  DIR *d=opendir(dir);
+  struct dirent *de;
+
+  if(d==NULL) return NULL;
+
+  while((de=readdir(d))){
+    struct stat s;
+    char buf[PATH_MAX];
+    snprintf(buf,PATH_MAX,"%s/%s",dir,de->d_name);
+    if(!stat(buf,&s)){
+      if (major==((int)(s.st_rdev>>8)&0xff) &&
+          minor==((int)(s.st_rdev&0xff))){
+        closedir(d);
+        return strdup(buf);
+      }
+    }
   }
-  return ret;
+
+  closedir(d);
+  return NULL;
 }
 
 static int is_oss(int f){
+  int id = ao_driver_id("oss");
   struct stat s;
 
-  if(isachr(f))
+  if(id>=0 && isachr(f))
     if(!fstat(f,&s)){
       int major=(int)(s.st_rdev>>8)&0xff;
       int minor=(int)(s.st_rdev&0xff);
 
-      // is this a Linux OSS audio device (Major 14) ?
-      if(major==14 && ((minor&0xf)==3 || (minor&0xf)==4))return 1;
+      /* is this a Linux OSS audio device (Major 14)? */
+      if(major==14){
+        char *output_stdout_devicename = search_for_major_minor("/dev",major,minor);
+        if(!output_stdout_devicename)
+          output_stdout_devicename = search_for_major_minor("/dev/sound",major,minor);
+        if(!output_stdout_devicename){
+          fprintf(stderr,"OSS: Unable to find sound device matching stdout.\n");
+          exit(1);
+        }
+
+        add_monitor(output_stdout_devicename,output_stdout_devicename,id);
+        free(output_stdout_devicename);
+        fclose(stdout);
+        stdout=NULL;
+        return 1;
+      }
     }
 
   return 0;
@@ -294,13 +354,37 @@
 
 static int is_alsa(int f){
   struct stat s;
+  int id = ao_driver_id("alsa");
 
-  if(isachr(f))
+  if(id>=0 && isachr(f))
     if(!fstat(f,&s)){
-      int type=(int)(s.st_rdev>>8);
+      int major=(int)(s.st_rdev>>8)&0xff;
+      int minor=(int)(s.st_rdev&0xff);
+      char buffer[80];
 
-      // is this a Linux ALSA audio device (Major 116) ?
-      if(type==116)return 1;
+      /* is this a Linux ALSA audio device (Major 116)? */
+      if(major==116){
+        int ret,c,d;
+
+        char *output_stdout_devicename = search_for_major_minor("/dev/snd",major,minor);
+        if(!output_stdout_devicename){
+          fprintf(stderr,"ALSA: Unable to find sound device matching stdout.\n");
+          exit(1);
+        }
+
+        /* parse the ALSA id from the device name */
+        ret=sscanf(output_stdout_devicename,"/dev/snd/pcmC%dD%dp",&c,&d);
+        if(ret!=2){
+          fprintf(stderr,"ALSA: Unable to find sound device matching stdout.\n");
+          exit(1);
+        }
+        free(output_stdout_devicename);
+        sprintf(buffer,"hw:%d,%d",c,d);
+        add_monitor(buffer,buffer,id);
+        fclose(stdout);
+        stdout=NULL;
+        return 1;
+      }
     }
 
   return 0;
@@ -313,7 +397,7 @@
 }
 
 int output_stdout_available=0;
-int output_stdout_device=0;    /* 0== file, 1==OSS, 2==ALSA */
+int output_stdout_ao=0; 
 int output_monitor_available=0;
 
 int output_probe_stdout(int outfileno){
@@ -326,90 +410,116 @@
   }else if (isareg(outfileno)){
     /* stdout is a regular file */
     output_stdout_available=1;
-    output_stdout_device=0;
+    output_stdout_ao=0;
 
   }else if((ret=isaudio(outfileno))){
-    /* stdout is an audio device */
+    /* stdout is an audio device; we don't actually use stdout, we'll reopen as an ao_device */
 
     output_stdout_available=1;
-    output_stdout_device=ret;
+    output_stdout_ao=1;
 
-    if(ret==2){
-      fprintf(stderr,
-	      "\nStdout is pointing to an ALSA sound device;\n"
-	      "Postfish does not yet support ALSA playback.\n\n");
-      exit(1);
-    }
   }else{
     /* God only knows what stdout is.  It might be /dev/null or some other.... treat it similar to file */
 
     output_stdout_available=1;
-    output_stdout_device=0;
+    output_stdout_ao=0;
 
   }
 
   return 0;
 }
 
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-output_monitor_entry *monitor_list;
-int monitor_entries;
+static void output_probe_monitor_OSS(){
+  /* open /dev and search of major 14 */
+  int id = ao_driver_id("oss");
 
-static char *audio_dev_type[]={"file","OSS"};
+  if(id>=0){
+    DIR *d=opendir("/dev");
+    struct dirent *de;
 
-/* look for sound devices that actually exist */
+    while((de=readdir(d))){
+      struct stat s;
+      char buf[PATH_MAX];
+      snprintf(buf,PATH_MAX,"/dev/%s",de->d_name);
+      if(!stat(buf,&s)){
 
-static void add_monitor(char *file, char *name,int type){
-  monitor_entries++;
-  if(monitor_list){
-    monitor_list=realloc(monitor_list,
-			 monitor_entries*sizeof(*monitor_list));
-  }else
-    monitor_list=malloc(monitor_entries*sizeof(*monitor_list));
-  
-  monitor_list[monitor_entries-1].file=strdup(file);
-  monitor_list[monitor_entries-1].name=strdup(name);
-  monitor_list[monitor_entries-1].type=type;
-  
-  fprintf(stderr,"Found an output device (type %s): %s\n",
-	  audio_dev_type[type],file);
+        int major=(int)(s.st_rdev>>8)&0xff;
+        int minor=(int)(s.st_rdev&0xff);
+
+        /* is this a Linux OSS dsp audio device? (Major 14, minor 3,19...[only list /dev/dspX]) */
+        if(major==14 && (minor&0xf)==3){
+          int f=open(buf,O_RDWR|O_NONBLOCK);
+          if(f!=-1){
+            char name[80];
+            snprintf(name,80,"OSS %s",de->d_name);
+            add_monitor(buf,name,id);
+            close(f);
+          }
+        }
+      }
+    }
+
+    closedir(d);
+  }
 }
 
-static void output_probe_monitor_OSS(){
-  /* open /dev and search of major 14 */
-  DIR *d=opendir("/dev");
-  struct dirent *de;
-  
-  if(d==NULL){
-    fprintf(stderr,"Odd; could not open /dev to look for audio devices.\n");
-    return;
-  }
-  
-  while((de=readdir(d))){
-    struct stat s;
-    char buf[PATH_MAX];
-    snprintf(buf,PATH_MAX,"/dev/%s",de->d_name);
-    if(!stat(buf,&s)){
-      
-      int major=(int)(s.st_rdev>>8)&0xff;
-      int minor=(int)(s.st_rdev&0xff);
-      
-      // is this a Linux OSS dsp audio device (Major 14, minor 3,19,35...) ?
-      if(major==14 && (minor&0xf)==3){
-	int f=open(buf,O_RDWR|O_NONBLOCK);
-	if(f!=-1){
-	  add_monitor(buf,de->d_name,1);
-	  close(f);
-	}
+static void output_probe_monitor_ALSA(){
+  /* does this AO even have alsa output? */
+  int id = ao_driver_id("alsa");
+  if(id>=0){
+
+    /* test adding a default plug device; the format doesn't matter */
+    ao_sample_format format={16,48000,2,AO_FMT_NATIVE,NULL};
+    ao_option opt1={"dev","default",0};
+    ao_option opt={"client_name","postfish",&opt1};
+    ao_device *test=ao_open_live(id, &format, &opt);
+
+    if(test){
+      add_monitor("default","ALSA default",id);
+      ao_close(test);
+
+      /* discover hardware devices from /proc/asound/pcm */
+      {
+        FILE *pcm=fopen("/proc/asound/pcm","r");
+        if(pcm){
+          char buf[1024];
+          while(fgets(buf,1024,pcm)){
+            /* is this a playback device? */
+            if(strstr(buf,": playback ")){
+              int c,d;
+              char desc[80];
+              /* parse the card and device numbers, and the name */
+              if(sscanf(buf,"%d-%d: %*[^:]: %79[^:]",&c,&d,desc)==3){
+                /* add a monitor device */
+                snprintf(buf,1024,"ALSA %s",desc);
+                snprintf(desc,80,"hw:%d,%d",c,d);
+                add_monitor(desc,buf,id);
+              }
+            }
+          }
+          fclose(pcm);
+        }
       }
     }
   }
-	
-  closedir(d);
 }
 
+static void output_probe_monitor_pulse(){
+  /* does this AO even have pulse output? */
+  int id = ao_driver_id("pulse");
+  if(id>=0){
+    /* test open; format doesn't matter */
+    ao_sample_format format={16,48000,2,AO_FMT_NATIVE,NULL};
+    ao_option opt={"client_name","postfish",NULL};
+    ao_device *test=ao_open_live(id, &format, &opt);
+
+    if(test){
+      add_monitor(NULL,"PulseAudio",id);
+      ao_close(test);
+    }
+  }
+}
+
 static int moncomp(const void *a, const void *b){
   output_monitor_entry *ma=(output_monitor_entry *)a;
   output_monitor_entry *mb=(output_monitor_entry *)b;
@@ -417,190 +527,154 @@
 }
 
 int output_probe_monitor(void ){
-  if(output_stdout_device!=0){
+  if(output_stdout_ao!=0){
     output_monitor_available=0;
     return 0;
   }
-  
-  output_probe_monitor_OSS();
-  
-  if(monitor_entries>0){
-    output_monitor_available=1;
 
-    /* sort the entries alphabetically by name */
-    qsort(monitor_list, monitor_entries, sizeof(*monitor_list), moncomp);
+  output_probe_monitor_pulse();
+  {
+    int n = monitor_entries;
+    output_probe_monitor_ALSA();
+    if(monitor_entries>n){
+      if(monitor_entries+1>n)
+        qsort(monitor_list+n+1, monitor_entries-n-1, sizeof(*monitor_list), moncomp);
+    }else{
+      /* only search for OSS if we don't find ALSA */
+      output_probe_monitor_OSS();
+      if(monitor_entries<n){
+        qsort(monitor_list+n, monitor_entries-n, sizeof(*monitor_list), moncomp);
+      }
+    }
   }
 
+  if(monitor_entries>0)
+    output_monitor_available=1;
+
   return 0;
 }
 
-#ifndef AFMT_S24_LE
-#       define AFMT_S24_LE              0x00000800      
-#       define AFMT_S24_BE              0x00001000      
-#       define AFMT_U24_LE              0x00002000      
-#       define AFMT_U24_BE              0x00004000
-#endif
-
-static int OSS_playback_startup(FILE *f, int rate, int *ch, int *endian, int *bits,int *signp){
-  int fd=fileno(f);
+static ao_device *playback_startup(int driver,char *device, int rate, int *ch, int *endian, int *bits,int *signp){
+  ao_device *ret = NULL;
   int downgrade=0;
-  int failflag=1;
+  int downgrade_dev=0;
   int local_ch=*ch;
   int local_bits=*bits;
+  char localdevice[80];
 
-  *endian=(AFMT_S16_NE==AFMT_S16_BE?1:0);
-  
+  *endian=host_is_big_endian();
+  if(device)
+    strncpy(localdevice,device,80);
+
   /* try to configure requested playback.  If it fails, keep dropping back
      until one works */
   while(local_ch || local_bits>16){
-    int format;
-    
+    ao_sample_format format;
+    ao_option opt1={"dev",localdevice,0};
+    ao_option opt={"client_name","postfish",&opt1};
+    if(!device)opt.next=0;
+
+    format.rate=rate;
+    format.channels=local_ch;
+    format.byte_format=AO_FMT_NATIVE;
+    format.matrix=0;
+
     switch(local_bits){
     case 8:
-      format=AFMT_U8;
+      format.bits=8;
       *signp=0;
       break;
     case 16:
-      format=AFMT_S16_NE;
+      format.bits=16;
       *signp=1;
       break;
     case 24:
-      format=AFMT_S24_LE;
-      if(*endian)format=AFMT_S24_BE;
+      format.bits=24;
       *signp=1;
       break;
     }
-    
-    /* try to lower the DSP delay; this ioctl may fail gracefully */
-    {
-      
-      long bytesperframe=(local_bits+7)/8*local_ch*input_size;
-      int fraglog=ilog(bytesperframe);
-      int fragment=0x00040000|fraglog,fragcheck;
-      
-      fragcheck=fragment;
-      int ret=ioctl(fd,SNDCTL_DSP_SETFRAGMENT,&fragment);
-      if(ret || fragcheck!=fragment){
-	fprintf(stderr,"Could not set DSP fragment size; continuing.\n");
+
+    ret = ao_open_live(driver,&format,&opt);
+    if(ret) break;
+
+    /* first, if this is ALSA, use a plughw instead of a hw device */
+    if(driver==ao_driver_id("alsa") && strstr(localdevice,"hw:")==localdevice){
+      snprintf(localdevice,80,"plug%s",device);
+      downgrade_dev=1;
+    }else{
+      /* first try decreasing bit depth */
+      downgrade=1;
+      if(local_bits==24){
+        local_bits=16;
+      }else{
+        /* next, drop channels */
+        local_bits=*bits;
+        local_ch--;
       }
     }
-    
-    /* format, channels, rate */
-    {
-      int temp=format;
-      int ret=ioctl(fd,SNDCTL_DSP_SETFMT,&temp);
-      if(ret || format!=temp) goto failset;
-    }
-    
-    {
-      int temp=local_ch;
-      int ret=ioctl(fd,SNDCTL_DSP_CHANNELS,&temp);
-      if(ret || temp!=local_ch) goto failset;
-    }
-    
-    {
-      int temp=rate;
-      int ret=ioctl(fd,SNDCTL_DSP_SPEED,&temp);
-      if(ret || temp!=rate) goto failset;
-    }
-    
-    failflag=0;
-    break;
-    
-  failset:
-    downgrade=1;
-    
-    /* first try decreasing bit depth */
-    if(local_bits==24){
-      local_bits=16;
-    }else{
-      
-      /* next, drop channels */
-      local_bits=*bits;
-      local_ch--;
-    }
-      
-    ioctl(fd,SNDCTL_DSP_RESET);
   }
 
-  if(failflag || downgrade)
-    fprintf(stderr,"Unable to set playback for %d bits, %d channels, %dHz\n",
-	    *bits,*ch,rate);
-  if(downgrade && !failflag)
+  if(!ret || downgrade_dev || downgrade)
+    fprintf(stderr,"Unable to open %s for %d bits, %d channels, %dHz\n",
+	    device,*bits,*ch,rate);
+  if(downgrade && ret)
     fprintf(stderr,"\tUsing %d bits, %d channels, %dHz instead\n",
 	    local_bits,local_ch,rate);
-  if(failflag)return -1;
-  
+  else if(downgrade_dev && ret)
+    fprintf(stderr,"\tUsing plug%s instead\n",
+	    device);
+
   *bits=local_bits;
   *ch=local_ch;
-  
-  return 0;
+
+  return ret;
 }
 
-static int output_startup(FILE *f, int devtype, int format, int rate, int *ch, int *endian, int *bits,int *signp){
-  switch(devtype){
-  case 0: // pipe, regular file or file device 
-    switch(format){
-    case 0:
+static int file_startup(FILE *f, int format, int rate, int *ch, int *endian, int *bits,int *signp){
+  switch(format){
+  case 0:
       /* WAVE format */
-      ftruncate(fileno(f),0);
-      WriteWav(f,*ch,rate,*bits,-1);
-      *endian=0;
-      *signp=1;
+    ftruncate(fileno(f),0);
+    WriteWav(f,*ch,rate,*bits,-1);
+    *endian=0;
+    *signp=1;
+    if(*bits==8)*signp=0;
+    break;
+  case 1:
+    /* AIFF-C format */
+    ftruncate(fileno(f),0);
+    WriteAifc(f,*ch,rate,*bits,-1);
+    *endian=1;
+    *signp=1;
+    break;
+  case 2:
+    /* raw little endian */
+    *endian=0;
+    *signp=1;
+    if(*bits==8)*signp=0;
+    break;
+  case 3:
+    /* raw big endian */
+    *endian=1;
+    *signp=1;
       if(*bits==8)*signp=0;
       break;
-    case 1:
-      /* AIFF-C format */
-      ftruncate(fileno(f),0);
-      WriteAifc(f,*ch,rate,*bits,-1);
-      *endian=1;
-      *signp=1;
-      break;
-    case 2:
-      /* raw little endian */
-      *endian=0;
-      *signp=1;
-      if(*bits==8)*signp=0;
-      break;
-    case 3:
-      /* raw big endian */
-      *endian=1;
-      *signp=1;
-      if(*bits==8)*signp=0;
-      break;
-    default:
-      fprintf(stderr,"Unsupported output file format selected!\n");
-      return -1;
-    }
-    return 0;
-
-  case 1: // OSS playback
-    return OSS_playback_startup(f, rate, ch, endian, bits, signp);
-
-  default: // undefined for now
-    fprintf(stderr,"Unsupported playback device selected\n");
+  default:
+    fprintf(stderr,"Unsupported output file format selected!\n");
     return -1;
   }
+  return 0;
 }
 
-static void output_halt(FILE *f,int devtype,int format, int rate, int ch, int endian, int bits,int signp,
-			off_t bytecount){
-  switch(devtype){
+static void file_halt(FILE *f,int format, int rate, int ch, int endian, int bits,int signp,
+                      off_t bytecount){
+  switch(format){
   case 0:
-    switch(format){
-    case 0:
-      WriteWav(f,ch,rate,bits,bytecount); // will complete header only if stream is seekable
-      break;
-    case 1:
-      WriteAifc(f,ch,rate,bits,bytecount); // will complete header only if stream is seekable
-      break;
-    }
+    WriteWav(f,ch,rate,bits,bytecount); // will complete header only if stream is seekable
     break;
-  case 1: // OSS
-    {
-      int fd=fileno(f);
-      ioctl(fd,SNDCTL_DSP_RESET);
-    }
+  case 1:
+    WriteAifc(f,ch,rate,bits,bytecount); // will complete header only if stream is seekable
+    break;
   }
 }
 
@@ -627,7 +701,7 @@
   for(j=0;j<ch;j++){
     unsigned char *o=audiobuf+bytes*j;
     if(!mute_channel_muted(link->active,j) && source[j]){
-      
+
       float *d=link->data[j];
 
       for(i=0;i<link->samples;i++){
@@ -636,7 +710,7 @@
 	if(val>8388607)val=8388607;
 	if(val<-8388608)val=-8388608;
 	val ^= signxor;
-  
+
 	switch(endbytecase){
 	case 2:
 	  /* LE 24 */
@@ -668,7 +742,7 @@
     }else{
       for(i=0;i<link->samples;i++){
 	int32_t val = signxor;
-  
+
 	switch(endbytecase){
 	case 2:case 5:
 	  /* 24 */
@@ -683,7 +757,7 @@
 	  *o++=val>>16;
 	  break;
 	}
-	
+
 	o+=bytestep;
       }
     }
@@ -698,7 +772,7 @@
 void *playback_thread(void *dummy){
   int i,j,k;
   unsigned char *audiobuf;
-  int bigendianp=(AFMT_S16_NE==AFMT_S16_BE?1:0);
+  int bigendianp=host_is_big_endian();
   time_linkage *link;
   int result;
   off_t output_bytecount=0;
@@ -712,7 +786,7 @@
   long offset=0;
 
   /* monitor setup */
-  FILE *monitor_fd=NULL;
+  ao_device *monitor_device=NULL;
   int monitor_bits;
   int monitor_ch;
   int monitor_endian=bigendianp;
@@ -720,6 +794,7 @@
   int monitor_started=0;
   int monitor_devicenum=outset.monitor.device;
 
+  ao_device *stdout_device=NULL;
   int stdout_bits;
   int stdout_ch;
   int stdout_endian;
@@ -732,7 +807,7 @@
     for(j=OUTPUT_CHANNELS-1;j>=0;j--){
       for(i=0;i<input_ch;i++){
 	mix_settings *m=mix_set+i;
-      
+
 	if(m->placer_destA[j] ||
 	   m->placer_destB[j])break;
 
@@ -775,7 +850,7 @@
       break;
     }
   }
-  
+
   if(output_stdout_available){
     int ch=outset.stdout.ch;
     int bits=outset.stdout.bytes;
@@ -795,7 +870,7 @@
     /* bits */
     switch(bits){
     case 0:
-      if(output_stdout_device)
+      if(output_stdout_ao)
 	stdout_bits=16;
       else
 	stdout_bits=24;
@@ -814,7 +889,7 @@
   }
 
   audiobuf=malloc(input_size*OUTPUT_CHANNELS*4); // largest possible need
-  
+
   while(1){
 
     /* the larger lock against seeking is primarily cosmetic, but
@@ -826,12 +901,12 @@
       pipeline_reset();
       playback_seeking=0;
     }
-    
+
     if(playback_exit){
       pthread_mutex_unlock(&input_mutex);
       break;
     }
-    
+
     offset+=input_size;
 
     /* get data */
@@ -876,14 +951,14 @@
 
     if(!result)break;
     /************/
-    
+
     /* master att */
     if(link->samples>0){
       int att=master_att;
 
       if(att==att_last){
 	float scale=fromdB(att/10.);
-	
+
 	for(i=0;i<link->samples;i++)
 	  for(j=0;j<link->channels;j++)
 	    link->data[j][i]*=scale;
@@ -891,7 +966,7 @@
 	/* slew-limit the scaling */
 	float scale=fromdB(att_last*.1);
 	float mult=fromdB((att-att_last)*.1 / input_size);
-	
+
 	for(i=0;i<link->samples;i++){
 	  for(j=0;j<link->channels;j++)
 	    link->data[j][i]*=scale;
@@ -908,43 +983,26 @@
     if(link->samples>0){
 
       /* final limiting and conversion */
-      
+
       /* monitor output */
       if(output_monitor_available){
 	if(outset.panel_active[0]){
-	  
+
 	  /* lazy playback init */
 	  if(!monitor_started){
 
-	    /* nonblocking open... just in case this is an exclusive
-               use device currently used by something else */
-	    int mfd=open(monitor_list[monitor_devicenum].file,O_RDWR|O_NONBLOCK);
-	    if(mfd==-1){
-	      fprintf(stderr,"unable to open audio monitor device %s for playback.\n",
-		      monitor_list[monitor_devicenum].file);
+            monitor_device =
+              playback_startup(monitor_list[monitor_devicenum].driver,
+                               monitor_list[monitor_devicenum].file,
+                               input_rate,
+                               &monitor_ch,&monitor_endian,&monitor_bits,&monitor_signp);
+            if(!monitor_device){
+              outpanel_monitor_off();
+	      fprintf(stderr,"unable to open audio monitor device %s (%s) for playback.\n",
+		      monitor_list[monitor_devicenum].file,monitor_list[monitor_devicenum].name);
 	      outpanel_monitor_off();
 	    }else{
-	      fcntl(mfd,F_SETFL,0); /* unset non-blocking */
-	      monitor_fd=fdopen(dup(mfd),"wb");
-	      close(mfd);
-
-	      if(monitor_fd==NULL){
-		fprintf(stderr,"unable to fdopen audio monitor device %s for playback.\n",
-			monitor_list[monitor_devicenum].file);
-		outpanel_monitor_off();
-	      }else{
-		if(setvbuf(monitor_fd, NULL, _IONBF , 0)){
-		  fprintf(stderr,"Unable to remove block buffering on audio monitor; continuing\n");
-		}
-
-		if(output_startup(monitor_fd,monitor_list[monitor_devicenum].type,0,input_rate,
-				  &monitor_ch,&monitor_endian,&monitor_bits,&monitor_signp)){
-		  outpanel_monitor_off();
-		  fclose(monitor_fd);
-		  monitor_fd=NULL;
-		}else
-		  monitor_started=1;
-	      }
+              monitor_started=1;
 	    }
 	  }
 
@@ -952,48 +1010,59 @@
 	    int outbytes=outpack(link,audiobuf,monitor_ch,
 				 monitor_bits,monitor_endian,monitor_signp,
 				 outset.monitor.source);
-	    
-	    fwrite(audiobuf,1,outbytes,monitor_fd);
+            ao_play(monitor_device,(char *)audiobuf,outbytes);
 	  }
 	}else{
 	  if(monitor_started){
 	    /* halt playback */
-	    output_halt(monitor_fd,monitor_list[monitor_devicenum].type,0,input_rate,monitor_ch,
-			monitor_endian,monitor_bits,monitor_signp,-1);
-	    fclose(monitor_fd);
-	    monitor_fd=NULL;
+            ao_close(monitor_device);
+	    monitor_device=NULL;
 	    monitor_started=0;
 	  }
 	}
       }
-      
+
       /* standard output */
       if(output_stdout_available){
 	if(outset.panel_active[1]){
 
 	  /* lazy playback/header init */
 	  if(!stdout_started){
-	    if(output_startup(stdout,output_stdout_device,stdout_format,input_rate,
+            if(output_stdout_ao){ // AO device
+              stdout_device =
+                playback_startup(monitor_list[0].driver,
+                                 monitor_list[0].file,
+                                 input_rate,
+                                 &stdout_ch,&stdout_endian,&stdout_bits,&stdout_signp);
+              if(!stdout_device){
+                outpanel_stdout_off();
+                fprintf(stderr,"unable to open stdout device for playback.\n");
+              }else
+                stdout_started=1;
+            }else{
+              if(file_startup(stdout,stdout_format,input_rate,
 			      &stdout_ch,&stdout_endian,&stdout_bits,&stdout_signp))
-	      outpanel_stdout_off();
-	    else
-	      stdout_started=1;
-	  }
+                outpanel_stdout_off();
+              else
+                stdout_started=1;
+            }
+          }
 
 	  if(stdout_started){
 	    int outbytes=outpack(link,audiobuf,stdout_ch,
 				 stdout_bits,stdout_endian,stdout_signp,
 				 outset.stdout.source);
-	    
-	    output_bytecount+=fwrite(audiobuf,1,outbytes,stdout);
+            if(output_stdout_ao) // AO device
+              ao_play(stdout_device,(char *)audiobuf,outbytes);
+            else
+              output_bytecount+=fwrite(audiobuf,1,outbytes,stdout);
 	  }
 	}else{
 	  if(stdout_started){
 	    /* if stdout is a device, halt playback.  Otherwise, write nothing */
-	    if(output_stdout_device){
-	      /* halt playback */
-	      output_halt(stdout,output_stdout_device,0,input_rate,stdout_ch,stdout_endian,
-			  stdout_bits,stdout_signp,-1);
+	    if(output_stdout_ao){
+              ao_close(stdout_device);
+              stdout_device=NULL;
 	      stdout_started=0;
 	    }
 	  }
@@ -1025,17 +1094,19 @@
   }
 
   /* shut down monitor */
-  if(monitor_fd){
+  if(monitor_device){
     if(monitor_started)
-      output_halt(monitor_fd,monitor_list[monitor_devicenum].type,0,input_rate,monitor_ch,
-		  monitor_endian,monitor_bits,monitor_signp,-1);
-    fclose(monitor_fd);
+      ao_close(monitor_device);
   }
 
   /* shut down stdout playback or write final header */
-  if(stdout_started)
-    output_halt(stdout,output_stdout_device,stdout_format,input_rate,stdout_ch,stdout_endian,
+  if(stdout_started){
+    if(output_stdout_ao)
+      ao_close(stdout_device);
+    else
+      file_halt(stdout,stdout_format,input_rate,stdout_ch,stdout_endian,
 		stdout_bits,stdout_signp,output_bytecount);
+  }
 
   pipeline_reset();
   playback_active=0;

Modified: trunk/postfish/output.h
===================================================================
--- trunk/postfish/output.h	2013-01-22 10:26:45 UTC (rev 18781)
+++ trunk/postfish/output.h	2013-01-22 10:29:03 UTC (rev 18782)
@@ -38,13 +38,13 @@
 } output_settings;
 
 typedef struct {
-  int type;
+  int driver;
   char *name;
   char *file;
 } output_monitor_entry;
 
 extern int output_stdout_available;
-extern int output_stdout_device;
+extern int output_stdout_ao;
 extern int output_monitor_available;
 extern output_monitor_entry *monitor_list;
 extern int monitor_entries;

Modified: trunk/postfish/version.h
===================================================================
--- trunk/postfish/version.h	2013-01-22 10:26:45 UTC (rev 18781)
+++ trunk/postfish/version.h	2013-01-22 10:29:03 UTC (rev 18782)
@@ -1,2 +1,2 @@
 #define VERSION "$Id$ "
-/* DO NOT EDIT: Automated versioning hack [Wed Aug  1 11:37:36 EDT 2012] */
+/* DO NOT EDIT: Automated versioning hack [Tue Jan 22 05:15:23 EST 2013] */



More information about the commits mailing list