Statistics
| Branch: | Tag: | Revision:

root / gr-audio-alsa / src / audio_alsa_source.cc @ ad13c00a

History | View | Annotate | Download (15.1 kB)

1 5d69a524 jcorgan
/* -*- c++ -*- */
2 5d69a524 jcorgan
/*
3 5d69a524 jcorgan
 * Copyright 2004,2006 Free Software Foundation, Inc.
4 5d69a524 jcorgan
 * 
5 5d69a524 jcorgan
 * This file is part of GNU Radio
6 5d69a524 jcorgan
 * 
7 5d69a524 jcorgan
 * GNU Radio is free software; you can redistribute it and/or modify
8 5d69a524 jcorgan
 * it under the terms of the GNU General Public License as published by
9 937b719d eb
 * the Free Software Foundation; either version 3, or (at your option)
10 5d69a524 jcorgan
 * any later version.
11 5d69a524 jcorgan
 * 
12 5d69a524 jcorgan
 * GNU Radio is distributed in the hope that it will be useful,
13 5d69a524 jcorgan
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 5d69a524 jcorgan
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 5d69a524 jcorgan
 * GNU General Public License for more details.
16 5d69a524 jcorgan
 * 
17 5d69a524 jcorgan
 * You should have received a copy of the GNU General Public License
18 5d69a524 jcorgan
 * along with GNU Radio; see the file COPYING.  If not, write to
19 86f5c924 eb
 * the Free Software Foundation, Inc., 51 Franklin Street,
20 86f5c924 eb
 * Boston, MA 02110-1301, USA.
21 5d69a524 jcorgan
 */
22 5d69a524 jcorgan
23 5d69a524 jcorgan
#ifdef HAVE_CONFIG_H
24 5d69a524 jcorgan
#include "config.h"
25 5d69a524 jcorgan
#endif
26 5d69a524 jcorgan
27 5d69a524 jcorgan
#include <audio_alsa_source.h>
28 5d69a524 jcorgan
#include <gr_io_signature.h>
29 5d69a524 jcorgan
#include <gr_prefs.h>
30 5d69a524 jcorgan
#include <stdio.h>
31 5d69a524 jcorgan
#include <iostream>
32 5d69a524 jcorgan
#include <stdexcept>
33 5d69a524 jcorgan
#include <gri_alsa.h>
34 5d69a524 jcorgan
35 5d69a524 jcorgan
36 5d69a524 jcorgan
static bool CHATTY_DEBUG = false;
37 5d69a524 jcorgan
38 5d69a524 jcorgan
static snd_pcm_format_t acceptable_formats[] = {
39 5d69a524 jcorgan
  // these are in our preferred order...
40 5d69a524 jcorgan
  SND_PCM_FORMAT_S32,
41 5d69a524 jcorgan
  SND_PCM_FORMAT_S16
42 5d69a524 jcorgan
};
43 5d69a524 jcorgan
44 5d69a524 jcorgan
#define NELEMS(x) (sizeof(x)/sizeof(x[0]))
45 5d69a524 jcorgan
46 5d69a524 jcorgan
47 5d69a524 jcorgan
static std::string 
48 5d69a524 jcorgan
default_device_name ()
49 5d69a524 jcorgan
{
50 5d69a524 jcorgan
  return gr_prefs::singleton()->get_string("audio_alsa", "default_input_device", "hw:0,0");
51 5d69a524 jcorgan
}
52 5d69a524 jcorgan
53 5d69a524 jcorgan
static double
54 5d69a524 jcorgan
default_period_time ()
55 5d69a524 jcorgan
{
56 5d69a524 jcorgan
  return std::max(0.001, gr_prefs::singleton()->get_double("audio_alsa", "period_time", 0.010));
57 5d69a524 jcorgan
}
58 5d69a524 jcorgan
59 5d69a524 jcorgan
static int
60 5d69a524 jcorgan
default_nperiods ()
61 5d69a524 jcorgan
{
62 5d69a524 jcorgan
  return std::max(2L, gr_prefs::singleton()->get_long("audio_alsa", "nperiods", 4));
63 5d69a524 jcorgan
}
64 5d69a524 jcorgan
65 5d69a524 jcorgan
// ----------------------------------------------------------------
66 5d69a524 jcorgan
67 5d69a524 jcorgan
audio_alsa_source_sptr
68 5d69a524 jcorgan
audio_alsa_make_source (int sampling_rate, const std::string dev,
69 5d69a524 jcorgan
                        bool ok_to_block)
