Jack2 1.9.7
|
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 "JackError.h" 00025 #include "JackTime.h" 00026 #include "JackCompilerDeps.h" 00027 #include <iostream> 00028 #include <assert.h> 00029 00030 using namespace std; 00031 00032 namespace Jack 00033 { 00034 int JackPortAudioDriver::Render(const void* inputBuffer, void* outputBuffer, 00035 unsigned long framesPerBuffer, 00036 const PaStreamCallbackTimeInfo* timeInfo, 00037 PaStreamCallbackFlags statusFlags, 00038 void* userData) 00039 { 00040 JackPortAudioDriver* driver = (JackPortAudioDriver*)userData; 00041 driver->fInputBuffer = (jack_default_audio_sample_t**)inputBuffer; 00042 driver->fOutputBuffer = (jack_default_audio_sample_t**)outputBuffer; 00043 // Setup threadded based log function 00044 set_threaded_log_function(); 00045 driver->CycleTakeBeginTime(); 00046 return (driver->Process() == 0) ? paContinue : paAbort; 00047 } 00048 00049 int JackPortAudioDriver::Read() 00050 { 00051 for (int i = 0; i < fCaptureChannels; i++) 00052 memcpy(GetInputBuffer(i), fInputBuffer[i], sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); 00053 return 0; 00054 } 00055 00056 int JackPortAudioDriver::Write() 00057 { 00058 for (int i = 0; i < fPlaybackChannels; i++) 00059 memcpy(fOutputBuffer[i], GetOutputBuffer(i), sizeof(jack_default_audio_sample_t) * fEngineControl->fBufferSize); 00060 return 0; 00061 } 00062 00063 int JackPortAudioDriver::Open(jack_nframes_t buffer_size, 00064 jack_nframes_t samplerate, 00065 bool capturing, 00066 bool playing, 00067 int inchannels, 00068 int outchannels, 00069 bool monitor, 00070 const char* capture_driver_uid, 00071 const char* playback_driver_uid, 00072 jack_nframes_t capture_latency, 00073 jack_nframes_t playback_latency) 00074 { 00075 PaError err = paNoError; 00076 PaStreamParameters inputParameters; 00077 PaStreamParameters outputParameters; 00078 int in_max = 0; 00079 int out_max = 0; 00080 00081 jack_log("JackPortAudioDriver::Open nframes = %ld in = %ld out = %ld capture name = %s playback name = %s samplerate = %ld", 00082 buffer_size, inchannels, outchannels, capture_driver_uid, playback_driver_uid, samplerate); 00083 00084 // Generic JackAudioDriver Open 00085 if (JackAudioDriver::Open(buffer_size, samplerate, capturing, playing, inchannels, outchannels, monitor, capture_driver_uid, playback_driver_uid, capture_latency, playback_latency) != 0) 00086 return -1; 00087 00088 //get devices 00089 if (capturing) 00090 { 00091 if (fPaDevices->GetInputDeviceFromName(capture_driver_uid, fInputDevice, in_max) < 0) 00092 goto error; 00093 } 00094 if (playing) 00095 { 00096 if (fPaDevices->GetOutputDeviceFromName(playback_driver_uid, fOutputDevice, out_max) < 0) 00097 goto error; 00098 } 00099 00100 jack_log("JackPortAudioDriver::Open fInputDevice = %d, fOutputDevice %d", fInputDevice, fOutputDevice); 00101 00102 //default channels number required 00103 if (inchannels == 0) 00104 { 00105 jack_log("JackPortAudioDriver::Open setup max in channels = %ld", in_max); 00106 inchannels = in_max; 00107 } 00108 if (outchannels == 0) 00109 { 00110 jack_log("JackPortAudioDriver::Open setup max out channels = %ld", out_max); 00111 outchannels = out_max; 00112 } 00113 00114 //too many channels required, take max available 00115 if (inchannels > in_max) 00116 { 00117 jack_error("This device has only %d available input channels.", in_max); 00118 inchannels = in_max; 00119 } 00120 if (outchannels > out_max) 00121 { 00122 jack_error("This device has only %d available output channels.", out_max); 00123 outchannels = out_max; 00124 } 00125 00126 //in/out streams parametering 00127 inputParameters.device = fInputDevice; 00128 inputParameters.channelCount = inchannels; 00129 inputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output 00130 inputParameters.suggestedLatency = (fInputDevice != paNoDevice) // TODO: check how to setup this on ASIO 00131 ? fPaDevices->GetDeviceInfo(fInputDevice)->defaultLowInputLatency 00132 : 0; 00133 inputParameters.hostApiSpecificStreamInfo = NULL; 00134 00135 outputParameters.device = fOutputDevice; 00136 outputParameters.channelCount = outchannels; 00137 outputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output 00138 outputParameters.suggestedLatency = (fOutputDevice != paNoDevice) // TODO: check how to setup this on ASIO 00139 ? fPaDevices->GetDeviceInfo(fOutputDevice)->defaultLowOutputLatency 00140 : 0; 00141 outputParameters.hostApiSpecificStreamInfo = NULL; 00142 00143 err = Pa_OpenStream(&fStream, 00144 (fInputDevice == paNoDevice) ? 0 : &inputParameters, 00145 (fOutputDevice == paNoDevice) ? 0 : &outputParameters, 00146 samplerate, 00147 buffer_size, 00148 paNoFlag, // Clipping is on... 00149 Render, 00150 this); 00151 if (err != paNoError) 00152 { 00153 jack_error("Pa_OpenStream error = %s", Pa_GetErrorText(err)); 00154 goto error; 00155 } 00156 00157 #ifdef __APPLE__ 00158 fEngineControl->fPeriod = fEngineControl->fPeriodUsecs * 1000; 00159 fEngineControl->fComputation = 500 * 1000; 00160 fEngineControl->fConstraint = fEngineControl->fPeriodUsecs * 1000; 00161 #endif 00162 00163 // Core driver may have changed the in/out values 00164 fCaptureChannels = inchannels; 00165 fPlaybackChannels = outchannels; 00166 00167 assert(strlen(capture_driver_uid) < JACK_CLIENT_NAME_SIZE); 00168 assert(strlen(playback_driver_uid) < JACK_CLIENT_NAME_SIZE); 00169 00170 strcpy(fCaptureDriverName, capture_driver_uid); 00171 strcpy(fPlaybackDriverName, playback_driver_uid); 00172 00173 return 0; 00174 00175 error: 00176 JackAudioDriver::Close(); 00177 jack_error("Can't open default PortAudio device : %s", Pa_GetErrorText(err)); 00178 return -1; 00179 } 00180 00181 int JackPortAudioDriver::Close() 00182 { 00183 // Generic audio driver close 00184 int res = JackAudioDriver::Close(); 00185 00186 jack_log("JackPortAudioDriver::Close"); 00187 Pa_CloseStream(fStream); 00188 return res; 00189 } 00190 00191 int JackPortAudioDriver::Start() 00192 { 00193 jack_log("JackPortAudioDriver::Start"); 00194 if (JackAudioDriver::Start() >= 0) { 00195 PaError err = Pa_StartStream(fStream); 00196 if (err == paNoError) { 00197 return 0; 00198 } 00199 JackAudioDriver::Stop(); 00200 } 00201 return -1; 00202 } 00203 00204 int JackPortAudioDriver::Stop() 00205 { 00206 jack_log("JackPortAudioDriver::Stop"); 00207 PaError err = Pa_StopStream(fStream); 00208 int res = (err == paNoError) ? 0 : -1; 00209 if (JackAudioDriver::Stop() < 0) { 00210 res = -1; 00211 } 00212 return res; 00213 } 00214 00215 int JackPortAudioDriver::SetBufferSize(jack_nframes_t buffer_size) 00216 { 00217 PaError err; 00218 PaStreamParameters inputParameters; 00219 PaStreamParameters outputParameters; 00220 00221 if ((err = Pa_CloseStream(fStream)) != paNoError) 00222 { 00223 jack_error("Pa_CloseStream error = %s", Pa_GetErrorText(err)); 00224 return -1; 00225 } 00226 00227 //change parametering 00228 inputParameters.device = fInputDevice; 00229 inputParameters.channelCount = fCaptureChannels; 00230 inputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output 00231 inputParameters.suggestedLatency = (fInputDevice != paNoDevice) // TODO: check how to setup this on ASIO 00232 ? Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency 00233 : 0; 00234 inputParameters.hostApiSpecificStreamInfo = NULL; 00235 00236 outputParameters.device = fOutputDevice; 00237 outputParameters.channelCount = fPlaybackChannels; 00238 outputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output 00239 outputParameters.suggestedLatency = (fOutputDevice != paNoDevice) // TODO: check how to setup this on ASIO 00240 ? Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency 00241 : 0; 00242 outputParameters.hostApiSpecificStreamInfo = NULL; 00243 00244 err = Pa_OpenStream(&fStream, 00245 (fInputDevice == paNoDevice) ? 0 : &inputParameters, 00246 (fOutputDevice == paNoDevice) ? 0 : &outputParameters, 00247 fEngineControl->fSampleRate, 00248 buffer_size, 00249 paNoFlag, // Clipping is on... 00250 Render, 00251 this); 00252 00253 if (err != paNoError) 00254 { 00255 jack_error("Pa_OpenStream error = %s", Pa_GetErrorText(err)); 00256 return -1; 00257 } 00258 else 00259 { 00260 // Only done when success 00261 return JackAudioDriver::SetBufferSize(buffer_size); // never fails 00262 } 00263 } 00264 00265 } // end of namespace 00266 00267 #ifdef __cplusplus 00268 extern "C" 00269 { 00270 #endif 00271 00272 #include "JackCompilerDeps.h" 00273 00274 SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor() 00275 { 00276 jack_driver_desc_t *desc; 00277 unsigned int i; 00278 desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t)); 00279 00280 strcpy(desc->name, "portaudio"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1 00281 strcpy(desc->desc, "PortAudio API based audio backend"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1 00282 00283 desc->nparams = 13; 00284 desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t)); 00285 00286 i = 0; 00287 strcpy(desc->params[i].name, "channels"); 00288 desc->params[i].character = 'c'; 00289 desc->params[i].type = JackDriverParamInt; 00290 desc->params[i].value.ui = 0; 00291 strcpy(desc->params[i].short_desc, "Maximum number of channels"); 00292 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 00293 00294 i++; 00295 strcpy(desc->params[i].name, "inchannels"); 00296 desc->params[i].character = 'i'; 00297 desc->params[i].type = JackDriverParamInt; 00298 desc->params[i].value.ui = 0; 00299 strcpy(desc->params[i].short_desc, "Maximum number of input channels"); 00300 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 00301 00302 i++; 00303 strcpy(desc->params[i].name, "outchannels"); 00304 desc->params[i].character = 'o'; 00305 desc->params[i].type = JackDriverParamInt; 00306 desc->params[i].value.ui = 0; 00307 strcpy(desc->params[i].short_desc, "Maximum number of output channels"); 00308 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 00309 00310 i++; 00311 strcpy(desc->params[i].name, "capture"); 00312 desc->params[i].character = 'C'; 00313 desc->params[i].type = JackDriverParamString; 00314 strcpy(desc->params[i].value.str, "will take default PortAudio input device"); 00315 strcpy(desc->params[i].short_desc, "Provide capture ports. Optionally set PortAudio device name"); 00316 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 00317 00318 i++; 00319 strcpy(desc->params[i].name, "playback"); 00320 desc->params[i].character = 'P'; 00321 desc->params[i].type = JackDriverParamString; 00322 strcpy(desc->params[i].value.str, "will take default PortAudio output device"); 00323 strcpy(desc->params[i].short_desc, "Provide playback ports. Optionally set PortAudio device name"); 00324 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 00325 00326 i++; 00327 strcpy (desc->params[i].name, "monitor"); 00328 desc->params[i].character = 'm'; 00329 desc->params[i].type = JackDriverParamBool; 00330 desc->params[i].value.i = 0; 00331 strcpy(desc->params[i].short_desc, "Provide monitor ports for the output"); 00332 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 00333 00334 i++; 00335 strcpy(desc->params[i].name, "duplex"); 00336 desc->params[i].character = 'D'; 00337 desc->params[i].type = JackDriverParamBool; 00338 desc->params[i].value.i = TRUE; 00339 strcpy(desc->params[i].short_desc, "Provide both capture and playback ports"); 00340 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 00341 00342 i++; 00343 strcpy(desc->params[i].name, "rate"); 00344 desc->params[i].character = 'r'; 00345 desc->params[i].type = JackDriverParamUInt; 00346 desc->params[i].value.ui = 44100U; 00347 strcpy(desc->params[i].short_desc, "Sample rate"); 00348 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 00349 00350 i++; 00351 strcpy(desc->params[i].name, "period"); 00352 desc->params[i].character = 'p'; 00353 desc->params[i].type = JackDriverParamUInt; 00354 desc->params[i].value.ui = 128U; 00355 strcpy(desc->params[i].short_desc, "Frames per period"); 00356 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 00357 00358 i++; 00359 strcpy(desc->params[i].name, "device"); 00360 desc->params[i].character = 'd'; 00361 desc->params[i].type = JackDriverParamString; 00362 strcpy(desc->params[i].value.str, "will take default PortAudio device name"); 00363 strcpy(desc->params[i].short_desc, "PortAudio device name"); 00364 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 00365 00366 i++; 00367 strcpy(desc->params[i].name, "input-latency"); 00368 desc->params[i].character = 'I'; 00369 desc->params[i].type = JackDriverParamUInt; 00370 desc->params[i].value.i = 0; 00371 strcpy(desc->params[i].short_desc, "Extra input latency"); 00372 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 00373 00374 i++; 00375 strcpy(desc->params[i].name, "output-latency"); 00376 desc->params[i].character = 'O'; 00377 desc->params[i].type = JackDriverParamUInt; 00378 desc->params[i].value.i = 0; 00379 strcpy(desc->params[i].short_desc, "Extra output latency"); 00380 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 00381 00382 i++; 00383 strcpy(desc->params[i].name, "list-devices"); 00384 desc->params[i].character = 'l'; 00385 desc->params[i].type = JackDriverParamBool; 00386 desc->params[i].value.i = TRUE; 00387 strcpy(desc->params[i].short_desc, "Display available PortAudio devices"); 00388 strcpy(desc->params[i].long_desc, desc->params[i].short_desc); 00389 00390 return desc; 00391 } 00392 00393 SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params) 00394 { 00395 jack_nframes_t srate = 44100; 00396 jack_nframes_t frames_per_interrupt = 512; 00397 const char* capture_pcm_name = ""; 00398 const char* playback_pcm_name = ""; 00399 bool capture = false; 00400 bool playback = false; 00401 int chan_in = 0; 00402 int chan_out = 0; 00403 bool monitor = false; 00404 const JSList *node; 00405 const jack_driver_param_t *param; 00406 jack_nframes_t systemic_input_latency = 0; 00407 jack_nframes_t systemic_output_latency = 0; 00408 PortAudioDevices* pa_devices = new PortAudioDevices(); 00409 00410 for (node = params; node; node = jack_slist_next(node)) 00411 { 00412 param = (const jack_driver_param_t *) node->data; 00413 00414 switch (param->character) 00415 { 00416 00417 case 'd': 00418 capture_pcm_name = param->value.str; 00419 playback_pcm_name = param->value.str; 00420 break; 00421 00422 case 'D': 00423 capture = true; 00424 playback = true; 00425 break; 00426 00427 case 'c': 00428 chan_in = chan_out = (int)param->value.ui; 00429 break; 00430 00431 case 'i': 00432 chan_in = (int)param->value.ui; 00433 break; 00434 00435 case 'o': 00436 chan_out = (int)param->value.ui; 00437 break; 00438 00439 case 'C': 00440 capture = true; 00441 if (strcmp(param->value.str, "none") != 0) { 00442 capture_pcm_name = param->value.str; 00443 } 00444 break; 00445 00446 case 'P': 00447 playback = TRUE; 00448 if (strcmp(param->value.str, "none") != 0) { 00449 playback_pcm_name = param->value.str; 00450 } 00451 break; 00452 00453 case 'm': 00454 monitor = param->value.i; 00455 break; 00456 00457 case 'r': 00458 srate = param->value.ui; 00459 break; 00460 00461 case 'p': 00462 frames_per_interrupt = (unsigned int)param->value.ui; 00463 break; 00464 00465 case 'I': 00466 systemic_input_latency = param->value.ui; 00467 break; 00468 00469 case 'O': 00470 systemic_output_latency = param->value.ui; 00471 break; 00472 00473 case 'l': 00474 pa_devices->DisplayDevicesNames(); 00475 break; 00476 } 00477 } 00478 00479 // duplex is the default 00480 if (!capture && !playback) { 00481 capture = true; 00482 playback = true; 00483 } 00484 00485 Jack::JackDriverClientInterface* driver = new Jack::JackPortAudioDriver("system", "portaudio", engine, table, pa_devices); 00486 if (driver->Open(frames_per_interrupt, srate, capture, playback, chan_in, chan_out, monitor, capture_pcm_name, playback_pcm_name, systemic_input_latency, systemic_output_latency) == 0) 00487 { 00488 return driver; 00489 } 00490 else 00491 { 00492 delete driver; 00493 return NULL; 00494 } 00495 } 00496 00497 #ifdef __cplusplus 00498 } 00499 #endif