All of lore.kernel.org
 help / color / mirror / Atom feed
* OSS layer doesn't ignore xruns.
@ 2003-07-15 12:01 Carlo Wood
  2003-07-15 18:31 ` Jaroslav Kysela
  0 siblings, 1 reply; 5+ messages in thread
From: Carlo Wood @ 2003-07-15 12:01 UTC (permalink / raw)
  To: alsa-devel

Is someone looking into my report please?

I did include a compilable test case, so it shouldn't
be too hard to reproduce this :/

Myself, I am using a Creative SoundBlaster Live! value,
but I think this should give the same results with any
sound card.

Using kernel 2.5.74 here.

The previous post:

On Sun, Jul 13, 2003 at 05:59:19PM +0200, Carlo Wood wrote:
> On Sun, Jul 13, 2003 at 04:38:47AM +0200, Carlo Wood wrote:
> > I wrote a patch for sound/core/oss/pcm_oss.c, that fixes the ViaVoice
> > problem.
> 
> Later I wrote a test case that still doesn't get fixed:
> 
> >a.out
>     Size of a fragment in bytes: 1024
>     Allocated fragments for buffering: 2
>     Successfully caused an xrun.
>     non-blocking fragments: 2
>     non-blocking bytes: 2048
>     Stream is not restarted after xrun.
> 
> now this is expected without my patch, but with
> the patch the stream *is* set back to a RUNNING state
> again successfully - nevertheless, snd_pcm_update_hw_ptr_interrupt
> is not called anymore.
> 
> Is there anyone who can get the following test code to work
> (by patching the ALSA kernel module, not by changing the test code! ;).
> 
> Test code:
> 
> 
> #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 = open("/dev/dsp", O_RDONLY);
>   if (fd == -1) { perror("open"); exit(127); }
>   int 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); }
>   res = 0x7fff000a;
>   if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &res) == -1) {
>     perror("ioctl"); exit(127); }
>   audio_buf_info info;
>   if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) == -1) {
>     perror("read"); exit(127); }
>   printf("    Size of a fragment in bytes: %d\n", info.fragsize);
>   printf("    Allocated fragments for buffering: %d\n", info.fragstotal);
>   char buf[1024];
>   if (read(fd, buf, sizeof(buf)) < 0) { perror("read"); exit(127); }
>   static struct timespec naptime = { 0, 100000000 };
>   int count = 0;
>   do {
>     if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) == -1) {
>       perror("read"); exit(127); }
>     nanosleep(&naptime, 0);
>     if (++count == 20) { printf("Failed to cause an xrun.\n"); exit(127); }
>   } while(info.bytes < info.fragsize * info.fragstotal);
>   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;
>   ssize_t trlen = 0;
>   int nf = 0;
>   for (;;)
>   {
>     if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) == -1) {
>       perror("ioctl"); exit(127); }
>     if (info.fragments > 0) {
>       ssize_t rlen;
>       if ((rlen = read(fd, buf, sizeof(buf))) < 0)
>       { perror("read"); exit(127); }
>       trlen += rlen;
>       if (trlen > bufsize) {
>         printf("    Read %d bytes: stream successfully restarted.\n", trlen);
> 	exit(0);
>       }
>       nf = 0;
>     }
>     else if (++nf > 10) {
>       printf("    Stream is not restarted after xrun.\n");
>       exit(1);
>     }
>   }
>   close(fd);
>   return 0;
> }
> 
> 
> Here is some debug output that I generated with added printk's:
> 
> Jul 13 17:22:27 ansset kernel: Entering snd_pcm_update_hw_ptr_interrupt
> Jul 13 17:22:27 ansset kernel: snd_pcm_update_hw_ptr_interrupt: status->hw_ptr set to 1536
> Jul 13 17:22:27 ansset kernel: snd_pcm_capture_avail: boundary = 1073741824, status->hw_ptr = 1536, control->appl_ptr = 512
> Jul 13 17:22:27 ansset kernel: Calling snd_pcm_stop, runtime->status->state = SNDRV_PCM_STATE_RUNNING
> Jul 13 17:22:27 ansset kernel: Returned from snd_pcm_stop, runtime->status->state = SNDRV_PCM_STATE_XRUN
> Jul 13 17:22:27 ansset kernel: Leaving snd_pcm_update_hw_ptr_interrupt with EPIPE
> ...
> Jul 13 17:22:27 ansset kernel: snd_pcm_oss_read3: calling snd_pcm_kernel_ioctl SNDRV_PCM_IOCTL_DRAIN
> Jul 13 17:22:27 ansset kernel: snd_pcm_capture_drain: state is SNDRV_PCM_STATE_XRUN.  Calling snd_pcm_change_state.
> Jul 13 17:22:27 ansset kernel: snd_pcm_capture_avail: boundary = 1073741824, status->hw_ptr = 1536, control->appl_ptr = 512
> Jul 13 17:22:27 ansset kernel: snd_pcm_capture_drain: Returning from snd_pcm_change_state, state is now 5
> Jul 13 17:22:27 ansset kernel: Entering snd_pcm_lib_read1
> Jul 13 17:22:27 ansset kernel: state is SNDRV_PCM_STATE_DRAINING
> Jul 13 17:22:27 ansset kernel: size = 512
> Jul 13 17:22:27 ansset kernel: snd_pcm_capture_avail: boundary = 1073741824, status->hw_ptr = 1536, control->appl_ptr = 512
> Jul 13 17:22:27 ansset kernel: Leaving snd_pcm_lib_read1; xfer = 512, err = 0
> ...
> Jul 13 17:22:27 ansset kernel: Entering snd_pcm_lib_read1
> Jul 13 17:22:27 ansset kernel: state is SNDRV_PCM_STATE_DRAINING
> Jul 13 17:22:27 ansset kernel: size = 512
> Jul 13 17:22:27 ansset kernel: snd_pcm_capture_avail: boundary = 1073741824, status->hw_ptr = 1536, control->appl_ptr = 1024
> Jul 13 17:22:27 ansset kernel: Leaving snd_pcm_lib_read1; xfer = 512, err = 0
> Jul 13 17:22:27 ansset kernel: snd_pcm_status: status->hw_ptr copied to be 1536
> Jul 13 17:22:27 ansset kernel: Calling snd_pcm_capture_avail()
> Jul 13 17:22:27 ansset kernel: snd_pcm_capture_avail: boundary = 1073741824, status->hw_ptr = 1536, control->appl_ptr = 1536
> Jul 13 17:22:27 ansset kernel: snd_pcm_capture_avail returned status->avail = 0
> Jul 13 17:22:27 ansset kernel: snd_pcm_status_user: status.avail = 0
> 
> [start of effect of my patch]
> 
> Jul 13 17:22:27 ansset kernel: snd_pcm_oss_read3: calling snd_pcm_kernel_ioctl(SNDRV_PCM_IOCTL_PREPARE)
> Jul 13 17:22:27 ansset kernel: snd_pcm_lib_ioctl_reset: status->hw_ptr set to 0
> Jul 13 17:22:27 ansset kernel: snd_pcm_oss_read3: state now SNDRV_PCM_STATE_RUNNING
> Jul 13 17:22:27 ansset kernel: snd_pcm_update_hw_ptr: status->hw_ptr set to 0
> Jul 13 17:22:27 ansset kernel: snd_pcm_capture_avail: boundary = 1073741824, status->hw_ptr = 0, control->appl_ptr = 0
> Jul 13 17:22:27 ansset kernel: snd_pcm_status: status->hw_ptr copied to be 0
> Jul 13 17:22:27 ansset kernel: snd_pcm_capture_avail: boundary = 1073741824, status->hw_ptr = 0, control->appl_ptr = 0
> Jul 13 17:22:27 ansset kernel: snd_pcm_capture_avail returned status->avail = 0
> Jul 13 17:22:27 ansset kernel: snd_pcm_status_user: status.avail = 0
> Jul 13 17:22:27 ansset kernel: space: bytes = 0, periods = 0, fragstotal = 2, fragsize = 1024
> 
> [end of patch effects]
> 
> ...
> 
> but snd_pcm_update_hw_ptr_interrupt is never called anymore,
> it only repeats
> 
> Jul 13 17:22:27 ansset kernel: snd_pcm_update_hw_ptr: status->hw_ptr set to 0
> Jul 13 17:22:27 ansset kernel: snd_pcm_capture_avail: boundary = 1073741824, status->hw_ptr = 0, control->appl_ptr = 0
> Jul 13 17:22:27 ansset kernel: snd_pcm_status: status->hw_ptr copied to be 0
> Jul 13 17:22:27 ansset kernel: Calling snd_pcm_capture_avail()
> Jul 13 17:22:27 ansset kernel: snd_pcm_capture_avail: boundary = 1073741824, status->hw_ptr = 0, control->appl_ptr = 0
> Jul 13 17:22:27 ansset kernel: snd_pcm_capture_avail returned status->avail = 0
> Jul 13 17:22:27 ansset kernel: snd_pcm_status_user: status.avail = 0
> Jul 13 17:22:27 ansset kernel: space: bytes = 0, periods = 0, fragstotal = 2, fragsize = 1024
> 
> after that.
> 
> -- 
> Carlo Wood <carlo@alinoe.com>
> 
> 
> -------------------------------------------------------
> This SF.Net email sponsored by: Parasoft
> Error proof Web apps, automate testing & more.
> Download & eval WebKing and get a free book.
> www.parasoft.com/bulletproofapps1
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/alsa-devel

-- 
Carlo Wood <carlo@alinoe.com>


-------------------------------------------------------
This SF.Net email sponsored by: Parasoft
Error proof Web apps, automate testing & more.
Download & eval WebKing and get a free book.
www.parasoft.com/bulletproofapps1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: OSS layer doesn't ignore xruns.
  2003-07-15 12:01 OSS layer doesn't ignore xruns Carlo Wood
@ 2003-07-15 18:31 ` Jaroslav Kysela
  2003-07-16  0:11   ` Carlo Wood
  2003-07-16 22:44   ` OSS layer still " Carlo Wood
  0 siblings, 2 replies; 5+ messages in thread
From: Jaroslav Kysela @ 2003-07-15 18:31 UTC (permalink / raw)
  To: Carlo Wood; +Cc: alsa-devel

[-- Attachment #1: Type: TEXT/PLAIN, Size: 793 bytes --]

On Tue, 15 Jul 2003, Carlo Wood wrote:

> Is someone looking into my report please?
> 
> I did include a compilable test case, so it shouldn't
> be too hard to reproduce this :/

Well, in case of urgent help we have something called as SuSE 
professional services. You can eventually buy our time, otherwise
you will have to wait for our free timeslot (if any).

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.

						Jaroslav

-----
Jaroslav Kysela <perex@suse.cz>
Linux Kernel Sound Maintainer
ALSA Project, SuSE Labs


[-- Attachment #2: Type: TEXT/plain, Size: 5373 bytes --]

Index: pcm_oss.c
===================================================================
RCS file: /cvsroot/alsa/alsa-kernel/core/oss/pcm_oss.c,v
retrieving revision 1.39
retrieving revision 1.41
diff -u -r1.39 -r1.41
--- pcm_oss.c	12 Jul 2003 19:21:16 -0000	1.39
+++ pcm_oss.c	15 Jul 2003 18:13:34 -0000	1.41
@@ -445,7 +445,7 @@
 	} else {
 		sw_params->start_threshold = runtime->boundary;
 	}
-	if (atomic_read(&runtime->mmap_count))
+	if (atomic_read(&runtime->mmap_count) || substream->stream == SNDRV_PCM_STREAM_CAPTURE)
 		sw_params->stop_threshold = runtime->boundary;
 	else
 		sw_params->stop_threshold = runtime->buffer_size;
@@ -570,6 +570,31 @@
 	return 0;
 }
 
+static int snd_pcm_oss_capture_position_fixup(snd_pcm_substream_t *substream, snd_pcm_sframes_t *delay)
+{
+	snd_pcm_runtime_t *runtime;
+	snd_pcm_uframes_t frames;
+	int err = 0;
+
+	while (1) {
+		err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, delay);
+		if (err < 0)
+			break;
+		runtime = substream->runtime;
+		if (*delay <= runtime->buffer_size)
+			break;
+		/* in case of overrun, skip whole periods like OSS/Linux driver does */
+		/* until avail(delay) <= buffer_size */
+		frames = (*delay - runtime->buffer_size) + runtime->period_size - 1;
+		frames /= runtime->period_size;
+		frames *= runtime->period_size;
+		err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_FORWARD, &frames);
+		if (err < 0)
+			break;
+	}
+	return err;
+}
+
 snd_pcm_sframes_t snd_pcm_oss_write3(snd_pcm_substream_t *substream, const char *ptr, snd_pcm_uframes_t frames, int in_kernel)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
@@ -608,6 +633,7 @@
 snd_pcm_sframes_t snd_pcm_oss_read3(snd_pcm_substream_t *substream, char *ptr, snd_pcm_uframes_t frames, int in_kernel)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_pcm_sframes_t delay;
 	int ret;
 	while (1) {
 		if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
@@ -626,6 +652,9 @@
 			if (ret < 0)
 				break;
 		}
+		ret = snd_pcm_oss_capture_position_fixup(substream, &delay);
+		if (ret < 0)
+			break;
 		if (in_kernel) {
 			mm_segment_t fs;
 			fs = snd_enter_user();
@@ -1335,7 +1364,7 @@
 {	
 	snd_pcm_substream_t *substream;
 	snd_pcm_runtime_t *runtime;
-	snd_pcm_status_t status;
+	snd_pcm_sframes_t delay;
 	struct count_info info;
 	int err;
 
@@ -1353,14 +1382,17 @@
 			return -EFAULT;
 		return 0;
 	}
-	memset(&status, 0, sizeof(status));
-	err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_STATUS, &status);
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &delay);
+	} else {
+		err = snd_pcm_oss_capture_position_fixup(substream, &delay);
+	}
 	if (err < 0)
 		return err;
 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		info.bytes = runtime->oss.bytes - snd_pcm_oss_bytes(substream, runtime->buffer_size - status.avail);
+		info.bytes = runtime->oss.bytes - snd_pcm_oss_bytes(substream, delay);
 	} else {
-		info.bytes = runtime->oss.bytes + snd_pcm_oss_bytes(substream, status.avail);
+		info.bytes = runtime->oss.bytes + snd_pcm_oss_bytes(substream, delay);
 	}
 	info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size);
 	if (atomic_read(&runtime->mmap_count)) {
@@ -1373,10 +1405,7 @@
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 			snd_pcm_oss_simulate_fill(substream);
 	} else {
-		if (stream == SNDRV_PCM_STREAM_PLAYBACK)
-			info.blocks = (runtime->buffer_size - status.avail) / runtime->period_size;
-		else
-			info.blocks = status.avail / runtime->period_size;
+		info.blocks = delay / runtime->period_size;
 	}
 	if (copy_to_user(_info, &info, sizeof(info)))
 		return -EFAULT;
@@ -1387,7 +1416,7 @@
 {
 	snd_pcm_substream_t *substream;
 	snd_pcm_runtime_t *runtime;
-	snd_pcm_status_t status;
+	snd_pcm_sframes_t avail;
 	struct audio_buf_info info;
 	int err;
 
@@ -1404,7 +1433,6 @@
 
 	info.fragsize = runtime->oss.period_bytes;
 	info.fragstotal = runtime->periods;
-	memset(&status, 0, sizeof(status));
 	if (runtime->oss.prepare) {
 		if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
 			info.bytes = runtime->oss.period_bytes * runtime->periods;
@@ -1414,20 +1442,18 @@
 			info.fragments = 0;
 		}
 	} else {
-		err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_STATUS, &status);
+		if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DELAY, &avail);
+			avail = runtime->buffer_size - avail;
+		} else {
+			err = snd_pcm_oss_capture_position_fixup(substream, &avail);
+		}
 		if (err < 0)
 			return err;
-		info.bytes = snd_pcm_oss_bytes(substream, status.avail);
-		info.fragments = status.avail / runtime->period_size;
+		info.bytes = snd_pcm_oss_bytes(substream, avail);
+		info.fragments = avail / runtime->period_size;
 	}
 
-#if 0
-	/* very experimental stuff to get Quake2 working */
-	runtime->oss.period = (info.periods - 1) << 16;
-	for (tmp = info.fragsize; tmp > 1; tmp >>= 1)
-		runtime->oss.period++;
-	runtime->oss.subdivision = 1;	/* disable SUBDIVIDE */
-#endif
 #ifdef OSS_DEBUG
 	printk("pcm_oss: space: bytes = %i, fragments = %i, fragstotal = %i, fragsize = %i\n", info.bytes, info.fragments, info.fragstotal, info.fragsize);
 #endif

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: OSS layer doesn't ignore xruns.
  2003-07-15 18:31 ` Jaroslav Kysela
@ 2003-07-16  0:11   ` Carlo Wood
  2003-07-16 22:44   ` OSS layer still " Carlo Wood
  1 sibling, 0 replies; 5+ messages in thread
From: Carlo Wood @ 2003-07-16  0:11 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: alsa-devel

On Tue, Jul 15, 2003 at 08:31:50PM +0200, Jaroslav Kysela wrote:
> Well, in case of urgent help we have something called as SuSE 
> professional services. You can eventually buy our time, otherwise
> you will have to wait for our free timeslot (if any).

Like you, I volunteer to code Open Source.  In my case 60 hours/week
with zero pay.  No need to rub into my face that you don't get paid.
As I said before, I am not doing this for myself.  There also wasn't
any hurry (except the deadline of the release of kernel 2.6 imho,
for which this better had be fixed) - I just wanted to know if someone
was looking into it.

> 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.

Thanks for the patch.  I couldn't have wished a better reply ;).

-- 
Carlo Wood <carlo@alinoe.com>


-------------------------------------------------------
This SF.net email is sponsored by: VM Ware
With VMware you can run multiple operating systems on a single machine.
WITHOUT REBOOTING! Mix Linux / Windows / Novell virtual machines at the
same time. Free trial click here: http://www.vmware.com/wl/offer/345/0

^ permalink raw reply	[flat|nested] 5+ messages in thread

* OSS layer still doesn't ignore xruns.
  2003-07-15 18:31 ` Jaroslav Kysela
  2003-07-16  0:11   ` Carlo Wood
@ 2003-07-16 22:44   ` Carlo Wood
  2003-07-17 10:14     ` Jaroslav Kysela
  1 sibling, 1 reply; 5+ messages in thread
From: Carlo Wood @ 2003-07-16 22:44 UTC (permalink / raw)
  To: Jaroslav Kysela; +Cc: alsa-devel

[-- Attachment #1: Type: text/plain, Size: 4637 bytes --]

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.

The stream is then still not restarted.

Attached is the source code of a slightly adjusted
test case that shows the problem.

Example output of attached test code:

>a.out
    Allocated 2 buffers of 1024 bytes.
    Allocated 2 buffers of 2048 bytes.
    Allocated 2 buffers of 4096 bytes.
    Successfully allocated a buffer that is large enough.
    Available bytes: 0
    Available bytes: 1632
    Available bytes: 3264
    Available bytes: 4896
    Available bytes: 6528
    Available bytes: 8160
    Available bytes: 5696
    Available bytes: 7328
    Available bytes: 4864
    Available bytes: 6496
    Available bytes: 8128
    Available bytes: 5664
    Available bytes: 7296
    Available bytes: 4832
    Available bytes: 6464
    Available bytes: 8096
    Available bytes: 5632
    Available bytes: 7264
    Available bytes: 4800
    Available bytes: 6432
    Available bytes: 8064
    Available bytes: 5600
    Available bytes: 7232
    Available bytes: 4768
    Available bytes: 6400
    Available bytes: 8032
    Available bytes: 5568
    Available bytes: 7200
    Available bytes: 4736
    Available bytes: 6368
    Available bytes: 8000
    Available bytes: 5536
    Available bytes: 7168
    Available bytes: 4704
    Available bytes: 6336
    Available bytes: 7968
    Available bytes: 5504
    Available bytes: 7136
    Available bytes: 4672
    Available bytes: 6304
    Available bytes: 7936
    Available bytes: 5472
    Available bytes: 7104
    Available bytes: 4640
    Available bytes: 6272
    Available bytes: 7904
    Available bytes: 5440
    Available bytes: 7072
    Available bytes: 4608
    Available bytes: 6240
    Available bytes: 7872
    Available bytes: 5408
    Available bytes: 7040
    Available bytes: 4576
    Available bytes: 6208
    Available bytes: 7840
    Available bytes: 5376
    Available bytes: 7008
    Available bytes: 4544
    Available bytes: 6176
    Available bytes: 7808
    Available bytes: 5344
    Available bytes: 6976
    Available bytes: 4512
    Available bytes: 6144
    Available bytes: 7776
    Available bytes: 5312
    Available bytes: 6944
    Available bytes: 4480
    Available bytes: 6112
    Available bytes: 7744
    Available bytes: 5280
    Available bytes: 6912
    Available bytes: 4448
    Available bytes: 6080
    Available bytes: 7712
    Available bytes: 5248
    Available bytes: 6880
    Available bytes: 4416
    Available bytes: 6048
    Available bytes: 7680
    Available bytes: 5216
    Available bytes: 6848
    Available bytes: 4384
    Available bytes: 6016
    Available bytes: 7648
    Available bytes: 5184
    Available bytes: 6816
    Available bytes: 4352
    Available bytes: 5984
    Available bytes: 7616
    Available bytes: 5152
    Available bytes: 6784
    Available bytes: 4320
    Available bytes: 5952
    Available bytes: 7584
    Available bytes: 5120
    Available bytes: 6752
    Available bytes: 4288
    Available bytes: 5920
    Available bytes: 7552
    Available bytes: 5088
    Available bytes: 6720
    Available bytes: 4256
    Available bytes: 5888
    Available bytes: 7520
    Available bytes: 5056
    Available bytes: 6688
    Available bytes: 4224
    Available bytes: 5856
    Available bytes: 7488
    Available bytes: 5024
    Available bytes: 6656
    Available bytes: 4192
    Available bytes: 5824
    Available bytes: 7456
    Available bytes: 4992
    Available bytes: 6624
    Available bytes: 4160
    Available bytes: 5792
    Available bytes: 7424
    Available bytes: 4960
    Available bytes: 6592
    Available bytes: 4128
    Available bytes: 5760
    Available bytes: 7392
    Available bytes: 4928
    Available bytes: 6560
    Available bytes: 8192
    Successfully caused an xrun.
    non-blocking fragments: 2
    non-blocking bytes: 8192
    Available bytes in buffer: 5728
    Additionally read 1024 bytes.
    Additionally read 1024 bytes.
    Additionally read 1024 bytes.
    Additionally read 1024 bytes.
    Stream is not restarted after xrun.

-- 
Carlo Wood <carlo@alinoe.com>

[-- Attachment #2: testcode.c --]
[-- Type: text/plain, Size: 2771 bytes --]

#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 = 0x7fff0009;
  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 };
  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);
  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); }
  printf("    Available bytes in buffer: %d\n", info.bytes);
  ssize_t trlen = 0;
  int nf = 0;
  for (;;)
  {
    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);
    }
    if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) == -1) {
      perror("read"); exit(127); }
  }
  close(fd);
  return 0;
}


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: OSS layer still doesn't ignore xruns.
  2003-07-16 22:44   ` OSS layer still " Carlo Wood
@ 2003-07-17 10:14     ` Jaroslav Kysela
  0 siblings, 0 replies; 5+ messages in thread
From: Jaroslav Kysela @ 2003-07-17 10:14 UTC (permalink / raw)
  To: Carlo Wood; +Cc: alsa-devel

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1176 bytes --]

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 <perex@suse.cz>
Linux Kernel Sound Maintainer
ALSA Project, SuSE Labs

[-- Attachment #2: Type: TEXT/plain, Size: 3048 bytes --]

#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;
}


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2003-07-17 10:14 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-07-15 12:01 OSS layer doesn't ignore xruns Carlo Wood
2003-07-15 18:31 ` Jaroslav Kysela
2003-07-16  0:11   ` Carlo Wood
2003-07-16 22:44   ` OSS layer still " Carlo Wood
2003-07-17 10:14     ` Jaroslav Kysela

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.