📄 pa_mac_core.c
字号:
return result;error: return result;}/*******************************************************************/PaError PaHost_OpenOutputStream( internalPortAudioStream *past ){ PaHostSoundControl *pahsc; const PaHostDeviceInfo *hostDeviceInfo; PaError result = paNoError; UInt32 bytesPerHostBuffer; UInt32 dataSize; OSStatus err = noErr; int bytesPerOutputFrame; pahsc = (PaHostSoundControl *) past->past_DeviceData; DBUG(("PaHost_OpenStream: 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]; /* Try to set sample rate. */ result = PaHost_SetSampleRate( hostDeviceInfo->audioDeviceID, IS_OUTPUT, past->past_SampleRate ); if( result != paNoError ) return result; if( past->past_NumOutputChannels != hostDeviceInfo->paInfo.maxOutputChannels ) {#if 1 return paInvalidChannelCount; // FIXME - how support mono?#else /* Attempt to set number of channels. */ AudioStreamBasicDescription formatDesc; OSStatus err; memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) ); formatDesc.mChannelsPerFrame = past->past_NumOutputChannels; err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_OUTPUT, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); if (err != kAudioHardwareNoError) { result = paInvalidChannelCount; goto error; }#endif } // calculate buffer sizes in bytes bytesPerOutputFrame = Pa_GetSampleSize(paFloat32) * past->past_NumOutputChannels; pahsc->pahsc_BytesPerUserNativeOutputBuffer = past->past_FramesPerUserBuffer * bytesPerOutputFrame; bytesPerHostBuffer = pahsc->pahsc_FramesPerHostBuffer * bytesPerOutputFrame; // Change the bufferSize of the device! Is this per device or just for our stream? dataSize = sizeof(bytesPerHostBuffer); err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_OUTPUT, kAudioDevicePropertyBufferSize, dataSize, &bytesPerHostBuffer); if( err != noErr ) { ERR_RPT(("Could not force buffer size!")); result = paHostError; goto error; } // setup conversion procedure result = PaConvert_SetupOutput( past, paFloat32 ); return result;error: return result;}/*******************************************************************/PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past ){ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; return pahsc->pahsc_FramesPerHostBuffer;}/******************************************************************** Determine how many User Buffers we can put into our CoreAudio stream buffer.* Uses:* past->past_FramesPerUserBuffer, etc.* Sets:* past->past_NumUserBuffers* pahsc->pahsc_UserBuffersPerHostBuffer* pahsc->pahsc_FramesPerHostBuffer*/static void PaHost_CalcHostBufferSize( internalPortAudioStream *past ){ PaHostSoundControl *pahsc = ( PaHostSoundControl *)past->past_DeviceData; unsigned int minNumUserBuffers; // Determine number of user buffers based on minimum latency. minNumUserBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); // Compare to user requested number in user wants more than the minimum. past->past_NumUserBuffers = ( minNumUserBuffers > past->past_NumUserBuffers ) ? minNumUserBuffers : past->past_NumUserBuffers; DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers )); // For CoreAudio, we only have one Host buffer, so... pahsc->pahsc_UserBuffersPerHostBuffer = past->past_NumUserBuffers; // Calculate size of CoreAudio buffer. pahsc->pahsc_FramesPerHostBuffer = past->past_FramesPerUserBuffer * past->past_NumUserBuffers; DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer )); DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer ));}/*******************************************************************/PaError PaHost_OpenStream( internalPortAudioStream *past ){ PaError result = paNoError; PaHostSoundControl *pahsc; /* Allocate and initialize host data. */ pahsc = (PaHostSoundControl *) malloc(sizeof(PaHostSoundControl)); if( pahsc == NULL ) { result = paInsufficientMemory; goto error; } memset( pahsc, 0, sizeof(PaHostSoundControl) ); past->past_DeviceData = (void *) pahsc; // If we are using both input and out, then they must be on the same CoreAudio device, // until we implement a FIFO between two devices. if( (past->past_OutputDeviceID != paNoDevice) && (past->past_InputDeviceID != paNoDevice) ) { AudioDeviceID inputID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID; AudioDeviceID outputID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID; if( inputID != outputID ) { ERR_RPT(("PortAudio: input and output must use same CoreAudio device!\n")); return paInvalidDeviceId; } } PaHost_CalcHostBufferSize( past ); { int msecLatency = (int) ((PaHost_GetTotalBufferFrames(past) * 1000) / past->past_SampleRate); PRINT(("PortAudio on OS X - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(past), msecLatency )); } /* Setup constants for CPU load measurement. */ pahsc->pahsc_InverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * pahsc->pahsc_FramesPerHostBuffer); /* ------------------ OUTPUT */ if( (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0) ) { pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID; result = PaHost_OpenOutputStream( past ); if( result < 0 ) goto error; } /* ------------------ INPUT */ if( (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0) ) { pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID; result = PaHost_OpenInputStream( past ); if( result < 0 ) goto error; } return result;error: PaHost_CloseStream( past ); return result;}/*************************************************************************/PaError PaHost_StartOutput( internalPortAudioStream *past ){ return 0;}/*************************************************************************/PaError PaHost_StartInput( internalPortAudioStream *past ){ return 0;}/*************************************************************************/PaError PaHost_StartEngine( internalPortAudioStream *past ){ OSStatus err = noErr; PaError result = paNoError; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; past->past_StopSoon = 0; past->past_StopNow = 0; past->past_IsActive = 1; // Associate an IO proc with the device and pass a pointer to the audio data context err = AudioDeviceAddIOProc(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc, past); if (err != noErr) goto error; // start playing sound through the device err = AudioDeviceStart(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc); if (err != noErr) goto error; return result;#if PA_TRACE_START_STOP AddTraceMessage( "PaHost_StartEngine: TimeSlice() returned ", result );#endiferror: return paHostError; // FIXME - save host error}/*************************************************************************/PaError PaHost_StopEngine( internalPortAudioStream *past, int abort ){ OSStatus err = noErr; PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError; (void) abort; /* Tell background thread to stop generating more data and to let current data play out. */ past->past_StopSoon = 1; /* If aborting, tell background thread to stop NOW! */ if( abort ) past->past_StopNow = 1; past->past_IsActive = 0;#if PA_TRACE_START_STOP AddTraceMessage( "PaHost_StopOutput: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut );#endif // FIXME - we should ask proc to stop instead of stopping abruptly err = AudioDeviceStop(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc); if (err != noErr) goto Bail; err = AudioDeviceRemoveIOProc(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc); if (err != noErr) goto Bail; return paNoError;Bail: return paHostError; // FIXME - save err}/*************************************************************************/PaError PaHost_StopInput( internalPortAudioStream *past, int abort ){ return paNoError;}/*************************************************************************/PaError PaHost_StopOutput( internalPortAudioStream *past, int abort ){ return paNoError;}/*******************************************************************/PaError PaHost_CloseStream( internalPortAudioStream *past ){ PaHostSoundControl *pahsc; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paNoError;#if PA_TRACE_START_STOP AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut );#endif free( pahsc ); past->past_DeviceData = NULL; return paNoError;}/*************************************************************************** Determine minimum number of buffers required for this host based** on minimum latency. Latency can be optionally set by user by setting** an environment variable. For example, to set latency to 200 msec, put:**** set PA_MIN_LATENCY_MSEC=200**** in the cshrc file.*/#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")#if 1int Pa_GetMinNumBuffers( int framesPerBuffer, double framesPerSecond ){ int minBuffers; int denominator; int minLatencyMsec = PA_MIN_LATENCY_MSEC; char *minLatencyText = getenv(PA_LATENCY_ENV_NAME); if( minLatencyText != NULL ) { PRINT(("PA_MIN_LATENCY_MSEC = %s\n", minLatencyText )); minLatencyMsec = atoi( minLatencyText ); if( minLatencyMsec < 1 ) minLatencyMsec = 1; else if( minLatencyMsec > 5000 ) minLatencyMsec = 5000; } denominator = 1000.0 * framesPerBuffer; minBuffers = (int) (((minLatencyMsec * framesPerSecond) + denominator - 1) / denominator ); if( minBuffers < 1 ) minBuffers = 1; return minBuffers;}#else/*************************************************************************** Determine minimum number of buffers required for this host based** on minimum latency. */int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate ){ int minUserBuffers; int minFramesPerHostBuffer; // Calculate minimum and maximum sizes based on timing and sample rate. minFramesPerHostBuffer = (int) (PA_MIN_LATENCY_MSEC * sampleRate / 1000.0); // round up to nearest multiple of 8 minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7; DBUG(("Pa_GetMinNumBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer )); minUserBuffers = (minFramesPerHostBuffer + framesPerUserBuffer - 1) / framesPerUserBuffer; if( minUserBuffers < 1 ) minUserBuffers = 1; return minUserBuffers;}#endif/*************************************************************************** Cleanup device info.*/PaError PaHost_Term( void ){ int i; if( sDeviceInfos != NULL ) { for( i=0; i<sNumPaDevices; i++ ) { if( sDeviceInfos[i].paInfo.name != NULL ) free( (char*)sDeviceInfos[i].paInfo.name ); if( sDeviceInfos[i].paInfo.sampleRates != NULL ) free( (void*)sDeviceInfos[i].paInfo.sampleRates ); } free( sDeviceInfos ); sDeviceInfos = NULL; } sNumPaDevices = 0; return paNoError;}/*************************************************************************/void Pa_Sleep( long msec ){#if 0 struct timeval timeout; timeout.tv_sec = msec / 1000; timeout.tv_usec = (msec % 1000) * 1000; select( 0, NULL, NULL, NULL, &timeout );#else usleep( msec * 1000 );#endif}/************************************************************************* * Allocate memory that can be accessed in real-time. * This may need to be held in physical memory so that it is not * paged to virtual memory. * This call MUST be balanced with a call to PaHost_FreeFastMemory(). */void *PaHost_AllocateFastMemory( long numBytes ){ void *addr = malloc( numBytes ); /* FIXME - do we need physical memory? */ if( addr != NULL ) memset( addr, 0, numBytes ); return addr;}/************************************************************************* * Free memory that could be accessed in real-time. * This call MUST be balanced with a call to PaHost_AllocateFastMemory(). */void PaHost_FreeFastMemory( void *addr, long numBytes ){ if( addr != NULL ) free( addr );}/***********************************************************************/PaError PaHost_StreamActive( internalPortAudioStream *past ){ PaHostSoundControl *pahsc; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; if( pahsc == NULL ) return paInternalError; return (PaError) past->past_IsActive;}/*************************************************************************/PaTimestamp Pa_StreamTime( PortAudioStream *stream ){ AudioTimeStamp timeStamp; PaTimestamp streamTime; PaHostSoundControl *pahsc; internalPortAudioStream *past = (internalPortAudioStream *) stream; if( past == NULL ) return paBadStreamPtr; pahsc = (PaHostSoundControl *) past->past_DeviceData; AudioDeviceGetCurrentTime(pahsc->pahsc_AudioDeviceID, &timeStamp); streamTime = ( timeStamp.mFlags & kAudioTimeStampSampleTimeValid) ? timeStamp.mSampleTime : past->past_FrameCount; return streamTime;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -