📄 pa_mac_core.c
字号:
}
}
#if 0
static void PaOSX_DumpDeviceInfo( AudioDeviceID devID, Boolean isInput )
{
OSStatus err = noErr;
UInt32 dataSize;
UInt32 uidata32;
Float32 fdata32;
AudioValueRange audioRange;
dataSize = sizeof( uidata32 );
err = AudioDeviceGetProperty( devID, 0, isInput,
kAudioDevicePropertyLatency, &dataSize, &uidata32 );
if( err != noErr )
{
PRINT_ERR("Error reading kAudioDevicePropertyLatency", err);
return;
}
PRINT(("kAudioDevicePropertyLatency = %d\n", (int)uidata32 ));
dataSize = sizeof( fdata32 );
err = AudioDeviceGetProperty( devID, 1, isInput,
kAudioDevicePropertyVolumeScalar, &dataSize, &fdata32 );
if( err != noErr )
{
PRINT_ERR("Error reading kAudioDevicePropertyVolumeScalar", err);
return;
}
PRINT(("kAudioDevicePropertyVolumeScalar = %f\n", fdata32 ));
dataSize = sizeof( uidata32 );
err = AudioDeviceGetProperty( devID, 0, isInput,
kAudioDevicePropertyBufferSize, &dataSize, &uidata32 );
if( err != noErr )
{
PRINT_ERR("Error reading buffer size", err);
return;
}
PRINT(("kAudioDevicePropertyBufferSize = %d bytes\n", (int)uidata32 ));
dataSize = sizeof( audioRange );
err = AudioDeviceGetProperty( devID, 0, isInput,
kAudioDevicePropertyBufferSizeRange, &dataSize, &audioRange );
if( err != noErr )
{
PRINT_ERR("Error reading buffer size range", err);
return;
}
PRINT(("kAudioDevicePropertyBufferSizeRange = %g to %g bytes\n", audioRange.mMinimum, audioRange.mMaximum ));
dataSize = sizeof( uidata32 );
err = AudioDeviceGetProperty( devID, 0, isInput,
kAudioDevicePropertyBufferFrameSize, &dataSize, &uidata32 );
if( err != noErr )
{
PRINT_ERR("Error reading buffer size", err);
return;
}
PRINT(("kAudioDevicePropertyBufferFrameSize = %d frames\n", (int)uidata32 ));
dataSize = sizeof( audioRange );
err = AudioDeviceGetProperty( devID, 0, isInput,
kAudioDevicePropertyBufferFrameSizeRange, &dataSize, &audioRange );
if( err != noErr )
{
PRINT_ERR("Error reading buffer size range", err);
return;
}
PRINT(("kAudioDevicePropertyBufferFrameSizeRange = %g to %g frames\n", audioRange.mMinimum, audioRange.mMaximum ));
return;
}
#endif
/*******************************************************************/
static OSStatus PAOSX_DevicePropertyListener (AudioDeviceID inDevice,
UInt32 inChannel,
Boolean isInput,
AudioDevicePropertyID inPropertyID,
void* inClientData)
{
PaHostSoundControl *pahsc;
internalPortAudioStream *past;
UInt32 dataSize;
OSStatus err = noErr;
AudioStreamBasicDescription userStreamFormat, hardwareStreamFormat;
PaHostInOut *hostInOut;
AudioStreamBasicDescription *destFormatPtr, *srcFormatPtr;
past = (internalPortAudioStream *) inClientData;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
DBUG(("PAOSX_DevicePropertyListener: called with propertyID = 0x%0X\n", (unsigned int) inPropertyID ));
if(inPropertyID == kAudioDevicePropertyStreamFormat)
{
/* Get target device format */
dataSize = sizeof(hardwareStreamFormat);
err = AudioDeviceGetProperty(inDevice, 0, isInput,
kAudioDevicePropertyStreamFormat, &dataSize, &hardwareStreamFormat);
if( err != noErr )
{
PRINT_ERR("PAOSX_DevicePropertyListener: Could not get device format", err);
sSavedHostError = err;
goto error;
}
DBUG(("PAOSX_DevicePropertyListener: HW mChannelsPerFrame = %d\n", (int)hardwareStreamFormat.mChannelsPerFrame ));
/* Set source user format. */
userStreamFormat = hardwareStreamFormat;
userStreamFormat.mSampleRate = past->past_SampleRate; // sample rate of the user synthesis code
userStreamFormat.mChannelsPerFrame = (isInput) ? past->past_NumInputChannels : past->past_NumOutputChannels; // the number of channels in each frame
DBUG(("PAOSX_DevicePropertyListener: User mChannelsPerFrame = %d\n", (int)userStreamFormat.mChannelsPerFrame ));
userStreamFormat.mBytesPerFrame = userStreamFormat.mChannelsPerFrame * sizeof(float);
userStreamFormat.mBytesPerPacket = userStreamFormat.mBytesPerFrame * userStreamFormat.mFramesPerPacket;
/* Don't use AudioConverter for merging or splitting channels. */
hardwareStreamFormat.mChannelsPerFrame = userStreamFormat.mChannelsPerFrame;
hardwareStreamFormat.mBytesPerFrame = userStreamFormat.mBytesPerFrame;
hardwareStreamFormat.mBytesPerPacket = userStreamFormat.mBytesPerPacket;
if( isInput )
{
hostInOut = &pahsc->input;
srcFormatPtr = &hardwareStreamFormat;
destFormatPtr = &userStreamFormat;
}
else
{
hostInOut = &pahsc->output;
srcFormatPtr = &userStreamFormat;
destFormatPtr = &hardwareStreamFormat;
}
DBUG(("PAOSX_DevicePropertyListener: source rate = %f\n", srcFormatPtr->mSampleRate ));
DBUG(("PAOSX_DevicePropertyListener: dest rate = %f\n", destFormatPtr->mSampleRate ));
// Don't delete old converter until we create new one so we don't pull
// the rug out from under other audio threads.
AudioConverterRef oldConverter = hostInOut->converter;
// Make converter to change sample rate.
err = AudioConverterNew (
srcFormatPtr,
destFormatPtr,
&hostInOut->converter );
if( err != noErr )
{
PRINT_ERR("Could not create format converter", err);
sSavedHostError = err;
goto error;
}
if( oldConverter != NULL )
{
verify_noerr( AudioConverterDispose( oldConverter ) );
}
}
error:
pahsc->formatListenerCalled = true;
return err;
}
/* Allocate FIFO between Device callback and Converter callback so that device can push data
* and converter can pull data.
*/
static PaError PaOSX_CreateInputRingBuffer( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
OSStatus err = noErr;
UInt32 dataSize;
double sampleRateRatio;
long numBytes;
UInt32 framesPerHostBuffer;
UInt32 bytesForDevice;
UInt32 bytesForUser;
UInt32 bytesPerFrame;
AudioStreamBasicDescription formatDesc;
dataSize = sizeof(formatDesc);
err = AudioDeviceGetProperty( pahsc->input.audioDeviceID, 0, IS_INPUT,
kAudioDevicePropertyStreamFormat, &dataSize, &formatDesc);
if( err != noErr )
{
PRINT_ERR("PaOSX_CreateInputRingBuffer: Could not get input format.\n", err);
sSavedHostError = err;
return paHostError;
}
// If device is delivering audio faster than being consumed then buffer must be bigger.
sampleRateRatio = formatDesc.mSampleRate / past->past_SampleRate;
// Get size of CoreAudio IO buffers.
dataSize = sizeof(framesPerHostBuffer);
err = AudioDeviceGetProperty( pahsc->input.audioDeviceID, 0, IS_INPUT,
kAudioDevicePropertyBufferFrameSize, &dataSize,
&framesPerHostBuffer);
if( err != noErr )
{
PRINT_ERR("PaOSX_CreateInputRingBuffer: Could not get input buffer size.\n", err);
sSavedHostError = err;
return paHostError;
}
bytesPerFrame = past->past_NumInputChannels * sizeof(Float32);
bytesForDevice = framesPerHostBuffer * bytesPerFrame * 2;
bytesForUser = past->past_FramesPerUserBuffer * bytesPerFrame * 3 * sampleRateRatio;
// Ring buffer should be large enough to consume audio input from device,
// and to deliver a complete user buffer.
numBytes = (bytesForDevice > bytesForUser) ? bytesForDevice : bytesForUser;
numBytes = RoundUpToNextPowerOf2( numBytes );
DBUG(("PaOSX_CreateInputRingBuffer: FIFO numBytes = %ld\n", numBytes));
pahsc->ringBufferData = PaHost_AllocateFastMemory( numBytes );
if( pahsc->ringBufferData == NULL )
{
return paInsufficientMemory;
}
RingBuffer_Init( &pahsc->ringBuffer, numBytes, pahsc->ringBufferData );
// Make it look almost full at beginning. We must advance by an integral number of frames
// so that the channels don't get scrambled when numChannels is not a power of 2.
{
int numZeroFrames = numBytes / bytesPerFrame;
int numZeroBytes = numZeroFrames * bytesPerFrame;
RingBuffer_AdvanceWriteIndex( &pahsc->ringBuffer, numZeroBytes );
}
return paNoError;
}
/******************************************************************
* Try to set the I/O bufferSize of the device.
* Scale the size by the ratio of the sample rates so that the converter will have
* enough data to operate on.
*/
static OSStatus PaOSX_SetDeviceBufferSize( AudioDeviceID devID, Boolean isInput, int framesPerUserBuffer, Float64 sampleRateRatio )
{
UInt32 dataSize;
UInt32 ioBufferSize;
int scaler;
scaler = (int) sampleRateRatio;
if( sampleRateRatio > (Float64) scaler ) scaler += 1;
DBUG(("PaOSX_SetDeviceBufferSize: buffer size scaler = %d\n", scaler ));
ioBufferSize = framesPerUserBuffer * scaler;
// Limit buffer size to reasonable value.
if( ioBufferSize < 128 ) ioBufferSize = 128;
dataSize = sizeof(ioBufferSize);
return AudioDeviceSetProperty( devID, 0, 0, isInput,
kAudioDevicePropertyBufferFrameSize, dataSize,
&ioBufferSize);
}
/*******************************************************************/
static PaError PaOSX_OpenCommonDevice( internalPortAudioStream *past,
PaHostInOut *inOut, Boolean isInput )
{
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
PaError result = paNoError;
OSStatus err = noErr;
Float64 deviceRate;
PaOSX_FixVolumeScalars( inOut->audioDeviceID, isInput,
inOut->numChannels, 0.1, 0.9 );
// The HW device format changes are asynchronous.
// So we don't know when or if the PAOSX_DevicePropertyListener() will
// get called. To be safe, call the listener now to forcibly create the converter.
if( inOut->converter == NULL )
{
err = PAOSX_DevicePropertyListener (inOut->audioDeviceID,
0, isInput, kAudioDevicePropertyStreamFormat, past);
if (err != kAudioHardwareNoError)
{
PRINT_ERR("PaOSX_OpenCommonDevice: PAOSX_DevicePropertyListener failed.\n", err);
sSavedHostError = err;
return paHostError;
}
}
// Add listener for when format changed by other apps.
DBUG(("PaOSX_OpenCommonDevice: call AudioDeviceAddPropertyListener()\n" ));
err = AudioDeviceAddPropertyListener( inOut->audioDeviceID, 0, isInput,
kAudioDevicePropertyStreamFormat,
(AudioDevicePropertyListenerProc) PAOSX_DevicePropertyListener, past );
if (err != noErr)
{
return -1; // FIXME
}
// Only change format if current HW format is different.
// Don't bother to check result because we are going to use an AudioConverter anyway.
pahsc->formatListenerCalled = false;
result = PaOSX_SetFormat( inOut->audioDeviceID, isInput, past->past_SampleRate, inOut->numChannels );
// Synchronize with device because format changes put some devices into unusable mode.
if( result > 0 )
{
const int sleepDurMsec = 50;
int spinCount = MIN_TIMEOUT_MSEC / sleepDurMsec;
while( !pahsc->formatListenerCalled && (spinCount > 0) )
{
Pa_Sleep( sleepDurMsec ); // FIXME - use a semaphore or signal
spinCount--;
}
if( !pahsc->formatListenerCalled )
{
PRINT(("PaOSX_OpenCommonDevice: timed out waiting for device format to settle.\n"));
}
result = 0;
}
#if SET_DEVICE_BUFFER_SIZE
// Try to set the I/O bufferSize of the device.
{
Float64 ratio;
deviceRate = PaOSX_GetDeviceSampleRate
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -