openbsd-ports/audio/mpg123/files/audio_openbsd.c
2003-06-12 22:25:59 +00:00

287 lines
7.3 KiB
C

/* $OpenBSD: audio_openbsd.c,v 1.6 2003/06/12 22:25:59 pvalchev Exp $ */
/*-
* Copyright (c) 1999 Marc Espie.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD
* PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#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);
}