diff options
Diffstat (limited to 'gr-audio/lib/alsa/alsa_source.cc')
-rw-r--r-- | gr-audio/lib/alsa/alsa_source.cc | 792 |
1 files changed, 390 insertions, 402 deletions
diff --git a/gr-audio/lib/alsa/alsa_source.cc b/gr-audio/lib/alsa/alsa_source.cc index 6655849362..82443268c4 100644 --- a/gr-audio/lib/alsa/alsa_source.cc +++ b/gr-audio/lib/alsa/alsa_source.cc @@ -34,480 +34,468 @@ #include <stdexcept> namespace gr { - namespace audio { - - source::sptr - alsa_source_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block) - { - return source::sptr - (new alsa_source(sampling_rate, device_name, ok_to_block)); - } - - static bool CHATTY_DEBUG = false; - - static snd_pcm_format_t acceptable_formats[] = { - // these are in our preferred order... - SND_PCM_FORMAT_S32, - SND_PCM_FORMAT_S16 - }; - -#define NELEMS(x) (sizeof(x)/sizeof(x[0])) - - static std::string - default_device_name() - { - return prefs::singleton()->get_string("audio_alsa", - "default_input_device", - "default"); - } - - static double - default_period_time() - { - return std::max(0.001, - prefs::singleton()->get_double("audio_alsa", "period_time", 0.010)); - } - - static int - default_nperiods() - { - return std::max(2L, - prefs::singleton()->get_long("audio_alsa", "nperiods", 4)); - } - - // ---------------------------------------------------------------- - - alsa_source::alsa_source(int sampling_rate, - const std::string device_name, - bool ok_to_block) - : sync_block("audio_alsa_source", - io_signature::make(0, 0, 0), - io_signature::make(0, 0, 0)), - d_sampling_rate(sampling_rate), - d_device_name(device_name.empty() ? default_device_name() : device_name), - d_pcm_handle(0), - d_hw_params((snd_pcm_hw_params_t*)(new char[snd_pcm_hw_params_sizeof()])), - d_sw_params((snd_pcm_sw_params_t*)(new char[snd_pcm_sw_params_sizeof()])), - d_nperiods(default_nperiods()), - d_period_time_us((unsigned int)(default_period_time() * 1e6)), - d_period_size(0), - d_buffer_size_bytes(0), d_buffer(0), - d_worker(0), d_hw_nchan(0), - d_special_case_stereo_to_mono(false), - d_noverruns(0), d_nsuspends(0) - { - CHATTY_DEBUG = prefs::singleton()->get_bool("audio_alsa", "verbose", false); - - int error; - int dir; - - // open the device for capture - error = snd_pcm_open(&d_pcm_handle, d_device_name.c_str(), - SND_PCM_STREAM_CAPTURE, 0); - if(error < 0){ - GR_LOG_ERROR(d_logger, boost::format("[%1%]: %2%") \ - % (d_device_name) % (snd_strerror(error))); +namespace audio { + +source::sptr +alsa_source_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block) +{ + return source::sptr(new alsa_source(sampling_rate, device_name, ok_to_block)); +} + +static bool CHATTY_DEBUG = false; + +static snd_pcm_format_t acceptable_formats[] = { + // these are in our preferred order... + SND_PCM_FORMAT_S32, + SND_PCM_FORMAT_S16 +}; + +#define NELEMS(x) (sizeof(x) / sizeof(x[0])) + +static std::string default_device_name() +{ + return prefs::singleton()->get_string( + "audio_alsa", "default_input_device", "default"); +} + +static double default_period_time() +{ + return std::max(0.001, + prefs::singleton()->get_double("audio_alsa", "period_time", 0.010)); +} + +static int default_nperiods() +{ + return std::max(2L, prefs::singleton()->get_long("audio_alsa", "nperiods", 4)); +} + +// ---------------------------------------------------------------- + +alsa_source::alsa_source(int sampling_rate, + const std::string device_name, + bool ok_to_block) + : sync_block( + "audio_alsa_source", io_signature::make(0, 0, 0), io_signature::make(0, 0, 0)), + d_sampling_rate(sampling_rate), + d_device_name(device_name.empty() ? default_device_name() : device_name), + d_pcm_handle(0), + d_hw_params((snd_pcm_hw_params_t*)(new char[snd_pcm_hw_params_sizeof()])), + d_sw_params((snd_pcm_sw_params_t*)(new char[snd_pcm_sw_params_sizeof()])), + d_nperiods(default_nperiods()), + d_period_time_us((unsigned int)(default_period_time() * 1e6)), + d_period_size(0), + d_buffer_size_bytes(0), + d_buffer(0), + d_worker(0), + d_hw_nchan(0), + d_special_case_stereo_to_mono(false), + d_noverruns(0), + d_nsuspends(0) +{ + CHATTY_DEBUG = prefs::singleton()->get_bool("audio_alsa", "verbose", false); + + int error; + int dir; + + // open the device for capture + error = snd_pcm_open(&d_pcm_handle, d_device_name.c_str(), SND_PCM_STREAM_CAPTURE, 0); + if (error < 0) { + GR_LOG_ERROR(d_logger, + boost::format("[%1%]: %2%") % (d_device_name) % + (snd_strerror(error))); throw std::runtime_error("audio_alsa_source"); - } + } - // Fill params with a full configuration space for a PCM. - error = snd_pcm_hw_params_any(d_pcm_handle, d_hw_params); - if(error < 0) + // Fill params with a full configuration space for a PCM. + error = snd_pcm_hw_params_any(d_pcm_handle, d_hw_params); + if (error < 0) bail("broken configuration for playback", error); - if(CHATTY_DEBUG) + if (CHATTY_DEBUG) gri_alsa_dump_hw_params(d_pcm_handle, d_hw_params, stdout); - // now that we know how many channels the h/w can handle, set output signature - unsigned int umax_chan; - unsigned int umin_chan; - snd_pcm_hw_params_get_channels_min(d_hw_params, &umin_chan); - snd_pcm_hw_params_get_channels_max(d_hw_params, &umax_chan); - int min_chan = std::min(umin_chan, 1000U); - int max_chan = std::min(umax_chan, 1000U); - - // As a special case, if the hw's min_chan is two, we'll accept - // a single output and handle the demux ourselves. - if(min_chan == 2) { + // now that we know how many channels the h/w can handle, set output signature + unsigned int umax_chan; + unsigned int umin_chan; + snd_pcm_hw_params_get_channels_min(d_hw_params, &umin_chan); + snd_pcm_hw_params_get_channels_max(d_hw_params, &umax_chan); + int min_chan = std::min(umin_chan, 1000U); + int max_chan = std::min(umax_chan, 1000U); + + // As a special case, if the hw's min_chan is two, we'll accept + // a single output and handle the demux ourselves. + if (min_chan == 2) { min_chan = 1; d_special_case_stereo_to_mono = true; - } + } - set_output_signature(io_signature::make(min_chan, max_chan, - sizeof(float))); + set_output_signature(io_signature::make(min_chan, max_chan, sizeof(float))); - // fill in portions of the d_hw_params that we know now... + // fill in portions of the d_hw_params that we know now... - // Specify the access methods we implement - // For now, we only handle RW_INTERLEAVED... - snd_pcm_access_mask_t *access_mask; - snd_pcm_access_mask_t **access_mask_ptr = &access_mask; // FIXME: workaround for compiler warning - snd_pcm_access_mask_alloca(access_mask_ptr); - snd_pcm_access_mask_none(access_mask); - snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED); - // snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED); + // Specify the access methods we implement + // For now, we only handle RW_INTERLEAVED... + snd_pcm_access_mask_t* access_mask; + snd_pcm_access_mask_t** access_mask_ptr = + &access_mask; // FIXME: workaround for compiler warning + snd_pcm_access_mask_alloca(access_mask_ptr); + snd_pcm_access_mask_none(access_mask); + snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED); + // snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED); - if((error = snd_pcm_hw_params_set_access_mask(d_pcm_handle, - d_hw_params, access_mask)) < 0) + if ((error = snd_pcm_hw_params_set_access_mask( + d_pcm_handle, d_hw_params, access_mask)) < 0) bail("failed to set access mask", error); - // set sample format - if(!gri_alsa_pick_acceptable_format(d_pcm_handle, d_hw_params, - acceptable_formats, - NELEMS(acceptable_formats), - &d_format, - "audio_alsa_source", - CHATTY_DEBUG)) + // set sample format + if (!gri_alsa_pick_acceptable_format(d_pcm_handle, + d_hw_params, + acceptable_formats, + NELEMS(acceptable_formats), + &d_format, + "audio_alsa_source", + CHATTY_DEBUG)) throw std::runtime_error("audio_alsa_source"); - // sampling rate - unsigned int orig_sampling_rate = d_sampling_rate; - if((error = snd_pcm_hw_params_set_rate_near(d_pcm_handle, d_hw_params, - &d_sampling_rate, 0)) < 0) + // sampling rate + unsigned int orig_sampling_rate = d_sampling_rate; + if ((error = snd_pcm_hw_params_set_rate_near( + d_pcm_handle, d_hw_params, &d_sampling_rate, 0)) < 0) bail("failed to set rate near", error); - if(orig_sampling_rate != d_sampling_rate){ - GR_LOG_INFO(d_logger, boost::format("[%1%]: unable to support sampling rate %2%\n\tCard requested %3% instead.") \ - % snd_pcm_name(d_pcm_handle) % orig_sampling_rate \ - % d_sampling_rate); - } - - /* - * ALSA transfers data in units of "periods". - * We indirectly determine the underlying buffersize by specifying - * the number of periods we want (typically 4) and the length of each - * period in units of time (typically 1ms). - */ - unsigned int min_nperiods, max_nperiods; - snd_pcm_hw_params_get_periods_min(d_hw_params, &min_nperiods, &dir); - snd_pcm_hw_params_get_periods_max(d_hw_params, &max_nperiods, &dir); - - unsigned int orig_nperiods = d_nperiods; - d_nperiods = std::min(std::max (min_nperiods, d_nperiods), max_nperiods); - - // adjust period time so that total buffering remains more-or-less constant - d_period_time_us = (d_period_time_us * orig_nperiods) / d_nperiods; - - error = snd_pcm_hw_params_set_periods(d_pcm_handle, d_hw_params, - d_nperiods, 0); - if(error < 0) + if (orig_sampling_rate != d_sampling_rate) { + GR_LOG_INFO(d_logger, + boost::format("[%1%]: unable to support sampling rate %2%\n\tCard " + "requested %3% instead.") % + snd_pcm_name(d_pcm_handle) % orig_sampling_rate % + d_sampling_rate); + } + + /* + * ALSA transfers data in units of "periods". + * We indirectly determine the underlying buffersize by specifying + * the number of periods we want (typically 4) and the length of each + * period in units of time (typically 1ms). + */ + unsigned int min_nperiods, max_nperiods; + snd_pcm_hw_params_get_periods_min(d_hw_params, &min_nperiods, &dir); + snd_pcm_hw_params_get_periods_max(d_hw_params, &max_nperiods, &dir); + + unsigned int orig_nperiods = d_nperiods; + d_nperiods = std::min(std::max(min_nperiods, d_nperiods), max_nperiods); + + // adjust period time so that total buffering remains more-or-less constant + d_period_time_us = (d_period_time_us * orig_nperiods) / d_nperiods; + + error = snd_pcm_hw_params_set_periods(d_pcm_handle, d_hw_params, d_nperiods, 0); + if (error < 0) bail("set_periods failed", error); - dir = 0; - error = snd_pcm_hw_params_set_period_time_near(d_pcm_handle, d_hw_params, - &d_period_time_us, &dir); - if(error < 0) + dir = 0; + error = snd_pcm_hw_params_set_period_time_near( + d_pcm_handle, d_hw_params, &d_period_time_us, &dir); + if (error < 0) bail("set_period_time_near failed", error); - dir = 0; - error = snd_pcm_hw_params_get_period_size(d_hw_params, - &d_period_size, &dir); - if(error < 0) + dir = 0; + error = snd_pcm_hw_params_get_period_size(d_hw_params, &d_period_size, &dir); + if (error < 0) bail("get_period_size failed", error); - set_output_multiple(d_period_size); - } - - bool - alsa_source::check_topology(int ninputs, int noutputs) - { - // noutputs is how many channels the user has connected. - // Now we can finish up setting up the hw params... - - unsigned int nchan = noutputs; - int err; - - // Check the state of the stream - // Ensure that the pcm is in a state where we can still mess with the hw_params - snd_pcm_state_t state; - state=snd_pcm_state(d_pcm_handle); - if(state== SND_PCM_STATE_RUNNING) - return true; // If stream is running, don't change any parameters - else if(state == SND_PCM_STATE_XRUN) - snd_pcm_prepare(d_pcm_handle); // Prepare stream on underrun, and we can set parameters; - - bool special_case = nchan == 1 && d_special_case_stereo_to_mono; - if(special_case) + set_output_multiple(d_period_size); +} + +bool alsa_source::check_topology(int ninputs, int noutputs) +{ + // noutputs is how many channels the user has connected. + // Now we can finish up setting up the hw params... + + unsigned int nchan = noutputs; + int err; + + // Check the state of the stream + // Ensure that the pcm is in a state where we can still mess with the hw_params + snd_pcm_state_t state; + state = snd_pcm_state(d_pcm_handle); + if (state == SND_PCM_STATE_RUNNING) + return true; // If stream is running, don't change any parameters + else if (state == SND_PCM_STATE_XRUN) + snd_pcm_prepare( + d_pcm_handle); // Prepare stream on underrun, and we can set parameters; + + bool special_case = nchan == 1 && d_special_case_stereo_to_mono; + if (special_case) nchan = 2; - d_hw_nchan = nchan; - err = snd_pcm_hw_params_set_channels(d_pcm_handle, d_hw_params, d_hw_nchan); - if(err < 0) { + d_hw_nchan = nchan; + err = snd_pcm_hw_params_set_channels(d_pcm_handle, d_hw_params, d_hw_nchan); + if (err < 0) { output_error_msg("set_channels failed", err); return false; - } + } - // set the parameters into the driver... - err = snd_pcm_hw_params(d_pcm_handle, d_hw_params); - if(err < 0) { + // set the parameters into the driver... + err = snd_pcm_hw_params(d_pcm_handle, d_hw_params); + if (err < 0) { output_error_msg("snd_pcm_hw_params failed", err); return false; - } + } - d_buffer_size_bytes = - d_period_size * d_hw_nchan * snd_pcm_format_size(d_format, 1); + d_buffer_size_bytes = d_period_size * d_hw_nchan * snd_pcm_format_size(d_format, 1); - d_buffer = new char[d_buffer_size_bytes]; + d_buffer = new char[d_buffer_size_bytes]; - if(CHATTY_DEBUG) { - GR_LOG_DEBUG(d_logger, boost::format("[%1%]: sample resolution = %2% bits") \ - % snd_pcm_name(d_pcm_handle) \ - % snd_pcm_hw_params_get_sbits(d_hw_params)); - } + if (CHATTY_DEBUG) { + GR_LOG_DEBUG(d_logger, + boost::format("[%1%]: sample resolution = %2% bits") % + snd_pcm_name(d_pcm_handle) % + snd_pcm_hw_params_get_sbits(d_hw_params)); + } - switch(d_format) { - case SND_PCM_FORMAT_S16: - if(special_case) - d_worker = &alsa_source::work_s16_2x1; + switch (d_format) { + case SND_PCM_FORMAT_S16: + if (special_case) + d_worker = &alsa_source::work_s16_2x1; else - d_worker = &alsa_source::work_s16; + d_worker = &alsa_source::work_s16; break; - case SND_PCM_FORMAT_S32: - if(special_case) - d_worker = &alsa_source::work_s32_2x1; + case SND_PCM_FORMAT_S32: + if (special_case) + d_worker = &alsa_source::work_s32_2x1; else - d_worker = &alsa_source::work_s32; + d_worker = &alsa_source::work_s32; break; - default: + default: assert(0); - } - - return true; } - alsa_source::~alsa_source() - { - if(snd_pcm_state(d_pcm_handle) == SND_PCM_STATE_RUNNING) + return true; +} + +alsa_source::~alsa_source() +{ + if (snd_pcm_state(d_pcm_handle) == SND_PCM_STATE_RUNNING) snd_pcm_drop(d_pcm_handle); - snd_pcm_close(d_pcm_handle); - delete [] ((char*)d_hw_params); - delete [] ((char*)d_sw_params); - delete [] d_buffer; - } + snd_pcm_close(d_pcm_handle); + delete[]((char*)d_hw_params); + delete[]((char*)d_sw_params); + delete[] d_buffer; +} - int - alsa_source::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - assert((noutput_items % d_period_size) == 0); - assert(noutput_items != 0); +int alsa_source::work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + assert((noutput_items % d_period_size) == 0); + assert(noutput_items != 0); - // this is a call through a pointer to a method... - return (this->*d_worker)(noutput_items, input_items, output_items); - } + // this is a call through a pointer to a method... + return (this->*d_worker)(noutput_items, input_items, output_items); +} - /* - * Work function that deals with float to S16 conversion - */ - int - alsa_source::work_s16(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - typedef int16_t sample_t; // the type of samples we're creating - static const float scale_factor = 1.0 / std::pow(2.0f, 16-1); - - unsigned int nchan = output_items.size (); - float **out = (float **)&output_items[0]; - sample_t *buf = (sample_t *)d_buffer; - int bi; - - unsigned int sizeof_frame = d_hw_nchan * sizeof (sample_t); - assert(d_buffer_size_bytes == d_period_size * sizeof_frame); - - // To minimize latency, return at most a single period's worth of samples. - // [We could also read the first one in a blocking mode and subsequent - // ones in non-blocking mode, but we'll leave that for later (or never).] - - if(!read_buffer(buf, d_period_size, sizeof_frame)) - return -1; // No fixing this problem. Say we're done. - - // process one period of data - bi = 0; - for(unsigned int i = 0; i < d_period_size; i++) { - for(unsigned int chan = 0; chan < nchan; chan++) { - out[chan][i] = (float) buf[bi++] * scale_factor; +/* + * Work function that deals with float to S16 conversion + */ +int alsa_source::work_s16(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + typedef int16_t sample_t; // the type of samples we're creating + static const float scale_factor = 1.0 / std::pow(2.0f, 16 - 1); + + unsigned int nchan = output_items.size(); + float** out = (float**)&output_items[0]; + sample_t* buf = (sample_t*)d_buffer; + int bi; + + unsigned int sizeof_frame = d_hw_nchan * sizeof(sample_t); + assert(d_buffer_size_bytes == d_period_size * sizeof_frame); + + // To minimize latency, return at most a single period's worth of samples. + // [We could also read the first one in a blocking mode and subsequent + // ones in non-blocking mode, but we'll leave that for later (or never).] + + if (!read_buffer(buf, d_period_size, sizeof_frame)) + return -1; // No fixing this problem. Say we're done. + + // process one period of data + bi = 0; + for (unsigned int i = 0; i < d_period_size; i++) { + for (unsigned int chan = 0; chan < nchan; chan++) { + out[chan][i] = (float)buf[bi++] * scale_factor; } - } - - return d_period_size; } - /* - * Work function that deals with float to S16 conversion - * and stereo to mono kludge... - */ - int - alsa_source::work_s16_2x1(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - typedef int16_t sample_t; // the type of samples we're creating - static const float scale_factor = 1.0 / std::pow(2.0f, 16-1); - - float **out = (float**)&output_items[0]; - sample_t *buf = (sample_t*)d_buffer; - int bi; - - assert(output_items.size () == 1); - - unsigned int sizeof_frame = d_hw_nchan * sizeof(sample_t); - assert(d_buffer_size_bytes == d_period_size * sizeof_frame); - - // To minimize latency, return at most a single period's worth of samples. - // [We could also read the first one in a blocking mode and subsequent - // ones in non-blocking mode, but we'll leave that for later (or never).] - if(!read_buffer (buf, d_period_size, sizeof_frame)) - return -1; // No fixing this problem. Say we're done. - - // process one period of data - bi = 0; - for(unsigned int i = 0; i < d_period_size; i++) { - int t = (buf[bi] + buf[bi+1]) / 2; - bi += 2; - out[0][i] = (float) t * scale_factor; - } + return d_period_size; +} - return d_period_size; +/* + * Work function that deals with float to S16 conversion + * and stereo to mono kludge... + */ +int alsa_source::work_s16_2x1(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + typedef int16_t sample_t; // the type of samples we're creating + static const float scale_factor = 1.0 / std::pow(2.0f, 16 - 1); + + float** out = (float**)&output_items[0]; + sample_t* buf = (sample_t*)d_buffer; + int bi; + + assert(output_items.size() == 1); + + unsigned int sizeof_frame = d_hw_nchan * sizeof(sample_t); + assert(d_buffer_size_bytes == d_period_size * sizeof_frame); + + // To minimize latency, return at most a single period's worth of samples. + // [We could also read the first one in a blocking mode and subsequent + // ones in non-blocking mode, but we'll leave that for later (or never).] + if (!read_buffer(buf, d_period_size, sizeof_frame)) + return -1; // No fixing this problem. Say we're done. + + // process one period of data + bi = 0; + for (unsigned int i = 0; i < d_period_size; i++) { + int t = (buf[bi] + buf[bi + 1]) / 2; + bi += 2; + out[0][i] = (float)t * scale_factor; } - /* - * Work function that deals with float to S32 conversion - */ - int - alsa_source::work_s32(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - typedef int32_t sample_t; // the type of samples we're creating - static const float scale_factor = 1.0 / std::pow(2.0f, 32-1); - - unsigned int nchan = output_items.size (); - float **out = (float**)&output_items[0]; - sample_t *buf = (sample_t*)d_buffer; - int bi; - - unsigned int sizeof_frame = d_hw_nchan * sizeof(sample_t); - assert(d_buffer_size_bytes == d_period_size * sizeof_frame); - - // To minimize latency, return at most a single period's worth of samples. - // [We could also read the first one in a blocking mode and subsequent - // ones in non-blocking mode, but we'll leave that for later (or never).] - - if(!read_buffer(buf, d_period_size, sizeof_frame)) - return -1; // No fixing this problem. Say we're done. - - // process one period of data - bi = 0; - for(unsigned int i = 0; i < d_period_size; i++) { - for(unsigned int chan = 0; chan < nchan; chan++) { - out[chan][i] = (float) buf[bi++] * scale_factor; - } - } + return d_period_size; +} - return d_period_size; +/* + * Work function that deals with float to S32 conversion + */ +int alsa_source::work_s32(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + typedef int32_t sample_t; // the type of samples we're creating + static const float scale_factor = 1.0 / std::pow(2.0f, 32 - 1); + + unsigned int nchan = output_items.size(); + float** out = (float**)&output_items[0]; + sample_t* buf = (sample_t*)d_buffer; + int bi; + + unsigned int sizeof_frame = d_hw_nchan * sizeof(sample_t); + assert(d_buffer_size_bytes == d_period_size * sizeof_frame); + + // To minimize latency, return at most a single period's worth of samples. + // [We could also read the first one in a blocking mode and subsequent + // ones in non-blocking mode, but we'll leave that for later (or never).] + + if (!read_buffer(buf, d_period_size, sizeof_frame)) + return -1; // No fixing this problem. Say we're done. + + // process one period of data + bi = 0; + for (unsigned int i = 0; i < d_period_size; i++) { + for (unsigned int chan = 0; chan < nchan; chan++) { + out[chan][i] = (float)buf[bi++] * scale_factor; + } } - /* - * Work function that deals with float to S32 conversion - * and stereo to mono kludge... - */ - int - alsa_source::work_s32_2x1(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - typedef int32_t sample_t; // the type of samples we're creating - static const float scale_factor = 1.0 / std::pow(2.0f, 32-1); - - float **out = (float**)&output_items[0]; - sample_t *buf = (sample_t*)d_buffer; - int bi; - - assert(output_items.size () == 1); - - unsigned int sizeof_frame = d_hw_nchan * sizeof(sample_t); - assert(d_buffer_size_bytes == d_period_size * sizeof_frame); - - // To minimize latency, return at most a single period's worth of samples. - // [We could also read the first one in a blocking mode and subsequent - // ones in non-blocking mode, but we'll leave that for later (or never).] - - if(!read_buffer(buf, d_period_size, sizeof_frame)) - return -1; // No fixing this problem. Say we're done. - - // process one period of data - bi = 0; - for(unsigned int i = 0; i < d_period_size; i++) { - int t = (buf[bi] + buf[bi+1]) / 2; + return d_period_size; +} + +/* + * Work function that deals with float to S32 conversion + * and stereo to mono kludge... + */ +int alsa_source::work_s32_2x1(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + typedef int32_t sample_t; // the type of samples we're creating + static const float scale_factor = 1.0 / std::pow(2.0f, 32 - 1); + + float** out = (float**)&output_items[0]; + sample_t* buf = (sample_t*)d_buffer; + int bi; + + assert(output_items.size() == 1); + + unsigned int sizeof_frame = d_hw_nchan * sizeof(sample_t); + assert(d_buffer_size_bytes == d_period_size * sizeof_frame); + + // To minimize latency, return at most a single period's worth of samples. + // [We could also read the first one in a blocking mode and subsequent + // ones in non-blocking mode, but we'll leave that for later (or never).] + + if (!read_buffer(buf, d_period_size, sizeof_frame)) + return -1; // No fixing this problem. Say we're done. + + // process one period of data + bi = 0; + for (unsigned int i = 0; i < d_period_size; i++) { + int t = (buf[bi] + buf[bi + 1]) / 2; bi += 2; out[0][i] = (float)t * scale_factor; - } - - return d_period_size; } - bool - alsa_source::read_buffer(void *vbuffer, unsigned nframes, unsigned sizeof_frame) - { - unsigned char *buffer = (unsigned char*)vbuffer; - - while(nframes > 0) { - int r = snd_pcm_readi (d_pcm_handle, buffer, nframes); - if(r == -EAGAIN) - continue; // try again - - else if(r == -EPIPE) { // overrun - d_noverruns++; - fputs("aO", stderr); - if((r = snd_pcm_prepare (d_pcm_handle)) < 0) { - output_error_msg("snd_pcm_prepare failed. Can't recover from overrun", r); - return false; - } - continue; // try again + return d_period_size; +} + +bool alsa_source::read_buffer(void* vbuffer, unsigned nframes, unsigned sizeof_frame) +{ + unsigned char* buffer = (unsigned char*)vbuffer; + + while (nframes > 0) { + int r = snd_pcm_readi(d_pcm_handle, buffer, nframes); + if (r == -EAGAIN) + continue; // try again + + else if (r == -EPIPE) { // overrun + d_noverruns++; + fputs("aO", stderr); + if ((r = snd_pcm_prepare(d_pcm_handle)) < 0) { + output_error_msg("snd_pcm_prepare failed. Can't recover from overrun", r); + return false; + } + continue; // try again } #ifdef ESTRPIPE - else if(r == -ESTRPIPE) { // h/w is suspended (whatever that means) - // This is apparently related to power management - d_nsuspends++; - if((r = snd_pcm_resume (d_pcm_handle)) < 0) { - output_error_msg ("failed to resume from suspend", r); - return false; - } - continue; // try again + else if (r == -ESTRPIPE) { // h/w is suspended (whatever that means) + // This is apparently related to power management + d_nsuspends++; + if ((r = snd_pcm_resume(d_pcm_handle)) < 0) { + output_error_msg("failed to resume from suspend", r); + return false; + } + continue; // try again } #endif - else if(r < 0) { - output_error_msg("snd_pcm_readi failed", r); - return false; + else if (r < 0) { + output_error_msg("snd_pcm_readi failed", r); + return false; } nframes -= r; buffer += r * sizeof_frame; - } - - return true; } - void - alsa_source::output_error_msg(const char *msg, int err) - { - GR_LOG_ERROR(d_logger, boost::format("[%1%]: %2%: %3%") \ - % snd_pcm_name(d_pcm_handle) % msg % snd_strerror(err)); - } + return true; +} - void - alsa_source::bail(const char *msg, int err) - { - output_error_msg(msg, err); - throw std::runtime_error("audio_alsa_source"); - } +void alsa_source::output_error_msg(const char* msg, int err) +{ + GR_LOG_ERROR(d_logger, + boost::format("[%1%]: %2%: %3%") % snd_pcm_name(d_pcm_handle) % msg % + snd_strerror(err)); +} + +void alsa_source::bail(const char* msg, int err) +{ + output_error_msg(msg, err); + throw std::runtime_error("audio_alsa_source"); +} - } /* namespace audio */ +} /* namespace audio */ } /* namespace gr */ |