static PaError Pa_PauseAndFlush(int devHandle) { audio_info_t solaris_info; AUDIO_INITINFO(&solaris_info); solaris_info.play.pause = solaris_info.record.pause = 1; if (ioctl(devHandle, AUDIO_SETINFO, &solaris_info) == -1) { ERR_RPT(("Pa_FlushStream failed.\n")); return paHostError; } if (ioctl(devHandle, I_FLUSH, FLUSHRW) == -1) { ERR_RPT(("Pa_FlushStream failed.\n")); /* Unpause! */ AUDIO_INITINFO(&solaris_info); solaris_info.play.pause = solaris_info.record.pause = 0; ioctl(devHandle, AUDIO_SETINFO, &solaris_info); return paHostError; } return paNoError; }
PaError PaHost_CloseStream( internalPortAudioStream *past ) { PaHostSoundControl *pahsc; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError; if( pahsc->pahsc_OutputHandle != BAD_DEVICE_ID ) { int err = 0; DBUG(("PaHost_CloseStream: attempt to close output device handle = %d\n", pahsc->pahsc_OutputHandle )); Pa_FlushStream(pahsc->pahsc_OutputHandle); err = close(pahsc->pahsc_OutputHandle); if( err < 0 ) { ERR_RPT(("PaHost_CloseStream: warning, closing output device failed.\n")); } } if( (pahsc->pahsc_InputHandle != BAD_DEVICE_ID) && (pahsc->pahsc_InputHandle != pahsc->pahsc_OutputHandle) ) { int err = 0; DBUG(("PaHost_CloseStream: attempt to close input device handle = %d\n", pahsc->pahsc_InputHandle )); Pa_FlushStream(pahsc->pahsc_InputHandle); err = close(pahsc->pahsc_InputHandle); if( err < 0 ) { ERR_RPT(("PaHost_CloseStream: warning, closing input device failed.\n")); } } pahsc->pahsc_OutputHandle = BAD_DEVICE_ID; pahsc->pahsc_InputHandle = BAD_DEVICE_ID; if( pahsc->pahsc_NativeInputBuffer ) { free( pahsc->pahsc_NativeInputBuffer ); pahsc->pahsc_NativeInputBuffer = NULL; } if( pahsc->pahsc_NativeOutputBuffer ) { free( pahsc->pahsc_NativeOutputBuffer ); pahsc->pahsc_NativeOutputBuffer = NULL; } free( pahsc ); past->past_DeviceData = NULL; return paNoError; }
/* 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; }
PaError Pa_SetupOutputDeviceFormat( int devHandle, int numChannels, int sampleRate ) { audio_info_t solaris_info; AUDIO_INITINFO(&solaris_info); /* Sam Bayer/Bryan George 1/10/02: Various folks have reported that on Solaris Ultra II, the not-right thing happens on read unless you make sure the audio device is flushed. The folks who wrote the Robust Audio Tool say: + XXX driver issue - on Ultra II's if you don't drain * the device before reading commences then the device * reads in blocks of 500ms irrespective of the * blocksize set. After a minute or so it flips into the * correct mode, but obviously this is too late to be + * useful for most apps. grrr. */ /* AS: And the Solaris man audio pages say you should flush before changing formats anyway. So there you go. */ if (Pa_FlushStream(devHandle) != paNoError) return paHostError; solaris_info.play.encoding = AUDIO_ENCODING_LINEAR; solaris_info.play.sample_rate = sampleRate; solaris_info.play.precision = 16; solaris_info.play.channels = numChannels; if (ioctl(devHandle, AUDIO_SETINFO, &solaris_info) == -1) { ERR_RPT(("Pa_SetupDeviceFormat: could not set audio info\n" )); return paHostError; } return paNoError; }
static PaError Pa_PauseAndFlush(int devHandle) { audio_info_t solaris_info; AUDIO_INITINFO(&solaris_info); solaris_info.play.pause = solaris_info.record.pause = 1; if (ioctl(devHandle, AUDIO_SETINFO, &solaris_info) == -1) { ERR_RPT(("Pa_FlushStream failed.\n")); return paHostError; } #if defined I_FLUSH && defined FLUSHRW /* Flush the audiobuffer */ if (ioctl(devHandle, I_FLUSH, FLUSHRW) == -1) { ERR_RPT(("Pa_FlushStream failed.\n")); /* Unpause! */ AUDIO_INITINFO(&solaris_info); solaris_info.play.pause = solaris_info.record.pause = 0; ioctl(devHandle, AUDIO_SETINFO, &solaris_info); return paHostError; } #endif #if defined AUDIO_FLUSH if (ioctl(devHandle, AUDIO_FLUSH, NULL) == -1) { ERR_RPT(("Pa_FlushStream failed.\n")); /* Unpause! */ AUDIO_INITINFO(&solaris_info); solaris_info.play.pause = solaris_info.record.pause = 0; ioctl(devHandle, AUDIO_SETINFO, &solaris_info); return paHostError; } #endif return paNoError; }
/*----------------------------------------------------------------------*/ 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(). */ }
void Pa_SetLatency( int devHandle, int numBuffers, int framesPerBuffer, int channelsPerFrame ) { int bufferSize; audio_info_t solaris_info; /* Increase size of buffers and reduce number of buffers to reduce latency inside driver. */ while( numBuffers > 8 ) { numBuffers = (numBuffers + 1) >> 1; framesPerBuffer = framesPerBuffer << 1; } /* calculate size of buffers in bytes */ bufferSize = framesPerBuffer * channelsPerFrame * sizeof(short); /* FIXME - other sizes? */ DBUG(("Pa_SetLatency: numBuffers = %d, framesPerBuffer = %d\n", numBuffers, framesPerBuffer)); /* SAM 6/6/02: Documentation says to pause and flush before changing buffer size. */ if (Pa_PauseAndFlush(devHandle) != paNoError) { ERR_RPT(("Pa_SetLatency: could not pause audio\n" )); return; } AUDIO_INITINFO(&solaris_info); /* AS: Doesn't look like solaris has multiple buffers, so I'm being conservative and making one buffer. Might not be what we want... */ solaris_info.play.buffer_size = solaris_info.record.buffer_size = bufferSize; if (ioctl(devHandle, AUDIO_SETINFO, &solaris_info) == -1) { ERR_RPT(("Pa_SetLatency: could not set audio info\n" )); } Pa_Unpause(devHandle); }
/* 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 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; }
/********************************************************************* * Try to open the named device. * If it opens, try to set various rates and formats and fill in * the device info structure. */ PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *pad ) { int result = paHostError; int tempDevHandle; int numChannels, maxNumChannels; int format; int numSampleRates; int sampleRate; int numRatesToTry; int lastRate; int ratesToTry[9] = {96000, 48000, 44100, 32000, 24000, 22050, 16000, 11025, 8000}; int i; /* douglas: we have to do this querying in a slightly different order. apparently some sound cards will give you different info based on their settings. e.g. a card might give you stereo at 22kHz but only mono at 44kHz. the correct order for OSS is: format, channels, sample rate */ if ( (tempDevHandle = open(deviceName,O_WRONLY|O_NONBLOCK)) == -1 ) { DBUG(("Pa_QueryDevice: could not open %s\n", deviceName )); return paHostError; } /* Ask OSS what formats are supported by the hardware. */ pad->pad_Info.nativeSampleFormats = 0; if (ioctl(tempDevHandle, SNDCTL_DSP_GETFMTS, &format) == -1) { ERR_RPT(("Pa_QueryDevice: could not get format info\n" )); goto error; } if( format & AFMT_U8 ) pad->pad_Info.nativeSampleFormats |= paUInt8; if( format & AFMT_S16_NE ) pad->pad_Info.nativeSampleFormats |= paInt16; /* Negotiate for the maximum number of channels for this device. PLB20010927 * Consider up to 16 as the upper number of channels. * Variable numChannels should contain the actual upper limit after the call. * Thanks to John Lazzaro and Heiko Purnhagen for suggestions. */ maxNumChannels = 0; for( numChannels = 1; numChannels <= 16; numChannels++ ) { int temp = numChannels; DBUG(("Pa_QueryDevice: use SNDCTL_DSP_CHANNELS, numChannels = %d\n", numChannels )) if(ioctl(tempDevHandle, SNDCTL_DSP_CHANNELS, &temp) < 0 ) { /* ioctl() failed so bail out if we already have stereo */ if( numChannels > 2 ) break; } else { /* ioctl() worked but bail out if it does not support numChannels. * We don't want to leave gaps in the numChannels supported. */ if( (numChannels > 2) && (temp != numChannels) ) break; DBUG(("Pa_QueryDevice: temp = %d\n", temp )) if( temp > maxNumChannels ) maxNumChannels = temp; /* Save maximum. */ } } /* The above negotiation may fail for an old driver so try this older technique. */ if( maxNumChannels < 1 ) { int stereo = 1; if(ioctl(tempDevHandle, SNDCTL_DSP_STEREO, &stereo) < 0) { maxNumChannels = 1; } else { maxNumChannels = (stereo) ? 2 : 1; } DBUG(("Pa_QueryDevice: use SNDCTL_DSP_STEREO, maxNumChannels = %d\n", maxNumChannels )) }
PaError PaHost_OpenStream( internalPortAudioStream *past ) { PaError result = paNoError; PaHostSoundControl *pahsc; unsigned int minNumBuffers; internalPortAudioDevice *pad; DBUG(("PaHost_OpenStream() called.\n" )); /* Allocate and initialize host data. */ pahsc = (PaHostSoundControl *) malloc(sizeof(PaHostSoundControl)); if( pahsc == NULL ) { result = paInsufficientMemory; goto error; } memset( pahsc, 0, sizeof(PaHostSoundControl) ); past->past_DeviceData = (void *) pahsc; pahsc->pahsc_OutputHandle = BAD_DEVICE_ID; /* No device currently opened. */ pahsc->pahsc_InputHandle = BAD_DEVICE_ID; pahsc->pahsc_IsAudioThreadValid = 0; pahsc->pahsc_IsWatchDogThreadValid = 0; /* Allocate native buffers. */ pahsc->pahsc_BytesPerInputBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels * sizeof(short); if( past->past_NumInputChannels > 0) { pahsc->pahsc_NativeInputBuffer = (short *) malloc(pahsc->pahsc_BytesPerInputBuffer); if( pahsc->pahsc_NativeInputBuffer == NULL ) { result = paInsufficientMemory; goto error; } } pahsc->pahsc_BytesPerOutputBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels * sizeof(short); if( past->past_NumOutputChannels > 0) { pahsc->pahsc_NativeOutputBuffer = (short *) malloc(pahsc->pahsc_BytesPerOutputBuffer); if( pahsc->pahsc_NativeOutputBuffer == NULL ) { result = paInsufficientMemory; goto error; } } /* 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; pahsc->pahsc_InverseMicrosPerBuffer = past->past_SampleRate / (1000000.0 * past->past_FramesPerUserBuffer); DBUG(("past_SampleRate = %g\n", past->past_SampleRate )); DBUG(("past_FramesPerUserBuffer = %d\n", past->past_FramesPerUserBuffer )); DBUG(("pahsc_InverseMicrosPerBuffer = %g\n", pahsc->pahsc_InverseMicrosPerBuffer )); /* ------------------------- OPEN DEVICE -----------------------*/ /* just output */ if (past->past_OutputDeviceID == past->past_InputDeviceID) { if ((past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0) ) { pad = Pa_GetInternalDevice( past->past_OutputDeviceID ); DBUG(("PaHost_OpenStream: attempt to open %s for O_RDWR\n", pad->pad_DeviceName )); /* dmazzoni: test it first in nonblocking mode to make sure the device is not busy */ pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDWR|O_NONBLOCK); if(pahsc->pahsc_InputHandle==-1) { ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDWR\n", pad->pad_DeviceName )); result = paHostError; goto error; } close(pahsc->pahsc_InputHandle); pahsc->pahsc_OutputHandle = pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDWR); if(pahsc->pahsc_InputHandle==-1) { ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDWR\n", pad->pad_DeviceName )); result = paHostError; goto error; } Pa_SetLatency( pahsc->pahsc_OutputHandle, past->past_NumUserBuffers, past->past_FramesPerUserBuffer, past->past_NumOutputChannels ); result = Pa_SetupDeviceFormat( pahsc->pahsc_OutputHandle, past->past_NumOutputChannels, (int)past->past_SampleRate ); } } else { if (past->past_NumOutputChannels > 0) { pad = Pa_GetInternalDevice( past->past_OutputDeviceID ); DBUG(("PaHost_OpenStream: attempt to open %s for O_WRONLY\n", pad->pad_DeviceName )); /* dmazzoni: test it first in nonblocking mode to make sure the device is not busy */ pahsc->pahsc_OutputHandle = open(pad->pad_DeviceName,O_WRONLY|O_NONBLOCK); if(pahsc->pahsc_OutputHandle==-1) { ERR_RPT(("PaHost_OpenStream: could not open %s for O_WRONLY\n", pad->pad_DeviceName )); result = paHostError; goto error; } close(pahsc->pahsc_OutputHandle); pahsc->pahsc_OutputHandle = open(pad->pad_DeviceName,O_WRONLY); if(pahsc->pahsc_OutputHandle==-1) { ERR_RPT(("PaHost_OpenStream: could not open %s for O_WRONLY\n", pad->pad_DeviceName )); result = paHostError; goto error; } Pa_SetLatency( pahsc->pahsc_OutputHandle, past->past_NumUserBuffers, past->past_FramesPerUserBuffer, past->past_NumOutputChannels ); result = Pa_SetupOutputDeviceFormat( pahsc->pahsc_OutputHandle, past->past_NumOutputChannels, (int)past->past_SampleRate ); } if (past->past_NumInputChannels > 0) { pad = Pa_GetInternalDevice( past->past_InputDeviceID ); DBUG(("PaHost_OpenStream: attempt to open %s for O_RDONLY\n", pad->pad_DeviceName )); /* dmazzoni: test it first in nonblocking mode to make sure the device is not busy */ pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDONLY|O_NONBLOCK); if(pahsc->pahsc_InputHandle==-1) { ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDONLY\n", pad->pad_DeviceName )); result = paHostError; goto error; } close(pahsc->pahsc_InputHandle); pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDONLY); if(pahsc->pahsc_InputHandle==-1) { ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDONLY\n", pad->pad_DeviceName )); result = paHostError; goto error; } Pa_SetLatency( pahsc->pahsc_InputHandle, /* DH20010115 - was OutputHandle! */ past->past_NumUserBuffers, past->past_FramesPerUserBuffer, past->past_NumInputChannels ); result = Pa_SetupInputDeviceFormat( pahsc->pahsc_InputHandle, past->past_NumInputChannels, (int)past->past_SampleRate ); } } DBUG(("PaHost_OpenStream: SUCCESS - result = %d\n", result )); return result; error: ERR_RPT(("PaHost_OpenStream: ERROR - result = %d\n", result )); PaHost_CloseStream( past ); return result; }
static PaError Pa_AudioThreadProc( internalPortAudioStream *past ) { PaError result; PaHostSoundControl *pahsc; ssize_t bytes_read, bytes_written; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paInternalError; #ifdef GNUSTEP GSRegisterCurrentThread(); /* SB20010904 */ #endif result = PaHost_BoostPriority( past ); if( result < 0 ) goto error; past->past_IsActive = 1; DBUG(("entering thread.\n")); while( (past->past_StopNow == 0) && (past->past_StopSoon == 0) ) { /* Read data from device */ if(pahsc->pahsc_NativeInputBuffer) { unsigned int totalread = 0; DBUG(("Pa_AudioThreadProc: attempt to read %d bytes\n", pahsc->pahsc_BytesPerInputBuffer)); do { bytes_read = read(pahsc->pahsc_InputHandle, (char *)pahsc->pahsc_NativeInputBuffer + totalread, pahsc->pahsc_BytesPerInputBuffer - totalread); if (bytes_read < 0) { ERR_RPT(("PortAudio: read interrupted!\n")); break; } totalread += bytes_read; } while( totalread < pahsc->pahsc_BytesPerInputBuffer); } /* Convert 16 bit native data to user data and call user routine. */ DBUG(("converting...\n")); Pa_StartUsageCalculation( past ); result = Pa_CallConvertInt16( past, pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_NativeOutputBuffer ); Pa_EndUsageCalculation( past ); if( result != 0) { DBUG(("hmm, Pa_CallConvertInt16() says: %d. i'm bailing.\n", result)); break; } /* Write data to device. */ if( pahsc->pahsc_NativeOutputBuffer ) { unsigned int totalwritten = 0; do { bytes_written = write(pahsc->pahsc_OutputHandle, (void *)pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer); if( bytes_written < 0 ) { ERR_RPT(("PortAudio: write interrupted!")); break; } totalwritten += bytes_written; } while( totalwritten < pahsc->pahsc_BytesPerOutputBuffer); } Pa_UpdateStreamTime(pahsc); } DBUG(("Pa_AudioThreadProc: left audio loop.\n")); past->past_IsActive = 0; PaHost_StopWatchDog( pahsc ); error: DBUG(("leaving audio thread.\n")); #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ #endif return result; }
static PaError PaHost_WatchDogProc( PaHostSoundControl *pahsc ) { struct sched_param schp = { 0 }; int maxPri; #ifdef GNUSTEP GSRegisterCurrentThread(); /* SB20010904 */ #endif /* Run at a priority level above audio thread so we can still run if it hangs. */ /* Rise more than 1 because of rumored off-by-one scheduler bugs. */ schp.sched_priority = pahsc->pahsc_AudioPriority + 4; maxPri = sched_get_priority_max(SCHEDULER_POLICY); if( schp.sched_priority > maxPri ) schp.sched_priority = maxPri; if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0) { ERR_RPT(("PaHost_WatchDogProc: cannot set watch dog priority!\n")); goto killAudio; } /* Compare watchdog time with audio and canary thread times. */ /* Sleep for a while or until thread cancelled. */ while( pahsc->pahsc_WatchDogRun ) { int delta; struct timeval currentTime; usleep( WATCHDOG_INTERVAL_USEC ); gettimeofday( ¤tTime, NULL ); /* If audio thread is not advancing, then it must be hung so kill it. */ delta = currentTime.tv_sec - pahsc->pahsc_EntryTime.tv_sec; DBUG(("PaHost_WatchDogProc: audio delta = %d\n", delta )); if( delta > WATCHDOG_MAX_SECONDS ) { goto killAudio; } /* If canary died, then lower audio priority and halt canary. */ delta = currentTime.tv_sec - pahsc->pahsc_CanaryTime.tv_sec; if( delta > WATCHDOG_MAX_SECONDS ) { ERR_RPT(("PaHost_WatchDogProc: canary died!\n")); goto lowerAudio; } } DBUG(("PaHost_WatchDogProc: exiting.\n")); #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ #endif return 0; lowerAudio: { struct sched_param schat = { 0 }; if( sched_setscheduler(pahsc->pahsc_AudioThreadPID, SCHED_OTHER, &schat) != 0) { ERR_RPT(("PaHost_WatchDogProc: failed to lower audio priority. errno = %d\n", errno )); /* Fall through into killing audio thread. */ } else { ERR_RPT(("PaHost_WatchDogProc: lowered audio priority to prevent hogging of CPU.\n")); goto cleanup; } } killAudio: ERR_RPT(("PaHost_WatchDogProc: killing hung audio thread!\n")); pthread_kill( pahsc->pahsc_AudioThread, SIGKILL ); cleanup: pahsc->pahsc_CanaryRun = 0; DBUG(("PaHost_WatchDogProc: cancel Canary\n")); pthread_cancel( pahsc->pahsc_CanaryThread ); DBUG(("PaHost_WatchDogProc: join Canary\n")); pthread_join( pahsc->pahsc_CanaryThread, NULL ); DBUG(("PaHost_WatchDogProc: forget Canary\n")); pahsc->pahsc_IsCanaryThreadValid = 0; #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ #endif return 0; }
static int WatchDogProc( prioboost *b ) { struct sched_param schp = { 0 }; int maxPri; /* Run at a priority level above main thread so we can still run if it hangs. */ /* Rise more than 1 because of rumored off-by-one scheduler bugs. */ schp.sched_priority = b->priority + 4; maxPri = sched_get_priority_max(SCHEDULER_POLICY); if( schp.sched_priority > maxPri ) schp.sched_priority = maxPri; if (pthread_setschedparam(pthread_self(), SCHEDULER_POLICY, &schp) != 0) { ERR_RPT("WatchDogProc: cannot set watch dog priority!\n"); goto killAudio; } DBUG("prioboost: WatchDog priority set to level %d!\n", schp.sched_priority); /* Compare watchdog time with audio and canary thread times. */ /* Sleep for a while or until thread cancelled. */ while( b->WatchDogRun ) { int delta; struct timeval currentTime; usleep( WATCHDOG_INTERVAL_USEC ); gettimeofday( ¤tTime, NULL ); #if 0 /* If audio thread is not advancing, then it must be hung so kill it. */ delta = currentTime.tv_sec - b->EntryTime.tv_sec; DBUG(("WatchDogProc: audio delta = %d\n", delta )); if( delta > WATCHDOG_MAX_SECONDS ) { goto killAudio; } #endif /* If canary died, then lower audio priority and halt canary. */ delta = currentTime.tv_sec - b->CanaryTime.tv_sec; DBUG("WatchDogProc: dogging, delta = %ld, mysec=%d\n", delta, currentTime.tv_sec); if( delta > WATCHDOG_MAX_SECONDS ) { ERR_RPT("WatchDogProc: canary died!\n"); goto lowerAudio; } } DBUG("WatchDogProc: exiting.\n"); return 0; lowerAudio: { struct sched_param schat = { 0 }; if( pthread_setschedparam(b->ThreadID, SCHED_OTHER, &schat) != 0) { ERR_RPT("WatchDogProc: failed to lower audio priority. errno = %d\n", errno ); /* Fall through into killing audio thread. */ } else { ERR_RPT("WatchDogProc: lowered audio priority to prevent hogging of CPU.\n"); goto cleanup; } } killAudio: ERR_RPT("WatchDogProc: killing hung audio thread!\n"); //pthread_cancel( b->ThreadID); //pthread_join( b->ThreadID); exit(1); cleanup: b->CanaryRun = 0; DBUG("WatchDogProc: cancel Canary\n"); pthread_cancel( b->CanaryThread ); DBUG("WatchDogProc: join Canary\n"); pthread_join( b->CanaryThread, NULL ); DBUG("WatchDogProc: forget Canary\n"); b->IsCanaryThreadValid = 0; #ifdef GNUSTEP GSUnregisterCurrentThread(); /* SB20010904 */ #endif return 0; }
PaError PaHost_OpenStream( internalPortAudioStream *past ) { HRESULT hr; PaError result = paNoError; PaHostSoundControl *pahsc; int numBytes, maxChannels; unsigned int minNumBuffers; internalPortAudioDevice *pad; DSoundWrapper *dsw; /* Allocate and initialize host data. */ pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); /* MEM */ if( pahsc == NULL ) { result = paInsufficientMemory; goto error; } memset( pahsc, 0, sizeof(PaHostSoundControl) ); past->past_DeviceData = (void *) pahsc; pahsc->pahsc_TimerID = 0; dsw = &pahsc->pahsc_DSoundWrapper; DSW_Init( dsw ); /* Allocate native buffer. */ maxChannels = ( past->past_NumOutputChannels > past->past_NumInputChannels ) ? past->past_NumOutputChannels : past->past_NumInputChannels; pahsc->pahsc_BytesPerBuffer = past->past_FramesPerUserBuffer * maxChannels * sizeof(short); if( maxChannels > 0 ) { pahsc->pahsc_NativeBuffer = (short *) PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerBuffer); /* MEM */ if( pahsc->pahsc_NativeBuffer == NULL ) { result = paInsufficientMemory; goto error; } } else { result = paInvalidChannelCount; goto error; } 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; numBytes = pahsc->pahsc_BytesPerBuffer * past->past_NumUserBuffers; if( numBytes < DSBSIZE_MIN ) { result = paBufferTooSmall; goto error; } if( numBytes > DSBSIZE_MAX ) { result = paBufferTooBig; goto error; } pahsc->pahsc_FramesPerDSBuffer = past->past_FramesPerUserBuffer * past->past_NumUserBuffers; { int msecLatency = (int) ((pahsc->pahsc_FramesPerDSBuffer * 1000) / past->past_SampleRate); PRINT(("PortAudio on DirectSound - Latency = %d frames, %d msec\n", pahsc->pahsc_FramesPerDSBuffer, msecLatency )); } /* ------------------ OUTPUT */ if( (past->past_OutputDeviceID >= 0) && (past->past_NumOutputChannels > 0) ) { DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID)); pad = Pa_GetInternalDevice( past->past_OutputDeviceID ); hr = DirectSoundCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSound, NULL ); /* If this fails, then try each output device until we find one that works. */ if( hr != DS_OK ) { int i; ERR_RPT(("Creation of requested Audio Output device '%s' failed.\n", ((pad->pad_lpGUID == NULL) ? "Default" : pad->pad_Info.name) )); for( i=0; i<Pa_CountDevices(); i++ ) { pad = Pa_GetInternalDevice( i ); if( pad->pad_Info.maxOutputChannels >= past->past_NumOutputChannels ) { DBUG(("Try device '%s' instead.\n", pad->pad_Info.name )); hr = DirectSoundCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSound, NULL ); if( hr == DS_OK ) { ERR_RPT(("Using device '%s' instead.\n", pad->pad_Info.name )); break; } } } } if( hr != DS_OK ) { ERR_RPT(("PortAudio: DirectSoundCreate() failed!\n")); result = paHostError; sPaHostError = hr; goto error; } hr = DSW_InitOutputBuffer( dsw, (unsigned long) (past->past_SampleRate + 0.5), past->past_NumOutputChannels, numBytes ); DBUG(("DSW_InitOutputBuffer() returns %x\n", hr)); if( hr != DS_OK ) { result = paHostError; sPaHostError = hr; goto error; } past->past_FrameCount = pahsc->pahsc_DSoundWrapper.dsw_FramesWritten; } #if SUPPORT_AUDIO_CAPTURE /* ------------------ INPUT */ if( (past->past_InputDeviceID >= 0) && (past->past_NumInputChannels > 0) ) { pad = Pa_GetInternalDevice( past->past_InputDeviceID ); hr = DirectSoundCaptureCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSoundCapture, NULL ); /* If this fails, then try each input device until we find one that works. */ if( hr != DS_OK ) { int i; ERR_RPT(("Creation of requested Audio Capture device '%s' failed.\n", ((pad->pad_lpGUID == NULL) ? "Default" : pad->pad_Info.name) )); for( i=0; i<Pa_CountDevices(); i++ ) { pad = Pa_GetInternalDevice( i ); if( pad->pad_Info.maxInputChannels >= past->past_NumInputChannels ) { PRINT(("Try device '%s' instead.\n", pad->pad_Info.name )); hr = DirectSoundCaptureCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSoundCapture, NULL ); if( hr == DS_OK ) break; } } } if( hr != DS_OK ) { ERR_RPT(("PortAudio: DirectSoundCaptureCreate() failed!\n")); result = paHostError; sPaHostError = hr; goto error; } hr = DSW_InitInputBuffer( dsw, (unsigned long) (past->past_SampleRate + 0.5), past->past_NumInputChannels, numBytes ); DBUG(("DSW_InitInputBuffer() returns %x\n", hr)); if( hr != DS_OK ) { ERR_RPT(("PortAudio: DSW_InitInputBuffer() returns %x\n", hr)); result = paHostError; sPaHostError = hr; goto error; } } #endif /* SUPPORT_AUDIO_CAPTURE */ /* Calculate scalar used in CPULoad calculation. */ { LARGE_INTEGER frequency; if( QueryPerformanceFrequency( &frequency ) == 0 ) { pahsc->pahsc_InverseTicksPerUserBuffer = 0.0; } else { pahsc->pahsc_InverseTicksPerUserBuffer = past->past_SampleRate / ( (double)frequency.QuadPart * past->past_FramesPerUserBuffer ); DBUG(("pahsc_InverseTicksPerUserBuffer = %g\n", pahsc->pahsc_InverseTicksPerUserBuffer )); } } return result; error: PaHost_CloseStream( past ); return result; }
static PaError Pa_TimeSlice( internalPortAudioStream *past ) { PaError result = 0; long bytesEmpty = 0; long bytesFilled = 0; long bytesToXfer = 0; long numChunks; HRESULT hresult; PaHostSoundControl *pahsc; short *nativeBufPtr; past->past_NumCallbacks += 1; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paInternalError; /* How much input data is available? */ #if SUPPORT_AUDIO_CAPTURE if( past->past_NumInputChannels > 0 ) { DSW_QueryInputFilled( &pahsc->pahsc_DSoundWrapper, &bytesFilled ); bytesToXfer = bytesFilled; } #endif /* SUPPORT_AUDIO_CAPTURE */ /* How much output room is available? */ if( past->past_NumOutputChannels > 0 ) { DSW_QueryOutputSpace( &pahsc->pahsc_DSoundWrapper, &bytesEmpty ); bytesToXfer = bytesEmpty; } AddTraceMessage( "bytesEmpty ", bytesEmpty ); /* Choose smallest value if both are active. */ if( (past->past_NumInputChannels > 0) && (past->past_NumOutputChannels > 0) ) { bytesToXfer = ( bytesFilled < bytesEmpty ) ? bytesFilled : bytesEmpty; } /* printf("bytesFilled = %d, bytesEmpty = %d, bytesToXfer = %d\n", bytesFilled, bytesEmpty, bytesToXfer); */ /* Quantize to multiples of a buffer. */ numChunks = bytesToXfer / pahsc->pahsc_BytesPerBuffer; if( numChunks > (long)(past->past_NumUserBuffers/2) ) { numChunks = (long)past->past_NumUserBuffers/2; } else if( numChunks < 0 ) { numChunks = 0; } AddTraceMessage( "numChunks ", numChunks ); nativeBufPtr = pahsc->pahsc_NativeBuffer; if( numChunks > 0 ) { while( numChunks-- > 0 ) { /* Measure usage based on time to process one user buffer. */ Pa_StartUsageCalculation( past ); #if SUPPORT_AUDIO_CAPTURE /* Get native data from DirectSound. */ if( past->past_NumInputChannels > 0 ) { hresult = DSW_ReadBlock( &pahsc->pahsc_DSoundWrapper, (char *) nativeBufPtr, pahsc->pahsc_BytesPerBuffer ); if( hresult < 0 ) { ERR_RPT(("DirectSound ReadBlock failed, hresult = 0x%x\n",hresult)); sPaHostError = hresult; break; } } #endif /* SUPPORT_AUDIO_CAPTURE */ /* Convert 16 bit native data to user data and call user routine. */ result = Pa_CallConvertInt16( past, nativeBufPtr, nativeBufPtr ); if( result != 0) break; /* Pass native data to DirectSound. */ if( past->past_NumOutputChannels > 0 ) { /* static short DEBUGHACK = 0; DEBUGHACK += 0x0049; nativeBufPtr[0] = DEBUGHACK; /* Make buzz to see if DirectSound still running. */ hresult = DSW_WriteBlock( &pahsc->pahsc_DSoundWrapper, (char *) nativeBufPtr, pahsc->pahsc_BytesPerBuffer ); if( hresult < 0 ) { ERR_RPT(("DirectSound WriteBlock failed, result = 0x%x\n",hresult)); sPaHostError = hresult; break; } } Pa_EndUsageCalculation( past ); } } return result; }
/********************************************************************* * Try to open the named device. * If it opens, try to set various rates and formats and fill in * the device info structure. */ PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *pad ) { int result = paHostError; int tempDevHandle; int numChannels, maxNumChannels; int numSampleRates; int sampleRate; int numRatesToTry; int ratesToTry[9] = {96000, 48000, 44100, 32000, 24000, 22050, 16000, 11025, 8000}; int i; audio_info_t solaris_info; audio_device_t device_info; /* douglas: we have to do this querying in a slightly different order. apparently some sound cards will give you different info based on their settins. e.g. a card might give you stereo at 22kHz but only mono at 44kHz. the correct order for OSS is: format, channels, sample rate */ /* to check a device for it's capabilities, it's probably better to use the equivalent "-ctl"-descriptor - MR */ char devname[strlen(deviceName) + 4]; snprintf(devname,(strlen(deviceName) + 4),"%sctl",deviceName); if ((tempDevHandle = open(devname, O_WRONLY|O_NONBLOCK)) == -1 ) { DBUG(("Pa_QueryDevice: could not open %s\n", deviceName )); return paHostError; } /* Ask OSS what formats are supported by the hardware. */ pad->pad_Info.nativeSampleFormats = 0; AUDIO_INITINFO(&solaris_info); /* SAM 12/31/01: Sparc native does mulaw, alaw and PCM. I think PCM is signed. */ for (i = 8; i <= 32; i += 8) { solaris_info.play.precision = i; solaris_info.play.encoding = AUDIO_ENCODING_LINEAR; /* If there are no errors, add the format. */ if (ioctl(tempDevHandle, AUDIO_SETINFO, &solaris_info) > -1) { switch (i) { case 8: pad->pad_Info.nativeSampleFormats |= paInt8; break; case 16: pad->pad_Info.nativeSampleFormats |= paInt16; break; case 24: pad->pad_Info.nativeSampleFormats |= paInt24; break; case 32: pad->pad_Info.nativeSampleFormats |= paInt32; break; } } } maxNumChannels = 0; for( numChannels = 1; numChannels <= 16; numChannels++ ) { int temp = numChannels; DBUG(("Pa_QueryDevice: use SNDCTL_DSP_CHANNELS, numChannels = %d\n", numChannels )) AUDIO_INITINFO(&solaris_info); solaris_info.play.channels = temp; if (ioctl(tempDevHandle, AUDIO_SETINFO, &solaris_info) < 0) { /* ioctl() failed so bail out if we already have stereo */ if( numChannels > 2 ) break; } else { /* ioctl() worked but bail out if it does not support numChannels. * We don't want to leave gaps in the numChannels supported. */ if( (numChannels > 2) && (temp != numChannels) ) break; DBUG(("Pa_QueryDevice: temp = %d\n", temp )) if( temp > maxNumChannels ) maxNumChannels = temp; /* Save maximum. */ } } pad->pad_Info.maxOutputChannels = maxNumChannels; DBUG(("Pa_QueryDevice: maxNumChannels = %d\n", maxNumChannels)) /* FIXME - for now, assume maxInputChannels = maxOutputChannels. * Eventually do separate queries for O_WRONLY and O_RDONLY */ pad->pad_Info.maxInputChannels = pad->pad_Info.maxOutputChannels; DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels)) /* Determine available sample rates by trying each one and seeing result. */ numSampleRates = 0; AUDIO_INITINFO(&solaris_info); numRatesToTry = sizeof(ratesToTry)/sizeof(int); for (i = 0; i < numRatesToTry; i++) { sampleRate = ratesToTry[i]; solaris_info.play.sample_rate = sampleRate; /* AS: We opened for Write, so set play */ if (ioctl(tempDevHandle, AUDIO_SETINFO, &solaris_info) >= 0 ) /* PLB20010817 */ { if (sampleRate == ratesToTry[i]) { DBUG(("Pa_QueryDevice: got sample rate: %d\n", sampleRate)) pad->pad_SampleRates[numSampleRates] = (float)ratesToTry[i]; numSampleRates++; } } } DBUG(("Pa_QueryDevice: final numSampleRates = %d\n", numSampleRates)) if (numSampleRates==0) /* HP20010922 */ { ERR_RPT(("Pa_QueryDevice: no supported sample rate (or SNDCTL_DSP_SPEED ioctl call failed).\n" )); goto error; } pad->pad_Info.numSampleRates = numSampleRates; pad->pad_Info.sampleRates = pad->pad_SampleRates; /* query for the device name instead of using the filesystem-device - MR */ if (ioctl(tempDevHandle, AUDIO_GETDEV, &device_info) == -1) { pad->pad_Info.name = deviceName; } else { char *pt = (char *)PaHost_AllocateFastMemory(strlen(device_info.name)); strcpy(pt, device_info.name); pad->pad_Info.name = pt; } result = paNoError; error: /* We MUST close the handle here or we won't be able to reopen it later!!! */ close(tempDevHandle); return result; }
/*--------------------------------------------------------------------------------------*/ 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. */ } }
/*--------------------------------------------------------------------------------------*/ 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? */
/*---------------------------------------------------------------------------------------------------*/ 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; }