Revision 6d1d64eb

b/gr-audio/lib/Makefile.am
47 47
########################################################################
48 48
if GR_AUDIO_ALSA_SUPPORT
49 49

50
AM_CPPFLAGS += $(ALSA_CPPFLAGS)
50
AM_CPPFLAGS += \
51
	-I$(srcdir)/alsa \
52
	$(ALSA_CPPFLAGS)
51 53

52 54
libgnuradio_audio_la_LIBADD += $(ALSA_LIBS)
53 55

54 56
libgnuradio_audio_la_SOURCES += \
55
	gri_alsa.cc \
56
	audio_alsa_source.cc \
57
	audio_alsa_sink.cc
57
	alsa/gri_alsa.cc \
58
	alsa/audio_alsa_source.cc \
59
	alsa/audio_alsa_sink.cc
58 60

59 61
noinst_HEADERS += \
60
	gri_alsa.h \
61
	audio_alsa_source.h \
62
	audio_alsa_sink.h
62
	alsa/gri_alsa.h \
63
	alsa/audio_alsa_source.h \
64
	alsa/audio_alsa_sink.h
63 65

64
dist_etc_DATA += gr-audio-alsa.conf
66
dist_etc_DATA += alsa/gr-audio-alsa.conf
65 67

66 68
endif
b/gr-audio/lib/alsa/audio_alsa_sink.cc
1
/* -*- c++ -*- */
2
/*
3
 * Copyright 2004-2011 Free Software Foundation, Inc.
4
 * 
5
 * This file is part of GNU Radio
6
 * 
7
 * GNU Radio is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3, or (at your option)
10
 * any later version.
11
 * 
12
 * GNU Radio is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 * 
17
 * You should have received a copy of the GNU General Public License
18
 * along with GNU Radio; see the file COPYING.  If not, write to
19
 * the Free Software Foundation, Inc., 51 Franklin Street,
20
 * Boston, MA 02110-1301, USA.
21
 */
22

23
#ifdef HAVE_CONFIG_H
24
#include "config.h"
25
#endif
26

27
#include "gr_audio_registry.h"
28
#include <audio_alsa_sink.h>
29
#include <gr_io_signature.h>
30
#include <gr_prefs.h>
31
#include <stdio.h>
32
#include <iostream>
33
#include <stdexcept>
34
#include <gri_alsa.h>
35

36
AUDIO_REGISTER_SINK(alsa)(
37
    int sampling_rate, const std::string &device_name, bool ok_to_block
38
){
39
    return audio_sink::sptr(new audio_alsa_sink(sampling_rate, device_name, ok_to_block));
40
}
41

42
static bool CHATTY_DEBUG = false;
43

44

45
static snd_pcm_format_t acceptable_formats[] = {
46
  // these are in our preferred order...
47
  SND_PCM_FORMAT_S32,
48
  SND_PCM_FORMAT_S16
49
};
50

51
#define NELEMS(x) (sizeof(x)/sizeof(x[0]))
52

53

54
static std::string 
55
default_device_name ()
56
{
57
  return gr_prefs::singleton()->get_string("audio_alsa", "default_output_device", "hw:0,0");
58
}
59

60
static double
61
default_period_time ()
62
{
63
  return std::max(0.001, gr_prefs::singleton()->get_double("audio_alsa", "period_time", 0.010));
64
}
65

66
static int
67
default_nperiods ()
68
{
69
  return std::max(2L, gr_prefs::singleton()->get_long("audio_alsa", "nperiods", 4));
70
}
71

72
// ----------------------------------------------------------------
73

74
audio_alsa_sink::audio_alsa_sink (int sampling_rate,
75
				  const std::string device_name,
76
				  bool ok_to_block)
77
  : audio_sink ("audio_alsa_sink",
78
		   gr_make_io_signature (0, 0, 0),
79
		   gr_make_io_signature (0, 0, 0)),
80
    d_sampling_rate (sampling_rate),
81
    d_device_name (device_name.empty() ? default_device_name() : device_name),
82
    d_pcm_handle (0),
83
    d_hw_params ((snd_pcm_hw_params_t *)(new char[snd_pcm_hw_params_sizeof()])),
84
    d_sw_params ((snd_pcm_sw_params_t *)(new char[snd_pcm_sw_params_sizeof()])),
85
    d_nperiods (default_nperiods()),
86
    d_period_time_us ((unsigned int) (default_period_time() * 1e6)),
87
    d_period_size (0),
88
    d_buffer_size_bytes (0), d_buffer (0),
89
    d_worker (0), d_special_case_mono_to_stereo (false),
90
    d_nunderuns (0), d_nsuspends (0), d_ok_to_block(ok_to_block)
91
{
92
  CHATTY_DEBUG = gr_prefs::singleton()->get_bool("audio_alsa", "verbose", false);
93

94
  int  	error;
95
  int	dir;
96

97
  // open the device for playback
98
  error = snd_pcm_open(&d_pcm_handle, d_device_name.c_str (),
99
		       SND_PCM_STREAM_PLAYBACK, 0);
100
  if (ok_to_block == false)
101
    snd_pcm_nonblock(d_pcm_handle, !ok_to_block);
102
  if (error < 0){
103
    fprintf (stderr, "audio_alsa_sink[%s]: %s\n",
104
	     d_device_name.c_str(), snd_strerror(error));
105
    throw std::runtime_error ("audio_alsa_sink");
106
  }
107

108
  // Fill params with a full configuration space for a PCM.
109
  error = snd_pcm_hw_params_any(d_pcm_handle, d_hw_params);
110
  if (error < 0)
111
    bail ("broken configuration for playback", error);
112

113

114
  if (CHATTY_DEBUG)
115
    gri_alsa_dump_hw_params (d_pcm_handle, d_hw_params, stdout);
116

117

118
  // now that we know how many channels the h/w can handle, set input signature
119
  unsigned int umin_chan, umax_chan;
120
  snd_pcm_hw_params_get_channels_min (d_hw_params, &umin_chan);
121
  snd_pcm_hw_params_get_channels_max (d_hw_params, &umax_chan);
122
  int min_chan = std::min (umin_chan, 1000U);
123
  int max_chan = std::min (umax_chan, 1000U);
124

125
  // As a special case, if the hw's min_chan is two, we'll accept
126
  // a single input and handle the duplication ourselves.
127

128
  if (min_chan == 2){
129
    min_chan = 1;
130
    d_special_case_mono_to_stereo = true;
131
  }
132
  set_input_signature (gr_make_io_signature (min_chan, max_chan,
133
					     sizeof (float)));
134
  
135
  // fill in portions of the d_hw_params that we know now...
136

137
  // Specify the access methods we implement
138
  // For now, we only handle RW_INTERLEAVED...
139
  snd_pcm_access_mask_t *access_mask;
140
  snd_pcm_access_mask_t **access_mask_ptr = &access_mask; // FIXME: workaround for compiler warning
141
  snd_pcm_access_mask_alloca (access_mask_ptr);
142
  snd_pcm_access_mask_none (access_mask);
143
  snd_pcm_access_mask_set (access_mask, SND_PCM_ACCESS_RW_INTERLEAVED);
144
  // snd_pcm_access_mask_set (access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED);
145

146
  if ((error = snd_pcm_hw_params_set_access_mask (d_pcm_handle,
147
						  d_hw_params, access_mask)) < 0)
148
    bail ("failed to set access mask", error);
149

150

151
  // set sample format
152
  if (!gri_alsa_pick_acceptable_format (d_pcm_handle, d_hw_params,
153
					acceptable_formats,
154
					NELEMS (acceptable_formats),
155
					&d_format,
156
					"audio_alsa_sink",
157
					CHATTY_DEBUG))
158
    throw std::runtime_error ("audio_alsa_sink");
159
  
160

161
  // sampling rate
162
  unsigned int orig_sampling_rate = d_sampling_rate;
163
  if ((error = snd_pcm_hw_params_set_rate_near (d_pcm_handle, d_hw_params,
164
						&d_sampling_rate, 0)) < 0)
165
    bail ("failed to set rate near", error);
166
  
167
  if (orig_sampling_rate != d_sampling_rate){
168
    fprintf (stderr, "audio_alsa_sink[%s]: unable to support sampling rate %d\n",
169
	     snd_pcm_name (d_pcm_handle), orig_sampling_rate);
170
    fprintf (stderr, "  card requested %d instead.\n", d_sampling_rate);
171
  }
172

173
  /*
174
   * ALSA transfers data in units of "periods".
175
   * We indirectly determine the underlying buffersize by specifying
176
   * the number of periods we want (typically 4) and the length of each
177
   * period in units of time (typically 1ms).
178
   */
179
  unsigned int min_nperiods, max_nperiods;
180
  snd_pcm_hw_params_get_periods_min (d_hw_params, &min_nperiods, &dir);
181
  snd_pcm_hw_params_get_periods_max (d_hw_params, &max_nperiods, &dir);
182
  //fprintf (stderr, "alsa_sink: min_nperiods = %d, max_nperiods = %d\n",
183
  // min_nperiods, max_nperiods);
184

185
  unsigned int orig_nperiods = d_nperiods;
186
  d_nperiods = std::min (std::max (min_nperiods, d_nperiods), max_nperiods);
187

188
  // adjust period time so that total buffering remains more-or-less constant
189
  d_period_time_us = (d_period_time_us * orig_nperiods) / d_nperiods;
190

191
  error = snd_pcm_hw_params_set_periods (d_pcm_handle, d_hw_params,
192
					 d_nperiods, 0);
193
  if (error < 0)
194
    bail ("set_periods failed", error);
195

196
  dir = 0;
197
  error = snd_pcm_hw_params_set_period_time_near (d_pcm_handle, d_hw_params,
198
						  &d_period_time_us, &dir);
199
  if (error < 0)
200
    bail ("set_period_time_near failed", error);
201

202
  dir = 0;
203
  error = snd_pcm_hw_params_get_period_size (d_hw_params,
204
					     &d_period_size, &dir);
205
  if (error < 0)
206
    bail ("get_period_size failed", error);
207
  
208
  set_output_multiple (d_period_size);
209
}
210

211

212
bool
213
audio_alsa_sink::check_topology (int ninputs, int noutputs)
214
{
215
  // ninputs is how many channels the user has connected.
216
  // Now we can finish up setting up the hw params...
217

218
  int nchan = ninputs;
219
  int err;
220

221
  // Check the state of the stream
222
  // Ensure that the pcm is in a state where we can still mess with the hw_params
223
  snd_pcm_state_t state;
224
  state=snd_pcm_state(d_pcm_handle);
225
  if ( state== SND_PCM_STATE_RUNNING)
226
    return true;  // If stream is running, don't change any parameters
227
  else if(state == SND_PCM_STATE_XRUN )
228
    snd_pcm_prepare ( d_pcm_handle ); // Prepare stream on underrun, and we can set parameters;
229
  
230
  bool special_case = nchan == 1 && d_special_case_mono_to_stereo;
231
  if (special_case)
232
    nchan = 2;
233
  
234
  err = snd_pcm_hw_params_set_channels (d_pcm_handle, d_hw_params, nchan);
235

236
  if (err < 0){
237
    output_error_msg ("set_channels failed", err);
238
    return false;
239
  }
240

241
  // set the parameters into the driver...
242
  err = snd_pcm_hw_params(d_pcm_handle, d_hw_params);
243
  if (err < 0){
244
    output_error_msg ("snd_pcm_hw_params failed", err);
245
    return false;
246
  }
247

248
  // get current s/w params
249
  err = snd_pcm_sw_params_current (d_pcm_handle, d_sw_params);
250
  if (err < 0)
251
    bail ("snd_pcm_sw_params_current", err);
252
  
253
  // Tell the PCM device to wait to start until we've filled
254
  // it's buffers half way full.  This helps avoid audio underruns.
255

256
  err = snd_pcm_sw_params_set_start_threshold(d_pcm_handle,
257
					      d_sw_params,
258
					      d_nperiods * d_period_size / 2);
259
  if (err < 0)
260
    bail ("snd_pcm_sw_params_set_start_threshold", err);
261

262
  // store the s/w params
263
  err = snd_pcm_sw_params (d_pcm_handle, d_sw_params);
264
  if (err < 0)
265
    bail ("snd_pcm_sw_params", err);
266

267
  d_buffer_size_bytes =
268
    d_period_size * nchan * snd_pcm_format_size (d_format, 1);
269

270
  d_buffer = new char [d_buffer_size_bytes];
271

272
  if (CHATTY_DEBUG)
273
    fprintf (stdout, "audio_alsa_sink[%s]: sample resolution = %d bits\n",
274
	     snd_pcm_name (d_pcm_handle),
275
	     snd_pcm_hw_params_get_sbits (d_hw_params));
276

277
  switch (d_format){
278
  case SND_PCM_FORMAT_S16:
279
    if (special_case)
280
      d_worker = &audio_alsa_sink::work_s16_1x2;
281
    else
282
      d_worker = &audio_alsa_sink::work_s16;
283
    break;
284

285
  case SND_PCM_FORMAT_S32:
286
    if (special_case)
287
      d_worker = &audio_alsa_sink::work_s32_1x2;
288
    else
289
      d_worker = &audio_alsa_sink::work_s32;
290
    break;
291

292
  default:
293
    assert (0);
294
  }
295
  return true;
296
}
297

298
audio_alsa_sink::~audio_alsa_sink ()
299
{
300
  if (snd_pcm_state (d_pcm_handle) == SND_PCM_STATE_RUNNING)
301
    snd_pcm_drop (d_pcm_handle);
302

303
  snd_pcm_close(d_pcm_handle);
304
  delete [] ((char *) d_hw_params);
305
  delete [] ((char *) d_sw_params);
306
  delete [] d_buffer;
307
}
308

309
int
310
audio_alsa_sink::work (int noutput_items,
311
		       gr_vector_const_void_star &input_items,
312
		       gr_vector_void_star &output_items)
313
{
314
  assert ((noutput_items % d_period_size) == 0);
315

316
  // this is a call through a pointer to a method...
317
  return (this->*d_worker)(noutput_items, input_items, output_items);
318
}
319

320
/*
321
 * Work function that deals with float to S16 conversion
322
 */
323
int
324
audio_alsa_sink::work_s16 (int noutput_items,
325
			   gr_vector_const_void_star &input_items,
326
			   gr_vector_void_star &output_items)
327
{
328
  typedef gr_int16	sample_t;	// the type of samples we're creating
329
  static const int NBITS = 16;		// # of bits in a sample
330
  
331
  unsigned int nchan = input_items.size ();
332
  const float **in = (const float **) &input_items[0];
333
  sample_t *buf = (sample_t *) d_buffer;
334
  int bi;
335
  int n;
336

337
  unsigned int sizeof_frame = nchan * sizeof (sample_t);
338
  assert (d_buffer_size_bytes == d_period_size * sizeof_frame);
339

340
  for (n = 0; n < noutput_items; n += d_period_size){
341

342
    // process one period of data
343
    bi = 0;
344
    for (unsigned int i = 0; i < d_period_size; i++){
345
      for (unsigned int chan = 0; chan < nchan; chan++){
346
	buf[bi++] = (sample_t) (in[chan][i] * (float) ((1L << (NBITS-1)) - 1));
347
      }
348
    }
349

350
    // update src pointers
351
    for (unsigned int chan = 0; chan < nchan; chan++)
352
      in[chan] += d_period_size;
353

354
    if (!write_buffer (buf, d_period_size, sizeof_frame))  
355
      return -1;	// No fixing this problem.  Say we're done.
356
  }
357

358
  return n;
359
}
360

361

362
/*
363
 * Work function that deals with float to S32 conversion
364
 */
365
int
366
audio_alsa_sink::work_s32 (int noutput_items,
367
			   gr_vector_const_void_star &input_items,
368
			   gr_vector_void_star &output_items)
369
{
370
  typedef gr_int32	sample_t;	// the type of samples we're creating
371
  static const int NBITS = 32;		// # of bits in a sample
372
  
373
  unsigned int nchan = input_items.size ();
374
  const float **in = (const float **) &input_items[0];
375
  sample_t *buf = (sample_t *) d_buffer;
376
  int bi;
377
  int n;
378

379
  unsigned int sizeof_frame = nchan * sizeof (sample_t);
380
  assert (d_buffer_size_bytes == d_period_size * sizeof_frame);
381

382
  for (n = 0; n < noutput_items; n += d_period_size){
383

384
    // process one period of data
385
    bi = 0;
386
    for (unsigned int i = 0; i < d_period_size; i++){
387
      for (unsigned int chan = 0; chan < nchan; chan++){
388
	buf[bi++] = (sample_t) (in[chan][i] * (float) ((1L << (NBITS-1)) - 1));
389
      }
390
    }
391

392
    // update src pointers
393
    for (unsigned int chan = 0; chan < nchan; chan++)
394
      in[chan] += d_period_size;
395

396
    if (!write_buffer (buf, d_period_size, sizeof_frame))  
397
      return -1;	// No fixing this problem.  Say we're done.
398
  }
399

400
  return n;
401
}
402

403
/*
404
 * Work function that deals with float to S16 conversion and
405
 * mono to stereo kludge.
406
 */
407
int
408
audio_alsa_sink::work_s16_1x2 (int noutput_items,
409
			       gr_vector_const_void_star &input_items,
410
			       gr_vector_void_star &output_items)
411
{
412
  typedef gr_int16	sample_t;	// the type of samples we're creating
413
  static const int NBITS = 16;		// # of bits in a sample
414
  
415
  assert (input_items.size () == 1);
416
  static const unsigned int nchan = 2;
417
  const float **in = (const float **) &input_items[0];
418
  sample_t *buf = (sample_t *) d_buffer;
419
  int bi;
420
  int n;
421

422
  unsigned int sizeof_frame = nchan * sizeof (sample_t);
423
  assert (d_buffer_size_bytes == d_period_size * sizeof_frame);
424

425
  for (n = 0; n < noutput_items; n += d_period_size){
426

427
    // process one period of data
428
    bi = 0;
429
    for (unsigned int i = 0; i < d_period_size; i++){
430
      sample_t t = (sample_t) (in[0][i] * (float) ((1L << (NBITS-1)) - 1));
431
      buf[bi++] = t;
432
      buf[bi++] = t;
433
    }
434

435
    // update src pointers
436
    in[0] += d_period_size;
437

438
    if (!write_buffer (buf, d_period_size, sizeof_frame))  
439
      return -1;	// No fixing this problem.  Say we're done.
440
  }
441

442
  return n;
443
}
444

445
/*
446
 * Work function that deals with float to S32 conversion and
447
 * mono to stereo kludge.
448
 */
449
int
450
audio_alsa_sink::work_s32_1x2 (int noutput_items,
451
			       gr_vector_const_void_star &input_items,
452
			       gr_vector_void_star &output_items)
453
{
454
  typedef gr_int32	sample_t;	// the type of samples we're creating
455
  static const int NBITS = 32;		// # of bits in a sample
456
  
457
  assert (input_items.size () == 1);
458
  static unsigned int nchan = 2;
459
  const float **in = (const float **) &input_items[0];
460
  sample_t *buf = (sample_t *) d_buffer;
461
  int bi;
462
  int n;
463

464
  unsigned int sizeof_frame = nchan * sizeof (sample_t);
465
  assert (d_buffer_size_bytes == d_period_size * sizeof_frame);
466

467
  for (n = 0; n < noutput_items; n += d_period_size){
468

469
    // process one period of data
470
    bi = 0;
471
    for (unsigned int i = 0; i < d_period_size; i++){
472
      sample_t t = (sample_t) (in[0][i] * (float) ((1L << (NBITS-1)) - 1));
473
      buf[bi++] = t;
474
      buf[bi++] = t;
475
    }
476

477
    // update src pointers
478
    in[0] += d_period_size;
479

480
    if (!write_buffer (buf, d_period_size, sizeof_frame))  
481
      return -1;	// No fixing this problem.  Say we're done.
482
  }
483

484
  return n;
485
}
486

487
bool
488
audio_alsa_sink::write_buffer (const void *vbuffer,
489
			       unsigned nframes, unsigned sizeof_frame)
490
{
491
  const unsigned char *buffer = (const unsigned char *) vbuffer;
492

493
  while (nframes > 0){
494
    int r = snd_pcm_writei (d_pcm_handle, buffer, nframes);
495
    if (r == -EAGAIN)
496
    {
497
      if (d_ok_to_block == true)
498
	continue;		// try again
499
      
500
      break;
501
    }
502

503
    else if (r == -EPIPE){	// underrun
504
      d_nunderuns++;
505
      fputs ("aU", stderr);
506
      if ((r = snd_pcm_prepare (d_pcm_handle)) < 0){
507
	output_error_msg ("snd_pcm_prepare failed. Can't recover from underrun", r);
508
	return false;
509
      }
510
      continue;			// try again
511
    }
512

513
    else if (r == -ESTRPIPE){	// h/w is suspended (whatever that means)
514
				// This is apparently related to power management
515
      d_nsuspends++;
516
      if ((r = snd_pcm_resume (d_pcm_handle)) < 0){
517
	output_error_msg ("failed to resume from suspend", r);
518
	return false;
519
      }
520
      continue;			// try again
521
    }
522

523
    else if (r < 0){
524
      output_error_msg ("snd_pcm_writei failed", r);
525
      return false;
526
    }
527

528
    nframes -= r;
529
    buffer += r * sizeof_frame;
530
  }
531

532
  return true;
533
}
534

535

536
void
537
audio_alsa_sink::output_error_msg (const char *msg, int err)
538
{
539
  fprintf (stderr, "audio_alsa_sink[%s]: %s: %s\n",
540
	   snd_pcm_name (d_pcm_handle), msg,  snd_strerror (err));
541
}
542

543
void
544
audio_alsa_sink::bail (const char *msg, int err) throw (std::runtime_error)
545
{
546
  output_error_msg (msg, err);
547
  throw std::runtime_error ("audio_alsa_sink");
548
}
b/gr-audio/lib/alsa/audio_alsa_sink.h
1
/* -*- c++ -*- */
2
/*
3
 * Copyright 2004-2011 Free Software Foundation, Inc.
4
 * 
5
 * This file is part of GNU Radio
6
 * 
7
 * GNU Radio is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3, or (at your option)
10
 * any later version.
11
 * 
12
 * GNU Radio is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 * 
17
 * You should have received a copy of the GNU General Public License
18
 * along with GNU Radio; see the file COPYING.  If not, write to
19
 * the Free Software Foundation, Inc., 51 Franklin Street,
20
 * Boston, MA 02110-1301, USA.
21
 */
22

23
#ifndef INCLUDED_AUDIO_ALSA_SINK_H
24
#define INCLUDED_AUDIO_ALSA_SINK_H
25

26
// use new ALSA API
27
#define ALSA_PCM_NEW_HW_PARAMS_API
28
#define ALSA_PCM_NEW_SW_PARAMS_API
29

30
#include <gr_audio_sink.h>
31
#include <string>
32
#include <alsa/asoundlib.h>
33
#include <stdexcept>
34

35
/*!
36
 * \brief audio sink using ALSA
37
 *
38
 * The sink has N input streams of floats, where N depends
39
 * on the hardware characteristics of the selected device.
40
 *
41
 * Input samples must be in the range [-1,1].
42
 */
43
class audio_alsa_sink : public audio_sink {
44
  // typedef for pointer to class work method
45
  typedef int (audio_alsa_sink::*work_t)(int noutput_items,
46
					 gr_vector_const_void_star &input_items,
47
					 gr_vector_void_star &output_items);
48

49
  unsigned int		d_sampling_rate;
50
  std::string		d_device_name;
51
  snd_pcm_t            *d_pcm_handle;
52
  snd_pcm_hw_params_t  *d_hw_params;
53
  snd_pcm_sw_params_t  *d_sw_params;
54
  snd_pcm_format_t	d_format;
55
  unsigned int		d_nperiods;
56
  unsigned int		d_period_time_us;	// microseconds
57
  snd_pcm_uframes_t	d_period_size;		// in frames
58
  unsigned int		d_buffer_size_bytes;	// sizeof of d_buffer
59
  char		       *d_buffer;
60
  work_t	        d_worker;		// the work method to use
61
  bool			d_special_case_mono_to_stereo;
62

63
  // random stats
64
  int			d_nunderuns;		// count of underruns
65
  int			d_nsuspends;		// count of suspends
66
  bool			d_ok_to_block;      // defaults to "true", controls blocking/non-block I/O
67

68
  void output_error_msg (const char *msg, int err);
69
  void bail (const char *msg, int err) throw (std::runtime_error);
70

71
public:
72
  audio_alsa_sink (int sampling_rate, const std::string device_name,
73
		   bool ok_to_block);
74

75
  ~audio_alsa_sink ();
76
  
77
  bool check_topology (int ninputs, int noutputs);
78

79
  int work (int noutput_items,
80
	    gr_vector_const_void_star &input_items,
81
	    gr_vector_void_star &output_items);
82

83

84
protected:
85
  bool write_buffer (const void *buffer, unsigned nframes, unsigned sizeof_frame);
86

87
  int work_s16 (int noutput_items,
88
		gr_vector_const_void_star &input_items,
89
		gr_vector_void_star &output_items);
90

91
  int work_s16_1x2 (int noutput_items,
92
		    gr_vector_const_void_star &input_items,
93
		    gr_vector_void_star &output_items);
94

95
  int work_s32 (int noutput_items,
96
		gr_vector_const_void_star &input_items,
97
		gr_vector_void_star &output_items);
98

99
  int work_s32_1x2 (int noutput_items,
100
		    gr_vector_const_void_star &input_items,
101
		    gr_vector_void_star &output_items);
102
};
103

104
#endif /* INCLUDED_AUDIO_ALSA_SINK_H */
b/gr-audio/lib/alsa/audio_alsa_source.cc
1
/* -*- c++ -*- */
2
/*
3
 * Copyright 2004-2011 Free Software Foundation, Inc.
4
 * 
5
 * This file is part of GNU Radio
6
 * 
7
 * GNU Radio is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3, or (at your option)
10
 * any later version.
11
 * 
12
 * GNU Radio is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 * 
17
 * You should have received a copy of the GNU General Public License
18
 * along with GNU Radio; see the file COPYING.  If not, write to
19
 * the Free Software Foundation, Inc., 51 Franklin Street,
20
 * Boston, MA 02110-1301, USA.
21
 */
22

23
#ifdef HAVE_CONFIG_H
24
#include "config.h"
25
#endif
26

27
#include "gr_audio_registry.h"
28
#include <audio_alsa_source.h>
29
#include <gr_io_signature.h>
30
#include <gr_prefs.h>
31
#include <stdio.h>
32
#include <iostream>
33
#include <stdexcept>
34
#include <gri_alsa.h>
35

36
AUDIO_REGISTER_SOURCE(alsa)(
37
    int sampling_rate, const std::string &device_name, bool ok_to_block
38
){
39
    return audio_source::sptr(new audio_alsa_source(sampling_rate, device_name, ok_to_block));
40
}
41

42
static bool CHATTY_DEBUG = false;
43

44
static snd_pcm_format_t acceptable_formats[] = {
45
  // these are in our preferred order...
46
  SND_PCM_FORMAT_S32,
47
  SND_PCM_FORMAT_S16
48
};
49

50
#define NELEMS(x) (sizeof(x)/sizeof(x[0]))
51

52

53
static std::string 
54
default_device_name ()
55
{
56
  return gr_prefs::singleton()->get_string("audio_alsa", "default_input_device", "hw:0,0");
57
}
58

59
static double
60
default_period_time ()
61
{
62
  return std::max(0.001, gr_prefs::singleton()->get_double("audio_alsa", "period_time", 0.010));
63
}
64

65
static int
66
default_nperiods ()
67
{
68
  return std::max(2L, gr_prefs::singleton()->get_long("audio_alsa", "nperiods", 4));
69
}
70

71
// ----------------------------------------------------------------
72

73
audio_alsa_source::audio_alsa_source (int sampling_rate,
74
				      const std::string device_name,
75
				      bool ok_to_block)
76
  : audio_source ("audio_alsa_source",
77
		   gr_make_io_signature (0, 0, 0),
78
		   gr_make_io_signature (0, 0, 0)),
79
    d_sampling_rate (sampling_rate),
80
    d_device_name (device_name.empty() ? default_device_name() : device_name),
