Jack2  1.9.8
JackAlsaAdapter.h
1 /*
2 Copyright (C) 2008 Grame
3 
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.
8 
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.
13 
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.
17 
18 */
19 
20 #ifndef __JackAlsaAdapter__
21 #define __JackAlsaAdapter__
22 
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"
32 
33 namespace Jack
34 {
35 
36  inline void* aligned_calloc ( size_t nmemb, size_t size ) { return ( void* ) calloc ( nmemb, size ); }
37 
38 #define max(x,y) (((x)>(y)) ? (x) : (y))
39 #define min(x,y) (((x)<(y)) ? (x) : (y))
40 
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); }
44 
48  class AudioParam
49  {
50  public:
51  const char* fCardName;
52  unsigned int fFrequency;
53  int fBuffering;
54 
55  unsigned int fSoftInputs;
56  unsigned int fSoftOutputs;
57 
58  public:
59  AudioParam() :
60  fCardName ( "hw:0" ),
61  fFrequency ( 44100 ),
62  fBuffering ( 512 ),
63  fSoftInputs ( 2 ),
64  fSoftOutputs ( 2 )
65  {}
66 
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 )
73  {}
74 
75  AudioParam& cardName ( const char* n )
76  {
77  fCardName = n;
78  return *this;
79  }
80 
81  AudioParam& frequency ( int f )
82  {
83  fFrequency = f;
84  return *this;
85  }
86 
87  AudioParam& buffering ( int fpb )
88  {
89  fBuffering = fpb;
90  return *this;
91  }
92 
93  void setInputs ( int inputs )
94  {
95  fSoftInputs = inputs;
96  }
97 
98  AudioParam& inputs ( int n )
99  {
100  fSoftInputs = n;
101  return *this;
102  }
103 
104  void setOutputs ( int outputs )
105  {
106  fSoftOutputs = outputs;
107  }
108 
109  AudioParam& outputs ( int n )
110  {
111  fSoftOutputs = n;
112  return *this;
113  }
114  };
115 
119  class AudioInterface : public AudioParam
120  {
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;
127 
128  //samples info
129  snd_pcm_format_t fSampleFormat;
130  snd_pcm_access_t fSampleAccess;
131 
132  //channels
133  unsigned int fCardInputs;
134  unsigned int fCardOutputs;
135 
136  //stream parameters
137  unsigned int fPeriod;
138 
139  //interleaved mode audiocard buffers
140  void* fInputCardBuffer;
141  void* fOutputCardBuffer;
142 
143  //non-interleaved mode audiocard buffers
144  void* fInputCardChannels[256];
145  void* fOutputCardChannels[256];
146 
147  //non-interleaved mod, floating point software buffers
148  jack_default_audio_sample_t* fInputSoftChannels[256];
149  jack_default_audio_sample_t* fOutputSoftChannels[256];
150 
151  //public methods ---------------------------------------------------------
152 
153  const char* cardName()
154  {
155  return fCardName;
156  }
157 
158  int frequency()
159  {
160  return fFrequency;
161  }
162 
163  int buffering()
164  {
165  return fBuffering;
166  }
167 
168  jack_default_audio_sample_t** inputSoftChannels()
169  {
170  return fInputSoftChannels;
171  }
172 
173  jack_default_audio_sample_t** outputSoftChannels()
174  {
175  return fOutputSoftChannels;
176  }
177 
178  AudioInterface ( const AudioParam& ap = AudioParam() ) : AudioParam ( ap )
179  {
180  fInputDevice = 0;
181  fOutputDevice = 0;
182  fInputParams = 0;
183  fOutputParams = 0;
184  fPeriod = 2;
185 
186  fInputCardBuffer = 0;
187  fOutputCardBuffer = 0;
188 
189  for ( int i = 0; i < 256; i++ )
190  {
191  fInputCardChannels[i] = 0;
192  fOutputCardChannels[i] = 0;
193  fInputSoftChannels[i] = 0;
194  fOutputSoftChannels[i] = 0;
195  }
196  }
197 
198  AudioInterface ( jack_nframes_t buffer_size, jack_nframes_t sample_rate ) :
199  AudioParam ( buffer_size, sample_rate )
200  {
201  fInputCardBuffer = 0;
202  fOutputCardBuffer = 0;
203 
204  for ( int i = 0; i < 256; i++ )
205  {
206  fInputCardChannels[i] = 0;
207  fOutputCardChannels[i] = 0;
208  fInputSoftChannels[i] = 0;
209  fOutputSoftChannels[i] = 0;
210  }
211  }
212 
216  int open()
217  {
218  //open input/output streams
219  check_error ( snd_pcm_open ( &fInputDevice, fCardName, SND_PCM_STREAM_CAPTURE, 0 ) );
220  check_error ( snd_pcm_open ( &fOutputDevice, fCardName, SND_PCM_STREAM_PLAYBACK, 0 ) );
221 
222  //get hardware input parameters
223  check_error ( snd_pcm_hw_params_malloc ( &fInputParams ) );
224  setAudioParams ( fInputDevice, fInputParams );
225 
226  //get hardware output parameters
227  check_error ( snd_pcm_hw_params_malloc ( &fOutputParams ) )
228  setAudioParams ( fOutputDevice, fOutputParams );
229 
230  // set the number of physical input and output channels close to what we need
231  fCardInputs = fSoftInputs;
232  fCardOutputs = fSoftOutputs;
233 
234  snd_pcm_hw_params_set_channels_near(fInputDevice, fInputParams, &fCardInputs);
235  snd_pcm_hw_params_set_channels_near(fOutputDevice, fOutputParams, &fCardOutputs);
236 
237  //set input/output param
238  check_error ( snd_pcm_hw_params ( fInputDevice, fInputParams ) );
239  check_error ( snd_pcm_hw_params ( fOutputDevice, fOutputParams ) );
240 
241  //set hardware buffers
242  if ( fSampleAccess == SND_PCM_ACCESS_RW_INTERLEAVED )
243  {
244  fInputCardBuffer = aligned_calloc ( interleavedBufferSize ( fInputParams ), 1 );
245  fOutputCardBuffer = aligned_calloc ( interleavedBufferSize ( fOutputParams ), 1 );
246  }
247  else
248  {
249  for ( unsigned int i = 0; i < fCardInputs; i++ )
250  fInputCardChannels[i] = aligned_calloc ( noninterleavedBufferSize ( fInputParams ), 1 );
251  for ( unsigned int i = 0; i < fCardOutputs; i++ )
252  fOutputCardChannels[i] = aligned_calloc ( noninterleavedBufferSize ( fOutputParams ), 1 );
253  }
254 
255  //set floating point buffers needed by the dsp code
256  fSoftInputs = max ( fSoftInputs, fCardInputs );
257  assert ( fSoftInputs < 256 );
258  fSoftOutputs = max ( fSoftOutputs, fCardOutputs );
259  assert ( fSoftOutputs < 256 );
260 
261  for ( unsigned int i = 0; i < fSoftInputs; i++ )
262  {
263  fInputSoftChannels[i] = ( jack_default_audio_sample_t* ) aligned_calloc ( fBuffering, sizeof ( jack_default_audio_sample_t ) );
264  for ( int j = 0; j < fBuffering; j++ )
265  fInputSoftChannels[i][j] = 0.0;
266  }
267 
268  for ( unsigned int i = 0; i < fSoftOutputs; i++ )
269  {
270  fOutputSoftChannels[i] = ( jack_default_audio_sample_t* ) aligned_calloc ( fBuffering, sizeof ( jack_default_audio_sample_t ) );
271  for ( int j = 0; j < fBuffering; j++ )
272  fOutputSoftChannels[i][j] = 0.0;
273  }
274  return 0;
275  }
276 
277  int close()
278  {
279  snd_pcm_hw_params_free ( fInputParams );
280  snd_pcm_hw_params_free ( fOutputParams );
281  snd_pcm_close ( fInputDevice );
282  snd_pcm_close ( fOutputDevice );
283 
284  for ( unsigned int i = 0; i < fSoftInputs; i++ )
285  if ( fInputSoftChannels[i] )
286  free ( fInputSoftChannels[i] );
287 
288  for ( unsigned int i = 0; i < fSoftOutputs; i++ )
289  if ( fOutputSoftChannels[i] )
290  free ( fOutputSoftChannels[i] );
291 
292  for ( unsigned int i = 0; i < fCardInputs; i++ )
293  if ( fInputCardChannels[i] )
294  free ( fInputCardChannels[i] );
295 
296  for ( unsigned int i = 0; i < fCardOutputs; i++ )
297  if ( fOutputCardChannels[i] )
298  free ( fOutputCardChannels[i] );
299 
300  if ( fInputCardBuffer )
301  free ( fInputCardBuffer );
302  if ( fOutputCardBuffer )
303  free ( fOutputCardBuffer );
304 
305  return 0;
306  }
307 
308  int setAudioParams ( snd_pcm_t* stream, snd_pcm_hw_params_t* params )
309  {
310  //set params record with initial values
311  check_error_msg ( snd_pcm_hw_params_any ( stream, params ), "unable to init parameters" )
312 
313  //set alsa access mode (and fSampleAccess field) either to non interleaved or interleaved
314  if ( snd_pcm_hw_params_set_access ( stream, params, SND_PCM_ACCESS_RW_NONINTERLEAVED ) )
315  check_error_msg ( snd_pcm_hw_params_set_access ( stream, params, SND_PCM_ACCESS_RW_INTERLEAVED ),
316  "unable to set access mode neither to non-interleaved or to interleaved" );
317  snd_pcm_hw_params_get_access ( params, &fSampleAccess );
318 
319  //search for 32-bits or 16-bits format
320  if ( snd_pcm_hw_params_set_format ( stream, params, SND_PCM_FORMAT_S32 ) )
321  check_error_msg ( snd_pcm_hw_params_set_format ( stream, params, SND_PCM_FORMAT_S16 ),
322  "unable to set format to either 32-bits or 16-bits" );
323  snd_pcm_hw_params_get_format ( params, &fSampleFormat );
324 
325  //set sample frequency
326  snd_pcm_hw_params_set_rate_near ( stream, params, &fFrequency, 0 );
327 
328  //set period and period size (buffering)
329  check_error_msg ( snd_pcm_hw_params_set_period_size ( stream, params, fBuffering, 0 ), "period size not available" );
330  check_error_msg ( snd_pcm_hw_params_set_periods ( stream, params, fPeriod, 0 ), "number of periods not available" );
331 
332  return 0;
333  }
334 
335  ssize_t interleavedBufferSize ( snd_pcm_hw_params_t* params )
336  {
337  _snd_pcm_format format;
338  unsigned int channels;
339  snd_pcm_hw_params_get_format ( params, &format );
340  snd_pcm_uframes_t psize;
341  snd_pcm_hw_params_get_period_size ( params, &psize, NULL );
342  snd_pcm_hw_params_get_channels ( params, &channels );
343  ssize_t bsize = snd_pcm_format_size ( format, psize * channels );
344  return bsize;
345  }
346 
347  ssize_t noninterleavedBufferSize ( snd_pcm_hw_params_t* params )
348  {
349  _snd_pcm_format format;
350  snd_pcm_hw_params_get_format ( params, &format );
351  snd_pcm_uframes_t psize;
352  snd_pcm_hw_params_get_period_size ( params, &psize, NULL );
353  ssize_t bsize = snd_pcm_format_size ( format, psize );
354  return bsize;
355  }
356 
361  int read()
362  {
363  int count, s;
364  unsigned int c;
365  switch ( fSampleAccess )
366  {
367  case SND_PCM_ACCESS_RW_INTERLEAVED :
368  count = snd_pcm_readi ( fInputDevice, fInputCardBuffer, fBuffering );
369  if ( count < 0 )
370  {
371  display_error_msg ( count, "reading samples" );
372  check_error_msg ( snd_pcm_prepare ( fInputDevice ), "preparing input stream" );
373  }
374  if ( fSampleFormat == SND_PCM_FORMAT_S16 )
375  {
376  short* buffer16b = ( short* ) fInputCardBuffer;
377  for ( s = 0; s < fBuffering; s++ )
378  for ( c = 0; c < fCardInputs; c++ )
379  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));
380  }
381  else // SND_PCM_FORMAT_S32
382  {
383  int32_t* buffer32b = ( int32_t* ) fInputCardBuffer;
384  for ( s = 0; s < fBuffering; s++ )
385  for ( c = 0; c < fCardInputs; c++ )
386  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));
387  }
388  break;
389  case SND_PCM_ACCESS_RW_NONINTERLEAVED :
390  count = snd_pcm_readn ( fInputDevice, fInputCardChannels, fBuffering );
391  if ( count < 0 )
392  {
393  display_error_msg ( count, "reading samples" );
394  check_error_msg ( snd_pcm_prepare ( fInputDevice ), "preparing input stream" );
395  }
396  if ( fSampleFormat == SND_PCM_FORMAT_S16 )
397  {
398  short* chan16b;
399  for ( c = 0; c < fCardInputs; c++ )
400  {
401  chan16b = ( short* ) fInputCardChannels[c];
402  for ( s = 0; s < fBuffering; s++ )
403  fInputSoftChannels[c][s] = jack_default_audio_sample_t(chan16b[s]) * (jack_default_audio_sample_t(1.0)/jack_default_audio_sample_t(SHRT_MAX));
404  }
405  }
406  else // SND_PCM_FORMAT_S32
407  {
408  int32_t* chan32b;
409  for ( c = 0; c < fCardInputs; c++ )
410  {
411  chan32b = ( int32_t* ) fInputCardChannels[c];
412  for ( s = 0; s < fBuffering; s++ )
413  fInputSoftChannels[c][s] = jack_default_audio_sample_t(chan32b[s]) * (jack_default_audio_sample_t(1.0)/jack_default_audio_sample_t(INT_MAX));
414  }
415  }
416  break;
417  default :
418  check_error_msg ( -10000, "unknow access mode" );
419  break;
420  }
421  return 0;
422  }
423 
428  int write()
429  {
430  int count, f;
431  unsigned int c;
432  recovery:
433  switch ( fSampleAccess )
434  {
435  case SND_PCM_ACCESS_RW_INTERLEAVED :
436  if ( fSampleFormat == SND_PCM_FORMAT_S16 )
437  {
438  short* buffer16b = ( short* ) fOutputCardBuffer;
439  for ( f = 0; f < fBuffering; f++ )
440  {
441  for ( unsigned int c = 0; c < fCardOutputs; c++ )
442  {
443  jack_default_audio_sample_t x = fOutputSoftChannels[c][f];
444  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));
445  }
446  }
447  }
448  else // SND_PCM_FORMAT_S32
449  {
450  int32_t* buffer32b = ( int32_t* ) fOutputCardBuffer;
451  for ( f = 0; f < fBuffering; f++ )
452  {
453  for ( unsigned int c = 0; c < fCardOutputs; c++ )
454  {
455  jack_default_audio_sample_t x = fOutputSoftChannels[c][f];
456  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));
457  }
458  }
459  }
460  count = snd_pcm_writei ( fOutputDevice, fOutputCardBuffer, fBuffering );
461  if ( count < 0 )
462  {
463  display_error_msg ( count, "w3" );
464  int err = snd_pcm_prepare ( fOutputDevice );
465  check_error_msg ( err, "preparing output stream" );
466  goto recovery;
467  }
468  break;
469  case SND_PCM_ACCESS_RW_NONINTERLEAVED :
470  if ( fSampleFormat == SND_PCM_FORMAT_S16 )
471  {
472  for ( c = 0; c < fCardOutputs; c++ )
473  {
474  short* chan16b = ( short* ) fOutputCardChannels[c];
475  for ( f = 0; f < fBuffering; f++ )
476  {
477  jack_default_audio_sample_t x = fOutputSoftChannels[c][f];
478  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));
479  }
480  }
481  }
482  else
483  {
484  for ( c = 0; c < fCardOutputs; c++ )
485  {
486  int32_t* chan32b = ( int32_t* ) fOutputCardChannels[c];
487  for ( f = 0; f < fBuffering; f++ )
488  {
489  jack_default_audio_sample_t x = fOutputSoftChannels[c][f];
490  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));
491  }
492  }
493  }
494  count = snd_pcm_writen ( fOutputDevice, fOutputCardChannels, fBuffering );
495  if ( count<0 )
496  {
497  display_error_msg ( count, "w3" );
498  int err = snd_pcm_prepare ( fOutputDevice );
499  check_error_msg ( err, "preparing output stream" );
500  goto recovery;
501  }
502  break;
503  default :
504  check_error_msg ( -10000, "unknow access mode" );
505  break;
506  }
507  return 0;
508  }
509 
513  int shortinfo()
514  {
515  int err;
516  snd_ctl_card_info_t* card_info;
517  snd_ctl_t* ctl_handle;
518  err = snd_ctl_open ( &ctl_handle, fCardName, 0 ); check_error ( err );
519  snd_ctl_card_info_alloca ( &card_info );
520  err = snd_ctl_card_info ( ctl_handle, card_info ); check_error ( err );
521  jack_info ( "%s|%d|%d|%d|%d|%s",
522  snd_ctl_card_info_get_driver ( card_info ),
523  fCardInputs, fCardOutputs,
524  fFrequency, fBuffering,
525  snd_pcm_format_name ( ( _snd_pcm_format ) fSampleFormat ) );
526  }
527 
531  int longinfo()
532  {
533  snd_ctl_card_info_t* card_info;
534  snd_ctl_t* ctl_handle;
535 
536  //display info
537  jack_info ( "Audio Interface Description :" );
538  jack_info ( "Sampling Frequency : %d, Sample Format : %s, buffering : %d, nperiod : %d",
539  fFrequency, snd_pcm_format_name ( ( _snd_pcm_format ) fSampleFormat ), fBuffering, fPeriod );
540  jack_info ( "Software inputs : %2d, Software outputs : %2d", fSoftInputs, fSoftOutputs );
541  jack_info ( "Hardware inputs : %2d, Hardware outputs : %2d", fCardInputs, fCardOutputs );
542 
543  //get audio card info and display
544  check_error ( snd_ctl_open ( &ctl_handle, fCardName, 0 ) );
545  snd_ctl_card_info_alloca ( &card_info );
546  check_error ( snd_ctl_card_info ( ctl_handle, card_info ) );
547  printCardInfo ( card_info );
548 
549  //display input/output streams info
550  if ( fSoftInputs > 0 )
551  printHWParams ( fInputParams );
552  if ( fSoftOutputs > 0 )
553  printHWParams ( fOutputParams );
554 
555  return 0;
556  }
557 
558  void printCardInfo ( snd_ctl_card_info_t* ci )
559  {
560  jack_info ( "Card info (address : %p)", ci );
561  jack_info ( "\tID = %s", snd_ctl_card_info_get_id ( ci ) );
562  jack_info ( "\tDriver = %s", snd_ctl_card_info_get_driver ( ci ) );
563  jack_info ( "\tName = %s", snd_ctl_card_info_get_name ( ci ) );
564  jack_info ( "\tLongName = %s", snd_ctl_card_info_get_longname ( ci ) );
565  jack_info ( "\tMixerName = %s", snd_ctl_card_info_get_mixername ( ci ) );
566  jack_info ( "\tComponents = %s", snd_ctl_card_info_get_components ( ci ) );
567  jack_info ( "--------------" );
568  }
569 
570  void printHWParams ( snd_pcm_hw_params_t* params )
571  {
572  jack_info ( "HW Params info (address : %p)\n", params );
573 #if 0
574  jack_info ( "\tChannels = %d", snd_pcm_hw_params_get_channels ( params, NULL ) );
575  jack_info ( "\tFormat = %s", snd_pcm_format_name ( ( _snd_pcm_format ) snd_pcm_hw_params_get_format ( params, NULL ) ) );
576  jack_info ( "\tAccess = %s", snd_pcm_access_name ( ( _snd_pcm_access ) snd_pcm_hw_params_get_access ( params, NULL ) ) );
577  jack_info ( "\tRate = %d", snd_pcm_hw_params_get_rate ( params, NULL, NULL ) );
578  jack_info ( "\tPeriods = %d", snd_pcm_hw_params_get_periods ( params, NULL, NULL ) );
579  jack_info ( "\tPeriod size = %d", ( int ) snd_pcm_hw_params_get_period_size ( params, NULL, NULL ) );
580  jack_info ( "\tPeriod time = %d", snd_pcm_hw_params_get_period_time ( params, NULL, NULL ) );
581  jack_info ( "\tBuffer size = %d", ( int ) snd_pcm_hw_params_get_buffer_size ( params, NULL ) );
582  jack_info ( "\tBuffer time = %d", snd_pcm_hw_params_get_buffer_time ( params, NULL, NULL ) );
583 #endif
584  jack_info ( "--------------" );
585  }
586  };
587 
593  {
594 
595  private:
596  JackThread fThread;
597  AudioInterface fAudioInterface;
598 
599  public:
600  JackAlsaAdapter ( jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params );
601  ~JackAlsaAdapter()
602  {}
603 
604  virtual int Open();
605  virtual int Close();
606 
607  virtual int SetSampleRate ( jack_nframes_t sample_rate );
608  virtual int SetBufferSize ( jack_nframes_t buffer_size );
609 
610  virtual bool Init();
611  virtual bool Execute();
612 
613  };
614 
615 }
616 
617 #ifdef __cplusplus
618 extern "C"
619 {
620 #endif
621 
622 #include "JackCompilerDeps.h"
623 #include "driver_interface.h"
624 
625 SERVER_EXPORT jack_driver_desc_t* jack_get_descriptor();
626 
627 #ifdef __cplusplus
628 }
629 #endif
630 
631 #endif