Fredrik Nilsson wrote: > On Thu, 2004-04-08 at 16:07, Clemens Ladisch wrote: > > Fredrik Nilsson wrote: > > > The music plays well in the beginning but after about 3 hours and > > > twenty minutes noise (small interrupts) is heard in the sound > > > every second. > > > > At 3:22:54 with 16-bit stereo data at 44100 Hz, the number of bytes > > played reaches 2^31. Apparently, some counter is interpreted as a > > signed quantity and becomes negative.
This is a bug in ALSA's OSS emulation, it indeed does return a negative value when the byte counter overflows. I've attached patches that reset the byte counter to zero after one hour (this is the same behaviour as in the commercial OSS drivers). (You don't need to apply the patch for the alsa-oss package if you don't use aoss.) For testing, you can change the number of seconds before wraparound (3600) in pcm_oss.c to a lower value. > I have now managed to reproduce the error on a system using OSS instead > of ALSA, again with ogg123. All OSS drivers in the kernel (except via82cxxx) have the same bug. > I also did a test run with MPlayer 1.0pre3-3.2.3 (both mplayer and > ogg123 uses libao) on the oss system and over 7 hours later I > hadn't heard any noise at all. Apparently, MPlayer doesn't use the byte counter, or works around this widespread bug. HTH Clemens
diff -urN alsaold/alsa-kernel/core/oss/pcm_oss.c alsa/alsa-kernel/core/oss/pcm_oss.c --- alsaold/alsa-kernel/core/oss/pcm_oss.c Thu Apr 8 14:05:33 2004 +++ alsa/alsa-kernel/core/oss/pcm_oss.c Mon Apr 12 23:03:20 2004 @@ -525,6 +525,9 @@ runtime->oss.period_frames = snd_pcm_alsa_frames(substream, oss_period_size); + n = oss_buffer_size / oss_frame_size; + runtime->oss.boundary = (runtime->oss.rate * 3600) / n * n; + err = 0; failure: if (sw_params) @@ -571,6 +574,8 @@ } runtime->oss.prepare = 0; runtime->oss.prev_hw_ptr_interrupt = 0; + runtime->oss.hw_ptr = 0; + runtime->oss.prev_hw_ptr = 0; runtime->oss.period_ptr = 0; runtime->oss.buffer_used = 0; @@ -835,7 +840,6 @@ tmp = snd_pcm_oss_write2(substream, runtime->oss.buffer, runtime->oss.buffer_used, 1); if (tmp <= 0) return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; - runtime->oss.bytes += tmp; runtime->oss.buffer_used = 0; runtime->oss.period_ptr += tmp; runtime->oss.period_ptr %= runtime->oss.period_bytes; @@ -844,7 +848,6 @@ tmp = snd_pcm_oss_write2(substream, (char *)buf, runtime->oss.period_bytes, 0); if (tmp <= 0) return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; - runtime->oss.bytes += tmp; buf += tmp; bytes -= tmp; xfer += tmp; @@ -900,7 +903,6 @@ tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1); if (tmp <= 0) return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; - runtime->oss.bytes += tmp; runtime->oss.period_ptr = tmp; runtime->oss.buffer_used = tmp; } @@ -917,7 +919,6 @@ tmp = snd_pcm_oss_read2(substream, (char *)buf, runtime->oss.period_bytes, 0); if (tmp <= 0) return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; - runtime->oss.bytes += tmp; buf += tmp; bytes -= tmp; xfer += tmp; @@ -1472,7 +1473,7 @@ { snd_pcm_substream_t *substream; snd_pcm_runtime_t *runtime; - snd_pcm_sframes_t delay; + snd_pcm_sframes_t delay, n; int fixup; struct count_info info; int err; @@ -1507,8 +1508,14 @@ if (err < 0) return err; info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); + n = runtime->status->hw_ptr - runtime->oss.prev_hw_ptr; + if (n < 0) + n += runtime->boundary; + runtime->oss.hw_ptr += n; + runtime->oss.hw_ptr %= runtime->oss.boundary; + runtime->oss.prev_hw_ptr = runtime->status->hw_ptr; + info.bytes = snd_pcm_oss_bytes(substream, runtime->oss.hw_ptr) & INT_MAX; if (atomic_read(&runtime->mmap_count)) { - snd_pcm_sframes_t n; n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt; if (n < 0) n += runtime->boundary; @@ -1516,14 +1523,9 @@ runtime->oss.prev_hw_ptr_interrupt = delay; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) snd_pcm_oss_simulate_fill(substream, delay); - info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr); } else { delay = snd_pcm_oss_bytes(substream, delay) + fixup; info.blocks = delay / runtime->oss.period_bytes; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - info.bytes = runtime->oss.bytes - delay; - else - info.bytes = runtime->oss.bytes + delay; } if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; diff -urN alsaold/alsa-kernel/core/pcm.c alsa/alsa-kernel/core/pcm.c --- alsaold/alsa-kernel/core/pcm.c Mon Mar 22 21:49:50 2004 +++ alsa/alsa-kernel/core/pcm.c Mon Apr 12 23:11:41 2004 @@ -359,6 +359,11 @@ snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold); snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size); snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary); +#if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) + if (substream->oss.oss) { + snd_iprintf(buffer, "OSS boundary: %u\n", runtime->oss.boundary); + } +#endif snd_pcm_stream_unlock_irq(substream); } diff -urN alsaold/alsa-kernel/include/pcm_oss.h alsa/alsa-kernel/include/pcm_oss.h --- alsaold/alsa-kernel/include/pcm_oss.h Tue Feb 17 15:51:09 2004 +++ alsa/alsa-kernel/include/pcm_oss.h Mon Apr 12 23:28:58 2004 @@ -54,13 +54,15 @@ size_t period_ptr; /* actual write pointer to period */ unsigned int periods; size_t buffer_bytes; /* requested buffer size */ - size_t bytes; /* total # bytes processed */ size_t mmap_bytes; char *buffer; /* vmallocated period */ size_t buffer_used; /* used length from period buffer */ snd_pcm_plugin_t *plugin_first; snd_pcm_plugin_t *plugin_last; unsigned int prev_hw_ptr_interrupt; + snd_pcm_uframes_t hw_ptr; + snd_pcm_uframes_t prev_hw_ptr; + unsigned int boundary; } snd_pcm_oss_runtime_t; typedef struct _snd_pcm_oss_file {
diff -urN -X alsa-d/Xo alsaold/alsa-oss/alsa/pcm.c alsa/alsa-oss/alsa/pcm.c --- alsaold/alsa-oss/alsa/pcm.c Mon Mar 29 09:48:31 2004 +++ alsa/alsa-oss/alsa/pcm.c Sat Apr 10 22:27:57 2004 @@ -351,7 +351,7 @@ } } str->oss.hw_bytes = 0; - str->oss.boundary = (0x3fffffff / str->oss.buffer_size) * str->oss.buffer_size; + str->oss.boundary = (rate * 3600 / str->oss.buffer_size) * str->oss.buffer_size; str->alsa.appl_ptr = 0; str->alsa.old_hw_ptr = 0; str->mmap_advance = str->oss.period_size; @@ -1149,8 +1149,8 @@ diff += str->alsa.boundary; str->oss.hw_bytes += diff; str->oss.hw_bytes %= str->oss.boundary; - info->bytes = str->oss.hw_bytes * str->frame_bytes; - info->ptr = info->bytes % (str->oss.buffer_size * str->frame_bytes); + info->bytes = (str->oss.hw_bytes * str->frame_bytes) & 0x7fffffff; + info->ptr = (str->oss.hw_bytes % str->oss.buffer_size) * str->frame_bytes; if (str->mmap_buffer) { ssize_t n = (hw_ptr / str->oss.period_size) - (str->alsa.old_hw_ptr / str->oss.period_size); if (n < 0) @@ -1192,8 +1192,8 @@ diff += str->alsa.boundary; str->oss.hw_bytes += diff; str->oss.hw_bytes %= str->oss.boundary; - info->bytes = str->oss.hw_bytes * str->frame_bytes; - info->ptr = info->bytes % (str->oss.buffer_size * str->frame_bytes); + info->bytes = (str->oss.hw_bytes * str->frame_bytes) & 0x7fffffff; + info->ptr = (str->oss.hw_bytes % str->oss.buffer_size) * str->frame_bytes; if (str->mmap_buffer) { ssize_t n = (hw_ptr / str->oss.period_size) - (str->alsa.old_hw_ptr / str->oss.period_size); if (n < 0)