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