📄 pa_jack.c
字号:
/* Unlock mutex and await signal from processing thread */ result = WaitCondition( stream->hostApi ); } ASSERT_CALL( pthread_mutex_unlock( &hostApi->mtx ), 0 ); ENSURE_PA( result );error: return result;}/* Add stream to processing queue */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 ){ PaError result = paNoError; PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi; PaJackStream *stream = NULL; char *port_string = PaUtil_GroupAllocateMemory( jackHostApi->deviceInfoMemory, jack_port_name_size() ); unsigned long regexSz = jack_client_name_size() + 3; char *regex_pattern = PaUtil_GroupAllocateMemory( jackHostApi->deviceInfoMemory, regexSz ); const char **jack_ports = NULL; /* int jack_max_buffer_size = jack_get_buffer_size( jackHostApi->jack_client ); */ int i; int inputChannelCount, outputChannelCount; const double jackSr = jack_get_sample_rate( jackHostApi->jack_client ); PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0; int bpInitialized = 0, srInitialized = 0; /* Initialized buffer processor and stream representation? */ unsigned long ofs; /* validate platform specific flags */ if( (streamFlags & paPlatformSpecificFlags) != 0 ) return paInvalidFlag; /* unexpected platform specific flag */ if( (streamFlags & paPrimeOutputBuffersUsingStreamCallback) != 0 ) { streamFlags &= ~paPrimeOutputBuffersUsingStreamCallback; /*return paInvalidFlag;*/ /* This implementation does not support buffer priming */ } if( framesPerBuffer != paFramesPerBufferUnspecified ) { /* Jack operates with power of two buffers, and we don't support non-integer buffer adaption (yet) */ /*UNLESS( !(framesPerBuffer & (framesPerBuffer - 1)), paBufferTooBig );*/ /* TODO: Add descriptive error code? */ } /* Preliminary checks */ 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; } /* ... check that the sample rate exactly matches the ONE acceptable rate * A: This rate isn't necessarily constant though? */#define ABS(x) ( (x) > 0 ? (x) : -(x) ) if( ABS(sampleRate - jackSr) > 1 ) return paInvalidSampleRate;#undef ABS UNLESS( stream = (PaJackStream*)PaUtil_AllocateMemory( sizeof(PaJackStream) ), paInsufficientMemory ); ENSURE_PA( InitializeStream( stream, jackHostApi, inputChannelCount, outputChannelCount ) ); /* the blocking emulation, if necessary */ stream->isBlockingStream = !streamCallback; if( stream->isBlockingStream ) { float latency = 0.001; /* 1ms is the absolute minimum we support */ int minimum_buffer_frames = 0; if( inputParameters && inputParameters->suggestedLatency > latency ) latency = inputParameters->suggestedLatency; else if( outputParameters && outputParameters->suggestedLatency > latency ) latency = outputParameters->suggestedLatency; /* the latency the user asked for indicates the minimum buffer size in frames */ minimum_buffer_frames = (int) (latency * jack_get_sample_rate( jackHostApi->jack_client )); /* we also need to be able to store at least three full jack buffers to avoid dropouts */ if( jackHostApi->jack_buffer_size * 3 > minimum_buffer_frames ) minimum_buffer_frames = jackHostApi->jack_buffer_size * 3; /* setup blocking API data structures (FIXME: can fail) */ BlockingBegin( stream, minimum_buffer_frames ); /* install our own callback for the blocking API */ streamCallback = BlockingCallback; userData = stream; PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &jackHostApi->blockingStreamInterface, streamCallback, userData ); } else { PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation, &jackHostApi->callbackStreamInterface, streamCallback, userData ); } srInitialized = 1; PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, jackSr ); /* create the JACK ports. We cannot connect them until audio * processing begins */ /* Register a unique set of ports for this stream * TODO: Robust allocation of new port names */ ofs = jackHostApi->inputBase; for( i = 0; i < inputChannelCount; i++ ) { snprintf( port_string, jack_port_name_size(), "in_%lu", ofs + i ); UNLESS( stream->local_input_ports[i] = jack_port_register( jackHostApi->jack_client, port_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ), paInsufficientMemory ); } jackHostApi->inputBase += inputChannelCount; ofs = jackHostApi->outputBase; for( i = 0; i < outputChannelCount; i++ ) { snprintf( port_string, jack_port_name_size(), "out_%lu", ofs + i ); UNLESS( stream->local_output_ports[i] = jack_port_register( jackHostApi->jack_client, port_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ), paInsufficientMemory ); } jackHostApi->outputBase += outputChannelCount; /* look up the jack_port_t's for the remote ports. We could do * this at stream start time, but doing it here ensures the * name lookup only happens once. */ if( inputChannelCount > 0 ) { int err = 0; /* ... remote output ports (that we input from) */ snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ inputParameters->device ]->name ); UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern, NULL, JackPortIsOutput ), paUnanticipatedHostError ); for( i = 0; i < inputChannelCount && jack_ports[i]; i++ ) { if( (stream->remote_output_ports[i] = jack_port_by_name( jackHostApi->jack_client, jack_ports[i] )) == NULL ) { err = 1; break; } } free( jack_ports ); UNLESS( !err, paInsufficientMemory ); /* Fewer ports than expected? */ UNLESS( i == inputChannelCount, paInternalError ); } if( outputChannelCount > 0 ) { int err = 0; /* ... remote input ports (that we output to) */ snprintf( regex_pattern, regexSz, "%s:.*", hostApi->deviceInfos[ outputParameters->device ]->name ); UNLESS( jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern, NULL, JackPortIsInput ), paUnanticipatedHostError ); for( i = 0; i < outputChannelCount && jack_ports[i]; i++ ) { if( (stream->remote_input_ports[i] = jack_port_by_name( jackHostApi->jack_client, jack_ports[i] )) == 0 ) { err = 1; break; } } free( jack_ports ); UNLESS( !err , paInsufficientMemory ); /* Fewer ports than expected? */ UNLESS( i == outputChannelCount, paInternalError ); } ENSURE_PA( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, inputChannelCount, inputSampleFormat, paFloat32, /* hostInputSampleFormat */ outputChannelCount, outputSampleFormat, paFloat32, /* hostOutputSampleFormat */ jackSr, streamFlags, framesPerBuffer, 0, /* Ignored */ paUtilUnknownHostBufferSize, /* Buffer size may vary on JACK's discretion */ streamCallback, userData ) ); bpInitialized = 1; if( stream->num_incoming_connections > 0 ) stream->streamRepresentation.streamInfo.inputLatency = (jack_port_get_latency( stream->remote_output_ports[0] ) - jack_get_buffer_size( jackHostApi->jack_client ) /* One buffer is not counted as latency */ + PaUtil_GetBufferProcessorInputLatency( &stream->bufferProcessor )) / sampleRate; if( stream->num_outgoing_connections > 0 ) stream->streamRepresentation.streamInfo.outputLatency = (jack_port_get_latency( stream->remote_input_ports[0] ) - jack_get_buffer_size( jackHostApi->jack_client ) /* One buffer is not counted as latency */ + PaUtil_GetBufferProcessorOutputLatency( &stream->bufferProcessor )) / sampleRate; stream->streamRepresentation.streamInfo.sampleRate = jackSr; stream->t0 = jack_frame_time( jackHostApi->jack_client ); /* A: Time should run from Pa_OpenStream */ ENSURE_PA( AddStream( stream ) ); /* Add to queue over opened streams */ *s = (PaStream*)stream; return result;error: if( stream ) CleanUpStream( stream, srInitialized, bpInitialized ); return result;}/* When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted.*/static PaError CloseStream( PaStream* s ){ PaError result = paNoError; PaJackStream *stream = (PaJackStream*)s; /* Remove this stream from the processing queue */ ENSURE_PA( RemoveStream( stream ) );error: CleanUpStream( stream, 1, 1 ); return result;}static PaError RealProcess( PaJackStream *stream, jack_nframes_t frames ){ PaError result = paNoError; PaStreamCallbackTimeInfo timeInfo = {0,0,0}; int chn; int framesProcessed; const double sr = jack_get_sample_rate( stream->jack_client ); /* Shouldn't change during the process callback */ PaStreamCallbackFlags cbFlags = 0; /* If the user has returned !paContinue from the callback we'll want to flush the internal buffers, * when these are empty we can finally mark the stream as inactive */ if( stream->callbackResult != paContinue && PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) ) { stream->is_active = 0; if( stream->streamRepresentation.streamFinishedCallback ) stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData ); PA_DEBUG(( "%s: Callback finished\n", __FUNCTION__ )); goto end; } timeInfo.currentTime = (jack_frame_time( stream->jack_client ) - stream->t0) / sr; if( stream->num_incoming_connections > 0 ) timeInfo.inputBufferAdcTime = timeInfo.currentTime - jack_port_get_latency( stream->remote_output_ports[0] ) / sr; if( stream->num_outgoing_connections > 0 ) timeInfo.outputBufferDacTime = timeInfo.currentTime + jack_port_get_latency( stream->remote_input_ports[0] ) / sr; PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); if( stream->xrun ) { /* XXX: Any way to tell which of these occurred? */ cbFlags = paOutputUnderflow | paInputOverflow; stream->xrun = FALSE; } PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, cbFlags ); if( stream->num_incoming_connections > 0 ) PaUtil_SetInputFrameCount( &stream->bufferProcessor, frames ); if( stream->num_outgoing_connections > 0 ) PaUtil_SetOutputFrameCount( &stream->bufferProcessor, frames ); for( chn = 0; chn < stream->num_incoming_connections; chn++ ) { jack_default_audio_sample_t *channel_buf = (jack_default_audio_sample_t*) jack_port_get_buffer( stream->local_input_ports[chn], frames ); PaUtil_SetNonInterleavedInputChannel( &stream->bufferProcessor, chn, channel_buf ); } for( chn = 0; chn < stream->num_outgoing_connections; chn++ ) { jack_default_audio_sample_t *channel_buf = (jack_default_audio_sample_t*) jack_port_get_buffer( stream->local_output_ports[chn], frames );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -