Use SERVER_EXPORT for audioadapter.
[jack2.git] / linux / alsa / JackAlsaAdapter.cpp
blob0734d1e41e37727a352b5fddcb9e143a4913d868
1 /*
2 Copyright (C) 2008 Grame
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.
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.
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.
20 #if defined(HAVE_CONFIG_H)
21 #include "config.h"
22 #endif
24 #include "JackAlsaAdapter.h"
25 #include "JackServer.h"
26 #include "JackEngineControl.h"
28 namespace Jack
31 JackAlsaAdapter::JackAlsaAdapter ( jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params ) :
32 JackAudioAdapterInterface ( buffer_size, sample_rate ),
33 fThread ( this ),
34 fAudioInterface ( buffer_size, sample_rate )
36 const JSList* node;
37 const jack_driver_param_t* param;
39 fCaptureChannels = 2;
40 fPlaybackChannels = 2;
42 for ( node = params; node; node = jack_slist_next ( node ) )
44 param = ( const jack_driver_param_t* ) node->data;
46 switch ( param->character )
48 case 'i':
49 fCaptureChannels = param->value.ui;
50 break;
51 case 'o':
52 fPlaybackChannels = param->value.ui;
53 break;
54 case 'C':
55 break;
56 case 'P':
57 break;
58 case 'D':
59 break;
60 case 'n':
61 fAudioInterface.fPeriod = param->value.ui;
62 break;
63 case 'd':
64 fAudioInterface.fCardName = strdup ( param->value.str );
65 break;
66 case 'r':
67 SetAdaptedSampleRate ( param->value.ui );
68 break;
69 case 'p':
70 SetAdaptedBufferSize ( param->value.ui );
71 break;
75 fAudioInterface.setInputs ( fCaptureChannels );
76 fAudioInterface.setOutputs ( fPlaybackChannels );
79 int JackAlsaAdapter::Open()
81 //open audio interface
82 if ( fAudioInterface.open() )
83 return -1;
85 //start adapter thread
86 if ( fThread.StartSync() < 0 )
88 jack_error ( "Cannot start audioadapter thread" );
89 return -1;
92 //display card info
93 fAudioInterface.longinfo();
95 //turn the thread realtime
96 fThread.AcquireRealTime ( JackServer::fInstance->GetEngineControl()->fPriority );
98 return 0;
101 int JackAlsaAdapter::Close()
103 #ifdef JACK_MONITOR
104 fTable.Save();
105 #endif
106 switch ( fThread.GetStatus() )
109 // Kill the thread in Init phase
110 case JackThread::kStarting:
111 case JackThread::kIniting:
112 if ( fThread.Kill() < 0 )
114 jack_error ( "Cannot kill thread" );
115 return -1;
117 break;
119 // Stop when the thread cycle is finished
120 case JackThread::kRunning:
121 if ( fThread.Stop() < 0 )
123 jack_error ( "Cannot stop thread" );
124 return -1;
126 break;
128 default:
129 break;
131 return fAudioInterface.close();
134 bool JackAlsaAdapter::Init()
136 //fill the hardware buffers
137 for ( unsigned int i = 0; i < fAudioInterface.fPeriod; i++ )
138 fAudioInterface.write();
139 return true;
142 bool JackAlsaAdapter::Execute()
144 //read data from audio interface
145 if ( fAudioInterface.read() < 0 )
146 return false;
148 bool failure = false;
150 //compute resampling factor
151 jack_nframes_t time1, time2;
152 ResampleFactor ( time1, time2 );
154 //resample inputs
155 for ( int i = 0; i < fCaptureChannels; i++ )
157 fCaptureRingBuffer[i]->SetRatio ( time1, time2 );
158 if ( fCaptureRingBuffer[i]->WriteResample ( fAudioInterface.fInputSoftChannels[i], fAdaptedBufferSize ) < fAdaptedBufferSize )
159 failure = true;
161 //resample outputs
162 for ( int i = 0; i < fPlaybackChannels; i++ )
164 fPlaybackRingBuffer[i]->SetRatio ( time2, time1 );
165 if ( fPlaybackRingBuffer[i]->ReadResample ( fAudioInterface.fOutputSoftChannels[i], fAdaptedBufferSize ) < fAdaptedBufferSize )
166 failure = true;
169 #ifdef JACK_MONITOR
170 fTable.Write ( time1, time2, double ( time1 ) / double ( time2 ), double ( time2 ) / double ( time1 ),
171 fCaptureRingBuffer[0]->ReadSpace(), fPlaybackRingBuffer[0]->WriteSpace() );
172 #endif
174 //write data to audio interface
175 if ( fAudioInterface.write() < 0 )
176 return false;
178 //reset all ringbuffers in case of failure
179 if ( failure )
181 jack_error ( "JackAlsaAdapter::Execute ringbuffer failure... reset" );
182 ResetRingBuffers();
185 return true;
188 int JackAlsaAdapter::SetSampleRate ( jack_nframes_t sample_rate )
190 JackAudioAdapterInterface::SetHostSampleRate ( sample_rate );
191 Close();
192 return Open();
195 int JackAlsaAdapter::SetBufferSize ( jack_nframes_t buffer_size )
197 JackAudioAdapterInterface::SetHostBufferSize ( buffer_size );
198 Close();
199 return Open();
202 } // namespace
204 #ifdef __cplusplus
205 extern "C"
207 #endif
209 SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor()
211 jack_driver_desc_t *desc;
212 jack_driver_param_desc_t * params;
213 unsigned int i;
215 desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t));
217 strcpy(desc->name, "audioadapter"); // size MUST be less then JACK_DRIVER_NAME_MAX + 1
218 strcpy(desc->desc, "netjack audio <==> net backend adapter"); // size MUST be less then JACK_DRIVER_PARAM_DESC + 1
220 desc->nparams = 9;
221 params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t));
223 i = 0;
224 strcpy ( params[i].name, "capture" );
225 params[i].character = 'C';
226 params[i].type = JackDriverParamString;
227 strcpy ( params[i].value.str, "none" );
228 strcpy ( params[i].short_desc,
229 "Provide capture ports. Optionally set device" );
230 strcpy ( params[i].long_desc, params[i].short_desc );
232 i++;
233 strcpy ( params[i].name, "playback" );
234 params[i].character = 'P';
235 params[i].type = JackDriverParamString;
236 strcpy ( params[i].value.str, "none" );
237 strcpy ( params[i].short_desc,
238 "Provide playback ports. Optionally set device" );
239 strcpy ( params[i].long_desc, params[i].short_desc );
241 i++;
242 strcpy ( params[i].name, "device" );
243 params[i].character = 'd';
244 params[i].type = JackDriverParamString;
245 strcpy ( params[i].value.str, "hw:0" );
246 strcpy ( params[i].short_desc, "ALSA device name" );
247 strcpy ( params[i].long_desc, params[i].short_desc );
249 i++;
250 strcpy ( params[i].name, "rate" );
251 params[i].character = 'r';
252 params[i].type = JackDriverParamUInt;
253 params[i].value.ui = 48000U;
254 strcpy ( params[i].short_desc, "Sample rate" );
255 strcpy ( params[i].long_desc, params[i].short_desc );
257 i++;
258 strcpy ( params[i].name, "periodsize" );
259 params[i].character = 'p';
260 params[i].type = JackDriverParamUInt;
261 params[i].value.ui = 512U;
262 strcpy ( params[i].short_desc, "Period size" );
263 strcpy ( params[i].long_desc, params[i].short_desc );
265 i++;
266 strcpy ( params[i].name, "nperiods" );
267 params[i].character = 'n';
268 params[i].type = JackDriverParamUInt;
269 params[i].value.ui = 2U;
270 strcpy ( params[i].short_desc, "Number of periods of playback latency" );
271 strcpy ( params[i].long_desc, params[i].short_desc );
273 i++;
274 strcpy ( params[i].name, "duplex" );
275 params[i].character = 'D';
276 params[i].type = JackDriverParamBool;
277 params[i].value.i = 1;
278 strcpy ( params[i].short_desc,
279 "Provide both capture and playback ports" );
280 strcpy ( params[i].long_desc, params[i].short_desc );
282 i++;
283 strcpy ( params[i].name, "inchannels" );
284 params[i].character = 'i';
285 params[i].type = JackDriverParamUInt;
286 params[i].value.i = 0;
287 strcpy ( params[i].short_desc,
288 "Number of capture channels (defaults to hardware max)" );
289 strcpy ( params[i].long_desc, params[i].short_desc );
291 i++;
292 strcpy ( params[i].name, "outchannels" );
293 params[i].character = 'o';
294 params[i].type = JackDriverParamUInt;
295 params[i].value.i = 0;
296 strcpy ( params[i].short_desc,
297 "Number of playback channels (defaults to hardware max)" );
298 strcpy ( params[i].long_desc, params[i].short_desc );
300 desc->params = params;
301 return desc;
304 #ifdef __cplusplus
306 #endif