📄 pa_mac_core.c
字号:
/* * Implementation of the PortAudio API for Apple AUHAL * * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code. * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation) * * Dominic's code was based on code by Phil Burk, Darren Gibbs, * Gord Peters, Stephane Letz, and Greg Pfiel. * * The following people also deserve acknowledgements: * * Olivier Tristan for feedback and testing * Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O * interface. * * * Based on the Open Source API proposed by Ross Bencina * Copyright (c) 1999-2002 Ross Bencina, Phil Burk * * 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. * * 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. *//* * The text above constitutes the entire PortAudio license; however, * the PortAudio community also makes the following non-binding requests: * * 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. It is also * requested that these non-binding requests be included along with the * license above. *//** @file pa_mac_core @ingroup hostapi_src @author Bjorn Roche @brief AUHAL implementation of PortAudio*//* FIXME: not all error conditions call PaUtil_SetLastHostErrorInfo() * PaMacCore_SetError() will do this. */#include "pa_mac_core_internal.h"#include <string.h> /* strlen(), memcmp() etc. */#include "pa_mac_core.h"#include "pa_mac_core_utilities.h"#include "pa_mac_core_blocking.h"#ifdef __cplusplusextern "C"{#endif /* __cplusplus *//* prototypes for functions declared in this file */PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );/* * Function declared in pa_mac_core.h. Sets up a PaMacCoreStreamInfoStruct * with the requested flags and initializes channel map. */void PaMacCore_SetupStreamInfo( PaMacCoreStreamInfo *data, const unsigned long flags ){ bzero( data, sizeof( PaMacCoreStreamInfo ) ); data->size = sizeof( PaMacCoreStreamInfo ); data->hostApiType = paCoreAudio; data->version = 0x01; data->flags = flags; data->channelMap = NULL; data->channelMapSize = 0;}/* * Function declared in pa_mac_core.h. Adds channel mapping to a PaMacCoreStreamInfoStruct */void PaMacCore_SetupChannelMap( PaMacCoreStreamInfo *data, const long * const channelMap, const unsigned long channelMapSize ){ data->channelMap = channelMap; data->channelMapSize = channelMapSize;}static char *channelName = NULL;static int channelNameSize = 0;static bool ensureChannelNameSize( int size ){ if( size >= channelNameSize ) { free( channelName ); channelName = (char *) malloc( ( channelNameSize = size ) + 1 ); if( !channelName ) { channelNameSize = 0; return false; } } return true;}/* * Function declared in pa_mac_core.h. retrives channel names. */const char *PaMacCore_GetChannelName( int device, int channelIndex, bool input ){ struct PaUtilHostApiRepresentation *hostApi; PaError err; OSStatus error; err = PaUtil_GetHostApiRepresentation( &hostApi, paCoreAudio ); assert(err == paNoError); PaMacAUHAL *macCoreHostApi = (PaMacAUHAL*)hostApi; AudioDeviceID hostApiDevice = macCoreHostApi->devIds[device]; UInt32 size = 0; error = AudioDeviceGetPropertyInfo( hostApiDevice, channelIndex + 1, input, kAudioDevicePropertyChannelName, &size, NULL ); if( error ) { //try the CFString CFStringRef name; bool isDeviceName = false; size = sizeof( name ); error = AudioDeviceGetProperty( hostApiDevice, channelIndex + 1, input, kAudioDevicePropertyChannelNameCFString, &size, &name ); if( error ) { //as a last-ditch effort, get the device name. Later we'll append the channel number. size = sizeof( name ); error = AudioDeviceGetProperty( hostApiDevice, channelIndex + 1, input, kAudioDevicePropertyDeviceNameCFString, &size, &name ); if( error ) return NULL; isDeviceName = true; } if( isDeviceName ) { name = CFStringCreateWithFormat( NULL, NULL, CFSTR( "%@: %d"), name, channelIndex + 1 ); } CFIndex length = CFStringGetLength(name); while( ensureChannelNameSize( length * sizeof(UniChar) + 1 ) ) { if( CFStringGetCString( name, channelName, channelNameSize, kCFStringEncodingUTF8 ) ) { if( isDeviceName ) CFRelease( name ); return channelName; } if( length == 0 ) ++length; length *= 2; } if( isDeviceName ) CFRelease( name ); return NULL; } //continue with C string: if( !ensureChannelNameSize( size ) ) return NULL; error = AudioDeviceGetProperty( hostApiDevice, channelIndex + 1, input, kAudioDevicePropertyChannelName, &size, channelName ); if( error ) { ERR( error ); return NULL; } return channelName;}AudioDeviceID PaMacCore_GetStreamInputDevice( PaStream* s ){ PaMacCoreStream *stream = (PaMacCoreStream*)s; VVDBUG(("PaMacCore_GetStreamInputHandle()\n")); return ( stream->inputDevice );}AudioDeviceID PaMacCore_GetStreamOutputDevice( PaStream* s ){ PaMacCoreStream *stream = (PaMacCoreStream*)s; VVDBUG(("PaMacCore_GetStreamOutputHandle()\n")); return ( stream->outputDevice );}#ifdef __cplusplus}#endif /* __cplusplus */#define RING_BUFFER_ADVANCE_DENOMINATOR (4)static void Terminate( struct PaUtilHostApiRepresentation *hostApi );static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate );static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, PaStream** s, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData );static PaError CloseStream( PaStream* stream );static PaError StartStream( PaStream *stream );static PaError StopStream( PaStream *stream );static PaError AbortStream( PaStream *stream );static PaError IsStreamStopped( PaStream *s );static PaError IsStreamActive( PaStream *stream );static PaTime GetStreamTime( PaStream *stream );static void setStreamStartTime( PaStream *stream );static OSStatus AudioIOProc( void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData );static double GetStreamCpuLoad( PaStream* stream );static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi, PaDeviceInfo *deviceInfo, AudioDeviceID macCoreDeviceId, int isInput);static PaError OpenAndSetupOneAudioUnit( const PaStreamParameters *inStreamParams, const PaStreamParameters *outStreamParams, const unsigned long requestedFramesPerBuffer, unsigned long *actualInputFramesPerBuffer, unsigned long *actualOutputFramesPerBuffer, const PaMacAUHAL *auhalHostApi, AudioUnit *audioUnit, AudioConverterRef *srConverter, AudioDeviceID *audioDevice, const double sampleRate, void *refCon );/* for setting errors. */#define PA_AUHAL_SET_LAST_HOST_ERROR( errorCode, errorText ) \ PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )/*currently, this is only used in initialization, but it might be modified to be used when the list of devices changes.*/static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi){ UInt32 size; UInt32 propsize; VVDBUG(("gatherDeviceInfo()\n")); /* -- free any previous allocations -- */ if( auhalHostApi->devIds ) PaUtil_GroupFreeMemory(auhalHostApi->allocations, auhalHostApi->devIds); auhalHostApi->devIds = NULL; /* -- figure out how many devices there are -- */ AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices, &propsize, NULL ); auhalHostApi->devCount = propsize / sizeof( AudioDeviceID ); VDBUG( ( "Found %ld device(s).\n", auhalHostApi->devCount ) ); /* -- copy the device IDs -- */ auhalHostApi->devIds = (AudioDeviceID *)PaUtil_GroupAllocateMemory( auhalHostApi->allocations, propsize ); if( !auhalHostApi->devIds ) return paInsufficientMemory; AudioHardwareGetProperty( kAudioHardwarePropertyDevices, &propsize, auhalHostApi->devIds );#ifdef MAC_CORE_VERBOSE_DEBUG { int i; for( i=0; i<auhalHostApi->devCount; ++i ) printf( "Device %d\t: %ld\n", i, auhalHostApi->devIds[i] ); }#endif size = sizeof(AudioDeviceID); auhalHostApi->defaultIn = kAudioDeviceUnknown; auhalHostApi->defaultOut = kAudioDeviceUnknown; /* determine the default device. */ /* I am not sure how these calls to AudioHardwareGetProperty() could fail, but in case they do, we use the first available device as the default. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -