📄 pa_linux_asihpi.c
字号:
CallbackFinished => HPI_STATE_STOPPED, HPI_STATE_DRAINED */typedef enum PaAsiHpiStreamState{ paAsiHpiStoppedState=0, paAsiHpiActiveState=1, paAsiHpiCallbackFinishedState=2}PaAsiHpiStreamState;/** Stream component data (associated with one direction, i.e. either input or output) */typedef struct PaAsiHpiStreamComponent{ /** Device information (HPI handles, etc) */ PaAsiHpiDeviceInfo *hpiDevice; /** Stream handle, as passed to HPI interface. HACK: we assume types HPI_HISTREAM and HPI_HOSTREAM are the same... (both are HW32 up to version 3.00 of ASIHPI, and hopefully they stay that way) */ HPI_HISTREAM hpiStream; /** Stream format, as passed to HPI interface */ HPI_FORMAT hpiFormat; /** Number of bytes per frame, derived from hpiFormat and saved for convenience */ HW32 bytesPerFrame; /** Size of hardware (on-card) buffer of stream in bytes */ HW32 hardwareBufferSize; /** Size of host (BBM) buffer of stream in bytes (if used) */ HW32 hostBufferSize; /** Upper limit on the utilization of output stream buffer (both hardware and host). This prevents large latencies in an output-only stream with a potentially huge buffer and a fast data generator, which would otherwise keep the hardware buffer filled to capacity. See also the "Hardware Buffering=off" option in the AudioScience WAV driver. */ HW32 outputBufferCap; /** Sample buffer (halfway station between HPI and buffer processor) */ HW8 *tempBuffer; /** Sample buffer size, in bytes */ HW32 tempBufferSize;}PaAsiHpiStreamComponent;/** Stream data */typedef struct PaAsiHpiStream{ /* PortAudio "base class" - keep the baseRep first! (C-style inheritance) */ PaUtilStreamRepresentation baseStreamRep; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaUtilBufferProcessor bufferProcessor; PaUtilAllocationGroup *allocations; /* implementation specific data goes here */ /** Separate structs for input and output sides of stream */ PaAsiHpiStreamComponent *input, *output; /** Polling interval (in milliseconds) */ HW32 pollingInterval; /** Are we running in callback mode? */ int callbackMode; /** Number of frames to transfer at a time to/from HPI */ unsigned long maxFramesPerHostBuffer; /** Indicates that the stream is in the paNeverDropInput mode */ int neverDropInput; /** Contains copy of user buffers, used by blocking interface to transfer non-interleaved data. It went here instead of to each stream component, as the stream component buffer setup in PaAsiHpi_SetupBuffers doesn't know the stream details such as callbackMode. (Maybe a problem later if ReadStream and WriteStream happens concurrently on same stream.) */ void **blockingUserBufferCopy; /* Thread-related variables */ /** Helper thread which will deliver data to user callback */ PaUnixThread thread; /** PortAudio stream state (Active/Stopped/CallbackFinished) */ volatile sig_atomic_t state; /** Hard abort, i.e. drop frames? */ volatile sig_atomic_t callbackAbort; /** True if stream stopped via exiting callback with paComplete/paAbort flag (as opposed to explicit call to StopStream/AbortStream) */ volatile sig_atomic_t callbackFinished;}PaAsiHpiStream;/** Stream state information, collected together for convenience */typedef struct PaAsiHpiStreamInfo{ /** HPI stream state (HPI_STATE_STOPPED, HPI_STATE_PLAYING, etc.) */ HW16 state; /** Size (in bytes) of recording/playback data buffer in HPI driver */ HW32 bufferSize; /** Amount of data (in bytes) available in the buffer */ HW32 dataSize; /** Number of frames played/recorded since last stream reset */ HW32 frameCounter; /** Amount of data (in bytes) in hardware (on-card) buffer. This differs from dataSize if bus mastering (BBM) is used, which introduces another driver-level buffer to which dataSize/bufferSize then refers. */ HW32 auxDataSize; /** Total number of data frames currently buffered by HPI driver (host + hw buffers) */ HW32 totalBufferedData; /** Size of immediately available data (for input) or space (for output) in frames. This only checks the first-level buffer (typically host buffer). This amount can be transferred immediately. */ HW32 availableFrames; /** Indicates that hardware buffer is getting too full */ int overflow; /** Indicates that hardware buffer is getting too empty */ int underflow;}PaAsiHpiStreamInfo;/* -------------------------------------------------------------------------- *//* * Function prototypes */#ifdef __cplusplusextern "C"{#endif /* __cplusplus */ /* The only exposed function in the entire host API implementation */ PaError PaAsiHpi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );#ifdef __cplusplus}#endif /* __cplusplus */static void Terminate( struct PaUtilHostApiRepresentation *hostApi );static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate );/* Stream prototypes */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 *s );static PaError StartStream( PaStream *s );static PaError StopStream( PaStream *s );static PaError AbortStream( PaStream *s );static PaError IsStreamStopped( PaStream *s );static PaError IsStreamActive( PaStream *s );static PaTime GetStreamTime( PaStream *s );static double GetStreamCpuLoad( PaStream *s );/* Blocking prototypes */static PaError ReadStream( PaStream *s, void *buffer, unsigned long frames );static PaError WriteStream( PaStream *s, const void *buffer, unsigned long frames );static signed long GetStreamReadAvailable( PaStream *s );static signed long GetStreamWriteAvailable( PaStream *s );/* Callback prototypes */static void *CallbackThreadFunc( void *userData );/* Functions specific to this API */static PaError PaAsiHpi_BuildDeviceList( PaAsiHpiHostApiRepresentation *hpiHostApi );static HW16 PaAsiHpi_PaToHpiFormat( PaSampleFormat paFormat );static PaSampleFormat PaAsiHpi_HpiToPaFormat( HW16 hpiFormat );static PaError PaAsiHpi_CreateFormat( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *parameters, double sampleRate, PaAsiHpiDeviceInfo **hpiDevice, HPI_FORMAT *hpiFormat );static PaError PaAsiHpi_OpenInput( struct PaUtilHostApiRepresentation *hostApi, const PaAsiHpiDeviceInfo *hpiDevice, const HPI_FORMAT *hpiFormat, HPI_HISTREAM *hpiStream );static PaError PaAsiHpi_OpenOutput( struct PaUtilHostApiRepresentation *hostApi, const PaAsiHpiDeviceInfo *hpiDevice, const HPI_FORMAT *hpiFormat, HPI_HOSTREAM *hpiStream );static PaError PaAsiHpi_GetStreamInfo( PaAsiHpiStreamComponent *streamComp, PaAsiHpiStreamInfo *info );static void PaAsiHpi_StreamComponentDump( PaAsiHpiStreamComponent *streamComp, PaAsiHpiStream *stream );static void PaAsiHpi_StreamDump( PaAsiHpiStream *stream );static PaError PaAsiHpi_SetupBuffers( PaAsiHpiStreamComponent *streamComp, HW32 pollingInterval, unsigned long framesPerPaHostBuffer, PaTime suggestedLatency );static PaError PaAsiHpi_PrimeOutputWithSilence( PaAsiHpiStream *stream );static PaError PaAsiHpi_StartStream( PaAsiHpiStream *stream, int outputPrimed );static PaError PaAsiHpi_StopStream( PaAsiHpiStream *stream, int abort );static PaError PaAsiHpi_ExplicitStop( PaAsiHpiStream *stream, int abort );static void PaAsiHpi_OnThreadExit( void *userData );static PaError PaAsiHpi_WaitForFrames( PaAsiHpiStream *stream, unsigned long *framesAvail, PaStreamCallbackFlags *cbFlags );static void PaAsiHpi_CalculateTimeInfo( PaAsiHpiStream *stream, PaStreamCallbackTimeInfo *timeInfo );static PaError PaAsiHpi_BeginProcessing( PaAsiHpiStream* stream, unsigned long* numFrames, PaStreamCallbackFlags *cbFlags );static PaError PaAsiHpi_EndProcessing( PaAsiHpiStream *stream, unsigned long numFrames, PaStreamCallbackFlags *cbFlags );/* ========================================================================== * ============================= IMPLEMENTATION ============================= * ========================================================================== *//* --------------------------- Host API Interface --------------------------- *//** Enumerate all PA devices (= HPI streams). This compiles a list of all HPI adapters, and registers a PA device for each input and output stream it finds. Most errors are ignored, as missing or erroneous devices are simply skipped. @param hpiHostApi Pointer to HPI host API struct @return PortAudio error code (only paInsufficientMemory in practice) */static PaError PaAsiHpi_BuildDeviceList( PaAsiHpiHostApiRepresentation *hpiHostApi ){ PaError result = paNoError; PaUtilHostApiRepresentation *hostApi = &hpiHostApi->baseHostApiRep; PaHostApiInfo *baseApiInfo = &hostApi->info; PaAsiHpiDeviceInfo *hpiDeviceList; HW16 adapterList[ HPI_MAX_ADAPTERS ]; HW16 numAdapters; HW16 hpiError = 0; int i, j, deviceCount = 0, deviceIndex = 0; assert( hpiHostApi ); assert( hpiHostApi->subSys ); /* Look for adapters (not strictly necessary, as AdapterOpen can do the same, but this */ /* way we have less errors since we do not try to open adapters we know aren't there) */ /* Errors not considered critical here (subsystem may report 0 devices), but report them */ /* in debug mode. */ PA_ASIHPI_UNLESS_( HPI_SubSysFindAdapters( hpiHostApi->subSys, &numAdapters, adapterList, HPI_MAX_ADAPTERS ), paNoError ); /* First open and count the number of devices (= number of streams), to ease memory allocation */ for( i=0; i < HPI_MAX_ADAPTERS; ++i ) { HW16 inStreams, outStreams; HW16 version; HW32 serial; HW16 type; /* If no adapter found at this index, skip it */ if( adapterList[i] == 0 ) continue; /* Try to open adapter */ hpiError = HPI_AdapterOpen( hpiHostApi->subSys, i ); /* Report error and skip to next device on failure */ if( hpiError ) { PA_ASIHPI_REPORT_ERROR_( hpiError ); continue; } hpiError = HPI_AdapterGetInfo( hpiHostApi->subSys, i, &outStreams, &inStreams, &version, &serial, &type ); /* Skip to next device on failure */ if( hpiError ) { PA_ASIHPI_REPORT_ERROR_( hpiError ); continue; } else { /* Assign default devices if available and increment device count */ if( (baseApiInfo->defaultInputDevice == paNoDevice) && (inStreams > 0) ) baseApiInfo->defaultInputDevice = deviceCount; deviceCount += inStreams; if( (baseApiInfo->defaultOutputDevice == paNoDevice) && (outStreams > 0) ) baseApiInfo->defaultOutputDevice = deviceCount; deviceCount += outStreams; } } /* Register any discovered devices */ if( deviceCount > 0 ) { /* Memory allocation */ PA_UNLESS_( hostApi->deviceInfos = (PaDeviceInfo**) PaUtil_GroupAllocateMemory( hpiHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount ), paInsufficientMemory ); /* Allocate all device info structs in a contiguous block */ PA_UNLESS_( hpiDeviceList = (PaAsiHpiDeviceInfo*) PaUtil_GroupAllocateMemory( hpiHostApi->allocations, sizeof(PaAsiHpiDeviceInfo) * deviceCount ), paInsufficientMemory ); /* Now query devices again for information */ for( i=0; i < HPI_MAX_ADAPTERS; ++i ) { HW16 inStreams, outStreams; HW16 version; HW32 serial; HW16 type; /* If no adapter found at this index, skip it */ if( adapterList[i] == 0 ) continue; /* Assume adapter is still open from previous round */ hpiError = HPI_AdapterGetInfo( hpiHostApi->subSys, i, &outStreams, &inStreams, &version, &serial, &type ); /* Report error and skip to next device on failure */ if( hpiError ) { PA_ASIHPI_REPORT_ERROR_( hpiError ); continue; } else { PA_DEBUG(( "Found HPI Adapter ID=%4X Idx=%d #In=%d #Out=%d S/N=%d HWver=%c%d DSPver=%03d\n", type, i, inStreams, outStreams, serial, ((version>>3)&0xf)+'A', /* Hw version major */ version&0x7, /* Hw version minor */ ((version>>13)*100)+((version>>7)&0x3f) /* DSP code version */ )); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -