Jack2 1.9.7

JackPortAudioDriver.cpp

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