📄 pa_jack.c
字号:
JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ); } for( i = 0; i < outputChannelCount; i++ ) { sprintf( port_string, "out_%d", i ); stream->local_output_ports[i] = jack_port_register( jackHostApi->jack_client, port_string, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ); } /* 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 ) { /* ... remote output ports (that we input from) */ sprintf( regex_pattern, "%s:.*", hostApi->deviceInfos[ inputParameters->device ]->name ); jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern, NULL, JackPortIsOutput); for( i = 0; i < inputChannelCount && jack_ports[i]; i++ ) { stream->remote_output_ports[i] = jack_port_by_name( jackHostApi->jack_client, jack_ports[i] ); } if( i < inputChannelCount ) { /* we found fewer ports than we expected */ return paInternalError; } free( jack_ports ); // XXX: this doesn't happen if we exit prematurely } if( outputChannelCount > 0 ) { /* ... remote input ports (that we output to) */ sprintf( regex_pattern, "%s:.*", hostApi->deviceInfos[ outputParameters->device ]->name ); jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern, NULL, JackPortIsInput); for( i = 0; i < outputChannelCount && jack_ports[i]; i++ ) { stream->remote_input_ports[i] = jack_port_by_name( jackHostApi->jack_client, jack_ports[i] ); } if( i < outputChannelCount ) { /* we found fewer ports than we expected */ return paInternalError; } free( jack_ports ); // XXX: this doesn't happen if we exit prematurely } result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor, inputChannelCount, inputSampleFormat, paFloat32, /* hostInputSampleFormat */ outputChannelCount, outputSampleFormat, paFloat32, /* hostOutputSampleFormat */ sampleRate, streamFlags, framesPerBuffer, jack_max_buffer_size, paUtilFixedHostBufferSize, streamCallback, userData ); if( result != paNoError ) goto error; stream->is_running = FALSE; stream->t0 = -1;/* set the first time through the callback*/ stream->total_frames_sent = 0; jack_set_process_callback( jackHostApi->jack_client, JackCallback, stream ); *s = (PaStream*)stream; return result;error: if( stream ) { if( stream->stream_memory ) { PaUtil_FreeAllAllocations( stream->stream_memory ); PaUtil_DestroyAllocationGroup( stream->stream_memory ); } PaUtil_FreeMemory( stream ); } return result;#undef MALLOC#undef MEMVERIFY}static int JackCallback( jack_nframes_t frames, void *userData ){ PaJackStream *stream = (PaJackStream*)userData; PaStreamCallbackTimeInfo timeInfo; int callbackResult; int chn; int framesProcessed; /* TODO: make this a lot more accurate */ PaTime now = GetStreamTime(stream); timeInfo.currentTime = now; timeInfo.outputBufferDacTime = now; timeInfo.inputBufferAdcTime = now; if( stream->t0 == -1 ) { if( stream->num_outgoing_connections == 0 ) { /* TODO: how to handle stream time for capture-only operation? */ } else { /* the beginning time needs to be initialized */ stream->t0 = jack_frame_time( stream->jack_client ) - jack_frames_since_cycle_start( stream->jack_client) + jack_port_get_total_latency( stream->jack_client, stream->local_output_ports[0] ); } } PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer ); PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo, 0 /* @todo pass underflow/overflow flags when necessary */ ); for( chn = 0; chn < stream->num_incoming_connections; chn++ ) { jack_default_audio_sample_t *channel_buf; 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; channel_buf = (jack_default_audio_sample_t*) jack_port_get_buffer( stream->local_output_ports[chn], frames ); PaUtil_SetNonInterleavedOutputChannel( &stream->bufferProcessor, chn, channel_buf ); } if( stream->num_incoming_connections > 0 ) PaUtil_SetInputFrameCount( &stream->bufferProcessor, frames ); if( stream->num_outgoing_connections > 0 ) PaUtil_SetOutputFrameCount( &stream->bufferProcessor, frames ); callbackResult = paContinue; framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult ); PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed ); stream->total_frames_sent += frames; if( callbackResult == paContinue ) { /* nothing special */ } else if( callbackResult == paAbort ) { /* finish playback immediately */ /* TODO: memset 0 the outgoing samples to "cancel" them */ stream->is_active = FALSE; /* return nonzero so we get deactivated (and the callback won't * get called again) */ return 1; } else { /* User callback has asked us to stop with paComplete or other non-zero value. */ stream->is_active = FALSE; /* return nonzero so we get deactivated (and the callback won't * get called again) */ return 1; } return 0;}/* 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; PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation ); PaUtil_FreeMemory( stream ); return result;}static PaError StartStream( PaStream *s ){ PaError result = paNoError; PaJackStream *stream = (PaJackStream*)s; int i; /* start the audio thread */ jack_activate( stream->jack_client ); /* connect the ports */ /* NOTE: I would rather use jack_port_connect which uses jack_port_t's * instead of port names, but it is not implemented yet. */ if( stream->num_incoming_connections > 0 ) { for( i = 0; i < stream->num_incoming_connections; i++ ) jack_connect( stream->jack_client, jack_port_name(stream->remote_output_ports[i]), jack_port_name(stream->local_input_ports[i] ) ); } if( stream->num_outgoing_connections > 0 ) { for( i = 0; i < stream->num_outgoing_connections; i++ ) jack_connect( stream->jack_client, jack_port_name(stream->local_output_ports[i]), jack_port_name(stream->remote_input_ports[i]) ); } stream->is_running = TRUE; stream->is_active = TRUE; return result;}static PaError StopStream( PaStream *s ){ PaError result = paNoError; PaJackStream *stream = (PaJackStream*)s; /* note: this automatically disconnects all ports, since a deactivated * client is not allowed to have any ports connected */ jack_deactivate( stream->jack_client ); stream->is_running = FALSE; /* TODO: block until playback complete */ stream->is_active = FALSE; return result;}static PaError AbortStream( PaStream *s ){ PaError result = paNoError; PaJackStream *stream = (PaJackStream*)s; /* There's no way to cancel samples already submitted, but we can * return immediately */ /* note: this automatically disconnects all ports, since a deactivated * client is not allowed to have any ports connected */ jack_deactivate( stream->jack_client ); stream->is_running = FALSE; stream->is_active = FALSE; return result;}static PaError IsStreamStopped( PaStream *s ){ PaJackStream *stream = (PaJackStream*)s; return stream->is_running == FALSE;}static PaError IsStreamActive( PaStream *s ){ PaJackStream *stream = (PaJackStream*)s; return stream->is_active == TRUE;}static PaTime GetStreamTime( PaStream *s ){ PaJackStream *stream = (PaJackStream*)s; /* TODO: what if we're recording-only? */ int delta_t = jack_frame_time( stream->jack_client ) - stream->t0; return delta_t / (PaTime)jack_get_sample_rate( stream->jack_client );}static double GetStreamCpuLoad( PaStream* s ){ PaJackStream *stream = (PaJackStream*)s; return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -