/* aix: Driver for IBM RS/6000 with AIX Ultimedia Services copyright ?-2006 by the mpg123 project - free software under the terms of the LGPL 2.1 see COPYING and AUTHORS files in distribution or http://mpg123.org initially written by Juergen Schoew and Tomas Oegren */ #include #include #include #include #include #include #include #include #include #include #include #include "mpg123app.h" #include "debug.h" /* use AUDIO_BSIZE to set the msec for audio buffering in Ultimedia library */ /* #define AUDIO_BSIZE AUDIO_IGNORE */ #define AUDIO_BSIZE 200 static int rate_best_match(audio_output_t *ao) { 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 || ao->fn < 0 || ao->rate < 0) { return -1; } while (valid [i]) { if (abs(valid[i] - ao->rate) < abs(best - ao->rate)) { best = valid [i]; } i = i + 1; } ao->rate = best; return best; } static int reset_parameters(audio_output_t *ao) { 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 (ao->flags == -1) achange.output = INTERNAL_SPEAKER; else achange.output = 0; if(ao->flags & AUDIO_OUT_INTERNAL_SPEAKER) achange.output |= INTERNAL_SPEAKER; if(ao->flags & AUDIO_OUT_HEADPHONES) achange.output |= EXTERNAL_SPEAKER; if(ao->flags & AUDIO_OUT_LINE_OUT) achange.output |= OUTPUT_1; if(ao->flags == 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 (ao->fn, AUDIO_CONTROL, & acontrol); if (ret < 0) return ret; /* Init Device for new values */ if (ao->rate >0) { memset ( & ainit, '\0', sizeof (ainit)); ainit.srate = rate_best_match(ai); if (ao->channels > 0) ainit.channels = ao->channels; else ainit.channels = 1; switch (ao->format) { default : ainit.mode = PCM; ainit.bits_per_sample = 8; ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT; break; case MPG123_ENC_SIGNED_16: ainit.mode = PCM; ainit.bits_per_sample = 16; ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT; break; case MPG123_ENC_SIGNED_8: ainit.mode = PCM; ainit.bits_per_sample = 8; ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT; break; case MPG123_ENC_UNSIGNED_16: ainit.mode = PCM; ainit.bits_per_sample = 16; ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT | SIGNED; break; case MPG123_ENC_UNSIGNED_8: ainit.mode = PCM; ainit.bits_per_sample = 8; ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT | SIGNED; break; case MPG123_ENC_ULAW_8: ainit.mode = MU_LAW; ainit.bits_per_sample = 8; ainit.flags = BIG_ENDIAN | TWOS_COMPLEMENT; break; case MPG123_ENC_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 (ao->fn, AUDIO_INIT, & ainit); if (ret < 0) { error("Can't set new audio parameters!"); return ret; } } acontrol.ioctl_request = AUDIO_START; acontrol.request_info = NULL; acontrol.position = 0; ret = ioctl (ao->fn, AUDIO_CONTROL, & acontrol); if (ret < 0) { error("Can't reset audio!"); return ret; } return 0; } static int open_aix(audio_output_t *ao) { audio_init ainit; int ret; if(!ao->device) { if(getenv("AUDIODEV")) { ao->device = getenv("AUDIODEV"); ao->fn = open(ao->device,O_WRONLY); } else { ao->device = "/dev/paud0/1"; /* paud0 for PCI */ ao->fn = open(ao->device,O_WRONLY); if ((ao->fn == -1) & (errno == ENOENT)) { ao->device = "/dev/baud0/1"; /* baud0 for MCA */ ao->fn = open(ao->device,O_WRONLY); } } } else ao->fn = open(ao->device,O_WRONLY); if(ao->fn < 0) { error("Can't open audio device!"); return ao->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 (ao->fn, AUDIO_INIT, & ainit); if (ret < 0) return ret; reset_parameters(ai); return ao->fn; } static int get_formats_aix(audio_output_t *ao) { /* 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 = ao->rate; rate_best_match(ai); if (ao->rate == rate) return (MPG123_ENC_SIGNED_16|MPG123_ENC_UNSIGNED_16| MPG123_ENC_UNSIGNED_8|MPG123_ENC_SIGNED_8| MPG123_ENC_ULAW_8|MPG123_ENC_ALAW_8); else return 0; } static int write_aix(audio_output_t *ao,unsigned char *buf,int len) { return write(ao->fn,buf,len); } static int close_aix(audio_output_t *ao) { 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(ao->fn, AUDIO_BUFFER, &acontrol))< 0) { error1("buffer read failed: %d", 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 ( ao->fn, AUDIO_CONTROL, & acontrol ); if (ret < 0) error("Can't close audio!"); ret = close (ao->fn); if (ret < 0) error("Can't close audio!"); return 0; } static void flush_aix(audio_output_t *ao) { } static int init_aix(audio_output_t* ao) { if (ao==NULL) return -1; /* Set callbacks */ ao->open = open_aix; ao->flush = flush_aix; ao->write = write_aix; ao->get_formats = get_formats_aix; ao->close = close_aix; /* Success */ return 0; } /* Module information data structure */ mpg123_module_t mpg123_output_module_info = { /* api_version */ MPG123_MODULE_API_VERSION, /* name */ "AIX", /* description */ "Output audio on IBM RS/6000 with AIX Ultimedia Services.", /* revision */ "$Rev: 932 $", /* handle */ NULL, /* init_output */ init_aix, };