Jack2 1.9.10
|
00001 /* 00002 Copyright (C) 2004-2008 Grame 00003 00004 This program is free software; you can redistribute it and/or modify 00005 it under the terms of the GNU General Public License as published by 00006 the Free Software Foundation; either version 2 of the License, or 00007 (at your option) any later version. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 00018 */ 00019 00020 #include "JackDriverLoader.h" 00021 #include "driver_interface.h" 00022 #include "JackPortAudioDriver.h" 00023 #include "JackEngineControl.h" 00024 #include "JackGraphManager.h" 00025 #include "JackError.h" 00026 #include "JackTime.h" 00027 #include "JackTools.h" 00028 #include "JackCompilerDeps.h" 00029 #include <iostream> 00030 #include <assert.h> 00031 00032 using namespace std; 00033 00034 namespace Jack 00035 { 00036 00037 int JackPortAudioDriver::Render(const void* inputBuffer, void* outputBuffer, 00038 unsigned long framesPerBuffer, 00039 const PaStreamCallbackTimeInfo* timeInfo, 00040 PaStreamCallbackFlags statusFlags, 00041 void* userData) 00042 { 00043 return static_cast<JackPortAudioDriver*>(userData)->Render(inputBuffer, outputBuffer, statusFlags); 00044 } 00045 00046 int JackPortAudioDriver::Render(const void* inputBuffer, void* outputBuffer, PaStreamCallbackFlags statusFlags) 00047 { 00048 fInputBuffer = (jack_default_audio_sample_t**)inputBuffer; 00049 fOutputBuffer = (jack_default_audio_sample_t**)outputBuffer; 00050 00051 if (statusFlags) { 00052 if (statusFlags & paOutputUnderflow) 00053 jack_error("JackPortAudioDriver::Render paOutputUnderflow"); 00054 if (statusFlags & paInputUnderflow) 00055 jack_error("JackPortAudioDriver::Render paInputUnderflow"); 00056 if (statusFlags & paOutputOverflow) 00057 jack_error("JackPortAudioDriver::Render paOutputOverflow"); 00058 if (statusFlags & paInputOverflow) 00059 jack_error("JackPortAudioDriver::Render paInputOverflow"); 00060 if (statusFlags & paPrimingOutput) 00061 jack_error("JackPortAudioDriver::Render paOutputUnderflow"); 00062 00063 if (statusFlags != paPrimingOutput) { 00064 jack_time_t cur_time = GetMicroSeconds(); 00065 NotifyXRun(cur_time, float(cur_time - fBeginDateUst)); // Better this value than nothing... 00066 } 00067 } 00068 00069 // Setup threaded based log function 00070 set_threaded_log_function(); 00071 CycleTakeBeginTime(); 00072 return (Process() == 0) ? paContinue : paAbort; 00073 } 00074 00075 int JackPortAudioDriver::Read() 00076 { 00077 for (int i = 0; i < fCaptureChannels; i++) { 00078 memcpy(GetInputBuffer(i), fInputBuffer[i], sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); 00079 } 00080 return 0; 00081 } 00082 00083 int JackPortAudioDriver::Write() 00084 { 00085 for (int i = 0; i < fPlaybackChannels; i++) { 00086 memcpy(fOutputBuffer[i], GetOutputBuffer(i), sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); 00087 } 00088 return 0; 00089 } 00090 00091 PaError JackPortAudioDriver::OpenStream(jack_nframes_t buffer_size) 00092 { 00093 PaStreamParameters inputParameters; 00094 PaStreamParameters outputParameters; 00095 00096 jack_log("JackPortAudioDriver::OpenStream buffer_size = %d", buffer_size); 00097 00098 // Update parameters 00099 inputParameters.device = fInputDevice; 00100 inputParameters.channelCount = fCaptureChannels; 00101 inputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point input 00102 inputParameters.suggestedLatency = (fInputDevice != paNoDevice) // TODO: check how to setup this on ASIO 00103 ? ((fPaDevices->GetHostFromDevice(fInputDevice) == "ASIO") ? 0 : Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency) 00104 : 0; 00105 inputParameters.hostApiSpecificStreamInfo = NULL; 00106 00107 outputParameters.device = fOutputDevice; 00108 outputParameters.channelCount = fPlaybackChannels; 00109 outputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output 00110 outputParameters.suggestedLatency = (fOutputDevice != paNoDevice) // TODO: check how to setup this on ASIO 00111 ? ((fPaDevices->GetHostFromDevice(fOutputDevice) == "ASIO") ? 0 : Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency) 00112 : 0; 00113 outputParameters.hostApiSpecificStreamInfo = NULL; 00114 00115 return Pa_OpenStream(&fStream, 00116 (fInputDevice == paNoDevice) ? 0 : &inputParameters, 00117 (fOutputDevice == paNoDevice) ? 0 : &outputParameters, 00118 fEngineControl->fSampleRate, 00119 buffer_size, 00120 paNoFlag, // Clipping is on... 00121 Render, 00122 this); 00123 } 00124 00125 void JackPortAudioDriver::UpdateLatencies() 00126 { 00127 jack_latency_range_t input_range; 00128 jack_latency_range_t output_range; 00129 jack_latency_range_t monitor_range; 00130 00131 const PaStreamInfo* info = Pa_GetStreamInfo(fStream); 00132 assert(info); 00133 00134 for (int i = 0; i < fCaptureChannels; i++) { 00135 input_range.max = input_range.min = fEngineControl->fBufferSize + (info->inputLatency * fEngineControl->fSampleRate) + fCaptureLatency; 00136 fGraphManager->GetPort(fCapturePortList[i])->SetLatencyRange(JackCaptureLatency, &input_range); 00137 } 00138 00139 for (int i = 0; i < fPlaybackChannels; i++) { 00140 output_range.max = output_range.min = (info->outputLatency * fEngineControl->fSampleRate) + fPlaybackLatency; 00141 if (fEngineControl->fSyncMode) { 00142 output_range.max = output_range.min += fEngineControl->fBufferSize; 00143 } else { 00144 output_range.max = output_range.min += fEngineControl->fBufferSize * 2; 00145 } 00146 fGraphManager->GetPort(fPlaybackPortList[i])->SetLatencyRange(JackPlaybackLatency, &output_range); 00147 if (fWithMonitorPorts) { 00148 monitor_range.min = monitor_range.max = fEngineControl->fBufferSize; 00149 fGraphManager->GetPort(fMonitorPortList[i])->SetLatencyRange(JackCaptureLatency, &monitor_range); 00150 } 00151 } 00152 } 00153 00154 int JackPortAudioDriver::Open(jack_nframes_t buffer_size, 00155 jack_nframes_t samplerate, 00156 bool capturing, 00157 bool playing, 00158 int inchannels, 00159 int outchannels, 00160 bool monitor, 00161 const char* capture_driver_uid, 00162 const char* playback_driver_uid, 00163 jack_nframes_t capture_latency, 00164 jack_nframes_t playback_latency) 00165 { 00166 int in_max = 0; 00167 int out_max = 0; 00168 PaError err = paNoError; 00169 00170 if (!fPaDevices) { 00171 fPaDevices = new PortAudioDevices(); 00172 } 00173 00174 fCaptureLatency = capture_latency; 00175 fPlaybackLatency = playback_latency; 00176 00177 jack_log("JackPortAudioDriver::Open nframes = %ld in = %ld out = %ld capture name = %s playback name = %s samplerate = %ld", 00178 buffer_size, inchannels, outchannels, capture_driver_uid, playback_driver_uid, samplerate); 00179 00180 // Get devices 00181 if (capturing) { 00182 if (fPaDevices->GetInputDeviceFromName(capture_driver_uid, fInputDevice, in_max) < 0) { 00183 goto error; 00184 } 00185 } 00186 if (playing) { 00187 if (fPaDevices->GetOutputDeviceFromName(playback_driver_uid, fOutputDevice, out_max) < 0) { 00188 goto error; 00189 } 00190 } 00191 00192 // If ASIO, request for preferred size (assuming fInputDevice and fOutputDevice are the same) 00193 if (buffer_size == 0) { 00194 buffer_size = fPaDevices->GetPreferredBufferSize(fInputDevice); 00195 jack_log("JackPortAudioDriver::Open preferred buffer_size = %d", buffer_size); 00196 } 00197 00198 // Generic JackAudioDriver Open 00199 if (JackAudioDriver::Open(buffer_size, samplerate, capturing, playing, inchannels, outchannels, monitor, 00200 capture_driver_uid, playback_driver_uid, capture_latency, playback_latency) != 0) { 00201 return -1; 00202 } 00203 00204 jack_log("JackPortAudioDriver::Open fInputDevice = %d, fOutputDevice %d", fInputDevice, fOutputDevice); 00205 00206 // Default channels number required 00207 if (inchannels == 0) { 00208 jack_log("JackPortAudioDriver::Open setup max in channels = %ld", in_max); 00209 inchannels = in_max; 00210 } 00211 if (outchannels == 0) { 00212 jack_log("JackPortAudioDriver::Open setup max out channels = %ld", out_max); 00213 outchannels = out_max; 00214 } 00215 00216 // Too many channels required, take max available 00217 if (inchannels > in_max) { 00218 jack_error("This device has only %d available input channels.", in_max); 00219 inchannels = in_max; 00220 } 00221 if (outchannels > out_max) { 00222 jack_error("This device has only %d available output channels.", out_max); 00223 outchannels = out_max; 00224 } 00225 00226 // Core driver may have changed the in/out values 00227 fCaptureChannels = inchannels; 00228 fPlaybackChannels = outchannels; 00229 00230 err = OpenStream(buffer_size); 00231 if (err != paNoError) { 00232 jack_error("Pa_OpenStream error = %s", Pa_GetErrorText(err)); 00233 goto error; 00234 } 00235 00236 #ifdef __APPLE__ 00237 fEngineControl->fPeriod = fEngineControl->fPeriodUsecs * 1000; 00238 fEngineControl->fComputation = JackTools::ComputationMicroSec(fEngineControl->fBufferSize) * 1000; 00239 fEngineControl->fConstraint = fEngineControl->fPeriodUsecs * 1000; 00240 #endif 00241 00242 assert(strlen(capture_driver_uid) < JACK_CLIENT_NAME_SIZE); 00243 assert(strlen(playback_driver_uid) < JACK_CLIENT_NAME_SIZE); 00244 00245 strcpy(fCaptureDriverName, capture_driver_uid); 00246 strcpy(fPlaybackDriverName, playback_driver_uid); 00247 00248 return 0; 00249 00250 error: 00251 JackAudioDriver::Close(); 00252 jack_error("Can't open default PortAudio device"); 00253 return -1; 00254 } 00255 00256 int JackPortAudioDriver::Close() 00257 { 00258 // Generic audio driver close 00259 jack_log("JackPortAudioDriver::Close"); 00260 JackAudioDriver::Close(); 00261 PaError err = Pa_CloseStream(fStream); 00262 if (err != paNoError) { 00263 jack_error("Pa_CloseStream error = %s", Pa_GetErrorText(err)); 00264 } 00265 delete fPaDevices; 00266 fPaDevices = NULL; 00267 return (err != paNoError) ? -1 : 0; 00268 } 00269 00270 int JackPortAudioDriver::Attach() 00271 { 00272 if (JackAudioDriver::Attach() == 0) { 00273 00274 const char* alias; 00275 00276 #if defined(HAVE_ASIO) 00277 if (fInputDevice != paNoDevice && fPaDevices->GetHostFromDevice(fInputDevice) == "ASIO") { 00278 for (int i = 0; i < fCaptureChannels; i++) { 00279 if (PaAsio_GetInputChannelName(fInputDevice, i, &alias) == paNoError) { 00280 JackPort* port = fGraphManager->GetPort(fCapturePortList[i]); 00281 port->SetAlias(alias); 00282 } 00283 } 00284 } 00285 00286 if (fOutputDevice != paNoDevice && fPaDevices->GetHostFromDevice(fOutputDevice) == "ASIO") { 00287 for (int i = 0; i < fPlaybackChannels; i++) { 00288 if (PaAsio_GetOutputChannelName(fOutputDevice, i, &alias) == paNoError) { 00289 JackPort* port = fGraphManager->GetPort(fPlaybackPortList[i]); 00290 port->SetAlias(alias); 00291 } 00292 } 00293 } 00294 #endif 00295 return 0; 00296 00297 } else { 00298 return -1; 00299 } 00300 } 00301 00302 int JackPortAudioDriver::Start() 00303 { 00304 jack_log("JackPortAudioDriver::Start"); 00305 if (JackAudioDriver::Start() == 0) { 00306 PaError err; 00307 if ((err = Pa_StartStream(fStream)) == paNoError) { 00308 return 0; 00309 } 00310 jack_error("Pa_StartStream error = %s", Pa_GetErrorText(err)); 00311 JackAudioDriver::Stop(); 00312 } 00313 return -1; 00314 } 00315 00316 int JackPortAudioDriver::Stop() 00317 { 00318 jack_log("JackPortAudioDriver::Stop"); 00319 PaError err; 00320 if ((err = Pa_StopStream(fStream)) != paNoError) { 00321 jack_error("Pa_StopStream error = %s", Pa_GetErrorText(err)); 00322 } 00323 if (JackAudioDriver::Stop() < 0) { 00324 return -1; 00325 } else { 00326 return (err == paNoError) ? 0 : -1; 00327 } 00328 } 00329 00330 int JackPortAudioDriver::SetBufferSize(jack_nframes_t buffer_size) 00331 { 00332 PaError err; 00333 00334 if (fStream && (err = Pa_CloseStream(fStream)) != paNoError) { 00335 jack_error("Pa_CloseStream error = %s", Pa_GetErrorText(err)); 00336 goto error; 00337 } 00338 00339 // It seems that some ASIO drivers (like ASIO4All) needs this to restart correctly; 00340 delete fPaDevices; 00341 fPaDevices = new PortAudioDevices(); 00342 00343 err = OpenStream(buffer_size); 00344 if (err != paNoError) { 00345 jack_error("Pa_OpenStream error = %s", Pa_GetErrorText(err)); 00346 goto error; 00347 } else { 00348 JackAudioDriver::SetBufferSize(buffer_size); // Generic change, never fails 00349 return 0; 00350 } 00351 00352 error: 00353 fStream = NULL; 00354 return -1; 00355 } 00356 00357 } // end of namespace 00358 00359 #ifdef __cplusplus 00360 extern "C" 00361 { 00362 #endif 00363 00364 #include "JackCompilerDeps.h" 00365 00366 SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() 00367 { 00368 jack_driver_desc_t * desc; 00369 jack_driver_desc_filler_t filler; 00370 jack_driver_param_value_t value; 00371 00372 desc = jack_driver_descriptor_construct("portaudio", JackDriverMaster, "PortAudio API based audio backend", &filler); 00373 00374 value.ui = 0; 00375 jack_driver_descriptor_add_parameter(desc, &filler, "channels", 'c', JackDriverParamUInt, &value, NULL, "Maximum number of channels", NULL); 00376 jack_driver_descriptor_add_parameter(desc, &filler, "inchannels", 'i', JackDriverParamUInt, &value, NULL, "Maximum number of input channels", NULL); 00377 jack_driver_descriptor_add_parameter(desc, &filler, "outchannels", 'o', JackDriverParamUInt, &value, NULL, "Maximum number of output channels", NULL); 00378 00379 jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Provide capture ports. Optionally set PortAudio device name", NULL); 00380 00381 jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamString, &value, NULL, "Provide playback ports. Optionally set PortAudio device name", NULL); 00382 00383 value.i = 0; 00384 jack_driver_descriptor_add_parameter(desc, &filler, "monitor", 'm', JackDriverParamBool, &value, NULL, "Provide monitor ports for the output", NULL); 00385 00386 value.i = true; 00387 jack_driver_descriptor_add_parameter(desc, &filler, "duplex", 'D', JackDriverParamBool, &value, NULL, "Provide both capture and playback ports", NULL); 00388 00389 value.ui = 44100U; 00390 jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL); 00391 00392 value.ui = 512U; 00393 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"); 00394 00395 jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "PortAudio device name", NULL); 00396 00397 value.ui = 0; 00398 jack_driver_descriptor_add_parameter(desc, &filler, "input-latency", 'I', JackDriverParamUInt, &value, NULL, "Extra input latency", NULL); 00399 jack_driver_descriptor_add_parameter(desc, &filler, "output-latency", 'O', JackDriverParamUInt, &value, NULL, "Extra output latency", NULL); 00400 00401 value.i = true; 00402 jack_driver_descriptor_add_parameter(desc, &filler, "list-devices", 'l', JackDriverParamBool, &value, NULL, "Display available PortAudio devices", NULL); 00403 00404 return desc; 00405 } 00406 00407 SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) 00408 { 00409 jack_nframes_t srate = 44100; 00410 jack_nframes_t frames_per_interrupt = 512; 00411 const char* capture_pcm_name = ""; 00412 const char* playback_pcm_name = ""; 00413 bool capture = false; 00414 bool playback = false; 00415 int chan_in = 0; 00416 int chan_out = 0; 00417 bool monitor = false; 00418 const JSList *node; 00419 const jack_driver_param_t *param; 00420 jack_nframes_t systemic_input_latency = 0; 00421 jack_nframes_t systemic_output_latency = 0; 00422 PortAudioDevices* pa_devices = new PortAudioDevices(); 00423 00424 for (node = params; node; node = jack_slist_next(node)) 00425 { 00426 param = (const jack_driver_param_t *) node->data; 00427 00428 switch (param->character) { 00429 00430 case 'd': 00431 capture_pcm_name = param->value.str; 00432 playback_pcm_name = param->value.str; 00433 break; 00434 00435 case 'D': 00436 capture = true; 00437 playback = true; 00438 break; 00439 00440 case 'c': 00441 chan_in = chan_out = (int)param->value.ui; 00442 break; 00443 00444 case 'i': 00445 chan_in = (int)param->value.ui; 00446 break; 00447 00448 case 'o': 00449 chan_out = (int)param->value.ui; 00450 break; 00451 00452 case 'C': 00453 capture = true; 00454 if (strcmp(param->value.str, "none") != 0) { 00455 capture_pcm_name = param->value.str; 00456 } 00457 break; 00458 00459 case 'P': 00460 playback = true; 00461 if (strcmp(param->value.str, "none") != 0) { 00462 playback_pcm_name = param->value.str; 00463 } 00464 break; 00465 00466 case 'm': 00467 monitor = param->value.i; 00468 break; 00469 00470 case 'r': 00471 srate = param->value.ui; 00472 break; 00473 00474 case 'p': 00475 frames_per_interrupt = (unsigned int)param->value.ui; 00476 break; 00477 00478 case 'I': 00479 systemic_input_latency = param->value.ui; 00480 break; 00481 00482 case 'O': 00483 systemic_output_latency = param->value.ui; 00484 break; 00485 00486 case 'l': 00487 pa_devices->DisplayDevicesNames(); 00488 // Stops the server in this case 00489 return NULL; 00490 } 00491 } 00492 00493 // duplex is the default 00494 if (!capture && !playback) { 00495 capture = true; 00496 playback = true; 00497 } 00498 00499 Jack::JackDriverClientInterface* driver = new Jack::JackPortAudioDriver("system", "portaudio", engine, table, pa_devices); 00500 if (driver->Open(frames_per_interrupt, srate, capture, playback, 00501 chan_in, chan_out, monitor, capture_pcm_name, 00502 playback_pcm_name, systemic_input_latency, 00503 systemic_output_latency) == 0) { 00504 return driver; 00505 } else { 00506 delete driver; 00507 return NULL; 00508 } 00509 } 00510 00511 #ifdef __cplusplus 00512 } 00513 #endif