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__
26 #include <alsa/asoundlib.h>
27 #include "JackAudioAdapterInterface.h"
28 #include "JackPlatformPlug.h"
29 #include "JackError.h"
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); }
46 * A convenient class to pass parameters to AudioInterface
51 const char* fCardName
;
52 unsigned int fFrequency
;
55 unsigned int fSoftInputs
;
56 unsigned int fSoftOutputs
;
67 AudioParam ( jack_nframes_t buffer_size
, jack_nframes_t sample_rate
) :
69 fFrequency ( sample_rate
),
70 fBuffering ( buffer_size
),
75 AudioParam
& cardName ( const char* n
)
81 AudioParam
& frequency ( int f
)
87 AudioParam
& buffering ( int fpb
)
93 void setInputs ( int inputs
)
98 AudioParam
& inputs ( int n
)
104 void setOutputs ( int outputs
)
106 fSoftOutputs
= outputs
;
109 AudioParam
& outputs ( int n
)
117 * An ALSA audio interface
119 class AudioInterface
: public AudioParam
123 snd_pcm_t
* fOutputDevice
;
124 snd_pcm_t
* fInputDevice
;
125 snd_pcm_hw_params_t
* fInputParams
;
126 snd_pcm_hw_params_t
* fOutputParams
;
129 snd_pcm_format_t fSampleFormat
;
130 snd_pcm_access_t fSampleAccess
;
133 const char* fCaptureName
;
134 const char* fPlaybackName
;
135 unsigned int fCardInputs
;
136 unsigned int fCardOutputs
;
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()
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
)
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;
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
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 );
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;
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
);
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" );
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
);
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
);
364 * Read audio samples from the audio card. Convert samples to floats and take
365 * care of interleaved buffers
371 switch ( fSampleAccess
)
373 case SND_PCM_ACCESS_RW_INTERLEAVED
:
374 count
= snd_pcm_readi ( fInputDevice
, fInputCardBuffer
, fBuffering
);
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
));
395 case SND_PCM_ACCESS_RW_NONINTERLEAVED
:
396 count
= snd_pcm_readn ( fInputDevice
, fInputCardChannels
, fBuffering
);
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
)
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
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
));
424 check_error_msg ( -10000, "unknow access mode" );
431 * write the output soft channels to the audio card. Convert sample
432 * format and interleaves buffers when needed
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
);
469 display_error_msg ( count
, "w3" );
470 int err
= snd_pcm_prepare ( fOutputDevice
);
471 check_error_msg ( err
, "preparing output stream" );
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
));
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
);
503 display_error_msg ( count
, "w3" );
504 int err
= snd_pcm_prepare ( fOutputDevice
);
505 check_error_msg ( err
, "preparing output stream" );
510 check_error_msg ( -10000, "unknow access mode" );
517 * print short information on the audio device
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
540 snd_ctl_card_info_t
* card_info
;
541 snd_ctl_t
* ctl_handle
;
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
);
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
);
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
) );
591 jack_info ( "--------------" );
596 \brief Audio adapter using ALSA API.
599 class JackAlsaAdapter
: public JackAudioAdapterInterface
, public JackRunnableInterface
604 AudioInterface fAudioInterface
;
607 JackAlsaAdapter ( jack_nframes_t buffer_size
, jack_nframes_t sample_rate
, const JSList
* params
);
614 virtual int SetSampleRate ( jack_nframes_t sample_rate
);
615 virtual int SetBufferSize ( jack_nframes_t buffer_size
);
618 virtual bool Execute();
629 #include "JackCompilerDeps.h"
630 #include "driver_interface.h"
632 SERVER_EXPORT jack_driver_desc_t
* jack_get_descriptor();