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 JackPortAudioDriver* driver = (JackPortAudioDriver*)userData;
44 driver->fInputBuffer = (jack_default_audio_sample_t**)inputBuffer;
45 driver->fOutputBuffer = (jack_default_audio_sample_t**)outputBuffer;
51 jack_error(
"JackPortAudioDriver::Render paOutputUnderflow");
53 jack_error(
"JackPortAudioDriver::Render paInputUnderflow");
55 jack_error(
"JackPortAudioDriver::Render paOutputOverflow");
57 jack_error(
"JackPortAudioDriver::Render paInputOverflow");
59 jack_error(
"JackPortAudioDriver::Render paOutputUnderflow");
61 if (statusFlags != paPrimingOutput) {
62 jack_time_t cur_time = GetMicroSeconds();
63 driver->NotifyXRun(cur_time,
float(cur_time - driver->fBeginDateUst));
68 set_threaded_log_function();
69 driver->CycleTakeBeginTime();
70 return (driver->Process() == 0) ? paContinue : paAbort;
73 int JackPortAudioDriver::Read()
75 for (
int i = 0; i < fCaptureChannels; i++) {
76 memcpy(GetInputBuffer(i), fInputBuffer[i],
sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize);
81 int JackPortAudioDriver::Write()
83 for (
int i = 0; i < fPlaybackChannels; i++) {
84 memcpy(fOutputBuffer[i], GetOutputBuffer(i),
sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize);
89 PaError JackPortAudioDriver::OpenStream(jack_nframes_t buffer_size)
94 jack_log(
"JackPortAudioDriver::OpenStream buffer_size = %d", buffer_size);
97 inputParameters.
device = fInputDevice;
101 ? ((fPaDevices->GetHostFromDevice(fInputDevice) ==
"ASIO") ? 0 :
Pa_GetDeviceInfo(inputParameters.
device)->defaultLowInputLatency)
105 outputParameters.
device = fOutputDevice;
109 ? ((fPaDevices->GetHostFromDevice(fOutputDevice) ==
"ASIO") ? 0 :
Pa_GetDeviceInfo(outputParameters.
device)->defaultLowOutputLatency)
114 (fInputDevice ==
paNoDevice) ? 0 : &inputParameters,
115 (fOutputDevice ==
paNoDevice) ? 0 : &outputParameters,
116 fEngineControl->fSampleRate,
123 void JackPortAudioDriver::UpdateLatencies()
132 for (
int i = 0; i < fCaptureChannels; i++) {
133 input_range.
max = input_range.
min = fEngineControl->fBufferSize + (info->
inputLatency * fEngineControl->fSampleRate) + fCaptureLatency;
134 fGraphManager->GetPort(fCapturePortList[i])->SetLatencyRange(JackCaptureLatency, &input_range);
137 for (
int i = 0; i < fPlaybackChannels; i++) {
138 output_range.
max = output_range.
min = (info->
outputLatency * fEngineControl->fSampleRate) + fPlaybackLatency;
139 if (fEngineControl->fSyncMode) {
140 output_range.
max = output_range.
min += fEngineControl->fBufferSize;
142 output_range.
max = output_range.
min += fEngineControl->fBufferSize * 2;
144 fGraphManager->GetPort(fPlaybackPortList[i])->SetLatencyRange(JackPlaybackLatency, &output_range);
145 if (fWithMonitorPorts) {
146 monitor_range.
min = monitor_range.
max = fEngineControl->fBufferSize;
147 fGraphManager->GetPort(fMonitorPortList[i])->SetLatencyRange(JackCaptureLatency, &monitor_range);
152 int JackPortAudioDriver::Open(jack_nframes_t buffer_size,
153 jack_nframes_t samplerate,
159 const char* capture_driver_uid,
160 const char* playback_driver_uid,
161 jack_nframes_t capture_latency,
162 jack_nframes_t playback_latency)
168 fCaptureLatency = capture_latency;
169 fPlaybackLatency = playback_latency;
171 jack_log(
"JackPortAudioDriver::Open nframes = %ld in = %ld out = %ld capture name = %s playback name = %s samplerate = %ld",
172 buffer_size, inchannels, outchannels, capture_driver_uid, playback_driver_uid, samplerate);
176 if (fPaDevices->GetInputDeviceFromName(capture_driver_uid, fInputDevice, in_max) < 0) {
181 if (fPaDevices->GetOutputDeviceFromName(playback_driver_uid, fOutputDevice, out_max) < 0) {
187 if (buffer_size == 0) {
188 buffer_size = fPaDevices->GetPreferredBufferSize(fInputDevice);
189 jack_log(
"JackPortAudioDriver::Open preferred buffer_size = %d", buffer_size);
193 if (JackAudioDriver::Open(buffer_size, samplerate, capturing, playing, inchannels, outchannels, monitor,
194 capture_driver_uid, playback_driver_uid, capture_latency, playback_latency) != 0) {
198 jack_log(
"JackPortAudioDriver::Open fInputDevice = %d, fOutputDevice %d", fInputDevice, fOutputDevice);
201 if (inchannels == 0) {
202 jack_log(
"JackPortAudioDriver::Open setup max in channels = %ld", in_max);
205 if (outchannels == 0) {
206 jack_log(
"JackPortAudioDriver::Open setup max out channels = %ld", out_max);
207 outchannels = out_max;
211 if (inchannels > in_max) {
212 jack_error(
"This device has only %d available input channels.", in_max);
215 if (outchannels > out_max) {
216 jack_error(
"This device has only %d available output channels.", out_max);
217 outchannels = out_max;
221 fCaptureChannels = inchannels;
222 fPlaybackChannels = outchannels;
224 err = OpenStream(buffer_size);
225 if (err != paNoError) {
231 fEngineControl->fPeriod = fEngineControl->fPeriodUsecs * 1000;
232 fEngineControl->fComputation = JackTools::ComputationMicroSec(fEngineControl->fBufferSize) * 1000;
233 fEngineControl->fConstraint = fEngineControl->fPeriodUsecs * 1000;
236 assert(strlen(capture_driver_uid) < JACK_CLIENT_NAME_SIZE);
237 assert(strlen(playback_driver_uid) < JACK_CLIENT_NAME_SIZE);
239 strcpy(fCaptureDriverName, capture_driver_uid);
240 strcpy(fPlaybackDriverName, playback_driver_uid);
245 JackAudioDriver::Close();
246 jack_error(
"Can't open default PortAudio device");
250 int JackPortAudioDriver::Close()
253 jack_log(
"JackPortAudioDriver::Close");
254 int res = JackAudioDriver::Close();
258 int JackPortAudioDriver::Attach()
260 if (JackAudioDriver::Attach() == 0) {
264 if (fInputDevice !=
paNoDevice && fPaDevices->GetHostFromDevice(fInputDevice) ==
"ASIO") {
265 for (
int i = 0; i < fCaptureChannels; i++) {
267 JackPort* port = fGraphManager->GetPort(fCapturePortList[i]);
268 port->SetAlias(alias);
273 if (fOutputDevice !=
paNoDevice && fPaDevices->GetHostFromDevice(fOutputDevice) ==
"ASIO") {
274 for (
int i = 0; i < fPlaybackChannels; i++) {
276 JackPort* port = fGraphManager->GetPort(fPlaybackPortList[i]);
277 port->SetAlias(alias);
289 int JackPortAudioDriver::Start()
291 jack_log(
"JackPortAudioDriver::Start");
292 if (JackAudioDriver::Start() >= 0) {
296 JackAudioDriver::Stop();
301 int JackPortAudioDriver::Stop()
303 jack_log(
"JackPortAudioDriver::Stop");
305 if (JackAudioDriver::Stop() < 0) {
311 int JackPortAudioDriver::SetBufferSize(jack_nframes_t buffer_size)
320 err = OpenStream(buffer_size);
321 if (err != paNoError) {
325 JackAudioDriver::SetBufferSize(buffer_size);
337 #include "JackCompilerDeps.h"
345 desc = jack_driver_descriptor_construct(
"portaudio", JackDriverMaster,
"PortAudio API based audio backend", &filler);
348 jack_driver_descriptor_add_parameter(desc, &filler,
"channels",
'c', JackDriverParamUInt, &value, NULL,
"Maximum number of channels", NULL);
349 jack_driver_descriptor_add_parameter(desc, &filler,
"inchannels",
'i', JackDriverParamUInt, &value, NULL,
"Maximum number of input channels", NULL);
350 jack_driver_descriptor_add_parameter(desc, &filler,
"outchannels",
'o', JackDriverParamUInt, &value, NULL,
"Maximum number of output channels", NULL);
352 jack_driver_descriptor_add_parameter(desc, &filler,
"capture",
'C', JackDriverParamString, &value, NULL,
"Provide capture ports. Optionally set PortAudio device name", NULL);
354 jack_driver_descriptor_add_parameter(desc, &filler,
"playback",
'P', JackDriverParamString, &value, NULL,
"Provide playback ports. Optionally set PortAudio device name", NULL);
357 jack_driver_descriptor_add_parameter(desc, &filler,
"monitor",
'm', JackDriverParamBool, &value, NULL,
"Provide monitor ports for the output", NULL);
360 jack_driver_descriptor_add_parameter(desc, &filler,
"duplex",
'D', JackDriverParamBool, &value, NULL,
"Provide both capture and playback ports", NULL);
363 jack_driver_descriptor_add_parameter(desc, &filler,
"rate",
'r', JackDriverParamUInt, &value, NULL,
"Sample rate", NULL);
366 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");
368 jack_driver_descriptor_add_parameter(desc, &filler,
"device",
'd', JackDriverParamString, &value, NULL,
"PortAudio device name", NULL);
371 jack_driver_descriptor_add_parameter(desc, &filler,
"input-latency",
'I', JackDriverParamUInt, &value, NULL,
"Extra input latency", NULL);
372 jack_driver_descriptor_add_parameter(desc, &filler,
"output-latency",
'O', JackDriverParamUInt, &value, NULL,
"Extra output latency", NULL);
375 jack_driver_descriptor_add_parameter(desc, &filler,
"list-devices",
'l', JackDriverParamBool, &value, NULL,
"Display available PortAudio devices", NULL);
382 jack_nframes_t srate = 44100;
383 jack_nframes_t frames_per_interrupt = 512;
384 const char* capture_pcm_name =
"";
385 const char* playback_pcm_name =
"";
386 bool capture =
false;
387 bool playback =
false;
390 bool monitor =
false;
393 jack_nframes_t systemic_input_latency = 0;
394 jack_nframes_t systemic_output_latency = 0;
397 for (node = params; node; node = jack_slist_next(node))
401 switch (param->character) {
404 capture_pcm_name = param->value.str;
405 playback_pcm_name = param->value.str;
414 chan_in = chan_out = (int)param->value.ui;
418 chan_in = (
int)param->value.ui;
422 chan_out = (int)param->value.ui;
427 if (strcmp(param->value.str,
"none") != 0) {
428 capture_pcm_name = param->value.str;
434 if (strcmp(param->value.str,
"none") != 0) {
435 playback_pcm_name = param->value.str;
440 monitor = param->value.i;
444 srate = param->value.ui;
448 frames_per_interrupt = (
unsigned int)param->value.ui;
452 systemic_input_latency = param->value.ui;
456 systemic_output_latency = param->value.ui;
460 pa_devices->DisplayDevicesNames();
467 if (!capture && !playback) {
473 if (driver->Open(frames_per_interrupt, srate, capture, playback,
474 chan_in, chan_out, monitor, capture_pcm_name,
475 playback_pcm_name, systemic_input_latency,
476 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.