81
    d_pcm_handle (0),
82
    d_hw_params ((snd_pcm_hw_params_t *)(new char[snd_pcm_hw_params_sizeof()])),
83
    d_sw_params ((snd_pcm_sw_params_t *)(new char[snd_pcm_sw_params_sizeof()])),
84
    d_nperiods (default_nperiods()),
85
    d_period_time_us ((unsigned int) (default_period_time() * 1e6)),
86
    d_period_size (0),
87
    d_buffer_size_bytes (0), d_buffer (0),
88
    d_worker (0), d_hw_nchan (0),
89
    d_special_case_stereo_to_mono (false),
90
    d_noverruns (0), d_nsuspends (0)
91
{
92

93
  CHATTY_DEBUG = gr_prefs::singleton()->get_bool("audio_alsa", "verbose", false);
94

95
  int  	error;
96
  int	dir;
97

98
  // open the device for capture
99
  error = snd_pcm_open(&d_pcm_handle, d_device_name.c_str (),
100
		       SND_PCM_STREAM_CAPTURE, 0);
101
  if (error < 0){
102
    fprintf (stderr, "audio_alsa_source[%s]: %s\n",
103
	     d_device_name.c_str(), snd_strerror(error));
104
    throw std::runtime_error ("audio_alsa_source");
105
  }
106

107
  // Fill params with a full configuration space for a PCM.
108
  error = snd_pcm_hw_params_any(d_pcm_handle, d_hw_params);
109
  if (error < 0)
110
    bail ("broken configuration for playback", error);
111

112
  if (CHATTY_DEBUG)
113
    gri_alsa_dump_hw_params (d_pcm_handle, d_hw_params, stdout);
114

115
  // now that we know how many channels the h/w can handle, set output signature
116
  unsigned int umax_chan;
117
  unsigned int umin_chan;
118
  snd_pcm_hw_params_get_channels_min (d_hw_params, &umin_chan);
119
  snd_pcm_hw_params_get_channels_max (d_hw_params, &umax_chan);
120
  int min_chan = std::min (umin_chan, 1000U);
121
  int max_chan = std::min (umax_chan, 1000U);
122

123
  // As a special case, if the hw's min_chan is two, we'll accept
124
  // a single output and handle the demux ourselves.
125

126
  if (min_chan == 2){
127
    min_chan = 1;
128
    d_special_case_stereo_to_mono = true;
129
  }
130
  
131
  set_output_signature (gr_make_io_signature (min_chan, max_chan,
132
					      sizeof (float)));
133
  
134
  // fill in portions of the d_hw_params that we know now...
135

136
  // Specify the access methods we implement
137
  // For now, we only handle RW_INTERLEAVED...
138
  snd_pcm_access_mask_t *access_mask;
139
  snd_pcm_access_mask_t **access_mask_ptr = &access_mask; // FIXME: workaround for compiler warning
140
  snd_pcm_access_mask_alloca (access_mask_ptr);
141
  snd_pcm_access_mask_none (access_mask);
142
  snd_pcm_access_mask_set (access_mask, SND_PCM_ACCESS_RW_INTERLEAVED);
143
  // snd_pcm_access_mask_set (access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED);
144

145
  if ((error = snd_pcm_hw_params_set_access_mask (d_pcm_handle,
146
						  d_hw_params, access_mask)) < 0)
147
    bail ("failed to set access mask", error);
148

149

150
  // set sample format
151
  if (!gri_alsa_pick_acceptable_format (d_pcm_handle, d_hw_params,
152
					acceptable_formats,
153
					NELEMS (acceptable_formats),
154
					&d_format,
155
					"audio_alsa_source",
156
					CHATTY_DEBUG))
157
    throw std::runtime_error ("audio_alsa_source");
158
  
159

160
  // sampling rate
161
  unsigned int orig_sampling_rate = d_sampling_rate;
162
  if ((error = snd_pcm_hw_params_set_rate_near (d_pcm_handle, d_hw_params,
163
						&d_sampling_rate, 0)) < 0)
164
    bail ("failed to set rate near", error);
165
  
166
  if (orig_sampling_rate != d_sampling_rate){
167
    fprintf (stderr, "audio_alsa_source[%s]: unable to support sampling rate %d\n",
168
	     snd_pcm_name (d_pcm_handle), orig_sampling_rate);
169
    fprintf (stderr, "  card requested %d instead.\n", d_sampling_rate);
170
  }
171

172
  /*
173
   * ALSA transfers data in units of "periods".
174
   * We indirectly determine the underlying buffersize by specifying
175
   * the number of periods we want (typically 4) and the length of each
176
   * period in units of time (typically 1ms).
177
   */
178
  unsigned int min_nperiods, max_nperiods;
179
  snd_pcm_hw_params_get_periods_min (d_hw_params, &min_nperiods, &dir);
180
  snd_pcm_hw_params_get_periods_max (d_hw_params, &max_nperiods, &dir);
181
  //fprintf (stderr, "alsa_source: min_nperiods = %d, max_nperiods = %d\n",
182
  // min_nperiods, max_nperiods);
183

184

185
  unsigned int orig_nperiods = d_nperiods;
186
  d_nperiods = std::min (std::max (min_nperiods, d_nperiods), max_nperiods);
187

188
  // adjust period time so that total buffering remains more-or-less constant
189
  d_period_time_us = (d_period_time_us * orig_nperiods) / d_nperiods;
190

191
  error = snd_pcm_hw_params_set_periods (d_pcm_handle, d_hw_params,
192
					 d_nperiods, 0);
193
  if (error < 0)
194
    bail ("set_periods failed", error);
195

196
  dir = 0;
197
  error = snd_pcm_hw_params_set_period_time_near (d_pcm_handle, d_hw_params,
198
						  &d_period_time_us, &dir);
199
  if (error < 0)
200
    bail ("set_period_time_near failed", error);
201

202
  dir = 0;
203
  error = snd_pcm_hw_params_get_period_size (d_hw_params,
204
					     &d_period_size, &dir);
205
  if (error < 0)
206
    bail ("get_period_size failed", error);
207
  
208
  set_output_multiple (d_period_size);
209
}
210

211
bool
212
audio_alsa_source::check_topology (int ninputs, int noutputs)
213
{
214
  // noutputs is how many channels the user has connected.
215
  // Now we can finish up setting up the hw params...
216

217
  unsigned int nchan = noutputs;
218
  int err;
219

220
  // FIXME check_topology may be called more than once.
221
  // Ensure that the pcm is in a state where we can still mess with the hw_params
222

223
  bool special_case = nchan == 1 && d_special_case_stereo_to_mono;
224
  if (special_case)
225
    nchan = 2;
226

227
  d_hw_nchan = nchan;
228
  err = snd_pcm_hw_params_set_channels (d_pcm_handle, d_hw_params, d_hw_nchan);
229
  if (err < 0){
230
    output_error_msg ("set_channels failed", err);
231
    return false;
232
  }
233

234
  // set the parameters into the driver...
235
  err = snd_pcm_hw_params(d_pcm_handle, d_hw_params);
236
  if (err < 0){
237
    output_error_msg ("snd_pcm_hw_params failed", err);
238
    return false;
239
  }
240

241
  d_buffer_size_bytes =
242
    d_period_size * d_hw_nchan * snd_pcm_format_size (d_format, 1);
243

244
  d_buffer = new char [d_buffer_size_bytes];
245

246
  if (CHATTY_DEBUG)
247
    fprintf (stdout, "audio_alsa_source[%s]: sample resolution = %d bits\n",
248
	     snd_pcm_name (d_pcm_handle),
249
	     snd_pcm_hw_params_get_sbits (d_hw_params));
250

251
  switch (d_format){
252
  case SND_PCM_FORMAT_S16:
253
    if (special_case)
254
      d_worker = &audio_alsa_source::work_s16_2x1;
255
    else
256
      d_worker = &audio_alsa_source::work_s16;
257
    break;
258

259
  case SND_PCM_FORMAT_S32:
260
    if (special_case)
261
      d_worker = &audio_alsa_source::work_s32_2x1;
262
    else
263
      d_worker = &audio_alsa_source::work_s32;
264
    break;
265

266
  default:
267
    assert (0);
268
  }
269

270
  return true;
271
}
272

273
audio_alsa_source::~audio_alsa_source ()
274
{
275
  if (snd_pcm_state (d_pcm_handle) == SND_PCM_STATE_RUNNING)
276
    snd_pcm_drop (d_pcm_handle);
277

278
  snd_pcm_close(d_pcm_handle);
279
  delete [] ((char *) d_hw_params);
280
  delete [] ((char *) d_sw_params);
281
  delete [] d_buffer;
282
}
283

284
int
285
audio_alsa_source::work (int noutput_items,
286
			 gr_vector_const_void_star &input_items,
287
			 gr_vector_void_star &output_items)
288
{
289
  assert ((noutput_items % d_period_size) == 0);
290
  assert (noutput_items != 0);
291

292
  // this is a call through a pointer to a method...
293
  return (this->*d_worker)(noutput_items, input_items, output_items);
294
}
295

296
/*
297
 * Work function that deals with float to S16 conversion
298
 */
299
int
300
audio_alsa_source::work_s16 (int noutput_items,
301
			     gr_vector_const_void_star &input_items,
302
			     gr_vector_void_star &output_items)
303
{
304
  typedef gr_int16	sample_t;	// the type of samples we're creating
305
  static const int NBITS = 16;		// # of bits in a sample
306
  
307
  unsigned int nchan = output_items.size ();
308
  float **out = (float **) &output_items[0];
309
  sample_t *buf = (sample_t *) d_buffer;
310
  int bi;
311

312
  unsigned int sizeof_frame = d_hw_nchan * sizeof (sample_t);
313
  assert (d_buffer_size_bytes == d_period_size * sizeof_frame);
314

315
  // To minimize latency, return at most a single period's worth of samples.
316
  // [We could also read the first one in a blocking mode and subsequent
317
  //  ones in non-blocking mode, but we'll leave that for later (or never).]
318
  
319
  if (!read_buffer (buf, d_period_size, sizeof_frame))
320
    return -1;		// No fixing this problem.  Say we're done.
321

322
  // process one period of data
323
  bi = 0;
324
  for (unsigned int i = 0; i < d_period_size; i++){
325
    for (unsigned int chan = 0; chan < nchan; chan++){
326
      out[chan][i] = (float) buf[bi++] * (1.0 / (float) ((1L << (NBITS-1)) - 1));
327
    }
328
  }
329

330
  return d_period_size;
331
}
332

333
/*
334
 * Work function that deals with float to S16 conversion
335
 * and stereo to mono kludge...
336
 */
337
int
338
audio_alsa_source::work_s16_2x1 (int noutput_items,
339
				 gr_vector_const_void_star &input_items,
340
				 gr_vector_void_star &output_items)
341
{
342
  typedef gr_int16	sample_t;	// the type of samples we're creating
343
  static const int NBITS = 16;		// # of bits in a sample
344
  
345
  unsigned int nchan = output_items.size ();
346
  float **out = (float **) &output_items[0];
347
  sample_t *buf = (sample_t *) d_buffer;
348
  int bi;
349

350
  assert (nchan == 1);
351

352
  unsigned int sizeof_frame = d_hw_nchan * sizeof (sample_t);
353
  assert (d_buffer_size_bytes == d_period_size * sizeof_frame);
354

355
  // To minimize latency, return at most a single period's worth of samples.
356
  // [We could also read the first one in a blocking mode and subsequent
357
  //  ones in non-blocking mode, but we'll leave that for later (or never).]
358
  
359
  if (!read_buffer (buf, d_period_size, sizeof_frame))
360
    return -1;		// No fixing this problem.  Say we're done.
361

362
  // process one period of data
363
  bi = 0;
364
  for (unsigned int i = 0; i < d_period_size; i++){
365
    int t = (buf[bi] + buf[bi+1]) / 2;
366
    bi += 2;
367
    out[0][i] = (float) t * (1.0 / (float) ((1L << (NBITS-1)) - 1));
368
  }
369

370
  return d_period_size;
371
}
372

373
/*
374
 * Work function that deals with float to S32 conversion
375
 */
376
int
377
audio_alsa_source::work_s32 (int noutput_items,
378
			     gr_vector_const_void_star &input_items,
379
			     gr_vector_void_star &output_items)
380
{
381
  typedef gr_int32	sample_t;	// the type of samples we're creating
382
  static const int NBITS = 32;		// # of bits in a sample
383
  
384
  unsigned int nchan = output_items.size ();
385
  float **out = (float **) &output_items[0];
386
  sample_t *buf = (sample_t *) d_buffer;
387
  int bi;
388

389
  unsigned int sizeof_frame = d_hw_nchan * sizeof (sample_t);
390
  assert (d_buffer_size_bytes == d_period_size * sizeof_frame);
391

392
  // To minimize latency, return at most a single period's worth of samples.
393
  // [We could also read the first one in a blocking mode and subsequent
394
  //  ones in non-blocking mode, but we'll leave that for later (or never).]
395
  
396
  if (!read_buffer (buf, d_period_size, sizeof_frame))
397
    return -1;		// No fixing this problem.  Say we're done.
398

399
  // process one period of data
400
  bi = 0;
401
  for (unsigned int i = 0; i < d_period_size; i++){
402
    for (unsigned int chan = 0; chan < nchan; chan++){
403
      out[chan][i] = (float) buf[bi++] * (1.0 / (float) ((1L << (NBITS-1)) - 1));
404
    }
405
  }
406

407
  return d_period_size;
408
}
409

410
/*
411
 * Work function that deals with float to S32 conversion
412
 * and stereo to mono kludge...
413
 */
414
int
415
audio_alsa_source::work_s32_2x1 (int noutput_items,
416
				 gr_vector_const_void_star &input_items,
417
				 gr_vector_void_star &output_items)
