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 unsigned int fCardInputs;
00134 unsigned int fCardOutputs;
00135
00136
00137 unsigned int fPeriod;
00138
00139
00140 void* fInputCardBuffer;
00141 void* fOutputCardBuffer;
00142
00143
00144 void* fInputCardChannels[256];
00145 void* fOutputCardChannels[256];
00146
00147
00148 float* fInputSoftChannels[256];
00149 float* fOutputSoftChannels[256];
00150
00151
00152
00153 const char* cardName()
00154 {
00155 return fCardName;
00156 }
00157
00158 int frequency()
00159 {
00160 return fFrequency;
00161 }
00162
00163 int buffering()
00164 {
00165 return fBuffering;
00166 }
00167
00168 float** inputSoftChannels()
00169 {
00170 return fInputSoftChannels;
00171 }
00172
00173 float** outputSoftChannels()
00174 {
00175 return fOutputSoftChannels;
00176 }
00177
00178 AudioInterface ( const AudioParam& ap = AudioParam() ) : AudioParam ( ap )
00179 {
00180 fInputDevice = 0;
00181 fOutputDevice = 0;
00182 fInputParams = 0;
00183 fOutputParams = 0;
00184 fPeriod = 2;
00185 }
00186
00187 AudioInterface ( jack_nframes_t buffer_size, jack_nframes_t sample_rate ) :
00188 AudioParam ( buffer_size, sample_rate )
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
00205 int open()
00206 {
00207
00208 check_error ( snd_pcm_open ( &fInputDevice, fCardName, SND_PCM_STREAM_CAPTURE, 0 ) );
00209 check_error ( snd_pcm_open ( &fOutputDevice, fCardName, SND_PCM_STREAM_PLAYBACK, 0 ) );
00210
00211
00212 check_error ( snd_pcm_hw_params_malloc ( &fInputParams ) );
00213 setAudioParams ( fInputDevice, fInputParams );
00214 snd_pcm_hw_params_get_channels ( fInputParams, &fCardInputs );
00215
00216
00217 check_error ( snd_pcm_hw_params_malloc ( &fOutputParams ) )
00218 setAudioParams ( fOutputDevice, fOutputParams );
00219 snd_pcm_hw_params_get_channels ( fOutputParams, &fCardOutputs );
00220
00221
00222 check_error ( snd_pcm_hw_params ( fInputDevice, fInputParams ) );
00223 check_error ( snd_pcm_hw_params ( fOutputDevice, fOutputParams ) );
00224
00225
00226 if ( fSampleAccess == SND_PCM_ACCESS_RW_INTERLEAVED )
00227 {
00228 fInputCardBuffer = aligned_calloc ( interleavedBufferSize ( fInputParams ), 1 );
00229 fOutputCardBuffer = aligned_calloc ( interleavedBufferSize ( fOutputParams ), 1 );
00230 }
00231 else
00232 {
00233 for ( unsigned int i = 0; i < fCardInputs; i++ )
00234 fInputCardChannels[i] = aligned_calloc ( noninterleavedBufferSize ( fInputParams ), 1 );
00235 for ( unsigned int i = 0; i < fCardOutputs; i++ )
00236 fOutputCardChannels[i] = aligned_calloc ( noninterleavedBufferSize ( fOutputParams ), 1 );
00237 }
00238
00239
00240 fSoftInputs = max ( fSoftInputs, fCardInputs );
00241 assert ( fSoftInputs < 256 );
00242 fSoftOutputs = max ( fSoftOutputs, fCardOutputs );
00243 assert ( fSoftOutputs < 256 );
00244
00245 for ( unsigned int i = 0; i < fSoftInputs; i++ )
00246 {
00247 fInputSoftChannels[i] = ( float* ) aligned_calloc ( fBuffering, sizeof ( float ) );
00248 for ( int j = 0; j < fBuffering; j++ )
00249 fInputSoftChannels[i][j] = 0.0;
00250 }
00251
00252 for ( unsigned int i = 0; i < fSoftOutputs; i++ )
00253 {
00254 fOutputSoftChannels[i] = ( float* ) aligned_calloc ( fBuffering, sizeof ( float ) );
00255 for ( int j = 0; j < fBuffering; j++ )
00256 fOutputSoftChannels[i][j] = 0.0;
00257 }
00258 return 0;
00259 }
00260
00261 int close()
00262 {
00263 snd_pcm_hw_params_free ( fInputParams );
00264 snd_pcm_hw_params_free ( fOutputParams );
00265 snd_pcm_close ( fInputDevice );
00266 snd_pcm_close ( fOutputDevice );
00267
00268 for ( unsigned int i = 0; i < fSoftInputs; i++ )
00269 if ( fInputSoftChannels[i] )
00270 free ( fInputSoftChannels[i] );
00271
00272 for ( unsigned int i = 0; i < fSoftOutputs; i++ )
00273 if ( fOutputSoftChannels[i] )
00274 free ( fOutputSoftChannels[i] );
00275
00276 for ( unsigned int i = 0; i < fCardInputs; i++ )
00277 if ( fInputCardChannels[i] )
00278 free ( fInputCardChannels[i] );
00279
00280 for ( unsigned int i = 0; i < fCardOutputs; i++ )
00281 if ( fOutputCardChannels[i] )
00282 free ( fOutputCardChannels[i] );
00283
00284 if ( fInputCardBuffer )
00285 free ( fInputCardBuffer );
00286 if ( fOutputCardBuffer )
00287 free ( fOutputCardBuffer );
00288
00289 return 0;
00290 }
00291
00292 int setAudioParams ( snd_pcm_t* stream, snd_pcm_hw_params_t* params )
00293 {
00294
00295 check_error_msg ( snd_pcm_hw_params_any ( stream, params ), "unable to init parameters" )
00296
00297
00298 if ( snd_pcm_hw_params_set_access ( stream, params, SND_PCM_ACCESS_RW_NONINTERLEAVED ) )
00299 check_error_msg ( snd_pcm_hw_params_set_access ( stream, params, SND_PCM_ACCESS_RW_INTERLEAVED ),
00300 "unable to set access mode neither to non-interleaved or to interleaved" );
00301 snd_pcm_hw_params_get_access ( params, &fSampleAccess );
00302
00303
00304 if ( snd_pcm_hw_params_set_format ( stream, params, SND_PCM_FORMAT_S32 ) )
00305 check_error_msg ( snd_pcm_hw_params_set_format ( stream, params, SND_PCM_FORMAT_S16 ),
00306 "unable to set format to either 32-bits or 16-bits" );
00307 snd_pcm_hw_params_get_format ( params, &fSampleFormat );
00308
00309
00310 snd_pcm_hw_params_set_rate_near ( stream, params, &fFrequency, 0 );
00311
00312
00313 check_error_msg ( snd_pcm_hw_params_set_period_size ( stream, params, fBuffering, 0 ), "period size not available" );
00314 check_error_msg ( snd_pcm_hw_params_set_periods ( stream, params, fPeriod, 0 ), "number of periods not available" );
00315
00316 return 0;
00317 }
00318
00319 ssize_t interleavedBufferSize ( snd_pcm_hw_params_t* params )
00320 {
00321 _snd_pcm_format format;
00322 unsigned int channels;
00323 snd_pcm_hw_params_get_format ( params, &format );
00324 snd_pcm_uframes_t psize;
00325 snd_pcm_hw_params_get_period_size ( params, &psize, NULL );
00326 snd_pcm_hw_params_get_channels ( params, &channels );
00327 ssize_t bsize = snd_pcm_format_size ( format, psize * channels );
00328 return bsize;
00329 }
00330
00331 ssize_t noninterleavedBufferSize ( snd_pcm_hw_params_t* params )
00332 {
00333 _snd_pcm_format format;
00334 snd_pcm_hw_params_get_format ( params, &format );
00335 snd_pcm_uframes_t psize;
00336 snd_pcm_hw_params_get_period_size ( params, &psize, NULL );
00337 ssize_t bsize = snd_pcm_format_size ( format, psize );
00338 return bsize;
00339 }
00340
00345 int read()
00346 {
00347 int count, s;
00348 unsigned int c;
00349 switch ( fSampleAccess )
00350 {
00351 case SND_PCM_ACCESS_RW_INTERLEAVED :
00352 count = snd_pcm_readi ( fInputDevice, fInputCardBuffer, fBuffering );
00353 if ( count < 0 )
00354 {
00355 display_error_msg ( count, "reading samples" );
00356 check_error_msg ( snd_pcm_prepare ( fInputDevice ), "preparing input stream" );
00357 }
00358 if ( fSampleFormat == SND_PCM_FORMAT_S16 )
00359 {
00360 short* buffer16b = ( short* ) fInputCardBuffer;
00361 for ( s = 0; s < fBuffering; s++ )
00362 for ( c = 0; c < fCardInputs; c++ )
00363 fInputSoftChannels[c][s] = float ( buffer16b[c + s*fCardInputs] ) * ( 1.0/float ( SHRT_MAX ) );
00364 }
00365 else
00366 {
00367 long* buffer32b = ( long* ) fInputCardBuffer;
00368 for ( s = 0; s < fBuffering; s++ )
00369 for ( c = 0; c < fCardInputs; c++ )
00370 fInputSoftChannels[c][s] = float ( buffer32b[c + s*fCardInputs] ) * ( 1.0/float ( LONG_MAX ) );
00371 }
00372 break;
00373 case SND_PCM_ACCESS_RW_NONINTERLEAVED :
00374 count = snd_pcm_readn ( fInputDevice, fInputCardChannels, 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* chan16b;
00383 for ( c = 0; c < fCardInputs; c++ )
00384 {
00385 chan16b = ( short* ) fInputCardChannels[c];
00386 for ( s = 0; s < fBuffering; s++ )
00387 fInputSoftChannels[c][s] = float ( chan16b[s] ) * ( 1.0/float ( SHRT_MAX ) );
00388 }
00389 }
00390 else
00391 {
00392 long* chan32b;
00393 for ( c = 0; c < fCardInputs; c++ )
00394 {
00395 chan32b = ( long* ) fInputCardChannels[c];
00396 for ( s = 0; s < fBuffering; s++ )
00397 fInputSoftChannels[c][s] = float ( chan32b[s] ) * ( 1.0/float ( LONG_MAX ) );
00398 }
00399 }
00400 break;
00401 default :
00402 check_error_msg ( -10000, "unknow access mode" );
00403 break;
00404 }
00405 return 0;
00406 }
00407
00412 int write()
00413 {
00414 int count, f;
00415 unsigned int c;
00416 recovery:
00417 switch ( fSampleAccess )
00418 {
00419 case SND_PCM_ACCESS_RW_INTERLEAVED :
00420 if ( fSampleFormat == SND_PCM_FORMAT_S16 )
00421 {
00422 short* buffer16b = ( short* ) fOutputCardBuffer;
00423 for ( f = 0; f < fBuffering; f++ )
00424 {
00425 for ( unsigned int c = 0; c < fCardOutputs; c++ )
00426 {
00427 float x = fOutputSoftChannels[c][f];
00428 buffer16b[c + f * fCardOutputs] = short ( max ( min ( x, 1.0 ), -1.0 ) * float ( SHRT_MAX ) );
00429 }
00430 }
00431 }
00432 else
00433 {
00434 long* buffer32b = ( long* ) fOutputCardBuffer;
00435 for ( f = 0; f < fBuffering; f++ )
00436 {
00437 for ( unsigned int c = 0; c < fCardOutputs; c++ )
00438 {
00439 float x = fOutputSoftChannels[c][f];
00440 buffer32b[c + f * fCardOutputs] = long ( max ( min ( x, 1.0 ), -1.0 ) * float ( LONG_MAX ) );
00441 }
00442 }
00443 }
00444 count = snd_pcm_writei ( fOutputDevice, fOutputCardBuffer, fBuffering );
00445 if ( count < 0 )
00446 {
00447 display_error_msg ( count, "w3" );
00448 int err = snd_pcm_prepare ( fOutputDevice );
00449 check_error_msg ( err, "preparing output stream" );
00450 goto recovery;
00451 }
00452 break;
00453 case SND_PCM_ACCESS_RW_NONINTERLEAVED :
00454 if ( fSampleFormat == SND_PCM_FORMAT_S16 )
00455 {
00456 for ( c = 0; c < fCardOutputs; c++ )
00457 {
00458 short* chan16b = ( short* ) fOutputCardChannels[c];
00459 for ( f = 0; f < fBuffering; f++ )
00460 {
00461 float x = fOutputSoftChannels[c][f];
00462 chan16b[f] = short ( max ( min ( x,1.0 ), -1.0 ) * float ( SHRT_MAX ) ) ;
00463 }
00464 }
00465 }
00466 else
00467 {
00468 for ( c = 0; c < fCardOutputs; c++ )
00469 {
00470 long* chan32b = ( long* ) fOutputCardChannels[c];
00471 for ( f = 0; f < fBuffering; f++ )
00472 {
00473 float x = fOutputSoftChannels[c][f];
00474 chan32b[f] = long ( max ( min ( x,1.0 ),-1.0 ) * float ( LONG_MAX ) ) ;
00475 }
00476 }
00477 }
00478 count = snd_pcm_writen ( fOutputDevice, fOutputCardChannels, fBuffering );
00479 if ( count<0 )
00480 {
00481 display_error_msg ( count, "w3" );
00482 int err = snd_pcm_prepare ( fOutputDevice );
00483 check_error_msg ( err, "preparing output stream" );
00484 goto recovery;
00485 }
00486 break;
00487 default :
00488 check_error_msg ( -10000, "unknow access mode" );
00489 break;
00490 }
00491 return 0;
00492 }
00493
00497 int shortinfo()
00498 {
00499 int err;
00500 snd_ctl_card_info_t* card_info;
00501 snd_ctl_t* ctl_handle;
00502 err = snd_ctl_open ( &ctl_handle, fCardName, 0 ); check_error ( err );
00503 snd_ctl_card_info_alloca ( &card_info );
00504 err = snd_ctl_card_info ( ctl_handle, card_info ); check_error ( err );
00505 jack_info ( "%s|%d|%d|%d|%d|%s",
00506 snd_ctl_card_info_get_driver ( card_info ),
00507 fCardInputs, fCardOutputs,
00508 fFrequency, fBuffering,
00509 snd_pcm_format_name ( ( _snd_pcm_format ) fSampleFormat ) );
00510 }
00511
00515 int longinfo()
00516 {
00517 snd_ctl_card_info_t* card_info;
00518 snd_ctl_t* ctl_handle;
00519
00520
00521 jack_info ( "Audio Interface Description :" );
00522 jack_info ( "Sampling Frequency : %d, Sample Format : %s, buffering : %d, nperiod : %d",
00523 fFrequency, snd_pcm_format_name ( ( _snd_pcm_format ) fSampleFormat ), fBuffering, fPeriod );
00524 jack_info ( "Software inputs : %2d, Software outputs : %2d", fSoftInputs, fSoftOutputs );
00525 jack_info ( "Hardware inputs : %2d, Hardware outputs : %2d", fCardInputs, fCardOutputs );
00526
00527
00528 check_error ( snd_ctl_open ( &ctl_handle, fCardName, 0 ) );
00529 snd_ctl_card_info_alloca ( &card_info );
00530 check_error ( snd_ctl_card_info ( ctl_handle, card_info ) );
00531 printCardInfo ( card_info );
00532
00533
00534 if ( fSoftInputs > 0 )
00535 printHWParams ( fInputParams );
00536 if ( fSoftOutputs > 0 )
00537 printHWParams ( fOutputParams );
00538
00539 return 0;
00540 }
00541
00542 void printCardInfo ( snd_ctl_card_info_t* ci )
00543 {
00544 jack_info ( "Card info (address : %p)", ci );
00545 jack_info ( "\tID = %s", snd_ctl_card_info_get_id ( ci ) );
00546 jack_info ( "\tDriver = %s", snd_ctl_card_info_get_driver ( ci ) );
00547 jack_info ( "\tName = %s", snd_ctl_card_info_get_name ( ci ) );
00548 jack_info ( "\tLongName = %s", snd_ctl_card_info_get_longname ( ci ) );
00549 jack_info ( "\tMixerName = %s", snd_ctl_card_info_get_mixername ( ci ) );
00550 jack_info ( "\tComponents = %s", snd_ctl_card_info_get_components ( ci ) );
00551 jack_info ( "--------------" );
00552 }
00553
00554 void printHWParams ( snd_pcm_hw_params_t* params )
00555 {
00556 jack_info ( "HW Params info (address : %p)\n", params );
00557 #if 0
00558 jack_info ( "\tChannels = %d", snd_pcm_hw_params_get_channels ( params, NULL ) );
00559 jack_info ( "\tFormat = %s", snd_pcm_format_name ( ( _snd_pcm_format ) snd_pcm_hw_params_get_format ( params, NULL ) ) );
00560 jack_info ( "\tAccess = %s", snd_pcm_access_name ( ( _snd_pcm_access ) snd_pcm_hw_params_get_access ( params, NULL ) ) );
00561 jack_info ( "\tRate = %d", snd_pcm_hw_params_get_rate ( params, NULL, NULL ) );
00562 jack_info ( "\tPeriods = %d", snd_pcm_hw_params_get_periods ( params, NULL, NULL ) );
00563 jack_info ( "\tPeriod size = %d", ( int ) snd_pcm_hw_params_get_period_size ( params, NULL, NULL ) );
00564 jack_info ( "\tPeriod time = %d", snd_pcm_hw_params_get_period_time ( params, NULL, NULL ) );
00565 jack_info ( "\tBuffer size = %d", ( int ) snd_pcm_hw_params_get_buffer_size ( params, NULL ) );
00566 jack_info ( "\tBuffer time = %d", snd_pcm_hw_params_get_buffer_time ( params, NULL, NULL ) );
00567 #endif
00568 jack_info ( "--------------" );
00569 }
00570 };
00571
00576 class JackAlsaAdapter : public JackAudioAdapterInterface, public JackRunnableInterface
00577 {
00578
00579 private:
00580 JackThread fThread;
00581 AudioInterface fAudioInterface;
00582
00583 public:
00584 JackAlsaAdapter ( jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params );
00585 ~JackAlsaAdapter()
00586 {}
00587
00588 virtual int Open();
00589 virtual int Close();
00590
00591 virtual int SetSampleRate ( jack_nframes_t sample_rate );
00592 virtual int SetBufferSize ( jack_nframes_t buffer_size );
00593
00594 virtual bool Init();
00595 virtual bool Execute();
00596
00597 };
00598
00599 }
00600
00601 #ifdef __cplusplus
00602 extern "C"
00603 {
00604 #endif
00605
00606 #include "JackCompilerDeps.h"
00607 #include "driver_interface.h"
00608
00609 EXPORT jack_driver_desc_t* jack_get_descriptor();
00610
00611 #ifdef __cplusplus
00612 }
00613 #endif
00614
00615 #endif