Re: audigy LS



On Sun, 29 Jan 2006, danny van elsen wrote:

hi Tim,

yes , other applications do work: xine, mplayer, rhtythmbox, ...

(only the flashplayer plugin for mozilla doesn't produce sound, but that seems to be a known limitation ...)

greetings, D.

ok, we can try debugging the exact setup steps required on your machine if
you want. for that, take dsptest1.c, compile it:
$ gcc -Wall -O2 -g `pkg-config --cflags --libs glib-2.0` dsptest1.c -o dsptest1
and run it on your machine, giving it your sound device:
$ ./dsptest1 /dev/dsp OSS: setup: w=1 r=1 n_channels=2 mix_freq=44100 queue=2205 nfrags=117 fsize=128 bufsz=14976
open(/dev/dsp) result: Everything went well

that way we can figure:
a) if it fails for you
b) the next thing will be to figure *where* it fails for you
c) what to do to fix sound driver initialization for you


---
ciaoTJ
#include        <sys/soundcard.h>
// #include        <soundcard.h>
#include        <sys/ioctl.h>
#include        <sys/types.h>
#include        <sys/time.h>
#include        <unistd.h>
#include        <string.h>
#include        <errno.h>
#include        <fcntl.h>
#include        <stdio.h>
#include        <stdlib.h>
#include <glib.h>

#define _(x) x

#if     G_BYTE_ORDER == G_LITTLE_ENDIAN
#define AFMT_S16_HE     AFMT_S16_LE
#elif   G_BYTE_ORDER == G_BIG_ENDIAN
#define AFMT_S16_HE     AFMT_S16_BE
#else
#error  unsupported byte order in G_BYTE_ORDER
#endif


typedef enum
{
  BSE_ERROR_NONE		= 0,
  BSE_ERROR_INTERNAL,
  BSE_ERROR_UNKNOWN,
  /* general errors */
  BSE_ERROR_IO,
  BSE_ERROR_PERMS,
  /* file errors */
  BSE_ERROR_FILE_BUSY,
  BSE_ERROR_FILE_EXISTS,
  BSE_ERROR_FILE_EOF,
  BSE_ERROR_FILE_EMPTY,
  BSE_ERROR_FILE_NOT_FOUND,
  BSE_ERROR_FILE_IS_DIR,
  BSE_ERROR_FILE_OPEN_FAILED,
  BSE_ERROR_FILE_SEEK_FAILED,
  BSE_ERROR_FILE_READ_FAILED,
  BSE_ERROR_FILE_WRITE_FAILED,
  /* out of resource conditions */
  BSE_ERROR_MANY_FILES,
  BSE_ERROR_NO_FILES,
  BSE_ERROR_NO_SPACE,
  BSE_ERROR_NO_MEMORY,
  /* content errors */
  BSE_ERROR_NO_HEADER,
  BSE_ERROR_NO_SEEK_INFO,
  BSE_ERROR_NO_DATA,
  BSE_ERROR_DATA_CORRUPT,
  BSE_ERROR_WRONG_N_CHANNELS,
  BSE_ERROR_FORMAT_INVALID,
  BSE_ERROR_FORMAT_UNKNOWN,
  BSE_ERROR_DATA_UNMATCHED,
  /* miscellaneous errors */
  BSE_ERROR_TEMP,
  BSE_ERROR_WAVE_NOT_FOUND,
  BSE_ERROR_CODEC_FAILURE,
  BSE_ERROR_UNIMPLEMENTED,
  BSE_ERROR_INVALID_PROPERTY,
  BSE_ERROR_INVALID_MIDI_CONTROL,
  BSE_ERROR_PARSE_ERROR,
  BSE_ERROR_SPAWN,
  /* Device errors */
  BSE_ERROR_DEVICE_NOT_AVAILABLE,
  BSE_ERROR_DEVICE_ASYNC,
  BSE_ERROR_DEVICE_BUSY,
  BSE_ERROR_DEVICE_FORMAT,
  BSE_ERROR_DEVICE_BUFFER,
  BSE_ERROR_DEVICE_LATENCY,
  BSE_ERROR_DEVICE_CHANNELS,
  BSE_ERROR_DEVICE_FREQUENCY,
  BSE_ERROR_DEVICES_MISMATCH,
  /* BseSource errors */
  BSE_ERROR_SOURCE_NO_SUCH_MODULE,
  BSE_ERROR_SOURCE_NO_SUCH_ICHANNEL,
  BSE_ERROR_SOURCE_NO_SUCH_OCHANNEL,
  BSE_ERROR_SOURCE_NO_SUCH_CONNECTION,
  BSE_ERROR_SOURCE_PRIVATE_ICHANNEL,
  BSE_ERROR_SOURCE_ICHANNEL_IN_USE,
  BSE_ERROR_SOURCE_CHANNELS_CONNECTED,
  BSE_ERROR_SOURCE_CONNECTION_INVALID,
  BSE_ERROR_SOURCE_PARENT_MISMATCH,
  BSE_ERROR_SOURCE_BAD_LOOPBACK,
  BSE_ERROR_SOURCE_BUSY,
  BSE_ERROR_SOURCE_TYPE_INVALID,
  /* BseProcedure errors */
  BSE_ERROR_PROC_NOT_FOUND,
  BSE_ERROR_PROC_BUSY,
  BSE_ERROR_PROC_PARAM_INVAL,
  BSE_ERROR_PROC_EXECUTION,
  BSE_ERROR_PROC_ABORT,
  /* various procedure errors */
  BSE_ERROR_NO_ENTRY,
  BSE_ERROR_NO_EVENT,
  BSE_ERROR_NO_TARGET,
  BSE_ERROR_NOT_OWNER,
  BSE_ERROR_INVALID_OFFSET,
  BSE_ERROR_INVALID_DURATION,
  BSE_ERROR_INVALID_OVERLAP,
} BseErrorType;