418
{
419
  typedef gr_int32	sample_t;	// the type of samples we're creating
420
  static const int NBITS = 32;		// # of bits in a sample
421
  
422
  unsigned int nchan = output_items.size ();
423
  float **out = (float **) &output_items[0];
424
  sample_t *buf = (sample_t *) d_buffer;
425
  int bi;
426

427
  assert (nchan == 1);
428

429
  unsigned int sizeof_frame = d_hw_nchan * sizeof (sample_t);
430
  assert (d_buffer_size_bytes == d_period_size * sizeof_frame);
431

432
  // To minimize latency, return at most a single period's worth of samples.
433
  // [We could also read the first one in a blocking mode and subsequent
434
  //  ones in non-blocking mode, but we'll leave that for later (or never).]
435
  
436
  if (!read_buffer (buf, d_period_size, sizeof_frame))
437
    return -1;		// No fixing this problem.  Say we're done.
438

439
  // process one period of data
440
  bi = 0;
441
  for (unsigned int i = 0; i < d_period_size; i++){
442
    int t = (buf[bi] + buf[bi+1]) / 2;
443
    bi += 2;
444
    out[0][i] = (float) t * (1.0 / (float) ((1L << (NBITS-1)) - 1));
445
  }
446

447
  return d_period_size;
448
}
449

450
bool
451
audio_alsa_source::read_buffer (void *vbuffer, unsigned nframes, unsigned sizeof_frame)
452
{
453
  unsigned char *buffer = (unsigned char *) vbuffer;
454

455
  while (nframes > 0){
456
    int r = snd_pcm_readi (d_pcm_handle, buffer, nframes);
457
    if (r == -EAGAIN)
458
      continue;			// try again
459

460
    else if (r == -EPIPE){	// overrun
461
      d_noverruns++;
462
      fputs ("aO", stderr);
463
      if ((r = snd_pcm_prepare (d_pcm_handle)) < 0){
464
	output_error_msg ("snd_pcm_prepare failed. Can't recover from overrun", r);
465
	return false;
466
      }
467
      continue;			// try again
468
    }
469

470
    else if (r == -ESTRPIPE){	// h/w is suspended (whatever that means)
471
				// This is apparently related to power management
472
      d_nsuspends++;
473
      if ((r = snd_pcm_resume (d_pcm_handle)) < 0){
474
	output_error_msg ("failed to resume from suspend", r);
475
	return false;
476
      }
477
      continue;			// try again
478
    }
479

480
    else if (r < 0){
481
      output_error_msg ("snd_pcm_readi failed", r);
482
      return false;
483
    }
484

485
    nframes -= r;
486
    buffer += r * sizeof_frame;
487
  }
488

489
  return true;
490
}
491

492

493
void
494
audio_alsa_source::output_error_msg (const char *msg, int err)
495
{
496
  fprintf (stderr, "audio_alsa_source[%s]: %s: %s\n",
497
	   snd_pcm_name (d_pcm_handle), msg,  snd_strerror (err));
498
}
499

500
void
501
audio_alsa_source::bail (const char *msg, int err) throw (std::runtime_error)
502
{
503
  output_error_msg (msg, err);
504
  throw std::runtime_error ("audio_alsa_source");
505
}
b/gr-audio/lib/alsa/audio_alsa_source.h
1
/* -*- c++ -*- */
2
/*
3
 * Copyright 2004-2011 Free Software Foundation, Inc.
4
 * 
5
 * This file is part of GNU Radio
6
 * 
7
 * GNU Radio is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3, or (at your option)
10
 * any later version.
11
 * 
12
 * GNU Radio is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 * 
17
 * You should have received a copy of the GNU General Public License
18
 * along with GNU Radio; see the file COPYING.  If not, write to
19
 * the Free Software Foundation, Inc., 51 Franklin Street,
20
 * Boston, MA 02110-1301, USA.
21
 */
22

23
#ifndef INCLUDED_AUDIO_ALSA_SOURCE_H
24
#define INCLUDED_AUDIO_ALSA_SOURCE_H
25

26
// use new ALSA API
27
#define ALSA_PCM_NEW_HW_PARAMS_API
28
#define ALSA_PCM_NEW_SW_PARAMS_API
29

30
#include <gr_audio_source.h>
31
#include <string>
32
#include <alsa/asoundlib.h>
33
#include <stdexcept>
34

35
class audio_alsa_source;
36
typedef boost::shared_ptr<audio_alsa_source> audio_alsa_source_sptr;
37

38
/*!
39
 * \brief audio source using ALSA
40
 *
41
 * The source has between 1 and N input streams of floats, where N is
42
 * depends on the hardware characteristics of the selected device.
43
 *
44
 * Output samples will be in the range [-1,1].
45
 */
46
class audio_alsa_source : public audio_source {
47
  // typedef for pointer to class work method
48
  typedef int (audio_alsa_source::*work_t)(int noutput_items,
49
					   gr_vector_const_void_star &input_items,
50
					   gr_vector_void_star &output_items);
51

52
  unsigned int		d_sampling_rate;
53
  std::string		d_device_name;
54
  snd_pcm_t            *d_pcm_handle;
55
  snd_pcm_hw_params_t  *d_hw_params;
56
  snd_pcm_sw_params_t  *d_sw_params;
57
  snd_pcm_format_t	d_format;
58
  unsigned int		d_nperiods;
59
  unsigned int		d_period_time_us;	// microseconds
60
  snd_pcm_uframes_t	d_period_size;		// in frames
61
  unsigned int		d_buffer_size_bytes;	// sizeof of d_buffer
62
  char		       *d_buffer;
63
  work_t	        d_worker;		// the work method to use
64
  unsigned int		d_hw_nchan;		// # of configured h/w channels
65
  bool			d_special_case_stereo_to_mono;
66

67
  // random stats
68
  int			d_noverruns;		// count of overruns
69
  int			d_nsuspends;		// count of suspends
70

71
  void output_error_msg (const char *msg, int err);
72
  void bail (const char *msg, int err) throw (std::runtime_error);
73

74
public:
75
  audio_alsa_source (int sampling_rate, const std::string device_name,
76
		     bool ok_to_block);
77

78
  ~audio_alsa_source ();
79
  
80
  bool check_topology (int ninputs, int noutputs);
81

82
  int work (int noutput_items,
83
	    gr_vector_const_void_star &input_items,
84
	    gr_vector_void_star &output_items);
85

86
protected:
87
  bool read_buffer (void *buffer, unsigned nframes, unsigned sizeof_frame);
88

89
  int work_s16 (int noutput_items,
90
		gr_vector_const_void_star &input_items,
91
		gr_vector_void_star &output_items);
92

93
  int work_s16_2x1 (int noutput_items,
94
		    gr_vector_const_void_star &input_items,
95
		    gr_vector_void_star &output_items);
96

97
  int work_s32 (int noutput_items,
98
		gr_vector_const_void_star &input_items,
99
		gr_vector_void_star &output_items);
100

101
  int work_s32_2x1 (int noutput_items,
102
		    gr_vector_const_void_star &input_items,
103
		    gr_vector_void_star &output_items);
104
};
105

106
#endif /* INCLUDED_AUDIO_ALSA_SOURCE_H */
b/gr-audio/lib/alsa/gr-audio-alsa.conf
1
# This file contains system wide configuration data for GNU Radio.
2
# You may override any setting on a per-user basis by editing
3
# ~/.gnuradio/config.conf
4

5
[audio_alsa]
6

7
default_input_device = hw:0,0
8
default_output_device = hw:0,0
9
period_time = 0.010                      # in seconds
10
nperiods = 4				 # total buffering = period_time * nperiods
11
verbose = false
b/gr-audio/lib/alsa/gri_alsa.cc
1
/* -*- c++ -*- */
2
/*
3
 * Copyright 2004 Free Software Foundation, Inc.
4
 * 
5
 * This file is part of GNU Radio
6
 * 
7
 * GNU Radio is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 3, or (at your option)
10
 * any later version.
11
 * 
12
 * GNU Radio is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 * 
17
 * You should have received a copy of the GNU General Public License
18
 * along with GNU Radio; see the file COPYING.  If not, write to
19
 * the Free Software Foundation, Inc., 51 Franklin Street,
20
 * Boston, MA 02110-1301, USA.
21
 */
22

23
#ifdef HAVE_CONFIG_H
24
#include "config.h"
25
#endif
26

27
#include <gri_alsa.h>
28
#include <algorithm>
29

30
static snd_pcm_access_t access_types[] = {
31
  SND_PCM_ACCESS_MMAP_INTERLEAVED,
32
  SND_PCM_ACCESS_MMAP_NONINTERLEAVED,
33
  SND_PCM_ACCESS_MMAP_COMPLEX,
34
  SND_PCM_ACCESS_RW_INTERLEAVED,
35
  SND_PCM_ACCESS_RW_NONINTERLEAVED
36
};
37

38
static snd_pcm_format_t format_types[] = {
39
  // SND_PCM_FORMAT_UNKNOWN,
40
  SND_PCM_FORMAT_S8,
41
  SND_PCM_FORMAT_U8,
42
  SND_PCM_FORMAT_S16_LE,
43
  SND_PCM_FORMAT_S16_BE,
44
  SND_PCM_FORMAT_U16_LE,
45
  SND_PCM_FORMAT_U16_BE,
46
  SND_PCM_FORMAT_S24_LE,
47
  SND_PCM_FORMAT_S24_BE,
48
  SND_PCM_FORMAT_U24_LE,
49
  SND_PCM_FORMAT_U24_BE,
50
  SND_PCM_FORMAT_S32_LE,
51
  SND_PCM_FORMAT_S32_BE,
52
  SND_PCM_FORMAT_U32_LE,
53
  SND_PCM_FORMAT_U32_BE,
54
  SND_PCM_FORMAT_FLOAT_LE,
55
  SND_PCM_FORMAT_FLOAT_BE,
56
  SND_PCM_FORMAT_FLOAT64_LE,
57
  SND_PCM_FORMAT_FLOAT64_BE,
58
  SND_PCM_FORMAT_IEC958_SUBFRAME_LE,
59
  SND_PCM_FORMAT_IEC958_SUBFRAME_BE,
60
  SND_PCM_FORMAT_MU_LAW,
61
  SND_PCM_FORMAT_A_LAW,
62
  SND_PCM_FORMAT_IMA_ADPCM,
63
  SND_PCM_FORMAT_MPEG,
64
  SND_PCM_FORMAT_GSM,
65
  SND_PCM_FORMAT_SPECIAL,
66
  SND_PCM_FORMAT_S24_3LE,
67
  SND_PCM_FORMAT_S24_3BE,
68
  SND_PCM_FORMAT_U24_3LE,
69
  SND_PCM_FORMAT_U24_3BE,
70
  SND_PCM_FORMAT_S20_3LE,
71
  SND_PCM_FORMAT_S20_3BE,
72
  SND_PCM_FORMAT_U20_3LE,
73
  SND_PCM_FORMAT_U20_3BE,
74
  SND_PCM_FORMAT_S18_3LE,
75
  SND_PCM_FORMAT_S18_3BE,
76
  SND_PCM_FORMAT_U18_3LE,
77
  SND_PCM_FORMAT_U18_3BE
78
};
79

80
static unsigned int test_rates[] = {
81
  8000, 16000, 22050, 32000, 44100, 48000, 96000, 192000
82
};
83

84
#define NELEMS(x) (sizeof(x)/sizeof(x[0]))
85

86
void
87
gri_alsa_dump_hw_params (snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams, FILE *fp)
88
{
89
  fprintf (fp, "PCM name: %s\n", snd_pcm_name (pcm));
90
  
91
  fprintf (fp, "Access types:\n");
92
  for (unsigned i = 0; i < NELEMS (access_types); i++){
93
    snd_pcm_access_t	at = access_types[i];
94
    fprintf (fp, "    %-20s %s\n",
95
	     snd_pcm_access_name (at),
96
	     snd_pcm_hw_params_test_access (pcm, hwparams, at) == 0 ? "YES" : "NO");
97
  }
98

99
  fprintf (fp, "Formats:\n");
100
  for (unsigned i = 0; i < NELEMS (format_types); i++){
101
    snd_pcm_format_t	ft = format_types[i];
102
    if (0)
103
      fprintf (fp, "    %-20s %s\n",
104
	       snd_pcm_format_name (ft),
105
	       snd_pcm_hw_params_test_format (pcm, hwparams, ft) == 0 ? "YES" : "NO");
106
    else {
107
      if (snd_pcm_hw_params_test_format (pcm, hwparams, ft) == 0)
108
	fprintf (fp, "    %-20s YES\n", snd_pcm_format_name (ft));
109
    }
110
  }
111

112
  fprintf (fp, "Number of channels\n");
113
  unsigned int min_chan, max_chan;
114
  snd_pcm_hw_params_get_channels_min (hwparams, &min_chan);
115
  snd_pcm_hw_params_get_channels_max (hwparams, &max_chan);
116
  fprintf (fp, "    min channels: %d\n", min_chan);
117
  fprintf (fp, "    max channels: %d\n", max_chan);
118
  unsigned int chan;
119
  max_chan = std::min (max_chan, 16U);	// truncate display...
120
  for (chan = min_chan; chan <= max_chan; chan++){
121
    fprintf (fp, "    %d channels\t%s\n", chan,
122
	     snd_pcm_hw_params_test_channels (pcm, hwparams, chan) == 0 ? "YES" : "NO");
123
  }
124

125
  fprintf (fp, "Sample Rates:\n");
126
  unsigned int min_rate, max_rate;
127
  int	min_dir, max_dir;
128

129
  snd_pcm_hw_params_get_rate_min (hwparams, &min_rate, &min_dir);
130
  snd_pcm_hw_params_get_rate_max (hwparams, &max_rate, &max_dir);
131
  fprintf (fp, "    min rate: %7d (dir = %d)\n", min_rate, min_dir);
132
  fprintf (fp, "    max rate: %7d (dir = %d)\n", max_rate, max_dir);
133
  for (unsigned i = 0; i < NELEMS (test_rates); i++){
134
    unsigned int rate = test_rates[i];
135
    fprintf (fp, "    %6u  %s\n", rate,
136
	     snd_pcm_hw_params_test_rate (pcm, hwparams, rate, 0) == 0 ? "YES" : "NO");
137
  }
138

139
  fflush (fp);
140
}
141

142
bool
143
gri_alsa_pick_acceptable_format (snd_pcm_t *pcm,
144
				 snd_pcm_hw_params_t *hwparams,
145
				 snd_pcm_format_t acceptable_formats[],
146
				 unsigned nacceptable_formats,
147
				 snd_pcm_format_t *selected_format,
148
				 const char *error_msg_tag,
149
				 bool verbose)
150
{
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff