📄 pa_mac_core.c
字号:
sSavedHostError = err; goto error; } } if( updateConverter ) { DBUG(("PAOSX_DevicePropertyListener: HW rate = %f\n", hardwareStreamFormat.mSampleRate )); DBUG(("PAOSX_DevicePropertyListener: user rate = %f\n", past->past_SampleRate )); /* Set source user format. */ memset(&userStreamFormat, 0, sizeof(AudioStreamBasicDescription)); userStreamFormat.mFormatID = kAudioFormatLinearPCM; userStreamFormat.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsPacked; userStreamFormat.mBitsPerChannel = 32; 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 userStreamFormat.mBytesPerFrame = userStreamFormat.mChannelsPerFrame * sizeof(float); userStreamFormat.mFramesPerPacket = 1; userStreamFormat.mBytesPerPacket = userStreamFormat.mBytesPerFrame * userStreamFormat.mFramesPerPacket; if( isInput ) { if( pahsc->input.converter != NULL ) { verify_noerr(AudioConverterDispose (pahsc->input.converter)); } // Convert from hardware format to user format. err = AudioConverterNew ( &hardwareStreamFormat, &userStreamFormat, &pahsc->input.converter ); if( err != noErr ) { PRINT_ERR("Could not create input format converter", err); sSavedHostError = err; goto error; } } else { if( pahsc->output.converter != NULL ) { verify_noerr(AudioConverterDispose (pahsc->output.converter)); } // Convert from user format to hardware format. err = AudioConverterNew ( &userStreamFormat, &hardwareStreamFormat, &pahsc->output.converter ); if( err != noErr ) { PRINT_ERR("Could not create output format converter", err); sSavedHostError = err; goto error; } } } if( updateInverseMicros ) { // Update coefficient used to calculate CPU Load based on sampleRate and bufferSize. UInt32 ioBufferSize; dataSize = sizeof(ioBufferSize); err = AudioDeviceGetProperty( inDevice, 0, isInput, kAudioDevicePropertyBufferFrameSize, &dataSize, &ioBufferSize); if( err == noErr ) { pahsc->inverseMicrosPerHostBuffer = hardwareStreamFormat.mSampleRate / (1000000.0 * ioBufferSize); } }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; 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 I/O buffer size.\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 I/O buffer size.\n", err); sSavedHostError = err; return paHostError; } bytesForDevice = framesPerHostBuffer * formatDesc.mChannelsPerFrame * sizeof(Float32) * 2; bytesForUser = past->past_FramesPerUserBuffer * past->past_NumInputChannels * sizeof(Float32) * 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 full at beginning RingBuffer_AdvanceWriteIndex( &pahsc->ringBuffer, numBytes ); 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; /* dmazzoni: this is not needed because we use PortMixer PaOSX_FixVolumeScalars( inOut->audioDeviceID, isInput, inOut->numChannels, -0.1, 0.9 ); */ pahsc->formatListenerCalled = false; // 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. 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 == 1 ) { const int sleepDurMsec = 10; int spinCount = MIN_TIMEOUT_MSEC / sleepDurMsec; while( !pahsc->formatListenerCalled && (spinCount > 0) ) { DBUG(("Sleeping: %d\n", spinCount)); 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; } // The HW device format changes are asynchronous. If the DevicePropertyListener // still hasn't been called, we call it manually here. 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; } }#if SET_DEVICE_BUFFER_SIZE // Try to set the I/O bufferSize of the device. { Float64 ratio; deviceRate = PaOSX_GetDeviceSampleRate( inOut->audioDeviceID, isInput ); if( deviceRate <= 0.0 ) deviceRate = past->past_SampleRate; ratio = deviceRate / past->past_SampleRate ; err = PaOSX_SetDeviceBufferSize( inOut->audioDeviceID, isInput, past->past_FramesPerUserBuffer, ratio ); if( err != noErr ) { DBUG(("PaOSX_OpenCommonDevice: Could not set I/O buffer size.\n")); } }#endif /* Allocate an input buffer because we need it between the user callback and the converter. */ inOut->converterBuffer = PaHost_AllocateFastMemory( inOut->bytesPerUserNativeBuffer ); if( inOut->converterBuffer == NULL ) { return paInsufficientMemory; } return result;}/*******************************************************************/static PaError PaOSX_OpenInputDevice( internalPortAudioStream *past ){ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; const PaHostDeviceInfo *hostDeviceInfo; PaError result = paNoError; DBUG(("PaOSX_OpenInputDevice: -------------\n")); if( (past->past_InputDeviceID < LOWEST_INPUT_DEVID) || (past->past_InputDeviceID > HIGHEST_INPUT_DEVID) ) { return paInvalidDeviceId; } hostDeviceInfo = &sDeviceInfos[past->past_InputDeviceID]; if( past->past_NumInputChannels > hostDeviceInfo->paInfo.maxInputChannels ) { return paInvalidChannelCount; /* Too many channels! */ } pahsc->input.numChannels = past->past_NumInputChannels; // setup PA conversion procedure result = PaConvert_SetupInput( past, paFloat32 ); result = PaOSX_OpenCommonDevice( past, &pahsc->input, IS_INPUT ); if( result != paNoError ) goto error; // Allocate a ring buffer so we can push in data from device, and pull through AudioConverter. result = PaOSX_CreateInputRingBuffer( past ); if( result != paNoError ) goto error; error: return result;}/*******************************************************************/static PaError PaOSX_OpenOutputDevice( internalPortAudioStream *past ){ PaHostSoundControl *pahsc; const PaHostDeviceInfo *hostDeviceInfo; PaError result = paNoError; DBUG(("PaOSX_OpenOutputDevice: -------------\n")); pahsc = (PaHostSoundControl *) past->past_DeviceData; // Validate DeviceID DBUG(("PaOSX_OpenOutputDevice: deviceID = 0x%x\n", past->past_OutputDeviceID)); if( (past->past_OutputDeviceID < LOWEST_OUTPUT_DEVID) || (past->past_OutputDeviceID > HIGHEST_OUTPUT_DEVID) ) { return paInvalidDeviceId; } hostDeviceInfo = &sDeviceInfos[past->past_OutputDeviceID]; // Validate number of channels. if( past->past_NumOutputChannels > hostDeviceInfo->paInfo.maxOutputChannels ) { return paInvalidChannelCount; /* Too many channels! */ } pahsc->output.numChannels = past->past_NumOutputChannels; // setup conversion procedure result = PaConvert_SetupOutput( past, paFloat32 ); if( result != paNoError ) goto error; result = PaOSX_OpenCommonDevice( past, &pahsc->output, IS_OUTPUT ); if( result != paNoError ) goto error; error: return result;}/******************************************************************** Determine how many User Buffers we can put into our CoreAudio stream buffer.* Uses:* past->past_FramesPerUser
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -