kobodl/sound/audiodev.c
Ville Lindholm dbc223eb84
Initial commit
Import existing source tree; original VCS history is no longer available.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-28 16:35:31 +03:00

188 lines
3.7 KiB
C

/*
------------------------------------------------------------
audiodev.h: Little silly audio device "class"
------------------------------------------------------------
* Copyright (C) David Olofson, 1999, 2001
* This code is released under the terms of the LGPL
*/
#include "audiodev.h"
#include "kobolog.h"
#include <stdio.h>
#ifndef HAVE_OSS
void audiodev_init(struct audiodev_t *ad)
{
log_printf(ELOG, "OSS sound output not compiled in!\n");
}
int audiodev_open(struct audiodev_t *ad)
{
return -1;
}
void audiodev_close(struct audiodev_t *ad)
{
}
#else /* HAVE_OSS */
#include <unistd.h>
#include <math.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#ifdef OSS_USE_SOUNDCARD_H
#include <soundcard.h>
#else
#include <sys/soundcard.h>
#endif
void audiodev_init(struct audiodev_t *ad)
{
ad->devicename = "/dev/dsp";
ad->mode = O_WRONLY;
ad->rate = 44100;
ad->fragmentsize = 256;
ad->fragments = 4;
ad->infd = ad->outfd = 0;
}
/* Open the audio device */
int audiodev_open(struct audiodev_t *ad)
{
int r,v;
struct audio_buf_info abinfo;
int fragmentshift;
fragmentshift=(int)floor((log(ad->fragmentsize)/log(2.0))+0.5);
if(fragmentshift < 4)
fragmentshift = 4;
log_printf(DLOG, " Fragment size: %d bytes\n", 1<<fragmentshift);
ad->outfd = ad->infd = open(ad->devicename, ad->mode | O_NONBLOCK);
if(ad->outfd < 0)
{
log_printf(ELOG, "Failed to open audio device!\n");
return -1;
}
if(!(ad->mode & O_NONBLOCK))
{
r = fcntl(ad->outfd, F_SETFL, ad->mode);
if(r < 0)
{
log_printf(ELOG, "Failed to set blocking mode!\n");
close(ad->outfd);
return -2;
}
}
r = ioctl(ad->outfd, SNDCTL_DSP_RESET, NULL);
if(r < 0)
{
log_printf(ELOG, "Failed to reset device!\n");
close(ad->outfd);
return -2;
}
/* Redundant? */
v = 16;
r = ioctl(ad->outfd, SNDCTL_DSP_SAMPLESIZE, &v);
if(r < 0)
{
log_printf(ELOG, "16 bit samples not supported!\n");
close(ad->outfd);
return -2;
}
v = AFMT_S16_LE;
r = ioctl(ad->outfd, SNDCTL_DSP_SETFMT, &v);
if(r < 0)
{
log_printf(ELOG, "Failed to set sample format!\n");
close(ad->outfd);
return -3;
}
else if(v != AFMT_S16_LE)
{
log_printf(ELOG, "16 bit stereo LE not supported!\n");
close(ad->outfd);
return -4;
}
v = 1;
r = ioctl(ad->outfd, SNDCTL_DSP_STEREO, &v);
if(r < 0)
{
log_printf(ELOG, "Stereo not supported!\n");
close(ad->outfd);
return -5;
}
v = ad->rate;
r = ioctl(ad->outfd, SNDCTL_DSP_SPEED, &v);
if(r < 0)
{
log_printf(ELOG, "Failed to set %d Hz sample rate!\n",
ad->rate);
close(ad->outfd);
return -6;
}
if(O_RDWR == ad->mode)
{
r = ioctl(ad->outfd, SNDCTL_DSP_SETDUPLEX, NULL);
if(r < 0)
{
log_printf(ELOG, "Full duplex not supported!\n");
close(ad->outfd);
return -4;
}
v = ((ad->fragments+2) << 16) | fragmentshift;
}
else
v = ((ad->fragments) << 16) | fragmentshift;
r = ioctl(ad->outfd, SNDCTL_DSP_SETFRAGMENT, &v);
if(r < 0)
{
log_printf(ELOG, "Failed to set fragment size/count!\n");
close(ad->outfd);
return -5;
}
r = ioctl(ad->outfd, SNDCTL_DSP_GETOSPACE, &abinfo);
if(r >= 0)
{
log_printf(DLOG, " Driver: fragments = %d, fragsize = %d\n",
abinfo.fragstotal,
abinfo.fragsize);
if( (abinfo.fragstotal != ad->fragments)
&& (O_RDWR != ad->mode) )
log_printf(WLOG, "Number of fragments is %d, "
"not %d as requested.\n",
abinfo.fragstotal, ad->fragments);
if(abinfo.fragsize != ad->fragmentsize)
log_printf(WLOG, "Fragment size is %d, "
"not %d as requested.\n",
abinfo.fragsize, ad->fragmentsize);
}
return 0;
}
void audiodev_close(struct audiodev_t *ad)
{
if( (ad->infd != ad->outfd) && ad->infd )
close(ad->infd);
if(ad->outfd)
close(ad->outfd);
ad->infd = ad->outfd = 0;
}
#endif /* HAVE_OSS */