Re: audigy LS
- From: Tim Janik <timj gtk org>
- To: danny van elsen <danny van elsen skynet be>
- Cc: beast gnome org
- Subject: Re: audigy LS
- Date: Fri, 10 Feb 2006 09:57:53 +0100 (CET)
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]