diff options
Diffstat (limited to 'pd/portaudio_v18/pa_sgi')
-rw-r--r-- | pd/portaudio_v18/pa_sgi/Makefile | 63 | ||||
-rw-r--r-- | pd/portaudio_v18/pa_sgi/pa_sgi.c | 1069 | ||||
-rw-r--r-- | pd/portaudio_v18/pa_sgi/pthread-Makefile | 52 | ||||
-rw-r--r-- | pd/portaudio_v18/pa_sgi/pthread-pa_sgi.c | 908 |
4 files changed, 0 insertions, 2092 deletions
diff --git a/pd/portaudio_v18/pa_sgi/Makefile b/pd/portaudio_v18/pa_sgi/Makefile deleted file mode 100644 index 0cecda2d..00000000 --- a/pd/portaudio_v18/pa_sgi/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# Makefile for pa_sgi. PortAudio for Silicon Graphics IRIX 6.2-6.5. -# Pieter suurmond, march 15, 2003. (pa-V18-patch). -# Tested under IRIX 6.5 with both GCC and MIPS compilers. -# Based on SGI-specific sproc()-method to spawn children, not on POSIX-threads. - -# Choose compiler in combination with options: - -CC = cc -CFLAGS = -O2 - -# Possible options with MIPSpro compiler are: -32, -o32, -n32, -64, -# -mips1, -mips2, -mips3, -mips4, etc. Use -g, -g2, -g3 for debugging. -# For GCC, use -Wall. And use for example -O2 or -O3 for better optimization: - -#CC = gcc -#CFLAGS = -O2 -Wall - -# Instead of "-lpthread", as with linux, just the audio- and math-library for SGI: - -LIBS = -laudio -lm - -# So sourcefiles can find included headerfiles in pa_common: -CDEFINES = -I../pa_common - -PASRC = ../pa_common/pa_lib.c pa_sgi.c -PAINC = ../pa_common/portaudio.h - -# Tests performed on SGI Indy with R5000 @ 180MHz running IRIX 6.5: -# Used GCC compiler version 3.0.4. and MIPS. - -TESTC = $(PASRC) ../pa_tests/patest_record.c ## OK GCC march 2003 (MIPS sees errors in patest_record.c, refuses compilation). -#TESTC = $(PASRC) ../pa_tests/patest_latency.c ## OK GCC march 2003. (MIPS doesn't like //) -#TESTC = $(PASRC) ../pa_tests/patest_longsine.c ## OK GCC march 2003. -#TESTC = $(PASRC) ../pa_tests/patest_wire.c ## OK GCC Click free now. march 2003. -#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c ## OK GCC march 2003. - -#TESTC = $(PASRC) ../pa_tests/pa_devs.c # Never knew my Indy had 16 input- and output-channels! -#TESTC = $(PASRC) ../pa_tests/patest_saw.c ## - Pa_sleep doesn't work anymore?! -#TESTC = $(PASRC) ../pa_tests/patest_sine.c # - Pa_sleep doesn't work anymore?! -#TESTC = $(PASRC) ../pa_tests/patest_many.c ## - Pa_sleep doesn't work anymore?! -#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c ## Silence for 2 seconds doesn't work, sine sounds ok. - -#TESTC = $(PASRC) ../pa_tests/patest_sine8.c ## Silence for 2 seconds doesn't work, sine sounds ok. -#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK GCC and MIPS-CC march 2003. -#TESTC = $(PASRC) ../pa_tests/patest_pink.c ## OK GCC march 2003 -#TESTC = $(PASRC) ../pa_tests/patest_clip.c # -#TESTC = $(PASRC) ../pa_tests/patest_stop.c # MIPS doesn't like patest_stop.c Worked before but now - # error AL_BAD_QSIZE on IRIX 6.5 (with GCC). -#TESTC = $(PASRC) ../pa_tests/patest_dither.c # -#TESTC = $(PASRC) ../pa_tests/patest_sync.c # I don't hear the 6th beep, not really in sync @500ms lat. -#TESTC = $(PASRC) ../pa_tests/paqa_devs.c # A lot of error messages but no coredump. -#TESTC = $(PASRC) ../pa_tests/paqa_errs.c # Segmentation fault (core dumped)! - -TESTH = $(PAINC) - -all: patest - -patest: $(TESTC) $(TESTH) Makefile - $(CC) $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest - -run: patest - ./patest - diff --git a/pd/portaudio_v18/pa_sgi/pa_sgi.c b/pd/portaudio_v18/pa_sgi/pa_sgi.c deleted file mode 100644 index fa2978b5..00000000 --- a/pd/portaudio_v18/pa_sgi/pa_sgi.c +++ /dev/null @@ -1,1069 +0,0 @@ -/* - * $Id: pa_sgi.c,v 1.2.4.2 2003/03/13 00:56:47 pieter Exp $ - * PortAudio Portable Real-Time Audio Library. Copyright (c) 1999-2001 Phil Burk. - * Latest Version at: http://www.portaudio.com - * - * Silicon Graphics (SGI) IRIX implementation by Pieter Suurmond. - * This implementation uses sproc()-spawning, not the POSIX-threads. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * -MODIFICATIONS: - 8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2. - 8/17/2001 - v15, first unstable alpha release for IRIX, sent to Phil & Ross. - 9/23/2001 - Many fixes and changes: POLLIN for input, not POLLOUT! - 7/04/2002 - Implemented multiple user buffers per host buffer to allow clients that - request smaller buffersizes. - 3/13/2003 - Fixed clicks in full-duplex (wire) mode. Fixed some uninitialised vars, got rid of - all GCC-warnings (-Wall). Tested with MIPS compiler and GCC 3.0.4. on IRIX 6.5 (AL v7). -TODO: - - Dynamically switch to 32 bit float as native format when appropriate (let SGI do the conversion), - and maybe also the other natively supported formats? (might increase performance) - - Implement fancy callback block adapter as described in the PDF by Stephane Letz in the ASIO dir. - -REFERENCES: - - IRIX 6.2 man pages regarding SGI AL library. - - IRIS Digital Media Programming Guide (online books and man-pages come - with IRIX 6.2 and may not be publically available on the internet). -*/ - -#include <stdio.h> /* Standard libraries. */ -#include <stdlib.h> - -#include "../pa_common/portaudio.h" /* (Makefile fails to find in subdirs, -I doesn't work?). */ -#include "../pa_common/pa_host.h" -#include "../pa_common/pa_trace.h" - -#include <errno.h> /* Needed for int oserror(void);. */ -#include <sys/time.h> -#include <sys/types.h> -#include <sys/prctl.h> -#include <sys/schedctl.h> /* For schedctl(NDPRI, NDPHIMIN). */ -#include <fcntl.h> /* fcntl.h needed. */ -#include <unistd.h> /* For streams, ioctl(), etc. */ -#include <ulocks.h> -#include <poll.h> -#include <dmedia/audio.h> /* System specific (IRIX 6.2-6.5). */ - -/*----------------- MACROS --------------------*/ -#define PRINT(x) { printf x; fflush(stdout); } -#define ERR_RPT(x) PRINT(x) -#define DBUG(x) /* PRINT(x) */ -#define DBUGX(x) /* PRINT(x) */ - -#define MAX_CHARS_DEVNAME (16) -#define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7. */ - /* Constants used in 'Pa_GetMinNumBuffers()' below: */ -#define MIN_LATENCY_MSEC (200) /* Used if 'getenv("PA_MIN_LATENCY_MSEC")' fails. */ -#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") /* Same names as in file pa_unix.h. */ - -/*------------------------------- IRIX AL specific device info: --------------------------------------*/ -typedef struct internalPortAudioDevice -{ - PaDeviceID pad_DeviceID; /* THIS "ID" IS NEW HERE. */ - long pad_ALdevice; /* SGI-number! */ - double pad_SampleRates[MAX_SAMPLE_RATES]; /* For pointing to from pad_Info */ - char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */ - PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */ - struct internalPortAudioDevice* pad_Next; /* Singly linked list (NULL=end). */ -} internalPortAudioDevice; - -/*----------------- Structure containing all SGI IRIX specific data: ---------------------------------------*/ -typedef struct PaHostSoundControl -{ - ALconfig pahsc_ALconfigIN, /* IRIX-audio-library-datatype. Configuration */ - pahsc_ALconfigOUT; /* stucts separate for input and output ports. */ - ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */ - pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */ - int pahsc_threadPID; /* Sproc()-result, written by PaHost_StartEngine(). */ - - unsigned int pahsc_UserBuffersPerHostBuffer, - pahsc_SamplesPerInputHostBuffer, /* Channels per frame are accounted for. */ - pahsc_SamplesPerOutputHostBuffer, - pahsc_BytesPerInputHostBuffer, /* Size per sample are accounted for. */ - pahsc_BytesPerOutputHostBuffer; - short *pahsc_InputHostBuffer, /* Allocated here, in this file, if necessary. */ - *pahsc_OutputHostBuffer; - - struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */ - pahsc_LastExitTime; - long pahsc_InsideCountSum, - pahsc_TotalCountSum; -} PaHostSoundControl; - -/*-------------------------------------------------------- Shared Data -------------------------------*/ -static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */ -static int sPaHostError = 0; /* Maybe more than one process writing errs!? */ -usema_t *SendSema, /* These variables are shared between the */ - *RcvSema; /* audio handling process and main process. */ -/*--------------------------*/ -long Pa_GetHostError(void) -{ - return (long)sPaHostError; -} - -/*----------------------------- BEGIN CPU UTILIZATION MEASUREMENT -----------------*/ -/* (copied from source pa_linux_oss/pa_linux_oss.c) */ -static void Pa_StartUsageCalculation( internalPortAudioStream *past ) -{ - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return; - /* Query system timer for usage analysis and to prevent overuse of CPU. */ - getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime ); -} - -static long SubtractTime_AminusB( struct itimerval *timeA, struct itimerval *timeB ) -{ - long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec; - long usecs = secs * 1000000; - usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec); - return usecs; -} - -static void Pa_EndUsageCalculation( internalPortAudioStream *past ) -{ - struct itimerval currentTime; - long insideCount; - long totalCount; /* Measure CPU utilization during this callback. */ - -#define LOWPASS_COEFFICIENT_0 (0.95) -#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) - - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if (pahsc == NULL) - return; - if (getitimer( ITIMER_REAL, ¤tTime ) == 0 ) - { - if (past->past_IfLastExitValid) - { - insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, ¤tTime ); - pahsc->pahsc_InsideCountSum += insideCount; - totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, ¤tTime ); - pahsc->pahsc_TotalCountSum += totalCount; - /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */ - /* Low pass filter the result because sometimes we get called several times in a row. */ - /* That can cause the TotalCount to be very low which can cause the usage to appear */ - /* unnaturally high. So we must filter numerator and denominator separately!!! */ - if (pahsc->pahsc_InsideCountSum > 0) - { - past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + - (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum)); - past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + - (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum)); - past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; - pahsc->pahsc_InsideCountSum = 0; - pahsc->pahsc_TotalCountSum = 0; - } - } - past->past_IfLastExitValid = 1; - } - pahsc->pahsc_LastExitTime.it_value.tv_sec = 100; - pahsc->pahsc_LastExitTime.it_value.tv_usec = 0; - setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL ); - past->past_IfLastExitValid = 1; -} /*----------- END OF CPU UTILIZATION CODE (from pa_linux_oss/pa_linux_oss.c v15)--------------------*/ - - -/*--------------------------------------------------------------------------------------*/ -PaError translateSGIerror(void) /* Calls oserror(), may be used after an SGI AL-library */ -{ /* call to report via ERR_RPT(), yields a PaError-num. */ - const char* a = "SGI AL "; /* (Not absolutely sure errno came from THIS thread! */ - switch(oserror()) /* Read IRIX man-pages about the _SGI_MP_SOURCE macro.) */ - { - case AL_BAD_OUT_OF_MEM: - ERR_RPT(("%sout of memory.\n", a)); - return paInsufficientMemory; /* Known PaError. */ - case AL_BAD_CONFIG: - ERR_RPT(("%sconfiguration invalid or NULL.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_CHANNELS: - ERR_RPT(("%schannels not 1,2 or 4.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_NO_PORTS: - ERR_RPT(("%sout of audio ports.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_DEVICE: - ERR_RPT(("%swrong device number.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_DEVICE_ACCESS: - ERR_RPT(("%swrong device access.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_DIRECTION: - ERR_RPT(("%sinvalid direction.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_SAMPFMT: - ERR_RPT(("%sdoesn't accept sampleformat.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_FLOATMAX: - ERR_RPT(("%smax float value is zero.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_WIDTH: - ERR_RPT(("%sunsupported samplewidth.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_QSIZE: - ERR_RPT(("%sinvalid queue size.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_PVBUFFER: - ERR_RPT(("%sPVbuffer null.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_BUFFERLENGTH_NEG: - ERR_RPT(("%snegative bufferlength.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_BUFFERLENGTH_ODD: - ERR_RPT(("%sodd bufferlength.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_PARAM: - ERR_RPT(("%sparameter not valid for device.\n", a)); - return paHostError; /* Generic PaError. */ - default: - ERR_RPT(("%sunknown error.\n", a)); - return paHostError; /* Generic PaError. */ - } -} - -/*------------------------------------------------------------------------------------------*/ -/* Tries to set various rates and formats and fill in the device info structure. */ -static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT_DEVICE) */ - PaDeviceID id, /* (DefaultI|ODeviceID()) */ - char* name, /* (for example "SGI AL") */ - internalPortAudioDevice* pad) /* Result written to pad. */ -{ - long min, max; /* To catch hardware characteristics. */ - ALseterrorhandler(0); /* 0 = turn off the default error handler. */ - /*--------------------------------------------------------------------------------------*/ - pad->pad_ALdevice = ALdev; /* Set the AL device number. */ - pad->pad_DeviceID = id; /* Set the PA device number. */ - if (strlen(name) > MAX_CHARS_DEVNAME) /* MAX_CHARS defined above. */ - { - ERR_RPT(("Pa_QueryDevice(): name too long (%s).\n", name)); - return paHostError; - } - strcpy(pad->pad_DeviceName, name); /* Write name-string. */ - pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */ - /*--------------------------------- natively supported sample formats: -----------------*/ - pad->pad_Info.nativeSampleFormats = paInt16; /* Later also include paFloat32 | ..| etc. */ - /* Then also choose other CallConvertXX()! */ - /*--------------------------------- number of available i/o channels: ------------------*/ - if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max)) - return translateSGIerror(); - pad->pad_Info.maxInputChannels = max; - DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels)) - if (ALgetminmax(ALdev, AL_OUTPUT_COUNT, &min, &max)) - return translateSGIerror(); - pad->pad_Info.maxOutputChannels = max; - DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels)) - /*--------------------------------- supported samplerates: ----------------------*/ - pad->pad_Info.numSampleRates = 7; - pad->pad_Info.sampleRates = pad->pad_SampleRates; - pad->pad_SampleRates[0] = (double)AL_RATE_8000; /* long -> double. */ - pad->pad_SampleRates[1] = (double)AL_RATE_11025; - pad->pad_SampleRates[2] = (double)AL_RATE_16000; - pad->pad_SampleRates[3] = (double)AL_RATE_22050; - pad->pad_SampleRates[4] = (double)AL_RATE_32000; - pad->pad_SampleRates[5] = (double)AL_RATE_44100; - pad->pad_SampleRates[6] = (double)AL_RATE_48000; - if (ALgetminmax(ALdev, AL_INPUT_RATE, &min, &max)) /* Ask INPUT rate-max. */ - return translateSGIerror(); /* double -> long. */ - if (max != (long)(0.5 + pad->pad_SampleRates[6])) /* FP-compare not recommndd. */ - goto weird; - if (ALgetminmax(ALdev, AL_OUTPUT_RATE, &min, &max)) /* Ask OUTPUT rate-max. */ - return translateSGIerror(); - if (max != (long)(0.5 + pad->pad_SampleRates[6])) - { -weird: ERR_RPT(("Pa_sgiQueryDevice() did not confirm max samplerate (%ld)\n",max)); - return paHostError; /* Or make it a warning and just carry on... */ - } - /*-------------------------------------------------------------------------------*/ - return paNoError; -} - - -/*--------------------------------------------------------------------------------*/ -int Pa_CountDevices() /* Name of this function suggests it only counts and */ -{ /* is NOT destructive, it however resets whole PA ! */ - int numDevices = 0; /* Let 's not do that here. */ - internalPortAudioDevice* currentDevice = sDeviceList; /* COPY GLOBAL VAR. */ -#if 0 /* Remains from linux_oss v15: Pa_Initialize(), on */ - if (!currentDevice) /* its turn, calls PaHost_Init() via file pa_lib.c. */ - Pa_Initialize(); /* Isn't that a bit too 'rude'? Don't be too */ -#endif /* friendly to clients that forgot to initialize PA. */ - while (currentDevice) /* Slower but more elegant than the sNumDevices-way: */ - { - numDevices++; - currentDevice = currentDevice->pad_Next; - } - return numDevices; -} - -/*-------------------------------------------------------------------------------*/ -static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id) -{ - int numDevices = 0; - internalPortAudioDevice *res = (internalPortAudioDevice*)NULL; - internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */ - while (pad) /* pad may be NULL, that's ok, return 0. */ - { /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */ - if (pad->pad_DeviceID == id) /* This the device we were looking for? */ - res = pad; /* But keep on(!) counting so we don't */ - numDevices++; /* have to call Pa_CountDevices() later. */ - pad = pad->pad_Next; /* Advance to the next device or NULL. */ - } /* No assumptions about order of ID's in */ - if (!res) /* the list. */ - ERR_RPT(("Pa_GetInternalDevice() could not find specified ID (%d).\n",id)); - if ((id < 0) || (id >= numDevices)) - { - ERR_RPT(("Pa_GetInternalDevice() supplied with an illegal ID (%d).\n",id)); -#if 1 /* Be strict, even when found, */ - res = (internalPortAudioDevice*)NULL; /* do not accept illegal ID's. */ -#endif - } - return res; -} - -/*----------------------------------------------------------------------*/ -const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id) -{ - PaDeviceInfo* res = (PaDeviceInfo*)NULL; - internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */ - if (pad) - res = &pad->pad_Info; /* Not finding the specified ID is not */ - if (!res) /* the same as &pad->pad_Info == NULL. */ - ERR_RPT(("Pa_GetDeviceInfo() could not find it (ID=%d).\n", id)); - return res; /* So (maybe) a second/third ERR_RPT(). */ -} - -/*------------------------------------------------*/ -PaDeviceID Pa_GetDefaultInputDeviceID(void) -{ - return 0; /* 0 is the default device ID. */ -} -/*------------------------------------------------*/ -PaDeviceID Pa_GetDefaultOutputDeviceID(void) -{ - return 0; -} - -/*-------------------------------------------------------------------------------------------------*/ -/* Build linked a list with all the available audio devices on this SGI machine (only 1 for now). */ -PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */ -{ - internalPortAudioDevice* pad; - PaError r = paNoError; - int audioLibFileID; /* To test for the presence of audio. */ - - if (sDeviceList) /* Allow re-init, only warn, no error. */ - { - ERR_RPT(("Warning: PaHost_Init() did not really re-init PA.\n")); - return r; - } - /*------------- ADD THE SGI DEFAULT DEVICE TO THE LIST: ---------------------------------------*/ - audioLibFileID = open("/dev/hdsp/hdsp0master", O_RDONLY); /* Try to open Indigo style audio */ - if (audioLibFileID < 0) /* IO port. On failure, machine */ - { /* has no audio ability. */ - ERR_RPT(("PaHost_Init(): This machine has no (Indigo-style) audio abilities.\n")); - return paHostError; - } - close(audioLibFileID); /* Allocate fast mem to hold device info. */ - pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice)); - if (pad == NULL) - return paInsufficientMemory; - memset(pad, 0, sizeof(internalPortAudioDevice)); /* "pad->pad_Next = NULL" is more elegant. */ - r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */ - Pa_GetDefaultOutputDeviceID(),/* Set PA device num (or InputDeviceID()). */ - "AL default", /* A suitable name. */ - pad); /* Write args and queried info into pad. */ - if (r != paNoError) - { - ERR_RPT(("Pa_QueryDevice for '%s' returned: %d\n", pad->pad_DeviceName, r)); - PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */ - } - else - sDeviceList = pad; /* First element in linked list. pad->pad_Next already NULL. */ - /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LINKED LIST: -------------------*/ - /*---------------------------------------------------------------------------------------------*/ - return r; -} - -/*--------------------------------------------------------------------------------------------*/ -#define MIN(a,b) ((a)<(b)?(a):(b)) /* MIN()-function is used below. */ -#define kPollSEMA 0 /* To index the pollfd-array, reads nicer than just */ -#define kPollOUT 1 /* numbers. */ -#define kPollIN 2 -void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_StartEngine() */ -{ /* as a separate thread. (Argument must be void*). */ - short evtLoop; /* Reset by parent indirectly, or at local errors. */ - PaError result; - struct pollfd PollFD[3]; /* To catch kPollSEMA-, kPollOUT- and kPollIN-events. */ - internalPortAudioStream *past = (internalPortAudioStream*)v; /* Copy void-ptr-argument. */ - PaHostSoundControl *pahsc; - short n, inputEvent, outputEvent, ioEvent, semaEvent = 0; - short *inBuffer, *outBuffer; /* Only 16 bit for now, may change... */ - unsigned int samplesPerInputUserBuffer, samplesPerOutputUserBuffer; - - DBUG(("Entering sproc-thread.\n")); - if (!past) - { - sPaHostError = paInternalError; /* Or paBadStreamPtr ? */ - ERR_RPT(("argument NULL!\n")); - goto noPast; - } - pahsc = (PaHostSoundControl*)past->past_DeviceData; - if (!pahsc) - { - sPaHostError = paInternalError; /* The only way is to signal error to shared area?! */ - ERR_RPT(("past_DeviceData NULL!\n")); - goto noPahsc; /* Sproc-ed threads MAY NOT RETURN paInternalError. */ - } - /*----------------------------- open AL-ports here, after sproc(): -----------------------*/ - if (past->past_NumInputChannels > 0) /* Open input port. */ - { - pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", pahsc->pahsc_ALconfigIN); - if (!pahsc->pahsc_ALportIN) - { - ERR_RPT(("Failed to open AL input port.\n")); - sPaHostError = paInternalError; - goto skip; - } - DBUG(("Opened %d input channel(s).\n", past->past_NumInputChannels)); - samplesPerInputUserBuffer = pahsc->pahsc_SamplesPerInputHostBuffer / - pahsc->pahsc_UserBuffersPerHostBuffer; - } - else - samplesPerInputUserBuffer = 0; /* Added 2003. */ - if (past->past_NumOutputChannels > 0) /* Open output port. */ - { - pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", pahsc->pahsc_ALconfigOUT); - if (!pahsc->pahsc_ALportOUT) - { - ERR_RPT(("Failed to open AL output port.\n")); - sPaHostError = paInternalError; /* Assume pahsc_ALconfigs are the */ - goto skip; /* same for IN and OUT in case */ - } /* both ports are opened (bidir). */ - DBUG(("Opened %d output channel(s).\n", past->past_NumOutputChannels)); - samplesPerOutputUserBuffer = pahsc->pahsc_SamplesPerOutputHostBuffer / - pahsc->pahsc_UserBuffersPerHostBuffer; - DBUG(("samplesPerOutputUserBuffer = %d\n", samplesPerOutputUserBuffer)); - } - else - samplesPerOutputUserBuffer = 0; /* Added 2003. */ - /*-----------------------------------------------------------------------*/ - past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */ - PollFD[kPollIN].fd = ALgetfd(pahsc->pahsc_ALportIN); /* ALgetfd returns -1 on failures */ - PollFD[kPollIN].events = POLLIN; /* such as ALport not there. */ - PollFD[kPollOUT].fd = ALgetfd(pahsc->pahsc_ALportOUT); - PollFD[kPollOUT].events = POLLOUT; /* .events = POLLOUT is OK. */ - schedctl(NDPRI, NDPHIMIN); /* Sets non-degrading priority for this process. */ - PollFD[kPollSEMA].fd = usopenpollsema(SendSema, 0777); /* To communicate with parent. */ - PollFD[kPollSEMA].events = POLLIN; /* .events = POLLIN is OK. */ - uspsema(SendSema); /* Blocks until ... MUST be here, this uspsema(). */ - evtLoop = ((past->past_StopNow | past->past_StopSoon) == 0); - while (evtLoop) - { - /*----------------------------- SET FILLPOINTS AND WAIT UNTIL SOMETHING HAPPENS: ---------*/ - if (pahsc->pahsc_InputHostBuffer) /* Then pahsc_ALportIN should also be there. */ - { - /* For input port, fill point is number of locations in the sample queue that must be */ - /* filled in order to trigger a return from select(). (or poll()) */ - /* Notice IRIX docs mention number of samples as argument, not number of sampleframes.*/ - if (ALsetfillpoint(pahsc->pahsc_ALportIN, pahsc->pahsc_SamplesPerInputHostBuffer)) - { /* Multiple amount as transferred per time. */ - ERR_RPT(("ALsetfillpoint() for ALportIN failed.\n")); - sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */ - goto skip; - } - } - /* 'else' added march 2003: set only one of both fillpoints: input or output. When */ - /* setting both fillpoints (as in earlier version) clicks occur at full duplex-mode. */ - else if (pahsc->pahsc_OutputHostBuffer) /* Then pahsc_ALportOUT should also be there. */ - { - /* For output port, fill point is number of locations that must be free in order to */ - /* wake up from select(). (or poll()) */ - if (ALsetfillpoint(pahsc->pahsc_ALportOUT, pahsc->pahsc_SamplesPerOutputHostBuffer)) - { - ERR_RPT(("ALsetfillpoint() for ALportOUT failed.\n")); - sPaHostError = paInternalError; - goto skip; - } - } /* poll() with timeout=-1 makes it block until a requested */ - poll(PollFD, 3, -1); /* event occurs or until call is interrupted. If fd-value in */ - /* array <0, events is ignored and revents is set to 0. */ - /*---------------------------- MESSAGE-EVENT FROM PARENT THREAD: -------------------------*/ - semaEvent = PollFD[kPollSEMA].revents & POLLIN; - if (semaEvent) - { - if (past->past_StopSoon) - evtLoop = 0; - if (past->past_StopNow) - goto skip; - } - /*------------------------------------- FILLED-EVENT FROM INPUT BUFFER: --------------------------*/ - inputEvent = PollFD[kPollIN].revents & POLLIN; - if (inputEvent) /* Don't need to check (pahsc->pahsc_InputHostBuffer): */ - { /* if buffer was not there, ALport not there, no events! */ - if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_InputHostBuffer, - pahsc->pahsc_SamplesPerInputHostBuffer)) - { /* Here again: number of samples instead of number of frames. */ - ERR_RPT(("ALreadsamps() failed.\n")); - sPaHostError = paInternalError; - goto skip; - } - } - outputEvent = PollFD[kPollOUT].revents & POLLOUT; - ioEvent = (inputEvent | outputEvent); /* Binary or is ok. */ - /*------------------------------------- USER-CALLBACK-ROUTINE: -----------------------------------*/ - if (ioEvent) /* Always true? Or can some other system-event awaken the */ - { /* poll? Sure it wasn't just a "sema"- (i.e. user)-event? */ - Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */ - /* user data and call user routine. */ - inBuffer = pahsc->pahsc_InputHostBuffer; /* Short pointers for now, care! */ - outBuffer = pahsc->pahsc_OutputHostBuffer; - n = pahsc->pahsc_UserBuffersPerHostBuffer; /* 'n' may never start at NULL ! */ - do { - result = Pa_CallConvertInt16(past, inBuffer, outBuffer); - if (result) /* This is apparently NOT an error! Just letting the userCallBack stop us. */ - { DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result)); goto skip; } - inBuffer += samplesPerInputUserBuffer; /* Num channels is accounted for. */ - outBuffer += samplesPerOutputUserBuffer; - } while (--n); - Pa_EndUsageCalculation(past); - } - /*------------------------------------ FREE-EVENT FROM OUTPUT BUFFER: ---------------------------*/ - if (pahsc->pahsc_OutputHostBuffer && ioEvent) /* Don't wait for outputEvent solely (that may cause clicks). */ - { /* Just assume it's time to write, outputEvent may not yet be there. */ - if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_OutputHostBuffer, - pahsc->pahsc_SamplesPerOutputHostBuffer)) - { - ERR_RPT(("ALwritesamps() failed.\n")); /* Better use SEMAS for messaging back to parent! */ - sPaHostError = paInternalError; - goto skip; - } - } - } -skip: - /*------------------------------- close AL-ports ----------------------------*/ - if (pahsc->pahsc_ALportIN) - { - if (ALcloseport(pahsc->pahsc_ALportIN)) - translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ - else /* But go on anyway... to release other stuff... */ - pahsc->pahsc_ALportIN = (ALport)0; - } - if (pahsc->pahsc_ALportOUT) - { - if (ALcloseport(pahsc->pahsc_ALportOUT)) - translateSGIerror(); - else - pahsc->pahsc_ALportOUT = (ALport)0; - } -noPahsc: - past->past_IsActive = 0; - if (semaEvent) - { - uspsema(SendSema); /* StopEngine() was still waiting for this acknowledgement. */ - usvsema(RcvSema); /* (semaEvent initialized with 0.) */ - } -noPast: - DBUG(("Leaving sproc-thread.\n")); -} - - -/*--------------------------------------------------------------------------------------*/ -PaError PaHost_OpenStream(internalPortAudioStream *past) -{ - PaError result = paNoError; - PaHostSoundControl *pahsc; - unsigned int minNumBuffers; - internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */ - long pvbuf[8], sr, alq; /* To get/set hardware configs. */ - - DBUG(("PaHost_OpenStream() called.\n")); /* Alloc FASTMEM and init host data. */ - if (!past) - { - ERR_RPT(("Streampointer NULL!\n")); - result = paBadStreamPtr; goto done; - } - pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); - if (pahsc == NULL) - { - ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */ - result = paInsufficientMemory; goto done; /* code (nothing will be freed). */ - } - memset(pahsc, 0, sizeof(PaHostSoundControl)); - pahsc->pahsc_threadPID = -1; /* Should pahsc_threadPID be inited to */ - past->past_DeviceData = (void*)pahsc; /* -1 instead of 0 ?? */ - /*------------------------------------------ Manipulate hardware if necessary and allowed: --*/ - ALseterrorhandler(0); /* 0 = turn off the default error handler. */ - pvbuf[0] = AL_INPUT_RATE; - pvbuf[2] = AL_INPUT_COUNT; - pvbuf[4] = AL_OUTPUT_RATE; /* TO FIX: rates may be logically, not always in Hz! */ - pvbuf[6] = AL_OUTPUT_COUNT; - sr = (long)(past->past_SampleRate + 0.5); /* Common for both input and output :-) */ - /*-----------------------------------------------------------------------------*/ - /* OVERWRITE 'past_NumUserBuffers'-field in the struct supplied by the caller. */ - /* This field may be set to zero by a client application to ask for minimum */ - /* latency. It is used below, to set both input- and output-AL-queuesizes. */ - minNumBuffers = Pa_GetMinNumBuffers(past->past_FramesPerUserBuffer, - past->past_SampleRate); /* Take biggest. */ - past->past_NumUserBuffers = (minNumBuffers > past->past_NumUserBuffers) ? - minNumBuffers : past->past_NumUserBuffers; - DBUG(("past->past_NumUserBuffers=%d\n", past->past_NumUserBuffers)); - /*----------------------------------------------------------------------------------*/ - pahsc->pahsc_UserBuffersPerHostBuffer = past->past_NumUserBuffers >> 1; - DBUG(("pahsc_UserBuffersPerHostBuffer=%d\n",pahsc->pahsc_UserBuffersPerHostBuffer)); - /* 1 is minimum because Pa_GetMinNumBuffers() returns >= 2. - Callback will be called 'pahsc_UserBuffersPerHostBuffer' times (with 'past_FramesPerUserBuffer') - per host transfer. */ - /*---------------------------------------------------- SET INPUT CONFIGURATION: ---------------------*/ - if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */ - { /* sponding native AL-number(s). */ - /*--------------------------------------------------- Allocate native buffers: --------------*/ - pahsc->pahsc_SamplesPerInputHostBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * - past->past_FramesPerUserBuffer * /* Needed by the */ - past->past_NumInputChannels; /* audio-thread. */ - DBUG(("pahsc_SamplesPerInputHostBuffer=%d\n", pahsc->pahsc_SamplesPerInputHostBuffer)); - pahsc->pahsc_BytesPerInputHostBuffer = pahsc->pahsc_SamplesPerInputHostBuffer * sizeof(short); - pahsc->pahsc_InputHostBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputHostBuffer); - if (!pahsc->pahsc_InputHostBuffer) - { - ERR_RPT(("Fast memory allocation failed (in).\n")); - result = paInsufficientMemory; - goto done; - } - padIN = Pa_GetInternalDevice(past->past_InputDeviceID); - if (!padIN) - { - ERR_RPT(("Pa_GetInternalDevice() for input failed.\n")); - result = paHostError; - goto done; - } - if (ALgetparams(padIN->pad_ALdevice, &pvbuf[0], 4)) /* Although input and output will both be on */ - goto sgiError; /* the same AL-device, the AL-library might */ - if (pvbuf[1] != sr) /* contain more than AL_DEFAULT_DEVICE in */ - { /* Rate different from current harware-rate? the future. Therefore 2 seperate queries. */ - if (pvbuf[3] > 0) /* Means, there's other clients using AL-input-ports */ - { - ERR_RPT(("Sorry, not allowed to switch input-hardware to %ld Hz because \ -another process is currently using input at %ld Hz.\n", sr, pvbuf[1])); - result = paHostError; - goto done; - } - pvbuf[1] = sr; /* Then set input-rate. */ - if (ALsetparams(padIN->pad_ALdevice, &pvbuf[0], 2)) - goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */ - } /* IS NOT CHECKED, AT LEAST NOT BY ME, WITHIN THIS FILE! Does PA do? */ - pahsc->pahsc_ALconfigIN = ALnewconfig(); /* Released at PaHost_CloseStream(). */ - if (pahsc->pahsc_ALconfigIN == (ALconfig)0) - goto sgiError; - if (ALsetsampfmt(pahsc->pahsc_ALconfigIN, AL_SAMPFMT_TWOSCOMP))/* Choose paInt16 as native i/o-format. */ - goto sgiError; - if (ALsetwidth (pahsc->pahsc_ALconfigIN, AL_SAMPLE_16)) /* Only meaningful when sample format for */ - goto sgiError; /* config is set to two's complement format. */ - /************************ Future versions might (dynamically) switch to 32-bit floats? ******* - if (ALsetsampfmt(pahsc_ALconfigIN, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.) - goto sgiError; - if (ALsetfloatmax (pahsc_ALconfigIN, 1.0)) Only meaningful when sample format for config - goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */ - /*--------- Set internal AL queuesize (in samples, not in frames!) -------------------------------*/ - alq = (long)past->past_NumUserBuffers * past->past_FramesPerUserBuffer * past->past_NumInputChannels; - DBUG(("AL input queuesize = %ld samples.\n", alq)); - if (ALsetqueuesize(pahsc->pahsc_ALconfigIN, alq)) - goto sgiError; - if (ALsetchannels (pahsc->pahsc_ALconfigIN, (long)(past->past_NumInputChannels))) - goto sgiError; /* Returns 0 on success, -1 on failure. */ - } - else - pahsc->pahsc_InputHostBuffer = (short*)NULL; /* Added 2003! Is checked in callback-routine. */ - /*---------------------------------------------------- SET OUTPUT CONFIGURATION: ------------------------*/ - if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels <= 0! */ - { /* We use padOUT/IN later on, or at least 1 of both. */ - pahsc->pahsc_SamplesPerOutputHostBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * - past->past_FramesPerUserBuffer * /* Needed by the */ - past->past_NumOutputChannels; /* audio-thread. */ - DBUG(("pahsc_SamplesPerOutputHostBuffer=%d\n", pahsc->pahsc_SamplesPerOutputHostBuffer)); - pahsc->pahsc_BytesPerOutputHostBuffer = pahsc->pahsc_SamplesPerOutputHostBuffer * sizeof(short); - pahsc->pahsc_OutputHostBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputHostBuffer); - if (!pahsc->pahsc_OutputHostBuffer) - { - ERR_RPT(("Fast memory allocation failed (out).\n")); - result = paInsufficientMemory; - goto done; - } - padOUT = Pa_GetInternalDevice(past->past_OutputDeviceID); - if (!padOUT) - { - ERR_RPT(("Pa_GetInternalDevice() for output failed.\n")); - result = paHostError; - goto done; - } - if (ALgetparams(padOUT->pad_ALdevice,&pvbuf[4], 4)) - goto sgiError; - if (pvbuf[5] != sr) - { /* Output needed and rate different from current harware-rate. */ - if (pvbuf[7] > 0) /* Means, there's other clients using AL-output-ports */ - { - ERR_RPT(("Sorry, not allowed to switch output-hardware to %ld Hz because \ -another process is currently using output at %ld Hz.\n", sr, pvbuf[5])); - result = paHostError; - goto done; /* Will free again the inputbuffer */ - } /* that was just created above. */ - pvbuf[5] = sr; /* Then set output-rate. */ - if (ALsetparams(padOUT->pad_ALdevice, &pvbuf[4], 2)) - goto sgiError; - } - pahsc->pahsc_ALconfigOUT = ALnewconfig(); /* Released at PaHost_CloseStream(). */ - if (pahsc->pahsc_ALconfigOUT == (ALconfig)0) - goto sgiError; - if (ALsetsampfmt(pahsc->pahsc_ALconfigOUT, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */ - goto sgiError; - if (ALsetwidth (pahsc->pahsc_ALconfigOUT, AL_SAMPLE_16)) /* Only meaningful when sample format for */ - goto sgiError; /* config is set to two's complement format. */ - /** Future versions might (dynamically) switch to 32-bit floats. **/ - alq = (long)past->past_NumUserBuffers * past->past_FramesPerUserBuffer * past->past_NumOutputChannels; - DBUG(("AL output queuesize = %ld samples.\n", alq)); - if (ALsetqueuesize(pahsc->pahsc_ALconfigOUT, alq)) - goto sgiError; - if (ALsetchannels (pahsc->pahsc_ALconfigOUT, (long)(past->past_NumOutputChannels))) - goto sgiError; - } - else - pahsc->pahsc_OutputHostBuffer = (short*)NULL; - /*----------------------------------------------- TEST DEVICE ID's: --------------------*/ - if ((past->past_OutputDeviceID != past->past_InputDeviceID) && /* Who SETS these devive-numbers? */ - (past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0)) - { - ERR_RPT(("Cannot setup bidirectional stream between different devices.\n")); - result = paHostError; - goto done; - } - goto done; /* (no errors occured) */ -sgiError: - result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ -done: - if (result != paNoError) - PaHost_CloseStream(past); /* Frees memory (only if really allocated!). */ - return result; -} - -/*-----------------------------------------------------*/ -PaError PaHost_StartOutput(internalPortAudioStream *past) -{ - return paNoError; /* Hmm, not implemented yet? */ -} -PaError PaHost_StartInput(internalPortAudioStream *past) -{ - return paNoError; -} - -/*------------------------------------------------------------------------------*/ -PaError PaHost_StartEngine(internalPortAudioStream *past) -{ - PaHostSoundControl *pahsc; - usptr_t *arena; - if (!past) /* Test argument. */ - { - ERR_RPT(("PaHost_StartEngine(NULL)!\n")); - return paBadStreamPtr; - } - pahsc = (PaHostSoundControl*)past->past_DeviceData; - if (!pahsc) - { - ERR_RPT(("PaHost_StartEngine(arg): arg->past_DeviceData = NULL!\n")); - return paHostError; - } - past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */ - past->past_StopNow = 0; /* Why don't we check pahsc for NULL? */ - past->past_IsActive = 1; - - /* Although the pthread_create() function, as well as <pthread.h>, may be */ - /* available in IRIX, use sproc() on SGI to create audio-background-thread. */ - /* (Linux/oss uses pthread_create() instead of __clone() because: */ - /* - pthread_create also works for other UNIX systems like Solaris, */ - /* - Java HotSpot VM crashes in pthread_setcanceltype() using __clone().) */ - - usconfig(CONF_ARENATYPE, US_SHAREDONLY); /* (From SGI-AL-examples, file */ - arena = usinit(tmpnam(0)); /* motifexample.c, function */ - SendSema = usnewpollsema(arena, 0); /* InitializeAudioProcess().) */ - RcvSema = usnewsema(arena, 1); /* 1= common mutual exclusion semaphore, where 1 and only 1 process - will be permitted through a semaphore at a time. Values > 1 - imply that up to val resources may be simultaneously used, but requests - for more than val resources cause the calling process to block until a - resource comes free (by a process holding a resource performing a - usvsema(). IS THIS usnewsema() TOO PLATFORM SPECIFIC? */ - prctl(PR_SETEXITSIG, 0); /* No not (void*)9, but 0, which doesn't kill the parent! */ - /* PR_SETEXITSIG controls whether all members of a share group will be - signaled if any one of them leaves the share group (either via exit() - or exec()). If 2nd arg, interpreted as an int is 0, then normal IRIX - process termination rules apply, namely that the parent is sent a - SIGCLD upon death of child, but no indication of death of parent is - given. If the second argument is a valid signal number then if any - member of a share group leaves the share group, a signal is - sent to ALL surviving members of the share group. */ - /* SPAWN AUDIO-CHILD: */ - pahsc->pahsc_threadPID = sproc(Pa_SgiAudioProcess, /* Returns process ID of */ - PR_SALL, /* new process, or -1. */ - (void*)past); /* Pass past as optional */ /* IS THIS SAFE, will past never */ - if (pahsc->pahsc_threadPID == -1) /* third void-ptr-arg. */ /* be moved around in memory???? */ - { - ERR_RPT(("PaHost_StartEngine() failed to spawn audio-thread.\n")); - sPaHostError = oserror(); /* Pass native error-number to shared area. */ - return paHostError; /* But return the generic error-number. */ - } - return paNoError; /* Hmmm, errno may come from other threads in same group! */ -} /* ("man sproc" in IRIX6.2 to read about _SGI_MP_SOURCE.) */ - -/*------------------------------------------------------------------------------*/ -PaError PaHost_StopEngine(internalPortAudioStream *past, int abort) -{ - PaError result = paNoError; - PaHostSoundControl *pahsc; - - DBUG(("PaHost_StopEngine() called.\n")); - if (!past) - return paBadStreamPtr; - pahsc = (PaHostSoundControl*)past->past_DeviceData; - /* Prevent from doing this twice!! */ - if ((!pahsc) || /* Some tests call this CLOSE twice!! */ - (!past->past_IsActive) || - past->past_StopSoon || past->past_StopNow) - return result; /* paNoError (already stopped, no err?). */ - past->past_StopSoon = 1; /* Tell background thread to stop generating */ - if (abort) /* more and to let current data play out. If */ - past->past_StopNow = 1; /* aborting, tell backgrnd thread to stop NOW! */ - /*---- USE SEMAPHORE LOCK TO COMMUNICATE: -----*/ - usvsema(SendSema); /* Increments count associated with SendSema. */ - /* Wait for the response. */ - uspsema(RcvSema); /* Decrements count of previously allocated */ - /* semaphore specified by RcvSema. */ - while (past->past_IsActive) /* REALLY WAIT. */ - { - /* DBUG(("wait 1 ms for audio-thread to stop.\n")); */ - Pa_Sleep(1); - } - -#if 0 /* We don't need to KILL(), just COMMUNICATE and be patient... */ - if (pahsc->pahsc_threadPID != -1) /* Did we really init it to -1 somewhere? */ - { - DBUG(("PaHost_StopEngine() is about to kill(SIGKILL) audio-thread.\n")); - if (kill(pahsc->pahsc_threadPID, SIGKILL)) /* Or SIGTERM or SIGQUIT(core) */ - { /* Returns -1 in case of error. */ - result = paHostError; - sPaHostError = oserror(); /* Hmmm, other threads may also write here! */ - ERR_RPT(("PaHost_StopEngine() failed to kill audio-thread.\n")); - } - else - pahsc->pahsc_threadPID = -1; /* Notify that we've killed this thread. */ - } -#endif - past->past_IsActive = 0; /* Even when kill() failed and pahsc_threadPID still there??? */ - return result; -} - -/*---------------------------------------------------------------*/ -PaError PaHost_StopOutput(internalPortAudioStream *past, int abort) -{ - return paNoError; /* Not implemented yet? */ -} -PaError PaHost_StopInput(internalPortAudioStream *past, int abort ) -{ - return paNoError; -} - -/*******************************************************************/ -PaError PaHost_CloseStream(internalPortAudioStream *past) -{ - PaHostSoundControl *pahsc; - PaError result = paNoError; - - DBUG(("PaHost_CloseStream() called.\n")); - if (!past) - return paBadStreamPtr; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if (!pahsc) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */ - return result; /* This test prevents from freeing NULL-pointers. */ - - if (pahsc->pahsc_ALconfigIN) - { /* Release configuration structs, only if allocated. */ - ALfreeconfig(pahsc->pahsc_ALconfigIN); - pahsc->pahsc_ALconfigIN = NULL; - } - if (pahsc->pahsc_ALconfigOUT) - { - ALfreeconfig(pahsc->pahsc_ALconfigOUT); /* (Al-ports were already closed by audioProcess). */ - pahsc->pahsc_ALconfigOUT = NULL; - } - if (pahsc->pahsc_InputHostBuffer) - { - PaHost_FreeFastMemory(pahsc->pahsc_InputHostBuffer, pahsc->pahsc_BytesPerInputHostBuffer); - pahsc->pahsc_InputHostBuffer = NULL; - } - if (pahsc->pahsc_OutputHostBuffer) - { - PaHost_FreeFastMemory(pahsc->pahsc_OutputHostBuffer, pahsc->pahsc_BytesPerOutputHostBuffer); - pahsc->pahsc_OutputHostBuffer = NULL; - } - PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl)); - past->past_DeviceData = NULL; /* PaHost_OpenStream() allocated FAST MEM. */ - return result; -} - - -/*------------------------------------------------------------------------*/ -/* Determine minimum number of buffers required for (SGI) host based on */ -/* minimum latency. Latency can be optionally set by user by setting an */ -/* environment variable. For example, to set my latency to 200 msec, I've */ -/* put this line in my '.cshrc' file: setenv PA_MIN_LATENCY_MSEC 200 */ -/* It always calls the 'PRINT' macro. */ -/* The minimum number that is returned is 2. */ -/* This number is directly proportional to the AL-queue sizes to set up. */ -/* It is one more than the number of user buffers per host buffer - in */ -/* case minimum is returned, or, twice the user buffers per host buffer. */ -/*------------------------------------------------------------------------*/ -int Pa_GetMinNumBuffers(int framesPerUserBuffer, double framesPerSecond) -{ - int minBuffers, minLatencyMsec; - char *minLatencyText; - double actualLatency; - - minLatencyText = getenv(PA_LATENCY_ENV_NAME); /* Defined at top of file. */ - if (minLatencyText) - { - minLatencyMsec = atoi(minLatencyText); - if (minLatencyMsec < 10) - { /* 10 is the minimum. */ - minLatencyMsec = 10; - PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' below minimum of %d milliseconds.\n", - minLatencyMsec)); - } - else if (minLatencyMsec > 4000) - { /* 4000 is the maximum. */ - minLatencyMsec = 4000; - PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' above maximum of %d milliseconds.\n", - minLatencyMsec)); - } - else - PRINT (("Using environment variable 'PA_MIN_LATENCY_MSEC' (set to %d milliseconds).\n", - minLatencyMsec)); - } - else - { - minLatencyMsec = MIN_LATENCY_MSEC; /* Defined at top of this file. */ - PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' not found.\nUsing default of %d milliseconds\n", - minLatencyMsec)); - } - minBuffers = (int)((minLatencyMsec * framesPerSecond) / - (1000.0 * framesPerUserBuffer)); - if (minBuffers < 2) - minBuffers = 2; - actualLatency = 1000.0 * minBuffers * framesPerUserBuffer / framesPerSecond; - PRINT (("Actual AL latency set to %.2f milliseconds\n", actualLatency)); - return minBuffers; -} - -/*---------------------------------------------------------------------*/ -PaError PaHost_Term(void) /* Frees all of the linked audio-devices. */ -{ /* Called by Pa_Terminate() from pa_lib.c. */ - internalPortAudioDevice *pad = sDeviceList, - *nxt; - while (pad) - { - DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName)); - nxt = pad->pad_Next; - PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); - pad = nxt; /* PaHost_Init allocated this fast mem.*/ - } - sDeviceList = (internalPortAudioDevice*)NULL; - return 0; -} - -/***********************************************************************/ -void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */ -{ -#if 0 - struct timeval timeout; - timeout.tv_sec = msec / 1000; - timeout.tv_usec = (msec % 1000) * 1000; - select(0, NULL, NULL, NULL, &timeout); -#else - long usecs = msec * 1000; - usleep( usecs ); -#endif -} - -/*---------------------------------------------------------------------------------------*/ -/* Allocate memory that can be accessed in real-time. This may need to be held in physi- */ -/* cal memory so that it is not paged to virtual memory. This call MUST be balanced with */ -/* a call to PaHost_FreeFastMemory(). */ -void *PaHost_AllocateFastMemory(long numBytes) -{ - void *addr = malloc(numBytes); /* mpin() reads into memory all pages over the given */ - if (addr) /* range and locks the pages into memory. A counter */ - { /* is incremented each time the page is locked. The */ - if (mpin(addr, numBytes)) /* superuser can lock as many pages as it wishes, */ - { /* others are limited to the configurable PLOCK_MA. */ - ERR_RPT(("PaHost_AllocateFastMemory() failed to mpin() memory.\n")); -#if 1 - free(addr); /* You MAY cut out these 2 lines to be less strict, */ - addr = NULL; /* you then only get the warning but PA goes on... */ -#endif /* Only problem then may be corresponding munpin() */ - } /* call at PaHost_FreeFastMemory(), below. */ - memset(addr, 0, numBytes); /* Locks established with mlock are not inherited by */ - } /* a child process after a fork. Furthermore, IRIX- */ - return addr; /* man-pages warn against mixing both mpin and mlock */ -} /* in 1 piece of code, so stick to mpin()/munpin() ! */ - - -/*---------------------------------------------------------------------------------------*/ -/* Free memory that could be accessed in real-time. This call MUST be balanced with a */ -/* call to PaHost_AllocateFastMemory(). */ -void PaHost_FreeFastMemory(void *addr, long numBytes) -{ - if (addr) - { - if (munpin(addr, numBytes)) /* Will munpin() fail when it was never mpinned? */ - ERR_RPT(("WARNING: PaHost_FreeFastMemory() failed to munpin() memory.\n")); - free(addr); /* But go on, try to release it, just warn... */ - } -} - -/*----------------------------------------------------------*/ -PaError PaHost_StreamActive( internalPortAudioStream *past ) -{ - PaHostSoundControl *pahsc; - if (past == NULL) - return paBadStreamPtr; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if (pahsc == NULL) - return paInternalError; - return (PaError)(past->past_IsActive != 0); -} - -/*-------------------------------------------------------------------*/ -PaTimestamp Pa_StreamTime( PortAudioStream *stream ) -{ - internalPortAudioStream *past = (internalPortAudioStream *) stream; -/* FIXME - return actual frames played, not frames generated. -** Need to query the output device somehow. -*/ - return past->past_FrameCount; -} diff --git a/pd/portaudio_v18/pa_sgi/pthread-Makefile b/pd/portaudio_v18/pa_sgi/pthread-Makefile deleted file mode 100644 index 527677a8..00000000 --- a/pd/portaudio_v18/pa_sgi/pthread-Makefile +++ /dev/null @@ -1,52 +0,0 @@ -# Make PortAudio for Silicon Graphics IRIX (6.2) -# Pieter suurmond, september 22, 2001. (v15 pa_sgi sub-version #0.18) - -# pthread, math (as with linux) and SGI audio library: -# SGI-books say -lpthread should be the last on the line. -LIBS = -lm -laudio -lpthread - -CDEFINES = -I../pa_common - -# Possible CFLAGS with MIPSpro compiler are: -32, -o32, -n32, -64, -# -mips1, -mips2, -mips3, -mips4, etc. Use -g, -g2, -g3 for debugging. -# And use for example -O2 or -O3 for better optimization: -CFLAGS = -O2 -PASRC = ../pa_common/pa_lib.c pa_sgi.c -PAINC = ../pa_common/portaudio.h - -# Tests that work (SGI Indy with R5000 @ 180MHz running IRIX 6.2). -#TESTC = $(PASRC) ../pa_tests/patest_record.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_many.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_latency.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # OK but needs more than 4 buffers to do without glitches. -TESTC = $(PASRC) ../pa_tests/patest_saw.c # Seems OK (does it gracefully exit?). -#TESTC = $(PASRC) ../pa_tests/patest_wire.c # OK -#TESTC = $(PASRC) ../pa_tests/pa_devs.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_sine.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_pink.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_clip.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_stop.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_dither.c # OK -#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore. - -# Tests that do not yet work. -#TESTC = $(PASRC) ../pa_tests/paqa_devs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 1 output channel(s) on AL default -#TESTC = $(PASRC) ../pa_tests/paqa_errs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 2 output channel(s) on AL default -#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # THIS FUZZ CRASHED MY WHOLE IRIX SYSTEM after "ENTER"! :-( - # PROCESS IN ITSELF RUNS OK, WITH LARGER BUFFSIZES THOUGH. - # OH MAYBE IT WAS BECAUSE DEBUGGING WAS ON??? - # ANYWAY, I'M NOT GONNA RUN THAT AGAIN... WAY TOO DANGEROUS! -TESTH = $(PAINC) - -all: patest - -# "cc" for the MIPSpro compiler, may be changed to "gcc": -patest: $(TESTC) $(TESTH) Makefile - cc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest - -run: patest - ./patest - diff --git a/pd/portaudio_v18/pa_sgi/pthread-pa_sgi.c b/pd/portaudio_v18/pa_sgi/pthread-pa_sgi.c deleted file mode 100644 index e9ab273c..00000000 --- a/pd/portaudio_v18/pa_sgi/pthread-pa_sgi.c +++ /dev/null @@ -1,908 +0,0 @@ -/* - * PortAudio Portable Real-Time Audio Library - * Latest Version at: http://www.portaudio.com - * SGI IRIX implementation by Pieter Suurmond, september 22, 2001 (#0.18). - * - * Copyright (c) 1999-2001 Phil Burk - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -/* -Modfication History: - 8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2. - 8/17/2001 - alpha release with IRIX sproc()-method, may sometimes let IRIX6.2 crash at closing audiostream. - 9/22/2001 - #0.18 pthread starts to work a bit: - BUT UNDER IRIX6.2, I DON'T GET IT TO WORK REALLY CORRECTLY, - this POSIX-attempt, - DON'T USE THIS FILE FOR RELIABLE OPERATION, IT IS HERE JUST - FOR DOCUMENTATION/ARCHIVE... OR FOR ANYONE WHO WANTS TO FIX...... -TODO: - - Test under IRIX 6.5. - - Dynamically switch to 32 bit float as native format when appropriate (let SGI do the conversion), - and maybe also the other natively supported formats? (might increase performance) - - Not sure whether CPU UTILIZATION MEASUREMENT (from OSS/linux) really works. Changed nothing yet, - seems ok, but I've not yet tested it thoroughly. (maybe utilization-code may be made _unix_common_ then?) - - The minimal number of buffers setting... I do not yet fully understand it.. I now just take *4. -REFERENCES: - - IRIX 6.2 man pages regarding SGI AL library. - - IRIS Digital MediaProgramming Guide (online books as well as man-pages come with IRIX 6.2 and - may not be publically available on the internet). -*/ - -#include <stdio.h> /* Standard libraries. */ -#include <stdlib.h> - -#include "../pa_common/portaudio.h" /* Portaudio headers. */ -#include "../pa_common/pa_host.h" -#include "../pa_common/pa_trace.h" - -/* -#include <malloc.h> -#include <memory.h> -#include <sys/prctl.h> Not needed -#include <sys/types.h> -#include <sys/schedctl.h> -#include <signal.h> -#include <sys/ioctl.h> Needed? -#include <sys/time.h> -#include <sched.h> sched_param struct and related functions - used in setting thread priorities. -#include <limits.h> Some POSIX constants such as _POSIX_THREAD_THREADS_MAX -*/ - -#include <pthread.h> /* Pthreads are supported by IRIX 6.2 after */ - /* patches 1361, 1367, and 1429 are applied. */ - -#include <fcntl.h> /* fcntl.h needed for "O_RDONLY". */ -#include <unistd.h> /* For usleep() and constants used when calling sysconf() */ - /* to query POSIX limits (see the sysconf(3) ref. page. */ - -#include <dmedia/audio.h> /* SGI-specific audio library. */ - - -/*--------------------------------------------*/ -#define PRINT(x) { printf x; fflush(stdout); } -#define ERR_RPT(x) PRINT(x) -#define DBUG(x) PRINT(x) -#define DBUGX(x) /* PRINT(x) */ - -#define MAX_CHARS_DEVNAME (16) /* Was 32 in OSS (20 for AL but "in"/"out" is concat. */ -#define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7 (was 10 in OSS v15). */ - -typedef struct internalPortAudioDevice /* IRIX specific device info: */ -{ - PaDeviceID /* NEW: */ pad_DeviceID; /* THIS "ID" IS NEW HERE (Pieter)! */ - long pad_ALdevice; /* SGI-number! */ - double pad_SampleRates[MAX_SAMPLE_RATES]; /* for pointing to from pad_Info */ - char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */ - PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */ - /* int structVersion; */ - /* const char* name; */ - /* int maxInputChannels, maxOutputChannels; */ - /* int numSampleRates; Num rates, or -1 if range supprtd. */ - /* const double* sampleRates; Array of supported sample rates, */ - /* PaSampleFormat nativeSampleFormats; or {min,max} if range supported. */ - struct internalPortAudioDevice* pad_Next; /* Singly linked list, (NULL=end). */ -} internalPortAudioDevice; - -typedef struct PaHostSoundControl /* Structure to contain all SGI IRIX specific data. */ -{ - ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */ - pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */ - pthread_t pahsc_ThreadPID; - short *pahsc_NativeInputBuffer, /* Allocated here, in this file, if necessary. */ - *pahsc_NativeOutputBuffer; - unsigned int pahsc_BytesPerInputBuffer, /* Native buffer sizes in bytes, really needed here */ - pahsc_BytesPerOutputBuffer; /* to free FAST memory, if buffs were alloctd FAST. */ - unsigned int pahsc_SamplesPerInputBuffer, /* These amounts are needed again and again in the */ - pahsc_SamplesPerOutputBuffer; /* audio-thread (don't need to be kept globally). */ - struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */ - pahsc_LastExitTime; - long pahsc_InsideCountSum, - pahsc_TotalCountSum; -} PaHostSoundControl; - -/*----------------------------- Shared Data ------------------------------------------------------*/ -static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */ -static int sPaHostError = 0; /* Maybe more than one process writing errs!? */ - -long Pa_GetHostError(void) -{ - return (long)sPaHostError; -} - -/*----------------------------- BEGIN CPU UTILIZATION MEASUREMENT -----------------*/ -/* (copied from source pa_linux_oss/pa_linux_oss.c) */ -static void Pa_StartUsageCalculation( internalPortAudioStream *past ) -{ - struct itimerval itimer; - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return; -/* Query system timer for usage analysis and to prevent overuse of CPU. */ - getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime ); -} - -static long SubtractTime_AminusB( struct itimerval *timeA, struct itimerval *timeB ) -{ - long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec; - long usecs = secs * 1000000; - usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec); - return usecs; -} - -static void Pa_EndUsageCalculation( internalPortAudioStream *past ) -{ - struct itimerval currentTime; - long insideCount; - long totalCount; /* Measure CPU utilization during this callback. */ - -#define LOWPASS_COEFFICIENT_0 (0.95) -#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) - - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if (pahsc == NULL) - return; - if (getitimer( ITIMER_REAL, ¤tTime ) == 0 ) - { - if (past->past_IfLastExitValid) - { - insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, ¤tTime ); - pahsc->pahsc_InsideCountSum += insideCount; - totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, ¤tTime ); - pahsc->pahsc_TotalCountSum += totalCount; - /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */ - /* Low pass filter the result because sometimes we get called several times in a row. */ - /* That can cause the TotalCount to be very low which can cause the usage to appear */ - /* unnaturally high. So we must filter numerator and denominator separately!!! */ - if (pahsc->pahsc_InsideCountSum > 0) - { - past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) + - (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum)); - past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) + - (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum)); - past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount; - pahsc->pahsc_InsideCountSum = 0; - pahsc->pahsc_TotalCountSum = 0; - } - } - past->past_IfLastExitValid = 1; - } - pahsc->pahsc_LastExitTime.it_value.tv_sec = 100; - pahsc->pahsc_LastExitTime.it_value.tv_usec = 0; - setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL ); - past->past_IfLastExitValid = 1; -} /*----------- END OF CPU UTILIZATION CODE (from pa_linux_oss/pa_linux_oss.c v15)--------------------*/ - - -/*--------------------------------------------------------------------------------------*/ -PaError translateSGIerror(void) /* Calls oserror(), may be used after an SGI AL-library */ -{ /* call to report via ERR_RPT(), yields a PaError-num. */ - const char* a = "SGI AL "; /* (Not absolutely sure errno came from THIS thread! */ - switch(oserror()) /* Read IRIX man-pages about the _SGI_MP_SOURCE macro.) */ - { - case AL_BAD_OUT_OF_MEM: - ERR_RPT(("%sout of memory.\n", a)); - return paInsufficientMemory; /* Known PaError. */ - case AL_BAD_CONFIG: - ERR_RPT(("%sconfiguration invalid or NULL.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_CHANNELS: - ERR_RPT(("%schannels not 1,2 or 4.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_NO_PORTS: - ERR_RPT(("%sout of audio ports.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_DEVICE: - ERR_RPT(("%swrong device number.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_DEVICE_ACCESS: - ERR_RPT(("%swrong device access.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_DIRECTION: - ERR_RPT(("%sinvalid direction.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_SAMPFMT: - ERR_RPT(("%sdoesn't accept sampleformat.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_FLOATMAX: - ERR_RPT(("%smax float value is zero.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_WIDTH: - ERR_RPT(("%sunsupported samplewidth.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_QSIZE: - ERR_RPT(("%sinvalid queue size.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_PVBUFFER: - ERR_RPT(("%sPVbuffer null.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_BUFFERLENGTH_NEG: - ERR_RPT(("%snegative bufferlength.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_BUFFERLENGTH_ODD: - ERR_RPT(("%sodd bufferlength.\n", a)); - return paHostError; /* Generic PaError. */ - case AL_BAD_PARAM: - ERR_RPT(("%sparameter not valid for device.\n", a)); - return paHostError; /* Generic PaError. */ - default: - ERR_RPT(("%sunknown error.\n", a)); - return paHostError; /* Generic PaError. */ - } -} - -/*------------------------------------------------------------------------------------------*/ -/* Tries to set various rates and formats and fill in the device info structure. */ -static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT_DEVICE) */ - PaDeviceID id, /* (DefaultI|ODeviceID()) */ - char* name, /* (for example "SGI AL") */ - internalPortAudioDevice* pad) /* Result written to pad. */ -{ - int format; - long min, max; /* To catch hardware characteristics. */ - ALseterrorhandler(0); /* 0 = turn off the default error handler. */ - /*--------------------------------------------------------------------------------------*/ - pad->pad_ALdevice = ALdev; /* Set the AL device number. */ - pad->pad_DeviceID = id; /* Set the PA device number. */ - if (strlen(name) > MAX_CHARS_DEVNAME) /* MAX_CHARS defined above. */ - { - ERR_RPT(("Pa_QueryDevice(): name too long (%s).\n", name)); - return paHostError; - } - strcpy(pad->pad_DeviceName, name); /* Write name-string. */ - pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */ - /*--------------------------------- natively supported sample formats: -----------------*/ - pad->pad_Info.nativeSampleFormats = paInt16; /* Later also include paFloat32 | ..| etc. */ - /* Then also choose other CallConvertXX()! */ - /*--------------------------------- number of available i/o channels: ------------------*/ - if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max)) - return translateSGIerror(); - pad->pad_Info.maxInputChannels = max; - DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels)) - if (ALgetminmax(ALdev, AL_OUTPUT_COUNT, &min, &max)) - return translateSGIerror(); - pad->pad_Info.maxOutputChannels = max; - DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels)) - /*--------------------------------- supported samplerates: ----------------------*/ - pad->pad_Info.numSampleRates = 7; - pad->pad_Info.sampleRates = pad->pad_SampleRates; - pad->pad_SampleRates[0] = (double)AL_RATE_8000; /* long -> double. */ - pad->pad_SampleRates[1] = (double)AL_RATE_11025; - pad->pad_SampleRates[2] = (double)AL_RATE_16000; - pad->pad_SampleRates[3] = (double)AL_RATE_22050; - pad->pad_SampleRates[4] = (double)AL_RATE_32000; - pad->pad_SampleRates[5] = (double)AL_RATE_44100; - pad->pad_SampleRates[6] = (double)AL_RATE_48000; - if (ALgetminmax(ALdev, AL_INPUT_RATE, &min, &max)) /* Ask INPUT rate-max. */ - return translateSGIerror(); /* double -> long. */ - if (max != (long)(0.5 + pad->pad_SampleRates[6])) /* FP-compare not recommndd. */ - goto weird; - if (ALgetminmax(ALdev, AL_OUTPUT_RATE, &min, &max)) /* Ask OUTPUT rate-max. */ - return translateSGIerror(); - if (max != (long)(0.5 + pad->pad_SampleRates[6])) - { -weird: ERR_RPT(("Pa_sgiQueryDevice() did not confirm max samplerate (%ld)\n",max)); - return paHostError; /* Or make it a warning and just carry on... */ - } - /*-------------------------------------------------------------------------------*/ - return paNoError; -} - - -/*--------------------------------------------------------------------------------*/ -int Pa_CountDevices() /* Name of this function suggests it only counts and */ -{ /* is NOT destructive, it however resets whole PA ! */ - int numDevices = 0; /* Let 's not do that here. */ - internalPortAudioDevice* currentDevice = sDeviceList; /* COPY GLOBAL VAR. */ -#if 0 /* Remains from linux_oss v15: Pa_Initialize(), on */ - if (!currentDevice) /* its turn, calls PaHost_Init() via file pa_lib.c. */ - Pa_Initialize(); /* Isn't that a bit too 'rude'? Don't be too */ -#endif /* friendly to clients that forgot to initialize PA. */ - while (currentDevice) /* Slower but more elegant than the sNumDevices-way: */ - { - numDevices++; - currentDevice = currentDevice->pad_Next; - } - return numDevices; -} - -/*-------------------------------------------------------------------------------*/ -static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id) -{ - int numDevices = 0; - internalPortAudioDevice *res = (internalPortAudioDevice*)NULL; - internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */ - while (pad) /* pad may be NULL, that's ok, return 0. */ - { /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */ - if (pad->pad_DeviceID == id) /* This the device we were looking for? */ - res = pad; /* But keep on(!) counting so we don't */ - numDevices++; /* have to call Pa_CountDevices() later. */ - pad = pad->pad_Next; /* Advance to the next device or NULL. */ - } /* No assumptions about order of ID's in */ - if (!res) /* the list. */ - ERR_RPT(("Pa_GetInternalDevice() could not find specified ID (%d).\n",id)); - if ((id < 0) || (id >= numDevices)) - { - ERR_RPT(("Pa_GetInternalDevice() supplied with an illegal ID (%d).\n",id)); -#if 1 /* Be strict, even when found, */ - res = (internalPortAudioDevice*)NULL; /* do not accept illegal ID's. */ -#endif - } - return res; -} - -/*----------------------------------------------------------------------*/ -const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id) -{ - PaDeviceInfo* res = (PaDeviceInfo*)NULL; - internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */ - if (pad) - res = &pad->pad_Info; /* Not finding the specified ID is not */ - if (!res) /* the same as &pad->pad_Info == NULL. */ - ERR_RPT(("Pa_GetDeviceInfo() could not find it (ID=%d).\n", id)); - return res; /* So (maybe) a second/third ERR_RPT(). */ -} - -/*------------------------------------------------*/ -PaDeviceID Pa_GetDefaultInputDeviceID(void) -{ - return 0; /* 0 is the default device ID. */ -} -/*------------------------------------------------*/ -PaDeviceID Pa_GetDefaultOutputDeviceID(void) -{ - return 0; -} - -/*-------------------------------------------------------------------------------------------------*/ -/* Build linked a list with all the available audio devices on this SGI machine (only 1 for now). */ -PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */ -{ - internalPortAudioDevice* pad; - PaError r = paNoError; - int audioLibFileID; /* To test for the presence of audio. */ - - if (sDeviceList) /* Allow re-init, only warn, no error. */ - { - ERR_RPT(("Warning: PaHost_Init() did not really re-init PA.\n")); - return r; - } - /*------------- ADD THE SGI DEFAULT DEVICE TO THE LIST: ---------------------------------------*/ - audioLibFileID = open("/dev/hdsp/hdsp0master", O_RDONLY); /* Try to open Indigo style audio */ - if (audioLibFileID < 0) /* IO port. On failure, machine */ - { /* has no audio ability. */ - ERR_RPT(("PaHost_Init(): This machine has no (Indigo-style) audio abilities.\n")); - return paHostError; - } - close(audioLibFileID); /* Allocate fast mem to hold device info. */ - pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice)); - if (pad == NULL) - return paInsufficientMemory; - memset(pad, 0, sizeof(internalPortAudioDevice)); /* "pad->pad_Next = NULL" is more elegant. */ - r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */ - Pa_GetDefaultOutputDeviceID(),/* Set PA device num (or InputDeviceID()). */ - "AL default", /* A suitable name. */ - pad); /* Write args and queried info into pad. */ - if (r != paNoError) - { - ERR_RPT(("Pa_QueryDevice for '%s' returned: %d\n", pad->pad_DeviceName, r)); - PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */ - } - else - sDeviceList = pad; /* First element in linked list. pad->pad_Next already NULL. */ - /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LINKED LIST: -------------------*/ - /*---------------------------------------------------------------------------------------------*/ - return r; -} - -/*---------------------------------------------------------------------------------------------------*/ -static PaError Pa_SgiAudioProcess(internalPortAudioStream *past) /* Spawned by PaHost_StartEngine(). */ -{ - PaError result = paNoError; - PaHostSoundControl *pahsc; - - if (!past) - return paBadStreamPtr; - pahsc = (PaHostSoundControl*)past->past_DeviceData; - if (!pahsc) - return paInternalError; - past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */ - DBUG(("entering thread.\n")); - - while (!past->past_StopSoon) /* OR-ing StopSoon and StopNow here gives problems! */ - { - /*---------------------------------------- INPUT: ------------------------------------*/ - if (pahsc->pahsc_NativeInputBuffer) /* Then pahsc_ALportIN should also be there! */ - { - while (ALgetfilled(pahsc->pahsc_ALportIN) < pahsc->pahsc_SamplesPerInputBuffer) - { - /* Trying sginap(1); and usleep(); here... things get blocked under IRIX6.2. */ - if (past->past_StopNow) /* Don't let ALreadsamps() block */ - goto done; - } - if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_NativeInputBuffer, - pahsc->pahsc_SamplesPerInputBuffer)) /* Number of samples instead */ - { /* of number of frames. */ - ERR_RPT(("ALreadsamps() failed.\n")); - result = paInternalError; - goto done; - } - } - /*---------------------------------------------------- USER CALLBACK ROUTINE: ----------*/ - /* DBUG(("Calling Pa_CallConvertInt16()...\n")); */ - Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */ - result = Pa_CallConvertInt16(past, /* user data and call user routine. */ - pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_NativeOutputBuffer); - Pa_EndUsageCalculation(past); - if (result) - { - DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result)); - goto done; /* This is apparently NOT an error! */ - } /* Just letting the userCallBack stop us. */ - /*---------------------------------------- OUTPUT: ------------------------------------*/ - if (pahsc->pahsc_NativeOutputBuffer) /* Then pahsc_ALportOUT should also be there! */ - { - while (ALgetfillable(pahsc->pahsc_ALportOUT) < pahsc->pahsc_SamplesPerOutputBuffer) - { - /* Trying sginap(1); and usleep(); here... things get blocked under IRIX6.2. */ - if (past->past_StopNow) /* Don't let ALwritesamps() block */ - goto done; - } - if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_NativeOutputBuffer, - pahsc->pahsc_SamplesPerOutputBuffer)) - { - ERR_RPT(("ALwritesamps() failed.\n")); - result = paInternalError; - goto done; - } - } - /*-------------------------------------------------------------------------------------*/ - } -done: - /* pahsc->pahsc_ThreadPID = -1; Hu? doesn't help!! (added by Pieter) */ - past->past_IsActive = 0; - DBUG(("leaving thread.\n")); - return result; -} - - -/*--------------------------------------------------------------------------------------*/ -PaError PaHost_OpenStream(internalPortAudioStream *past) -{ - PaError result = paNoError; - PaHostSoundControl *pahsc; - unsigned int minNumBuffers; - internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */ - ALconfig sgiALconfig = NULL; /* IRIX-datatype. */ - long pvbuf[8]; /* To get/set hardware configs. */ - long sr, ALqsize; - DBUG(("PaHost_OpenStream() called.\n")); /* Alloc FASTMEM and init host data. */ - if (!past) - { - ERR_RPT(("Streampointer NULL!\n")); - result = paBadStreamPtr; goto done; - } - pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); - if (pahsc == NULL) - { - ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */ - result = paInsufficientMemory; goto done; /* code (nothing will be freed). */ - } - memset(pahsc, 0, sizeof(PaHostSoundControl)); -/* pahsc->pahsc_threadPID = -1; Should pahsc_threadPID be inited to */ - past->past_DeviceData = (void*)pahsc; /* -1 instead of 0 ?? */ - /*--------------------------------------------------- Allocate native buffers: --------*/ - pahsc->pahsc_SamplesPerInputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ - past->past_NumInputChannels; /* audio-thread. */ - pahsc->pahsc_BytesPerInputBuffer = pahsc->pahsc_SamplesPerInputBuffer * sizeof(short); - if (past->past_NumInputChannels > 0) /* Assumes short = 16 bits! */ - { - pahsc->pahsc_NativeInputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputBuffer); - if( pahsc->pahsc_NativeInputBuffer == NULL ) - { - ERR_RPT(("Fast memory allocation for input-buffer failed.\n")); - result = paInsufficientMemory; goto done; - } - } - pahsc->pahsc_SamplesPerOutputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */ - past->past_NumOutputChannels; /* audio-thread. */ - pahsc->pahsc_BytesPerOutputBuffer = pahsc->pahsc_SamplesPerOutputBuffer * sizeof(short); - if (past->past_NumOutputChannels > 0) /* Assumes short = 16 bits! */ - { - pahsc->pahsc_NativeOutputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputBuffer); - if (pahsc->pahsc_NativeOutputBuffer == NULL) - { - ERR_RPT(("Fast memory allocation for output-buffer failed.\n")); - result = paInsufficientMemory; goto done; - } - } - /*------------------------------------------ Manipulate hardware if necessary and allowed: --*/ - ALseterrorhandler(0); /* 0 = turn off the default error handler. */ - pvbuf[0] = AL_INPUT_RATE; - pvbuf[2] = AL_INPUT_COUNT; - pvbuf[4] = AL_OUTPUT_RATE; /* TO FIX: rates may be logically, not always in Hz! */ - pvbuf[6] = AL_OUTPUT_COUNT; - sr = (long)(past->past_SampleRate + 0.5); /* Common for input and output :-) */ - if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */ - { /* sponding native AL-number(s). */ - padIN = Pa_GetInternalDevice(past->past_InputDeviceID); - if (!padIN) - { - ERR_RPT(("Pa_GetInternalDevice() for input failed.\n")); - result = paHostError; goto done; - } - if (ALgetparams(padIN->pad_ALdevice, &pvbuf[0], 4)) /* Although input and output will both be on */ - goto sgiError; /* the same AL-device, the AL-library might */ - if (pvbuf[1] != sr) /* contain more than AL_DEFAULT_DEVICE in */ - { /* Rate different from current harware-rate? the future. Therefore 2 seperate queries. */ - if (pvbuf[3] > 0) /* Means, there's other clients using AL-input-ports */ - { - ERR_RPT(("Sorry, not allowed to switch input-hardware to %ld Hz because \ -another process is currently using input at %ld kHz.\n", sr, pvbuf[1])); - result = paHostError; goto done; - } - pvbuf[1] = sr; /* Then set input-rate. */ - if (ALsetparams(padIN->pad_ALdevice, &pvbuf[0], 2)) - goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */ - } /* IS NOT CHECKED, AT LEAST NOT BY ME, WITHIN THIS FILE! Does PA do? */ - } - if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels <= 0! */ - { /* We use padOUT/IN later on, or at least 1 of both. */ - padOUT = Pa_GetInternalDevice(past->past_OutputDeviceID); - if (!padOUT) - { - ERR_RPT(("Pa_GetInternalDevice() for output failed.\n")); - result = paHostError; goto done; - } - if (ALgetparams(padOUT->pad_ALdevice,&pvbuf[4], 4)) - goto sgiError; - if ((past->past_NumOutputChannels > 0) && (pvbuf[5] != sr)) - { /* Output needed and rate different from current harware-rate. */ - if (pvbuf[7] > 0) /* Means, there's other clients using AL-output-ports */ - { - ERR_RPT(("Sorry, not allowed to switch output-hardware to %ld Hz because \ -another process is currently using output at %ld kHz.\n", sr, pvbuf[5])); - result = paHostError; goto done; /* Will free again the inputbuffer */ - } /* that was just created above. */ - pvbuf[5] = sr; /* Then set output-rate. */ - if (ALsetparams(padOUT->pad_ALdevice, &pvbuf[4], 2)) - goto sgiError; - } - } - /*------------------------------------------ Construct an audio-port-configuration ----------*/ - sgiALconfig = ALnewconfig(); /* Change the SGI-AL-default-settings. */ - if (sgiALconfig == (ALconfig)0) /* sgiALconfig is released here after use! */ - goto sgiError; /* See that sgiALconfig is NOT released! */ - if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */ - goto sgiError; - if (ALsetwidth (sgiALconfig, AL_SAMPLE_16)) /* Only meaningful when sample format for */ - goto sgiError; /* config is set to two's complement format. */ - /************************ Future versions might (dynamically) switch to 32-bit floats? ******* - if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.) - goto sgiError; - if (ALsetfloatmax (sgiALconfig, 1.0)) Only meaningful when sample format for config - goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */ - /*---------- ?? --------------------*/ - /* DBUG(("PaHost_OpenStream: pahsc_MinFramesPerHostBuffer = %d\n", pahsc->pahsc_MinFramesPerHostBuffer )); */ - minNumBuffers = Pa_GetMinNumBuffers(past->past_FramesPerUserBuffer, past->past_SampleRate); - past->past_NumUserBuffers = (minNumBuffers > past->past_NumUserBuffers) ? - minNumBuffers : past->past_NumUserBuffers; - /*------------------------------------------------ Set internal AL queuesize (in samples) ----*/ - if (pahsc->pahsc_SamplesPerInputBuffer >= pahsc->pahsc_SamplesPerOutputBuffer) - ALqsize = (long)pahsc->pahsc_SamplesPerInputBuffer; - else /* Take the largest of the two amounts. */ - ALqsize = (long)pahsc->pahsc_SamplesPerOutputBuffer; - ALqsize *= 4; /* 4 times as large as amount per transfer! */ - if (ALsetqueuesize(sgiALconfig, ALqsize)) /* Or should we use past_NumUserBuffers here? */ - goto sgiError; /* Using 2 times may give glitches... */ - /* Have to work on ALsetqueuesize() above. */ - - /* Do ALsetchannels() later, apart per input and/or output. */ - /*----------------------------------------------- OPEN 1 OR 2 AL-DEVICES: --------------------*/ - if (past->past_OutputDeviceID == past->past_InputDeviceID) /* Who SETS these devive-numbers? */ - { - if ((past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0)) - { - DBUG(("PaHost_OpenStream: opening both input and output channels.\n")); - /*------------------------- open output port: ----------------------------------*/ - if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels))) - goto sgiError; /* Returns 0 on success, -1 on failure. */ - pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig); - if (pahsc->pahsc_ALportOUT == (ALport)0) - goto sgiError; - /*------------------------- open input port: -----------------------------------*/ - if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels))) - goto sgiError; /* Returns 0 on success, -1 on failure. */ - pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig); - if (pahsc->pahsc_ALportIN == (ALport)0) - goto sgiError; /* For some reason the "patest_wire.c"-test crashes! */ - } /* Probably due to too small buffersizes?.... */ - else - { - ERR_RPT(("Cannot setup bidirectional stream between different devices.\n")); - result = paHostError; - goto done; - } - } - else /* (OutputDeviceID != InputDeviceID) */ - { - if (past->past_NumOutputChannels > 0) /* WRITE-ONLY: */ - { - /*------------------------- open output port: ----------------------------------*/ - DBUG(("PaHost_OpenStream: opening %d output channel(s) on %s.\n", - past->past_NumOutputChannels, padOUT->pad_DeviceName)); - if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels))) - goto sgiError; /* Returns 0 on success, -1 on failure. */ - pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig); - if (pahsc->pahsc_ALportOUT == (ALport)0) - goto sgiError; - } - if (past->past_NumInputChannels > 0) /* READ-ONLY: */ - { - /*------------------------- open input port: -----------------------------------*/ - DBUG(("PaHost_OpenStream: opening %d input channel(s) on %s.\n", - past->past_NumInputChannels, padIN->pad_DeviceName)); - if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels))) - goto sgiError; /* Returns 0 on success, -1 on failure. */ - pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig); - if (pahsc->pahsc_ALportIN == (ALport)0) - goto sgiError; - } - } - DBUG(("PaHost_OpenStream() succeeded.\n")); - goto done; /* (no errors occured) */ -sgiError: - result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ -done: - if (sgiALconfig) - ALfreeconfig(sgiALconfig); /* We don't need that struct anymore. */ - if (result != paNoError) - PaHost_CloseStream(past); /* Frees memory (only if really allocated!). */ - return result; -} - -/*-----------------------------------------------------*/ -PaError PaHost_StartOutput(internalPortAudioStream *past) -{ - return paNoError; /* Hmm, not implemented yet? */ -} -PaError PaHost_StartInput(internalPortAudioStream *past) -{ - return paNoError; -} - -/*------------------------------------------------------------------------------*/ -PaError PaHost_StartEngine(internalPortAudioStream *past) -{ - PaHostSoundControl *pahsc; - int hres; - PaError result = paNoError; - - if (!past) /* Test argument. */ - { - ERR_RPT(("PaHost_StartEngine(NULL)!\n")); - return paBadStreamPtr; - } - pahsc = (PaHostSoundControl*)past->past_DeviceData; - if (!pahsc) - { - ERR_RPT(("PaHost_StartEngine(arg): arg->past_DeviceData == NULL!\n")); - return paHostError; - } - past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */ - past->past_StopNow = 0; - past->past_IsActive = 1; - DBUG(("PaHost_StartEngine() called.\n")); - /* Use pthread_create() instead of __clone() because: */ - /* - pthread_create also works for other UNIX systems like Solaris, */ - /* - Java HotSpot VM crashes in pthread_setcanceltype() when using __clone(). */ - hres = pthread_create(&(pahsc->pahsc_ThreadPID), /* SPAWN AUDIO-CHILD. */ - NULL, /* pthread_attr_t * attr */ - (void*)Pa_SgiAudioProcess, - past); - if (hres) - { - result = paHostError; - sPaHostError = hres; - ERR_RPT(("PaHost_StartEngine() failed to spawn audio-thread.\n")); - } - return result; -} - -/*------------------------------------------------------------------------------*/ -PaError PaHost_StopEngine(internalPortAudioStream *past, int abort) -{ - int hres; - PaError result = paNoError; - PaHostSoundControl *pahsc; - - DBUG(("PaHost_StopEngine() called.\n")); - if (!past) - return paBadStreamPtr; - pahsc = (PaHostSoundControl*)past->past_DeviceData; - if (pahsc == NULL) - return result; /* paNoError (already stopped, no err?). */ - past->past_StopSoon = 1; /* Tell background thread to stop generating */ - if (abort) /* more and to let current data play out. If */ - past->past_StopNow = 1; /* aborting, tell backgrnd thread to stop NOW! */ - if (pahsc->pahsc_ThreadPID != -1) /* Join thread to recover memory resources. */ - { - DBUG(("pthread_join() called.\n")); - hres = pthread_join(pahsc->pahsc_ThreadPID, NULL); - if (hres) - { - result = paHostError; - sPaHostError = hres; - ERR_RPT(("PaHost_StopEngine() failed pthread_join().\n")); - } - pahsc->pahsc_ThreadPID = -1; - } - past->past_IsActive = 0; - return result; -} - -/*---------------------------------------------------------------*/ -PaError PaHost_StopOutput(internalPortAudioStream *past, int abort) -{ - return paNoError; /* Not implemented yet? */ -} -PaError PaHost_StopInput(internalPortAudioStream *past, int abort ) -{ - return paNoError; -} - -/*******************************************************************/ -PaError PaHost_CloseStream(internalPortAudioStream *past) -{ - PaHostSoundControl *pahsc; - PaError result = paNoError; - - DBUG(("PaHost_CloseStream() called.\n")); - if (past == NULL) - return paBadStreamPtr; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if (pahsc == NULL) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */ - return result; /* This test prevents from freeing NULL-pointers. */ - - if (pahsc->pahsc_ALportIN) - { - if (ALcloseport(pahsc->pahsc_ALportIN)) - result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */ - else /* But go on anyway... to release other stuff... */ - pahsc->pahsc_ALportIN = (ALport)0; - } - if (pahsc->pahsc_ALportOUT) - { - if (ALcloseport(pahsc->pahsc_ALportOUT)) - result = translateSGIerror(); - else - pahsc->pahsc_ALportOUT = (ALport)0; - } - if (pahsc->pahsc_NativeInputBuffer) - { - PaHost_FreeFastMemory(pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_BytesPerInputBuffer); - pahsc->pahsc_NativeInputBuffer = NULL; - } - if (pahsc->pahsc_NativeOutputBuffer) - { - PaHost_FreeFastMemory(pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer); - pahsc->pahsc_NativeOutputBuffer = NULL; - } - PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl)); - past->past_DeviceData = NULL; /* PaHost_OpenStream() allocated FAST. */ - return result; -} - -/************************************************************************* -** Determine minimum number of buffers required for this host based -** on minimum latency. Latency can be optionally set by user by setting -** an environment variable. For example, to set latency to 200 msec, put: -** set PA_MIN_LATENCY_MSEC=200 -** in the AUTOEXEC.BAT file and reboot. -** If the environment variable is not set, then the latency will be -** determined based on the OS. Windows NT has higher latency than Win95. -*/ -#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") - -int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate ) -{ - return 2; -} -/* Hmmm, the note above isn't appropriate for SGI I'm afraid... */ -/* Do we HAVE to do it this way under IRIX???.... */ -/*--------------------------------------------------------------*/ - - -/*---------------------------------------------------------------------*/ -PaError PaHost_Term(void) /* Frees all of the linked audio-devices. */ -{ /* Called by Pa_Terminate() from pa_lib.c. */ - internalPortAudioDevice *pad = sDeviceList, - *nxt; - while (pad) - { - DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName)); - nxt = pad->pad_Next; - PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); - pad = nxt; /* PaHost_Init allocated this FAST MEM.*/ - } - sDeviceList = (internalPortAudioDevice*)NULL; - return 0; /* Got rid of sNumDevices=0; */ -} - -/***********************************************************************/ -void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */ -{ -#if 0 - struct timeval timeout; - timeout.tv_sec = msec / 1000; - timeout.tv_usec = (msec % 1000) * 1000; - select(0, NULL, NULL, NULL, &timeout); -#else - long usecs = msec * 1000; - usleep( usecs ); -#endif -} - -/*---------------------------------------------------------------------------------------*/ -/* Allocate memory that can be accessed in real-time. This may need to be held in physi- */ -/* cal memory so that it is not paged to virtual memory. This call MUST be balanced with */ -/* a call to PaHost_FreeFastMemory(). */ -void *PaHost_AllocateFastMemory(long numBytes) -{ - void *addr = malloc(numBytes); - if (addr) - memset(addr, 0, numBytes); - return addr; -} - -/*---------------------------------------------------------------------------------------*/ -/* Free memory that could be accessed in real-time. This call MUST be balanced with a */ -/* call to PaHost_AllocateFastMemory(). */ -void PaHost_FreeFastMemory(void *addr, long numBytes) -{ - if (addr) - free(addr); -} - -/*----------------------------------------------------------*/ -PaError PaHost_StreamActive (internalPortAudioStream *past) -{ - PaHostSoundControl *pahsc; - if (past == NULL) - return paBadStreamPtr; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - if (pahsc == NULL) - return paInternalError; - return (PaError)(past->past_IsActive != 0); -} - -/*-------------------------------------------------------------------*/ -PaTimestamp Pa_StreamTime( PortAudioStream *stream ) -{ - internalPortAudioStream *past = (internalPortAudioStream *) stream; -/* FIXME - return actual frames played, not frames generated. -** Need to query the output device somehow. -*/ - return past->past_FrameCount; -} |