📄 pa_jack.c
字号:
/* * $Id: pa_jack.c 1186 2007-04-02 17:56:26Z aknudsen $ * PortAudio Portable Real-Time Audio Library * Latest Version at: http://www.portaudio.com * JACK Implementation by Joshua Haberman * * Copyright (c) 2004 Stefan Westerfeld <stefan@space.twc.de> * Copyright (c) 2004 Arve Knudsen <aknuds-1@broadpark.no> * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com> * * 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 @ingroup hostaip_src*/#include <string.h>#include <regex.h>#include <stdlib.h>#include <stdio.h>#include <assert.h>#include <sys/types.h>#include <unistd.h>#include <errno.h> /* EBUSY */#include <signal.h> /* sig_atomic_t */#include <math.h>#include <semaphore.h>#include <jack/types.h>#include <jack/jack.h>#include "pa_util.h"#include "pa_hostapi.h"#include "pa_stream.h"#include "pa_process.h"#include "pa_allocation.h"#include "pa_cpuload.h"#include "pa_ringbuffer.h"static int aErr_;static PaError paErr_; /* For use with ENSURE_PA */static pthread_t mainThread_;static char *jackErr_ = NULL;#define STRINGIZE_HELPER(expr) #expr#define STRINGIZE(expr) STRINGIZE_HELPER(expr)/* Check PaError */#define ENSURE_PA(expr) \ do { \ if( (paErr_ = (expr)) < paNoError ) \ { \ if( (paErr_) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \ { \ if (! jackErr_ ) jackErr_ = "unknown error";\ PaUtil_SetLastHostErrorInfo( paJACK, -1, jackErr_ ); \ } \ PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ result = paErr_; \ goto error; \ } \ } while( 0 )#define UNLESS(expr, code) \ do { \ if( (expr) == 0 ) \ { \ if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \ { \ if (!jackErr_) jackErr_ = "unknown error";\ PaUtil_SetLastHostErrorInfo( paJACK, -1, jackErr_ ); \ } \ PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \ result = (code); \ goto error; \ } \ } while( 0 )#define ASSERT_CALL(expr, success) \ aErr_ = (expr); \ assert( aErr_ == success );/* * Functions that directly map to the PortAudio stream interface */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 GetStreamInputLatency( PaStream *stream );*//*static PaTime GetStreamOutputLatency( PaStream *stream );*/static PaTime GetStreamTime( PaStream *stream );static double GetStreamCpuLoad( PaStream* stream );/* * Data specific to this API */struct PaJackStream;typedef struct{ PaUtilHostApiRepresentation commonHostApiRep; PaUtilStreamInterface callbackStreamInterface; PaUtilStreamInterface blockingStreamInterface; PaUtilAllocationGroup *deviceInfoMemory; jack_client_t *jack_client; int jack_buffer_size; PaHostApiIndex hostApiIndex; pthread_mutex_t mtx; pthread_cond_t cond; unsigned long inputBase, outputBase; /* For dealing with the process thread */ volatile int xrun; /* Received xrun notification from JACK? */ struct PaJackStream * volatile toAdd, * volatile toRemove; struct PaJackStream *processQueue; volatile sig_atomic_t jackIsDown;}PaJackHostApiRepresentation;/* PaJackStream - a stream data structure specifically for this implementation */typedef struct PaJackStream{ PaUtilStreamRepresentation streamRepresentation; PaUtilBufferProcessor bufferProcessor; PaUtilCpuLoadMeasurer cpuLoadMeasurer; PaJackHostApiRepresentation *hostApi; /* our input and output ports */ jack_port_t **local_input_ports; jack_port_t **local_output_ports; /* the input and output ports of the client we are connecting to */ jack_port_t **remote_input_ports; jack_port_t **remote_output_ports; int num_incoming_connections; int num_outgoing_connections; jack_client_t *jack_client; /* The stream is running if it's still producing samples. * The stream is active if samples it produced are still being heard. */ volatile sig_atomic_t is_running; volatile sig_atomic_t is_active; /* Used to signal processing thread that stream should start or stop, respectively */ volatile sig_atomic_t doStart, doStop, doAbort; jack_nframes_t t0; PaUtilAllocationGroup *stream_memory; /* These are useful in the process callback */ int callbackResult; int isSilenced; int xrun; /* These are useful for the blocking API */ int isBlockingStream; PaUtilRingBuffer inFIFO; PaUtilRingBuffer outFIFO; volatile sig_atomic_t data_available; sem_t data_semaphore; int bytesPerFrame; int samplesPerFrame; struct PaJackStream *next;}PaJackStream;#define TRUE 1#define FALSE 0/* * Functions specific to this API */static int JackCallback( jack_nframes_t frames, void *userData );/* * * Implementation * *//* ---- blocking emulation layer ---- *//* Allocate buffer. */static PaError BlockingInitFIFO( PaUtilRingBuffer *rbuf, long numFrames, long bytesPerFrame ){ long numBytes = numFrames * bytesPerFrame; char *buffer = (char *) malloc( numBytes ); if( buffer == NULL ) return paInsufficientMemory; memset( buffer, 0, numBytes ); return (PaError) PaUtil_InitializeRingBuffer( rbuf, numBytes, buffer );}/* Free buffer. */static PaError BlockingTermFIFO( PaUtilRingBuffer *rbuf ){ if( rbuf->buffer ) free( rbuf->buffer ); rbuf->buffer = NULL; return paNoError;}static intBlockingCallback( const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData ){ struct PaJackStream *stream = (PaJackStream *)userData; long numBytes = stream->bytesPerFrame * framesPerBuffer; /* This may get called with NULL inputBuffer during initial setup. */ if( inputBuffer != NULL ) { PaUtil_WriteRingBuffer( &stream->inFIFO, inputBuffer, numBytes ); } if( outputBuffer != NULL ) { int numRead = PaUtil_ReadRingBuffer( &stream->outFIFO, outputBuffer, numBytes ); /* Zero out remainder of buffer if we run out of data. */ memset( (char *)outputBuffer + numRead, 0, numBytes - numRead ); } if( !stream->data_available ) { stream->data_available = 1; sem_post( &stream->data_semaphore ); } return paContinue;}static PaErrorBlockingBegin( PaJackStream *stream, int minimum_buffer_size ){ long doRead = 0; long doWrite = 0; PaError result = paNoError; long numFrames; doRead = stream->local_input_ports != NULL; doWrite = stream->local_output_ports != NULL; /* <FIXME> */ stream->samplesPerFrame = 2; stream->bytesPerFrame = sizeof(float) * stream->samplesPerFrame; /* </FIXME> */ numFrames = 32; while (numFrames < minimum_buffer_size) numFrames *= 2; if( doRead ) { ENSURE_PA( BlockingInitFIFO( &stream->inFIFO, numFrames, stream->bytesPerFrame ) ); } if( doWrite ) { long numBytes; ENSURE_PA( BlockingInitFIFO( &stream->outFIFO, numFrames, stream->bytesPerFrame ) ); /* Make Write FIFO appear full initially. */ numBytes = PaUtil_GetRingBufferWriteAvailable( &stream->outFIFO ); PaUtil_AdvanceRingBufferWriteIndex( &stream->outFIFO, numBytes ); } stream->data_available = 0; sem_init( &stream->data_semaphore, 0, 0 );error: return result;}static voidBlockingEnd( PaJackStream *stream ){ BlockingTermFIFO( &stream->inFIFO ); BlockingTermFIFO( &stream->outFIFO ); sem_destroy( &stream->data_semaphore );}static PaError BlockingReadStream( PaStream* s, void *data, unsigned long numFrames ){ PaError result = paNoError;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -