You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdemultimedia/mpeglib/lib/util/audio/audioIO_AIX.cpp

534 lines
15 KiB

/*
* AIX audio - griff@acm.org 02aug2000
* tested on 43P 260 with builtin audio
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
/* A conflict within AIX 4.3.3 <sys/> headers and probably others as well.
* I guess nobody ever uses audio... Shame over AIX header files. */
#include <sys/machine.h>
#undef BIG_ENDIAN
#include <sys/audio.h>
static int audio_fd;
static void debugUpdate( unsigned long& flags, long& bsize );
#ifndef AUDIO_BIG_ENDIAN
#define AUDIO_BIG_ENDIAN BIG_ENDIAN
#endif
int audioConstruct() {
printf("audioConstruct AIX ********\n");
audio_fd=-1;
return true;
}
void audioDestruct() {
}
int audioOpen()
{
char devname[14];
for ( int dev=0; dev<4; dev++ )
{
for ( int chan=1; chan<8; chan++ )
{
sprintf(devname,"/dev/paud%d/%d",dev,chan);
audio_fd = open (devname, O_WRONLY, 0);
if ( audio_fd >= 0 )
{
return 1;
}
sprintf(devname,"/dev/baud%d/%d",dev,chan);
audio_fd = open (devname, O_WRONLY, 0);
if ( audio_fd >= 0 )
{
return 1;
}
}
}
fprintf(stderr, "Could not open AIX audio device, faking\n" );
return 1;
}
int getAudioBufferSize()
{
audio_buffer paud_bufinfo;
if( audio_fd < 0 ) return 1024*65;
if ( ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0 )
{
perror("ioctl getAudioBufferSize using default");
return 1024*65;
}
/*
* Do you need the total capacity or the current capacity?
* This is the total capacity:
*/
return paud_bufinfo.write_buf_cap;
/*
* This is the current capacity:
* return (paud_bufinfo.write_buf_cap - paud_bufinfo.write_buf_size);
*/
}
void audioInit(int sampleSize,int frequency, int stereo, int sign, int bigendian )
{
// int format;
int bytes_per_sample;
audio_init paud_init;
audio_buffer paud_bufinfo;
// audio_status paud_status;
audio_control paud_control;
audio_change paud_change;
if( audio_fd < 0 ) return;
/*
* We can't set the buffer size - just ask the device for the maximum
* that we can have.
*/
if ( ioctl(audio_fd, AUDIO_BUFFER, &paud_bufinfo) < 0 )
{
perror("Couldn't get audio buffer information");
return;
}
/*
* Fields in the audio_init structure:
*
* Ignored by us:
*
* paud.loadpath[LOAD_PATH]; * DSP code to load, MWave chip only?
* paud.slot_number; * slot number of the adapter
* paud.device_id; * adapter identification number
*
* Input:
*
* paud.srate; * the sampling rate in Hz
* paud.bits_per_sample; * 8, 16, 32, ...
* paud.bsize; * block size for this rate
* paud.mode; * ADPCM, PCM, MU_LAW, A_LAW, SOURCE_MIX
* paud.channels; * 1=mono, 2=stereo
* paud.flags; * FIXED - fixed length data
* * LEFT_ALIGNED, RIGHT_ALIGNED (var len only)
* * TWOS_COMPLEMENT - 2's complement data
* * SIGNED - signed? comment seems wrong in sys/audio.h
* * BIG_ENDIAN
* paud.operation; * PLAY, RECORD
*
* Output:
*
* paud.flags; * PITCH - pitch is supported
* * INPUT - input is supported
* * OUTPUT - output is supported
* * MONITOR - monitor is supported
* * VOLUME - volume is supported
* * VOLUME_DELAY - volume delay is supported
* * BALANCE - balance is supported
* * BALANCE_DELAY - balance delay is supported
* * TREBLE - treble control is supported
* * BASS - bass control is supported
* * BESTFIT_PROVIDED - best fit returned
* * LOAD_CODE - DSP load needed
* paud.rc; * NO_PLAY - DSP code can't do play requests
* * NO_RECORD - DSP code can't do record requests
* * INVALID_REQUEST - request was invalid
* * CONFLICT - conflict with open's flags
* * OVERLOADED - out of DSP MIPS or memory
* paud.position_resolution; * smallest increment for position
*/
paud_init.srate = frequency;
paud_init.mode = PCM;
paud_init.operation = PLAY;
paud_init.channels = (stereo?2:1);
/*
* options in AIX:
* paud_init.bits_per_sample: 8 | 16
* paud_init.flags: AUDIO_BIG_ENDIAN (not used here)
* SIGNED (always used here)
* TWOS_COMPLEMENT (always on for Linux dsp porting?)
* FIXED <- that's right for SDL
* or LEFT_ALIGNED <- that's right for mpeglib
* or RIGHT_ALIGNED
* paud_init.bsize: sample byte size,
* bits_per_sample * (stereo?2:1) - for SDL
* bits_per_sample * (stereo?2:1) * 2 - for mpeglib
*/
if ( sampleSize == 8 )
{
/* AFMT_S8 in linux dsp */
bytes_per_sample = 2; // why not 1 ?
paud_init.bits_per_sample = 8;
paud_init.flags = TWOS_COMPLEMENT | LEFT_ALIGNED;
}
else
{
/* AFMT_S16_LE in linux dsp */
bytes_per_sample = 4; // why not 2 ?
paud_init.bits_per_sample = 16;
paud_init.flags = TWOS_COMPLEMENT | LEFT_ALIGNED;
}
if( sign ) paud_init.flags |= SIGNED;
if( bigendian ) paud_init.flags |= AUDIO_BIG_ENDIAN;
paud_init.bsize = bytes_per_sample * (stereo?2:1);
#if 0
debugUpdate(paud_init.flags, paud_init.bsize);
printf("CG: sampleSize = %d\n", sampleSize);
printf("CG: frequency = %d\n", frequency);
printf("CG: stereo = %s\n", (stereo)?"y":"n");
printf("CG: mode = %s\n", "PCM");
printf("CG: channels = %d\n", paud_init.channels);
printf("CG: bsize = %d\n", paud_init.bsize);
printf("CG: bits_per_sample = %d\n", paud_init.bits_per_sample);
printf("CG: flags & BIG_ENDIAN = %s\n", ((paud_init.flags&AUDIO_BIG_ENDIAN)?"y":"n"));
printf("CG: flags & SIGNED = %s\n", ((paud_init.flags&SIGNED)?"y":"n"));
printf("CG: flags & TWOS_COMPLEMENT = %s\n", ((paud_init.flags&TWOS_COMPLEMENT)?"y":"n"));
printf("CG: flags & FIXED = %s\n", ((paud_init.flags&FIXED)?"y":"n"));
printf("CG: flags & LEFT_ALIGNED = %s\n", ((paud_init.flags&LEFT_ALIGNED)?"y":"n"));
printf("CG: flags & RIGHT_ALIGNED = %s\n", ((paud_init.flags&RIGHT_ALIGNED)?"y":"n"));
#endif
/*
* We know the buffer size and the max number of subsequent writes
* that can be pending. If more than one can pend, allow the application
* to do something like double buffering between our write buffer and
* the device's own buffer that we are filling with write() anyway.
*
* We can calculate the number of samples that fit into the audio
* device buffer if that is necessary:
*
* samples_capacity = paud_bufinfo.write_buf_cap
* / bytes_per_sample
* / (stereo?2:1);
* if ( paud_bufinfo.request_buf_cap != 1 ) samples_capacity /= 2;
*/
/*
* The AIX paud device init can't modify the values of the audio_init
* structure that we pass to it. So we don't need any recalculation
* of this stuff and no reinit call as in linux SDL dsp and dma code.
*
* /dev/paud supports all of the encoding formats, so we don't need
* to do anything like reopening the device, either.
*/
if ( ioctl(audio_fd, AUDIO_INIT, &paud_init) < 0 )
{
switch ( paud_init.rc )
{
case 1 :
perror("Couldn't set audio format: DSP can't do play requests");
return;
break;
case 2 :
perror("Couldn't set audio format: DSP can't do record requests");
return;
break;
case 4 :
perror("Couldn't set audio format: request was invalid");
return;
break;
case 5 :
perror("Couldn't set audio format: conflict with open's flags");
return;
break;
case 6 :
perror("Couldn't set audio format: out of DSP MIPS or memory");
return;
break;
default :
perror("Couldn't set audio format: not documented in sys/audio.h");
return;
break;
}
}
/*
* Set some parameters: full volume, first speaker that we can find.
* Ignore the other settings for now.
*/
paud_change.input = AUDIO_IGNORE; /* the new input source */
paud_change.output = OUTPUT_1;
/* EXTERNAL_SPEAKER,
* INTERNAL_SPEAKER,
* OUTPUT_1 */
paud_change.monitor = AUDIO_IGNORE; /* the new monitor state */
paud_change.volume = 0x7fffffff; /* volume level [0-0x7fffffff] */
paud_change.volume_delay = AUDIO_IGNORE; /* the new volume delay */
paud_change.balance = 0x3fffffff; /* the new balance */
paud_change.balance_delay = AUDIO_IGNORE; /* the new balance delay */
paud_change.treble = AUDIO_IGNORE; /* the new treble state */
paud_change.bass = AUDIO_IGNORE; /* the new bass state */
paud_change.pitch = AUDIO_IGNORE; /* the new pitch state */
paud_control.ioctl_request = AUDIO_CHANGE;
paud_control.request_info = (char*)&paud_change;
if ( ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0 )
{
perror("Can't change audio display settings (ignoring)" );
}
/*
* Tell the device to expect data. Actual start will wait for
* the first write() call.
*/
paud_control.ioctl_request = AUDIO_START;
paud_control.position = 0;
if ( ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0 )
{
perror("Can't start audio play");
return;
}
}
void audioSetVolume(int volume)
{
long vol = (long)(volume/100.0) * 0x7fffffff;
if( audio_fd < 0 ) return;
audio_control paud_control;
audio_change paud_change;
paud_change.input = AUDIO_IGNORE; /* the new input source */
paud_change.output = OUTPUT_1; /* EXTERNAL_SPEAKER,INTERNAL_SPEAKER,
OUTPUT_1 */
paud_change.monitor = AUDIO_IGNORE; /* the new monitor state */
paud_change.volume = vol; /* volume level [0-0x7fffffff] */
paud_change.volume_delay = AUDIO_IGNORE; /* the new volume delay */
paud_change.balance = AUDIO_IGNORE; /* the new balance */
paud_change.balance_delay = AUDIO_IGNORE; /* the new balance delay */
paud_change.treble = AUDIO_IGNORE; /* the new treble state */
paud_change.bass = AUDIO_IGNORE; /* the new bass state */
paud_change.pitch = AUDIO_IGNORE; /* the new pitch state */
paud_control.ioctl_request = AUDIO_CHANGE;
paud_control.request_info = (char*)&paud_change;
if ( ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0 )
{
perror("Change audio volume failed");
}
}
void audioFlush()
{
if( audio_fd < 0 ) return;
if ( ioctl(audio_fd, AUDIO_WAIT, NULL) < 0 )
{
perror("Flush audio buffers failed");
}
}
void audioClose()
{
if( audio_fd < 0 ) return;
if ( ioctl(audio_fd, AUDIO_WAIT, NULL) < 0 )
{
perror("Flush audio buffers failed");
}
close(audio_fd);
}
int audioWrite(char *buffer, int count)
{
int written = write(audio_fd, buffer, count);
if( written < count )
{
return count;
}
return written;
}
int
getAudioFd()
{
return audio_fd;
}
int mixerOpen()
{
return true;
}
void mixerClose()
{
}
void mixerSetVolume(int leftVolume,int rightVolume)
{
long balance;
if( audio_fd < 0 ) return;
balance = 2 * (leftVolume-rightVolume) / (leftVolume+rightVolume);
balance = 0x3fffffff + balance*0x3fffffff;
audio_control paud_control;
audio_change paud_change;
paud_change.input = AUDIO_IGNORE; /* the new input source */
paud_change.output = OUTPUT_1; /* EXTERNAL_SPEAKER,INTERNAL_SPEAKER,
OUTPUT_1 */
paud_change.monitor = AUDIO_IGNORE; /* the new monitor state */
paud_change.volume = AUDIO_IGNORE; /* volume level [0-0x7fffffff] */
paud_change.volume_delay = AUDIO_IGNORE; /* the new volume delay */
paud_change.balance = balance; /* the new balance */
paud_change.balance_delay = AUDIO_IGNORE; /* the new balance delay */
paud_change.treble = AUDIO_IGNORE; /* the new treble state */
paud_change.bass = AUDIO_IGNORE; /* the new bass state */
paud_change.pitch = AUDIO_IGNORE; /* the new pitch state */
paud_control.ioctl_request = AUDIO_CHANGE;
paud_control.request_info = (char*)&paud_change;
if ( ioctl(audio_fd, AUDIO_CONTROL, &paud_control) < 0 )
{
perror("Change audio volume failed");
}
}
static void debugUpdate( unsigned long& flags, long& bsize )
{
const char* g;
g = getenv("AUDIO_BIG_ENDIAN");
if ( g )
{
int i = atoi(g);
if ( i == 1 )
{
flags |= AUDIO_BIG_ENDIAN;
}
else if ( i == 0 )
{
flags &= ~AUDIO_BIG_ENDIAN;
}
else
{
printf("CG: bad AUDIO_BIG_ENDIAN env variable %s\n", g);
}
}
g = getenv("SIGNED");
if ( g )
{
int i = atoi(g);
if ( i == 1 )
{
flags |= SIGNED;
}
else if ( i == 0 )
{
flags &= ~SIGNED;
}
else
{
printf("CG: bad SIGNED env variable %s\n", g);
}
}
g = getenv("TWOS_COMPLEMENT");
if ( g )
{
int i = atoi(g);
if ( i == 1 )
{
flags |= TWOS_COMPLEMENT;
}
else if ( i == 0 )
{
flags &= ~TWOS_COMPLEMENT;
}
else
{
printf("CG: bad TWOS_COMPLEMENT env variable %s\n", g);
}
}
g = getenv("FIXED");
if ( g )
{
int i = atoi(g);
if ( i == 1 )
{
flags |= FIXED;
}
else if ( i == 0 )
{
flags &= ~FIXED;
}
else
{
printf("CG: bad FIXED env variable %s\n", g);
}
}
g = getenv("LEFT_ALIGNED");
if ( g )
{
int i = atoi(g);
if ( i == 1 )
{
flags |= LEFT_ALIGNED;
}
else if ( i == 0 )
{
flags &= ~LEFT_ALIGNED;
}
else
{
printf("CG: bad LEFT_ALIGNED env variable %s\n", g);
}
}
g = getenv("RIGHT_ALIGNED");
if ( g )
{
int i = atoi(g);
if ( i == 1 )
{
flags |= RIGHT_ALIGNED;
}
else if ( i == 0 )
{
flags &= ~RIGHT_ALIGNED;
}
else
{
printf("CG: bad RIGHT_ALIGNED env variable %s\n", g);
}
}
g = getenv("BSIZE");
if ( g )
{
bsize = atoi(g);
}
}