[xiph-commits] r8830 - trunk/MTG
xiphmont at motherfish-iii.xiph.org
xiphmont at motherfish-iii.xiph.org
Fri Feb 4 01:05:24 PST 2005
Author: xiphmont
Date: 2005-02-04 01:05:23 -0800 (Fri, 04 Feb 2005)
New Revision: 8830
Modified:
trunk/MTG/soundboard.c
Log:
Move the MTG soundboad to using ALSA 1.0 API
Modified: trunk/MTG/soundboard.c
===================================================================
--- trunk/MTG/soundboard.c 2005-02-04 06:59:04 UTC (rev 8829)
+++ trunk/MTG/soundboard.c 2005-02-04 09:05:23 UTC (rev 8830)
@@ -37,8 +37,7 @@
#include <signal.h>
#include <curses.h>
#include <fcntl.h>
-
-#include <sys/soundcard.h>
+#include <alsa/asoundlib.h>
#include <sys/ioctl.h>
/* we need some cooperative multitasking to eliminate locking (and
@@ -78,19 +77,19 @@
static char *lockfile="/tmp/beaverphonic/lock";
//static char *installdir="/usr/local/beaverphonic/";
static char *installdir="/home/xiphmont/MotherfishCVS/MTG/";
-#define VERSION "$Id: soundboard.c,v 1.13 2003/10/02 17:11:58 xiphmont Exp $"
+#define VERSION "$Id$"
/******** channel mappings. All hardwired for now... ***********/
// only OSS stereo builin for now
-#define MAX_CHANNELS 4
+#define MAX_CHANNELS 12
-#define OUTPUT_CHANNELS1 4
-#define OUTPUT_CHANNELS2 0
+#define OUTPUT_CHANNELS1 2
+#define OUTPUT_CHANNELS2 2
-#define INPUT_CHANNELS1 0
-#define INPUT_CHANNELS2 0
+#define INPUT_CHANNELS1 6
+#define INPUT_CHANNELS2 6
#define INPUT_SAMPLE_BYTES 2
-#define INPUT_SAMPLE_FMT AFMT_S16_LE
+#define INPUT_SAMPLE_FMT SND_PCM_FORMAT_S16_LE
#define MAX_INPUT_CHANNELS (INPUT_CHANNELS1+INPUT_CHANNELS2)
@@ -109,17 +108,7 @@
static outchannel channel_list[MAX_OUTPUT_CHANNELS]={
{"house L",0},
- {"center L",0},
- {"center R",0},
{"house R",0},
- {"",0},
- {"",0},
- {"",0},
- {"",0},
-};
-static outchannel rchannel_list[8]={
- {"1",0},
- {"2",0},
{"3",0},
{"4",0},
{"5",0},
@@ -127,7 +116,22 @@
{"7",0},
{"8",0},
};
+static outchannel rchannel_list[MAX_INPUT_CHANNELS]={
+ {"drums L",0},
+ {"drums R",0},
+ {"guitar 1",0},
+ {"guitar 2",0},
+ {"keyboard L",0},
+ {"keyboard R",0},
+ {"bass",0},
+ {"upstage L",0},
+ {"upstage R",0},
+ {"house L",0},
+ {"house R",0},
+ {"vocal",0},
+};
+
enum menutype {MENU_MAIN,MENU_KEYPRESS,MENU_ADD,MENU_EDIT,MENU_OUTPUT,MENU_QUIT};
pthread_mutex_t cache_mutex=PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
@@ -138,6 +142,7 @@
static long main_master_volume=50;
char *program;
static int playback_buffer_minfill=0;
+static int playback_buffer_starve=0;
static int running=1;
static enum menutype menu=MENU_MAIN;
static int cue_list_position=0;
@@ -145,15 +150,15 @@
static int firstsave=0;
static int unsaved=0;
-static char *playdevice1="/dev/dsp";
-static char *playdevice2="/dev/dsp2";
-static FILE *playfd1=NULL;
-static FILE *playfd2=NULL;
+static char *playdevice1="hw:1,0";
+static char *playdevice2="hw:2,0";
+static snd_pcm_t *playhandle1=NULL;
+static snd_pcm_t *playhandle2=NULL;
-static char *recdevice1="/dev/dsp1";
-static char *recdevice2="/dev/dsp2";
-static FILE *recfd1=NULL;
-static FILE *recfd2=NULL;
+static char *recdevice1="hw:1,0";
+static char *recdevice2="hw:2,0";
+static snd_pcm_t *rechandle1=NULL;
+static snd_pcm_t *rechandle2=NULL;
int ttyfd;
int ttypipe[2];
@@ -853,8 +858,9 @@
/*************** threaded record ****************************/
-#define REC_BLOCK1 (INPUT_CHANNELS1 * INPUT_SAMPLE_BYTES * 512)
-#define REC_BLOCK2 (INPUT_CHANNELS2 * INPUT_SAMPLE_BYTES * 512)
+#define RECBUFFER 512
+#define REC_BLOCK1 (INPUT_CHANNELS1 * INPUT_SAMPLE_BYTES * RECBUFFER)
+#define REC_BLOCK2 (INPUT_CHANNELS2 * INPUT_SAMPLE_BYTES * RECBUFFER)
#define REC_BLOCK (REC_BLOCK1 + REC_BLOCK2)
unsigned char recordbuffer1[REC_BLOCK1];
unsigned char recordbuffer2[REC_BLOCK2];
@@ -874,6 +880,7 @@
int rec_buffer_disk_min=100;
int rec_buffer_dma_min=100;
+int rec_dmabuffer_starve=0;
/* writes a wav header without the length set. */
void PutNumLE(long num,FILE *f,int bytes){
@@ -906,7 +913,7 @@
struct sched_param param;
param.sched_priority=78;
if(pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶m)){
- fprintf(stderr,"Could not set realtime priority for caching; am I suid root?\n");
+ fprintf(stderr,"Could not set realtime priority for record flush; am I suid root?\n");
exit(1);
}
@@ -933,23 +940,14 @@
/* wait for it */
pthread_cond_wait(&rec_buffer_cond,&rec_buffer_mutex);
pthread_mutex_unlock(&rec_buffer_mutex);
- pthread_mutex_lock(&rec_mutex);
}else{
pthread_mutex_unlock(&rec_buffer_mutex);
- pthread_mutex_lock(&rec_mutex);
break;
}
if(rec_exit)break;
- pthread_mutex_unlock(&rec_mutex);
}
- /* rec mutex lock fell through */
- {
- int percent=rint(100.-record_count*100./sizeof(recordbuffer));
- if(rec_buffer_disk_min>percent)rec_buffer_disk_min=percent;
- }
- pthread_mutex_unlock(&rec_mutex);
/* flush to disk */
@@ -1025,19 +1023,14 @@
/* sound device startup */
int i,j;
-#if (INPUT_CHANNELS1)
- int fd1=fileno(recfd1);
-#endif
-#if (INPUT_CHANNELS2)
- int fd2=fileno(recfd2);
-#endif
int format=INPUT_SAMPLE_FMT;
int channels1=INPUT_CHANNELS1;
int channels2=INPUT_CHANNELS2;
int rate=44100;
- long totalsize[2];
+ int totalsize[2]={0,0};
int ret;
- audio_buf_info info,info2;
+ snd_pcm_uframes_t frames;
+ snd_pcm_sframes_t sframes;
struct sched_param param;
param.sched_priority=89;
@@ -1047,43 +1040,145 @@
}
#if (INPUT_CHANNELS1)
- ret=ioctl(fd1,SNDCTL_DSP_SETFMT,&format);
- if(ret || format!=INPUT_SAMPLE_FMT){
- fprintf(stderr,"Could not set recording format\n");
- exit(1);
+ {
+ snd_pcm_hw_params_t *hw;
+ if ((ret = snd_pcm_hw_params_malloc (&hw)) < 0) {
+ fprintf (stderr, "capture 1 cannot allocate hardware parameter structure (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_any (rechandle1, hw)) < 0) {
+ fprintf (stderr, "capture 1 cannot initialize hardware parameter structure (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_set_access (rechandle1, hw, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
+ fprintf (stderr, "capture 1 cannot set access type (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_set_format (rechandle1, hw, format)) < 0) {
+ fprintf (stderr, "capture 1 cannot set sample format (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_set_rate (rechandle1, hw, rate, 0)) < 0) {
+ fprintf (stderr, "capture 1 cannot set sample rate (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_set_channels (rechandle1, hw, channels1)) < 0) {
+ fprintf (stderr, "capture 1 cannot set channel count (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params (rechandle1, hw)) < 0) {
+ fprintf (stderr, "capture 1 cannot set parameters (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ {
+ if((ret = snd_pcm_hw_params_get_buffer_size(hw,&frames)) < 0){
+ fprintf (stderr, "capture 1 cannot query buffer size (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ totalsize[0] = frames;
+ }
+
+ snd_pcm_hw_params_free (hw);
+
+ if ((ret = snd_pcm_prepare (rechandle1)) < 0) {
+ fprintf (stderr, "capture 1 cannot prepare audio interface for use (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
}
- ret=ioctl(fd1,SNDCTL_DSP_CHANNELS,&channels1);
- if(ret || channels1!=INPUT_CHANNELS1){
- fprintf(stderr,"Could not set %d channel recording\n",INPUT_CHANNELS1);
- exit(1);
- }
- ret=ioctl(fd1,SNDCTL_DSP_SPEED,&rate);
- if(ret || rate!=44100){
- fprintf(stderr,"Could not set %dHz recording\n",44100);
- exit(1);
- }
- ioctl(fd1,SNDCTL_DSP_GETISPACE,&info);
- totalsize[0]=info.fragstotal*info.fragsize;
#endif
+
#if (INPUT_CHANNELS2)
- ret=ioctl(fd2,SNDCTL_DSP_SETFMT,&format);
- if(ret || format!=INPUT_SAMPLE_FMT){
- fprintf(stderr,"Could not set recording format\n");
- exit(1);
+ {
+ snd_pcm_hw_params_t *hw;
+ if ((ret = snd_pcm_hw_params_malloc (&hw)) < 0) {
+ fprintf (stderr, "capture 2 cannot allocate hardware parameter structure (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_any (rechandle2, hw)) < 0) {
+ fprintf (stderr, "capture 2 cannot initialize hardware parameter structure (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_set_access (rechandle2, hw, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
+ fprintf (stderr, "capture 2 cannot set access type (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_set_format (rechandle2, hw, format)) < 0) {
+ fprintf (stderr, "capture 2 cannot set sample format (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_set_rate (rechandle2, hw, rate, 0)) < 0) {
+ fprintf (stderr, "capture 2 cannot set sample rate (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_set_channels (rechandle2, hw, channels2)) < 0) {
+ fprintf (stderr, "capture 2 cannot set channel count (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params (rechandle2, hw)) < 0) {
+ fprintf (stderr, "capture 2 cannot set parameters (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ {
+ if((ret = snd_pcm_hw_params_get_buffer_size(hw,&frames)) < 0){
+ fprintf (stderr, "capture 2 cannot query buffer size (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ totalsize[1] = frames;
+ }
+
+ snd_pcm_hw_params_free (hw);
+
+ if ((ret = snd_pcm_prepare (rechandle2)) < 0) {
+ fprintf (stderr, "capture 2 cannot prepare audio interface for use (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
}
- ret=ioctl(fd2,SNDCTL_DSP_CHANNELS,&channels2);
- if(ret || channels2!=INPUT_CHANNELS2){
- fprintf(stderr,"Could not set %d channel recording\n",INPUT_CHANNELS2);
+
+#if (INPUT_CHANNELS1)
+
+ if ((ret = snd_pcm_link(rechandle1, rechandle2)) < 0) {
+ printf("record streams link error: %s\n", snd_strerror(ret));
exit(1);
}
- ret=ioctl(fd2,SNDCTL_DSP_SPEED,&rate);
- if(ret || rate!=44100){
- fprintf(stderr,"Could not set %dHz recording\n",44100);
- exit(1);
- }
- ioctl(fd2,SNDCTL_DSP_GETISPACE,&info);
- totalsize[1]=info.fragstotal*info.fragsize;
+
#endif
+#endif
pthread_create(&record_disk_thread_id,NULL,record_disk_thread,NULL);
@@ -1109,27 +1204,96 @@
/* update ISPACE min */
#if (INPUT_CHANNELS1)
- ioctl(fd1,SNDCTL_DSP_GETISPACE,&info);
- {
- int percent1=rint((totalsize[0]-info.bytes)*100./totalsize[0]);
+ if(snd_pcm_delay (rechandle1, &sframes) ==0){
+ int percent1=rint((totalsize[0]-sframes)*100./totalsize[0]);
if(rec_buffer_dma_min>percent1)rec_buffer_dma_min=percent1;
}
#endif
#if (INPUT_CHANNELS2)
- ioctl(fd2,SNDCTL_DSP_GETISPACE,&info2);
- {
- int percent2=rint((totalsize[1]-info2.bytes)*100./totalsize[1]);
+ if(snd_pcm_delay (rechandle2, &sframes) ==0){
+ int percent2=rint((totalsize[1]-sframes)*100./totalsize[1]);
if(rec_buffer_dma_min>percent2)rec_buffer_dma_min=percent2;
}
#endif
+
+
#if (INPUT_CHANNELS1)
- fread(recordbuffer1,1,REC_BLOCK1,recfd1);
+ {
+ int frames=0;
+
+ while(frames<RECBUFFER){
+ ret = snd_pcm_readi (rechandle1,recordbuffer1+frames*channels1*INPUT_SAMPLE_BYTES,
+ RECBUFFER-frames);
+
+ if(ret<0){
+ // most likely an underrun
+ switch(ret){
+ case -EAGAIN:
+ break;
+ case -EPIPE: case -ESTRPIPE:
+ // underrun; set starve and reset soft device
+ rec_dmabuffer_starve=1;
+ snd_pcm_drop(rechandle1);
+ snd_pcm_prepare(rechandle1);
+ frames=0; // start this frame over such that both channels are in sync
+
+ break;
+ case -EBADFD:
+ default:
+ // "well, shit." Don't hose the machine here in a realtime thread
+ frames=RECBUFFER;
+ rec_exit=1;
+ fprintf (stderr, "capture1 read error (%s)\n",
+ snd_strerror (ret));
+ break;
+ }
+ }else{
+ frames+=ret;
+ }
+ }
+ }
#endif
#if (INPUT_CHANNELS2)
- fread(recordbuffer2,1,REC_BLOCK2,recfd2);
-#endif
+ {
+ int frames=0;
+ while(frames<RECBUFFER){
+ ret = snd_pcm_readi (rechandle2,recordbuffer2+frames*channels2*INPUT_SAMPLE_BYTES,
+ RECBUFFER-frames);
+ if(ret<0){
+ // most likely an underrun
+ switch(ret){
+ case -EAGAIN:
+ break;
+ case -EPIPE: case -ESTRPIPE:
+ // underrun; set starve and reset soft device
+ rec_dmabuffer_starve=1;
+#if(INPUT_CHANNELS1)
+ snd_pcm_drop(rechandle1); // operate on linked interface
+ snd_pcm_prepare(rechandle1);
+#else
+ snd_pcm_drop(rechandle2);
+ snd_pcm_prepare(rechandle2);
+#endif
+ frames=RECBUFFER; // abort this frame such that both channels are in sync
+ break;
+ case -EBADFD:
+ default:
+ // "well, shit." Don't hose the machine here in a realtime thread
+ frames=RECBUFFER;
+ rec_exit=1;
+ fprintf (stderr, "capture2 read error (%s)\n",
+ snd_strerror (ret));
+ break;
+ }
+ }else{
+ frames+=ret;
+ }
+ }
+ }
+#endif
+
pthread_mutex_lock(&rec_mutex);
{
unsigned char *ptr1=recordbuffer1;
@@ -1163,6 +1327,10 @@
record_head+=REC_BLOCK;
if((unsigned)record_head>=sizeof(recordbuffer))record_head=0;
record_count+=REC_BLOCK;
+ {
+ int percent=rint(100.-record_count*100./sizeof(recordbuffer));
+ if(rec_buffer_disk_min>percent)rec_buffer_disk_min=percent;
+ }
pthread_cond_signal(&rec_buffer_cond);
pthread_mutex_unlock(&rec_buffer_mutex);
}else{
@@ -1503,6 +1671,8 @@
out1[i]=-32768;
}else
out1[i]=(int)(rint(staging[i]));
+
+ out1[i]= ((out1[i]<<8)&0xff00) | ((out1[i]>>8)&0xff);
}
for(i=0;i<ch2;i++){
@@ -1514,6 +1684,8 @@
out2[i]=-32768;
}else
out2[i]=(int)(rint(staging[i+ch1]));
+
+ out2[i]= ((out2[i]<<8)&0xff00) | ((out2[i]>>8)&0xff);
}
}
@@ -1526,24 +1698,19 @@
void *playback_thread(void *dummy){
/* sound device startup */
- audio_buf_info info;
-#if (OUTPUT_CHANNELS1)
- int fd1=fileno(playfd1),i;
-#endif
-#if (OUTPUT_CHANNELS2)
- int fd2=fileno(playfd2);
-#endif
- int format=AFMT_S16_NE;
+ int i;
+ int format=SND_PCM_FORMAT_S16_LE;
int channels1=OUTPUT_CHANNELS1;
int channels2=OUTPUT_CHANNELS2;
int rate=44100;
- long last=0;
- long delay=10;
- long totalsize;
- int fragment=0x7fff000d;
- int16 audiobuf1[256*OUTPUT_CHANNELS1];
- int16 audiobuf2[256*OUTPUT_CHANNELS2];
+ int last=0;
+ int totalsize;
+ int buffersize=1024;
+ int16 audiobuf1[buffersize*OUTPUT_CHANNELS1];
+ int16 audiobuf2[buffersize*OUTPUT_CHANNELS2];
int ret;
+ snd_pcm_uframes_t frames;
+ snd_pcm_sframes_t sframes;
/* realtime schedule setup */
{
@@ -1556,93 +1723,282 @@
}
#if (OUTPUT_CHANNELS1)
- ioctl(fd1,SNDCTL_DSP_SETFRAGMENT,&fragment);
- ret=ioctl(fd1,SNDCTL_DSP_SETFMT,&format);
- if(ret || format!=AFMT_S16_NE){
- fprintf(stderr,"Could not set AFMT_S16_NE playback\n");
- exit(1);
+ {
+ snd_pcm_hw_params_t *hw;
+ if ((ret = snd_pcm_hw_params_malloc (&hw)) < 0) {
+ fprintf (stderr, "playback 1 cannot allocate hardware parameter structure (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_any (playhandle1, hw)) < 0) {
+ fprintf (stderr, "playback 1 cannot initialize hardware parameter structure (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_set_access(playhandle1,hw,SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
+ fprintf (stderr, "playback 1 cannot set access type (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_set_format (playhandle1, hw, format)) < 0) {
+ fprintf (stderr, "playback 1 cannot set sample format (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_set_rate(playhandle1, hw, rate, 0)) < 0) {
+ fprintf (stderr, "playback 1 cannot set sample rate (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_set_channels(playhandle1, hw, channels1)) < 0) {
+ fprintf (stderr, "playback 1 cannot set channel count (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ {
+ snd_pcm_uframes_t near=buffersize*2;
+ if((ret = snd_pcm_hw_params_set_buffer_size_near (playhandle1,hw,&near)) < 0){
+ fprintf (stderr, "playback 1 cannot set buffer size (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ near=buffersize/4;
+ if((ret = snd_pcm_hw_params_set_period_size_near (playhandle1,hw,&near,0)) < 0){
+ fprintf (stderr, "playback 1 cannot set period size (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+ }
+
+ if ((ret = snd_pcm_hw_params (playhandle1, hw)) < 0) {
+ fprintf (stderr, "playback 1 cannot set parameters (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ {
+ if((ret = snd_pcm_hw_params_get_buffer_size(hw,&frames)) < 0){
+ fprintf (stderr, "playback 1 cannot query buffer size (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ playback_buffer_minfill = totalsize = frames;
+ }
+
+ snd_pcm_hw_params_free (hw);
+
+ if ((ret = snd_pcm_prepare (playhandle1)) < 0) {
+ fprintf (stderr, "playback 1 cannot prepare audio interface for use (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
}
- ret=ioctl(fd1,SNDCTL_DSP_CHANNELS,&channels1);
- if(ret || channels1!=OUTPUT_CHANNELS1){
- fprintf(stderr,"Could not set %d channel playback\n",OUTPUT_CHANNELS1);
- exit(1);
- }
- ret=ioctl(fd1,SNDCTL_DSP_SPEED,&rate);
- if(ret || rate!=44100){
- fprintf(stderr,"Could not set %dHz playback\n",44100);
- exit(1);
- }
- ioctl(fd1,SNDCTL_DSP_GETOSPACE,&info);
- playback_buffer_minfill=totalsize=info.fragstotal*info.fragsize;
#else
totalsize=0;
#endif
-#if (OUTPUT_CHANNELS2)
- ioctl(fd2,SNDCTL_DSP_SETFRAGMENT,&fragment);
- ret=ioctl(fd2,SNDCTL_DSP_SETFMT,&format);
- if(ret || format!=AFMT_S16_NE){
- fprintf(stderr,"Could not set AFMT_S16_NE playback\n");
- exit(1);
+
+#if (OUTPUT_CHANNELS2)
+ {
+ snd_pcm_hw_params_t *hw;
+ if ((ret = snd_pcm_hw_params_malloc (&hw)) < 0) {
+ fprintf (stderr, "playback 2 cannot allocate hardware parameter structure (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_any (playhandle2, hw)) < 0) {
+ fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_set_access(playhandle2,hw,SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
+ fprintf (stderr, "cannot set access type (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_set_format (playhandle2, hw, format)) < 0) {
+ fprintf (stderr, "cannot set sample format (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_set_rate(playhandle2, hw, rate, 0)) < 0) {
+ fprintf (stderr, "cannot set sample rate (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ if ((ret = snd_pcm_hw_params_set_channels(playhandle2, hw, channels2)) < 0) {
+ fprintf (stderr, "cannot set channel count (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ {
+ snd_pcm_uframes_t near=buffersize*2;
+ if((ret = snd_pcm_hw_params_set_buffer_size_near (playhandle2,hw,&near)) < 0){
+ fprintf (stderr, "playback 2 cannot set buffer size (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ near=buffersize/4;
+ if((ret = snd_pcm_hw_params_set_period_size_near (playhandle2,hw,&near,0)) < 0){
+ fprintf (stderr, "playback 2 cannot set period size (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+ }
+
+ if ((ret = snd_pcm_hw_params (playhandle2, hw)) < 0) {
+ fprintf (stderr, "cannot set parameters (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ {
+ if((ret = snd_pcm_hw_params_get_buffer_size(hw,&frames)) < 0){
+ fprintf (stderr, "cannot query buffer size (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+ playback_buffer_minfill = totalsize += frames;
+ }
+
+ snd_pcm_hw_params_free (hw);
+
+ if ((ret = snd_pcm_prepare (playhandle2)) < 0) {
+ fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
+ snd_strerror (ret));
+ exit (1);
+ }
+
+
}
- ret=ioctl(fd2,SNDCTL_DSP_CHANNELS,&channels2);
- if(ret || channels2!=OUTPUT_CHANNELS2){
- fprintf(stderr,"Could not set %d channel playback\n",OUTPUT_CHANNELS2);
+
+#if (OUTPUT_CHANNELS1)
+
+ if ((ret = snd_pcm_link(playhandle1, playhandle2)) < 0) {
+ printf("playback streams link error: %s\n", snd_strerror(ret));
exit(1);
}
- ret=ioctl(fd2,SNDCTL_DSP_SPEED,&rate);
- if(ret || rate!=44100){
- fprintf(stderr,"Could not set %dHz playback\n",44100);
- exit(1);
- }
- ioctl(fd2,SNDCTL_DSP_GETOSPACE,&info);
- playback_buffer_minfill=totalsize+=info.fragstotal*info.fragsize;
+
#endif
+#endif
+
while(!playback_exit){
- int samples;
+ int samples=0;
- delay--;
- if(delay<0){
- delay=0;
- samples=0;
+ playback_bufsize=totalsize;
+
#if (OUTPUT_CHANNELS1)
- ioctl(fd1,SNDCTL_DSP_GETOSPACE,&info);
- playback_bufsize=totalsize;
- samples=info.bytes;
-#else
- playback_bufsize=0;
- samples=0;
+ if(snd_pcm_delay (playhandle1, &sframes) == 0)
+ samples+=sframes;
#endif
+
#if (OUTPUT_CHANNELS2)
- ioctl(fd2,SNDCTL_DSP_GETOSPACE,&info);
- playback_bufsize+=totalsize;
- samples+=info.bytes;
+ if(snd_pcm_delay (playhandle2, &sframes) == 0)
+ samples+=sframes;
#endif
-
- samples+=playback_bufsize-samples;
-
- if(playback_buffer_minfill>samples)
- playback_buffer_minfill=samples-64; // sample fragment
-
- }
-
- for(i=0;i<256;i++)
+
+ if(playback_buffer_minfill>samples)
+ playback_buffer_minfill=samples;
+
+ for(i=0;i<buffersize;i++)
_next_sample(audiobuf1+i*OUTPUT_CHANNELS1,
OUTPUT_CHANNELS1,
audiobuf2+i*OUTPUT_CHANNELS2,
OUTPUT_CHANNELS2);
-
+
/* this is a calculated race; the race would not trip except in
situations where our locking latency would also cause the
realtime house of cards to come crashing down anyway */
pthread_cond_signal(&cache_cond);
+
+#if (OUTPUT_CHANNELS1)
+ {
+ int frames=0;
-#if (OUTPUT_CHANNELS1)
- fwrite(audiobuf1,2*OUTPUT_CHANNELS1,256,playfd1);
+ while(frames<buffersize){
+ ret = snd_pcm_writei (playhandle1,audiobuf1+frames*channels1,buffersize-frames);
+ if(ret<0){
+ // most likely an underrun
+ switch(ret){
+ case -EAGAIN:
+ break;
+ case -EPIPE: case -ESTRPIPE:
+ // underrun; set starve and reset soft device
+ playback_buffer_starve=1;
+ snd_pcm_drop(playhandle1);
+ snd_pcm_prepare(playhandle1);
+ frames=0; // start this frame over such that both channels are in sync
+
+ break;
+ case -EBADFD:
+ default:
+ // "well, shit." Don't hose the machine here in a realtime thread
+ frames=buffersize;
+ playback_exit=1;
+ fprintf (stderr, "playback1 write error (%s)\n",
+ snd_strerror (ret));
+ break;
+ }
+ }else{
+ frames+=ret;
+ }
+ }
+ }
#endif
#if (OUTPUT_CHANNELS2)
- fwrite(audiobuf2,2*OUTPUT_CHANNELS2,256,playfd2);
+ {
+ int frames=0;
+
+ while(frames<buffersize){
+ ret = snd_pcm_writei (playhandle2,audiobuf2+frames*channels2,buffersize-frames);
+ if(ret<0){
+ // most likely an underrun
+ switch(ret){
+ case -EAGAIN:
+ break;
+ case -EPIPE: case -ESTRPIPE:
+ // underrun; set starve and reset soft device
+ playback_buffer_starve=1;
+#if(OUTPUT_CHANNELS1)
+ snd_pcm_drop(playhandle1); // operate on linked interface
+ snd_pcm_prepare(playhandle1);
+#else
+ snd_pcm_drop(playhandle2);
+ snd_pcm_prepare(playhandle2);
#endif
+ frames=buffersize; // abort this frame such that both channels are in sync
+ break;
+ case -EBADFD:
+ default:
+ // "well, shit." Don't hose the machine here in a realtime thread
+ frames=buffersize;
+ playback_exit=1;
+ fprintf (stderr, "playback2 write error (%s)\n",
+ snd_strerror (ret));
+ break;
+ }
+ }else{
+ frames+=ret;
+ }
+ }
+ }
+#endif
{
struct timeval tv;
@@ -1660,10 +2016,10 @@
/* sound device shutdown */
#if (OUTPUT_CHANNELS1)
- ioctl(fd1,SNDCTL_DSP_RESET);
+ snd_pcm_drop (playhandle1);
#endif
#if (OUTPUT_CHANNELS2)
- ioctl(fd2,SNDCTL_DSP_RESET);
+ snd_pcm_drop (playhandle2);
#endif
fprintf(stderr,"Playback thread exit...\n");
return(NULL);
@@ -2169,8 +2525,9 @@
n=playback_buffer_minfill;
playback_buffer_minfill=playback_bufsize;
- if(n==0){
- starve=15;
+ if(playback_buffer_starve){ // get this from the HW interface now
+ starve=45;
+ playback_buffer_starve=0;
}
starve--;
if(starve<0){
@@ -2220,8 +2577,9 @@
rec_buffer_dma_min=100;
pthread_mutex_unlock(&rec_mutex);
- if(nr==0){
- starver1=15;
+ if(rec_dmabuffer_starve){
+ starver1=45;
+ rec_dmabuffer_starve=0;
}
starver1--;
if(starver1<0){
@@ -3413,7 +3771,7 @@
}
int main(int gratuitously,char *different[]){
- int lf;
+ int lf,err;
if(gratuitously<2){
fprintf(stderr,"Usage: beaverphonic <settingfile>\n");
@@ -3436,36 +3794,32 @@
}
#if (OUTPUT_CHANNELS1)
- playfd1=fopen(playdevice1,"wb");
- if(!playfd1){
- fprintf(stderr,"unable to open audio device 1 for playback: %s.\n",strerror(errno));
+ if ((err = snd_pcm_open (&playhandle1, playdevice1, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
+ fprintf(stderr,"unable to open audio device 1 for playback: %s.\n",snd_strerror(err));
fprintf(stderr,"\nPress enter to continue\n");
getc(stdin);
}
#endif
#if (OUTPUT_CHANNELS2)
- playfd2=fopen(playdevice2,"wb");
- if(!playfd2){
- fprintf(stderr,"unable to open audio device 2 for playback: %s.\n",strerror(errno));
+ if ((err = snd_pcm_open (&playhandle2, playdevice2, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
+ fprintf(stderr,"unable to open audio device 2 for playback: %s.\n",snd_strerror(err));
fprintf(stderr,"\nPress enter to continue\n");
getc(stdin);
}
#endif
#if (INPUT_CHANNELS1)
- recfd1=fopen(recdevice1,"rb");
- if(!recfd1){
- fprintf(stderr,"unable to open audio device 1 for record: %s.\n",strerror(errno));
+ if ((err = snd_pcm_open (&rechandle1, recdevice1, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
+ fprintf(stderr,"unable to open audio device 1 for record: %s.\n",snd_strerror(err));
fprintf(stderr,"\nPress enter to continue\n");
getc(stdin);
}
#endif
#if (INPUT_CHANNELS2)
- recfd2=fopen(recdevice2,"rb");
- if(!recfd2){
- fprintf(stderr,"unable to open audio device 2 for record: %s.\n",strerror(errno));
+ if ((err = snd_pcm_open (&rechandle2, recdevice2, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
+ fprintf(stderr,"unable to open audio device 2 for record: %s.\n",snd_strerror(err));
fprintf(stderr,"\nPress enter to continue\n");
getc(stdin);
}
@@ -3565,16 +3919,16 @@
}
#if (OUTPUT_CHANNELS1)
- fclose(playfd1);
+ snd_pcm_close(playhandle1);
#endif
#if (OUTPUT_CHANNELS2)
- fclose(playfd2);
+ snd_pcm_close(playhandle2);
#endif
#if (INPUT_CHANNELS1)
- fclose(recfd1);
+ snd_pcm_close(rechandle1);
#endif
#if (INPUT_CHANNELS2)
- fclose(recfd2);
+ snd_pcm_close(rechandle2);
#endif
unlink(lockfile);
return 0;
More information about the commits
mailing list