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