From fe8aa4ce5e8eebc1c6f762f4fc40328718a13e22 Mon Sep 17 00:00:00 2001 From: Miller Puckette Date: Sat, 31 Dec 2005 01:32:12 +0000 Subject: Deleted unused (?) files svn path=/trunk/; revision=4318 --- pd/portaudio_v18/pa_mac_core/pa_mac_core.c | 2136 ---------------------------- 1 file changed, 2136 deletions(-) delete mode 100644 pd/portaudio_v18/pa_mac_core/pa_mac_core.c (limited to 'pd/portaudio_v18/pa_mac_core/pa_mac_core.c') diff --git a/pd/portaudio_v18/pa_mac_core/pa_mac_core.c b/pd/portaudio_v18/pa_mac_core/pa_mac_core.c deleted file mode 100644 index 983d0e4f..00000000 --- a/pd/portaudio_v18/pa_mac_core/pa_mac_core.c +++ /dev/null @@ -1,2136 +0,0 @@ -/* - * $Id: pa_mac_core.c,v 1.8.4.13 2003/12/09 19:04:54 philburk Exp $ - * pa_mac_core.c - * Implementation of PortAudio for Mac OS X Core Audio - * - * PortAudio Portable Real-Time Audio Library - * Latest Version at: http://www.portaudio.com - * - * Authors: Ross Bencina and Phil Burk - * Copyright (c) 1999-2002 Ross Bencina and Phil Burk - * - * Theory of Operation - * - * This code uses the HAL (Hardware Access Layer) of the Apple CoreAudio library. - * This is the layer closes to the hardware. - * The HAL layer only supports the native HW supported sample rates. - * So if the chip only supports 44100 Hz, then the HAL only supports 44100. - * To provide other rates we use the handy Apple AudioConverter which provides - * sample rate conversion, mono-to-stereo conversion, and buffer size adaptation. - * - * There are four modes of operation: - * PA_MODE_OUTPUT_ONLY, - * PA_MODE_INPUT_ONLY, - * PA_MODE_IO_ONE_DEVICE, - * PA_MODE_IO_TWO_DEVICES - * - * The processing pipeline for PA_MODE_IO_ONE_DEVICE is in one thread: - * - * PaOSX_CoreAudioIOCallback() input buffers -> RingBuffer -> input.AudioConverter -> - * PortAudio callback -> output.AudioConverter -> PaOSX_CoreAudioIOCallback() output buffers - * - * For two separate devices, we have to use two separate callbacks. - * We pass data between them using a RingBuffer FIFO. - * The processing pipeline for PA_MODE_IO_TWO_DEVICES is split into two threads: - * - * PaOSX_CoreAudioInputCallback() input buffers -> RingBuffer - * - * RingBuffer -> input.AudioConverter -> - * PortAudio callback -> output.AudioConverter -> PaOSX_CoreAudioIOCallback() output buffers - * - * License - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files - * (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * Any person wishing to distribute modifications to the Software is - * requested to send the modifications to the original developer so that - * they can be incorporated into the canonical version. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * CHANGE HISTORY: - - 3.29.2001 - Phil Burk - First pass... converted from Window MME code with help from Darren. - 3.30.2001 - Darren Gibbs - Added more support for dynamically querying device info. - 12.7.2001 - Gord Peters - Tweaks to compile on PA V17 and OS X 10.1 - 2.7.2002 - Darren and Phil - fixed isInput so GetProperty works better, - fixed device queries for numChannels and sampleRates, - one CoreAudio device now maps to separate input and output PaDevices, - audio input works if using same CoreAudio device (some HW devices make separate CoreAudio devices). - 2.22.2002 - Stephane Letz - Explicit cast needed for compilation with Code Warrior 7 - 3.19.2002 - Phil Burk - Added paInt16, paInt8, format using new "pa_common/pa_convert.c" file. - Return error if opened in mono mode cuz not supported. [Supported 10.12.2002] - Add support for Pa_GetCPULoad(); - Fixed timestamp in callback and Pa_StreamTime() (Thanks n++k for the advice!) - Check for invalid sample rates and return an error. - Check for getenv("PA_MIN_LATENCY_MSEC") to set latency externally. - Better error checking for invalid channel counts and invalid devices. - 3.29.2002 - Phil Burk - Fixed Pa_GetCPULoad() for small buffers. - 3.31.2002 - Phil Burk - Use getrusage() instead of gettimeofday() for CPU Load calculation. - 10.12.2002 - Phil Burk - Use AudioConverter to allow wide range of sample rates, and mono. - Use FIFO (from pablio/rinbuffer.h) so that we can pull data through converter. - Added PaOSX_FixVolumeScalar() to make iMic audible. - 10.17.2002 - Phil Burk - Support full duplex between two different devices. - Name internal functions PaOSX_* - Dumped useless PA_MIN_LATENCY_MSEC environment variable. - Use kAudioDevicePropertyStreamFormatMatch to determine max channels. - 02.03.2003 - Phil Burk - always use AudioConverters so that we can adapt when format changes. - Synchronize with device when format changes. - 02.13.2003 - Phil Burk - scan for maxChannels because FormatMatch won't tell us. - 03.05.2003 - Phil Burk and Dominic Mazzoni - interleave and deinterleave multiple - CoreAudio buffers. Needed for MOTU828 and some other N>2 channel devices. - See code related to "streamInterleavingBuffer". - 03.06.2003 - Phil Burk and Ryan Francesconi - fixed numChannels query for MOTU828. - Handle fact that MOTU828 gives you 8 channels even when you ask for 2! - 04.06.2003 - Phil Burk - Combine Dominic Mazzoni's technique of using Configuration to query maxChannels - with old technique of scanning for mormat. - Increase channel scan by 1 to handle mono USB microphones. - Do not merge or split channels in AudioConverter to handle 2+2 channels - of Quattro which has a format of 2 channels. - 04.07.2003 - Phil Burk - use AudioGetCurrentHostTime instead of getrusage() which can lock threads. - 04.10.2003 - Phil Burk - fixed pointer bug with input deinterleaving loop. - Detect and ignore NULL inputData and outputData in CodeAudio callback. - Overlap creation and deletion of AudioConverters to prevent thread death when device rate changes. - 04.16.2003 - Phil Burk - Fixed input channel scrambling when numChannels != 2^N. Caused by alignment - error when filling RingBuffer with 2^N zero bytes. - 04.26.2003 - Phil Burk - Removed code to turn up volume and unmute to prevent blown eardrums. - 12.08.2003 - Phil Burk - Move declaration of oldConverter to top of PAOSX_DevicePropertyListener() - 12.08.2003 - Phil Burk - Removed need for #include "pa_trace.h", just for debug - 12.09.2003 - Phil Burk - Only change sampleRate or numChannels if we need to improve over - current setting. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "portaudio.h" -#include "pa_host.h" -#include "ringbuffer.h" - -/************************************************* Configuration ********/ -#define PA_ENABLE_LOAD_MEASUREMENT (1) - -/************************************************* Constants ********/ -#define SET_DEVICE_BUFFER_SIZE (1) - -/* To trace program, enable TRACE_REALTIME_EVENTS in pa_trace.h */ -#define PA_TRACE_RUN (0) -#define PA_TRACE_START_STOP (0) - -#define PA_MIN_LATENCY_MSEC (20) /* FIXME */ -#define MIN_TIMEOUT_MSEC (3000) - -#define PRINT(x) { printf x; fflush(stdout); } -#define PRINT_ERR( msg, err ) PRINT(( msg ": error = 0x%0lX = '%s'\n", (err), ErrorToString(err)) ) -#define DBUG(x) /* PRINT(x) */ -#define DBUGBACK(x) /* if( sMaxBackgroundErrorMessages-- > 0 ) PRINT(x) */ -#define DBUGX(x) - -// define value of isInput passed to CoreAudio routines -#define IS_INPUT (true) -#define IS_OUTPUT (false) - -typedef enum PaDeviceMode -{ - PA_MODE_OUTPUT_ONLY, - PA_MODE_INPUT_ONLY, - PA_MODE_IO_ONE_DEVICE, - PA_MODE_IO_TWO_DEVICES -} PaDeviceMode; - -#define PA_USING_OUTPUT (pahsc->mode != PA_MODE_INPUT_ONLY) -#define PA_USING_INPUT (pahsc->mode != PA_MODE_OUTPUT_ONLY) - -/************************************************************** - * Information needed by PortAudio specific to a CoreAudio device. - */ -typedef struct PaHostInOut_s -{ - AudioDeviceID audioDeviceID; /* CoreAudio specific ID */ - int bytesPerUserNativeBuffer; /* User buffer size in native host format. Depends on numChannels. */ - AudioConverterRef converter; - void *converterBuffer; - int numChannels; - /** Used for interleaving or de-interleaving multiple streams for devices like MOTU828. */ - int streamInterleavingBufferLen; /**< size in bytes */ - Float32 *streamInterleavingBuffer; -} PaHostInOut; - -/************************************************************** - * Structure for internal host specific stream data. - * This is allocated on a per stream basis. - */ -typedef struct PaHostSoundControl -{ - PaHostInOut input; - PaHostInOut output; - AudioDeviceID primaryDeviceID; - PaDeviceMode mode; - RingBuffer ringBuffer; - char *ringBufferData; - Boolean formatListenerCalled; - /* For measuring CPU utilization. */ - UInt64 entryTime; - double inverseHostTicksPerBuffer; /* 1/Ticks of real-time audio per user buffer. */ -} PaHostSoundControl; - -/************************************************************** - * Structure for internal extended device info query. - * There will be one or two PortAudio devices for each Core Audio device: - * one input and or one output. - */ -typedef struct PaHostDeviceInfo -{ - PaDeviceInfo paInfo; - AudioDeviceID audioDeviceID; -} -PaHostDeviceInfo; - -/************************************************* Shared Data ********/ -/* FIXME - put Mutex around this shared data. */ -static int sNumPaDevices = 0; /* Total number of PaDeviceInfos */ -static int sNumInputDevices = 0; /* Total number of input PaDeviceInfos */ -static int sNumOutputDevices = 0; -static int sNumCoreDevices = 0; -static AudioDeviceID *sCoreDeviceIDs; // Array of Core AudioDeviceIDs -static PaHostDeviceInfo *sDeviceInfos = NULL; -static int sDefaultInputDeviceID = paNoDevice; -static int sDefaultOutputDeviceID = paNoDevice; -static int sSavedHostError = 0; - -static const double supportedSampleRateRange[] = { 8000.0, 96000.0 }; /* FIXME - go to double HW rate. */ -static const char sMapperSuffixInput[] = " - Input"; -static const char sMapperSuffixOutput[] = " - Output"; - -/* Debug support. */ -//static int sMaxBackgroundErrorMessages = 100; -//static int sCoverageCounter = 1; // used to check code coverage during validation - -/* We index the input devices first, then the output devices. */ -#define LOWEST_INPUT_DEVID (0) -#define HIGHEST_INPUT_DEVID (sNumInputDevices - 1) -#define LOWEST_OUTPUT_DEVID (sNumInputDevices) -#define HIGHEST_OUTPUT_DEVID (sNumPaDevices - 1) - -/************************************************* Macros ********/ - -/************************************************* Prototypes **********/ - -static PaError PaOSX_QueryDevices( void ); -static int PaOSX_ScanDevices( Boolean isInput ); -static int PaOSX_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput ); -static PaDeviceID PaOSX_QueryDefaultInputDevice( void ); -static PaDeviceID PaOSX_QueryDefaultOutputDevice( void ); -static void PaOSX_CalcHostBufferSize( internalPortAudioStream *past ); - -static OSStatus PAOSX_DevicePropertyListener (AudioDeviceID inDevice, - UInt32 inChannel, - Boolean isInput, - AudioDevicePropertyID inPropertyID, - void* inClientData); - -/**********************************************************************/ -/* OS X errors are 4 character ID that can be printed. - * Note that uses a static pad so result must be printed immediately. - */ -static OSStatus statusText[2] = { 0, 0 }; -static const char *ErrorToString( OSStatus err ) -{ - const char *str; - - switch (err) - { - case kAudioHardwareUnspecifiedError: - str = "kAudioHardwareUnspecifiedError"; - break; - case kAudioHardwareNotRunningError: - str = "kAudioHardwareNotRunningError"; - break; - case kAudioHardwareUnknownPropertyError: - str = "kAudioHardwareUnknownPropertyError"; - break; - case kAudioDeviceUnsupportedFormatError: - str = "kAudioDeviceUnsupportedFormatError"; - break; - case kAudioHardwareBadPropertySizeError: - str = "kAudioHardwareBadPropertySizeError"; - break; - case kAudioHardwareIllegalOperationError: - str = "kAudioHardwareIllegalOperationError"; - break; - default: - statusText[0] = err; - str = (const char *)statusText; - break; - } - - return str; -} - -/**********************************************************************/ -static unsigned long RoundUpToNextPowerOf2( unsigned long n ) -{ - long numBits = 0; - if( ((n-1) & n) == 0) return n; /* Already Power of two. */ - while( n > 0 ) - { - n= n>>1; - numBits++; - } - return (1<past_DeviceData; - if( pahsc == NULL ) return; - /* Query user CPU timer for usage analysis and to prevent overuse of CPU. */ - pahsc->entryTime = AudioGetCurrentHostTime(); -} - -/****************************************************************************** -** Measure fractional CPU load based on real-time it took to calculate -** buffers worth of output. -*/ -static void Pa_EndUsageCalculation( internalPortAudioStream *past ) -{ - UInt64 exitTime; - UInt64 ticksElapsed; - double newUsage; - -#define LOWPASS_COEFFICIENT_0 (0.95) -#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0) - - PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData; - if( pahsc == NULL ) return; - - exitTime = AudioGetCurrentHostTime(); - - ticksElapsed = exitTime - pahsc->entryTime; - - /* Use inverse because it is faster than the divide. */ - newUsage = ticksElapsed * pahsc->inverseHostTicksPerBuffer; - /* Low pass filter result. */ - past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) + - (LOWPASS_COEFFICIENT_1 * newUsage); -} -/****************************************** END CPU UTILIZATION *******/ - -/************************************************************************/ -static PaDeviceID PaOSX_QueryDefaultInputDevice( void ) -{ - OSStatus err = noErr; - UInt32 count; - int i; - AudioDeviceID tempDeviceID = kAudioDeviceUnknown; - PaDeviceID defaultDeviceID = paNoDevice; - - // get the default output device for the HAL - // it is required to pass the size of the data to be returned - count = sizeof(tempDeviceID); - err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice, &count, (void *) &tempDeviceID); - if (err != noErr) goto error; - - // scan input devices to see which one matches this device - defaultDeviceID = paNoDevice; - for( i=LOWEST_INPUT_DEVID; i<=HIGHEST_INPUT_DEVID; i++ ) - { - DBUG(("PaOSX_QueryDefaultInputDevice: i = %d, aDevId = %ld\n", i, sDeviceInfos[i].audioDeviceID )); - if( sDeviceInfos[i].audioDeviceID == tempDeviceID ) - { - defaultDeviceID = i; - break; - } - } -error: - return defaultDeviceID; -} - -/************************************************************************/ -static PaDeviceID PaOSX_QueryDefaultOutputDevice( void ) -{ - OSStatus err = noErr; - UInt32 count; - int i; - AudioDeviceID tempDeviceID = kAudioDeviceUnknown; - PaDeviceID defaultDeviceID = paNoDevice; - - // get the default output device for the HAL - // it is required to pass the size of the data to be returned - count = sizeof(tempDeviceID); - err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) &tempDeviceID); - if (err != noErr) goto error; - - // scan output devices to see which one matches this device - defaultDeviceID = paNoDevice; - for( i=LOWEST_OUTPUT_DEVID; i<=HIGHEST_OUTPUT_DEVID; i++ ) - { - DBUG(("PaOSX_QueryDefaultOutputDevice: i = %d, aDevId = %ld\n", i, sDeviceInfos[i].audioDeviceID )); - if( sDeviceInfos[i].audioDeviceID == tempDeviceID ) - { - defaultDeviceID = i; - break; - } - } -error: - return defaultDeviceID; -} - -/******************************************************************/ -static PaError PaOSX_QueryDevices( void ) -{ - OSStatus err = noErr; - UInt32 outSize; - Boolean outWritable; - int numBytes; - - // find out how many Core Audio devices there are, if any - outSize = sizeof(outWritable); - err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &outSize, &outWritable); - if (err != noErr) - { - PRINT_ERR("Couldn't get info about list of audio devices", err); - sSavedHostError = err; - return paHostError; - } - - // calculate the number of device available - sNumCoreDevices = outSize / sizeof(AudioDeviceID); - - // Bail if there aren't any devices - if (sNumCoreDevices < 1) - { - PRINT(("No Devices Available")); - return paHostError; - } - - // make space for the devices we are about to get - sCoreDeviceIDs = (AudioDeviceID *)malloc(outSize); - - // get an array of AudioDeviceIDs - err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &outSize, (void *)sCoreDeviceIDs); - if (err != noErr) - { - PRINT_ERR("Couldn't get list of audio device IDs", err); - sSavedHostError = err; - return paHostError; - } - - // Allocate structures to hold device info pointers. - // There will be a maximum of two Pa devices per Core Audio device, input and/or output. - numBytes = sNumCoreDevices * 2 * sizeof(PaHostDeviceInfo); - sDeviceInfos = (PaHostDeviceInfo *) PaHost_AllocateFastMemory( numBytes ); - if( sDeviceInfos == NULL ) return paInsufficientMemory; - - // Scan all the Core Audio devices to see which support input and allocate a - // PaHostDeviceInfo structure for each one. - DBUG(("PaOSX_QueryDevices: scan for input ======================\n")); - PaOSX_ScanDevices( IS_INPUT ); - sNumInputDevices = sNumPaDevices; - // Now scan all the output devices. - DBUG(("PaOSX_QueryDevices: scan for output ======================\n")); - PaOSX_ScanDevices( IS_OUTPUT ); - sNumOutputDevices = sNumPaDevices - sNumInputDevices; - - // Figure out which of the devices that we scanned is the default device. - sDefaultInputDeviceID = PaOSX_QueryDefaultInputDevice(); - sDefaultOutputDeviceID = PaOSX_QueryDefaultOutputDevice(); - - return paNoError; -} - - -/*************************************************************************/ -/* Query a device for its sample rate. - * @return positive rate or 0.0 on error. - */ -static Float64 PaOSX_GetDeviceSampleRate( AudioDeviceID deviceID, Boolean isInput ) -{ - OSStatus err = noErr; - AudioStreamBasicDescription formatDesc; - UInt32 dataSize; - dataSize = sizeof(formatDesc); - err = AudioDeviceGetProperty( deviceID, 0, isInput, - kAudioDevicePropertyStreamFormat, &dataSize, &formatDesc); - if( err != noErr ) return 0.0; - else return formatDesc.mSampleRate; -} - -/*************************************************************************/ -/* Allocate a string containing the device name. */ -static char *PaOSX_DeviceNameFromID(AudioDeviceID deviceID, Boolean isInput ) -{ - OSStatus err = noErr; - UInt32 outSize; - Boolean outWritable; - char *deviceName = nil; - - // query size of name - err = AudioDeviceGetPropertyInfo(deviceID, 0, isInput, kAudioDevicePropertyDeviceName, &outSize, &outWritable); - if (err == noErr) - { - deviceName = (char*)malloc( outSize + 1); - if( deviceName ) - { - err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyDeviceName, &outSize, deviceName); - if (err != noErr) - PRINT_ERR("Couldn't get audio device name", err); - } - } - - return deviceName; -} - -/************************************************************************* -** Scan all of the Core Audio devices to see which support selected -** input or output mode. -** Changes sNumDevices, and fills in sDeviceInfos. -*/ -static int PaOSX_ScanDevices( Boolean isInput ) -{ - int coreDeviceIndex; - int result; - PaHostDeviceInfo *hostDeviceInfo; - int numAdded = 0; - - for( coreDeviceIndex=0; coreDeviceIndex 0 ) - { - sNumPaDevices += 1; // bump global counter if we got one - numAdded += 1; - } - else if( result < 0 ) return result; - } - return numAdded; -} - -/************************************************************************* -** Determine the maximum number of channels based on the configuration. -** @return maxChannels or negative error. -*/ -static int PaOSX_GetMaxChannels_Config( AudioDeviceID devID, Boolean isInput ) -{ - OSStatus err; - UInt32 outSize; - Boolean outWritable; - AudioBufferList *list; - int numChannels; - int i; - - // Determine maximum number of channels supported. - // dmazzoni: new method - - outSize = 0; - err = AudioDeviceGetPropertyInfo(devID, 0, isInput, - kAudioDevicePropertyStreamConfiguration, - &outSize, &outWritable); - if ( err != noErr ) - { - PRINT_ERR("PaOSX_GetMaxChannels_Config: Could not get stream configuration info", err); - sSavedHostError = err; - return paHostError; - } - - list = (AudioBufferList *)PaHost_AllocateFastMemory( outSize ); - err = AudioDeviceGetProperty(devID, 0, isInput, - kAudioDevicePropertyStreamConfiguration, - &outSize, list); - if ( err != noErr ) - { - PRINT_ERR("PaOSX_GetMaxChannels_Config: Could not get stream configuration", err); - sSavedHostError = err; - return paHostError; - } - - numChannels = 0; - for( i=0; imNumberBuffers; i++ ) - { - int bufChannels = list->mBuffers[i].mNumberChannels; - DBUG(("PaOSX_GetMaxChannels_Config: buffer %d has %d channels.\n", i, bufChannels )); - numChannels += bufChannels; - } - - PaHost_FreeFastMemory( list, outSize ); - - return numChannels; -} - -/************************************************************************* -** Determine the maximum number of channels a device will support based on scanning the format. -** @return maxChannels or negative error. -*/ -static int PaOSX_GetMaxChannels_Format( AudioDeviceID devID, Boolean isInput ) -{ - OSStatus err; - UInt32 outSize; - AudioStreamBasicDescription formatDesc; - int maxChannels; - int numChannels; - Boolean gotMax; - - // Scan to find highest matching format. - // Unfortunately some devices won't just return maxChannels for the match. - // For example, some 8 channel devices return 2 when given 256 as input. - gotMax = false; - maxChannels = 0; - numChannels = 0; - while( !gotMax ) - { - - memset( &formatDesc, 0, sizeof(formatDesc)); - numChannels = numChannels + 1; - DBUG(("PaOSX_GetMaxChannels: try numChannels = %d = %d + 1\n", - numChannels, numChannels )); - formatDesc.mChannelsPerFrame = numChannels; - outSize = sizeof(formatDesc); - - err = AudioDeviceGetProperty( devID, 0, - isInput, kAudioDevicePropertyStreamFormatMatch, &outSize, &formatDesc); - - DBUG(("PaOSX_GetMaxChannels: err 0x%0x, formatDesc.mChannelsPerFrame= %d\n", - err, formatDesc.mChannelsPerFrame )); - if( err != noErr ) - { - if (numChannels > (maxChannels + 4)) // Try several possibilities above current max - { - gotMax = true; - } - } - else - { - // This value worked so we have a new candidate for maxChannels. - if (formatDesc.mChannelsPerFrame > numChannels) - { - maxChannels = formatDesc.mChannelsPerFrame; - } - else if(formatDesc.mChannelsPerFrame < numChannels) - { - if (numChannels > (maxChannels + 4)) // Try several possibilities above current max - { - gotMax = true; - } - } - else - { - maxChannels = numChannels; - } - } - } - return maxChannels; -} - - - -/************************************************************************* -** Determine the maximum number of channels a device will support. -** It is not clear at this point which the better technique so -** we do both and use the biggest result. -** -** @return maxChannels or negative error. -*/ -static int PaOSX_GetMaxChannels( AudioDeviceID devID, Boolean isInput ) -{ - int maxChannelsFormat; - int maxChannelsConfig; - maxChannelsFormat = PaOSX_GetMaxChannels_Format( devID, isInput ); - maxChannelsConfig = PaOSX_GetMaxChannels_Config( devID, isInput ); - return (maxChannelsFormat > maxChannelsConfig) ? maxChannelsFormat : maxChannelsConfig; -} - -/************************************************************************* -** 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. */ - 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; imNumberBuffers; 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; jinput.streamInterleavingBuffer[ currentInterleavedChannelIndex ]; - float *src = &((float *)inInputData->mBuffers[i].mData)[ j ]; - /* Move one channel from CoreAudio buffer to interleaved buffer. */ - for( k=0; kinput.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; - int numChannelsRemaining; - Boolean deinterleavingNeeded; - int numFramesInOutputBuffer; - - if( outOutputData == NULL ) - { - DBUG(("PaOSX_HandleOutput: outOutputData == NULL\n")); - return noErr; - } - - deinterleavingNeeded = past->past_NumOutputChannels != outOutputData->mBuffers[0].mNumberChannels; - - numFramesInOutputBuffer = outOutputData->mBuffers[0].mDataByteSize / - (sizeof(float) * outOutputData->mBuffers[0].mNumberChannels); - - if( pahsc->mode != PA_MODE_INPUT_ONLY ) - { - /* If we are using output, then we need an empty output buffer. */ - if( outOutputData->mNumberBuffers > 0 ) - { - - /* If we have multiple CoreAudio buffers, then we will need to deinterleave after conversion. */ - if( deinterleavingNeeded ) - { - numBytes = numFramesInOutputBuffer * sizeof(float) * past->past_NumOutputChannels; - - /* Free old buffer if we are allocating new one. */ - if ( (pahsc->output.streamInterleavingBuffer != NULL) && - (pahsc->output.streamInterleavingBufferLen < numBytes) ) - { - PaHost_FreeFastMemory( pahsc->output.streamInterleavingBuffer, pahsc->output.streamInterleavingBufferLen ); - pahsc->output.streamInterleavingBuffer = NULL; - } - /* Allocate interleaving buffer if needed. */ - if ( pahsc->output.streamInterleavingBuffer == NULL ) - { - pahsc->output.streamInterleavingBufferLen = numBytes; - pahsc->output.streamInterleavingBuffer = (float *)PaHost_AllocateFastMemory( pahsc->output.streamInterleavingBufferLen ); - } - - outputNativeBufferfPtr = (void*)pahsc->output.streamInterleavingBuffer; - } - else - { - numBytes = outOutputData->mBuffers[0].mDataByteSize; - outputNativeBufferfPtr = (void*)outOutputData->mBuffers[0].mData; - } - - /* Pull data from PA user through converter. */ - err = AudioConverterFillBuffer( - pahsc->output.converter, - PaOSX_OutputConverterCallbackProc, - past, - &numBytes, - outputNativeBufferfPtr); - if( err != noErr ) - { - PRINT_ERR("PaOSX_HandleOutput: AudioConverterFillBuffer failed", err); - goto error; - } - - /* Deinterleave data from PortAudio and write to multiple CoreAudio buffers. */ - if( deinterleavingNeeded ) - { - int numInterleavedChannels = past->past_NumOutputChannels; - int i, currentInterleavedChannelIndex = 0; - numChannelsRemaining = numInterleavedChannels; - - for( i=0; imNumberBuffers; i++ ) - { - int numBufChannels = outOutputData->mBuffers[i].mNumberChannels; - int j; - /* Don't use more than we need or more than we have. */ - int numChannelsUsedInThisBuffer = (numChannelsRemaining < numBufChannels ) ? - numChannelsRemaining : numBufChannels; - - for( j=0; jmBuffers[i].mData)[ j ]; - float *src = &pahsc->output.streamInterleavingBuffer[ currentInterleavedChannelIndex ]; - /* Move one channel from interleaved buffer to CoreAudio buffer. */ - for( k=0; kpast_DeviceData; - - /* If there is a FIFO for input then write to it. */ - if( (pahsc->ringBufferData != NULL) && (inInputData != NULL) ) - { - err = PaOSX_WriteInputRingBuffer( past, inInputData ); - if( err != noErr ) goto error; - } -error: - return err; -} - -/****************************************************************** - * This is the primary callback for CoreAudio. - * It can handle input and/or output for a single device. - * It takes input from CoreAudio, converts it and passes it to the - * PortAudio user callback. Then takes the PA results and passes it - * back to CoreAudio. - */ -static OSStatus PaOSX_CoreAudioIOCallback (AudioDeviceID inDevice, const AudioTimeStamp* inNow, - const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, - AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, - void* contextPtr) -{ - OSStatus err = noErr; - internalPortAudioStream *past; - PaHostSoundControl *pahsc; - past = (internalPortAudioStream *) contextPtr; - pahsc = (PaHostSoundControl *) past->past_DeviceData; - - /* 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. Should wait for audio to play out but CoreAudio latency very low. - 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; - } - else if( inInputTime->mFlags & kAudioTimeStampSampleTimeValid) - { - past->past_FrameCount = inInputTime->mSampleTime; - } - - past->past_NumCallbacks += 1; - - /* Process full input buffer. */ - err = PaOSX_HandleInput( past, inInputData ); - if( err != 0 ) goto error; - - /* Fill up empty output buffers. */ - err = PaOSX_HandleOutput( past, outOutputData ); - if( err != 0 ) goto error; - } - - if( err != 0 ) DBUG(("PaOSX_CoreAudioIOCallback: returns %ld.\n", err )); - -error: - return err; -} - -/*******************************************************************/ -/** Attempt to set device sample rate. - * This is not critical because we use an AudioConverter but we may - * get better fidelity if we can avoid resampling. - * - * Only set format once because some devices take time to settle. - * Return flag indicating whether format changed so we know whether to wait - * for DevicePropertyListener to get called. - * - * @return negative error, zero if no change, or one if changed successfully. - */ -static PaError PaOSX_SetFormat( AudioDeviceID devID, Boolean isInput, - double desiredRate, int desiredNumChannels ) -{ - AudioStreamBasicDescription formatDesc; - PaError result = 0; - OSStatus err; - UInt32 dataSize; - Float64 originalRate; - int originalChannels; - - /* Get current device format. This is critical because if we pass - * zeros for unspecified fields then the iMic device gets switched to a 16 bit - * integer format!!! I don't know if this is a Mac bug or not. But it only - * started happening when I upgraded from OS X V10.1 to V10.2 (Jaguar). - */ - dataSize = sizeof(formatDesc); - err = AudioDeviceGetProperty( devID, 0, isInput, - kAudioDevicePropertyStreamFormat, &dataSize, &formatDesc); - if( err != noErr ) - { - PRINT_ERR("PaOSX_SetFormat: Could not get format.", err); - sSavedHostError = err; - return paHostError; - } - - originalRate = formatDesc.mSampleRate; - originalChannels = formatDesc.mChannelsPerFrame; - - // Changing the format can mess up other apps. - // So only change the format if the original format - // has a lower sample rate, or fewer channels, than the desired format. - if( (originalRate < desiredRate) || (originalChannels < desiredNumChannels) ) - { - DBUG(("PaOSX_SetFormat: try to change sample rate from %f to %f.\n", originalRate, desiredRate )); - DBUG(("PaOSX_SetFormat: try to set number of channels %d to %d\n", originalChannels, desiredNumChannels)); - - formatDesc.mSampleRate = desiredRate; - formatDesc.mChannelsPerFrame = desiredNumChannels; - formatDesc.mBytesPerFrame = formatDesc.mChannelsPerFrame * sizeof(float); - formatDesc.mBytesPerPacket = formatDesc.mBytesPerFrame * formatDesc.mFramesPerPacket; - - err = AudioDeviceSetProperty( devID, 0, 0, - isInput, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); - if (err != noErr) - { - /* Could not set to desired rate so query for closest match. */ - dataSize = sizeof(formatDesc); - err = AudioDeviceGetProperty( devID, 0, - isInput, kAudioDevicePropertyStreamFormatMatch, &dataSize, &formatDesc); - - DBUG(("PaOSX_SetFormat: closest rate is %f.\n", formatDesc.mSampleRate )); - DBUG(("PaOSX_SetFormat: closest numChannels is %d.\n", (int)formatDesc.mChannelsPerFrame )); - // Set to closest if different from original. - if( (err == noErr) && - ((originalRate != formatDesc.mSampleRate) || - (originalChannels != formatDesc.mChannelsPerFrame)) ) - { - err = AudioDeviceSetProperty( devID, 0, 0, - isInput, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc); - if( err == noErr ) result = 1; - } - } - else result = 1; - } - - return result; -} - -#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; - AudioConverterRef oldConverter = NULL; // PLB 20031208 - Declare here for standard 'C'. - - 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. - 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; - - - // 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( 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_FramesPerUserBuffer, etc. -* Sets: -* past->past_NumUserBuffers -* pahsc->input.bytesPerUserNativeBuffer -* pahsc->output.bytesPerUserNativeBuffer -*/ -static void PaOSX_CalcHostBufferSize( internalPortAudioStream *past ) -{ - PaHostSoundControl *pahsc = ( PaHostSoundControl *)past->past_DeviceData; - - // Determine number of user buffers based strictly on minimum reasonable buffer size. - // We ignore the Pa_OpenStream numBuffer parameter because CoreAudio has a big - // mix buffer and handles latency automatically. - past->past_NumUserBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); - - // calculate buffer sizes in bytes - pahsc->input.bytesPerUserNativeBuffer = past->past_FramesPerUserBuffer * - Pa_GetSampleSize(paFloat32) * past->past_NumInputChannels; - pahsc->output.bytesPerUserNativeBuffer = past->past_FramesPerUserBuffer * - Pa_GetSampleSize(paFloat32) * past->past_NumOutputChannels; - - DBUG(("PaOSX_CalcNumHostBuffers: past_NumUserBuffers = %ld\n", past->past_NumUserBuffers )); - DBUG(("PaOSX_CalcNumHostBuffers: input.bytesPerUserNativeBuffer = %d\n", pahsc->input.bytesPerUserNativeBuffer )); - DBUG(("PaOSX_CalcNumHostBuffers: output.bytesPerUserNativeBuffer = %d\n", pahsc->output.bytesPerUserNativeBuffer )); -} - -/*****************************************************************************/ -/************** Internal Host API ********************************************/ -/*****************************************************************************/ -PaError PaHost_OpenStream( internalPortAudioStream *past ) -{ - PaError result = paNoError; - PaHostSoundControl *pahsc; - Boolean useInput; - Boolean useOutput; - - assert( past->past_Magic == PA_MAGIC ); - - /* 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; - pahsc->primaryDeviceID = kAudioDeviceUnknown; - pahsc->input.audioDeviceID = kAudioDeviceUnknown; - pahsc->output.audioDeviceID = kAudioDeviceUnknown; - - PaOSX_CalcHostBufferSize( past ); - - useOutput = (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0); - useInput = (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0); - - // Set device IDs and determine IO Device mode. - if( useOutput ) - { - pahsc->output.audioDeviceID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID; - pahsc->primaryDeviceID = pahsc->output.audioDeviceID; - if( useInput ) - { - pahsc->input.audioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID; - pahsc->mode = ( pahsc->input.audioDeviceID != pahsc->primaryDeviceID ) ? - PA_MODE_IO_TWO_DEVICES : PA_MODE_IO_ONE_DEVICE; - } - else - { - pahsc->mode = PA_MODE_OUTPUT_ONLY; - } - } - else - { - /* Just input, not output. */ - pahsc->input.audioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID; - pahsc->primaryDeviceID = pahsc->input.audioDeviceID; - pahsc->mode = PA_MODE_INPUT_ONLY; - } - - DBUG(("outputDeviceID = %ld\n", pahsc->output.audioDeviceID )); - DBUG(("inputDeviceID = %ld\n", pahsc->input.audioDeviceID )); - DBUG(("primaryDeviceID = %ld\n", pahsc->primaryDeviceID )); - - /* ------------------ OUTPUT */ - if( useOutput ) - { - result = PaOSX_OpenOutputDevice( past ); - if( result < 0 ) goto error; - } - - /* ------------------ INPUT */ - if( useInput ) - { - result = PaOSX_OpenInputDevice( past ); - if( result < 0 ) goto error; - } - -#if PA_ENABLE_LOAD_MEASUREMENT - pahsc->inverseHostTicksPerBuffer = past->past_SampleRate / - (AudioGetHostClockFrequency() * past->past_FramesPerUserBuffer); - DBUG(("inverseHostTicksPerBuffer based on buffer size of %d frames.\n", past->past_FramesPerUserBuffer )); -#else - PRINT(("WARNING - Pa_GetCPULoad() mesaurement disabled in pa_mac_core.c.\n")); -#endif - - 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; - -/* If full duplex and using two separate devices then start input device. */ - if( pahsc->mode == PA_MODE_IO_TWO_DEVICES ) - { - // Associate an IO proc with the device and pass a pointer to the audio data context - err = AudioDeviceAddIOProc(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback, past); - if (err != noErr) - { - PRINT_ERR("PaHost_StartEngine: AudioDeviceAddIOProc secondary failed", err ); - goto error; - } - - // start playing sound through the device - err = AudioDeviceStart(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback); - if (err != noErr) - { - PRINT_ERR("PaHost_StartEngine: AudioDeviceStart secondary failed", err ); - PRINT(("The program may succeed if you run it again!\n")); - goto error; - } - } - - // Associate an IO proc with the device and pass a pointer to the audio data context - err = AudioDeviceAddIOProc(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback, past); - if (err != noErr) - { - PRINT_ERR("PaHost_StartEngine: AudioDeviceAddIOProc primary failed", err ); - goto error; - } - - // start playing sound through the device - err = AudioDeviceStart(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback); - if (err != noErr) - { - PRINT_ERR("PaHost_StartEngine: AudioDeviceStart primary failed", err ); - PRINT(("The program may succeed if you run it again!\n")); - goto error; - } - - return result; - -error: - sSavedHostError = err; - return paHostError; -} - -/*************************************************************************/ -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->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback); - if (err != noErr) - { - goto error; - } - - err = AudioDeviceRemoveIOProc(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback); - if (err != noErr) goto error; - -/* If full duplex and using two separate devices then stop second input device. */ - if( pahsc->mode == PA_MODE_IO_TWO_DEVICES ) - { - err = AudioDeviceStop(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback); - if (err != noErr) goto error; - err = AudioDeviceRemoveIOProc(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback); - if (err != noErr) goto error; - } - - return paNoError; - -error: - sSavedHostError = err; - return paHostError; -} - -/*************************************************************************/ -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; - - //PaOSX_DumpDeviceInfo( sDeviceInfos[past->past_OutputDeviceID].audioDeviceID, IS_OUTPUT ); - -#if PA_TRACE_START_STOP - AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut ); -#endif - // Stop Listener callbacks ASAP before dismantling stream. - if( PA_USING_INPUT ) - { - AudioDeviceRemovePropertyListener( pahsc->input.audioDeviceID, 0, IS_INPUT, - kAudioDevicePropertyStreamFormat, - (AudioDevicePropertyListenerProc) PAOSX_DevicePropertyListener ); - } - - if( PA_USING_OUTPUT ) - { - AudioDeviceRemovePropertyListener( pahsc->output.audioDeviceID, 0, IS_OUTPUT, - kAudioDevicePropertyStreamFormat, - (AudioDevicePropertyListenerProc) PAOSX_DevicePropertyListener ); - } - - if( pahsc->output.converterBuffer != NULL ) - { - PaHost_FreeFastMemory( pahsc->output.converterBuffer, pahsc->output.bytesPerUserNativeBuffer ); - } - if( pahsc->input.converterBuffer != NULL ) - { - PaHost_FreeFastMemory( pahsc->input.converterBuffer, pahsc->input.bytesPerUserNativeBuffer ); - } - if( pahsc->ringBufferData != NULL ) - { - PaHost_FreeFastMemory( pahsc->ringBufferData, pahsc->ringBuffer.bufferSize ); - } - if( pahsc->output.converter != NULL ) - { - verify_noerr(AudioConverterDispose (pahsc->output.converter)); - } - if( pahsc->input.converter != NULL ) - { - verify_noerr(AudioConverterDispose (pahsc->input.converter)); - } - if ( pahsc->input.streamInterleavingBuffer != NULL ) - { - PaHost_FreeFastMemory( pahsc->input.streamInterleavingBuffer, pahsc->input.streamInterleavingBufferLen ); - } - if ( pahsc->output.streamInterleavingBuffer != NULL ) - { - PaHost_FreeFastMemory( pahsc->output.streamInterleavingBuffer, pahsc->output.streamInterleavingBufferLen ); - } - - free( pahsc ); - past->past_DeviceData = NULL; - - return paNoError; -} - -/********************************************************************** -** Initialize Host dependant part of API. -*/ -PaError PaHost_Init( void ) -{ - return PaOSX_MaybeQueryDevices(); -} - -/************************************************************************* -** Cleanup device info. -*/ -PaError PaHost_Term( void ) -{ - int i; - - if( sDeviceInfos != NULL ) - { - for( i=0; ipast_DeviceData; - if( pahsc == NULL ) return paInternalError; - return (PaError) past->past_IsActive; -} - -/*****************************************************************************/ -/************** External User API ********************************************/ -/*****************************************************************************/ - -/********************************************************************** -** Query devices and use result. -*/ -PaDeviceID Pa_GetDefaultInputDeviceID( void ) -{ - PaError result = PaOSX_MaybeQueryDevices(); - if( result < 0 ) return result; - return sDefaultInputDeviceID; -} - -PaDeviceID Pa_GetDefaultOutputDeviceID( void ) -{ - PaError result = PaOSX_MaybeQueryDevices(); - if( result < 0 ) return result; - return sDefaultOutputDeviceID; -} - - -/************************************************************************* -** Determine minimum number of buffers required for this host based -** on minimum latency. Because CoreAudio manages latency, this just selects -** a reasonably small number of buffers. -*/ -int Pa_GetMinNumBuffers( int framesPerBuffer, double framesPerSecond ) -{ - int minBuffers; - double denominator; - int minLatencyMsec = PA_MIN_LATENCY_MSEC; - denominator = 1000.0 * framesPerBuffer; - minBuffers = (int) (((minLatencyMsec * framesPerSecond) + denominator - 1) / denominator ); - if( minBuffers < 1 ) minBuffers = 1; - return minBuffers; -} - -/*************************************************************************/ -void Pa_Sleep( long msec ) -{ - usleep( msec * 1000 ); -} - -/*************************************************************************/ -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->primaryDeviceID, &timeStamp); - - streamTime = ( timeStamp.mFlags & kAudioTimeStampSampleTimeValid) ? - timeStamp.mSampleTime : past->past_FrameCount; - - return streamTime; -} - -/************************************************************************************/ -long Pa_GetHostError() -{ - return sSavedHostError; -} - -/*************************************************************************/ -int Pa_CountDevices() -{ - if( sNumPaDevices <= 0 ) Pa_Initialize(); - return sNumPaDevices; -} - -/************************************************************************* -** PaDeviceInfo structures have already been created -** so just return the pointer. -** -*/ -const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id ) -{ - if( id < 0 || id >= sNumPaDevices ) - return NULL; - - return &sDeviceInfos[id].paInfo; -} - - -- cgit v1.2.1