Jack2  1.9.12
JackPortAudioAdapter.cpp
1 /*
2 Copyright (C) 2008 Grame
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 
18 */
19 
20 #include "JackPortAudioAdapter.h"
21 #include "JackError.h"
22 
23 namespace Jack
24 {
25 
26  int JackPortAudioAdapter::Render(const void* inputBuffer,
27  void* outputBuffer,
28  unsigned long framesPerBuffer,
29  const PaStreamCallbackTimeInfo* timeInfo,
30  PaStreamCallbackFlags statusFlags,
31  void* userData)
32  {
33  static_cast<JackPortAudioAdapter*>(userData)->PushAndPull((jack_default_audio_sample_t**)inputBuffer, (jack_default_audio_sample_t**)outputBuffer, framesPerBuffer);
34  return paContinue;
35  }
36 
37  JackPortAudioAdapter::JackPortAudioAdapter(jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params)
38  : JackAudioAdapterInterface(buffer_size, sample_rate)
39  {
40  jack_log("JackPortAudioAdapter::JackPortAudioAdapter buffer_size = %d, sample_rate = %d", buffer_size, sample_rate);
41 
42  const JSList* node;
43  const jack_driver_param_t* param;
44  int in_max = 0;
45  int out_max = 0;
46 
47  fInputDevice = Pa_GetDefaultInputDevice();
48  fOutputDevice = Pa_GetDefaultOutputDevice();
49 
50  for (node = params; node; node = jack_slist_next(node)) {
51  param = (const jack_driver_param_t*) node->data;
52 
53  switch (param->character)
54  {
55  case 'i' :
56  fCaptureChannels = param->value.ui;
57  break;
58  case 'o' :
59  fPlaybackChannels = param->value.ui;
60  break;
61  case 'C' :
62  if (fPaDevices.GetInputDeviceFromName(param->value.str, fInputDevice, in_max) < 0) {
63  jack_error("Can't use %s, taking default input device", param->value.str);
64  fInputDevice = Pa_GetDefaultInputDevice();
65  }
66  break;
67  case 'P' :
68  if (fPaDevices.GetOutputDeviceFromName(param->value.str, fOutputDevice, out_max) < 0) {
69  jack_error("Can't use %s, taking default output device", param->value.str);
70  fOutputDevice = Pa_GetDefaultOutputDevice();
71  }
72  break;
73  case 'r' :
74  SetAdaptedSampleRate(param->value.ui);
75  break;
76  case 'p' :
77  SetAdaptedBufferSize(param->value.ui);
78  break;
79  case 'd' :
80  if (fPaDevices.GetInputDeviceFromName(param->value.str, fInputDevice, in_max) < 0)
81  jack_error("Can't use %s, taking default input device", param->value.str);
82  if (fPaDevices.GetOutputDeviceFromName(param->value.str, fOutputDevice, out_max) < 0)
83  jack_error("Can't use %s, taking default output device", param->value.str);
84  break;
85  case 'l' :
86  fPaDevices.DisplayDevicesNames();
87  break;
88  case 'q':
89  fQuality = param->value.ui;
90  break;
91  case 'g':
92  fRingbufferCurSize = param->value.ui;
93  fAdaptative = false;
94  break;
95  }
96  }
97 
98  //max channels
99  if (in_max == 0 && fInputDevice != paNoDevice)
100  in_max = fPaDevices.GetDeviceInfo(fInputDevice)->maxInputChannels;
101  if (out_max == 0 && fOutputDevice != paNoDevice)
102  out_max = fPaDevices.GetDeviceInfo(fOutputDevice)->maxOutputChannels;
103 
104  //effective channels
105  if ((fCaptureChannels == 0) || (fCaptureChannels > in_max))
106  fCaptureChannels = in_max;
107  if ((fPlaybackChannels == 0) || (fPlaybackChannels > out_max))
108  fPlaybackChannels = out_max;
109 
110  //set adapter interface channels
111  SetInputs(fCaptureChannels);
112  SetOutputs(fPlaybackChannels);
113  }
114 
115  int JackPortAudioAdapter::Open()
116  {
117  PaError err;
118  PaStreamParameters inputParameters;
119  PaStreamParameters outputParameters;
120 
121  if (fInputDevice == paNoDevice && fOutputDevice == paNoDevice) {
122  jack_error("No input and output device!!");
123  return -1;
124  }
125 
126  jack_log("JackPortAudioAdapter::Open fInputDevice = %d DeviceName %s", fInputDevice, fPaDevices.GetFullName(fInputDevice).c_str());
127  jack_log("JackPortAudioAdapter::Open fOutputDevice = %d DeviceName %s", fOutputDevice, fPaDevices.GetFullName(fOutputDevice).c_str());
128  jack_log("JackPortAudioAdapter::Open fAdaptedBufferSize = %u fAdaptedSampleRate %u", fAdaptedBufferSize, fAdaptedSampleRate);
129 
130  inputParameters.device = fInputDevice;
131  inputParameters.channelCount = fCaptureChannels;
132  inputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output
133  inputParameters.suggestedLatency = (fInputDevice != paNoDevice) // TODO: check how to setup this on ASIO
134  ? fPaDevices.GetDeviceInfo(fInputDevice)->defaultLowInputLatency
135  : 0;
136  inputParameters.hostApiSpecificStreamInfo = NULL;
137 
138  outputParameters.device = fOutputDevice;
139  outputParameters.channelCount = fPlaybackChannels;
140  outputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output
141  outputParameters.suggestedLatency = (fOutputDevice != paNoDevice) // TODO: check how to setup this on ASIO
142  ? fPaDevices.GetDeviceInfo(fOutputDevice)->defaultLowOutputLatency
143  : 0;
144  outputParameters.hostApiSpecificStreamInfo = NULL;
145 
146  err = Pa_OpenStream( &fStream,
147  (fInputDevice == paNoDevice) ? 0 : &inputParameters,
148  (fOutputDevice == paNoDevice) ? 0 : &outputParameters,
149  fAdaptedSampleRate,
150  fAdaptedBufferSize,
151  paNoFlag, // Clipping is on...
152  Render,
153  this);
154 
155  if (err != paNoError) {
156  jack_error("Pa_OpenStream error = %s", Pa_GetErrorText(err));
157  return -1;
158  }
159 
160  err = Pa_StartStream(fStream);
161 
162  if (err != paNoError) {
163  jack_error("Pa_StartStream error = %s", Pa_GetErrorText(err));
164  return -1;
165  }
166 
167  jack_log("JackPortAudioAdapter::Open OK");
168  return 0;
169  }
170 
171  int JackPortAudioAdapter::Close()
172  {
173 #ifdef JACK_MONITOR
174  fTable.Save(fHostBufferSize, fHostSampleRate, fAdaptedSampleRate, fAdaptedBufferSize);
175 #endif
176  jack_log("JackPortAudioAdapter::Close");
177  Pa_StopStream(fStream);
178  jack_log("JackPortAudioAdapter:: Pa_StopStream");
179  Pa_CloseStream(fStream);
180  jack_log("JackPortAudioAdapter:: Pa_CloseStream");
181  return 0;
182  }
183 
184  int JackPortAudioAdapter::SetSampleRate(jack_nframes_t sample_rate)
185  {
186  JackAudioAdapterInterface::SetHostSampleRate(sample_rate);
187  Close();
188  return Open();
189  }
190 
191  int JackPortAudioAdapter::SetBufferSize(jack_nframes_t buffer_size)
192  {
193  JackAudioAdapterInterface::SetHostBufferSize(buffer_size);
194  Close();
195  return Open();
196  }
197 
198 } // namespace
199 
200 #ifdef __cplusplus
201 extern "C"
202 {
203 #endif
204 
205  SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
206  {
207  jack_driver_desc_t * desc;
210 
211  desc = jack_driver_descriptor_construct("audioadapter", JackDriverNone, "netjack audio <==> net backend adapter", &filler);
212 
213  value.ui = 0;
214  jack_driver_descriptor_add_parameter(desc, &filler, "in-channels", 'i', JackDriverParamInt, &value, NULL, "Maximum number of input channels", NULL);
215  jack_driver_descriptor_add_parameter(desc, &filler, "out-channels", 'o', JackDriverParamInt, &value, NULL, "Maximum number of output channels", NULL);
216 
217  jack_driver_descriptor_add_parameter(desc, &filler, "capture", 'C', JackDriverParamString, &value, NULL, "Provide capture ports. Optionally set PortAudio device name", NULL);
218 
219  jack_driver_descriptor_add_parameter(desc, &filler, "playback", 'P', JackDriverParamString, &value, NULL, "Provide playback ports. Optionally set PortAudio device name", NULL);
220 
221  value.ui = 44100U;
222  jack_driver_descriptor_add_parameter(desc, &filler, "rate", 'r', JackDriverParamUInt, &value, NULL, "Sample rate", NULL);
223 
224  value.ui = 512U;
225  jack_driver_descriptor_add_parameter(desc, &filler, "periodsize", 'p', JackDriverParamUInt, &value, NULL, "Period size", NULL);
226 
227  jack_driver_descriptor_add_parameter(desc, &filler, "device", 'd', JackDriverParamString, &value, NULL, "PortAudio device name", NULL);
228 
229  value.i = true;
230  jack_driver_descriptor_add_parameter(desc, &filler, "list-devices", 'l', JackDriverParamBool, &value, NULL, "Display available PortAudio devices", NULL);
231 
232  value.ui = 0;
233  jack_driver_descriptor_add_parameter(desc, &filler, "quality", 'q', JackDriverParamInt, &value, NULL, "Resample algorithm quality (0 - 4)", NULL);
234 
235  value.ui = 32768;
236  jack_driver_descriptor_add_parameter(desc, &filler, "ring-buffer", 'g', JackDriverParamInt, &value, NULL, "Fixed ringbuffer size", "Fixed ringbuffer size (if not set => automatic adaptative)");
237 
238  return desc;
239  }
240 
241 #ifdef __cplusplus
242 }
243 #endif
244