70 5d69a524 jcorgan
{
71 5d69a524 jcorgan
  return audio_alsa_source_sptr (new audio_alsa_source (sampling_rate, dev,
72 5d69a524 jcorgan
                                                        ok_to_block));
73 5d69a524 jcorgan
}
74 5d69a524 jcorgan
75 5d69a524 jcorgan
audio_alsa_source::audio_alsa_source (int sampling_rate,
76 5d69a524 jcorgan
                                      const std::string device_name,
77 5d69a524 jcorgan
                                      bool ok_to_block)
78 5d69a524 jcorgan
  : gr_sync_block ("audio_alsa_source",
79 5d69a524 jcorgan
                   gr_make_io_signature (0, 0, 0),
80 5d69a524 jcorgan
                   gr_make_io_signature (0, 0, 0)),
81 5d69a524 jcorgan
    d_sampling_rate (sampling_rate),
82 5d69a524 jcorgan
    d_device_name (device_name.empty() ? default_device_name() : device_name),
83 5d69a524 jcorgan
    d_pcm_handle (0),
84 5d69a524 jcorgan
    d_hw_params ((snd_pcm_hw_params_t *)(new char[snd_pcm_hw_params_sizeof()])),
85 5d69a524 jcorgan
    d_sw_params ((snd_pcm_sw_params_t *)(new char[snd_pcm_sw_params_sizeof()])),
86 5d69a524 jcorgan
    d_nperiods (default_nperiods()),
87 5d69a524 jcorgan
    d_period_time_us ((unsigned int) (default_period_time() * 1e6)),
88 5d69a524 jcorgan
    d_period_size (0),
89 5d69a524 jcorgan
    d_buffer_size_bytes (0), d_buffer (0),
90 5d69a524 jcorgan
    d_worker (0), d_hw_nchan (0),
91 5d69a524 jcorgan
    d_special_case_stereo_to_mono (false),
92 5d69a524 jcorgan
    d_noverruns (0), d_nsuspends (0)
93 5d69a524 jcorgan
{
94 5d69a524 jcorgan
95 5d69a524 jcorgan
  CHATTY_DEBUG = gr_prefs::singleton()->get_bool("audio_alsa", "verbose", false);
96 5d69a524 jcorgan
97 5d69a524 jcorgan
  int          error;
98 5d69a524 jcorgan
  int        dir;
99 5d69a524 jcorgan
100 5d69a524 jcorgan
  // open the device for capture
101 5d69a524 jcorgan
  error = snd_pcm_open(&d_pcm_handle, d_device_name.c_str (),
102 5d69a524 jcorgan
                       SND_PCM_STREAM_CAPTURE, 0);
103 5d69a524 jcorgan
  if (error < 0){
104 5d69a524 jcorgan
    fprintf (stderr, "audio_alsa_source[%s]: %s\n",
105 5d69a524 jcorgan
             d_device_name.c_str(), snd_strerror(error));
106 5d69a524 jcorgan
    throw std::runtime_error ("audio_alsa_source");
107 5d69a524 jcorgan
  }
108 5d69a524 jcorgan
109 5d69a524 jcorgan
  // Fill params with a full configuration space for a PCM.
110 5d69a524 jcorgan
  error = snd_pcm_hw_params_any(d_pcm_handle, d_hw_params);
111 5d69a524 jcorgan
  if (error < 0)
112 5d69a524 jcorgan
    bail ("broken configuration for playback", error);
113 5d69a524 jcorgan
114 5d69a524 jcorgan
  if (CHATTY_DEBUG)
115 5d69a524 jcorgan
    gri_alsa_dump_hw_params (d_pcm_handle, d_hw_params, stdout);
116 5d69a524 jcorgan
117 5d69a524 jcorgan
  // now that we know how many channels the h/w can handle, set output signature
118 5d69a524 jcorgan
  unsigned int umax_chan;
119 5d69a524 jcorgan
  unsigned int umin_chan;
120 5d69a524 jcorgan
  snd_pcm_hw_params_get_channels_min (d_hw_params, &umin_chan);
121 5d69a524 jcorgan
  snd_pcm_hw_params_get_channels_max (d_hw_params, &umax_chan);
122 5d69a524 jcorgan
  int min_chan = std::min (umin_chan, 1000U);
123 5d69a524 jcorgan
  int max_chan = std::min (umax_chan, 1000U);
124 5d69a524 jcorgan
125 5d69a524 jcorgan
  // As a special case, if the hw's min_chan is two, we'll accept
126 5d69a524 jcorgan
  // a single output and handle the demux ourselves.
127 5d69a524 jcorgan
128 5d69a524 jcorgan
  if (min_chan == 2){
129 5d69a524 jcorgan
    min_chan = 1;
130 5d69a524 jcorgan
    d_special_case_stereo_to_mono = true;
131 5d69a524 jcorgan
  }
132 5d69a524 jcorgan
  
133 5d69a524 jcorgan
  set_output_signature (gr_make_io_signature (min_chan, max_chan,
134 5d69a524 jcorgan
                                              sizeof (float)));
135 5d69a524 jcorgan
  
136 5d69a524 jcorgan
  // fill in portions of the d_hw_params that we know now...
137 5d69a524 jcorgan
138 5d69a524 jcorgan
  // Specify the access methods we implement
139 5d69a524 jcorgan
  // For now, we only handle RW_INTERLEAVED...
140 5d69a524 jcorgan
  snd_pcm_access_mask_t *access_mask;
141 34af4364 jcorgan
  snd_pcm_access_mask_t **access_mask_ptr = &access_mask; // FIXME: workaround for compiler warning
142 34af4364 jcorgan
  snd_pcm_access_mask_alloca (access_mask_ptr);
143 5d69a524 jcorgan
  snd_pcm_access_mask_none (access_mask);
144 5d69a524 jcorgan
  snd_pcm_access_mask_set (access_mask, SND_PCM_ACCESS_RW_INTERLEAVED);
145 5d69a524 jcorgan
  // snd_pcm_access_mask_set (access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED);
146 5d69a524 jcorgan
147 5d69a524 jcorgan
  if ((error = snd_pcm_hw_params_set_access_mask (d_pcm_handle,
148 5d69a524 jcorgan
                                                  d_hw_params, access_mask)) < 0)
149 5d69a524 jcorgan
    bail ("failed to set access mask", error);
150 5d69a524 jcorgan
151 5d69a524 jcorgan
152 5d69a524 jcorgan
  // set sample format
153 5d69a524 jcorgan
  if (!gri_alsa_pick_acceptable_format (d_pcm_handle, d_hw_params,
154 5d69a524 jcorgan
                                        acceptable_formats,
155 5d69a524 jcorgan
                                        NELEMS (acceptable_formats),
156 5d69a524 jcorgan
                                        &d_format,
157 5d69a524 jcorgan
                                        "audio_alsa_source",
158 5d69a524 jcorgan
                                        CHATTY_DEBUG))
159 5d69a524 jcorgan
    throw std::runtime_error ("audio_alsa_source");
160 5d69a524 jcorgan
  
161 5d69a524 jcorgan
162 5d69a524 jcorgan
  // sampling rate
163 5d69a524 jcorgan
  unsigned int orig_sampling_rate = d_sampling_rate;
164 5d69a524 jcorgan
  if ((error = snd_pcm_hw_params_set_rate_near (d_pcm_handle, d_hw_params,
165 5d69a524 jcorgan
                                                &d_sampling_rate, 0)) < 0)
166 5d69a524 jcorgan
    bail ("failed to set rate near", error);
167 5d69a524 jcorgan
  
168 5d69a524 jcorgan
  if (orig_sampling_rate != d_sampling_rate){
169 5d69a524 jcorgan
    fprintf (stderr, "audio_alsa_source[%s]: unable to support sampling rate %d\n",
170 5d69a524 jcorgan
             snd_pcm_name (d_pcm_handle), orig_sampling_rate);
171 5d69a524 jcorgan
    fprintf (stderr, "  card requested %d instead.\n", d_sampling_rate);
172 5d69a524 jcorgan
  }
173 5d69a524 jcorgan
174 5d69a524 jcorgan
  /*
175 5d69a524 jcorgan
   * ALSA transfers data in units of "periods".
176 5d69a524 jcorgan
   * We indirectly determine the underlying buffersize by specifying
177 5d69a524 jcorgan
   * the number of periods we want (typically 4) and the length of each
178 5d69a524 jcorgan
   * period in units of time (typically 1ms).
179 5d69a524 jcorgan
   */
180 5d69a524 jcorgan
  unsigned int min_nperiods, max_nperiods;
181 5d69a524 jcorgan
  snd_pcm_hw_params_get_periods_min (d_hw_params, &min_nperiods, &dir);
182 5d69a524 jcorgan
  snd_pcm_hw_params_get_periods_max (d_hw_params, &max_nperiods, &dir);
183 5d69a524 jcorgan
  //fprintf (stderr, "alsa_source: min_nperiods = %d, max_nperiods = %d\n",
184 5d69a524 jcorgan
  // min_nperiods, max_nperiods);
185 5d69a524 jcorgan
186 5d69a524 jcorgan
187 5d69a524 jcorgan
  unsigned int orig_nperiods = d_nperiods;
188 5d69a524 jcorgan
  d_nperiods = std::min (std::max (min_nperiods, d_nperiods), max_nperiods);
189 5d69a524 jcorgan
190 5d69a524 jcorgan
  // adjust period time so that total buffering remains more-or-less constant
191 5d69a524 jcorgan
  d_period_time_us = (d_period_time_us * orig_nperiods) / d_nperiods;
192 5d69a524 jcorgan
193 5d69a524 jcorgan
  error = snd_pcm_hw_params_set_periods (d_pcm_handle, d_hw_params,
194 5d69a524 jcorgan
                                         d_nperiods, 0);
195 5d69a524 jcorgan
  if (error < 0)
196 5d69a524 jcorgan
    bail ("set_periods failed", error);
197 5d69a524 jcorgan
198 5d69a524 jcorgan
  dir = 0;
199 5d69a524 jcorgan
  error = snd_pcm_hw_params_set_period_time_near (d_pcm_handle, d_hw_params,
200 5d69a524 jcorgan
                                                  &d_period_time_us, &dir);
201 5d69a524 jcorgan
  if (error < 0)
202 5d69a524 jcorgan
    bail ("set_period_time_near failed", error);
203 5d69a524 jcorgan
204 5d69a524 jcorgan
  dir = 0;
205 5d69a524 jcorgan
  error = snd_pcm_hw_params_get_period_size (d_hw_params,
206 5d69a524 jcorgan
                                             &d_period_size, &dir);
207 5d69a524 jcorgan
  if (error < 0)
208 5d69a524 jcorgan
    bail ("get_period_size failed", error);
209 5d69a524 jcorgan
  
210 5d69a524 jcorgan
  set_output_multiple (d_period_size);
211 5d69a524 jcorgan
}
212 5d69a524 jcorgan
213 5d69a524 jcorgan
bool
214 5d69a524 jcorgan
audio_alsa_source::check_topology (int ninputs, int noutputs)
215 5d69a524 jcorgan
{
216 5d69a524 jcorgan
  // noutputs is how many channels the user has connected.
217 5d69a524 jcorgan
  // Now we can finish up setting up the hw params...
218 5d69a524 jcorgan
219 5d69a524 jcorgan
  unsigned int nchan = noutputs;
220 5d69a524 jcorgan
  int err;
221 5d69a524 jcorgan
222 5d69a524 jcorgan
  // FIXME check_topology may be called more than once.
223 5d69a524 jcorgan
  // Ensure that the pcm is in a state where we can still mess with the hw_params
224 5d69a524 jcorgan
225 5d69a524 jcorgan
  bool special_case = nchan == 1 && d_special_case_stereo_to_mono;
226 5d69a524 jcorgan
  if (special_case)
227 5d69a524 jcorgan
    nchan = 2;
228 5d69a524 jcorgan
229 5d69a524 jcorgan
  d_hw_nchan = nchan;
230 5d69a524 jcorgan
  err = snd_pcm_hw_params_set_channels (d_pcm_handle, d_hw_params, d_hw_nchan);
231 5d69a524 jcorgan
  if (err < 0){
232 5d69a524 jcorgan
    output_error_msg ("set_channels failed", err);
233 5d69a524 jcorgan
    return false;
234 5d69a524 jcorgan
  }
235 5d69a524 jcorgan
236 5d69a524 jcorgan
  // set the parameters into the driver...
237 5d69a524 jcorgan
  err = snd_pcm_hw_params(d_pcm_handle, d_hw_params);
238 5d69a524 jcorgan
  if (err < 0){
239 5d69a524 jcorgan
    output_error_msg ("snd_pcm_hw_params failed", err);
240 5d69a524 jcorgan
    return false;
241 5d69a524 jcorgan
  }
242 5d69a524 jcorgan
243 5d69a524 jcorgan
  d_buffer_size_bytes =
244 5d69a524 jcorgan
    d_period_size * d_hw_nchan * snd_pcm_format_size (d_format, 1);
245 5d69a524 jcorgan
246 5d69a524 jcorgan
  d_buffer = new char [d_buffer_size_bytes];
247 5d69a524 jcorgan
248 5d69a524 jcorgan
  if (CHATTY_DEBUG)
249 5d69a524 jcorgan
    fprintf (stdout, "audio_alsa_source[%s]: sample resolution = %d bits\n",
250 5d69a524 jcorgan
             snd_pcm_name (d_pcm_handle),
251 5d69a524 jcorgan
             snd_pcm_hw_params_get_sbits (d_hw_params));
252 5d69a524 jcorgan
253 5d69a524 jcorgan
  switch (d_format){
254 5d69a524 jcorgan
  case SND_PCM_FORMAT_S16:
255 5d69a524 jcorgan
    if (special_case)
256 5d69a524 jcorgan
      d_worker = &audio_alsa_source::work_s16_2x1;
257 5d69a524 jcorgan
    else
258 5d69a524 jcorgan
      d_worker = &audio_alsa_source::work_s16;
259 5d69a524 jcorgan
    break;
260 5d69a524 jcorgan
261 5d69a524 jcorgan
  case SND_PCM_FORMAT_S32:
262 5d69a524 jcorgan
    if (special_case)
263 5d69a524 jcorgan
      d_worker = &audio_alsa_source::work_s32_2x1;
264 5d69a524 jcorgan
    else
265 5d69a524 jcorgan
      d_worker = &audio_alsa_source::work_s32;
266 5d69a524 jcorgan
    break;
267 5d69a524 jcorgan
268 5d69a524 jcorgan
  default:
269 5d69a524 jcorgan
    assert (0);
270 5d69a524 jcorgan
  }
271 5d69a524 jcorgan
272 5d69a524 jcorgan
  return true;
273 5d69a524 jcorgan
}
274 5d69a524 jcorgan
275 5d69a524 jcorgan
audio_alsa_source::~audio_alsa_source ()
276 5d69a524 jcorgan
{
277 5d69a524 jcorgan
  if (snd_pcm_state (d_pcm_handle) == SND_PCM_STATE_RUNNING)
278 5d69a524 jcorgan
    snd_pcm_drop (d_pcm_handle);
279 5d69a524 jcorgan
280 5d69a524 jcorgan
  snd_pcm_close(d_pcm_handle);
281 5d69a524 jcorgan
  delete [] ((char *) d_hw_params);
282 5d69a524 jcorgan
  delete [] ((char *) d_sw_params);
283 5d69a524 jcorgan
  delete [] d_buffer;
284 5d69a524 jcorgan
}
285 5d69a524 jcorgan
286 5d69a524 jcorgan
int
287 5d69a524 jcorgan
audio_alsa_source::work (int noutput_items,
288 5d69a524 jcorgan
                         gr_vector_const_void_star &input_items,
289 5d69a524 jcorgan
                         gr_vector_void_star &output_items)
290 5d69a524 jcorgan
{
291 5d69a524 jcorgan
  assert ((noutput_items % d_period_size) == 0);
292 5d69a524 jcorgan
  assert (noutput_items != 0);
293 5d69a524 jcorgan
294 5d69a524 jcorgan
  // this is a call through a pointer to a method...
295 5d69a524 jcorgan
  return (this->*d_worker)(noutput_items, input_items, output_items);
296 5d69a524 jcorgan
}
297 5d69a524 jcorgan
298 5d69a524 jcorgan
/*
299 5d69a524 jcorgan
 * Work function that deals with float to S16 conversion
300 5d69a524 jcorgan
 */
301 5d69a524 jcorgan
int
302 5d69a524 jcorgan
audio_alsa_source::work_s16 (int noutput_items,
303 5d69a524 jcorgan
                             gr_vector_const_void_star &input_items,
304 5d69a524 jcorgan
                             gr_vector_void_star &output_items)
305 5d69a524 jcorgan
{
306 5d69a524 jcorgan
  typedef gr_int16        sample_t;        // the type of samples we're creating
307 5d69a524 jcorgan
  static const int NBITS = 16;                // # of bits in a sample
308 5d69a524 jcorgan
  
309 5d69a524 jcorgan
  unsigned int nchan = output_items.size ();
310 5d69a524 jcorgan
  float **out = (float **) &output_items[0];
311 5d69a524 jcorgan
  sample_t *buf = (sample_t *) d_buffer;
312 5d69a524 jcorgan
  int bi;
313 5d69a524 jcorgan
314 5d69a524 jcorgan
  unsigned int sizeof_frame = d_hw_nchan * sizeof (sample_t);
315 5d69a524 jcorgan
  assert (d_buffer_size_bytes == d_period_size * sizeof_frame);
316 5d69a524 jcorgan
317 5d69a524 jcorgan
  // To minimize latency, return at most a single period's worth of samples.
318 5d69a524 jcorgan
  // [We could also read the first one in a blocking mode and subsequent
319 5d69a524 jcorgan
  //  ones in non-blocking mode, but we'll leave that for later (or never).]
320 5d69a524 jcorgan
  
321 5d69a524 jcorgan
  if (!read_buffer (buf, d_period_size, sizeof_frame))
322 5d69a524 jcorgan
    return -1;                // No fixing this problem.  Say we're done.
323 5d69a524 jcorgan
324 5d69a524 jcorgan
  // process one period of data
325 5d69a524 jcorgan
  bi = 0;
326 5d69a524 jcorgan
  for (unsigned int i = 0; i < d_period_size; i++){
327 5d69a524 jcorgan
    for (unsigned int chan = 0; chan < nchan; chan++){
328 5d69a524 jcorgan
      out[chan][i] = (float) buf[bi++] * (1.0 / (float) ((1L << (NBITS-1)) - 1));
329 5d69a524 jcorgan
    }
330 5d69a524 jcorgan
  }
331 5d69a524 jcorgan
332 5d69a524 jcorgan
  return d_period_size;
333 5d69a524 jcorgan
}
334 5d69a524 jcorgan
335 5d69a524 jcorgan
/*
336 5d69a524 jcorgan
 * Work function that deals with float to S16 conversion
337 5d69a524 jcorgan
 * and stereo to mono kludge...
338 5d69a524 jcorgan
 */
339 5d69a524 jcorgan
int
340 5d69a524 jcorgan
audio_alsa_source::work_s16_2x1 (int noutput_items,
341 5d69a524 jcorgan
                                 gr_vector_const_void_star &input_items,
342 5d69a524 jcorgan
                                 gr_vector_void_star &output_items)
343 5d69a524 jcorgan
{
344 5d69a524 jcorgan
  typedef gr_int16        sample_t;        // the type of samples we're creating
345 5d69a524 jcorgan
  static const int NBITS = 16;                // # of bits in a sample
346 5d69a524 jcorgan
  
347 5d69a524 jcorgan
  unsigned int nchan = output_items.size ();
348 5d69a524 jcorgan
  float **out = (float **) &output_items[0];
349 5d69a524 jcorgan
  sample_t *buf = (sample_t *) d_buffer;
350 5d69a524 jcorgan
  int bi;
351 5d69a524 jcorgan
352 5d69a524 jcorgan
  assert (nchan == 1);
353 5d69a524 jcorgan
354 5d69a524 jcorgan
  unsigned int sizeof_frame = d_hw_nchan * sizeof (sample_t);
355 5d69a524 jcorgan
  assert (d_buffer_size_bytes == d_period_size * sizeof_frame);
356 5d69a524 jcorgan
357 5d69a524 jcorgan
  // To minimize latency, return at most a single period's worth of samples.
358 5d69a524 jcorgan
  // [We could also read the first one in a blocking mode and subsequent
359 5d69a524 jcorgan
  //  ones in non-blocking mode, but we'll leave that for later (or never).]
360 5d69a524 jcorgan
  
361 5d69a524 jcorgan
  if (!read_buffer (buf, d_period_size, sizeof_frame))
362 5d69a524 jcorgan
    return -1;                // No fixing this problem.  Say we're done.
363 5d69a524 jcorgan
364 5d69a524 jcorgan
  // process one period of data
365 5d69a524 jcorgan
  bi = 0;
366 5d69a524 jcorgan
  for (unsigned int i = 0; i < d_period_size; i++){
367 5d69a524 jcorgan
    int t = (buf[bi] + buf[bi+1]) / 2;
368 5d69a524 jcorgan
    bi += 2;
369 5d69a524 jcorgan
    out[0][i] = (float) t * (1.0 / (float) ((1L << (NBITS-1)) - 1));
370 5d69a524 jcorgan
  }
371 5d69a524 jcorgan
372 5d69a524 jcorgan
  return d_period_size;
373 5d69a524 jcorgan
}
374 5d69a524 jcorgan
375 5d69a524 jcorgan
/*
376 5d69a524 jcorgan
 * Work function that deals with float to S32 conversion
377 5d69a524 jcorgan
 */
378 5d69a524 jcorgan
int
379 5d69a524 jcorgan
audio_alsa_source::work_s32 (int noutput_items,
380 5d69a524 jcorgan
                             gr_vector_const_void_star &input_items,
381 5d69a524 jcorgan
                             gr_vector_void_star &output_items)
382 5d69a524 jcorgan
{
383 5d69a524 jcorgan
  typedef gr_int32        sample_t;        // the type of samples we're creating
384 5d69a524 jcorgan
  static const int NBITS = 32;                // # of bits in a sample
385 5d69a524 jcorgan
  
386 5d69a524 jcorgan
  unsigned int nchan = output_items.size ();
387 5d69a524 jcorgan
  float **out = (float **) &output_items[0];
388 5d69a524 jcorgan
  sample_t *buf = (sample_t *) d_buffer;
389 5d69a524 jcorgan
  int bi;
390 5d69a524 jcorgan
391 5d69a524 jcorgan
  unsigned int sizeof_frame = d_hw_nchan * sizeof (sample_t);
392 5d69a524 jcorgan
  assert (d_buffer_size_bytes == d_period_size * sizeof_frame);
393 5d69a524 jcorgan
394 5d69a524 jcorgan
  // To minimize latency, return at most a single period's worth of samples.
395 5d69a524 jcorgan
  // [We could also read the first one in a blocking mode and subsequent
396 5d69a524 jcorgan
  //  ones in non-blocking mode, but we'll leave that for later (or never).]
397 5d69a524 jcorgan
  
398 5d69a524 jcorgan
  if (!read_buffer (buf, d_period_size, sizeof_frame))
399 5d69a524 jcorgan
    return -1;                // No fixing this problem.  Say we're done.
400 5d69a524 jcorgan
401 5d69a524 jcorgan
  // process one period of data
402 5d69a524 jcorgan
  bi = 0;
403 5d69a524 jcorgan
  for (unsigned int i = 0; i < d_period_size; i++){
404 5d69a524 jcorgan
    for (unsigned int chan = 0; chan < nchan; chan++){
405 5d69a524 jcorgan
      out[chan][i] = (float) buf[bi++] * (1.0 / (float) ((1L << (NBITS-1)) - 1));
406 5d69a524 jcorgan
    }
407 5d69a524 jcorgan
  }
408 5d69a524 jcorgan
409 5d69a524 jcorgan
  return d_period_size;
410 5d69a524 jcorgan
}
411 5d69a524 jcorgan
412 5d69a524 jcorgan
/*
413 5d69a524 jcorgan
 * Work function that deals with float to S32 conversion
414 5d69a524 jcorgan
 * and stereo to mono kludge...
415 5d69a524 jcorgan
 */
416 5d69a524 jcorgan
int
417 5d69a524 jcorgan
audio_alsa_source::work_s32_2x1 (int noutput_items,
418 5d69a524 jcorgan
                                 gr_vector_const_void_star &input_items,
419 5d69a524 jcorgan
                                 gr_vector_void_star &output_items)
420 5d69a524 jcorgan
{
421 5d69a524 jcorgan
  typedef gr_int32        sample_t;        // the type of samples we're creating
422 5d69a524 jcorgan
  static const int NBITS = 32;                // # of bits in a sample
423 5d69a524 jcorgan
  
424 5d69a524 jcorgan
  unsigned int nchan = output_items.size ();
425 5d69a524 jcorgan
  float **out = (float **) &output_items[0];
426 5d69a524 jcorgan
  sample_t *buf = (sample_t *) d_buffer;
427 5d69a524 jcorgan
  int bi;
428 5d69a524 jcorgan
429 5d69a524 jcorgan
  assert (nchan == 1);
430 5d69a524 jcorgan
431 5d69a524 jcorgan
  unsigned int sizeof_frame = d_hw_nchan * sizeof (sample_t);
432 5d69a524 jcorgan
  assert (d_buffer_size_bytes == d_period_size * sizeof_frame);
433 5d69a524 jcorgan
434 5d69a524 jcorgan
  // To minimize latency, return at most a single period's worth of samples.
435 5d69a524 jcorgan
  // [We could also read the first one in a blocking mode and subsequent
436 5d69a524 jcorgan
  //  ones in non-blocking mode, but we'll leave that for later (or never).]
437 5d69a524 jcorgan
  
438 5d69a524 jcorgan
  if (!read_buffer (buf, d_period_size, sizeof_frame))
439 5d69a524 jcorgan
    return -1;                // No fixing this problem.  Say we're done.
440 5d69a524 jcorgan
441 5d69a524 jcorgan
  // process one period of data
442 5d69a524 jcorgan
  bi = 0;
443 5d69a524 jcorgan
  for (unsigned int i = 0; i < d_period_size; i++){
444 5d69a524 jcorgan
    int t = (buf[bi] + buf[bi+1]) / 2;
445 5d69a524 jcorgan
    bi += 2;
446 5d69a524 jcorgan
    out[0][i] = (float) t * (1.0 / (float) ((1L << (NBITS-1)) - 1));
447 5d69a524 jcorgan
  }
448 5d69a524 jcorgan
449 5d69a524 jcorgan
  return d_period_size;
450 5d69a524 jcorgan
}
451 5d69a524 jcorgan
452 5d69a524 jcorgan
bool
453 5d69a524 jcorgan
audio_alsa_source::read_buffer (void *vbuffer, unsigned nframes, unsigned sizeof_frame)
454 5d69a524 jcorgan
{
455 5d69a524 jcorgan
  unsigned char *buffer = (unsigned char *) vbuffer;
456 5d69a524 jcorgan
457 5d69a524 jcorgan
  while (nframes > 0){
458 5d69a524 jcorgan
    int r = snd_pcm_readi (d_pcm_handle, buffer, nframes);
459 5d69a524 jcorgan
    if (r == -EAGAIN)
460 5d69a524 jcorgan
      continue;                        // try again
461 5d69a524 jcorgan
462 5d69a524 jcorgan
    else if (r == -EPIPE){        // overrun
463 5d69a524 jcorgan
      d_noverruns++;
464 5d69a524 jcorgan
      fputs ("aO", stderr);
465 5d69a524 jcorgan
      if ((r = snd_pcm_prepare (d_pcm_handle)) < 0){
466 5d69a524 jcorgan
        output_error_msg ("snd_pcm_prepare failed. Can't recover from overrun", r);
467 5d69a524 jcorgan
        return false;
468 5d69a524 jcorgan
      }
469 5d69a524 jcorgan
      continue;                        // try again
470 5d69a524 jcorgan
    }
471 5d69a524 jcorgan
472 5d69a524 jcorgan
    else if (r == -ESTRPIPE){        // h/w is suspended (whatever that means)
473 5d69a524 jcorgan
                                // This is apparently related to power management
474 5d69a524 jcorgan
      d_nsuspends++;
475 5d69a524 jcorgan
      if ((r = snd_pcm_resume (d_pcm_handle)) < 0){
476 5d69a524 jcorgan
        output_error_msg ("failed to resume from suspend", r);
477 5d69a524 jcorgan
        return false;
478 5d69a524 jcorgan
      }
479 5d69a524 jcorgan
      continue;                        // try again
480 5d69a524 jcorgan
    }
481 5d69a524 jcorgan
482 5d69a524 jcorgan
    else if (r < 0){
483 5d69a524 jcorgan
      output_error_msg ("snd_pcm_readi failed", r);
484 5d69a524 jcorgan
      return false;
485 5d69a524 jcorgan
    }
486 5d69a524 jcorgan
487 5d69a524 jcorgan
    nframes -= r;
488 5d69a524 jcorgan
    buffer += r * sizeof_frame;
489 5d69a524 jcorgan
  }
490 5d69a524 jcorgan
491 5d69a524 jcorgan
  return true;
492 5d69a524 jcorgan
}
493 5d69a524 jcorgan
494 5d69a524 jcorgan
495 5d69a524 jcorgan
void
496 5d69a524 jcorgan
audio_alsa_source::output_error_msg (const char *msg, int err)
497 5d69a524 jcorgan
{
498 5d69a524 jcorgan
  fprintf (stderr, "audio_alsa_source[%s]: %s: %s\n",
499 5d69a524 jcorgan
           snd_pcm_name (d_pcm_handle), msg,  snd_strerror (err));
500 5d69a524 jcorgan
}
501 5d69a524 jcorgan
502 5d69a524 jcorgan
void
503 5d69a524 jcorgan
audio_alsa_source::bail (const char *msg, int err) throw (std::runtime_error)
504 5d69a524 jcorgan
{
505 5d69a524 jcorgan
  output_error_msg (msg, err);
506 5d69a524 jcorgan
  throw std::runtime_error ("audio_alsa_source");
507 5d69a524 jcorgan
}