📄 pa_jack.c
字号:
return 0;}PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex ){ PaError result = paNoError; PaJackHostApiRepresentation *jackHostApi; int activated = 0; char *clientName; int written; *hostApi = NULL; /* Initialize to NULL */ UNLESS( jackHostApi = (PaJackHostApiRepresentation*) PaUtil_AllocateMemory( sizeof(PaJackHostApiRepresentation) ), paInsufficientMemory ); UNLESS( jackHostApi->deviceInfoMemory = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); mainThread_ = pthread_self(); ASSERT_CALL( pthread_mutex_init( &jackHostApi->mtx, NULL ), 0 ); ASSERT_CALL( pthread_cond_init( &jackHostApi->cond, NULL ), 0 ); /* Try to become a client of the JACK server. If we cannot do * this, then this API cannot be used. */ clientName = PaUtil_GroupAllocateMemory( jackHostApi->deviceInfoMemory, jack_client_name_size() ); written = snprintf( clientName, jack_client_name_size(), "PortAudio-%d", getpid() ); assert( written < jack_client_name_size() ); jackHostApi->jack_client = jack_client_new( clientName ); if( jackHostApi->jack_client == NULL ) { /* the V19 development docs say that if an implementation * detects that it cannot be used, it should return a NULL * interface and paNoError */ result = paNoError; goto error; } jackHostApi->hostApiIndex = hostApiIndex; *hostApi = &jackHostApi->commonHostApiRep; (*hostApi)->info.structVersion = 1; (*hostApi)->info.type = paJACK; (*hostApi)->info.name = "JACK Audio Connection Kit"; /* Build a device list by querying the JACK server */ ENSURE_PA( BuildDeviceList( jackHostApi ) ); /* Register functions */ (*hostApi)->Terminate = Terminate; (*hostApi)->OpenStream = OpenStream; (*hostApi)->IsFormatSupported = IsFormatSupported; PaUtil_InitializeStreamInterface( &jackHostApi->callbackStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, GetStreamCpuLoad, PaUtil_DummyRead, PaUtil_DummyWrite, PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable ); PaUtil_InitializeStreamInterface( &jackHostApi->blockingStreamInterface, CloseStream, StartStream, StopStream, AbortStream, IsStreamStopped, IsStreamActive, GetStreamTime, PaUtil_DummyGetCpuLoad, BlockingReadStream, BlockingWriteStream, BlockingGetStreamReadAvailable, BlockingGetStreamWriteAvailable ); jackHostApi->inputBase = jackHostApi->outputBase = 0; jackHostApi->xrun = 0; jackHostApi->toAdd = jackHostApi->toRemove = NULL; jackHostApi->processQueue = NULL; jackHostApi->jackIsDown = 0; jack_on_shutdown( jackHostApi->jack_client, JackOnShutdown, jackHostApi ); jack_set_error_function( JackErrorCallback ); jackHostApi->jack_buffer_size = jack_get_buffer_size ( jackHostApi->jack_client ); UNLESS( !jack_set_sample_rate_callback( jackHostApi->jack_client, JackSrCb, jackHostApi ), paUnanticipatedHostError ); UNLESS( !jack_set_xrun_callback( jackHostApi->jack_client, JackXRunCb, jackHostApi ), paUnanticipatedHostError ); UNLESS( !jack_set_process_callback( jackHostApi->jack_client, JackCallback, jackHostApi ), paUnanticipatedHostError ); UNLESS( !jack_activate( jackHostApi->jack_client ), paUnanticipatedHostError ); activated = 1; return result;error: if( activated ) ASSERT_CALL( jack_deactivate( jackHostApi->jack_client ), 0 ); if( jackHostApi ) { if( jackHostApi->jack_client ) ASSERT_CALL( jack_client_close( jackHostApi->jack_client ), 0 ); if( jackHostApi->deviceInfoMemory ) { PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory ); PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory ); } PaUtil_FreeMemory( jackHostApi ); } return result;}static void Terminate( struct PaUtilHostApiRepresentation *hostApi ){ PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi; /* note: this automatically disconnects all ports, since a deactivated * client is not allowed to have any ports connected */ ASSERT_CALL( jack_deactivate( jackHostApi->jack_client ), 0 ); ASSERT_CALL( pthread_mutex_destroy( &jackHostApi->mtx ), 0 ); ASSERT_CALL( pthread_cond_destroy( &jackHostApi->cond ), 0 ); ASSERT_CALL( jack_client_close( jackHostApi->jack_client ), 0 ); if( jackHostApi->deviceInfoMemory ) { PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory ); PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory ); } PaUtil_FreeMemory( jackHostApi ); free( jackErr_ );}static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate ){ int inputChannelCount = 0, outputChannelCount = 0; PaSampleFormat inputSampleFormat, outputSampleFormat; if( inputParameters ) { inputChannelCount = inputParameters->channelCount; inputSampleFormat = inputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that input device can support inputChannelCount */ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels ) return paInvalidChannelCount; /* validate inputStreamInfo */ if( inputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { inputChannelCount = 0; } if( outputParameters ) { outputChannelCount = outputParameters->channelCount; outputSampleFormat = outputParameters->sampleFormat; /* unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification */ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification ) return paInvalidDevice; /* check that output device can support inputChannelCount */ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels ) return paInvalidChannelCount; /* validate outputStreamInfo */ if( outputParameters->hostApiSpecificStreamInfo ) return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */ } else { outputChannelCount = 0; } /* The following check is not necessary for JACK. - if a full duplex stream is requested, check that the combination of input and output parameters is supported Because the buffer adapter handles conversion between all standard sample formats, the following checks are only required if paCustomFormat is implemented, or under some other unusual conditions. - check that input device can support inputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format - check that output device can support outputSampleFormat, or that we have the capability to convert from outputSampleFormat to a native format */ /* check that the device supports sampleRate */ #define ABS(x) ( (x) > 0 ? (x) : -(x) ) if( ABS(sampleRate - jack_get_sample_rate(((PaJackHostApiRepresentation *) hostApi)->jack_client )) > 1 ) return paInvalidSampleRate;#undef ABS return paFormatIsSupported;}/* Basic stream initialization */static PaError InitializeStream( PaJackStream *stream, PaJackHostApiRepresentation *hostApi, int numInputChannels, int numOutputChannels ){ PaError result = paNoError; assert( stream ); memset( stream, 0, sizeof (PaJackStream) ); UNLESS( stream->stream_memory = PaUtil_CreateAllocationGroup(), paInsufficientMemory ); stream->jack_client = hostApi->jack_client; stream->hostApi = hostApi; if( numInputChannels > 0 ) { UNLESS( stream->local_input_ports = (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ), paInsufficientMemory ); memset( stream->local_input_ports, 0, sizeof(jack_port_t*) * numInputChannels ); UNLESS( stream->remote_output_ports = (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numInputChannels ), paInsufficientMemory ); memset( stream->remote_output_ports, 0, sizeof(jack_port_t*) * numInputChannels ); } if( numOutputChannels > 0 ) { UNLESS( stream->local_output_ports = (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ), paInsufficientMemory ); memset( stream->local_output_ports, 0, sizeof(jack_port_t*) * numOutputChannels ); UNLESS( stream->remote_input_ports = (jack_port_t**) PaUtil_GroupAllocateMemory( stream->stream_memory, sizeof(jack_port_t*) * numOutputChannels ), paInsufficientMemory ); memset( stream->remote_input_ports, 0, sizeof(jack_port_t*) * numOutputChannels ); } stream->num_incoming_connections = numInputChannels; stream->num_outgoing_connections = numOutputChannels;error: return result;}/*! * Free resources associated with stream, and eventually stream itself. * * Frees allocated memory, and closes opened pcms. */static void CleanUpStream( PaJackStream *stream, int terminateStreamRepresentation, int terminateBufferProcessor ){ int i; assert( stream ); if( stream->isBlockingStream ) BlockingEnd( stream ); for( i = 0; i < stream->num_incoming_connections; ++i ) { if( stream->local_input_ports[i] ) ASSERT_CALL( jack_port_unregister( stream->jack_client, stream->local_input_ports[i] ), 0 ); } for( i = 0; i < stream->num_outgoing_connections; ++i ) { if( stream->local_output_ports[i] ) ASSERT_CALL( jack_port_unregister( stream->jack_client, stream->local_output_ports[i] ), 0 ); } if( terminateStreamRepresentation ) PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); if( terminateBufferProcessor ) PaUtil_TerminateBufferProcessor( &stream->bufferProcessor ); if( stream->stream_memory ) { PaUtil_FreeAllAllocations( stream->stream_memory ); PaUtil_DestroyAllocationGroup( stream->stream_memory ); } PaUtil_FreeMemory( stream );}static PaError WaitCondition( PaJackHostApiRepresentation *hostApi ){ PaError result = paNoError; int err = 0; PaTime pt = PaUtil_GetTime(); struct timespec ts; ts.tv_sec = (time_t) floor( pt + 1 ); ts.tv_nsec = (long) ((pt - floor( pt )) * 1000000000); /* XXX: Best enclose in loop, in case of spurious wakeups? */ err = pthread_cond_timedwait( &hostApi->cond, &hostApi->mtx, &ts ); /* Make sure we didn't time out */ UNLESS( err != ETIMEDOUT, paTimedOut ); UNLESS( !err, paInternalError );error: return result;}static PaError AddStream( PaJackStream *stream ){ PaError result = paNoError; PaJackHostApiRepresentation *hostApi = stream->hostApi; /* Add to queue of streams that should be processed */ ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 ); if( !hostApi->jackIsDown ) { hostApi->toAdd = stream; /* Unlock mutex and await signal from processing thread */ result = WaitCondition( stream->hostApi ); } ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 ); ENSURE_PA( result ); UNLESS( !hostApi->jackIsDown, paDeviceUnavailable );error: return result;}/* Remove stream from processing queue */static PaError RemoveStream( PaJackStream *stream ){ PaError result = paNoError; PaJackHostApiRepresentation *hostApi = stream->hostApi; /* Add to queue over streams that should be processed */ ASSERT_CALL( pthread_mutex_lock( &hostApi->mtx ), 0 ); if( !hostApi->jackIsDown ) { hostApi->toRemove = stream;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -