Hi all

> > I did this last night.  The following is my analysis of the problem.
> > With full debug selected, the only message reported by the ALSA system is
> >   ALSA ../alsa-kernel/core/pcm_timer.c:70: BUG? (rate != 0) 
> >   (called from d8c33a79)
> > That is, the assertion "rate!=0" fails.  This confirms the reported oops
> > trigger (that is, divide by zero).
> 
> Could you add exactly same initialization sequence to 
> alsa-oss/test/testoss.c code? So we can debug easily the problem here.

Sorry, I couldn't see where this would fit in in this file - testoss.c seems
more like it's testing the oss redirector though.  The bug I'm seeing is in
software which uses the oss emulation layer directly (that is, it accesses
/dev/dsp with no knowledge of ALSA).

To this end I've hacked up the following small C program which triggers the
fault (see the end of this email).  It essentially contains the exact same
initialisation sequence used in cinelerra 1.1.9.  In developing this program
I've made some more potentially interesting observations.

The divide by zero in snd_pcm_timer_resolution_change() is always triggered
by the SNDCTL_DSP_SETFMT ioctl following the SNDCTL_DSP_SETFRAGMENT. 
However, not all arguments to SNDCTL_DSP_SETFRAGMENT cause a problem.
The argument to SNDCTL_DSP_SETFRAGMENT is set to 
  (4 << 16) | XX
where XX is some number indicating the size of the buffer.  If XX<=14 then
ALSA works fine.  If, however, XX is 15 or greater we get the divide by zero
in snd_pcm_timer_resolution_change() during the following SNDCTL_DSP_SETFMT
call.

In cinelerra the default settings result in XX being set to 16 which is why
this application triggers the bug.  Other OSS applications either never call
the SNDCTL_DSP_SETFRAGMENT ioctl OR call it with smaller buffer sizes.

This program's output with ALSA when XX==16 (with alsa debug mode preventing
divide by zero):
   params: fragments=2 fragstotal=2 fragsize=32768 bytes=65536
Output with ALSA when XX==14:
   params: fragments=4 fragstotal=4 fragsize=16384 bytes=65536

Output with OSS when XX==16:
   fragments=4 fragstotal=4 fragsize=32768 bytes=131072
Output with OSS when XX==14:
   fragments=4 fragstotal=4 fragsize=16384 bytes=65536

Note that the bug has been observed when using an Ensoniq AudioPCI card with
the ens1370 ALSA driver.

I hope this is of assistance.
  jonathan

/*
 * This is a small program to illustrate a problem with the OSS emulation
 * in ALSA driver 1.0.2c.  The initialisation sequence herein causes
 * a divide by zero in snd_pcm_timer_resolution_change().  More particularly,
 * the SNDCTL_DSP_SETFRAGMENT ioctl call has a side effect which causes
 * the divide by zero when SNDCTL_DSP_SETFMT is called.
 *
 * buffer_info = (4 << 16) | XX;
 * If XX is 16 the fault is triggered.  If XX is 14 everything's fine.
 * In general, if XX<=14 everything works, but XX>=15 triggers the bug.
 *
 * Compile with
 *   gcc -o test_alsa_oss{,.c}
 *
 * The bug has been observed when using the ens1370 driver.  It's not known
 * whether it is triggered with other soundcards/drivers.
 *
 * Note: Cinelerra's default configuration has 16384 samples in the buffer -
 * this makes XX equal to 16, thus triggering the bug.
 *
 */
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/soundcard.h>

int set_cloexec_flag(int desc, int value) {
  int oldflags = fcntl (desc, F_GETFD, 0);
  if (oldflags < 0) return oldflags;
  if(value != 0)
    oldflags |= FD_CLOEXEC;
  else
    oldflags &= ~FD_CLOEXEC;
  return fcntl(desc, F_SETFD, oldflags);
}

int main() {

int fd;
int format = AFMT_S16_LE;
int buffer_info = (4 << 16) | 16;
int res, arg;
audio_buf_info playinfo;

  fd = open("/dev/dsp", O_WRONLY);
  if (fd<1) {
    fprintf(stderr,"open() failed on /dev/dsp\n");
    return 1;
  } else {
    printf("open(): fd = %d\n",fd);
  }

  if (set_cloexec_flag(fd,1)<0) {
    printf("failed to set close-on-exec flag\n");
  }

  res = ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &buffer_info);
  if (res < 0)
    printf("SNDCTL_DSP_SETFRAGMENT failed: returned %d\n",res);
  else
    printf("SNDCTL_DSP_SETFRAGMENT ok: %d\n",res); 
  res = ioctl(fd, SNDCTL_DSP_SETFMT, &format);
  if (res < 0)
    printf("SNDCTL_DSP_SETFMT failed: returned %d\n",res);
  else
    printf("SNDCTL_DSP_SETFMT ok: %d\n",res);
   
  arg = 2;
  res = ioctl(fd, SNDCTL_DSP_CHANNELS, &arg);
  if (res < 0)
    printf("SNDCTL_DSP_CHANNELS failed: returned %d\n",res);
  else
    printf("SNDCTL_DSP_CHANNELS ok: %d\n",res);
  arg = 48000;
  res = ioctl(fd, SNDCTL_DSP_SPEED, &arg);
  if (res < 0)
    printf("SNDCTL_DSP_SPEED failed: returned %d\n",res);
  else
    printf("SNDCTL_DSP_SPEED ok: %d\n",res);

  ioctl(fd, SNDCTL_DSP_GETOSPACE, &playinfo);
  printf("params: fragments=%d fragstotal=%d fragsize=%d bytes=%d\n",
    playinfo.fragments, playinfo.fragstotal, playinfo.fragsize, 
    playinfo.bytes);

  close(fd);
  return 0;
}

-- 
* Jonathan Woithe    [EMAIL PROTECTED]                        *
*                    http://www.physics.adelaide.edu.au/~jwoithe            *
***-----------------------------------------------------------------------***
** "Time is an illusion; lunchtime doubly so"                              **
*  "...you wouldn't recognize a subtle plan if it painted itself purple and *
*   danced naked on a harpsichord singing 'subtle plans are here again'"    *


-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials
Free Linux tutorial presented by Daniel Robbins, President and CEO of
GenToo technologies. Learn everything from fundamentals to system
administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
Alsa-devel mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/alsa-devel

Reply via email to