const gchar*
bse_error_blurb (BseErrorType error_value)
{
  switch (error_value)
    {
    case BSE_ERROR_NONE:                        return _("Everything went well");
    case BSE_ERROR_INTERNAL:                    return _("Internal error (please report)");
    case BSE_ERROR_UNKNOWN:                     return _("Unknown error");
    case BSE_ERROR_IO:                          return _("Input/output error");
    case BSE_ERROR_PERMS:                       return _("Insufficient permission");
      /* file errors */
    case BSE_ERROR_FILE_BUSY:                   return _("Device or resource busy");
    case BSE_ERROR_FILE_EXISTS:                 return _("File exists already");
    case BSE_ERROR_FILE_EOF:                    return _("Premature EOF");
    case BSE_ERROR_FILE_EMPTY:                  return _("File empty");
    case BSE_ERROR_FILE_NOT_FOUND:              return _("No such file, device or directory");
    case BSE_ERROR_FILE_IS_DIR:                 return _("Is a directory");
    case BSE_ERROR_FILE_OPEN_FAILED:            return _("Open failed");
    case BSE_ERROR_FILE_SEEK_FAILED:            return _("Seek failed");
    case BSE_ERROR_FILE_READ_FAILED:            return _("Read failed");
    case BSE_ERROR_FILE_WRITE_FAILED:           return _("Write failed");
      /* out of resource conditions */
    case BSE_ERROR_MANY_FILES:                  return _("Too many open files");
    case BSE_ERROR_NO_FILES:                    return _("Too many open files in system");
    case BSE_ERROR_NO_SPACE:                    return _("No space left on device");
    case BSE_ERROR_NO_MEMORY:                   return _("Out of memory");
      /* content errors */
    case BSE_ERROR_NO_HEADER:                   return _("Failed to detect (start of) header");
    case BSE_ERROR_NO_SEEK_INFO:                return _("Failed to retrieve seek information");
    case BSE_ERROR_NO_DATA:                     return _("No data available");
    case BSE_ERROR_DATA_CORRUPT:                return _("Data corrupt");
    case BSE_ERROR_WRONG_N_CHANNELS:            return _("Wrong number of channels");
    case BSE_ERROR_FORMAT_INVALID:              return _("Invalid format");
    case BSE_ERROR_FORMAT_UNKNOWN:              return _("Unknown format");
    case BSE_ERROR_DATA_UNMATCHED:              return _("Requested data values unmatched");
      /* miscellaneous errors */
    case BSE_ERROR_TEMP:                        return _("Temporary error");
    case BSE_ERROR_WAVE_NOT_FOUND:              return _("No such wave");
    case BSE_ERROR_CODEC_FAILURE:               return _("CODEC failure");
    case BSE_ERROR_UNIMPLEMENTED:		return _("Functionality not implemented");
    case BSE_ERROR_INVALID_PROPERTY:	        return _("Invalid object property");
    case BSE_ERROR_INVALID_MIDI_CONTROL:	return _("Invalid MIDI control type");
    case BSE_ERROR_PARSE_ERROR:			return _("Parsing error");
    case BSE_ERROR_SPAWN:			return _("Failed to spawn child process");
      /* Device errors */
    case BSE_ERROR_DEVICE_NOT_AVAILABLE:	return _("No device (driver) available");
    case BSE_ERROR_DEVICE_ASYNC:		return _("Device not async capable");
    case BSE_ERROR_DEVICE_BUSY:			return _("Device busy");
    case BSE_ERROR_DEVICE_FORMAT:               return _("Failed to configure device format");
    case BSE_ERROR_DEVICE_BUFFER:               return _("Failed to configure device buffer");
    case BSE_ERROR_DEVICE_LATENCY:              return _("Failed to configure device latency");
    case BSE_ERROR_DEVICE_CHANNELS:             return _("Failed to configure number of device channels");
    case BSE_ERROR_DEVICE_FREQUENCY:            return _("Failed to configure device frequency");
    case BSE_ERROR_DEVICES_MISMATCH:            return _("Device configurations mismatch");
      /* BseSource errors */
    case BSE_ERROR_SOURCE_NO_SUCH_MODULE:	return _("No such synthesis module");
    case BSE_ERROR_SOURCE_NO_SUCH_ICHANNEL:	return _("No such input channel");
    case BSE_ERROR_SOURCE_NO_SUCH_OCHANNEL:	return _("No such output channel");
    case BSE_ERROR_SOURCE_NO_SUCH_CONNECTION:	return _("Input/Output channels not connected");
    case BSE_ERROR_SOURCE_PRIVATE_ICHANNEL:	return _("Input channel is private");
    case BSE_ERROR_SOURCE_ICHANNEL_IN_USE:	return _("Input channel already in use");
    case BSE_ERROR_SOURCE_CHANNELS_CONNECTED:	return _("Input/Output channels already connected");
    case BSE_ERROR_SOURCE_CONNECTION_INVALID:	return _("Invalid synthesis module connection");
    case BSE_ERROR_SOURCE_PARENT_MISMATCH:	return _("Parent mismatch");
    case BSE_ERROR_SOURCE_BAD_LOOPBACK:		return _("Bad loopback");
    case BSE_ERROR_SOURCE_BUSY:			return _("Synthesis module currently busy");
    case BSE_ERROR_SOURCE_TYPE_INVALID:		return _("Invalid synthsis module type");
      /* BseProcedure errors */
    case BSE_ERROR_PROC_NOT_FOUND:		return _("No such procedure");
    case BSE_ERROR_PROC_BUSY:			return _("Procedure currently busy"); /* recursion */
    case BSE_ERROR_PROC_PARAM_INVAL:		return _("Procedure parameter invalid");
    case BSE_ERROR_PROC_EXECUTION:		return _("Procedure execution failed");
    case BSE_ERROR_PROC_ABORT:			return _("Procedure execution aborted");
      /* various procedure errors */
    case BSE_ERROR_NO_ENTRY:			return _("No such entry");
    case BSE_ERROR_NO_EVENT:			return _("No such event");
    case BSE_ERROR_NO_TARGET:			return _("No target");
    case BSE_ERROR_NOT_OWNER:			return _("Ownership mismatch");
    case BSE_ERROR_INVALID_OFFSET:		return _("Invalid offset");
    case BSE_ERROR_INVALID_DURATION:		return _("Invalid duration");
    case BSE_ERROR_INVALID_OVERLAP:		return _("Invalid overlap");
    }
  return NULL;
}

BseErrorType
gsl_error_from_errno (gint         sys_errno,
                      BseErrorType fallback)
{
  switch (sys_errno)
    {
    case 0:             return BSE_ERROR_NONE;
    case ELOOP:
    case ENAMETOOLONG:
    case ENOENT:        return BSE_ERROR_FILE_NOT_FOUND;
    case EISDIR:        return BSE_ERROR_FILE_IS_DIR;
    case EROFS:
    case EPERM:
    case EACCES:        return BSE_ERROR_PERMS;
    case ENODATA:       return BSE_ERROR_FILE_EOF;
    case ENOMEM:        return BSE_ERROR_NO_MEMORY;
    case ENOSPC:        return BSE_ERROR_NO_SPACE;
    case ENFILE:        return BSE_ERROR_NO_FILES;
    case EMFILE:        return BSE_ERROR_MANY_FILES;
    case EFBIG:
    case ESPIPE:
    case EIO:           return BSE_ERROR_IO;
    case EEXIST:        return BSE_ERROR_FILE_EXISTS;
    case ETXTBSY:
    case EBUSY:         return BSE_ERROR_FILE_BUSY;
    case EAGAIN:
    case EINTR:         return BSE_ERROR_TEMP;
    case EFAULT:        return BSE_ERROR_INTERNAL;
    case EBADF:
    case ENOTDIR:
    case ENODEV:
    case EINVAL:
    default:            return fallback;
    }
}

typedef struct _BsePcmHandle            BsePcmHandle;
struct _BsePcmHandle
{
  guint                  readable : 1;
  guint                  writable : 1;
  guint                  n_channels;    /* should be req_n_channels */
  guint                  mix_freq;      /* should be req_mix_freq within 1% tolerance */
};


typedef struct
{
  BsePcmHandle  handle;
  gint          fd;
  guint         n_frags;
  guint         frag_size;
  guint         frame_size;
  guint         queue_length;
  gint16       *frag_buf;
  guint         read_write_count;
  gboolean      needs_trigger;
  gboolean      hard_sync;
} OSSHandle;


static BseErrorType
oss_device_setup (OSSHandle *oss,
                  guint      req_queue_length)
{
  BsePcmHandle *handle = &oss->handle;
  gint fd = oss->fd;
  glong d_long;
  gint d_int;

  /* to get usable low-latency behaviour with OSS, we
   * make the device blocking, choose small fragments
   * and read() the first fragment once available.
   */
  d_long = fcntl (fd, F_GETFL);
  d_long &= ~O_NONBLOCK;
  if (fcntl (fd, F_SETFL, d_long))
    return BSE_ERROR_DEVICE_ASYNC;

  d_int = 0;
  if (ioctl (fd, SNDCTL_DSP_GETFMTS, &d_int) < 0)
    return BSE_ERROR_DEVICE_FORMAT;
  if ((d_int & AFMT_S16_HE) != AFMT_S16_HE)
    return BSE_ERROR_DEVICE_FORMAT;
  d_int = AFMT_S16_HE;
  if (ioctl (fd, SNDCTL_DSP_SETFMT, &d_int) < 0 ||
      d_int != AFMT_S16_HE)
    return BSE_ERROR_DEVICE_FORMAT;
  guint bytes_per_value = 2;
  
  d_int = handle->n_channels - 1;
  if (ioctl (fd, SNDCTL_DSP_STEREO, &d_int) < 0)
    return BSE_ERROR_DEVICE_CHANNELS;
  if (handle->n_channels != d_int + 1)
    return BSE_ERROR_DEVICE_CHANNELS;
  oss->frame_size = handle->n_channels * bytes_per_value;

  d_int = handle->mix_freq;
  if (ioctl (fd, SNDCTL_DSP_SPEED, &d_int) < 0)
    return BSE_ERROR_DEVICE_FREQUENCY;
  handle->mix_freq = d_int;
  if (MAX (d_int, handle->mix_freq) - MIN (d_int, handle->mix_freq) > handle->mix_freq / 100)
    return BSE_ERROR_DEVICE_FREQUENCY;

  /* Note: fragment = n_fragments << 16;
   *       fragment |= g_bit_storage (fragment_size - 1);
   */
  oss->frag_size = CLAMP (oss->frag_size, 128, 65536);
  oss->n_frags = CLAMP (oss->n_frags, 128, 65536);
  if (handle->readable)
    {
      /* don't allow fragments to be too large, to get
       * low latency behaviour (hack)
       */
      oss->frag_size = MIN (oss->frag_size, 512);
    }
  d_int = (oss->n_frags << 16) | g_bit_storage (oss->frag_size - 1);
  if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &d_int) < 0)
    return BSE_ERROR_DEVICE_LATENCY;
  
  d_int = 0;
  if (ioctl (fd, SNDCTL_DSP_GETBLKSIZE, &d_int) < 0 ||
      d_int < 128 || d_int > 131072 || (d_int & 1))
    return BSE_ERROR_DEVICE_BUFFER;

  audio_buf_info info = { 0, };
  if (handle->writable && ioctl (fd, SNDCTL_DSP_GETOSPACE, &info) < 0)
    return BSE_ERROR_DEVICE_BUFFER;
  else if (!handle->writable && ioctl (fd, SNDCTL_DSP_GETISPACE, &info) < 0)
    return BSE_ERROR_DEVICE_BUFFER;
  oss->n_frags = info.fragstotal;
  oss->frag_size = info.fragsize;
  oss->queue_length = info.bytes / oss->frame_size;
  if (oss->queue_length != oss->frag_size * oss->n_frags / oss->frame_size)
    {
      /* return BSE_ERROR_DEVICE_BUFFER; */
      printf ("OSS: buffer size (%d) differs from fragment space (%d)\n", info.bytes, info.fragstotal * info.fragsize);
      oss->queue_length = oss->n_frags * oss->frag_size / oss->frame_size;
    }

  if (handle->readable)
    {
      req_queue_length = MAX (req_queue_length, 3 * info.fragsize / oss->frame_size);   /* can't get better than 3 fragments */
      oss->queue_length = MIN (oss->queue_length, req_queue_length);
    }
  else  /* only writable */
    {
      /* give up on low latency for write-only handles, there's no reliable
       * way to achieve this with OSS. so we set a lower bound of enough milli
       * seconds for the latency, to not force the suer to adjust latency if
       * he catches a write-only OSS device temporarily.
       */
      req_queue_length = MIN (req_queue_length, oss->queue_length);
      oss->queue_length = CLAMP (25 * handle->mix_freq / 1000, req_queue_length, oss->queue_length);
    }

  printf ("OSS: setup: w=%d r=%d n_channels=%d mix_freq=%u queue=%u nfrags=%u fsize=%u bufsz=%u\n",
          handle->writable,
          handle->readable,
          handle->n_channels,
          handle->mix_freq,
          oss->queue_length,
          oss->n_frags,
          oss->frag_size / oss->frame_size,
          info.bytes / oss->frame_size);
  
  return BSE_ERROR_NONE;
}


#include <stdio.h>
int
main (int   argc,
      char *argv[])
{
  if (argc != 2)
    {
      printf ("usage: dsptest1.c <dsp-device>\n");
      exit (2);
    }
  char *dname = argv[1];
  gint omode = O_RDWR;
  gint fd = open (dname, omode | O_NONBLOCK, 0);                   /* open non blocking to avoid waiting for other clients */
  BseErrorType error;
  if (fd >= 0)
    {
      /* try setup */
      OSSHandle *oss = g_new0 (OSSHandle, 1);
      BsePcmHandle *handle = &oss->handle;
      /* setup request */
      handle->readable = omode == O_RDWR || omode == O_RDONLY;      /* O_RDONLY maybe defined to 0 */
      handle->writable = omode == O_RDWR || omode == O_WRONLY;
      handle->n_channels = 2;
      handle->mix_freq = 44100;
      oss->n_frags = 1024;
      oss->frag_buf = NULL;
      oss->fd = fd;
      oss->needs_trigger = TRUE;
      oss->hard_sync = FALSE;
      oss->frag_size = 2048;
      guint latency = 2205; /* in frames */
      error = oss_device_setup (oss, latency);
    }
  else
    error = gsl_error_from_errno (errno, BSE_ERROR_FILE_OPEN_FAILED);
  printf ("open(%s) result: %s\n", dname, bse_error_blurb (error));

  return 0;
}
/*
gcc -Wall -O2 -g `pkg-config --cflags --libs glib-2.0` dsptest1.c -o dsptest1
*/


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]