00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef __JackAlsaAdapter__
00021 #define __JackAlsaAdapter__
00022
00023 #include <math.h>
00024 #include <limits.h>
00025 #include <assert.h>
00026 #include <alsa/asoundlib.h>
00027 #include "JackAudioAdapterInterface.h"
00028 #include "JackPlatformPlug.h"
00029 #include "JackError.h"
00030 #include "jack.h"
00031 #include "jslist.h"
00032
00033 namespace Jack
00034 {
00035
00036 inline void* aligned_calloc ( size_t nmemb, size_t size ) { return ( void* ) calloc ( nmemb, size ); }
00037
00038 #define max(x,y) (((x)>(y)) ? (x) : (y))
00039 #define min(x,y) (((x)<(y)) ? (x) : (y))
00040
00041 #define check_error(err) if (err) { jack_error("%s:%d, alsa error %d : %s", __FILE__, __LINE__, err, snd_strerror(err)); return err; }
00042 #define check_error_msg(err,msg) if (err) { jack_error("%s:%d, %s : %s(%d)", __FILE__, __LINE__, msg, snd_strerror(err), err); return err; }
00043 #define display_error_msg(err,msg) if (err) { jack_error("%s:%d, %s : %s(%d)", __FILE__, __LINE__, msg, snd_strerror(err), err); }
00044
00048 class AudioParam
00049 {
00050 public:
00051 const char* fCardName;
00052 unsigned int fFrequency;
00053 int fBuffering;
00054
00055 unsigned int fSoftInputs;
00056 unsigned int fSoftOutputs;
00057
00058 public:
00059 AudioParam() :
00060 fCardName ( "hw:0" ),
00061 fFrequency ( 44100 ),
00062 fBuffering ( 512 ),
00063 fSoftInputs ( 2 ),
00064 fSoftOutputs ( 2 )
00065 {}
00066
00067 AudioParam ( jack_nframes_t buffer_size, jack_nframes_t sample_rate ) :
00068 fCardName ( "hw:0" ),
00069 fFrequency ( sample_rate ),
00070 fBuffering ( buffer_size ),
00071 fSoftInputs ( 2 ),
00072 fSoftOutputs ( 2 )
00073 {}
00074
00075 AudioParam& cardName ( const char* n )
00076 {
00077 fCardName = n;
00078 return *this;
00079 }
00080
00081 AudioParam& frequency ( int f )
00082 {
00083 fFrequency = f;
00084 return *this;
00085 }
00086
00087 AudioParam& buffering ( int fpb )
00088 {
00089 fBuffering = fpb;
00090 return *this;
00091 }
00092
00093 void setInputs ( int inputs )
00094 {
00095 fSoftInputs = inputs;
00096 }
00097
00098 AudioParam& inputs ( int n )
00099 {
00100 fSoftInputs = n;
00101 return *this;
00102 }
00103
00104 void setOutputs ( int outputs )
00105 {
00106 fSoftOutputs = outputs;
00107 }
00108
00109 AudioParam& outputs ( int n )
00110 {
00111 fSoftOutputs = n;
00112 return *this;
00113 }
00114 };
00115
00119 class AudioInterface : public AudioParam
00120 {
00121 public:
00122
00123 snd_pcm_t* fOutputDevice;
00124 snd_pcm_t* fInputDevice;
00125 snd_pcm_hw_params_t* fInputParams;
00126 snd_pcm_hw_params_t* fOutputParams;
00127
00128
00129 snd_pcm_format_t fSampleFormat;
00130 snd_pcm_access_t fSampleAccess;
00131
00132
00133 const char* fCaptureName;
00134 const char* fPlaybackName;
00135 unsigned int fCardInputs;
00136 unsigned int fCardOutputs;
00137
00138
00139 unsigned int fPeriod;
00140
00141
00142 void* fInputCardBuffer;
00143 void* fOutputCardBuffer;
00144
00145
00146 void* fInputCardChannels[256];
00147 void* fOutputCardChannels[256];
00148
00149
00150 jack_default_audio_sample_t* fInputSoftChannels[256];
00151 jack_default_audio_sample_t* fOutputSoftChannels[256];
00152
00153
00154
00155 const char* cardName()
00156 {
00157 return fCardName;
00158 }
00159
00160 int frequency()
00161 {
00162 return fFrequency;
00163 }
00164
00165 int buffering()
00166 {
00167 return fBuffering;
00168 }
00169
00170 jack_default_audio_sample_t** inputSoftChannels()
00171 {
00172 return fInputSoftChannels;
00173 }
00174
00175 jack_default_audio_sample_t** outputSoftChannels()
00176 {
00177 return fOutputSoftChannels;
00178 }
00179
00180 AudioInterface ( const AudioParam& ap = AudioParam() ) : AudioParam ( ap )
00181 {
00182 fInputDevice = 0;
00183 fOutputDevice = 0;
00184 fInputParams = 0;
00185 fOutputParams = 0;
00186 fPeriod = 2;
00187 fCaptureName = NULL;
00188 fPlaybackName = NULL;
00189
00190 fInputCardBuffer = 0;
00191 fOutputCardBuffer = 0;
00192
00193 for ( int i = 0; i < 256; i++ )
00194 {
00195 fInputCardChannels[i] = 0;
00196 fOutputCardChannels[i] = 0;
00197 fInputSoftChannels[i] = 0;
00198 fOutputSoftChannels[i] = 0;
00199 }
00200 }
00201
00202 AudioInterface ( jack_nframes_t buffer_size, jack_nframes_t sample_rate ) :
00203 AudioParam ( buffer_size, sample_rate )
00204 {
00205 fInputCardBuffer = 0;
00206 fOutputCardBuffer = 0;
00207 fCaptureName = NULL;
00208 fPlaybackName = NULL;
00209
00210 for ( int i = 0; i < 256; i++ )
00211 {
00212 fInputCardChannels[i] = 0;
00213 fOutputCardChannels[i] = 0;
00214 fInputSoftChannels[i] = 0;
00215 fOutputSoftChannels[i] = 0;
00216 }
00217 }
00218
00222 int open()
00223 {
00224
00225 check_error ( snd_pcm_open ( &fInputDevice, (fCaptureName == NULL) ? fCardName : fCaptureName, SND_PCM_STREAM_CAPTURE, 0 ) );
00226 check_error ( snd_pcm_open ( &fOutputDevice, (fPlaybackName == NULL) ? fCardName : fPlaybackName, SND_PCM_STREAM_PLAYBACK, 0 ) );
00227
00228
00229 check_error ( snd_pcm_hw_params_malloc ( &fInputParams ) );
00230 setAudioParams ( fInputDevice, fInputParams );
00231
00232
00233 check_error ( snd_pcm_hw_params_malloc ( &fOutputParams ) )
00234 setAudioParams ( fOutputDevice, fOutputParams );
00235
00236
00237 fCardInputs = fSoftInputs;
00238 fCardOutputs = fSoftOutputs;
00239
00240 snd_pcm_hw_params_set_channels_near(fInputDevice, fInputParams, &fCardInputs);
00241 snd_pcm_hw_params_set_channels_near(fOutputDevice, fOutputParams, &fCardOutputs);
00242
00243
00244 check_error ( snd_pcm_hw_params ( fInputDevice, fInputParams ) );
00245 check_error ( snd_pcm_hw_params ( fOutputDevice, fOutputParams ) );
00246
00247
00248 if ( fSampleAccess == SND_PCM_ACCESS_RW_INTERLEAVED )
00249 {
00250 fInputCardBuffer = aligned_calloc ( interleavedBufferSize ( fInputParams ), 1 );
00251 fOutputCardBuffer = aligned_calloc ( interleavedBufferSize ( fOutputParams ), 1 );
00252 }
00253 else
00254 {
00255 for ( unsigned int i = 0; i < fCardInputs; i++ )
00256 fInputCardChannels[i] = aligned_calloc ( noninterleavedBufferSize ( fInputParams ), 1 );
00257 for ( unsigned int i = 0; i < fCardOutputs; i++ )
00258 fOutputCardChannels[i] = aligned_calloc ( noninterleavedBufferSize ( fOutputParams ), 1 );
00259 }
00260
00261
00262 fSoftInputs = max ( fSoftInputs, fCardInputs );
00263 assert ( fSoftInputs < 256 );
00264 fSoftOutputs = max ( fSoftOutputs, fCardOutputs );
00265 assert ( fSoftOutputs < 256 );
00266
00267 for ( unsigned int i = 0; i < fSoftInputs; i++ )
00268 {
00269 fInputSoftChannels[i] = ( jack_default_audio_sample_t* ) aligned_calloc ( fBuffering, sizeof ( jack_default_audio_sample_t ) );
00270 for ( int j = 0; j < fBuffering; j++ )
00271 fInputSoftChannels[i][j] = 0.0;
00272 }
00273
00274 for ( unsigned int i = 0; i < fSoftOutputs; i++ )
00275 {
00276 fOutputSoftChannels[i] = ( jack_default_audio_sample_t* ) aligned_calloc ( fBuffering, sizeof ( jack_default_audio_sample_t ) );
00277 for ( int j = 0; j < fBuffering; j++ )
00278 fOutputSoftChannels[i][j] = 0.0;
00279 }
00280 return 0;
00281 }
00282
00283 int close()
00284 {
00285 snd_pcm_hw_params_free ( fInputParams );
00286 snd_pcm_hw_params_free ( fOutputParams );
00287 snd_pcm_close ( fInputDevice );
00288 snd_pcm_close ( fOutputDevice );
00289
00290 for ( unsigned int i = 0; i < fSoftInputs; i++ )
00291 if ( fInputSoftChannels[i] )
00292 free ( fInputSoftChannels[i] );
00293
00294 for ( unsigned int i = 0; i < fSoftOutputs; i++ )
00295 if ( fOutputSoftChannels[i] )
00296 free ( fOutputSoftChannels[i] );
00297
00298 for ( unsigned int i = 0; i < fCardInputs; i++ )
00299 if ( fInputCardChannels[i] )
00300 free ( fInputCardChannels[i] );
00301
00302 for ( unsigned int i = 0; i < fCardOutputs; i++ )
00303 if ( fOutputCardChannels[i] )
00304 free ( fOutputCardChannels[i] );
00305
00306 if ( fInputCardBuffer )
00307 free ( fInputCardBuffer );
00308 if ( fOutputCardBuffer )
00309 free ( fOutputCardBuffer );
00310
00311 return 0;
00312 }
00313
00314 int setAudioParams ( snd_pcm_t* stream, snd_pcm_hw_params_t* params )
00315 {
00316
00317 check_error_msg ( snd_pcm_hw_params_any ( stream, params ), "unable to init parameters" )
00318
00319
00320 if ( snd_pcm_hw_params_set_access ( stream, params, SND_PCM_ACCESS_RW_NONINTERLEAVED ) )
00321 check_error_msg ( snd_pcm_hw_params_set_access ( stream, params, SND_PCM_ACCESS_RW_INTERLEAVED ),
00322 "unable to set access mode neither to non-interleaved or to interleaved" );
00323 snd_pcm_hw_params_get_access ( params, &fSampleAccess );
00324
00325
00326 if ( snd_pcm_hw_params_set_format ( stream, params, SND_PCM_FORMAT_S32 ) )
00327 check_error_msg ( snd_pcm_hw_params_set_format ( stream, params, SND_PCM_FORMAT_S16 ),
00328 "unable to set format to either 32-bits or 16-bits" );
00329 snd_pcm_hw_params_get_format ( params, &fSampleFormat );
00330
00331
00332 snd_pcm_hw_params_set_rate_near ( stream, params, &fFrequency, 0 );
00333
00334
00335 check_error_msg ( snd_pcm_hw_params_set_period_size ( stream, params, fBuffering, 0 ), "period size not available" );
00336 check_error_msg ( snd_pcm_hw_params_set_periods ( stream, params, fPeriod, 0 ), "number of periods not available" );
00337
00338 return 0;
00339 }
00340
00341 ssize_t interleavedBufferSize ( snd_pcm_hw_params_t* params )
00342 {
00343 _snd_pcm_format format;
00344 unsigned int channels;
00345 snd_pcm_hw_params_get_format ( params, &format );
00346 snd_pcm_uframes_t psize;
00347 snd_pcm_hw_params_get_period_size ( params, &psize, NULL );
00348 snd_pcm_hw_params_get_channels ( params, &channels );
00349 ssize_t bsize = snd_pcm_format_size ( format, psize * channels );
00350 return bsize;
00351 }
00352
00353 ssize_t noninterleavedBufferSize ( snd_pcm_hw_params_t* params )
00354 {
00355 _snd_pcm_format format;
00356 snd_pcm_hw_params_get_format ( params, &format );
00357 snd_pcm_uframes_t psize;
00358 snd_pcm_hw_params_get_period_size ( params, &psize, NULL );
00359 ssize_t bsize = snd_pcm_format_size ( format, psize );
00360 return bsize;
00361 }
00362
00367 int read()
00368 {
00369 int count, s;
00370 unsigned int c;
00371 switch ( fSampleAccess )
00372 {
00373 case SND_PCM_ACCESS_RW_INTERLEAVED :
00374 count = snd_pcm_readi ( fInputDevice, fInputCardBuffer, fBuffering );
00375 if ( count < 0 )
00376 {
00377 display_error_msg ( count, "reading samples" );
00378 check_error_msg ( snd_pcm_prepare ( fInputDevice ), "preparing input stream" );
00379 }
00380 if ( fSampleFormat == SND_PCM_FORMAT_S16 )
00381 {
00382 short* buffer16b = ( short* ) fInputCardBuffer;
00383 for ( s = 0; s < fBuffering; s++ )
00384 for ( c = 0; c < fCardInputs; c++ )
00385 fInputSoftChannels[c][s] = jack_default_audio_sample_t(buffer16b[c + s*fCardInputs]) * (jack_default_audio_sample_t(1.0)/jack_default_audio_sample_t(SHRT_MAX));
00386 }
00387 else
00388 {
00389 int32_t* buffer32b = ( int32_t* ) fInputCardBuffer;
00390 for ( s = 0; s < fBuffering; s++ )
00391 for ( c = 0; c < fCardInputs; c++ )
00392 fInputSoftChannels[c][s] = jack_default_audio_sample_t(buffer32b[c + s*fCardInputs]) * (jack_default_audio_sample_t(1.0)/jack_default_audio_sample_t(INT_MAX));
00393 }
00394 break;
00395 case SND_PCM_ACCESS_RW_NONINTERLEAVED :
00396 count = snd_pcm_readn ( fInputDevice, fInputCardChannels, fBuffering );
00397 if ( count < 0 )
00398 {
00399 display_error_msg ( count, "reading samples" );
00400 check_error_msg ( snd_pcm_prepare ( fInputDevice ), "preparing input stream" );
00401 }
00402 if ( fSampleFormat == SND_PCM_FORMAT_S16 )
00403 {
00404 short* chan16b;
00405 for ( c = 0; c < fCardInputs; c++ )
00406 {
00407 chan16b = ( short* ) fInputCardChannels[c];
00408 for ( s = 0; s < fBuffering; s++ )
00409 fInputSoftChannels[c][s] = jack_default_audio_sample_t(chan16b[s]) * (jack_default_audio_sample_t(1.0)/jack_default_audio_sample_t(SHRT_MAX));
00410 }
00411 }
00412 else
00413 {
00414 int32_t* chan32b;
00415 for ( c = 0; c < fCardInputs; c++ )
00416 {
00417 chan32b = ( int32_t* ) fInputCardChannels[c];
00418 for ( s = 0; s < fBuffering; s++ )
00419 fInputSoftChannels[c][s] = jack_default_audio_sample_t(chan32b[s]) * (jack_default_audio_sample_t(1.0)/jack_default_audio_sample_t(INT_MAX));
00420 }
00421 }
00422 break;
00423 default :
00424 check_error_msg ( -10000, "unknow access mode" );
00425 break;
00426 }
00427 return 0;
00428 }
00429
00434 int write()
00435 {
00436 int count, f;
00437 unsigned int c;
00438 recovery:
00439 switch ( fSampleAccess )
00440 {
00441 case SND_PCM_ACCESS_RW_INTERLEAVED :
00442 if ( fSampleFormat == SND_PCM_FORMAT_S16 )
00443 {
00444 short* buffer16b = ( short* ) fOutputCardBuffer;
00445 for ( f = 0; f < fBuffering; f++ )
00446 {
00447 for ( unsigned int c = 0; c < fCardOutputs; c++ )
00448 {
00449 jack_default_audio_sample_t x = fOutputSoftChannels[c][f];
00450 buffer16b[c + f * fCardOutputs] = short(max(min (x, jack_default_audio_sample_t(1.0)), jack_default_audio_sample_t(-1.0)) * jack_default_audio_sample_t(SHRT_MAX));
00451 }
00452 }
00453 }
00454 else
00455 {
00456 int32_t* buffer32b = ( int32_t* ) fOutputCardBuffer;
00457 for ( f = 0; f < fBuffering; f++ )
00458 {
00459 for ( unsigned int c = 0; c < fCardOutputs; c++ )
00460 {
00461 jack_default_audio_sample_t x = fOutputSoftChannels[c][f];
00462 buffer32b[c + f * fCardOutputs] = int32_t(max(min(x, jack_default_audio_sample_t(1.0)), jack_default_audio_sample_t(-1.0)) * jack_default_audio_sample_t(INT_MAX));
00463 }
00464 }
00465 }
00466 count = snd_pcm_writei ( fOutputDevice, fOutputCardBuffer, fBuffering );
00467 if ( count < 0 )
00468 {
00469 display_error_msg ( count, "w3" );
00470 int err = snd_pcm_prepare ( fOutputDevice );
00471 check_error_msg ( err, "preparing output stream" );
00472 goto recovery;
00473 }
00474 break;
00475 case SND_PCM_ACCESS_RW_NONINTERLEAVED :
00476 if ( fSampleFormat == SND_PCM_FORMAT_S16 )
00477 {
00478 for ( c = 0; c < fCardOutputs; c++ )
00479 {
00480 short* chan16b = ( short* ) fOutputCardChannels[c];
00481 for ( f = 0; f < fBuffering; f++ )
00482 {
00483 jack_default_audio_sample_t x = fOutputSoftChannels[c][f];
00484 chan16b[f] = short(max(min (x, jack_default_audio_sample_t(1.0)), jack_default_audio_sample_t(-1.0)) * jack_default_audio_sample_t(SHRT_MAX));
00485 }
00486 }
00487 }
00488 else
00489 {
00490 for ( c = 0; c < fCardOutputs; c++ )
00491 {
00492 int32_t* chan32b = ( int32_t* ) fOutputCardChannels[c];
00493 for ( f = 0; f < fBuffering; f++ )
00494 {
00495 jack_default_audio_sample_t x = fOutputSoftChannels[c][f];
00496 chan32b[f] = int32_t(max(min(x, jack_default_audio_sample_t(1.0)), jack_default_audio_sample_t(-1.0)) * jack_default_audio_sample_t(INT_MAX));
00497 }
00498 }
00499 }
00500 count = snd_pcm_writen ( fOutputDevice, fOutputCardChannels, fBuffering );
00501 if ( count<0 )
00502 {
00503 display_error_msg ( count, "w3" );
00504 int err = snd_pcm_prepare ( fOutputDevice );
00505 check_error_msg ( err, "preparing output stream" );
00506 goto recovery;
00507 }
00508 break;
00509 default :
00510 check_error_msg ( -10000, "unknow access mode" );
00511 break;
00512 }
00513 return 0;
00514 }
00515
00519 int shortinfo()
00520 {
00521 int err;
00522 snd_ctl_card_info_t* card_info;
00523 snd_ctl_t* ctl_handle;
00524 err = snd_ctl_open ( &ctl_handle, fCardName, 0 ); check_error ( err );
00525 snd_ctl_card_info_alloca ( &card_info );
00526 err = snd_ctl_card_info ( ctl_handle, card_info ); check_error ( err );
00527 jack_info ( "%s|%d|%d|%d|%d|%s",
00528 snd_ctl_card_info_get_driver ( card_info ),
00529 fCardInputs, fCardOutputs,
00530 fFrequency, fBuffering,
00531 snd_pcm_format_name ( ( _snd_pcm_format ) fSampleFormat ) );
00532 snd_ctl_close(ctl_handle);
00533 }
00534
00538 int longinfo()
00539 {
00540 snd_ctl_card_info_t* card_info;
00541 snd_ctl_t* ctl_handle;
00542
00543
00544 jack_info ( "Audio Interface Description :" );
00545 jack_info ( "Sampling Frequency : %d, Sample Format : %s, buffering : %d, nperiod : %d",
00546 fFrequency, snd_pcm_format_name ( ( _snd_pcm_format ) fSampleFormat ), fBuffering, fPeriod );
00547 jack_info ( "Software inputs : %2d, Software outputs : %2d", fSoftInputs, fSoftOutputs );
00548 jack_info ( "Hardware inputs : %2d, Hardware outputs : %2d", fCardInputs, fCardOutputs );
00549
00550
00551 check_error ( snd_ctl_open ( &ctl_handle, fCardName, 0 ) );
00552 snd_ctl_card_info_alloca ( &card_info );
00553 check_error ( snd_ctl_card_info ( ctl_handle, card_info ) );
00554 printCardInfo ( card_info );
00555
00556
00557 if ( fSoftInputs > 0 )
00558 printHWParams ( fInputParams );
00559 if ( fSoftOutputs > 0 )
00560 printHWParams ( fOutputParams );
00561 snd_ctl_close(ctl_handle);
00562 return 0;
00563 }
00564
00565 void printCardInfo ( snd_ctl_card_info_t* ci )
00566 {
00567 jack_info ( "Card info (address : %p)", ci );
00568 jack_info ( "\tID = %s", snd_ctl_card_info_get_id ( ci ) );
00569 jack_info ( "\tDriver = %s", snd_ctl_card_info_get_driver ( ci ) );
00570 jack_info ( "\tName = %s", snd_ctl_card_info_get_name ( ci ) );
00571 jack_info ( "\tLongName = %s", snd_ctl_card_info_get_longname ( ci ) );
00572 jack_info ( "\tMixerName = %s", snd_ctl_card_info_get_mixername ( ci ) );
00573 jack_info ( "\tComponents = %s", snd_ctl_card_info_get_components ( ci ) );
00574 jack_info ( "--------------" );
00575 }
00576
00577 void printHWParams ( snd_pcm_hw_params_t* params )
00578 {
00579 jack_info ( "HW Params info (address : %p)\n", params );
00580 #if 0
00581 jack_info ( "\tChannels = %d", snd_pcm_hw_params_get_channels ( params, NULL ) );
00582 jack_info ( "\tFormat = %s", snd_pcm_format_name ( ( _snd_pcm_format ) snd_pcm_hw_params_get_format ( params, NULL ) ) );
00583 jack_info ( "\tAccess = %s", snd_pcm_access_name ( ( _snd_pcm_access ) snd_pcm_hw_params_get_access ( params, NULL ) ) );
00584 jack_info ( "\tRate = %d", snd_pcm_hw_params_get_rate ( params, NULL, NULL ) );
00585 jack_info ( "\tPeriods = %d", snd_pcm_hw_params_get_periods ( params, NULL, NULL ) );
00586 jack_info ( "\tPeriod size = %d", ( int ) snd_pcm_hw_params_get_period_size ( params, NULL, NULL ) );
00587 jack_info ( "\tPeriod time = %d", snd_pcm_hw_params_get_period_time ( params, NULL, NULL ) );
00588 jack_info ( "\tBuffer size = %d", ( int ) snd_pcm_hw_params_get_buffer_size ( params, NULL ) );
00589 jack_info ( "\tBuffer time = %d", snd_pcm_hw_params_get_buffer_time ( params, NULL, NULL ) );
00590 #endif
00591 jack_info ( "--------------" );
00592 }
00593 };
00594
00599 class JackAlsaAdapter : public JackAudioAdapterInterface, public JackRunnableInterface
00600 {
00601
00602 private:
00603 JackThread fThread;
00604 AudioInterface fAudioInterface;
00605
00606 public:
00607 JackAlsaAdapter ( jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params );
00608 ~JackAlsaAdapter()
00609 {}
00610
00611 virtual int Open();
00612 virtual int Close();
00613
00614 virtual int SetSampleRate ( jack_nframes_t sample_rate );
00615 virtual int SetBufferSize ( jack_nframes_t buffer_size );
00616
00617 virtual bool Init();
00618 virtual bool Execute();
00619
00620 };
00621
00622 }
00623
00624 #ifdef __cplusplus
00625 extern "C"
00626 {
00627 #endif
00628
00629 #include "JackCompilerDeps.h"
00630 #include "driver_interface.h"
00631
00632 SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor();
00633
00634 #ifdef __cplusplus
00635 }
00636 #endif
00637
00638 #endif