Jack2  1.9.8
JackPortAudioAdapter.cpp
00001 /*
00002 Copyright (C) 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 "JackPortAudioAdapter.h"
00021 #include "JackError.h"
00022 
00023 namespace Jack
00024 {
00025 
00026     int JackPortAudioAdapter::Render(const void* inputBuffer,
00027                                     void* outputBuffer,
00028                                     unsigned long framesPerBuffer,
00029                                     const PaStreamCallbackTimeInfo* timeInfo,
00030                                     PaStreamCallbackFlags statusFlags,
00031                                     void* userData)
00032     {
00033         JackPortAudioAdapter* adapter = static_cast<JackPortAudioAdapter*>(userData);
00034         adapter->PushAndPull((jack_default_audio_sample_t**)inputBuffer, (jack_default_audio_sample_t**)outputBuffer, framesPerBuffer);
00035         return paContinue;
00036     }
00037 
00038     JackPortAudioAdapter::JackPortAudioAdapter(jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params)
00039             : JackAudioAdapterInterface(buffer_size, sample_rate)
00040     {
00041         jack_log("JackPortAudioAdapter::JackPortAudioAdapter buffer_size = %d, sample_rate = %d", buffer_size, sample_rate);
00042 
00043         const JSList* node;
00044         const jack_driver_param_t* param;
00045         int in_max = 0;
00046         int out_max = 0;
00047 
00048         fInputDevice = Pa_GetDefaultInputDevice();
00049         fOutputDevice = Pa_GetDefaultOutputDevice();
00050 
00051         for (node = params; node; node = jack_slist_next(node)) {
00052             param = (const jack_driver_param_t*) node->data;
00053 
00054             switch (param->character)
00055             {
00056             case 'i' :
00057                 fCaptureChannels = param->value.ui;
00058                 break;
00059             case 'o' :
00060                 fPlaybackChannels = param->value.ui;
00061                 break;
00062             case 'C' :
00063                 if (fPaDevices.GetInputDeviceFromName(param->value.str, fInputDevice, in_max) < 0) {
00064                     jack_error("Can't use %s, taking default input device", param->value.str);
00065                     fInputDevice = Pa_GetDefaultInputDevice();
00066                 }
00067                 break;
00068             case 'P' :
00069                 if (fPaDevices.GetOutputDeviceFromName(param->value.str, fOutputDevice, out_max) < 0) {
00070                     jack_error("Can't use %s, taking default output device", param->value.str);
00071                     fOutputDevice = Pa_GetDefaultOutputDevice();
00072                 }
00073                 break;
00074             case 'r' :
00075                 SetAdaptedSampleRate(param->value.ui);
00076                 break;
00077             case 'p' :
00078                 SetAdaptedBufferSize(param->value.ui);
00079                 break;
00080             case 'd' :
00081                 if (fPaDevices.GetInputDeviceFromName(param->value.str, fInputDevice, in_max) < 0)
00082                     jack_error("Can't use %s, taking default input device", param->value.str);
00083                 if (fPaDevices.GetOutputDeviceFromName(param->value.str, fOutputDevice, out_max) < 0)
00084                     jack_error("Can't use %s, taking default output device", param->value.str);
00085                 break;
00086             case 'l' :
00087                 fPaDevices.DisplayDevicesNames();
00088                 break;
00089             case 'q':
00090                 fQuality = param->value.ui;
00091                 break;
00092             case 'g':
00093                 fRingbufferCurSize = param->value.ui;
00094                 fAdaptative = false;
00095                 break;
00096             }
00097         }
00098 
00099         //max channels
00100         if (in_max == 0 && fInputDevice != paNoDevice)
00101             in_max = fPaDevices.GetDeviceInfo(fInputDevice)->maxInputChannels;
00102         if (out_max == 0 && fOutputDevice != paNoDevice)
00103             out_max = fPaDevices.GetDeviceInfo(fOutputDevice)->maxOutputChannels;
00104 
00105         //effective channels
00106         if ((fCaptureChannels == 0) || (fCaptureChannels > in_max))
00107             fCaptureChannels = in_max;
00108         if ((fPlaybackChannels == 0) || (fPlaybackChannels > out_max))
00109             fPlaybackChannels = out_max;
00110 
00111         //set adapter interface channels
00112         SetInputs(fCaptureChannels);
00113         SetOutputs(fPlaybackChannels);
00114     }
00115 
00116     int JackPortAudioAdapter::Open()
00117     {
00118         PaError err;
00119         PaStreamParameters inputParameters;
00120         PaStreamParameters outputParameters;
00121 
00122         if (fInputDevice == paNoDevice && fOutputDevice == paNoDevice) {
00123             jack_error("No input and output device!!");
00124             return -1;
00125         }
00126 
00127         jack_log("JackPortAudioAdapter::Open fInputDevice = %d DeviceName %s", fInputDevice, fPaDevices.GetFullName(fInputDevice).c_str());
00128         jack_log("JackPortAudioAdapter::Open fOutputDevice = %d DeviceName %s", fOutputDevice, fPaDevices.GetFullName(fOutputDevice).c_str());
00129         jack_log("JackPortAudioAdapter::Open fAdaptedBufferSize = %u fAdaptedSampleRate %u", fAdaptedBufferSize, fAdaptedSampleRate);
00130 
00131         inputParameters.device = fInputDevice;
00132         inputParameters.channelCount = fCaptureChannels;
00133         inputParameters.sampleFormat = paFloat32 | paNonInterleaved;            // 32 bit floating point output
00134         inputParameters.suggestedLatency = (fInputDevice != paNoDevice)   // TODO: check how to setup this on ASIO
00135                                            ? fPaDevices.GetDeviceInfo(fInputDevice)->defaultLowInputLatency
00136                                            : 0;
00137         inputParameters.hostApiSpecificStreamInfo = NULL;
00138 
00139         outputParameters.device = fOutputDevice;
00140         outputParameters.channelCount = fPlaybackChannels;
00141         outputParameters.sampleFormat = paFloat32 | paNonInterleaved;           // 32 bit floating point output
00142         outputParameters.suggestedLatency = (fOutputDevice != paNoDevice)       // TODO: check how to setup this on ASIO
00143                                             ? fPaDevices.GetDeviceInfo(fOutputDevice)->defaultLowOutputLatency
00144                                             : 0;
00145         outputParameters.hostApiSpecificStreamInfo = NULL;
00146 
00147         err = Pa_OpenStream( &fStream,
00148                            (fInputDevice == paNoDevice) ? 0 : &inputParameters,
00149                            (fOutputDevice == paNoDevice) ? 0 : &outputParameters,
00150                             fAdaptedSampleRate,
00151                             fAdaptedBufferSize,
00152                             paNoFlag,  // Clipping is on...
00153                             Render,
00154                             this);
00155 
00156         if (err != paNoError) {
00157             jack_error("Pa_OpenStream error = %s", Pa_GetErrorText(err));
00158             return -1;
00159         }
00160 
00161         err = Pa_StartStream(fStream);
00162 
00163         if (err != paNoError) {
00164             jack_error("Pa_StartStream error = %s", Pa_GetErrorText(err));
00165             return -1;
00166         }
00167 
00168         jack_log("JackPortAudioAdapter::Open OK");
00169         return 0;
00170     }
00171 
00172     int JackPortAudioAdapter::Close()
00173     {
00174 #ifdef JACK_MONITOR
00175         fTable.Save(fHostBufferSize, fHostSampleRate, fAdaptedSampleRate, fAdaptedBufferSize);
00176 #endif
00177         jack_log("JackPortAudioAdapter::Close");
00178         Pa_StopStream(fStream);
00179         jack_log("JackPortAudioAdapter:: Pa_StopStream");
00180         Pa_CloseStream(fStream);
00181         jack_log("JackPortAudioAdapter:: Pa_CloseStream");
00182         return 0;
00183     }
00184 
00185     int JackPortAudioAdapter::SetSampleRate(jack_nframes_t sample_rate)
00186     {
00187         JackAudioAdapterInterface::SetHostSampleRate(sample_rate);
00188         Close();
00189         return Open();
00190     }
00191 
00192     int JackPortAudioAdapter::SetBufferSize(jack_nframes_t buffer_size)
00193     {
00194         JackAudioAdapterInterface::SetHostBufferSize(buffer_size);
00195         Close();
00196         return Open();
00197     }
00198 
00199 } // namespace
00200 
00201 #ifdef __cplusplus
00202 extern "C"
00203 {
00204 #endif
00205 
00206     SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
00207     {
00208         jack_driver_desc_t * desc;
00209         jack_driver_desc_filler_t filler;
00210         jack_driver_param_value_t value;
00211 
00212         desc = jack_driver_descriptor_construct("audioadapter", JackDriverNone, "netjack audio <==> net backend adapter", &filler);
00213 
00214         value.ui = 0;
00215         jack_driver_descriptor_add_parameter(desc, &filler, "in-channels", 'i', JackDriverParamInt, &value, NULL, "Maximum number of input channels", NULL);
00216         jack_driver_descriptor_add_parameter(desc, &filler, "out-channels", 'o', JackDriverParamInt, &value, NULL, "Maximum number of output channels", NULL);
00217 
00218         strcpy(value.str, "default input device");
00219         jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Provide capture ports. Optionally set PortAudio device name", NULL);
00220 
00221         strcpy(value.str, "default output device");
00222         jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamString, &value, NULL, "Provide playback ports. Optionally set PortAudio device name", NULL);
00223 
00224         value.ui = 44100U;
00225         jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL);
00226 
00227         value.ui = 512U;
00228         jack_driver_descriptor_add_parameter(desc, &filler, "periodsize", 'p', JackDriverParamUInt, &value, NULL, "Period size", NULL);
00229 
00230         strcpy(value.str, "default device");
00231         jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "PortAudio device name", NULL);
00232 
00233         value.i = true;
00234         jack_driver_descriptor_add_parameter(desc, &filler, "list-devices", 'l', JackDriverParamBool, &value, NULL, "Display available PortAudio devices", NULL);
00235 
00236         value.ui = 0;
00237         jack_driver_descriptor_add_parameter(desc, &filler, "quality", 'q', JackDriverParamInt, &value, NULL, "Resample algorithm quality (0 - 4)", NULL);
00238 
00239         value.ui = 32768;
00240         jack_driver_descriptor_add_parameter(desc, &filler, "ring-buffer", 'g', JackDriverParamInt, &value, NULL, "Fixed ringbuffer size", "Fixed ringbuffer size (if not set => automatic adaptative)");
00241 
00242         return desc;
00243     }
00244 
00245 #ifdef __cplusplus
00246 }
00247 #endif
00248