summaryrefslogtreecommitdiffstats
path: root/flow/audioioaix.cc
diff options
context:
space:
mode:
Diffstat (limited to 'flow/audioioaix.cc')
-rw-r--r--flow/audioioaix.cc390
1 files changed, 390 insertions, 0 deletions
diff --git a/flow/audioioaix.cc b/flow/audioioaix.cc
new file mode 100644
index 0000000..f36e9db
--- /dev/null
+++ b/flow/audioioaix.cc
@@ -0,0 +1,390 @@
+/*
+
+ Copyright (C) 2001 Carsten Griwodz
+ griff@ifi.uio.no
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef _AIX
+
+/*
+ * The audio header files exist even if there is not soundcard the
+ * the AIX machine. You won't be able to compile this code on AIX3
+ * which had ACPA support, so /dev/acpa is not checked here.
+ * I have no idea whether the Ultimedia Audio Adapter is actually
+ * working or what it is right now.
+ * For PCI machines including PowerSeries 850, baud or paud should
+ * work. The DSP (MWave?) of the 850 laptops may need microcode
+ * download. This is not implemented.
+ */
+
+#include <assert.h>
+#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>
+#include <sys/machine.h>
+#undef BIG_ENDIAN
+#include <sys/audio.h>
+
+#ifndef AUDIO_BIG_ENDIAN
+#define AUDIO_BIG_ENDIAN BIG_ENDIAN
+#endif
+
+#include "debug.h"
+#include "audioio.h"
+
+namespace Arts {
+
+class AudioIOAIX : public AudioIO {
+ int openDevice();
+
+protected:
+ int audio_fd;
+
+public:
+ AudioIOAIX();
+
+ void setParam(AudioParam param, int& value);
+ int getParam(AudioParam param);
+
+ bool open();
+ void close();
+ int read(void *buffer, int size);
+ int write(void *buffer, int size);
+};
+
+REGISTER_AUDIO_IO(AudioIOAIX,"paud","Personal Audio Device");
+};
+
+using namespace std;
+using namespace Arts;
+
+int AudioIOAIX::openDevice()
+{
+ char devname[14];
+ int fd;
+ for ( int dev=0; dev<4; dev++ )
+ {
+ for ( int chan=1; chan<8; chan++ )
+ {
+ sprintf(devname,"/dev/paud%d/%d",dev,chan);
+ fd = ::open (devname, O_WRONLY, 0);
+ if ( fd >= 0 )
+ {
+ paramStr(deviceName) = devname;
+ return fd;
+ }
+ sprintf(devname,"/dev/baud%d/%d",dev,chan);
+ fd = ::open (devname, O_WRONLY, 0);
+ if ( fd >= 0 )
+ {
+ paramStr(deviceName) = devname;
+ return fd;
+ }
+ }
+ }
+ return -1;
+}
+
+AudioIOAIX::AudioIOAIX()
+{
+ int fd = openDevice();
+ if( fd >= 0 )
+ {
+ audio_status audioStatus;
+ memset( &audioStatus, 0, sizeof(audio_status) );
+ ioctl(fd, AUDIO_STATUS, &audioStatus);
+
+ audio_buffer audioBuffer;
+ memset( &audioBuffer, 0, sizeof(audio_buffer) );
+ ioctl(fd, AUDIO_BUFFER, &audioBuffer);
+
+ ::close( fd );
+
+ /*
+ * default parameters
+ */
+ param(samplingRate) = audioStatus.srate;
+ param(fragmentSize) = audioStatus.bsize;
+ param(fragmentCount) = audioBuffer.write_buf_cap / audioStatus.bsize;
+ param(channels) = audioStatus.channels;
+ param(direction) = 2;
+
+ param(format) = ( audioStatus.bits_per_sample==8 ) ? 8
+ : ( ( audioStatus.flags & AUDIO_BIG_ENDIAN ) ? 17 : 16 );
+ }
+}
+
+bool AudioIOAIX::open()
+{
+ string& _error = paramStr(lastError);
+ string& _deviceName = paramStr(deviceName);
+ int& _channels = param(channels);
+ int& _fragmentSize = param(fragmentSize);
+ int& _fragmentCount = param(fragmentCount);
+ int& _samplingRate = param(samplingRate);
+ int& _format = param(format);
+
+ int mode;
+
+ switch( param(direction) )
+ {
+ case 1 : mode = O_RDONLY | O_NDELAY; break;
+ case 2 : mode = O_WRONLY | O_NDELAY; break;
+ case 3 :
+ _error = "open device twice to RDWR";
+ return false;
+ default :
+ _error = "invalid direction";
+ return false;
+ }
+
+ audio_fd = ::open(_deviceName.c_str(), mode, 0);
+
+ if(audio_fd == -1)
+ {
+ _error = "device ";
+ _error += _deviceName.c_str();
+ _error += " can't be opened (";
+ _error += strerror(errno);
+ _error += ")";
+ return false;
+ }
+
+ if( (_channels!=1) && (_channels!=2) )
+ {
+ _error = "internal error; set channels to 1 (mono) or 2 (stereo)";
+
+ close();
+ return false;
+ }
+
+ // int requeststereo = stereo;
+
+ // int speed = _samplingRate;
+
+ audio_init audioInit;
+ memset( &audioInit, 0, sizeof(audio_init) );
+ audioInit.srate = _samplingRate;
+ audioInit.bits_per_sample = ((_format==8)?8:16);
+ audioInit.bsize = _fragmentSize;
+ audioInit.mode = PCM;
+ audioInit.channels = _channels;
+ audioInit.flags = 0;
+ audioInit.flags |= (_format==17) ? AUDIO_BIG_ENDIAN : 0;
+ audioInit.flags |= (_format==8) ? 0 : SIGNED;
+ audioInit.operation = (param(direction)==1) ? RECORD : PLAY;
+
+ if ( ioctl(audio_fd, AUDIO_INIT, &audioInit) < 0 )
+ {
+ _error = "AUDIO_INIT failed - ";
+ _error += strerror(errno);
+ switch ( audioInit.rc )
+ {
+ case 1 :
+ _error += "Couldn't set audio format: DSP can't do play requests";
+ break;
+ case 2 :
+ _error += "Couldn't set audio format: DSP can't do record requests";
+ break;
+ case 4 :
+ _error += "Couldn't set audio format: request was invalid";
+ break;
+ case 5 :
+ _error += "Couldn't set audio format: conflict with open's flags";
+ break;
+ case 6 :
+ _error += "Couldn't set audio format: out of DSP MIPS or memory";
+ break;
+ default :
+ _error += "Couldn't set audio format: not documented in sys/audio.h";
+ break;
+ }
+
+ close();
+ return false;
+ }
+
+ if (audioInit.channels != _channels)
+ {
+ _error = "audio device doesn't support number of requested channels";
+ close();
+ return false;
+ }
+
+ switch( _format )
+ {
+ case 8 :
+ if (audioInit.flags&AUDIO_BIG_ENDIAN==1)
+ {
+ _error = "setting little endian format failed";
+ close();
+ return false;
+ }
+ if (audioInit.flags&SIGNED==1)
+ {
+ _error = "setting unsigned format failed";
+ close();
+ return false;
+ }
+ break;
+ case 16 :
+ if (audioInit.flags&AUDIO_BIG_ENDIAN==1)
+ {
+ _error = "setting little endian format failed";
+ close();
+ return false;
+ }
+ if (audioInit.flags&SIGNED==0)
+ {
+ _error = "setting signed format failed";
+ close();
+ return false;
+ }
+ break;
+ case 17 :
+ if (audioInit.flags&AUDIO_BIG_ENDIAN==0)
+ {
+ _error = "setting big endian format failed";
+ close();
+ return false;
+ }
+ if (audioInit.flags&SIGNED==0)
+ {
+ _error = "setting signed format failed";
+ close();
+ return false;
+ }
+ break;
+ default :
+ break;
+ }
+
+ /*
+ * Some soundcards seem to be able to only supply "nearly" the requested
+ * sampling rate, especially PAS 16 cards seem to quite radical supplying
+ * something different than the requested sampling rate ;)
+ *
+ * So we have a quite large tolerance here (when requesting 44100 Hz, it
+ * will accept anything between 38690 Hz and 49510 Hz). Most parts of the
+ * aRts code will do resampling where appropriate, so it shouldn't affect
+ * sound quality.
+ */
+ int tolerance = _samplingRate/10+1000;
+
+ if (abs(audioInit.srate - _samplingRate) > tolerance)
+ {
+ _error = "can't set requested samplingrate";
+
+ char details[80];
+ sprintf(details," (requested rate %d, got rate %ld)",
+ _samplingRate, audioInit.srate);
+ _error += details;
+
+ close();
+ return false;
+ }
+ _samplingRate = audioInit.srate;
+
+ _fragmentSize = audioInit.bsize;
+ _fragmentCount = audioInit.bsize / audioInit.bits_per_sample;
+
+ audio_buffer buffer_info;
+ ioctl(audio_fd, AUDIO_BUFFER, &buffer_info);
+ _fragmentCount = buffer_info.write_buf_cap / audioInit.bsize;
+
+
+ artsdebug("buffering: %d fragments with %d bytes "
+ "(audio latency is %1.1f ms)", _fragmentCount, _fragmentSize,
+ (float)(_fragmentSize*_fragmentCount) /
+ (float)(2.0 * _samplingRate * _channels)*1000.0);
+
+ return true;
+}
+
+void AudioIOAIX::close()
+{
+ ::close(audio_fd);
+}
+
+void AudioIOAIX::setParam(AudioParam p, int& value)
+{
+ param(p) = value;
+}
+
+int AudioIOAIX::getParam(AudioParam p)
+{
+ audio_buffer info;
+ switch(p)
+ {
+ case canRead:
+ ioctl(audio_fd, AUDIO_BUFFER, &info);
+ return (info.read_buf_cap - info.read_buf_size);
+ break;
+
+ case canWrite:
+ ioctl(audio_fd, AUDIO_BUFFER, &info);
+ return (info.write_buf_cap - info.write_buf_size);
+ break;
+
+ case selectReadFD:
+ return (param(direction) & directionRead)?audio_fd:-1;
+ break;
+
+ case selectWriteFD:
+ return (param(direction) & directionWrite)?audio_fd:-1;
+ break;
+
+ case autoDetect:
+ /* You may prefer OSS if it works, e.g. on 43P 240
+ * or you may prefer UMS, if anyone bothers to write
+ * a module for it.
+ */
+ return 2;
+ break;
+
+ default:
+ return param(p);
+ break;
+ }
+}
+
+int AudioIOAIX::read(void *buffer, int size)
+{
+ arts_assert(audio_fd != 0);
+ return ::read(audio_fd,buffer,size);
+}
+
+int AudioIOAIX::write(void *buffer, int size)
+{
+ arts_assert(audio_fd != 0);
+ return ::write(audio_fd,buffer,size);
+}
+
+#endif
+