/*
* Driver for IBM RS/6000 with AIX Ultimedia Services
*
* Code by Juergen Schoew <juergen.schoew@unix-ag.org>
*
* Tomas Oegren <stric@acc.umu.se>
* (code for audio_close delay)
*
* Cleanups and testing by Niklas Edmundsson <nikke@ing.umu.se>
*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/audio.h>
#include <stropts.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/param.h>
#include "mpg123.h"
/* use AUDIO_BSIZE to set the msec for audio buffering in Ultimedia library
*/
/* #define AUDIO_BSIZE AUDIO_IGNORE */
#define AUDIO_BSIZE 200
int audio_open(struct audio_info_struct *ai)
{
audio_init ainit;
int ret;
if(!ai->device) {
if(getenv("AUDIODEV")) {
if(param.verbose > 1)
fprintf(stderr,"Using audio-device value from AUDIODEV environmentvariable!\n");
ai->device = getenv("AUDIODEV");
ai->fn = open(ai->device,O_WRONLY);
}
else {
ai->device = "/dev/paud0/1"; /* paud0 for PCI */
ai->fn = open(ai->device,O_WRONLY);
if ((ai->fn == -1) & (errno == ENOENT)) {
ai->device = "/dev/baud0/1"; /* baud0 for MCA */
ai->fn = open(ai->device,O_WRONLY);
}
}
} else ai->fn = open(ai->device,O_WRONLY);
if(ai->fn < 0){
fprintf(stderr,"Can't open audio device!\n");
return ai->fn;
}
/* Init to default values */
memset ( & ainit, '\0', sizeof (ainit));
ainit.srate = 44100;
ainit.channels = 2;
ainit.mode = PCM;
ainit.bits_per_sample = 16;
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
ainit.operation = PLAY;
ainit.bsize = AUDIO_BSIZE;
ret = ioctl (ai->fn, AUDIO_INIT, & ainit);
if (ret < 0)
return ret;
audio_reset_parameters(ai);
return ai->fn;
}
int audio_reset_parameters(struct audio_info_struct *ai)
{
audio_control acontrol;
audio_change achange;
audio_init ainit;
int ret;
memset ( & achange, '\0', sizeof (achange));
memset ( & acontrol, '\0', sizeof (acontrol));
achange.balance = 0x3fff0000;
achange.balance_delay = 0;
achange.volume = (long) (0x7fff << 16);
achange.volume_delay = 0;
achange.input = AUDIO_IGNORE;
if (ai->output == -1) achange.output = INTERNAL_SPEAKER;
else
achange.output = 0;
if(ai->output & AUDIO_OUT_INTERNAL_SPEAKER)
achange.output |= INTERNAL_SPEAKER;
if(ai->output & AUDIO_OUT_HEADPHONES)
achange.output |= EXTERNAL_SPEAKER;
if(ai->output & AUDIO_OUT_LINE_OUT)
achange.output |= OUTPUT_1;
if(ai->output == 0)
achange.output = AUDIO_IGNORE;
achange.treble = AUDIO_IGNORE;
achange.bass = AUDIO_IGNORE;
achange.pitch = AUDIO_IGNORE;
achange.monitor = AUDIO_IGNORE;
achange.dev_info = (char *) NULL;
acontrol.ioctl_request = AUDIO_CHANGE;
acontrol.position = 0;
acontrol.request_info = (char *) & achange;
ret = ioctl (ai->fn, AUDIO_CONTROL, & acontrol);
if (ret < 0)
return ret;
/* Init Device for new values */
if (ai->rate >0) {
memset ( & ainit, '\0', sizeof (ainit));
ainit.srate = audio_rate_best_match(ai);
if (ai->channels > 0)
ainit.channels = ai->channels;
else
ainit.channels = 1;
switch (ai->format) {
default :
ainit.mode = PCM;
ainit.bits_per_sample = 8;
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
break;
case AUDIO_FORMAT_SIGNED_16:
ainit.mode = PCM;
ainit.bits_per_sample = 16;
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
break;
case AUDIO_FORMAT_SIGNED_8:
ainit.mode = PCM;
ainit.bits_per_sample = 8;
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
break;
case AUDIO_FORMAT_UNSIGNED_16:
ainit.mode = PCM;
ainit.bits_per_sample = 16;
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT | SIGNED;
break;
case AUDIO_FORMAT_UNSIGNED_8:
ainit.mode = PCM;
ainit.bits_per_sample = 8;
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT | SIGNED;
break;
case AUDIO_FORMAT_ULAW_8:
ainit.mode = MU_LAW;
ainit.bits_per_sample = 8;
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
break;
case AUDIO_FORMAT_ALAW_8:
ainit.mode = A_LAW;
ainit.bits_per_sample = 8;
ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT;
break;
}
ainit.operation = PLAY;
ainit.bsize = AUDIO_BSIZE;
ret = ioctl (ai->fn, AUDIO_INIT, & ainit);
if (ret < 0) {
fprintf(stderr,"Can't set new audio parameters!\n");
return ret;
}
}
acontrol.ioctl_request = AUDIO_START;
acontrol.request_info = NULL;
acontrol.position = 0;
ret = ioctl (ai->fn, AUDIO_CONTROL, & acontrol);
if (ret < 0) {
fprintf(stderr,"Can't reset audio!\n");
return ret;
}
return 0;
}
int audio_rate_best_match(struct audio_info_struct *ai)
{
static long valid [ ] = { 5510, 6620, 8000, 9600, 11025, 16000, 18900,
22050, 27420, 32000, 33075, 37800, 44100, 48000, 0 };
int i = 0;
long best = 8000;
if(!ai || ai->fn < 0 || ai->rate < 0) {
return -1;
}
while (valid [i])
{
if (abs(valid[i] - ai->rate) < abs(best - ai->rate))
{
best = valid [i];
}
i = i + 1;
}
ai->rate = best;
return best;
}
int audio_set_rate(struct audio_info_struct *ai)
{
return audio_reset_parameters(ai);
}
int audio_set_channels(struct audio_info_struct *ai)
{
return audio_reset_parameters(ai);
}
int audio_set_format(struct audio_info_struct *ai)
{
return audio_reset_parameters(ai);
}
int audio_get_formats(struct audio_info_struct *ai)
{
/* ULTIMEDIA DOCUMENTATION SAYS:
The Ultimedia Audio Adapter supports fourteen sample rates you can use to
capture and playback audio data. The rates are (in kHz): 5.51, 6.62, 8.0,
9.6, 11.025, 16.0, 18.9, 22.050, 27.42, 32.0, 33.075, 37.8, 44.1, and 48.0.
These rates are supported for mono and stereo PCM (8- and 16-bit), mu-law,
and A-law.
*/
long rate;
rate = ai->rate;
audio_rate_best_match(ai);
if (ai->rate == rate)
return (AUDIO_FORMAT_SIGNED_16|AUDIO_FORMAT_UNSIGNED_16|
AUDIO_FORMAT_UNSIGNED_8|AUDIO_FORMAT_SIGNED_8|
AUDIO_FORMAT_ULAW_8|AUDIO_FORMAT_ALAW_8);
else
return 0;
}
int audio_play_samples(struct audio_info_struct *ai,unsigned char *buf,int len)
{
return write(ai->fn,buf,len);
}
int audio_close(struct audio_info_struct *ai)
{
audio_control acontrol;
audio_buffer abuffer;
int ret,i;
/* Don't close the audio-device until it's played all its contents */
memset ( & acontrol, '\0', sizeof ( acontrol ) );
acontrol.request_info = &abuffer;
acontrol.position = 0;
i=50; /* Don't do this forever on a bad day :-) */
while (i-- > 0) {
if ((ioctl(ai->fn, AUDIO_BUFFER, &acontrol))< 0) {
fprintf(stderr, "buffer read failed: %d\n", errno);
break;
} else {
if (abuffer.flags <= 0)
break;
}
usleep(200000); /* sleep 0.2 sec */
}
memset ( & acontrol, '\0', sizeof ( acontrol ) );
acontrol.ioctl_request = AUDIO_STOP;
acontrol.request_info = NULL;
acontrol.position = 0;
ret = ioctl ( ai->fn, AUDIO_CONTROL, & acontrol );
if (ret < 0)
fprintf(stderr,"Can't close audio!\n");
ret = close (ai->fn);
if (ret < 0)
fprintf(stderr,"Can't close audio!\n");
return 0;
}