📄 pa_unix_oss.c
字号:
maxNumChannels = (stereo) ? 2 : 1;
}
PA_DEBUG(( "%s: use SNDCTL_DSP_STEREO, maxNumChannels = %d\n", __FUNCTION__, maxNumChannels ))
}
/* 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 */
{
/* use most reasonable default value */
int temp = PA_MIN( maxNumChannels, 2 );
ENSURE_( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ), paUnanticipatedHostError );
}
/* Get supported sample rate closest to 44100 Hz */
if( *defaultSampleRate < 0 )
{
sr = 44100;
if( ioctl( devHandle, SNDCTL_DSP_SPEED, &sr ) < 0 )
{
result = paUnanticipatedHostError;
goto error;
}
*defaultSampleRate = sr;
}
*maxChannelCount = maxNumChannels;
/* TODO */
*defaultLowLatency = 512. / *defaultSampleRate;
*defaultHighLatency = 2048. / *defaultSampleRate;
error:
if( devHandle >= 0 )
close( devHandle );
return result;
}
/** Query OSS device.
*
* This is where PaDeviceInfo objects are constructed and filled in with relevant information.
*
* Aspect DeviceCapabilities: The inferred device capabilities are recorded in a PaDeviceInfo object that is constructed
* in place.
*/
static PaError QueryDevice( char *deviceName, PaOSSHostApiRepresentation *ossApi, PaDeviceInfo **deviceInfo )
{
PaError result = paNoError;
double sampleRate = -1.;
int maxInputChannels, maxOutputChannels;
PaTime defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency;
PaError tmpRes = paNoError;
int busy = 0;
*deviceInfo = NULL;
/* 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
*/
/* Aspect StreamChannels: The number of channels supported for a device may depend on the mode it is
* opened in, it may have more channels available for capture than playback and vice versa. Therefore
* we will open the device in both read- and write-only mode to determine the supported number.
*/
if( (tmpRes = QueryDirection( deviceName, StreamMode_In, &sampleRate, &maxInputChannels, &defaultLowInputLatency,
&defaultHighInputLatency )) != paNoError )
{
if( tmpRes != paDeviceUnavailable )
{
PA_DEBUG(( "%s: Querying device %s for capture failed!\n", __FUNCTION__, deviceName ));
/* PA_ENSURE( tmpRes ); */
}
++busy;
}
if( (tmpRes = QueryDirection( deviceName, StreamMode_Out, &sampleRate, &maxOutputChannels, &defaultLowOutputLatency,
&defaultHighOutputLatency )) != paNoError )
{
if( tmpRes != paDeviceUnavailable )
{
PA_DEBUG(( "%s: Querying device %s for playback failed!\n", __FUNCTION__, deviceName ));
/* PA_ENSURE( tmpRes ); */
}
++busy;
}
assert( 0 <= busy && busy <= 2 );
if( 2 == busy ) /* Both directions are unavailable to us */
{
result = paDeviceUnavailable;
goto error;
}
PA_UNLESS( *deviceInfo = PaUtil_GroupAllocateMemory( ossApi->allocations, sizeof (PaDeviceInfo) ), paInsufficientMemory );
PA_ENSURE( PaUtil_InitializeDeviceInfo( *deviceInfo, deviceName, ossApi->hostApiIndex, maxInputChannels, maxOutputChannels,
defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency, sampleRate,
ossApi->allocations ) );
error:
return result;
}
/** Query host devices.
*
* Loop over host devices and query their capabilitiesu
*
* Aspect DeviceCapabilities: This function calls QueryDevice on each device entry and receives a filled in PaDeviceInfo object
* per device, these are placed in the host api representation's deviceInfos array.
*/
static PaError BuildDeviceList( PaOSSHostApiRepresentation *ossApi )
{
PaError result = paNoError;
PaUtilHostApiRepresentation *commonApi = &ossApi->inheritedHostApiRep;
int i;
int numDevices = 0, maxDeviceInfos = 1;
PaDeviceInfo **deviceInfos = NULL;
/* These two will be set to the first working input and output device, respectively */
commonApi->info.defaultInputDevice = paNoDevice;
commonApi->info.defaultOutputDevice = paNoDevice;
/* Find devices by calling QueryDevice on each
* potential device names. When we find a valid one,
* add it to a linked list.
* A: Can there only be 10 devices? */
for( i = 0; i < 10; i++ )
{
char deviceName[32];
PaDeviceInfo *deviceInfo;
int testResult;
struct stat stbuf;
if( i == 0 )
snprintf(deviceName, sizeof (deviceName), "%s", DEVICE_NAME_BASE);
else
snprintf(deviceName, sizeof (deviceName), "%s%d", DEVICE_NAME_BASE, i);
/* PA_DEBUG(("PaOSS BuildDeviceList: trying device %s\n", deviceName )); */
if( stat( deviceName, &stbuf ) < 0 )
{
if( ENOENT != errno )
PA_DEBUG(( "%s: Error stat'ing %s: %s\n", __FUNCTION__, deviceName, strerror( errno ) ));
continue;
}
if( (testResult = QueryDevice( deviceName, ossApi, &deviceInfo )) != paNoError )
{
if( testResult != paDeviceUnavailable )
PA_ENSURE( testResult );
continue;
}
++numDevices;
if( !deviceInfos || numDevices > maxDeviceInfos )
{
maxDeviceInfos *= 2;
PA_UNLESS( deviceInfos = (PaDeviceInfo **) realloc( deviceInfos, maxDeviceInfos * sizeof (PaDeviceInfo *) ),
paInsufficientMemory );
}
deviceInfos[numDevices - 1] = deviceInfo;
if( commonApi->info.defaultInputDevice == paNoDevice && deviceInfo->maxInputChannels > 0 )
commonApi->info.defaultInputDevice = i;
if( commonApi->info.defaultOutputDevice == paNoDevice && deviceInfo->maxOutputChannels > 0 )
commonApi->info.defaultOutputDevice = i;
}
/* Make an array of PaDeviceInfo pointers out of the linked list */
PA_DEBUG(("PaOSS %s: Total number of devices found: %d\n", __FUNCTION__, numDevices));
commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
ossApi->allocations, sizeof(PaDeviceInfo*) * numDevices );
memcpy( commonApi->deviceInfos, deviceInfos, numDevices * sizeof (PaDeviceInfo *) );
commonApi->info.deviceCount = numDevices;
error:
free( deviceInfos );
return result;
}
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 )
{
PaError result = paNoError;
PaDeviceIndex device;
PaDeviceInfo *deviceInfo;
char *deviceName;
int inputChannelCount, outputChannelCount;
int tempDevHandle = -1;
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;
ENSURE_( tempDevHandle = open( deviceInfo->name, flags ), paDeviceUnavailable );
/* PaOssStream_Configure will do the rest of the checking for us */
/* PA_ENSURE( PaOssStream_Configure( tempDevHandle, deviceName, outputChannelCount, &sampleRate ) ); */
/* everything succeeded! */
error:
if( tempDevHandle >= 0 )
close( tempDevHandle );
return result;
}
/** Validate stream parameters.
*
* Aspect StreamChannels: We verify that the number of channels is within the allowed range for the device
*/
static PaError ValidateParameters( const PaStreamParameters *parameters, const PaDeviceInfo *deviceInfo, StreamMode mode )
{
int maxChans;
assert( parameters );
if( parameters->device == paUseHostApiSpecificDeviceSpecification )
{
return paInvalidDevice;
}
maxChans = (mode == StreamMode_In ? deviceInfo->maxInputChannels :
deviceInfo->maxOutputChannels);
if( parameters->channelCount > maxChans )
{
return paInvalidChannelCount;
}
return paNoError;
}
static PaError PaOssStreamComponent_Initialize( PaOssStreamComponent *component, const PaStreamParameters *parameters,
int callbackMode, int fd, const char *deviceName )
{
PaError result = paNoError;
assert( component );
memset( component, 0, sizeof (PaOssStreamComponent) );
component->fd = fd;
component->devName = deviceName;
component->userChannelCount = parameters->channelCount;
component->userFormat = parameters->sampleFormat;
component->latency = parameters->suggestedLatency;
component->userInterleaved = !(parameters->sampleFormat & paNonInterleaved);
if( !callbackMode && !component->userInterleaved )
{
/* Pre-allocate non-interleaved user provided buffers */
PA_UNLESS( component->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * component->userChannelCount ),
paInsufficientMemory );
}
error:
return result;
}
static void PaOssStreamComponent_Terminate( PaOssStreamComponent *component )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -