📄 pa_mac_core.c
字号:
/*************************************************************************
** Try to fill in the device info for this device.
** Return 1 if a good device that PA can use.
** Return 0 if not appropriate
** or return negative error.
**
*/
static int PaOSX_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput )
{
OSStatus err;
UInt32 outSize;
AudioStreamBasicDescription formatDesc;
AudioDeviceID devID;
PaDeviceInfo *deviceInfo = &hostDeviceInfo->paInfo;
int maxChannels;
deviceInfo->structVersion = 1;
deviceInfo->maxInputChannels = 0;
deviceInfo->maxOutputChannels = 0;
deviceInfo->sampleRates = supportedSampleRateRange; // because we use sample rate converter to get continuous rates
deviceInfo->numSampleRates = -1;
devID = sCoreDeviceIDs[ coreDeviceIndex ];
hostDeviceInfo->audioDeviceID = devID;
DBUG(("PaOSX_QueryDeviceInfo: coreDeviceIndex = %d, devID = %d, isInput = %d\n",
coreDeviceIndex, (int) devID, isInput ));
// Get data format info from the device.
outSize = sizeof(formatDesc);
err = AudioDeviceGetProperty(devID, 0, isInput, kAudioDevicePropertyStreamFormat, &outSize, &formatDesc);
// This just may not be an appropriate device for input or output so leave quietly.
if( (err != noErr) || (formatDesc.mChannelsPerFrame == 0) ) goto error;
DBUG(("PaOSX_QueryDeviceInfo: mFormatID = 0x%x\n", (unsigned int) formatDesc.mFormatID));
DBUG(("PaOSX_QueryDeviceInfo: mFormatFlags = 0x%x\n",(unsigned int) formatDesc.mFormatFlags));
// Right now the Core Audio headers only define one formatID: LinearPCM
// Apparently LinearPCM must be Float32 for now.
if( (formatDesc.mFormatID == kAudioFormatLinearPCM) &&
((formatDesc.mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0) )
{
deviceInfo->nativeSampleFormats = paFloat32;
}
else
{
PRINT(("PaOSX_QueryDeviceInfo: ERROR - not LinearPCM & Float32!!!\n"));
return paSampleFormatNotSupported;
}
maxChannels = PaOSX_GetMaxChannels( devID, isInput );
if( maxChannels <= 0 ) goto error;
if( isInput )
{
deviceInfo->maxInputChannels = maxChannels;
}
else
{
deviceInfo->maxOutputChannels = maxChannels;
}
// Get the device name
deviceInfo->name = PaOSX_DeviceNameFromID( devID, isInput );
DBUG(("PaOSX_QueryDeviceInfo: name = %s\n", deviceInfo->name ));
return 1;
error:
return 0;
}
/**********************************************************************/
static PaError PaOSX_MaybeQueryDevices( void )
{
if( sNumPaDevices == 0 )
{
return PaOSX_QueryDevices();
}
return 0;
}
static char zeroPad[256] = { 0 };
/**********************************************************************
** This is the proc that supplies the data to the AudioConverterFillBuffer call.
** We can pass back arbitrarily sized blocks so if the FIFO region is split
** just pass back the first half.
*/
static OSStatus PaOSX_InputConverterCallbackProc (AudioConverterRef inAudioConverter,
UInt32* outDataSize,
void** outData,
void* inUserData)
{
internalPortAudioStream *past = (internalPortAudioStream *) inUserData;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
void *dataPtr1;
long size1;
void *dataPtr2;
long size2;
/* Pass contiguous region from FIFO directly to converter. */
RingBuffer_GetReadRegions( &pahsc->ringBuffer, *outDataSize,
&dataPtr1, &size1, &dataPtr2, &size2 );
if( size1 > 0 )
{
*outData = dataPtr1;
*outDataSize = size1;
RingBuffer_AdvanceReadIndex( &pahsc->ringBuffer, size1 );
DBUGX(("PaOSX_InputConverterCallbackProc: read %ld bytes from FIFO.\n", size1 ));
}
else
{
DBUGBACK(("PaOSX_InputConverterCallbackProc: got no data!\n"));
*outData = zeroPad; /* Give it zero data to keep it happy. */
*outDataSize = sizeof(zeroPad);
}
return noErr;
}
/*****************************************************************************
** Get audio input, if any, from passed in buffer, or from converter or from FIFO,
** then run PA callback and output data.
*/
static OSStatus PaOSX_LoadAndProcess( internalPortAudioStream *past,
void *inputBuffer, void *outputBuffer )
{
OSStatus err = noErr;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( past->past_StopSoon )
{
if( outputBuffer )
{
/* Clear remainder of audio buffer if we are waiting for stop. */
AddTraceMessage("PaOSX_LoadAndProcess: zero rest of wave buffer ", i );
memset( outputBuffer, 0, pahsc->output.bytesPerUserNativeBuffer );
}
}
else
{
/* Do we need data from the converted input? */
if( PA_USING_INPUT )
{
UInt32 size = pahsc->input.bytesPerUserNativeBuffer;
err = AudioConverterFillBuffer(
pahsc->input.converter,
PaOSX_InputConverterCallbackProc,
past,
&size,
pahsc->input.converterBuffer);
if( err != noErr ) return err;
inputBuffer = pahsc->input.converterBuffer;
}
/* Measure CPU load. */
#if PA_ENABLE_LOAD_MEASUREMENT
Pa_StartUsageCalculation( past );
#endif
/* Fill part of audio converter buffer by converting input to user format,
* calling user callback, then converting output to native format. */
if( PaConvert_Process( past, inputBuffer, outputBuffer ))
{
past->past_StopSoon = 1;
}
#if PA_ENABLE_LOAD_MEASUREMENT
Pa_EndUsageCalculation( past );
#endif
}
return err;
}
/*****************************************************************************
** This is the proc that supplies the data to the AudioConverterFillBuffer call
*/
static OSStatus PaOSX_OutputConverterCallbackProc (AudioConverterRef inAudioConverter,
UInt32* outDataSize,
void** outData,
void* inUserData)
{
internalPortAudioStream *past = (internalPortAudioStream *) inUserData;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
*outData = pahsc->output.converterBuffer;
*outDataSize = pahsc->output.bytesPerUserNativeBuffer;
return PaOSX_LoadAndProcess ( past, pahsc->input.converterBuffer, pahsc->output.converterBuffer );
}
/**********************************************************************
** If data available, write it to the Ring Buffer so we can
** pull it from the other side.
*/
static OSStatus PaOSX_WriteInputRingBuffer( internalPortAudioStream *past,
const AudioBufferList* inInputData )
{
int numBytes = 0;
int currentInterleavedChannelIndex;
int numFramesInInputBuffer;
int numInterleavedChannels;
int numChannelsRemaining;
int i;
long writeRoom;
char *inputNativeBufferfPtr = NULL;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
/* Do we need to deinterleave the buffers first? */
if( past->past_NumInputChannels != inInputData->mBuffers[0].mNumberChannels )
{
numFramesInInputBuffer = inInputData->mBuffers[0].mDataByteSize /
(sizeof(float) * inInputData->mBuffers[0].mNumberChannels);
numBytes = numFramesInInputBuffer * sizeof(float) * past->past_NumInputChannels;
/* Allocate temporary buffer if needed. */
if ( (pahsc->input.streamInterleavingBuffer != NULL) &&
(pahsc->input.streamInterleavingBufferLen < numBytes) )
{
PaHost_FreeFastMemory( pahsc->input.streamInterleavingBuffer, pahsc->input.streamInterleavingBufferLen );
pahsc->input.streamInterleavingBuffer = NULL;
}
if ( pahsc->input.streamInterleavingBuffer == NULL )
{
pahsc->input.streamInterleavingBufferLen = numBytes;
pahsc->input.streamInterleavingBuffer = (float *)PaHost_AllocateFastMemory( pahsc->input.streamInterleavingBufferLen );
}
/* Perform interleaving by writing to temp buffer. */
currentInterleavedChannelIndex = 0;
numInterleavedChannels = past->past_NumInputChannels;
numChannelsRemaining = numInterleavedChannels;
for( i=0; i<inInputData->mNumberBuffers; i++ )
{
int j;
int numBufChannels = inInputData->mBuffers[i].mNumberChannels;
/* Don't use more than we need or more than we have. */
int numChannelsUsedInThisBuffer = (numChannelsRemaining < numBufChannels ) ?
numChannelsRemaining : numBufChannels;
for( j=0; j<numChannelsUsedInThisBuffer; j++ )
{
int k;
float *dest = &pahsc->input.streamInterleavingBuffer[ currentInterleavedChannelIndex ];
float *src = &((float *)inInputData->mBuffers[i].mData)[ j ];
/* Move one channel from CoreAudio buffer to interleaved buffer. */
for( k=0; k<numFramesInInputBuffer; k++ )
{
*dest = *src;
src += numBufChannels;
dest += numInterleavedChannels;
}
currentInterleavedChannelIndex++;
}
numChannelsRemaining -= numChannelsUsedInThisBuffer;
if( numChannelsRemaining <= 0 ) break;
}
inputNativeBufferfPtr = (char *)pahsc->input.streamInterleavingBuffer;
}
else
{
inputNativeBufferfPtr = (char*)inInputData->mBuffers[0].mData;
numBytes = inInputData->mBuffers[0].mDataByteSize;
}
writeRoom = RingBuffer_GetWriteAvailable( &pahsc->ringBuffer );
if( numBytes <= writeRoom )
{
RingBuffer_Write( &pahsc->ringBuffer, inputNativeBufferfPtr, numBytes );
DBUGBACK(("PaOSX_WriteInputRingBuffer: wrote %ld bytes to FIFO.\n", numBytes));
} // FIXME else drop samples on floor, remember overflow???
return noErr;
}
/**********************************************************************
** Use any available input buffers by writing to RingBuffer.
** Process input if PA_MODE_INPUT_ONLY.
*/
static OSStatus PaOSX_HandleInput( internalPortAudioStream *past,
const AudioBufferList* inInputData )
{
OSStatus err = noErr;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( inInputData == NULL )
{
DBUG(("PaOSX_HandleInput: inInputData == NULL\n"));
return noErr;
}
if( inInputData->mNumberBuffers > 0 )
{
/* Write to FIFO here if we are only using this callback. */
if( (pahsc->mode == PA_MODE_INPUT_ONLY) || (pahsc->mode == PA_MODE_IO_ONE_DEVICE) )
{
err = PaOSX_WriteInputRingBuffer( past, inInputData );
if( err != noErr ) goto error;
}
}
if( pahsc->mode == PA_MODE_INPUT_ONLY )
{
/* Generate user buffers as long as we have a half full input FIFO. */
long halfSize = pahsc->ringBuffer.bufferSize / 2;
while( (RingBuffer_GetReadAvailable( &pahsc->ringBuffer ) >= halfSize) &&
(past->past_StopSoon == 0) )
{
err = PaOSX_LoadAndProcess ( past, NULL, NULL );
if( err != noErr ) goto error;
}
}
error:
return err;
}
/**********************************************************************
** Fill any available output buffers.
*/
static OSStatus PaOSX_HandleOutput( internalPortAudioStream *past,
AudioBufferList* outOutputData )
{
OSStatus err = noErr;
void *outputNativeBufferfPtr = NULL;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
UInt32 numBytes = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -