From 2e416ee0095f1bf608f849f156d564e0f45fb8ab Mon Sep 17 00:00:00 2001 From: Guenter Geiger Date: Mon, 2 Feb 2004 12:18:59 +0000 Subject: merged in version_0_37_1test6 svn path=/trunk/; revision=1305 --- pd/portaudio/pa_unix_oss/pa_unix_oss.c | 1187 -------------------------------- 1 file changed, 1187 deletions(-) delete mode 100644 pd/portaudio/pa_unix_oss/pa_unix_oss.c (limited to 'pd/portaudio/pa_unix_oss/pa_unix_oss.c') diff --git a/pd/portaudio/pa_unix_oss/pa_unix_oss.c b/pd/portaudio/pa_unix_oss/pa_unix_oss.c deleted file mode 100644 index 2e51b245..00000000 --- a/pd/portaudio/pa_unix_oss/pa_unix_oss.c +++ /dev/null @@ -1,1187 +0,0 @@ -/* - * $Id - * PortAudio Portable Real-Time Audio Library - * Latest Version at: http://www.portaudio.com - * OSS implementation by: - * Douglas Repetto - * Phil Burk - * Dominic Mazzoni - * - * Based on the Open Source API proposed by Ross Bencina - * Copyright (c) 1999-2002 Ross Bencina, 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. - */ - -#include -#include -#include -#include -#include -#include -#include - -#ifdef __linux__ -# include -# define DEVICE_NAME_BASE "/dev/dsp" -#else -# include /* JH20010905 */ -# define DEVICE_NAME_BASE "/dev/audio" -#endif - -#include "portaudio.h" -#include "pa_util.h" -#include "pa_allocation.h" -#include "pa_hostapi.h" -#include "pa_stream.h" -#include "pa_cpuload.h" -#include "pa_process.h" - -/* TODO: add error text handling -#define PA_UNIX_OSS_ERROR( errorCode, errorText ) \ - PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText ) -*/ - -#define PRINT(x) { printf x; fflush(stdout); } -#define DBUG(x) /* PRINT(x) */ - -/* PaOSSHostApiRepresentation - host api datastructure specific to this implementation */ - -typedef struct -{ - PaUtilHostApiRepresentation inheritedHostApiRep; - PaUtilStreamInterface callbackStreamInterface; - PaUtilStreamInterface blockingStreamInterface; - - PaUtilAllocationGroup *allocations; - - PaHostApiIndex hostApiIndex; -} -PaOSSHostApiRepresentation; - -typedef struct PaOSS_DeviceList { - PaDeviceInfo *deviceInfo; - struct PaOSS_DeviceList *next; -} -PaOSS_DeviceList; - -/* prototypes for functions declared in this file */ - -PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ); -static void Terminate( struct PaUtilHostApiRepresentation *hostApi ); -static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate ); -static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, - PaStream** s, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate, - unsigned long framesPerBuffer, - PaStreamFlags streamFlags, - PaStreamCallback *streamCallback, - void *userData ); -static PaError CloseStream( PaStream* stream ); -static PaError StartStream( PaStream *stream ); -static PaError StopStream( PaStream *stream ); -static PaError AbortStream( PaStream *stream ); -static PaError IsStreamStopped( PaStream *s ); -static PaError IsStreamActive( PaStream *stream ); -static PaTime GetStreamTime( PaStream *stream ); -static double GetStreamCpuLoad( PaStream* stream ); -static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames ); -static PaError WriteStream( PaStream* stream, void *buffer, unsigned long frames ); -static signed long GetStreamReadAvailable( PaStream* stream ); -static signed long GetStreamWriteAvailable( PaStream* stream ); -static PaError BuildDeviceList( PaOSSHostApiRepresentation *hostApi ); - - -PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ) -{ - PaError result = paNoError; - PaOSSHostApiRepresentation *ossHostApi; - - DBUG(("PaOSS_Initialize\n")); - - ossHostApi = (PaOSSHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaOSSHostApiRepresentation) ); - if( !ossHostApi ) - { - result = paInsufficientMemory; - goto error; - } - - ossHostApi->allocations = PaUtil_CreateAllocationGroup(); - if( !ossHostApi->allocations ) - { - result = paInsufficientMemory; - goto error; - } - - *hostApi = &ossHostApi->inheritedHostApiRep; - (*hostApi)->info.structVersion = 1; - (*hostApi)->info.type = paOSS; - (*hostApi)->info.name = "OSS"; - ossHostApi->hostApiIndex = hostApiIndex; - - BuildDeviceList( ossHostApi ); - - (*hostApi)->Terminate = Terminate; - (*hostApi)->OpenStream = OpenStream; - (*hostApi)->IsFormatSupported = IsFormatSupported; - - PaUtil_InitializeStreamInterface( &ossHostApi->callbackStreamInterface, CloseStream, StartStream, - StopStream, AbortStream, IsStreamStopped, IsStreamActive, - GetStreamTime, GetStreamCpuLoad, - PaUtil_DummyReadWrite, PaUtil_DummyReadWrite, - PaUtil_DummyGetAvailable, PaUtil_DummyGetAvailable ); - - PaUtil_InitializeStreamInterface( &ossHostApi->blockingStreamInterface, CloseStream, StartStream, - StopStream, AbortStream, IsStreamStopped, IsStreamActive, - GetStreamTime, PaUtil_DummyGetCpuLoad, - ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable ); - - return result; - -error: - if( ossHostApi ) - { - if( ossHostApi->allocations ) - { - PaUtil_FreeAllAllocations( ossHostApi->allocations ); - PaUtil_DestroyAllocationGroup( ossHostApi->allocations ); - } - - PaUtil_FreeMemory( ossHostApi ); - } - return result; -} - -#ifndef AFMT_S16_NE -#define AFMT_S16_NE Get_AFMT_S16_NE() -/********************************************************************* - * Some versions of OSS do not define AFMT_S16_NE. So check CPU. - * PowerPC is Big Endian. X86 is Little Endian. - */ -static int Get_AFMT_S16_NE( void ) -{ - long testData = 1; - char *ptr = (char *) &testData; - int isLittle = ( *ptr == 1 ); /* Does address point to least significant byte? */ - return isLittle ? AFMT_S16_LE : AFMT_S16_BE; -} -#endif - -PaError PaOSS_SetFormat(const char *callingFunctionName, int deviceHandle, - char *deviceName, int inputChannelCount, int outputChannelCount, - double *sampleRate) -{ - int format; - int rate; - int temp; - - /* Attempt to set format to 16-bit */ - - format = AFMT_S16_NE; - if (ioctl(deviceHandle, SNDCTL_DSP_SETFMT, &format) == -1) { - DBUG(("%s: could not set format: %s\n", callingFunctionName, deviceName )); - return paSampleFormatNotSupported; - } - if (format != AFMT_S16_NE) { - DBUG(("%s: device does not support AFMT_S16_NE: %s\n", callingFunctionName, deviceName )); - return paSampleFormatNotSupported; - } - - /* try to set the number of channels */ - - if (inputChannelCount > 0) { - temp = inputChannelCount; - - if( ioctl(deviceHandle, SNDCTL_DSP_CHANNELS, &temp) < 0 ) { - DBUG(("%s: Couldn't set device %s to %d channels\n", callingFunctionName, deviceName, inputChannelCount )); - return paSampleFormatNotSupported; - } - } - - if (outputChannelCount > 0) { - temp = outputChannelCount; - - if( ioctl(deviceHandle, SNDCTL_DSP_CHANNELS, &temp) < 0 ) { - DBUG(("%s: Couldn't set device %s to %d channels\n", callingFunctionName, deviceName, outputChannelCount )); - return paSampleFormatNotSupported; - } - } - - /* try to set the sample rate */ - - rate = (int)(*sampleRate); - if (ioctl(deviceHandle, SNDCTL_DSP_SPEED, &rate) == -1) - { - DBUG(("%s: Device %s, couldn't set sample rate to %d\n", - callingFunctionName, deviceName, (int)*sampleRate )); - return paInvalidSampleRate; - } - - /* reject if there's no sample rate within 1% of the one requested */ - if ((fabs(*sampleRate - rate) / *sampleRate) > 0.01) - { - DBUG(("%s: Device %s, wanted %d, closest sample rate was %d\n", - callingFunctionName, deviceName, (int)*sampleRate, rate )); - return paInvalidSampleRate; - } - - *sampleRate = rate; - - return paNoError; -} - -static PaError PaOSS_QueryDevice(char *deviceName, PaDeviceInfo *deviceInfo) -{ - PaError result = paNoError; - int tempDevHandle; - int numChannels, maxNumChannels; - int sampleRate; - int format; - - /* 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 - */ - - if ( (tempDevHandle = open(deviceName,O_WRONLY|O_NONBLOCK)) == -1 ) - { - DBUG(("PaOSS_QueryDevice: could not open %s\n", deviceName )); - return paDeviceUnavailable; - } - - /* Attempt to set format to 16-bit */ - format = AFMT_S16_NE; - if (ioctl(tempDevHandle, SNDCTL_DSP_SETFMT, &format) == -1) { - DBUG(("PaOSS_QueryDevice: could not set format: %s\n", deviceName )); - result = paSampleFormatNotSupported; - goto error; - } - if (format != AFMT_S16_NE) { - DBUG(("PaOSS_QueryDevice: device does not support AFMT_S16_NE: %s\n", deviceName )); - result = paSampleFormatNotSupported; - goto error; - } - - /* Negotiate for the maximum number of channels for this device. PLB20010927 - * Consider up to 16 as the upper number of channels. - * Variable maxNumChannels 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(("PaOSS_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(("PaOSS_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(("PaOSS_QueryDevice: use SNDCTL_DSP_STEREO, maxNumChannels = %d\n", maxNumChannels )) - } - - DBUG(("PaOSS_QueryDevice: maxNumChannels = %d\n", maxNumChannels)) - - deviceInfo->maxOutputChannels = maxNumChannels; - /* FIXME - for now, assume maxInputChannels = maxOutputChannels. - * Eventually do separate queries for O_WRONLY and O_RDONLY - */ - deviceInfo->maxInputChannels = deviceInfo->maxOutputChannels; - - /* During channel negotiation, the last ioctl() may have failed. This can - * also cause sample rate negotiation to fail. Hence the following, to return - * to a supported number of channels. SG20011005 */ - { - int temp = maxNumChannels; - if( temp > 2 ) temp = 2; /* use most reasonable default value */ - ioctl(tempDevHandle, SNDCTL_DSP_CHANNELS, &temp); - } - - /* Get supported sample rate closest to 44100 Hz */ - sampleRate = 44100; - if (ioctl(tempDevHandle, SNDCTL_DSP_SPEED, &sampleRate) == -1) - { - result = paUnanticipatedHostError; - goto error; - } - - deviceInfo->defaultSampleRate = sampleRate; - - deviceInfo->structVersion = 2; - - /* TODO */ - deviceInfo->defaultLowInputLatency = 128.0 / sampleRate; - deviceInfo->defaultLowOutputLatency = 128.0 / sampleRate; - deviceInfo->defaultHighInputLatency = 16384.0 / sampleRate; - deviceInfo->defaultHighOutputLatency = 16384.0 / sampleRate; - - result = paNoError; - -error: - /* We MUST close the handle here or we won't be able to reopen it later!!! */ - close(tempDevHandle); - - return result; -} - -static PaError BuildDeviceList( PaOSSHostApiRepresentation *ossApi ) -{ - PaUtilHostApiRepresentation *commonApi = &ossApi->inheritedHostApiRep; - PaOSS_DeviceList *head = NULL, *tail = NULL, *entry; - int i; - int numDevices; - - /* Find devices by calling PaOSS_QueryDevice on each - potential device names. When we find a valid one, - add it to a linked list. */ - - for(i=0; i<10; i++) { - char deviceName[32]; - PaDeviceInfo deviceInfo; - int testResult; - - if (i==0) - sprintf(deviceName, "%s", DEVICE_NAME_BASE); - else - sprintf(deviceName, "%s%d", DEVICE_NAME_BASE, i); - - DBUG(("PaOSS BuildDeviceList: trying device %s\n", deviceName )); - testResult = PaOSS_QueryDevice(deviceName, &deviceInfo); - DBUG(("PaOSS BuildDeviceList: PaOSS_QueryDevice returned %d\n", testResult )); - - if (testResult == paNoError) { - DBUG(("PaOSS BuildDeviceList: Adding device %s to list\n", deviceName)); - deviceInfo.hostApi = ossApi->hostApiIndex; - deviceInfo.name = PaUtil_GroupAllocateMemory( - ossApi->allocations, strlen(deviceName)+1); - strcpy((char *)deviceInfo.name, deviceName); - entry = (PaOSS_DeviceList *)PaUtil_AllocateMemory(sizeof(PaOSS_DeviceList)); - entry->deviceInfo = (PaDeviceInfo*)PaUtil_GroupAllocateMemory( - ossApi->allocations, sizeof(PaDeviceInfo) ); - entry->next = NULL; - memcpy(entry->deviceInfo, &deviceInfo, sizeof(PaDeviceInfo)); - if (tail) - tail->next = entry; - else { - head = entry; - tail = entry; - } - } - } - - /* Make an array of PaDeviceInfo pointers out of the linked list */ - - numDevices = 0; - entry = head; - while(entry) { - numDevices++; - entry = entry->next; - } - - DBUG(("PaOSS BuildDeviceList: Total number of devices found: %d\n", numDevices)); - - commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory( - ossApi->allocations, sizeof(PaDeviceInfo*) *numDevices ); - - entry = head; - i = 0; - while(entry) { - commonApi->deviceInfos[i] = entry->deviceInfo; - i++; - entry = entry->next; - } - - commonApi->info.deviceCount = numDevices; - commonApi->info.defaultInputDevice = 0; - commonApi->info.defaultOutputDevice = 0; - - return paNoError; -} - -static void Terminate( struct PaUtilHostApiRepresentation *hostApi ) -{ - PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi; - - if( ossHostApi->allocations ) - { - PaUtil_FreeAllAllocations( ossHostApi->allocations ); - PaUtil_DestroyAllocationGroup( ossHostApi->allocations ); - } - - PaUtil_FreeMemory( ossHostApi ); -} - -static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate ) -{ - PaDeviceIndex device; - PaDeviceInfo *deviceInfo; - PaError result = paNoError; - char *deviceName; - int inputChannelCount, outputChannelCount; - int tempDevHandle = 0; - int flags; - PaSampleFormat inputSampleFormat, outputSampleFormat; - - if( inputParameters ) - { - inputChannelCount = inputParameters->channelCount; - inputSampleFormat = inputParameters->sampleFormat; - - /* unless alternate device specification is supported, reject the use of - paUseHostApiSpecificDeviceSpecification */ - - if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) - return paInvalidDevice; - - /* check that input device can support inputChannelCount */ - if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) - return paInvalidChannelCount; - - /* validate inputStreamInfo */ - if( inputParameters->hostApiSpecificStreamInfo ) - return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ - } - else - { - inputChannelCount = 0; - } - - if( outputParameters ) - { - outputChannelCount = outputParameters->channelCount; - outputSampleFormat = outputParameters->sampleFormat; - - /* unless alternate device specification is supported, reject the use of - paUseHostApiSpecificDeviceSpecification */ - - if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) - return paInvalidDevice; - - /* check that output device can support inputChannelCount */ - if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) - return paInvalidChannelCount; - - /* validate outputStreamInfo */ - if( outputParameters->hostApiSpecificStreamInfo ) - return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ - } - else - { - outputChannelCount = 0; - } - - if (inputChannelCount == 0 && outputChannelCount == 0) - return paInvalidChannelCount; - - /* if full duplex, make sure that they're the same device */ - - if (inputChannelCount > 0 && outputChannelCount > 0 && - inputParameters->device != outputParameters->device) - return paInvalidDevice; - - /* if full duplex, also make sure that they're the same number of channels */ - - if (inputChannelCount > 0 && outputChannelCount > 0 && - inputChannelCount != outputChannelCount) - return paInvalidChannelCount; - - /* open the device so we can do more tests */ - - if (inputChannelCount > 0) { - result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, inputParameters->device, hostApi); - if (result != paNoError) - return result; - } - else { - result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, outputParameters->device, hostApi); - if (result != paNoError) - return result; - } - - deviceInfo = hostApi->deviceInfos[device]; - deviceName = (char *)deviceInfo->name; - - flags = O_NONBLOCK; - if (inputChannelCount > 0 && outputChannelCount > 0) - flags |= O_RDWR; - else if (inputChannelCount > 0) - flags |= O_RDONLY; - else - flags |= O_WRONLY; - - if ( (tempDevHandle = open(deviceInfo->name, flags)) == -1 ) - { - DBUG(("PaOSS IsFormatSupported: could not open %s\n", deviceName )); - return paDeviceUnavailable; - } - - /* PaOSS_SetFormat will do the rest of the checking for us */ - - if ((result = PaOSS_SetFormat("PaOSS IsFormatSupported", tempDevHandle, - deviceName, inputChannelCount, outputChannelCount, - &sampleRate)) != paNoError) - { - goto error; - } - - /* everything succeeded! */ - - close(tempDevHandle); - - return paFormatIsSupported; - - error: - if (tempDevHandle) - close(tempDevHandle); - - return paSampleFormatNotSupported; -} - -/* PaOSSStream - a stream data structure specifically for this implementation */ - -typedef struct PaOSSStream -{ - PaUtilStreamRepresentation streamRepresentation; - PaUtilCpuLoadMeasurer cpuLoadMeasurer; - PaUtilBufferProcessor bufferProcessor; - - int deviceHandle; - - int stopSoon; - int stopNow; - int isActive; - - int inputChannelCount; - int outputChannelCount; - - pthread_t thread; - - void *inputBuffer; - void *outputBuffer; - - int lastPosPtr; - double lastStreamBytes; - - int framesProcessed; - - double sampleRate; - - unsigned long framesPerHostCallback; -} -PaOSSStream; - -/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */ - -static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, - PaStream** s, - const PaStreamParameters *inputParameters, - const PaStreamParameters *outputParameters, - double sampleRate, - unsigned long framesPerBuffer, - PaStreamFlags streamFlags, - PaStreamCallback *streamCallback, - void *userData ) -{ - PaError result = paNoError; - PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi; - PaOSSStream *stream = 0; - PaDeviceIndex device; - PaDeviceInfo *deviceInfo; - audio_buf_info bufinfo; - int bytesPerHostBuffer; - int flags; - int deviceHandle = 0; - char *deviceName; - unsigned long framesPerHostBuffer; - int inputChannelCount, outputChannelCount; - PaSampleFormat inputSampleFormat = paInt16, outputSampleFormat = paInt16; - PaSampleFormat hostInputSampleFormat = paInt16, hostOutputSampleFormat = paInt16; - - if( inputParameters ) - { - inputChannelCount = inputParameters->channelCount; - inputSampleFormat = inputParameters->sampleFormat; - - /* unless alternate device specification is supported, reject the use of - paUseHostApiSpecificDeviceSpecification */ - - if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) - return paInvalidDevice; - - /* check that input device can support inputChannelCount */ - if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) - return paInvalidChannelCount; - - /* validate inputStreamInfo */ - if( inputParameters->hostApiSpecificStreamInfo ) - return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ - - hostInputSampleFormat = - PaUtil_SelectClosestAvailableFormat( paInt16, inputSampleFormat ); - } - else - { - inputChannelCount = 0; - } - - if( outputParameters ) - { - outputChannelCount = outputParameters->channelCount; - outputSampleFormat = outputParameters->sampleFormat; - - /* unless alternate device specification is supported, reject the use of - paUseHostApiSpecificDeviceSpecification */ - - if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) - return paInvalidDevice; - - /* check that output device can support inputChannelCount */ - if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) - return paInvalidChannelCount; - - /* validate outputStreamInfo */ - if( outputParameters->hostApiSpecificStreamInfo ) - return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ - - hostOutputSampleFormat = - PaUtil_SelectClosestAvailableFormat( paInt16, outputSampleFormat ); - } - else - { - outputChannelCount = 0; - } - - if( inputChannelCount == 0 && outputChannelCount == 0 ) - { - DBUG(("Both inputChannelCount and outputChannelCount are zero!\n")); - return paUnanticipatedHostError; - } - - /* validate platform specific flags */ - if( (streamFlags & paPlatformSpecificFlags) != 0 ) - return paInvalidFlag; /* unexpected platform specific flag */ - - /* - * open the device and set parameters here - */ - - if (inputChannelCount == 0 && outputChannelCount == 0) - return paInvalidChannelCount; - - /* if full duplex, make sure that they're the same device */ - - if (inputChannelCount > 0 && outputChannelCount > 0 && - inputParameters->device != outputParameters->device) - return paInvalidDevice; - - /* if full duplex, also make sure that they're the same number of channels */ - - if (inputChannelCount > 0 && outputChannelCount > 0 && - inputChannelCount != outputChannelCount) - return paInvalidChannelCount; - - if (inputChannelCount > 0) { - result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, inputParameters->device, hostApi); - if (result != paNoError) - return result; - } - else { - result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, outputParameters->device, hostApi); - if (result != paNoError) - return result; - } - - deviceInfo = hostApi->deviceInfos[device]; - deviceName = (char *)deviceInfo->name; - - flags = O_NONBLOCK; - if (inputChannelCount > 0 && outputChannelCount > 0) - flags |= O_RDWR; - else if (inputChannelCount > 0) - flags |= O_RDONLY; - else - flags |= O_WRONLY; - - /* open first in nonblocking mode, in case it's busy... */ - if ( (deviceHandle = open(deviceInfo->name, flags)) == -1 ) - { - DBUG(("PaOSS OpenStream: could not open %s\n", deviceName )); - return paDeviceUnavailable; - } - - /* if that succeeded, immediately open it again in blocking mode */ - close(deviceHandle); - flags -= O_NONBLOCK; - if ( (deviceHandle = open(deviceInfo->name, flags)) == -1 ) - { - DBUG(("PaOSS OpenStream: could not open %s in blocking mode\n", deviceName )); - return paDeviceUnavailable; - } - - if ((result = PaOSS_SetFormat("PaOSS OpenStream", deviceHandle, - deviceName, inputChannelCount, outputChannelCount, - &sampleRate)) != paNoError) - { - goto error; - } - - /* Compute number of frames per host buffer - if we can't retrieve the - * value, use the user's value instead - */ - - if ( ioctl(deviceHandle, SNDCTL_DSP_GETBLKSIZE, &bytesPerHostBuffer) == 0) - { - framesPerHostBuffer = bytesPerHostBuffer / 2 / (inputChannelCount>0? inputChannelCount: outputChannelCount); - } - else - framesPerHostBuffer = framesPerBuffer; - - /* Allocate stream and fill in structure */ - - stream = (PaOSSStream*)PaUtil_AllocateMemory( sizeof(PaOSSStream) ); - if( !stream ) - { - result = paInsufficientMemory; - goto error; - } - - if( streamCallback ) - { - PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, - &ossHostApi->callbackStreamInterface, streamCallback, userData ); - } - else - { - PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, - &ossHostApi->blockingStreamInterface, streamCallback, userData ); - } - - stream->streamRepresentation.streamInfo.inputLatency = 0.; - stream->streamRepresentation.streamInfo.outputLatency = 0.; - - if (inputChannelCount > 0) { - if (ioctl( deviceHandle, SNDCTL_DSP_GETISPACE, &bufinfo) == 0) - stream->streamRepresentation.streamInfo.inputLatency = - (bufinfo.fragsize * bufinfo.fragstotal) / sampleRate; - } - - if (outputChannelCount > 0) { - if (ioctl( deviceHandle, SNDCTL_DSP_GETOSPACE, &bufinfo) == 0) - stream->streamRepresentation.streamInfo.outputLatency = - (bufinfo.fragsize * bufinfo.fragstotal) / sampleRate; - } - - stream->streamRepresentation.streamInfo.sampleRate = sampleRate; - - PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate ); - - /* we assume a fixed host buffer size in this example, but the buffer processor - can also support bounded and unknown host buffer sizes by passing - paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of - paUtilFixedHostBufferSize below. */ - - result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, - inputChannelCount, inputSampleFormat, hostInputSampleFormat, - outputChannelCount, outputSampleFormat, hostOutputSampleFormat, - sampleRate, streamFlags, framesPerBuffer, - framesPerHostBuffer, paUtilFixedHostBufferSize, - streamCallback, userData ); - if( result != paNoError ) - goto error; - - stream->framesPerHostCallback = framesPerHostBuffer; - - stream->stopSoon = 0; - stream->stopNow = 0; - stream->isActive = 0; - stream->thread = 0; - stream->lastPosPtr = 0; - stream->lastStreamBytes = 0; - stream->sampleRate = sampleRate; - stream->framesProcessed = 0; - stream->deviceHandle = deviceHandle; - - if (inputChannelCount > 0) - stream->inputBuffer = PaUtil_AllocateMemory( 2 * framesPerHostBuffer * inputChannelCount ); - else - stream->inputBuffer = NULL; - - if (outputChannelCount > 0) - stream->outputBuffer = PaUtil_AllocateMemory( 2 * framesPerHostBuffer * outputChannelCount ); - else - stream->outputBuffer = NULL; - - stream->inputChannelCount = inputChannelCount; - stream->outputChannelCount = outputChannelCount; - - *s = (PaStream*)stream; - - result = paNoError; - - return result; - -error: - if( stream ) - PaUtil_FreeMemory( stream ); - - if( deviceHandle ) - close( deviceHandle ); - - return result; -} - -static void *PaOSS_AudioThreadProc(void *userData) -{ - PaOSSStream *stream = (PaOSSStream*)userData; - - DBUG(("PaOSS AudioThread: %d in, %d out\n", stream->inputChannelCount, stream->outputChannelCount)); - - while( (stream->stopNow == 0) && (stream->stopSoon == 0) ) { - PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* TODO: IMPLEMENT ME */ - int callbackResult; - unsigned long framesProcessed; - int bytesRequested; - int bytesRead, bytesWritten; - int delta; - int result; - count_info info; - - PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); - - PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo ); - - /* - depending on whether the host buffers are interleaved, non-interleaved - or a mixture, you will want to call PaUtil_SetInterleaved*Channels(), - PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here. - */ - - if ( stream->inputChannelCount > 0 ) - { - bytesRequested = stream->framesPerHostCallback * 2 * stream->inputChannelCount; - bytesRead = read( stream->deviceHandle, stream->inputBuffer, bytesRequested ); - - PaUtil_SetInputFrameCount( &stream->bufferProcessor, bytesRead/(2*stream->inputChannelCount)); - PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, - 0, /* first channel of inputBuffer is channel 0 */ - stream->inputBuffer, - 0 ); /* 0 - use inputChannelCount passed to init buffer processor */ - } - - if ( stream->outputChannelCount > 0 ) - { - PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ ); - PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, - 0, /* first channel of outputBuffer is channel 0 */ - stream->outputBuffer, - 0 ); /* 0 - use outputChannelCount passed to init buffer processor */ - } - - framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); - - PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); - - if( callbackResult == paContinue ) - { - /* nothing special to do */ - } - else if( callbackResult == paAbort ) - { - /* once finished, call the finished callback */ - if( stream->streamRepresentation.streamFinishedCallback != 0 ) - stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); - - return NULL; /* return from the loop */ - } - else if ( callbackResult == paComplete ) - { - /* User callback has asked us to stop with paComplete or other non-zero value */ - - /* once finished, call the finished callback */ - if( stream->streamRepresentation.streamFinishedCallback != 0 ) - stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); - - stream->stopSoon = 1; - } - - if ( stream->outputChannelCount > 0 ) { - /* write output samples AFTER we've checked the callback result code */ - - bytesRequested = stream->framesPerHostCallback * 2 * stream->outputChannelCount; - bytesWritten = write( stream->deviceHandle, stream->outputBuffer, bytesRequested ); - - /* TODO: handle bytesWritten != bytesRequested (slippage?) */ - } - - /* Update current stream time (using a double so that - we don't wrap around like info.bytes does) */ - if( stream->outputChannelCount > 0 ) - result = ioctl( stream->deviceHandle, SNDCTL_DSP_GETOPTR, &info); - else - result = ioctl( stream->deviceHandle, SNDCTL_DSP_GETIPTR, &info); - - if (result == 0) { - delta = ( info.bytes - stream->lastPosPtr ) & 0x000FFFFF; - stream->lastStreamBytes += delta; - stream->lastPosPtr = info.bytes; - } - - stream->framesProcessed += stream->framesPerHostCallback; - } - - return NULL; -} - -/* - When CloseStream() is called, the multi-api layer ensures that - the stream has already been stopped or aborted. -*/ -static PaError CloseStream( PaStream* s ) -{ - PaError result = paNoError; - PaOSSStream *stream = (PaOSSStream*)s; - - close(stream->deviceHandle); - - if ( stream->inputBuffer ) - PaUtil_FreeMemory( stream->inputBuffer ); - if ( stream->outputBuffer ) - PaUtil_FreeMemory( stream->outputBuffer ); - - PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); - PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); - PaUtil_FreeMemory( stream ); - - return result; -} - - -static PaError StartStream( PaStream *s ) -{ - PaError result = paNoError; - PaOSSStream *stream = (PaOSSStream*)s; - int presult; - - stream->isActive = 1; - stream->lastPosPtr = 0; - stream->lastStreamBytes = 0; - stream->framesProcessed = 0; - - DBUG(("PaOSS StartStream\n")); - - presult = pthread_create(&stream->thread, - NULL /*pthread_attr_t * attr*/, - (void*)PaOSS_AudioThreadProc, (void *)stream); - - return result; -} - - -static PaError StopStream( PaStream *s ) -{ - PaError result = paNoError; - PaOSSStream *stream = (PaOSSStream*)s; - - stream->stopSoon = 1; - pthread_join( stream->thread, NULL ); - stream->stopSoon = 0; - stream->stopNow = 0; - stream->isActive = 0; - - DBUG(("PaOSS StopStream: Stopped stream\n")); - - return result; -} - - -static PaError AbortStream( PaStream *s ) -{ - PaError result = paNoError; - PaOSSStream *stream = (PaOSSStream*)s; - - stream->stopNow = 1; - pthread_join( stream->thread, NULL ); - stream->stopSoon = 0; - stream->stopNow = 0; - stream->isActive = 0; - - DBUG(("PaOSS AbortStream: Stopped stream\n")); - - return result; -} - - -static PaError IsStreamStopped( PaStream *s ) -{ - PaOSSStream *stream = (PaOSSStream*)s; - - return (!stream->isActive); -} - - -static PaError IsStreamActive( PaStream *s ) -{ - PaOSSStream *stream = (PaOSSStream*)s; - - return (stream->isActive); -} - - -static PaTime GetStreamTime( PaStream *s ) -{ - PaOSSStream *stream = (PaOSSStream*)s; - count_info info; - int delta; - - if( stream->outputChannelCount > 0 ) { - if (ioctl( stream->deviceHandle, SNDCTL_DSP_GETOPTR, &info) == 0) { - delta = ( info.bytes - stream->lastPosPtr ) & 0x000FFFFF; - return ( stream->lastStreamBytes + delta) / ( stream->outputChannelCount * 2 ) / stream->sampleRate; - } - } - else { - if (ioctl( stream->deviceHandle, SNDCTL_DSP_GETIPTR, &info) == 0) { - delta = (info.bytes - stream->lastPosPtr) & 0x000FFFFF; - return ( stream->lastStreamBytes + delta) / ( stream->inputChannelCount * 2 ) / stream->sampleRate; - } - } - - /* the ioctl failed, but we can still give a coarse estimate */ - - return stream->framesProcessed / stream->sampleRate; -} - - -static double GetStreamCpuLoad( PaStream* s ) -{ - PaOSSStream *stream = (PaOSSStream*)s; - - return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ); -} - - -/* - As separate stream interfaces are used for blocking and callback - streams, the following functions can be guaranteed to only be called - for blocking streams. -*/ - - -static PaError ReadStream( PaStream* s, - void *buffer, - unsigned long frames ) -{ - PaOSSStream *stream = (PaOSSStream*)s; - int bytesRequested, bytesRead; - - bytesRequested = frames * 2 * stream->inputChannelCount; - bytesRead = read( stream->deviceHandle, stream->inputBuffer, bytesRequested ); - - if ( bytesRequested != bytesRead ) - return paUnanticipatedHostError; - else - return paNoError; -} - - -static PaError WriteStream( PaStream* s, - void *buffer, - unsigned long frames ) -{ - PaOSSStream *stream = (PaOSSStream*)s; - int bytesRequested, bytesWritten; - - bytesRequested = frames * 2 * stream->outputChannelCount; - bytesWritten = write( stream->deviceHandle, buffer, bytesRequested ); - - if ( bytesRequested != bytesWritten ) - return paUnanticipatedHostError; - else - return paNoError; -} - - -static signed long GetStreamReadAvailable( PaStream* s ) -{ - PaOSSStream *stream = (PaOSSStream*)s; - audio_buf_info info; - - if ( ioctl(stream->deviceHandle, SNDCTL_DSP_GETISPACE, &info) == 0) - { - int bytesAvailable = info.fragments * info.fragsize; - return ( bytesAvailable / 2 / stream->inputChannelCount ); - } - else - return 0; /* TODO: is this right for "don't know"? */ -} - - -static signed long GetStreamWriteAvailable( PaStream* s ) -{ - PaOSSStream *stream = (PaOSSStream*)s; - - audio_buf_info info; - - if ( ioctl(stream->deviceHandle, SNDCTL_DSP_GETOSPACE, &info) == 0) - { - int bytesAvailable = info.fragments * info.fragsize; - return ( bytesAvailable / 2 / stream->outputChannelCount ); - } - else - return 0; /* TODO: is this right for "don't know"? */ -} - -- cgit v1.2.1