On Thu, 17 Jul 2003, Carlo Wood wrote: > On Tue, Jul 15, 2003 at 08:31:50PM +0200, Jaroslav Kysela wrote: > > I looked to the problem and it seems that the overrun state is handled > > differently in the OSS API than ALSA implemented. It seems that the stream > > is not stopped but rather the oldest period (fragment) is discarded. > > > > The new code (plus some optimization) is in the ALSA CVS tree. The patch > > is attached to this e-mail. > > This patch does not solve the problem. > As soon as the buffers runs exactly full - which is now a coincidence, > but happens reasonable quickly, the alsa layer detects an "overrun" > and stops the stream.
Nope. Your test code is buggy. If you have 2 fragments per 4096 bytes and you will read samples then the ring buffer goes filled bellow 4096 bytes, then info.frags is zero, thus your loop goes very quickly to 10 iterations. I attached fixed code which adds additional wait - not very clean solution - poll() is prefered (plus commented code which sleeps 4 seconds to generate an overrun at the start). Jaroslav ----- Jaroslav Kysela <[EMAIL PROTECTED]> Linux Kernel Sound Maintainer ALSA Project, SuSE Labs
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/ioctl.h> #include <unistd.h> #include <sys/soundcard.h> #include <time.h> int main(void) { int fd; int res = 0x20009; audio_buf_info info; int prev_size = 0; do { ++res; close(fd); fd = open("/dev/dsp", O_RDONLY); if (fd == -1) { perror("open"); exit(127); } if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &res) == -1) { perror("ioctl"); exit(127); } if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) == -1) { perror("read"); exit(127); } printf(" Allocated %d buffers of %d bytes.\n", info.fragstotal, info.fragsize); if (prev_size == info.fragsize * info.fragstotal) { printf(" It seems impossible to set a recording buffer with a\n" " total size of at least 8192 bytes. This is not going\n" " to work with ViaVoice. Sorry.\n"); exit(126); } prev_size = info.fragsize * info.fragstotal; } while (prev_size < 8192); printf(" Successfully allocated a buffer that is large enough.\n"); res = AFMT_S16_LE; if (ioctl(fd, SNDCTL_DSP_SETFMT, &res) == -1) { perror("ioctl"); exit(127); } res = 0; if (ioctl(fd, SNDCTL_DSP_STEREO, &res) == -1) { perror("ioctl"); exit(127); } res = 22050; if (ioctl(fd, SOUND_PCM_READ_RATE, 0xbfffdcfc) == -1) { perror("ioctl"); exit(127); } char buf[1024]; if (read(fd, buf, sizeof(buf)) < 0) { perror("read"); exit(127); } static struct timespec naptime = { 0, 100000000 }; #if 1 do { if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) == -1) { perror("read"); exit(127); } printf(" Available bytes: %d\n", info.bytes); nanosleep(&naptime, 0); } while(info.bytes < info.fragsize * info.fragstotal); #else sleep(4); if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) == -1) { perror("read"); exit(127); } #endif printf(" Successfully caused an xrun.\n"); printf(" non-blocking fragments: %d\n", info.fragments); printf(" non-blocking bytes: %d\n", info.bytes); ssize_t bufsize = info.bytes; if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) == -1) { perror("read"); exit(127); } ssize_t trlen = 0; int nf = 0; for (;;) { printf(" Available bytes in buffer: %d (frags %d)\n", info.bytes, info.fragments); if (info.fragments > 0) { ssize_t rlen; if ((rlen = read(fd, buf, sizeof(buf))) < 0) { perror("read"); exit(127); } printf(" Additionally read %d bytes.\n", rlen); trlen += rlen; if (trlen > bufsize) { printf(" Read %d bytes: stream successfully restarted.\n", trlen); break; } nf = 0; } else if (++nf > 10) { printf(" Stream is not restarted after xrun.\n"); exit(1); } else { usleep(100000); } if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) == -1) { perror("read"); exit(127); } } close(fd); return 0; }