// Poll the sound playback system to see if it needs more data. We use this flag as // the clock to generate the data. IE when needs_data is true we mix some audio // and play it back. This way ALSA drives our output clock. // for pulse use system timer ? // // snd_pcm_avail returns the number of samples required to refresh the playback buffer // we simply say if has room for another 1000 then its time to stick in another 512 int sound_system_needs_data_now() { int res; int framesleft; snd_pcm_status_t *status = NULL; snd_pcm_status_alloca( &status ); // alloca allocates once per function, does not need a free if ((err=snd_pcm_status(playback_handle,status))!=0) { printf("snd_pcm_status() failed: %s",snd_strerror(err)); return; } res=snd_pcm_status_get_state(status); if (res!=SND_PCM_STATE_RUNNING) // If sound system is not running then it needs data return(TRUE); framesleft=snd_pcm_avail (playback_handle); //printf("res=%d FL=%d\n",res,framesleft); fflush(stdout); if (framesleft>1000) return(TRUE); else return(FALSE); } playsample(short int *bufptr, int bufsize) { // pcm_writen takes argument "bufs" bufs is an array of pointers (to pointers!) one per channel // we only have 1 channel so //short int *mybufptr=(short int*)&bufptr; void *bufs[2] = { NULL , NULL }; // Allocate two (bufs[0],bufs[1]) but we only user lowest one for now short int interleaved_sample_buffer[8192]; // bigger than we will ever use int numrecs; numrecs=bufsize/2; // audio buffer size bytes, 16 bit words is half this value int err; int retry_overrun; bufs[0]=(void *)bufptr; // Set the pointer array element zero to pointer bufptr ie **data retry_overrun=1; // Retry writes rejected due to overrun (buffer full) if (alsa_insists_on_stereo==TRUE) { // Just to be awkward alsa insists we use stereo on this device, use writei instead // munge mono into interleaved stero by copying each sample twice int x; int y; y=0; for (x=0;x0) { fprintf (stderr, "snd_pcm_writei: wrote only %d\n",err); fflush(stderr); } else { if (err == -32) // if broken pipe -32 { soundoutput_underruns++; int errb; errb=snd_pcm_recover(playback_handle,err,0); // error passed is resullt of writen if (errb<0) { fprintf(stderr,"Failed to recover from underrun\n"); fflush(stderr); exit(1); } else printf("RECOVER!"); } else { soundoutput_overruns++; fprintf (stderr, "snd_pcm_writei: write to audio interface failed (%s) (%d)\n", snd_strerror (err),err); fflush(stdout); fflush(stderr); if (err !=-11) exit (1); } } } } else { // Write mono (non interleaved) audio printf("A"); writen: err = snd_pcm_writen (playback_handle, bufs, numrecs); // write NON interleaved, returns 0 if all was happy if (err0) { fprintf (stderr, "snd_pcm_writen: wrote only %d\n",err); fflush(stderr); } else { if (err == -32) // if broken pipe -32 { soundoutput_underruns++; int errb; printf("RECOVER!"); fflush(stdout); errb=snd_pcm_recover(playback_handle,err,0); // error passed is resullt of writen if (errb<0) { fprintf(stderr,"Failed to recover from underrun\n"); fflush(stderr); exit(1); } } else { // At this point we are simply early, keep trying a few times with a bit of snooze inbetween soundoutput_overruns++; fprintf (stderr, "snd_pcm_writen: write to audio interface failed (%s) (%d)\n", snd_strerror (err),err); fflush(stdout); fflush(stderr); if (err !=-11) exit (1); else { if (retry_overrun==0) return(0); // Done N retries, give up ! retry_overrun--; usleep(1000); // ask for 10ms zzzz, best we can do without hires timers goto writen; } } } } } fflush(stdout); }