📄 pa_mac_core.c
字号:
static int PaHost_ScanDevices( Boolean isInput ){ int coreDeviceIndex; int result; PaHostDeviceInfo *hostDeviceInfo; int numAdded = 0; for( coreDeviceIndex=0; coreDeviceIndex<sNumCoreDevices; coreDeviceIndex++ ) { // try to fill in next PaHostDeviceInfo hostDeviceInfo = &sDeviceInfos[sNumPaDevices]; result = PaHost_QueryDeviceInfo( hostDeviceInfo, coreDeviceIndex, isInput ); DBUG(("PaHost_ScanDevices: paDevId = %d, coreDevId = %d\n", sNumPaDevices, hostDeviceInfo->audioDeviceID )); if( result > 0 ) { sNumPaDevices += 1; // bump global counter if we got one numAdded += 1; } else if( result < 0 ) return result; } return numAdded;}/*************************************************************************** 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 PaHost_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput ){ OSErr err; int index; UInt32 outSize; AudioStreamBasicDescription formatDesc; Boolean result; AudioDeviceID devID; double *sampleRates = NULL; /* non-const ptr */ PaDeviceInfo *deviceInfo = &hostDeviceInfo->paInfo; double possibleSampleRates[] = {8000.0, 11025.0, 22050.0, 44100.0, 48000.0, 88200.0, 96000.0}; int maxNumSampleRates = sizeof( possibleSampleRates ) / sizeof( double ); deviceInfo->structVersion = 1; deviceInfo->maxInputChannels = 0; deviceInfo->maxOutputChannels = 0; deviceInfo->numSampleRates = -1; devID = sCoreDeviceIDs[ coreDeviceIndex ]; hostDeviceInfo->audioDeviceID = devID; // Figure out supported sample rates // Make room in case device supports all rates. sampleRates = (double*)PaHost_AllocateFastMemory( maxNumSampleRates * sizeof(double) ); if( sampleRates == NULL ) return paInsufficientMemory; deviceInfo->sampleRates = sampleRates; deviceInfo->numSampleRates = 0; // Loop through the possible sampling rates and check each to see if the device supports it. for (index = 0; index < maxNumSampleRates; index ++) { memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); formatDesc.mSampleRate = possibleSampleRates[index]; result = deviceDoesSupportFormat( devID, &formatDesc, isInput ); if (result == true) { deviceInfo->numSampleRates += 1; *sampleRates = possibleSampleRates[index]; sampleRates++; } } // If no sample rates supported, then not a very good device. if( deviceInfo->numSampleRates == 0 ) goto error; // Get data format info from the device. outSize = sizeof(formatDesc); err = AudioDeviceGetProperty(devID, 0, isInput, kAudioDevicePropertyStreamFormat, &outSize, &formatDesc); // If no channels supported, then not a very good device. if( (err != noErr) || (formatDesc.mChannelsPerFrame == 0) ) goto error; if( isInput ) { deviceInfo->maxInputChannels = formatDesc.mChannelsPerFrame; } else { deviceInfo->maxOutputChannels = formatDesc.mChannelsPerFrame; } // FIXME - where to put current sample rate?: formatDesc.mSampleRate // Right now the Core Audio headers only define one formatID: LinearPCM // Apparently LinearPCM must be Float32 for now. switch (formatDesc.mFormatID) { case kAudioFormatLinearPCM: deviceInfo->nativeSampleFormats = paFloat32; // FIXME - details about the format are in these flags. // formatDesc.mFormatFlags // here are the possibilities // kLinearPCMFormatFlagIsFloat // set for floating point, clear for integer // kLinearPCMFormatFlagIsBigEndian // set for big endian, clear for little // kLinearPCMFormatFlagIsSignedInteger // set for signed integer, clear for unsigned integer, // only valid if kLinearPCMFormatFlagIsFloat is clear // kLinearPCMFormatFlagIsPacked // set if the sample bits are packed as closely together as possible, // clear if they are high or low aligned within the channel // kLinearPCMFormatFlagIsAlignedHigh // set if the sample bits are placed break; default: deviceInfo->nativeSampleFormats = paFloat32; // FIXME break; } // Get the device name deviceInfo->name = PaHost_DeviceNameFromID( devID, isInput ); return 1;error: if( sampleRates != NULL ) free( sampleRates ); return 0;}/*************************************************************************** Returns recommended device ID.** On the PC, the recommended device can be specified by the user by** setting an environment variable. For example, to use device #1.**** set PA_RECOMMENDED_OUTPUT_DEVICE=1**** The user should first determine the available device ID by using** the supplied application "pa_devs".*/#define PA_ENV_BUF_SIZE (32)#define PA_REC_IN_DEV_ENV_NAME ("PA_RECOMMENDED_INPUT_DEVICE")#define PA_REC_OUT_DEV_ENV_NAME ("PA_RECOMMENDED_OUTPUT_DEVICE")static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName ){#if 0 UInt32 hresult; char envbuf[PA_ENV_BUF_SIZE]; PaDeviceID recommendedID = paNoDevice; /* Let user determine default device by setting environment variable. */ hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE ); if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) ) { recommendedID = atoi( envbuf ); } return recommendedID;#endif return paNoDevice;}static PaError Pa_MaybeQueryDevices( void ){ if( sNumPaDevices == 0 ) { return Pa_QueryDevices(); } return 0;}/************************************************************************ Check for environment variable, else query devices and use result.*/PaDeviceID Pa_GetDefaultInputDeviceID( void ){ PaError result; result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME ); if( result < 0 ) { result = Pa_MaybeQueryDevices(); if( result < 0 ) return result; result = sDefaultInputDeviceID; } return result;}PaDeviceID Pa_GetDefaultOutputDeviceID( void ){ PaError result; result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME ); if( result < 0 ) { result = Pa_MaybeQueryDevices(); if( result < 0 ) return result; result = sDefaultOutputDeviceID; } return result;}/************************************************************************ Initialize Host dependant part of API.*/PaError PaHost_Init( void ){ return Pa_MaybeQueryDevices();}/************************************************************************ Fill any available output buffers and use any available** input buffers by calling user callback.*/static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferList* inInputData, AudioBufferList* outOutputData ){ PaError result = 0; char *inputNativeBufferfPtr = NULL; char *outputNativeBufferfPtr = NULL; int i; int buffersProcessed = 0; int done = 0; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paInternalError; past->past_NumCallbacks += 1;#if PA_TRACE_RUN AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", past->past_NumCallbacks );#endif Pa_StartUsageCalculation( past ); /* If we are using output, then we need an empty output buffer. */ if( past->past_NumOutputChannels > 0 ) { outputNativeBufferfPtr = (char*)outOutputData->mBuffers[0].mData; } /* If we are using input, then we need a full input buffer. */ if( past->past_NumInputChannels > 0 ) { inputNativeBufferfPtr = (char*)inInputData->mBuffers[0].mData; } buffersProcessed += 1; /* Each host buffer contains multiple user buffers so do them all now. */ for( i=0; i<pahsc->pahsc_UserBuffersPerHostBuffer; i++ ) { if( done ) { if( outputNativeBufferfPtr ) { /* Clear remainder of wave buffer if we are waiting for stop. */ AddTraceMessage("Pa_TimeSlice: zero rest of wave buffer ", i ); memset( outputNativeBufferfPtr, 0, pahsc->pahsc_BytesPerUserNativeOutputBuffer ); } } else { /* Convert 32 bit native data to user data and call user routine. */ result = PaConvert_Process( past, inputNativeBufferfPtr, outputNativeBufferfPtr ); if( result != 0) done = 1; } if( inputNativeBufferfPtr ) inputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeInputBuffer; if( outputNativeBufferfPtr) outputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeOutputBuffer; } Pa_EndUsageCalculation( past );#if PA_TRACE_RUN AddTraceMessage("Pa_TimeSlice: buffersProcessed ", buffersProcessed );#endif return (result != 0) ? result : done;}OSStatus appIOProc (AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* contextPtr){ PaError result = 0; internalPortAudioStream *past; PaHostSoundControl *pahsc; past = (internalPortAudioStream *) contextPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData;// printf("Num input Buffers: %d; Num output Buffers: %d.\n", inInputData->mNumberBuffers, outOutputData->mNumberBuffers); /* Has someone asked us to abort by calling Pa_AbortStream()? */ if( past->past_StopNow ) { past->past_IsActive = 0; /* Will cause thread to return. */ } /* Has someone asked us to stop by calling Pa_StopStream() * OR has a user callback returned '1' to indicate finished. */ else if( past->past_StopSoon ) { // FIXME - pretend all done past->past_IsActive = 0; /* Will cause thread to return. */ } else { /* use time stamp from CoreAudio if valid */ if( inOutputTime->mFlags & kAudioTimeStampSampleTimeValid) { past->past_FrameCount = inOutputTime->mSampleTime; } /* Process full input buffer and fill up empty output buffers. */ if( (result = Pa_TimeSlice( past, inInputData, outOutputData )) != 0) { /* User callback has asked us to stop. */#if PA_TRACE_START_STOP AddTraceMessage( "Pa_OutputThreadProc: TimeSlice() returned ", result );#endif past->past_StopSoon = 1; /* Request that audio play out then stop. */ result = paNoError; } } // FIXME PaHost_UpdateStreamTime( pahsc ); return result;}#if 0static int PaHost_CalcTimeOut( internalPortAudioStream *past ){ /* Calculate timeOut longer than longest time it could take to play all buffers. */ int timeOut = (UInt32) (1500.0 * PaHost_GetTotalBufferFrames( past ) / past->past_SampleRate); if( timeOut < MIN_TIMEOUT_MSEC ) timeOut = MIN_TIMEOUT_MSEC; return timeOut;}#endif/*******************************************************************//* Attempt to set device sample rate. */static PaError PaHost_SetSampleRate( AudioDeviceID devID, Boolean isInput, double sampleRate ){ AudioStreamBasicDescription formatDesc; OSStatus err; memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); formatDesc.mSampleRate = sampleRate; err = AudioDeviceSetProperty( devID, 0, 0, isInput, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); if (err != kAudioHardwareNoError) return paInvalidSampleRate; else return paNoError;}/*******************************************************************/PaError PaHost_OpenInputStream( internalPortAudioStream *past ){ PaHostSoundControl *pahsc; const PaHostDeviceInfo *hostDeviceInfo; PaError result = paNoError; UInt32 bytesPerHostBuffer; UInt32 dataSize; OSStatus err = noErr; int bytesPerInputFrame; pahsc = (PaHostSoundControl *) past->past_DeviceData; DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_InputDeviceID)); if( (past->past_InputDeviceID < LOWEST_INPUT_DEVID) || (past->past_InputDeviceID > HIGHEST_INPUT_DEVID) ) { return paInvalidDeviceId; } hostDeviceInfo = &sDeviceInfos[past->past_InputDeviceID]; /* Try to set sample rate. */ result = PaHost_SetSampleRate( hostDeviceInfo->audioDeviceID, IS_INPUT, past->past_SampleRate ); if( result != paNoError ) return result; if( past->past_NumInputChannels != hostDeviceInfo->paInfo.maxInputChannels ) {#if 1 return paInvalidChannelCount; // FIXME - how support mono?#elseFIXME - should this be set on a stream basis? Is it possible to change? /* Attempt to set number of channels. */ AudioStreamBasicDescription formatDesc; OSStatus err; memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); formatDesc.mChannelsPerFrame = past->past_NumInputChannels; err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_INPUT, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); if (err != kAudioHardwareNoError) { result = paInvalidChannelCount; goto error; }#endif } // calculate native buffer sizes in bytes bytesPerInputFrame = Pa_GetSampleSize(paFloat32) * past->past_NumInputChannels; pahsc->pahsc_BytesPerUserNativeInputBuffer = past->past_FramesPerUserBuffer * bytesPerInputFrame; bytesPerHostBuffer = pahsc->pahsc_FramesPerHostBuffer * bytesPerInputFrame; // Change the bufferSize of the device! Is this per device or just for our stream? dataSize = sizeof(UInt32); err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_INPUT, kAudioDevicePropertyBufferSize, dataSize, &bytesPerHostBuffer); if( err != noErr ) { ERR_RPT(("Could not force buffer size!")); result = paHostError; goto error; } // setup conversion procedure result = PaConvert_SetupInput( past, paFloat32 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -