Jack2 1.9.6

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 = (float**)inputBuffer;
00042         driver->fOutputBuffer = (float**)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(float) * 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(float) * 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         int res = JackAudioDriver::Close();
00184         jack_log("JackPortAudioDriver::Close");
00185         Pa_CloseStream(fStream);
00186         return res;
00187     }
00188 
00189     int JackPortAudioDriver::Start()
00190     {
00191         jack_log("JackPortAudioDriver::Start");
00192         JackAudioDriver::Start();
00193         PaError err = Pa_StartStream(fStream);
00194         return (err == paNoError) ? 0 : -1;
00195     }
00196 
00197     int JackPortAudioDriver::Stop()
00198     {
00199         jack_log("JackPortAudioDriver::Stop");
00200         PaError err = Pa_StopStream(fStream);
00201         return (err == paNoError) ? 0 : -1;
00202     }
00203 
00204     int JackPortAudioDriver::SetBufferSize(jack_nframes_t buffer_size)
00205     {
00206         PaError err;
00207         PaStreamParameters inputParameters;
00208         PaStreamParameters outputParameters;
00209 
00210         if ((err = Pa_CloseStream(fStream)) != paNoError)
00211         {
00212             jack_error("Pa_CloseStream error = %s", Pa_GetErrorText(err));
00213             return -1;
00214         }
00215 
00216         //change parametering
00217         inputParameters.device = fInputDevice;
00218         inputParameters.channelCount = fCaptureChannels;
00219         inputParameters.sampleFormat = paFloat32 | paNonInterleaved;            // 32 bit floating point output
00220         inputParameters.suggestedLatency = (fInputDevice != paNoDevice)         // TODO: check how to setup this on ASIO
00221                                            ? Pa_GetDeviceInfo(inputParameters.device)->defaultLowInputLatency
00222                                            : 0;
00223         inputParameters.hostApiSpecificStreamInfo = NULL;
00224 
00225         outputParameters.device = fOutputDevice;
00226         outputParameters.channelCount = fPlaybackChannels;
00227         outputParameters.sampleFormat = paFloat32 | paNonInterleaved;           // 32 bit floating point output
00228         outputParameters.suggestedLatency = (fOutputDevice != paNoDevice)       // TODO: check how to setup this on ASIO
00229                                             ? Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency
00230                                             : 0;
00231         outputParameters.hostApiSpecificStreamInfo = NULL;
00232 
00233         err = Pa_OpenStream(&fStream,
00234                             (fInputDevice == paNoDevice) ? 0 : &inputParameters,
00235                             (fOutputDevice == paNoDevice) ? 0 : &outputParameters,
00236                             fEngineControl->fSampleRate,
00237                             buffer_size,
00238                             paNoFlag,  // Clipping is on...
00239                             Render,
00240                             this);
00241 
00242         if (err != paNoError)
00243         {
00244             jack_error("Pa_OpenStream error = %s", Pa_GetErrorText(err));
00245             return -1;
00246         }
00247         else
00248         {
00249             // Only done when success
00250             return JackAudioDriver::SetBufferSize(buffer_size); // never fails
00251         }
00252     }
00253 
00254 } // end of namespace
00255 
00256 #ifdef __cplusplus
00257 extern "C"
00258 {
00259 #endif
00260 
00261 #include "JackCompilerDeps.h"
00262 
00263     SERVER_EXPORT jack_driver_desc_t* driver_get_descriptor()
00264     {
00265         jack_driver_desc_t *desc;
00266         unsigned int i;
00267         desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t));
00268 
00269         strcpy(desc->name, "portaudio");                             // size MUST be less then JACK_DRIVER_NAME_MAX + 1
00270         strcpy(desc->desc, "PortAudio API based audio backend");     // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
00271 
00272         desc->nparams = 13;
00273         desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t));
00274 
00275         i = 0;
00276         strcpy(desc->params[i].name, "channels");
00277         desc->params[i].character = 'c';
00278         desc->params[i].type = JackDriverParamInt;
00279         desc->params[i].value.ui = 0;
00280         strcpy(desc->params[i].short_desc, "Maximum number of channels");
00281         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
00282 
00283         i++;
00284         strcpy(desc->params[i].name, "inchannels");
00285         desc->params[i].character = 'i';
00286         desc->params[i].type = JackDriverParamInt;
00287         desc->params[i].value.ui = 0;
00288         strcpy(desc->params[i].short_desc, "Maximum number of input channels");
00289         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
00290 
00291         i++;
00292         strcpy(desc->params[i].name, "outchannels");
00293         desc->params[i].character = 'o';
00294         desc->params[i].type = JackDriverParamInt;
00295         desc->params[i].value.ui = 0;
00296         strcpy(desc->params[i].short_desc, "Maximum number of output channels");
00297         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
00298 
00299         i++;
00300         strcpy(desc->params[i].name, "capture");
00301         desc->params[i].character = 'C';
00302         desc->params[i].type = JackDriverParamString;
00303         strcpy(desc->params[i].value.str, "will take default PortAudio input device");
00304         strcpy(desc->params[i].short_desc, "Provide capture ports. Optionally set PortAudio device name");
00305         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
00306 
00307         i++;
00308         strcpy(desc->params[i].name, "playback");
00309         desc->params[i].character = 'P';
00310         desc->params[i].type = JackDriverParamString;
00311         strcpy(desc->params[i].value.str, "will take default PortAudio output device");
00312         strcpy(desc->params[i].short_desc, "Provide playback ports. Optionally set PortAudio device name");
00313         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
00314 
00315         i++;
00316         strcpy (desc->params[i].name, "monitor");
00317         desc->params[i].character = 'm';
00318         desc->params[i].type = JackDriverParamBool;
00319         desc->params[i].value.i = 0;
00320         strcpy(desc->params[i].short_desc, "Provide monitor ports for the output");
00321         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
00322 
00323         i++;
00324         strcpy(desc->params[i].name, "duplex");
00325         desc->params[i].character = 'D';
00326         desc->params[i].type = JackDriverParamBool;
00327         desc->params[i].value.i = TRUE;
00328         strcpy(desc->params[i].short_desc, "Provide both capture and playback ports");
00329         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
00330 
00331         i++;
00332         strcpy(desc->params[i].name, "rate");
00333         desc->params[i].character = 'r';
00334         desc->params[i].type = JackDriverParamUInt;
00335         desc->params[i].value.ui = 44100U;
00336         strcpy(desc->params[i].short_desc, "Sample rate");
00337         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
00338 
00339         i++;
00340         strcpy(desc->params[i].name, "period");
00341         desc->params[i].character = 'p';
00342         desc->params[i].type = JackDriverParamUInt;
00343         desc->params[i].value.ui = 128U;
00344         strcpy(desc->params[i].short_desc, "Frames per period");
00345         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
00346 
00347         i++;
00348         strcpy(desc->params[i].name, "device");
00349         desc->params[i].character = 'd';
00350         desc->params[i].type = JackDriverParamString;
00351         strcpy(desc->params[i].value.str, "will take default PortAudio device name");
00352         strcpy(desc->params[i].short_desc, "PortAudio device name");
00353         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
00354 
00355         i++;
00356         strcpy(desc->params[i].name, "input-latency");
00357         desc->params[i].character = 'I';
00358         desc->params[i].type = JackDriverParamUInt;
00359         desc->params[i].value.i = 0;
00360         strcpy(desc->params[i].short_desc, "Extra input latency");
00361         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
00362 
00363         i++;
00364         strcpy(desc->params[i].name, "output-latency");
00365         desc->params[i].character = 'O';
00366         desc->params[i].type = JackDriverParamUInt;
00367         desc->params[i].value.i = 0;
00368         strcpy(desc->params[i].short_desc, "Extra output latency");
00369         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
00370 
00371         i++;
00372         strcpy(desc->params[i].name, "list-devices");
00373         desc->params[i].character = 'l';
00374         desc->params[i].type = JackDriverParamBool;
00375         desc->params[i].value.i = TRUE;
00376         strcpy(desc->params[i].short_desc, "Display available PortAudio devices");
00377         strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
00378 
00379         return desc;
00380     }
00381 
00382     SERVER_EXPORT Jack::JackDriverClientInterface* driver_initialize(Jack::JackLockedEngine* engine, Jack::JackSynchro* table, const JSList* params)
00383     {
00384         jack_nframes_t srate = 44100;
00385         jack_nframes_t frames_per_interrupt = 512;
00386         const char* capture_pcm_name = "";
00387         const char* playback_pcm_name = "";
00388         bool capture = false;
00389         bool playback = false;
00390         int chan_in = 0;
00391         int chan_out = 0;
00392         bool monitor = false;
00393         const JSList *node;
00394         const jack_driver_param_t *param;
00395         jack_nframes_t systemic_input_latency = 0;
00396         jack_nframes_t systemic_output_latency = 0;
00397         PortAudioDevices* pa_devices = new PortAudioDevices();
00398 
00399         for (node = params; node; node = jack_slist_next(node))
00400         {
00401             param = (const jack_driver_param_t *) node->data;
00402 
00403             switch (param->character)
00404             {
00405 
00406             case 'd':
00407                 capture_pcm_name = param->value.str;
00408                 playback_pcm_name = param->value.str;
00409                 break;
00410 
00411             case 'D':
00412                 capture = true;
00413                 playback = true;
00414                 break;
00415 
00416             case 'c':
00417                 chan_in = chan_out = (int)param->value.ui;
00418                 break;
00419 
00420             case 'i':
00421                 chan_in = (int)param->value.ui;
00422                 break;
00423 
00424             case 'o':
00425                 chan_out = (int)param->value.ui;
00426                 break;
00427 
00428             case 'C':
00429                 capture = true;
00430                 if (strcmp(param->value.str, "none") != 0) {
00431                     capture_pcm_name = param->value.str;
00432                 }
00433                 break;
00434 
00435             case 'P':
00436                 playback = TRUE;
00437                 if (strcmp(param->value.str, "none") != 0) {
00438                     playback_pcm_name = param->value.str;
00439                 }
00440                 break;
00441 
00442             case 'm':
00443                 monitor = param->value.i;
00444                 break;
00445 
00446             case 'r':
00447                 srate = param->value.ui;
00448                 break;
00449 
00450             case 'p':
00451                 frames_per_interrupt = (unsigned int)param->value.ui;
00452                 break;
00453 
00454             case 'I':
00455                 systemic_input_latency = param->value.ui;
00456                 break;
00457 
00458             case 'O':
00459                 systemic_output_latency = param->value.ui;
00460                 break;
00461 
00462             case 'l':
00463                 pa_devices->DisplayDevicesNames();
00464                 break;
00465             }
00466         }
00467 
00468         // duplex is the default
00469         if (!capture && !playback) {
00470             capture = true;
00471             playback = true;
00472         }
00473 
00474         Jack::JackDriverClientInterface* driver = new Jack::JackPortAudioDriver("system", "portaudio", engine, table, pa_devices);
00475         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)
00476         {
00477             return driver;
00478         }
00479         else
00480         {
00481             delete driver;
00482             return NULL;
00483         }
00484     }
00485 
00486 #ifdef __cplusplus
00487 }
00488 #endif