4fd45d6e59
- add esd flavor - don't clobber xterm title no response from maintainer; ok espie@
263 lines
5.9 KiB
C
263 lines
5.9 KiB
C
/* $OpenBSD */
|
|
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include "mpg123.h"
|
|
|
|
#include <sys/audioio.h>
|
|
|
|
static void audio_set_format_helper(int fmt, audio_info_t *ainfo);
|
|
|
|
static int audio_fd = -1;
|
|
static int uptodate = 1;
|
|
static int possible = 0;
|
|
|
|
static audio_info_t ainfo;
|
|
|
|
static void really_close_audio()
|
|
{
|
|
if (audio_fd != -1)
|
|
close(audio_fd);
|
|
}
|
|
|
|
static void really_open_audio(struct audio_info_struct *ai)
|
|
{
|
|
if (audio_fd == -1) {
|
|
audio_encoding_t cap;
|
|
|
|
if(!ai->device) {
|
|
if(getenv("AUDIODEV")) {
|
|
if(param.verbose > 1)
|
|
fprintf(stderr,"Using audio-device value from AUDIODEV environment variable!\n");
|
|
ai->device = getenv("AUDIODEV");
|
|
}
|
|
else
|
|
ai->device = "/dev/audio";
|
|
}
|
|
if ((audio_fd = open (ai->device, O_WRONLY)) == -1) {
|
|
fprintf (stderr, "Failed to open %.100s: %s\n", ai->device,
|
|
strerror (errno));
|
|
return;
|
|
}
|
|
for (cap.index = 0; ioctl(audio_fd, AUDIO_GETENC, &cap) == 0; cap.index++) {
|
|
if (cap.flags & AUDIO_ENCODINGFLAG_EMULATED)
|
|
continue;
|
|
switch(cap.encoding) {
|
|
case AUDIO_ENCODING_ULAW:
|
|
possible |= AUDIO_FORMAT_ULAW_8;
|
|
break;
|
|
case AUDIO_ENCODING_ALAW:
|
|
possible |= AUDIO_FORMAT_ALAW_8;
|
|
break;
|
|
case AUDIO_ENCODING_SLINEAR:
|
|
case AUDIO_ENCODING_SLINEAR_BE:
|
|
case AUDIO_ENCODING_SLINEAR_LE:
|
|
if (cap.precision == 8)
|
|
possible |= AUDIO_FORMAT_SIGNED_8;
|
|
else
|
|
possible |= AUDIO_FORMAT_SIGNED_16;
|
|
break;
|
|
case AUDIO_ENCODING_ULINEAR:
|
|
case AUDIO_ENCODING_ULINEAR_BE:
|
|
case AUDIO_ENCODING_ULINEAR_LE:
|
|
if (cap.precision == 8)
|
|
possible |= AUDIO_FORMAT_UNSIGNED_8;
|
|
else
|
|
possible |= AUDIO_FORMAT_UNSIGNED_16;
|
|
break;
|
|
}
|
|
}
|
|
atexit(really_close_audio);
|
|
}
|
|
}
|
|
|
|
int audio_open(struct audio_info_struct *ai)
|
|
{
|
|
really_open_audio(ai);
|
|
|
|
ai->fn = audio_fd;
|
|
if(ai->fn < 0)
|
|
return ai->fn;
|
|
|
|
AUDIO_INITINFO(&ainfo);
|
|
uptodate = 0;
|
|
{
|
|
audio_device_t ad;
|
|
if(ioctl(ai->fn, AUDIO_GETDEV, &ad) == -1)
|
|
return -1;
|
|
if(param.verbose > 1)
|
|
fprintf(stderr,"Audio device type: %s\n",ad.name);
|
|
}
|
|
|
|
if(audio_reset_parameters(ai) < 0) {
|
|
return -1;
|
|
}
|
|
|
|
if(ai->output > 0)
|
|
ainfo.play.port = 0;
|
|
if(ai->output & AUDIO_OUT_INTERNAL_SPEAKER)
|
|
ainfo.play.port |= AUDIO_SPEAKER;
|
|
if(ai->output & AUDIO_OUT_HEADPHONES)
|
|
ainfo.play.port |= AUDIO_HEADPHONE;
|
|
if(ai->output & AUDIO_OUT_LINE_OUT)
|
|
ainfo.play.port |= AUDIO_LINE_OUT;
|
|
|
|
return ai->fn;
|
|
}
|
|
|
|
int audio_reset_parameters(struct audio_info_struct *ai)
|
|
{
|
|
if(ai->rate != -1)
|
|
ainfo.play.sample_rate = ai->rate;
|
|
if(ai->channels >= 0)
|
|
ainfo.play.channels = ai->channels;
|
|
audio_set_format_helper(ai->format,&ainfo);
|
|
uptodate = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int audio_rate_best_match(struct audio_info_struct *ai)
|
|
{
|
|
audio_info_t ainfo;
|
|
|
|
ainfo.play.sample_rate = ai->rate;
|
|
if(ioctl(ai->fn, AUDIO_SETINFO, &ainfo) < 0) {
|
|
ai->rate = 0;
|
|
return 0;
|
|
}
|
|
if(ioctl(ai->fn, AUDIO_GETINFO, &ainfo) < 0) {
|
|
return -1;
|
|
}
|
|
ai->rate = ainfo.play.sample_rate;
|
|
uptodate = 1;
|
|
return 0;
|
|
}
|
|
|
|
int audio_set_rate(struct audio_info_struct *ai)
|
|
{
|
|
audio_info_t ainfo;
|
|
|
|
if(ai->rate != -1) {
|
|
ainfo.play.sample_rate = ai->rate;
|
|
uptodate = 0;
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int audio_set_channels(struct audio_info_struct *ai)
|
|
{
|
|
audio_info_t ainfo;
|
|
|
|
ainfo.play.channels = ai->channels;
|
|
uptodate = 0;
|
|
return 0;
|
|
}
|
|
|
|
static void audio_set_format_helper(int fmt, audio_info_t *ainfo)
|
|
{
|
|
switch(fmt) {
|
|
case -1:
|
|
case AUDIO_FORMAT_SIGNED_16:
|
|
default:
|
|
ainfo->play.encoding = AUDIO_ENCODING_SLINEAR;
|
|
ainfo->play.precision = 16;
|
|
break;
|
|
case AUDIO_FORMAT_UNSIGNED_16:
|
|
ainfo->play.encoding = AUDIO_ENCODING_ULINEAR;
|
|
ainfo->play.precision = 16;
|
|
break;
|
|
case AUDIO_FORMAT_UNSIGNED_8:
|
|
ainfo->play.encoding = AUDIO_ENCODING_ULINEAR;
|
|
ainfo->play.precision = 8;
|
|
break;
|
|
case AUDIO_FORMAT_SIGNED_8:
|
|
ainfo->play.encoding = AUDIO_ENCODING_SLINEAR;
|
|
ainfo->play.precision = 8;
|
|
break;
|
|
case AUDIO_FORMAT_ULAW_8:
|
|
ainfo->play.encoding = AUDIO_ENCODING_ULAW;
|
|
ainfo->play.precision = 8;
|
|
break;
|
|
case AUDIO_FORMAT_ALAW_8:
|
|
ainfo->play.encoding = AUDIO_ENCODING_ALAW;
|
|
ainfo->play.precision = 8;
|
|
break;
|
|
}
|
|
}
|
|
|
|
int audio_set_format(struct audio_info_struct *ai)
|
|
{
|
|
audio_set_format_helper(ai->format,&ainfo);
|
|
uptodate = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int try_format(int fmt, struct audio_info_struct *ai)
|
|
{
|
|
audio_info_t ainfo;
|
|
|
|
AUDIO_INITINFO(&ainfo);
|
|
|
|
audio_set_format_helper(fmt, &ainfo);
|
|
ainfo.play.sample_rate = ai->rate;
|
|
ainfo.play.channels = ai->channels;
|
|
if(ioctl(audio_fd, AUDIO_SETINFO, &ainfo) >= 0)
|
|
return fmt;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int audio_get_formats(struct audio_info_struct *ai)
|
|
{
|
|
int fmts = 0;
|
|
|
|
really_open_audio(ai);
|
|
|
|
if ((possible & AUDIO_FORMAT_SIGNED_16) == AUDIO_FORMAT_SIGNED_16)
|
|
fmts |= try_format(AUDIO_FORMAT_SIGNED_16, ai);
|
|
else if ((possible & AUDIO_FORMAT_UNSIGNED_16) == AUDIO_FORMAT_UNSIGNED_16)
|
|
fmts |= try_format(AUDIO_FORMAT_UNSIGNED_16, ai);
|
|
if ((possible & AUDIO_FORMAT_SIGNED_8) == AUDIO_FORMAT_SIGNED_8)
|
|
fmts |= try_format(AUDIO_FORMAT_SIGNED_8, ai);
|
|
else if ((possible & AUDIO_FORMAT_UNSIGNED_8) == AUDIO_FORMAT_UNSIGNED_8)
|
|
fmts |= try_format(AUDIO_FORMAT_UNSIGNED_8, ai);
|
|
if (!fmts && ((possible & AUDIO_FORMAT_ULAW_8) == AUDIO_FORMAT_ULAW_8))
|
|
fmts |= try_format(AUDIO_FORMAT_ULAW_8, ai);
|
|
if (!fmts && ((possible & AUDIO_FORMAT_ALAW_8) == AUDIO_FORMAT_ALAW_8))
|
|
fmts |= try_format(AUDIO_FORMAT_ALAW_8, ai);
|
|
return fmts;
|
|
}
|
|
|
|
|
|
int audio_play_samples(struct audio_info_struct *ai,unsigned char *buf,int len)
|
|
{
|
|
if (!uptodate) {
|
|
uptodate = 1;
|
|
ioctl(ai->fn, AUDIO_SETINFO, &ainfo);
|
|
}
|
|
|
|
return write(ai->fn,buf,len);
|
|
}
|
|
|
|
int audio_close(struct audio_info_struct *ai)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void audio_queueflush (struct audio_info_struct *ai)
|
|
{
|
|
ioctl (ai->fn, AUDIO_FLUSH, 0);
|
|
}
|