alsa driver/adapter improvements to flexibly use playback/capture devices through...
[jack2.git] / linux / alsa / JackAlsaAdapter.h
blob6773371851db845cd63a1bae0b560790b6631742
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 #ifndef __JackAlsaAdapter__
21 #define __JackAlsaAdapter__
23 #include <math.h>
24 #include <limits.h>
25 #include <assert.h>
26 #include <alsa/asoundlib.h>
27 #include "JackAudioAdapterInterface.h"
28 #include "JackPlatformPlug.h"
29 #include "JackError.h"
30 #include "jack.h"
31 #include "jslist.h"
33 namespace Jack
36 inline void* aligned_calloc ( size_t nmemb, size_t size ) { return ( void* ) calloc ( nmemb, size ); }
38 #define max(x,y) (((x)>(y)) ? (x) : (y))
39 #define min(x,y) (((x)<(y)) ? (x) : (y))
41 #define check_error(err) if (err) { jack_error("%s:%d, alsa error %d : %s", __FILE__, __LINE__, err, snd_strerror(err)); return err; }
42 #define check_error_msg(err,msg) if (err) { jack_error("%s:%d, %s : %s(%d)", __FILE__, __LINE__, msg, snd_strerror(err), err); return err; }
43 #define display_error_msg(err,msg) if (err) { jack_error("%s:%d, %s : %s(%d)", __FILE__, __LINE__, msg, snd_strerror(err), err); }
45 /**
46 * A convenient class to pass parameters to AudioInterface
48 class AudioParam
50 public:
51 const char* fCardName;
52 unsigned int fFrequency;
53 int fBuffering;
55 unsigned int fSoftInputs;
56 unsigned int fSoftOutputs;
58 public:
59 AudioParam() :
60 fCardName ( "hw:0" ),
61 fFrequency ( 44100 ),
62 fBuffering ( 512 ),
63 fSoftInputs ( 2 ),
64 fSoftOutputs ( 2 )
67 AudioParam ( jack_nframes_t buffer_size, jack_nframes_t sample_rate ) :
68 fCardName ( "hw:0" ),
69 fFrequency ( sample_rate ),
70 fBuffering ( buffer_size ),
71 fSoftInputs ( 2 ),
72 fSoftOutputs ( 2 )
75 AudioParam& cardName ( const char* n )
77 fCardName = n;
78 return *this;
81 AudioParam& frequency ( int f )
83 fFrequency = f;
84 return *this;
87 AudioParam& buffering ( int fpb )
89 fBuffering = fpb;
90 return *this;
93 void setInputs ( int inputs )
95 fSoftInputs = inputs;
98 AudioParam& inputs ( int n )
100 fSoftInputs = n;
101 return *this;
104 void setOutputs ( int outputs )
106 fSoftOutputs = outputs;
109 AudioParam& outputs ( int n )
111 fSoftOutputs = n;
112 return *this;
117 * An ALSA audio interface
119 class AudioInterface : public AudioParam
121 public:
122 //device info
123 snd_pcm_t* fOutputDevice;
124 snd_pcm_t* fInputDevice;
125 snd_pcm_hw_params_t* fInputParams;
126 snd_pcm_hw_params_t* fOutputParams;
128 //samples info
129 snd_pcm_format_t fSampleFormat;
130 snd_pcm_access_t fSampleAccess;
132 //channels
133 const char* fCaptureName;
134 const char* fPlaybackName;
135 unsigned int fCardInputs;
136 unsigned int fCardOutputs;
138 //stream parameters
139 unsigned int fPeriod;
141 //interleaved mode audiocard buffers
142 void* fInputCardBuffer;
143 void* fOutputCardBuffer;
145 //non-interleaved mode audiocard buffers
146 void* fInputCardChannels[256];
147 void* fOutputCardChannels[256];
149 //non-interleaved mod, floating point software buffers
150 jack_default_audio_sample_t* fInputSoftChannels[256];
151 jack_default_audio_sample_t* fOutputSoftChannels[256];
153 //public methods ---------------------------------------------------------
155 const char* cardName()
157 return fCardName;
160 int frequency()
162 return fFrequency;
165 int buffering()
167 return fBuffering;
170 jack_default_audio_sample_t** inputSoftChannels()
172 return fInputSoftChannels;
175 jack_default_audio_sample_t** outputSoftChannels()
177 return fOutputSoftChannels;
180 AudioInterface ( const AudioParam& ap = AudioParam() ) : AudioParam ( ap )
182 fInputDevice = 0;
183 fOutputDevice = 0;
184 fInputParams = 0;
185 fOutputParams = 0;
186 fPeriod = 2;
187 fCaptureName = NULL;
188 fPlaybackName = NULL;
190 fInputCardBuffer = 0;
191 fOutputCardBuffer = 0;
193 for ( int i = 0; i < 256; i++ )
195 fInputCardChannels[i] = 0;
196 fOutputCardChannels[i] = 0;
197 fInputSoftChannels[i] = 0;
198 fOutputSoftChannels[i] = 0;
202 AudioInterface ( jack_nframes_t buffer_size, jack_nframes_t sample_rate ) :
203 AudioParam ( buffer_size, sample_rate )
205 fInputCardBuffer = 0;
206 fOutputCardBuffer = 0;
207 fCaptureName = NULL;
208 fPlaybackName = NULL;
210 for ( int i = 0; i < 256; i++ )
212 fInputCardChannels[i] = 0;
213 fOutputCardChannels[i] = 0;
214 fInputSoftChannels[i] = 0;
215 fOutputSoftChannels[i] = 0;
220 * Open the audio interface
222 int open()
224 //open input/output streams
225 check_error ( snd_pcm_open ( &fInputDevice, (fCaptureName == NULL) ? fCardName : fCaptureName, SND_PCM_STREAM_CAPTURE, 0 ) );
226 check_error ( snd_pcm_open ( &fOutputDevice, (fPlaybackName == NULL) ? fCardName : fPlaybackName, SND_PCM_STREAM_PLAYBACK, 0 ) );
228 //get hardware input parameters
229 check_error ( snd_pcm_hw_params_malloc ( &fInputParams ) );
230 setAudioParams ( fInputDevice, fInputParams );
232 //get hardware output parameters
233 check_error ( snd_pcm_hw_params_malloc ( &fOutputParams ) )
234 setAudioParams ( fOutputDevice, fOutputParams );
236 // set the number of physical input and output channels close to what we need
237 fCardInputs = fSoftInputs;
238 fCardOutputs = fSoftOutputs;
240 snd_pcm_hw_params_set_channels_near(fInputDevice, fInputParams, &fCardInputs);
241 snd_pcm_hw_params_set_channels_near(fOutputDevice, fOutputParams, &fCardOutputs);
243 //set input/output param
244 check_error ( snd_pcm_hw_params ( fInputDevice, fInputParams ) );
245 check_error ( snd_pcm_hw_params ( fOutputDevice, fOutputParams ) );
247 //set hardware buffers
248 if ( fSampleAccess == SND_PCM_ACCESS_RW_INTERLEAVED )
250 fInputCardBuffer = aligned_calloc ( interleavedBufferSize ( fInputParams ), 1 );
251 fOutputCardBuffer = aligned_calloc ( interleavedBufferSize ( fOutputParams ), 1 );
253 else
255 for ( unsigned int i = 0; i < fCardInputs; i++ )
256 fInputCardChannels[i] = aligned_calloc ( noninterleavedBufferSize ( fInputParams ), 1 );
257 for ( unsigned int i = 0; i < fCardOutputs; i++ )
258 fOutputCardChannels[i] = aligned_calloc ( noninterleavedBufferSize ( fOutputParams ), 1 );
261 //set floating point buffers needed by the dsp code
262 fSoftInputs = max ( fSoftInputs, fCardInputs );
263 assert ( fSoftInputs < 256 );
264 fSoftOutputs = max ( fSoftOutputs, fCardOutputs );
265 assert ( fSoftOutputs < 256 );
267 for ( unsigned int i = 0; i < fSoftInputs; i++ )
269 fInputSoftChannels[i] = ( jack_default_audio_sample_t* ) aligned_calloc ( fBuffering, sizeof ( jack_default_audio_sample_t ) );
270 for ( int j = 0; j < fBuffering; j++ )
271 fInputSoftChannels[i][j] = 0.0;
274 for ( unsigned int i = 0; i < fSoftOutputs; i++ )
276 fOutputSoftChannels[i] = ( jack_default_audio_sample_t* ) aligned_calloc ( fBuffering, sizeof ( jack_default_audio_sample_t ) );
277 for ( int j = 0; j < fBuffering; j++ )
278 fOutputSoftChannels[i][j] = 0.0;
280 return 0;
283 int close()
285 snd_pcm_hw_params_free ( fInputParams );
286 snd_pcm_hw_params_free ( fOutputParams );
287 snd_pcm_close ( fInputDevice );
288 snd_pcm_close ( fOutputDevice );
290 for ( unsigned int i = 0; i < fSoftInputs; i++ )
291 if ( fInputSoftChannels[i] )
292 free ( fInputSoftChannels[i] );
294 for ( unsigned int i = 0; i < fSoftOutputs; i++ )
295 if ( fOutputSoftChannels[i] )
296 free ( fOutputSoftChannels[i] );
298 for ( unsigned int i = 0; i < fCardInputs; i++ )
299 if ( fInputCardChannels[i] )
300 free ( fInputCardChannels[i] );
302 for ( unsigned int i = 0; i < fCardOutputs; i++ )
303 if ( fOutputCardChannels[i] )
304 free ( fOutputCardChannels[i] );
306 if ( fInputCardBuffer )
307 free ( fInputCardBuffer );
308 if ( fOutputCardBuffer )
309 free ( fOutputCardBuffer );
311 return 0;
314 int setAudioParams ( snd_pcm_t* stream, snd_pcm_hw_params_t* params )
316 //set params record with initial values
317 check_error_msg ( snd_pcm_hw_params_any ( stream, params ), "unable to init parameters" )
319 //set alsa access mode (and fSampleAccess field) either to non interleaved or interleaved
320 if ( snd_pcm_hw_params_set_access ( stream, params, SND_PCM_ACCESS_RW_NONINTERLEAVED ) )
321 check_error_msg ( snd_pcm_hw_params_set_access ( stream, params, SND_PCM_ACCESS_RW_INTERLEAVED ),
322 "unable to set access mode neither to non-interleaved or to interleaved" );
323 snd_pcm_hw_params_get_access ( params, &fSampleAccess );
325 //search for 32-bits or 16-bits format
326 if ( snd_pcm_hw_params_set_format ( stream, params, SND_PCM_FORMAT_S32 ) )
327 check_error_msg ( snd_pcm_hw_params_set_format ( stream, params, SND_PCM_FORMAT_S16 ),
328 "unable to set format to either 32-bits or 16-bits" );
329 snd_pcm_hw_params_get_format ( params, &fSampleFormat );
331 //set sample frequency
332 snd_pcm_hw_params_set_rate_near ( stream, params, &fFrequency, 0 );
334 //set period and period size (buffering)
335 check_error_msg ( snd_pcm_hw_params_set_period_size ( stream, params, fBuffering, 0 ), "period size not available" );
336 check_error_msg ( snd_pcm_hw_params_set_periods ( stream, params, fPeriod, 0 ), "number of periods not available" );
338 return 0;
341 ssize_t interleavedBufferSize ( snd_pcm_hw_params_t* params )
343 _snd_pcm_format format;
344 unsigned int channels;
345 snd_pcm_hw_params_get_format ( params, &format );
346 snd_pcm_uframes_t psize;
347 snd_pcm_hw_params_get_period_size ( params, &psize, NULL );
348 snd_pcm_hw_params_get_channels ( params, &channels );
349 ssize_t bsize = snd_pcm_format_size ( format, psize * channels );
350 return bsize;
353 ssize_t noninterleavedBufferSize ( snd_pcm_hw_params_t* params )
355 _snd_pcm_format format;
356 snd_pcm_hw_params_get_format ( params, &format );
357 snd_pcm_uframes_t psize;
358 snd_pcm_hw_params_get_period_size ( params, &psize, NULL );
359 ssize_t bsize = snd_pcm_format_size ( format, psize );
360 return bsize;
364 * Read audio samples from the audio card. Convert samples to floats and take
365 * care of interleaved buffers
367 int read()
369 int count, s;
370 unsigned int c;
371 switch ( fSampleAccess )
373 case SND_PCM_ACCESS_RW_INTERLEAVED :
374 count = snd_pcm_readi ( fInputDevice, fInputCardBuffer, fBuffering );
375 if ( count < 0 )
377 display_error_msg ( count, "reading samples" );
378 check_error_msg ( snd_pcm_prepare ( fInputDevice ), "preparing input stream" );
380 if ( fSampleFormat == SND_PCM_FORMAT_S16 )
382 short* buffer16b = ( short* ) fInputCardBuffer;
383 for ( s = 0; s < fBuffering; s++ )
384 for ( c = 0; c < fCardInputs; c++ )
385 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));
387 else // SND_PCM_FORMAT_S32
389 int32_t* buffer32b = ( int32_t* ) fInputCardBuffer;
390 for ( s = 0; s < fBuffering; s++ )
391 for ( c = 0; c < fCardInputs; c++ )
392 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));
394 break;
395 case SND_PCM_ACCESS_RW_NONINTERLEAVED :
396 count = snd_pcm_readn ( fInputDevice, fInputCardChannels, fBuffering );
397 if ( count < 0 )
399 display_error_msg ( count, "reading samples" );
400 check_error_msg ( snd_pcm_prepare ( fInputDevice ), "preparing input stream" );
402 if ( fSampleFormat == SND_PCM_FORMAT_S16 )
404 short* chan16b;
405 for ( c = 0; c < fCardInputs; c++ )
407 chan16b = ( short* ) fInputCardChannels[c];
408 for ( s = 0; s < fBuffering; s++ )
409 fInputSoftChannels[c][s] = jack_default_audio_sample_t(chan16b[s]) * (jack_default_audio_sample_t(1.0)/jack_default_audio_sample_t(SHRT_MAX));
412 else // SND_PCM_FORMAT_S32
414 int32_t* chan32b;
415 for ( c = 0; c < fCardInputs; c++ )
417 chan32b = ( int32_t* ) fInputCardChannels[c];
418 for ( s = 0; s < fBuffering; s++ )
419 fInputSoftChannels[c][s] = jack_default_audio_sample_t(chan32b[s]) * (jack_default_audio_sample_t(1.0)/jack_default_audio_sample_t(INT_MAX));
422 break;
423 default :
424 check_error_msg ( -10000, "unknow access mode" );
425 break;
427 return 0;
431 * write the output soft channels to the audio card. Convert sample
432 * format and interleaves buffers when needed
434 int write()
436 int count, f;
437 unsigned int c;
438 recovery:
439 switch ( fSampleAccess )
441 case SND_PCM_ACCESS_RW_INTERLEAVED :
442 if ( fSampleFormat == SND_PCM_FORMAT_S16 )
444 short* buffer16b = ( short* ) fOutputCardBuffer;
445 for ( f = 0; f < fBuffering; f++ )
447 for ( unsigned int c = 0; c < fCardOutputs; c++ )
449 jack_default_audio_sample_t x = fOutputSoftChannels[c][f];
450 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));
454 else // SND_PCM_FORMAT_S32
456 int32_t* buffer32b = ( int32_t* ) fOutputCardBuffer;
457 for ( f = 0; f < fBuffering; f++ )
459 for ( unsigned int c = 0; c < fCardOutputs; c++ )
461 jack_default_audio_sample_t x = fOutputSoftChannels[c][f];
462 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));
466 count = snd_pcm_writei ( fOutputDevice, fOutputCardBuffer, fBuffering );
467 if ( count < 0 )
469 display_error_msg ( count, "w3" );
470 int err = snd_pcm_prepare ( fOutputDevice );
471 check_error_msg ( err, "preparing output stream" );
472 goto recovery;
474 break;
475 case SND_PCM_ACCESS_RW_NONINTERLEAVED :
476 if ( fSampleFormat == SND_PCM_FORMAT_S16 )
478 for ( c = 0; c < fCardOutputs; c++ )
480 short* chan16b = ( short* ) fOutputCardChannels[c];
481 for ( f = 0; f < fBuffering; f++ )
483 jack_default_audio_sample_t x = fOutputSoftChannels[c][f];
484 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));
488 else
490 for ( c = 0; c < fCardOutputs; c++ )
492 int32_t* chan32b = ( int32_t* ) fOutputCardChannels[c];
493 for ( f = 0; f < fBuffering; f++ )
495 jack_default_audio_sample_t x = fOutputSoftChannels[c][f];
496 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));
500 count = snd_pcm_writen ( fOutputDevice, fOutputCardChannels, fBuffering );
501 if ( count<0 )
503 display_error_msg ( count, "w3" );
504 int err = snd_pcm_prepare ( fOutputDevice );
505 check_error_msg ( err, "preparing output stream" );
506 goto recovery;
508 break;
509 default :
510 check_error_msg ( -10000, "unknow access mode" );
511 break;
513 return 0;
517 * print short information on the audio device
519 int shortinfo()
521 int err;
522 snd_ctl_card_info_t* card_info;
523 snd_ctl_t* ctl_handle;
524 err = snd_ctl_open ( &ctl_handle, fCardName, 0 ); check_error ( err );
525 snd_ctl_card_info_alloca ( &card_info );
526 err = snd_ctl_card_info ( ctl_handle, card_info ); check_error ( err );
527 jack_info ( "%s|%d|%d|%d|%d|%s",
528 snd_ctl_card_info_get_driver ( card_info ),
529 fCardInputs, fCardOutputs,
530 fFrequency, fBuffering,
531 snd_pcm_format_name ( ( _snd_pcm_format ) fSampleFormat ) );
532 snd_ctl_close(ctl_handle);
536 * print more detailled information on the audio device
538 int longinfo()
540 snd_ctl_card_info_t* card_info;
541 snd_ctl_t* ctl_handle;
543 //display info
544 jack_info ( "Audio Interface Description :" );
545 jack_info ( "Sampling Frequency : %d, Sample Format : %s, buffering : %d, nperiod : %d",
546 fFrequency, snd_pcm_format_name ( ( _snd_pcm_format ) fSampleFormat ), fBuffering, fPeriod );
547 jack_info ( "Software inputs : %2d, Software outputs : %2d", fSoftInputs, fSoftOutputs );
548 jack_info ( "Hardware inputs : %2d, Hardware outputs : %2d", fCardInputs, fCardOutputs );
550 //get audio card info and display
551 check_error ( snd_ctl_open ( &ctl_handle, fCardName, 0 ) );
552 snd_ctl_card_info_alloca ( &card_info );
553 check_error ( snd_ctl_card_info ( ctl_handle, card_info ) );
554 printCardInfo ( card_info );
556 //display input/output streams info
557 if ( fSoftInputs > 0 )
558 printHWParams ( fInputParams );
559 if ( fSoftOutputs > 0 )
560 printHWParams ( fOutputParams );
561 snd_ctl_close(ctl_handle);
562 return 0;
565 void printCardInfo ( snd_ctl_card_info_t* ci )
567 jack_info ( "Card info (address : %p)", ci );
568 jack_info ( "\tID = %s", snd_ctl_card_info_get_id ( ci ) );
569 jack_info ( "\tDriver = %s", snd_ctl_card_info_get_driver ( ci ) );
570 jack_info ( "\tName = %s", snd_ctl_card_info_get_name ( ci ) );
571 jack_info ( "\tLongName = %s", snd_ctl_card_info_get_longname ( ci ) );
572 jack_info ( "\tMixerName = %s", snd_ctl_card_info_get_mixername ( ci ) );
573 jack_info ( "\tComponents = %s", snd_ctl_card_info_get_components ( ci ) );
574 jack_info ( "--------------" );
577 void printHWParams ( snd_pcm_hw_params_t* params )
579 jack_info ( "HW Params info (address : %p)\n", params );
580 #if 0
581 jack_info ( "\tChannels = %d", snd_pcm_hw_params_get_channels ( params, NULL ) );
582 jack_info ( "\tFormat = %s", snd_pcm_format_name ( ( _snd_pcm_format ) snd_pcm_hw_params_get_format ( params, NULL ) ) );
583 jack_info ( "\tAccess = %s", snd_pcm_access_name ( ( _snd_pcm_access ) snd_pcm_hw_params_get_access ( params, NULL ) ) );
584 jack_info ( "\tRate = %d", snd_pcm_hw_params_get_rate ( params, NULL, NULL ) );
585 jack_info ( "\tPeriods = %d", snd_pcm_hw_params_get_periods ( params, NULL, NULL ) );
586 jack_info ( "\tPeriod size = %d", ( int ) snd_pcm_hw_params_get_period_size ( params, NULL, NULL ) );
587 jack_info ( "\tPeriod time = %d", snd_pcm_hw_params_get_period_time ( params, NULL, NULL ) );
588 jack_info ( "\tBuffer size = %d", ( int ) snd_pcm_hw_params_get_buffer_size ( params, NULL ) );
589 jack_info ( "\tBuffer time = %d", snd_pcm_hw_params_get_buffer_time ( params, NULL, NULL ) );
590 #endif
591 jack_info ( "--------------" );
596 \brief Audio adapter using ALSA API.
599 class JackAlsaAdapter : public JackAudioAdapterInterface, public JackRunnableInterface
602 private:
603 JackThread fThread;
604 AudioInterface fAudioInterface;
606 public:
607 JackAlsaAdapter ( jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params );
608 ~JackAlsaAdapter()
611 virtual int Open();
612 virtual int Close();
614 virtual int SetSampleRate ( jack_nframes_t sample_rate );
615 virtual int SetBufferSize ( jack_nframes_t buffer_size );
617 virtual bool Init();
618 virtual bool Execute();
624 #ifdef __cplusplus
625 extern "C"
627 #endif
629 #include "JackCompilerDeps.h"
630 #include "driver_interface.h"
632 SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor();
634 #ifdef __cplusplus
636 #endif
638 #endif