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 if (JackAudioDriver::Open(buffer_size, samplerate, capturing, playing, inchannels, outchannels, monitor,
200 capture_driver_uid, playback_driver_uid, capture_latency, playback_latency) != 0) {
204 jack_log(
"JackPortAudioDriver::Open fInputDevice = %d, fOutputDevice %d", fInputDevice, fOutputDevice);
207 if (inchannels == 0) {
208 jack_log(
"JackPortAudioDriver::Open setup max in channels = %ld", in_max);
211 if (outchannels == 0) {
212 jack_log(
"JackPortAudioDriver::Open setup max out channels = %ld", out_max);
213 outchannels = out_max;
217 if (inchannels > in_max) {
218 jack_error(
"This device has only %d available input channels.", in_max);
221 if (outchannels > out_max) {
222 jack_error(
"This device has only %d available output channels.", out_max);
223 outchannels = out_max;
227 fCaptureChannels = inchannels;
228 fPlaybackChannels = outchannels;
230 err = OpenStream(buffer_size);
231 if (err != paNoError) {
237 fEngineControl->fPeriod = fEngineControl->fPeriodUsecs * 1000;
238 fEngineControl->fComputation = JackTools::ComputationMicroSec(fEngineControl->fBufferSize) * 1000;
239 fEngineControl->fConstraint = fEngineControl->fPeriodUsecs * 1000;
242 assert(strlen(capture_driver_uid) < JACK_CLIENT_NAME_SIZE);
243 assert(strlen(playback_driver_uid) < JACK_CLIENT_NAME_SIZE);
245 strcpy(fCaptureDriverName, capture_driver_uid);
246 strcpy(fPlaybackDriverName, playback_driver_uid);
251 JackAudioDriver::Close();
252 jack_error(
"Can't open default PortAudio device");
256 int JackPortAudioDriver::Close()
259 jack_log(
"JackPortAudioDriver::Close");
260 JackAudioDriver::Close();
262 if (err != paNoError) {
267 return (err != paNoError) ? -1 : 0;
270 int JackPortAudioDriver::Attach()
272 if (JackAudioDriver::Attach() == 0) {
276 #if defined(HAVE_ASIO)
277 if (fInputDevice !=
paNoDevice && fPaDevices->GetHostFromDevice(fInputDevice) ==
"ASIO") {
278 for (
int i = 0; i < fCaptureChannels; i++) {
280 JackPort* port = fGraphManager->GetPort(fCapturePortList[i]);
281 port->SetAlias(alias);
286 if (fOutputDevice !=
paNoDevice && fPaDevices->GetHostFromDevice(fOutputDevice) ==
"ASIO") {
287 for (
int i = 0; i < fPlaybackChannels; i++) {
289 JackPort* port = fGraphManager->GetPort(fPlaybackPortList[i]);
290 port->SetAlias(alias);
302 int JackPortAudioDriver::Start()
304 jack_log(
"JackPortAudioDriver::Start");
305 if (JackAudioDriver::Start() == 0) {
311 JackAudioDriver::Stop();
316 int JackPortAudioDriver::Stop()
318 jack_log(
"JackPortAudioDriver::Stop");
323 if (JackAudioDriver::Stop() < 0) {
326 return (err == paNoError) ? 0 : -1;
330 int JackPortAudioDriver::SetBufferSize(jack_nframes_t buffer_size)
343 err = OpenStream(buffer_size);
344 if (err != paNoError) {
348 JackAudioDriver::SetBufferSize(buffer_size);
364 #include "JackCompilerDeps.h"
372 desc = jack_driver_descriptor_construct(
"portaudio", JackDriverMaster,
"PortAudio API based audio backend", &filler);
375 jack_driver_descriptor_add_parameter(desc, &filler,
"channels",
'c', JackDriverParamUInt, &value, NULL,
"Maximum number of channels", NULL);
376 jack_driver_descriptor_add_parameter(desc, &filler,
"inchannels",
'i', JackDriverParamUInt, &value, NULL,
"Maximum number of input channels", NULL);
377 jack_driver_descriptor_add_parameter(desc, &filler,
"outchannels",
'o', JackDriverParamUInt, &value, NULL,
"Maximum number of output channels", NULL);
379 jack_driver_descriptor_add_parameter(desc, &filler,
"capture",
'C', JackDriverParamString, &value, NULL,
"Provide capture ports. Optionally set PortAudio device name", NULL);
381 jack_driver_descriptor_add_parameter(desc, &filler,
"playback",
'P', JackDriverParamString, &value, NULL,
"Provide playback ports. Optionally set PortAudio device name", NULL);
384 jack_driver_descriptor_add_parameter(desc, &filler,
"monitor",
'm', JackDriverParamBool, &value, NULL,
"Provide monitor ports for the output", NULL);
387 jack_driver_descriptor_add_parameter(desc, &filler,
"duplex",
'D', JackDriverParamBool, &value, NULL,
"Provide both capture and playback ports", NULL);
390 jack_driver_descriptor_add_parameter(desc, &filler,
"rate",
'r', JackDriverParamUInt, &value, NULL,
"Sample rate", NULL);
393 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");
395 jack_driver_descriptor_add_parameter(desc, &filler,
"device",
'd', JackDriverParamString, &value, NULL,
"PortAudio device name", NULL);
398 jack_driver_descriptor_add_parameter(desc, &filler,
"input-latency",
'I', JackDriverParamUInt, &value, NULL,
"Extra input latency", NULL);
399 jack_driver_descriptor_add_parameter(desc, &filler,
"output-latency",
'O', JackDriverParamUInt, &value, NULL,
"Extra output latency", NULL);
402 jack_driver_descriptor_add_parameter(desc, &filler,
"list-devices",
'l', JackDriverParamBool, &value, NULL,
"Display available PortAudio devices", NULL);
409 jack_nframes_t srate = 44100;
410 jack_nframes_t frames_per_interrupt = 512;
411 const char* capture_pcm_name =
"";
412 const char* playback_pcm_name =
"";
413 bool capture =
false;
414 bool playback =
false;
417 bool monitor =
false;
420 jack_nframes_t systemic_input_latency = 0;
421 jack_nframes_t systemic_output_latency = 0;
424 for (node = params; node; node = jack_slist_next(node))
428 switch (param->character) {
431 capture_pcm_name = param->value.str;
432 playback_pcm_name = param->value.str;
441 chan_in = chan_out = (int)param->value.ui;
445 chan_in = (
int)param->value.ui;
449 chan_out = (int)param->value.ui;
454 if (strcmp(param->value.str,
"none") != 0) {
455 capture_pcm_name = param->value.str;
461 if (strcmp(param->value.str,
"none") != 0) {
462 playback_pcm_name = param->value.str;
467 monitor = param->value.i;
471 srate = param->value.ui;
475 frames_per_interrupt = (
unsigned int)param->value.ui;
479 systemic_input_latency = param->value.ui;
483 systemic_output_latency = param->value.ui;
487 pa_devices->DisplayDevicesNames();
494 if (!capture && !playback) {
500 if (driver->Open(frames_per_interrupt, srate, capture, playback,
501 chan_in, chan_out, monitor, capture_pcm_name,
502 playback_pcm_name, systemic_input_latency,
503 systemic_output_latency) == 0) {
Inter process synchronization using using Mach semaphore.
Locked Engine, access to methods is serialized using a mutex.
PaError Pa_StopStream(PaStream *stream)
#define paOutputUnderflow
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.