20 #include "JackDriverLoader.h" 21 #include "driver_interface.h" 22 #include "JackPortAudioDriver.h" 23 #include "JackEngineControl.h" 24 #include "JackGraphManager.h" 25 #include "JackError.h" 27 #include "JackTools.h" 28 #include "JackCompilerDeps.h" 37 int JackPortAudioDriver::Render(
const void* inputBuffer,
void* outputBuffer,
38 unsigned long framesPerBuffer,
43 return static_cast<JackPortAudioDriver*
>(userData)->Render(inputBuffer, outputBuffer, statusFlags);
46 int JackPortAudioDriver::Render(
const void* inputBuffer,
void* outputBuffer,
PaStreamCallbackFlags statusFlags)
48 fInputBuffer = (jack_default_audio_sample_t**)inputBuffer;
49 fOutputBuffer = (jack_default_audio_sample_t**)outputBuffer;
53 jack_error(
"JackPortAudioDriver::Render paOutputUnderflow");
55 jack_error(
"JackPortAudioDriver::Render paInputUnderflow");
57 jack_error(
"JackPortAudioDriver::Render paOutputOverflow");
59 jack_error(
"JackPortAudioDriver::Render paInputOverflow");
61 jack_error(
"JackPortAudioDriver::Render paOutputUnderflow");
63 if (statusFlags != paPrimingOutput) {
64 jack_time_t cur_time = GetMicroSeconds();
65 NotifyXRun(cur_time,
float(cur_time - fBeginDateUst));
70 set_threaded_log_function();
72 return (Process() == 0) ? paContinue : paAbort;
75 int JackPortAudioDriver::Read()
77 for (
int i = 0; i < fCaptureChannels; i++) {
78 memcpy(GetInputBuffer(i), fInputBuffer[i],
sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize);
83 int JackPortAudioDriver::Write()
85 for (
int i = 0; i < fPlaybackChannels; i++) {
86 memcpy(fOutputBuffer[i], GetOutputBuffer(i),
sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize);
91 PaError JackPortAudioDriver::OpenStream(jack_nframes_t buffer_size)
96 jack_log(
"JackPortAudioDriver::OpenStream buffer_size = %d", buffer_size);
99 inputParameters.
device = fInputDevice;
103 ? ((fPaDevices->GetHostFromDevice(fInputDevice) ==
"ASIO") ? 0 :
Pa_GetDeviceInfo(inputParameters.
device)->defaultLowInputLatency)
107 outputParameters.
device = fOutputDevice;
111 ? ((fPaDevices->GetHostFromDevice(fOutputDevice) ==
"ASIO") ? 0 :
Pa_GetDeviceInfo(outputParameters.
device)->defaultLowOutputLatency)
116 (fInputDevice ==
paNoDevice) ? 0 : &inputParameters,
117 (fOutputDevice ==
paNoDevice) ? 0 : &outputParameters,
118 fEngineControl->fSampleRate,
125 void JackPortAudioDriver::UpdateLatencies()
134 for (
int i = 0; i < fCaptureChannels; i++) {
135 input_range.
max = input_range.
min = fEngineControl->fBufferSize + (info->
inputLatency * fEngineControl->fSampleRate) + fCaptureLatency;
136 fGraphManager->GetPort(fCapturePortList[i])->SetLatencyRange(JackCaptureLatency, &input_range);
139 for (
int i = 0; i < fPlaybackChannels; i++) {
140 output_range.
max = output_range.
min = (info->
outputLatency * fEngineControl->fSampleRate) + fPlaybackLatency;
141 if (fEngineControl->fSyncMode) {
142 output_range.
max = output_range.
min += fEngineControl->fBufferSize;
144 output_range.
max = output_range.
min += fEngineControl->fBufferSize * 2;
146 fGraphManager->GetPort(fPlaybackPortList[i])->SetLatencyRange(JackPlaybackLatency, &output_range);
147 if (fWithMonitorPorts) {
148 monitor_range.
min = monitor_range.
max = fEngineControl->fBufferSize;
149 fGraphManager->GetPort(fMonitorPortList[i])->SetLatencyRange(JackCaptureLatency, &monitor_range);
154 int JackPortAudioDriver::Open(jack_nframes_t buffer_size,
155 jack_nframes_t samplerate,
161 const char* capture_driver_uid,
162 const char* playback_driver_uid,
163 jack_nframes_t capture_latency,
164 jack_nframes_t playback_latency)
174 fCaptureLatency = capture_latency;
175 fPlaybackLatency = playback_latency;
177 jack_log(
"JackPortAudioDriver::Open nframes = %ld in = %ld out = %ld capture name = %s playback name = %s samplerate = %ld",
178 buffer_size, inchannels, outchannels, capture_driver_uid, playback_driver_uid, samplerate);
182 if (fPaDevices->GetInputDeviceFromName(capture_driver_uid, fInputDevice, in_max) < 0) {
187 if (fPaDevices->GetOutputDeviceFromName(playback_driver_uid, fOutputDevice, out_max) < 0) {
193 if (buffer_size == 0) {
194 buffer_size = fPaDevices->GetPreferredBufferSize(fInputDevice);
195 jack_log(
"JackPortAudioDriver::Open preferred buffer_size = %d", buffer_size);
199 char capture_driver_name[JACK_CLIENT_NAME_SIZE];
200 char playback_driver_name[JACK_CLIENT_NAME_SIZE];
201 snprintf(capture_driver_name,
sizeof(capture_driver_name),
"%s", capture_driver_uid);
202 snprintf(playback_driver_name,
sizeof(playback_driver_name),
"%s", playback_driver_uid);
203 if (JackAudioDriver::Open(buffer_size, samplerate, capturing, playing, inchannels, outchannels, monitor,
204 capture_driver_name, playback_driver_name, capture_latency, playback_latency) != 0) {
208 jack_log(
"JackPortAudioDriver::Open fInputDevice = %d, fOutputDevice %d", fInputDevice, fOutputDevice);
211 if (inchannels == 0) {
212 jack_log(
"JackPortAudioDriver::Open setup max in channels = %ld", in_max);
215 if (outchannels == 0) {
216 jack_log(
"JackPortAudioDriver::Open setup max out channels = %ld", out_max);
217 outchannels = out_max;
221 if (inchannels > in_max) {
222 jack_error(
"This device has only %d available input channels.", in_max);
225 if (outchannels > out_max) {
226 jack_error(
"This device has only %d available output channels.", out_max);
227 outchannels = out_max;
231 fCaptureChannels = inchannels;
232 fPlaybackChannels = outchannels;
234 err = OpenStream(buffer_size);
235 if (err != paNoError) {
241 fEngineControl->fPeriod = fEngineControl->fPeriodUsecs * 1000;
242 fEngineControl->fComputation = JackTools::ComputationMicroSec(fEngineControl->fBufferSize) * 1000;
243 fEngineControl->fConstraint = fEngineControl->fPeriodUsecs * 1000;
249 JackAudioDriver::Close();
250 jack_error(
"Can't open default PortAudio device");
254 int JackPortAudioDriver::Close()
257 jack_log(
"JackPortAudioDriver::Close");
258 JackAudioDriver::Close();
260 if (err != paNoError) {
265 return (err != paNoError) ? -1 : 0;
268 int JackPortAudioDriver::Attach()
270 if (JackAudioDriver::Attach() == 0) {
274 #if defined(HAVE_ASIO) 275 if (fInputDevice !=
paNoDevice && fPaDevices->GetHostFromDevice(fInputDevice) ==
"ASIO") {
276 for (
int i = 0; i < fCaptureChannels; i++) {
278 JackPort* port = fGraphManager->GetPort(fCapturePortList[i]);
279 port->SetAlias(alias);
284 if (fOutputDevice !=
paNoDevice && fPaDevices->GetHostFromDevice(fOutputDevice) ==
"ASIO") {
285 for (
int i = 0; i < fPlaybackChannels; i++) {
287 JackPort* port = fGraphManager->GetPort(fPlaybackPortList[i]);
288 port->SetAlias(alias);
300 int JackPortAudioDriver::Start()
302 jack_log(
"JackPortAudioDriver::Start");
303 if (JackAudioDriver::Start() == 0) {
309 JackAudioDriver::Stop();
314 int JackPortAudioDriver::Stop()
316 jack_log(
"JackPortAudioDriver::Stop");
321 if (JackAudioDriver::Stop() < 0) {
324 return (err == paNoError) ? 0 : -1;
328 int JackPortAudioDriver::SetBufferSize(jack_nframes_t buffer_size)
341 err = OpenStream(buffer_size);
342 if (err != paNoError) {
346 JackAudioDriver::SetBufferSize(buffer_size);
362 #include "JackCompilerDeps.h" 370 desc = jack_driver_descriptor_construct(
"portaudio", JackDriverMaster,
"PortAudio API based audio backend", &filler);
373 jack_driver_descriptor_add_parameter(desc, &filler,
"channels",
'c', JackDriverParamUInt, &value, NULL,
"Maximum number of channels", NULL);
374 jack_driver_descriptor_add_parameter(desc, &filler,
"inchannels",
'i', JackDriverParamUInt, &value, NULL,
"Maximum number of input channels", NULL);
375 jack_driver_descriptor_add_parameter(desc, &filler,
"outchannels",
'o', JackDriverParamUInt, &value, NULL,
"Maximum number of output channels", NULL);
377 jack_driver_descriptor_add_parameter(desc, &filler,
"capture",
'C', JackDriverParamString, &value, NULL,
"Provide capture ports. Optionally set PortAudio device name", NULL);
379 jack_driver_descriptor_add_parameter(desc, &filler,
"playback",
'P', JackDriverParamString, &value, NULL,
"Provide playback ports. Optionally set PortAudio device name", NULL);
382 jack_driver_descriptor_add_parameter(desc, &filler,
"monitor",
'm', JackDriverParamBool, &value, NULL,
"Provide monitor ports for the output", NULL);
385 jack_driver_descriptor_add_parameter(desc, &filler,
"duplex",
'D', JackDriverParamBool, &value, NULL,
"Provide both capture and playback ports", NULL);
388 jack_driver_descriptor_add_parameter(desc, &filler,
"rate",
'r', JackDriverParamUInt, &value, NULL,
"Sample rate", NULL);
391 jack_driver_descriptor_add_parameter(desc, &filler,
"period",
'p', JackDriverParamUInt, &value, NULL,
"Frames per period",
"Frames per period. If 0 and ASIO driver, will take preferred value");
393 jack_driver_descriptor_add_parameter(desc, &filler,
"device",
'd', JackDriverParamString, &value, NULL,
"PortAudio device name", NULL);
396 jack_driver_descriptor_add_parameter(desc, &filler,
"input-latency",
'I', JackDriverParamUInt, &value, NULL,
"Extra input latency", NULL);
397 jack_driver_descriptor_add_parameter(desc, &filler,
"output-latency",
'O', JackDriverParamUInt, &value, NULL,
"Extra output latency", NULL);
400 jack_driver_descriptor_add_parameter(desc, &filler,
"list-devices",
'l', JackDriverParamBool, &value, NULL,
"Display available PortAudio devices", NULL);
407 jack_nframes_t srate = 44100;
408 jack_nframes_t frames_per_interrupt = 512;
409 const char* capture_pcm_name =
"";
410 const char* playback_pcm_name =
"";
411 bool capture =
false;
412 bool playback =
false;
415 bool monitor =
false;
418 jack_nframes_t systemic_input_latency = 0;
419 jack_nframes_t systemic_output_latency = 0;
422 for (node = params; node; node = jack_slist_next(node))
426 switch (param->character) {
429 capture_pcm_name = param->value.str;
430 playback_pcm_name = param->value.str;
439 chan_in = chan_out = (int)param->value.ui;
443 chan_in = (
int)param->value.ui;
447 chan_out = (int)param->value.ui;
452 if (strcmp(param->value.str,
"none") != 0) {
453 capture_pcm_name = param->value.str;
459 if (strcmp(param->value.str,
"none") != 0) {
460 playback_pcm_name = param->value.str;
465 monitor = param->value.i;
469 srate = param->value.ui;
473 frames_per_interrupt = (
unsigned int)param->value.ui;
477 systemic_input_latency = param->value.ui;
481 systemic_output_latency = param->value.ui;
485 pa_devices->DisplayDevicesNames();
492 if (!capture && !playback) {
498 if (driver->Open(frames_per_interrupt, srate, capture, playback,
499 chan_in, chan_out, monitor, capture_pcm_name,
500 playback_pcm_name, systemic_input_latency,
501 systemic_output_latency) == 0) {
Locked Engine, access to methods is serialized using a mutex.
PaError Pa_StopStream(PaStream *stream)
#define paOutputUnderflow
Inter process synchronization using POSIX semaphore.
const PaStreamInfo * Pa_GetStreamInfo(PaStream *stream)
SERVER_EXPORT void jack_error(const char *fmt,...)
PaError Pa_OpenStream(PaStream **stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters, double sampleRate, unsigned long framesPerBuffer, PaStreamFlags streamFlags, PaStreamCallback *streamCallback, void *userData)
PaError PaAsio_GetOutputChannelName(PaDeviceIndex device, int channelIndex, const char **channelName)
PaError Pa_StartStream(PaStream *stream)
void * hostApiSpecificStreamInfo
PaError PaAsio_GetInputChannelName(PaDeviceIndex device, int channelIndex, const char **channelName)
PaSampleFormat sampleFormat
unsigned long PaStreamCallbackFlags
The base interface for drivers clients.
const PaDeviceInfo * Pa_GetDeviceInfo(PaDeviceIndex device)
const char * Pa_GetErrorText(PaError errorCode)
SERVER_EXPORT void jack_log(const char *fmt,...)
PaError Pa_CloseStream(PaStream *stream)
A PortAudio Devices manager.