#include #include #include #include #include #define RATE 48000 snd_pcm_uframes_t setup(snd_pcm_t ** pcm) { snd_pcm_uframes_t bsize, psize; assert(snd_pcm_open(pcm, "default", SND_PCM_STREAM_PLAYBACK, 0) == 0); assert(snd_pcm_set_params(*pcm, SND_PCM_FORMAT_S16_LE, SND_PCM_ACCESS_RW_INTERLEAVED, 1, RATE, 1, 250000) == 0); assert(snd_pcm_get_params(*pcm, &bsize, &psize) == 0); assert(bsize / psize >= 4); return psize; } void bwrite(snd_pcm_t * pcm, snd_pcm_sframes_t towrite) { int r; char * garbage; garbage = calloc(1, towrite); r = snd_pcm_writei(pcm, garbage, towrite); free(garbage); if (r < 0) { fprintf(stderr, "bwrite error recovery\n"); snd_pcm_recover(pcm, r, 1); } } snd_pcm_sframes_t fill(snd_pcm_t * pcm) { snd_pcm_sframes_t avail; avail = snd_pcm_avail_update(pcm); if (avail < 0) { fprintf(stderr, "fill error recovery\n"); snd_pcm_recover(pcm, avail, 1); avail = snd_pcm_avail_update(pcm); } if (avail) { bwrite(pcm, avail); } return avail; } int main(int argc, char * argv[]) { snd_pcm_t * pcm; snd_pcm_uframes_t psize; int pause = 0, count = 0, recovery = 0; if (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'r') { recovery = 1; } /* set up a mono output device at RATE Hz with at least 4 periods */ psize = setup(&pcm); /* prefill sound buffers and begin playback */ fill(pcm); while (++count) { if (pause || count % 7 == 0) { fprintf(stderr, pause ? "resuming playback\n" : "pausing playback\n"); pause = !pause; snd_pcm_pause(pcm, pause); /* if resuming playback and recovery enabled, fill sound buffers */ if (recovery && !pause) { fprintf(stderr, "recovery, wrote %d frames\n", (int) fill(pcm)); } } /* if not paused, write a period of sound data */ if (!pause) { snd_pcm_sframes_t avail = snd_pcm_avail_update(pcm); bwrite(pcm, psize); fprintf(stderr, "playback, wrote %u frames (needed %d)\n", (unsigned int) psize, (int) avail); } /* sleep for half a period */ usleep(psize * 1000000 / RATE / 2); } return 0; }