diff options
Diffstat (limited to 'gr-audio/lib')
40 files changed, 0 insertions, 6781 deletions
diff --git a/gr-audio/lib/CMakeLists.txt b/gr-audio/lib/CMakeLists.txt deleted file mode 100644 index f39264d5d..000000000 --- a/gr-audio/lib/CMakeLists.txt +++ /dev/null @@ -1,154 +0,0 @@ -# Copyright 2011 Free Software Foundation, Inc. -# -# This file is part of GNU Radio -# -# GNU Radio is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3, or (at your option) -# any later version. -# -# GNU Radio is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Radio; see the file COPYING. If not, write to -# the Free Software Foundation, Inc., 51 Franklin Street, -# Boston, MA 02110-1301, USA. - -######################################################################## -# Setup the include and linker paths -######################################################################## -include_directories( - ${CMAKE_CURRENT_SOURCE_DIR} - ${GR_AUDIO_INCLUDE_DIRS} - ${GNURADIO_CORE_INCLUDE_DIRS} - ${GRUEL_INCLUDE_DIRS} - ${Boost_INCLUDE_DIRS} -) - -link_directories(${Boost_LIBRARY_DIRS}) - -list(APPEND gr_audio_libs gnuradio-core ${Boost_LIBRARIES}) -list(APPEND gr_audio_sources gr_audio_registry.cc) -list(APPEND gr_audio_confs ${CMAKE_CURRENT_SOURCE_DIR}/gr-audio.conf) - -######################################################################## -## ALSA Support -######################################################################## -find_package(ALSA) - -if(ALSA_FOUND) - - include_directories(${CMAKE_CURRENT_SOURCE_DIR}/alsa ${ALSA_INCLUDE_DIRS}) - list(APPEND gr_audio_libs ${ALSA_LIBRARIES}) - list(APPEND gr_audio_sources - ${CMAKE_CURRENT_SOURCE_DIR}/alsa/gri_alsa.cc - ${CMAKE_CURRENT_SOURCE_DIR}/alsa/audio_alsa_source.cc - ${CMAKE_CURRENT_SOURCE_DIR}/alsa/audio_alsa_sink.cc - ) - list(APPEND gr_audio_confs ${CMAKE_CURRENT_SOURCE_DIR}/alsa/gr-audio-alsa.conf) - -endif(ALSA_FOUND) - -######################################################################## -## OSS Support -######################################################################## -find_package(OSS) - -if(OSS_FOUND) - - include_directories(${CMAKE_CURRENT_SOURCE_DIR}/oss ${OSS_INCLUDE_DIRS}) - list(APPEND gr_audio_sources - ${CMAKE_CURRENT_SOURCE_DIR}/oss/audio_oss_source.cc - ${CMAKE_CURRENT_SOURCE_DIR}/oss/audio_oss_sink.cc - ) - list(APPEND gr_audio_confs ${CMAKE_CURRENT_SOURCE_DIR}/oss/gr-audio-oss.conf) - -endif(OSS_FOUND) - - -######################################################################## -## Jack Support -######################################################################## -find_package(Jack) - -if(JACK_FOUND) - - include_directories(${CMAKE_CURRENT_SOURCE_DIR}/jack ${JACK_INCLUDE_DIRS}) - list(APPEND gr_audio_libs ${JACK_LIBRARIES}) - add_definitions(${JACK_DEFINITIONS}) - list(APPEND gr_audio_sources - ${CMAKE_CURRENT_SOURCE_DIR}/jack/gri_jack.cc - ${CMAKE_CURRENT_SOURCE_DIR}/jack/audio_jack_source.cc - ${CMAKE_CURRENT_SOURCE_DIR}/jack/audio_jack_sink.cc - ) - list(APPEND gr_audio_confs ${CMAKE_CURRENT_SOURCE_DIR}/jack/gr-audio-jack.conf) - -endif(JACK_FOUND) - -######################################################################## -## OSX Support -######################################################################## -include(CheckIncludeFileCXX) -CHECK_INCLUDE_FILE_CXX(AudioUnit/AudioUnit.h AUDIO_UNIT_H) -CHECK_INCLUDE_FILE_CXX(AudioToolbox/AudioToolbox.h AUDIO_TOOLBOX_H) - -if(AUDIO_UNIT_H AND AUDIO_TOOLBOX_H) - - include_directories(${CMAKE_CURRENT_SOURCE_DIR}/osx) - list(APPEND gr_audio_libs - "-framework AudioUnit" - "-framework CoreAudio" - "-framework AudioToolbox" - "-framework Carbon" - ) - list(APPEND gr_audio_sources - ${CMAKE_CURRENT_SOURCE_DIR}/osx/audio_osx_source.cc - ${CMAKE_CURRENT_SOURCE_DIR}/osx/audio_osx_sink.cc - ) - -endif(AUDIO_UNIT_H AND AUDIO_TOOLBOX_H) - -######################################################################## -## PortAudio Support -######################################################################## -find_package(Portaudio) - -if(PORTAUDIO_FOUND) - - include_directories(${CMAKE_CURRENT_SOURCE_DIR}/portaudio ${PORTAUDIO_INCLUDE_DIRS}) - list(APPEND gr_audio_libs ${PORTAUDIO_LIBRARIES}) - add_definitions(${PORTAUDIO_DEFINITIONS}) - list(APPEND gr_audio_sources - ${CMAKE_CURRENT_SOURCE_DIR}/portaudio/gri_portaudio.cc - ${CMAKE_CURRENT_SOURCE_DIR}/portaudio/audio_portaudio_source.cc - ${CMAKE_CURRENT_SOURCE_DIR}/portaudio/audio_portaudio_sink.cc - ) - list(APPEND gr_audio_confs ${CMAKE_CURRENT_SOURCE_DIR}/portaudio/gr-audio-portaudio.conf) - -endif(PORTAUDIO_FOUND) - -######################################################################## -## Windows Support -######################################################################## -if(WIN32) - - include_directories(${CMAKE_CURRENT_SOURCE_DIR}/windows) - list(APPEND gr_audio_libs winmm.lib) - list(APPEND gr_audio_sources - ${CMAKE_CURRENT_SOURCE_DIR}/windows/audio_windows_source.cc - ${CMAKE_CURRENT_SOURCE_DIR}/windows/audio_windows_sink.cc - ) - -endif(WIN32) - -######################################################################## -# Setup library -######################################################################## -add_library(gnuradio-audio SHARED ${gr_audio_sources}) -target_link_libraries(gnuradio-audio ${gr_audio_libs}) -GR_LIBRARY_FOO(gnuradio-audio RUNTIME_COMPONENT "audio_runtime" DEVEL_COMPONENT "audio_devel") - -install(FILES ${gr_audio_confs} DESTINATION ${GR_PREFSDIR} COMPONENT "audio_runtime") diff --git a/gr-audio/lib/alsa/audio_alsa_sink.cc b/gr-audio/lib/alsa/audio_alsa_sink.cc deleted file mode 100644 index 687f24bde..000000000 --- a/gr-audio/lib/alsa/audio_alsa_sink.cc +++ /dev/null @@ -1,548 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gr_audio_registry.h" -#include <audio_alsa_sink.h> -#include <gr_io_signature.h> -#include <gr_prefs.h> -#include <stdio.h> -#include <iostream> -#include <stdexcept> -#include <gri_alsa.h> - -AUDIO_REGISTER_SINK(REG_PRIO_HIGH, alsa)( - int sampling_rate, const std::string &device_name, bool ok_to_block -){ - return audio_sink::sptr(new audio_alsa_sink(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 gr_prefs::singleton()->get_string("audio_alsa", "default_output_device", "hw:0,0"); -} - -static double -default_period_time () -{ - return std::max(0.001, gr_prefs::singleton()->get_double("audio_alsa", "period_time", 0.010)); -} - -static int -default_nperiods () -{ - return std::max(2L, gr_prefs::singleton()->get_long("audio_alsa", "nperiods", 4)); -} - -// ---------------------------------------------------------------- - -audio_alsa_sink::audio_alsa_sink (int sampling_rate, - const std::string device_name, - bool ok_to_block) - : gr_sync_block ("audio_alsa_sink", - gr_make_io_signature (0, 0, 0), - gr_make_io_signature (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_special_case_mono_to_stereo (false), - d_nunderuns (0), d_nsuspends (0), d_ok_to_block(ok_to_block) -{ - CHATTY_DEBUG = gr_prefs::singleton()->get_bool("audio_alsa", "verbose", false); - - int error; - int dir; - - // open the device for playback - error = snd_pcm_open(&d_pcm_handle, d_device_name.c_str (), - SND_PCM_STREAM_PLAYBACK, 0); - if (ok_to_block == false) - snd_pcm_nonblock(d_pcm_handle, !ok_to_block); - if (error < 0){ - fprintf (stderr, "audio_alsa_sink[%s]: %s\n", - d_device_name.c_str(), snd_strerror(error)); - throw std::runtime_error ("audio_alsa_sink"); - } - - // 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) - 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 input signature - unsigned int umin_chan, umax_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 input and handle the duplication ourselves. - - if (min_chan == 2){ - min_chan = 1; - d_special_case_mono_to_stereo = true; - } - set_input_signature (gr_make_io_signature (min_chan, max_chan, - sizeof (float))); - - // 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); - - 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_sink", - CHATTY_DEBUG)) - throw std::runtime_error ("audio_alsa_sink"); - - - // 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){ - fprintf (stderr, "audio_alsa_sink[%s]: unable to support sampling rate %d\n", - snd_pcm_name (d_pcm_handle), orig_sampling_rate); - fprintf (stderr, " card requested %d instead.\n", 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); - //fprintf (stderr, "alsa_sink: min_nperiods = %d, max_nperiods = %d\n", - // min_nperiods, max_nperiods); - - 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) - 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) - bail ("get_period_size failed", error); - - set_output_multiple (d_period_size); -} - - -bool -audio_alsa_sink::check_topology (int ninputs, int noutputs) -{ - // ninputs is how many channels the user has connected. - // Now we can finish up setting up the hw params... - - int nchan = ninputs; - 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_mono_to_stereo; - if (special_case) - nchan = 2; - - err = snd_pcm_hw_params_set_channels (d_pcm_handle, d_hw_params, 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){ - output_error_msg ("snd_pcm_hw_params failed", err); - return false; - } - - // get current s/w params - err = snd_pcm_sw_params_current (d_pcm_handle, d_sw_params); - if (err < 0) - bail ("snd_pcm_sw_params_current", err); - - // Tell the PCM device to wait to start until we've filled - // it's buffers half way full. This helps avoid audio underruns. - - err = snd_pcm_sw_params_set_start_threshold(d_pcm_handle, - d_sw_params, - d_nperiods * d_period_size / 2); - if (err < 0) - bail ("snd_pcm_sw_params_set_start_threshold", err); - - // store the s/w params - err = snd_pcm_sw_params (d_pcm_handle, d_sw_params); - if (err < 0) - bail ("snd_pcm_sw_params", err); - - d_buffer_size_bytes = - d_period_size * nchan * snd_pcm_format_size (d_format, 1); - - d_buffer = new char [d_buffer_size_bytes]; - - if (CHATTY_DEBUG) - fprintf (stdout, "audio_alsa_sink[%s]: sample resolution = %d bits\n", - 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 = &audio_alsa_sink::work_s16_1x2; - else - d_worker = &audio_alsa_sink::work_s16; - break; - - case SND_PCM_FORMAT_S32: - if (special_case) - d_worker = &audio_alsa_sink::work_s32_1x2; - else - d_worker = &audio_alsa_sink::work_s32; - break; - - default: - assert (0); - } - return true; -} - -audio_alsa_sink::~audio_alsa_sink () -{ - 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; -} - -int -audio_alsa_sink::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - assert ((noutput_items % d_period_size) == 0); - - // 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 -audio_alsa_sink::work_s16 (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - typedef gr_int16 sample_t; // the type of samples we're creating - static const float scale_factor = std::pow(2.0f, 16-1) - 1; - - unsigned int nchan = input_items.size (); - const float **in = (const float **) &input_items[0]; - sample_t *buf = (sample_t *) d_buffer; - int bi; - int n; - - unsigned int sizeof_frame = nchan * sizeof (sample_t); - assert (d_buffer_size_bytes == d_period_size * sizeof_frame); - - for (n = 0; n < noutput_items; n += d_period_size){ - - // 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++){ - buf[bi++] = (sample_t) (in[chan][i] * scale_factor); - } - } - - // update src pointers - for (unsigned int chan = 0; chan < nchan; chan++) - in[chan] += d_period_size; - - if (!write_buffer (buf, d_period_size, sizeof_frame)) - return -1; // No fixing this problem. Say we're done. - } - - return n; -} - - -/* - * Work function that deals with float to S32 conversion - */ -int -audio_alsa_sink::work_s32 (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - typedef gr_int32 sample_t; // the type of samples we're creating - static const float scale_factor = std::pow(2.0f, 32-1) - 1; - - unsigned int nchan = input_items.size (); - const float **in = (const float **) &input_items[0]; - sample_t *buf = (sample_t *) d_buffer; - int bi; - int n; - - unsigned int sizeof_frame = nchan * sizeof (sample_t); - assert (d_buffer_size_bytes == d_period_size * sizeof_frame); - - for (n = 0; n < noutput_items; n += d_period_size){ - - // 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++){ - buf[bi++] = (sample_t) (in[chan][i] * scale_factor); - } - } - - // update src pointers - for (unsigned int chan = 0; chan < nchan; chan++) - in[chan] += d_period_size; - - if (!write_buffer (buf, d_period_size, sizeof_frame)) - return -1; // No fixing this problem. Say we're done. - } - - return n; -} - -/* - * Work function that deals with float to S16 conversion and - * mono to stereo kludge. - */ -int -audio_alsa_sink::work_s16_1x2 (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - typedef gr_int16 sample_t; // the type of samples we're creating - static const float scale_factor = std::pow(2.0f, 16-1) - 1; - - assert (input_items.size () == 1); - static const unsigned int nchan = 2; - const float **in = (const float **) &input_items[0]; - sample_t *buf = (sample_t *) d_buffer; - int bi; - int n; - - unsigned int sizeof_frame = nchan * sizeof (sample_t); - assert (d_buffer_size_bytes == d_period_size * sizeof_frame); - - for (n = 0; n < noutput_items; n += d_period_size){ - - // process one period of data - bi = 0; - for (unsigned int i = 0; i < d_period_size; i++){ - sample_t t = (sample_t) (in[0][i] * scale_factor); - buf[bi++] = t; - buf[bi++] = t; - } - - // update src pointers - in[0] += d_period_size; - - if (!write_buffer (buf, d_period_size, sizeof_frame)) - return -1; // No fixing this problem. Say we're done. - } - - return n; -} - -/* - * Work function that deals with float to S32 conversion and - * mono to stereo kludge. - */ -int -audio_alsa_sink::work_s32_1x2 (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - typedef gr_int32 sample_t; // the type of samples we're creating - static const float scale_factor = std::pow(2.0f, 32-1) - 1; - - assert (input_items.size () == 1); - static unsigned int nchan = 2; - const float **in = (const float **) &input_items[0]; - sample_t *buf = (sample_t *) d_buffer; - int bi; - int n; - - unsigned int sizeof_frame = nchan * sizeof (sample_t); - assert (d_buffer_size_bytes == d_period_size * sizeof_frame); - - for (n = 0; n < noutput_items; n += d_period_size){ - - // process one period of data - bi = 0; - for (unsigned int i = 0; i < d_period_size; i++){ - sample_t t = (sample_t) (in[0][i] * scale_factor); - buf[bi++] = t; - buf[bi++] = t; - } - - // update src pointers - in[0] += d_period_size; - - if (!write_buffer (buf, d_period_size, sizeof_frame)) - return -1; // No fixing this problem. Say we're done. - } - - return n; -} - -bool -audio_alsa_sink::write_buffer (const void *vbuffer, - unsigned nframes, unsigned sizeof_frame) -{ - const unsigned char *buffer = (const unsigned char *) vbuffer; - - while (nframes > 0){ - int r = snd_pcm_writei (d_pcm_handle, buffer, nframes); - if (r == -EAGAIN) - { - if (d_ok_to_block == true) - continue; // try again - - break; - } - - else if (r == -EPIPE){ // underrun - d_nunderuns++; - fputs ("aU", stderr); - if ((r = snd_pcm_prepare (d_pcm_handle)) < 0){ - output_error_msg ("snd_pcm_prepare failed. Can't recover from underrun", 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 - } - - else if (r < 0){ - output_error_msg ("snd_pcm_writei failed", r); - return false; - } - - nframes -= r; - buffer += r * sizeof_frame; - } - - return true; -} - - -void -audio_alsa_sink::output_error_msg (const char *msg, int err) -{ - fprintf (stderr, "audio_alsa_sink[%s]: %s: %s\n", - snd_pcm_name (d_pcm_handle), msg, snd_strerror (err)); -} - -void -audio_alsa_sink::bail (const char *msg, int err) throw (std::runtime_error) -{ - output_error_msg (msg, err); - throw std::runtime_error ("audio_alsa_sink"); -} diff --git a/gr-audio/lib/alsa/audio_alsa_sink.h b/gr-audio/lib/alsa/audio_alsa_sink.h deleted file mode 100644 index d456e53de..000000000 --- a/gr-audio/lib/alsa/audio_alsa_sink.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_AUDIO_ALSA_SINK_H -#define INCLUDED_AUDIO_ALSA_SINK_H - -// use new ALSA API -#define ALSA_PCM_NEW_HW_PARAMS_API -#define ALSA_PCM_NEW_SW_PARAMS_API - -#include <gr_audio_sink.h> -#include <string> -#include <alsa/asoundlib.h> -#include <stdexcept> - -/*! - * \brief audio sink using ALSA - * \ingroup audio_blk - * - * The sink has N input streams of floats, where N depends - * on the hardware characteristics of the selected device. - * - * Input samples must be in the range [-1,1]. - */ -class audio_alsa_sink : public audio_sink { - // typedef for pointer to class work method - typedef int (audio_alsa_sink::*work_t)(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - - unsigned int d_sampling_rate; - std::string d_device_name; - snd_pcm_t *d_pcm_handle; - snd_pcm_hw_params_t *d_hw_params; - snd_pcm_sw_params_t *d_sw_params; - snd_pcm_format_t d_format; - unsigned int d_nperiods; - unsigned int d_period_time_us; // microseconds - snd_pcm_uframes_t d_period_size; // in frames - unsigned int d_buffer_size_bytes; // sizeof of d_buffer - char *d_buffer; - work_t d_worker; // the work method to use - bool d_special_case_mono_to_stereo; - - // random stats - int d_nunderuns; // count of underruns - int d_nsuspends; // count of suspends - bool d_ok_to_block; // defaults to "true", controls blocking/non-block I/O - - void output_error_msg (const char *msg, int err); - void bail (const char *msg, int err) throw (std::runtime_error); - -public: - audio_alsa_sink (int sampling_rate, const std::string device_name, - bool ok_to_block); - - ~audio_alsa_sink (); - - bool check_topology (int ninputs, int noutputs); - - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - - -protected: - bool write_buffer (const void *buffer, unsigned nframes, unsigned sizeof_frame); - - int work_s16 (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - - int work_s16_1x2 (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - - int work_s32 (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - - int work_s32_1x2 (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); -}; - -#endif /* INCLUDED_AUDIO_ALSA_SINK_H */ diff --git a/gr-audio/lib/alsa/audio_alsa_source.cc b/gr-audio/lib/alsa/audio_alsa_source.cc deleted file mode 100644 index 9fdf80b43..000000000 --- a/gr-audio/lib/alsa/audio_alsa_source.cc +++ /dev/null @@ -1,509 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gr_audio_registry.h" -#include <audio_alsa_source.h> -#include <gr_io_signature.h> -#include <gr_prefs.h> -#include <stdio.h> -#include <iostream> -#include <stdexcept> -#include <gri_alsa.h> - -AUDIO_REGISTER_SOURCE(REG_PRIO_HIGH, alsa)( - int sampling_rate, const std::string &device_name, bool ok_to_block -){ - return audio_source::sptr(new audio_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 gr_prefs::singleton()->get_string("audio_alsa", "default_input_device", "hw:0,0"); -} - -static double -default_period_time () -{ - return std::max(0.001, gr_prefs::singleton()->get_double("audio_alsa", "period_time", 0.010)); -} - -static int -default_nperiods () -{ - return std::max(2L, gr_prefs::singleton()->get_long("audio_alsa", "nperiods", 4)); -} - -// ---------------------------------------------------------------- - -audio_alsa_source::audio_alsa_source (int sampling_rate, - const std::string device_name, - bool ok_to_block) - : gr_sync_block ("audio_alsa_source", - gr_make_io_signature (0, 0, 0), - gr_make_io_signature (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 = gr_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){ - fprintf (stderr, "audio_alsa_source[%s]: %s\n", - d_device_name.c_str(), 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) - bail ("broken configuration for playback", error); - - 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){ - min_chan = 1; - d_special_case_stereo_to_mono = true; - } - - set_output_signature (gr_make_io_signature (min_chan, max_chan, - sizeof (float))); - - // 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); - - 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)) - 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) - bail ("failed to set rate near", error); - - if (orig_sampling_rate != d_sampling_rate){ - fprintf (stderr, "audio_alsa_source[%s]: unable to support sampling rate %d\n", - snd_pcm_name (d_pcm_handle), orig_sampling_rate); - fprintf (stderr, " card requested %d instead.\n", 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); - //fprintf (stderr, "alsa_source: min_nperiods = %d, max_nperiods = %d\n", - // min_nperiods, max_nperiods); - - - 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) - 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) - bail ("get_period_size failed", error); - - set_output_multiple (d_period_size); -} - -bool -audio_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){ - 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){ - 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 = new char [d_buffer_size_bytes]; - - if (CHATTY_DEBUG) - fprintf (stdout, "audio_alsa_source[%s]: sample resolution = %d bits\n", - 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 = &audio_alsa_source::work_s16_2x1; - else - d_worker = &audio_alsa_source::work_s16; - break; - - case SND_PCM_FORMAT_S32: - if (special_case) - d_worker = &audio_alsa_source::work_s32_2x1; - else - d_worker = &audio_alsa_source::work_s32; - break; - - default: - assert (0); - } - - return true; -} - -audio_alsa_source::~audio_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; -} - -int -audio_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); -} - -/* - * Work function that deals with float to S16 conversion - */ -int -audio_alsa_source::work_s16 (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - typedef gr_int16 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 -audio_alsa_source::work_s16_2x1 (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - typedef gr_int16 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; -} - -/* - * Work function that deals with float to S32 conversion - */ -int -audio_alsa_source::work_s32 (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - typedef gr_int32 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; -} - -/* - * Work function that deals with float to S32 conversion - * and stereo to mono kludge... - */ -int -audio_alsa_source::work_s32_2x1 (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - typedef gr_int32 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 -audio_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 - } - - 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 < 0){ - output_error_msg ("snd_pcm_readi failed", r); - return false; - } - - nframes -= r; - buffer += r * sizeof_frame; - } - - return true; -} - - -void -audio_alsa_source::output_error_msg (const char *msg, int err) -{ - fprintf (stderr, "audio_alsa_source[%s]: %s: %s\n", - snd_pcm_name (d_pcm_handle), msg, snd_strerror (err)); -} - -void -audio_alsa_source::bail (const char *msg, int err) throw (std::runtime_error) -{ - output_error_msg (msg, err); - throw std::runtime_error ("audio_alsa_source"); -} diff --git a/gr-audio/lib/alsa/audio_alsa_source.h b/gr-audio/lib/alsa/audio_alsa_source.h deleted file mode 100644 index 320d49bd2..000000000 --- a/gr-audio/lib/alsa/audio_alsa_source.h +++ /dev/null @@ -1,107 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_AUDIO_ALSA_SOURCE_H -#define INCLUDED_AUDIO_ALSA_SOURCE_H - -// use new ALSA API -#define ALSA_PCM_NEW_HW_PARAMS_API -#define ALSA_PCM_NEW_SW_PARAMS_API - -#include <gr_audio_source.h> -#include <string> -#include <alsa/asoundlib.h> -#include <stdexcept> - -class audio_alsa_source; -typedef boost::shared_ptr<audio_alsa_source> audio_alsa_source_sptr; - -/*! - * \brief audio source using ALSA - * \ingroup audio_blk - * - * The source has between 1 and N input streams of floats, where N is - * depends on the hardware characteristics of the selected device. - * - * Output samples will be in the range [-1,1]. - */ -class audio_alsa_source : public audio_source { - // typedef for pointer to class work method - typedef int (audio_alsa_source::*work_t)(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - - unsigned int d_sampling_rate; - std::string d_device_name; - snd_pcm_t *d_pcm_handle; - snd_pcm_hw_params_t *d_hw_params; - snd_pcm_sw_params_t *d_sw_params; - snd_pcm_format_t d_format; - unsigned int d_nperiods; - unsigned int d_period_time_us; // microseconds - snd_pcm_uframes_t d_period_size; // in frames - unsigned int d_buffer_size_bytes; // sizeof of d_buffer - char *d_buffer; - work_t d_worker; // the work method to use - unsigned int d_hw_nchan; // # of configured h/w channels - bool d_special_case_stereo_to_mono; - - // random stats - int d_noverruns; // count of overruns - int d_nsuspends; // count of suspends - - void output_error_msg (const char *msg, int err); - void bail (const char *msg, int err) throw (std::runtime_error); - -public: - audio_alsa_source (int sampling_rate, const std::string device_name, - bool ok_to_block); - - ~audio_alsa_source (); - - bool check_topology (int ninputs, int noutputs); - - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - -protected: - bool read_buffer (void *buffer, unsigned nframes, unsigned sizeof_frame); - - int work_s16 (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - - int work_s16_2x1 (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - - int work_s32 (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - - int work_s32_2x1 (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); -}; - -#endif /* INCLUDED_AUDIO_ALSA_SOURCE_H */ diff --git a/gr-audio/lib/alsa/gr-audio-alsa.conf b/gr-audio/lib/alsa/gr-audio-alsa.conf deleted file mode 100644 index 5cec63e7a..000000000 --- a/gr-audio/lib/alsa/gr-audio-alsa.conf +++ /dev/null @@ -1,11 +0,0 @@ -# This file contains system wide configuration data for GNU Radio. -# You may override any setting on a per-user basis by editing -# ~/.gnuradio/config.conf - -[audio_alsa] - -default_input_device = hw:0,0 -default_output_device = hw:0,0 -period_time = 0.010 # in seconds -nperiods = 4 # total buffering = period_time * nperiods -verbose = false diff --git a/gr-audio/lib/alsa/gri_alsa.cc b/gr-audio/lib/alsa/gri_alsa.cc deleted file mode 100644 index 7bae0937d..000000000 --- a/gr-audio/lib/alsa/gri_alsa.cc +++ /dev/null @@ -1,175 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gri_alsa.h> -#include <algorithm> - -static snd_pcm_access_t access_types[] = { - SND_PCM_ACCESS_MMAP_INTERLEAVED, - SND_PCM_ACCESS_MMAP_NONINTERLEAVED, - SND_PCM_ACCESS_MMAP_COMPLEX, - SND_PCM_ACCESS_RW_INTERLEAVED, - SND_PCM_ACCESS_RW_NONINTERLEAVED -}; - -static snd_pcm_format_t format_types[] = { - // SND_PCM_FORMAT_UNKNOWN, - SND_PCM_FORMAT_S8, - SND_PCM_FORMAT_U8, - SND_PCM_FORMAT_S16_LE, - SND_PCM_FORMAT_S16_BE, - SND_PCM_FORMAT_U16_LE, - SND_PCM_FORMAT_U16_BE, - SND_PCM_FORMAT_S24_LE, - SND_PCM_FORMAT_S24_BE, - SND_PCM_FORMAT_U24_LE, - SND_PCM_FORMAT_U24_BE, - SND_PCM_FORMAT_S32_LE, - SND_PCM_FORMAT_S32_BE, - SND_PCM_FORMAT_U32_LE, - SND_PCM_FORMAT_U32_BE, - SND_PCM_FORMAT_FLOAT_LE, - SND_PCM_FORMAT_FLOAT_BE, - SND_PCM_FORMAT_FLOAT64_LE, - SND_PCM_FORMAT_FLOAT64_BE, - SND_PCM_FORMAT_IEC958_SUBFRAME_LE, - SND_PCM_FORMAT_IEC958_SUBFRAME_BE, - SND_PCM_FORMAT_MU_LAW, - SND_PCM_FORMAT_A_LAW, - SND_PCM_FORMAT_IMA_ADPCM, - SND_PCM_FORMAT_MPEG, - SND_PCM_FORMAT_GSM, - SND_PCM_FORMAT_SPECIAL, - SND_PCM_FORMAT_S24_3LE, - SND_PCM_FORMAT_S24_3BE, - SND_PCM_FORMAT_U24_3LE, - SND_PCM_FORMAT_U24_3BE, - SND_PCM_FORMAT_S20_3LE, - SND_PCM_FORMAT_S20_3BE, - SND_PCM_FORMAT_U20_3LE, - SND_PCM_FORMAT_U20_3BE, - SND_PCM_FORMAT_S18_3LE, - SND_PCM_FORMAT_S18_3BE, - SND_PCM_FORMAT_U18_3LE, - SND_PCM_FORMAT_U18_3BE -}; - -static unsigned int test_rates[] = { - 8000, 16000, 22050, 32000, 44100, 48000, 96000, 192000 -}; - -#define NELEMS(x) (sizeof(x)/sizeof(x[0])) - -void -gri_alsa_dump_hw_params (snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams, FILE *fp) -{ - fprintf (fp, "PCM name: %s\n", snd_pcm_name (pcm)); - - fprintf (fp, "Access types:\n"); - for (unsigned i = 0; i < NELEMS (access_types); i++){ - snd_pcm_access_t at = access_types[i]; - fprintf (fp, " %-20s %s\n", - snd_pcm_access_name (at), - snd_pcm_hw_params_test_access (pcm, hwparams, at) == 0 ? "YES" : "NO"); - } - - fprintf (fp, "Formats:\n"); - for (unsigned i = 0; i < NELEMS (format_types); i++){ - snd_pcm_format_t ft = format_types[i]; - if (0) - fprintf (fp, " %-20s %s\n", - snd_pcm_format_name (ft), - snd_pcm_hw_params_test_format (pcm, hwparams, ft) == 0 ? "YES" : "NO"); - else { - if (snd_pcm_hw_params_test_format (pcm, hwparams, ft) == 0) - fprintf (fp, " %-20s YES\n", snd_pcm_format_name (ft)); - } - } - - fprintf (fp, "Number of channels\n"); - unsigned int min_chan, max_chan; - snd_pcm_hw_params_get_channels_min (hwparams, &min_chan); - snd_pcm_hw_params_get_channels_max (hwparams, &max_chan); - fprintf (fp, " min channels: %d\n", min_chan); - fprintf (fp, " max channels: %d\n", max_chan); - unsigned int chan; - max_chan = std::min (max_chan, 16U); // truncate display... - for (chan = min_chan; chan <= max_chan; chan++){ - fprintf (fp, " %d channels\t%s\n", chan, - snd_pcm_hw_params_test_channels (pcm, hwparams, chan) == 0 ? "YES" : "NO"); - } - - fprintf (fp, "Sample Rates:\n"); - unsigned int min_rate, max_rate; - int min_dir, max_dir; - - snd_pcm_hw_params_get_rate_min (hwparams, &min_rate, &min_dir); - snd_pcm_hw_params_get_rate_max (hwparams, &max_rate, &max_dir); - fprintf (fp, " min rate: %7d (dir = %d)\n", min_rate, min_dir); - fprintf (fp, " max rate: %7d (dir = %d)\n", max_rate, max_dir); - for (unsigned i = 0; i < NELEMS (test_rates); i++){ - unsigned int rate = test_rates[i]; - fprintf (fp, " %6u %s\n", rate, - snd_pcm_hw_params_test_rate (pcm, hwparams, rate, 0) == 0 ? "YES" : "NO"); - } - - fflush (fp); -} - -bool -gri_alsa_pick_acceptable_format (snd_pcm_t *pcm, - snd_pcm_hw_params_t *hwparams, - snd_pcm_format_t acceptable_formats[], - unsigned nacceptable_formats, - snd_pcm_format_t *selected_format, - const char *error_msg_tag, - bool verbose) -{ - int err; - - // pick a format that we like... - for (unsigned i = 0; i < nacceptable_formats; i++){ - if (snd_pcm_hw_params_test_format (pcm, hwparams, - acceptable_formats[i]) == 0){ - err = snd_pcm_hw_params_set_format (pcm, hwparams, acceptable_formats[i]); - if (err < 0){ - fprintf (stderr, "%s[%s]: failed to set format: %s\n", - error_msg_tag, snd_pcm_name (pcm), snd_strerror (err)); - return false; - } - if (verbose) - fprintf (stdout, "%s[%s]: using %s\n", - error_msg_tag, snd_pcm_name (pcm), - snd_pcm_format_name (acceptable_formats[i])); - *selected_format = acceptable_formats[i]; - return true; - } - } - - fprintf (stderr, "%s[%s]: failed to find acceptable format", - error_msg_tag, snd_pcm_name (pcm)); - return false; -} diff --git a/gr-audio/lib/alsa/gri_alsa.h b/gr-audio/lib/alsa/gri_alsa.h deleted file mode 100644 index 9c64e2c36..000000000 --- a/gr-audio/lib/alsa/gri_alsa.h +++ /dev/null @@ -1,44 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_GRI_ALSA_H -#define INCLUDED_GRI_ALSA_H - -#include <stdio.h> -#include <alsa/asoundlib.h> - -void -gri_alsa_dump_hw_params (snd_pcm_t *pcm, - snd_pcm_hw_params_t *hwparams, - FILE *fp); - -bool -gri_alsa_pick_acceptable_format (snd_pcm_t *pcm, - snd_pcm_hw_params_t *hwparams, - snd_pcm_format_t acceptable_formats[], - unsigned nacceptable_formats, - snd_pcm_format_t *selected_format, - const char *error_msg_tag, - bool verbose); - - -#endif /* INCLUDED_GRI_ALSA_H */ diff --git a/gr-audio/lib/gr-audio.conf b/gr-audio/lib/gr-audio.conf deleted file mode 100644 index e0d9221c3..000000000 --- a/gr-audio/lib/gr-audio.conf +++ /dev/null @@ -1,12 +0,0 @@ -# This file contains system wide configuration data for GNU Radio. -# You may override any setting on a per-user basis by editing -# ~/.gnuradio/config.conf - -# specify which audio module to load, or use "auto" to have the system -# select one. Valid choices depend on your OS and which modules -# you've installed, but typically include: -# auto, alsa, oss, portaudio, jack, osx, windows - -[audio] - -audio_module = auto diff --git a/gr-audio/lib/gr_audio_registry.cc b/gr-audio/lib/gr_audio_registry.cc deleted file mode 100644 index e07bf844a..000000000 --- a/gr-audio/lib/gr_audio_registry.cc +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#include "gr_audio_registry.h" -#include <boost/foreach.hpp> -#include <gr_prefs.h> -#include <stdexcept> -#include <vector> -#include <iostream> - -/*********************************************************************** - * Create registries - **********************************************************************/ - -struct source_entry_t{ - reg_prio_type prio; - std::string arch; - source_factory_t source; -}; - -static std::vector<source_entry_t> &get_source_registry(void){ - static std::vector<source_entry_t> _registry; - return _registry; -} - -struct sink_entry_t{ - reg_prio_type prio; - std::string arch; - sink_factory_t sink; -}; - -static std::vector<sink_entry_t> &get_sink_registry(void){ - static std::vector<sink_entry_t> _registry; - return _registry; -} - -/*********************************************************************** - * Register functions - **********************************************************************/ -void audio_register_source( - reg_prio_type prio, const std::string &arch, source_factory_t source -){ - source_entry_t entry; - entry.prio = prio; - entry.arch = arch; - entry.source = source; - get_source_registry().push_back(entry); -} - -void audio_register_sink( - reg_prio_type prio, const std::string &arch, sink_factory_t sink -){ - sink_entry_t entry; - entry.prio = prio; - entry.arch = arch; - entry.sink = sink; - get_sink_registry().push_back(entry); -} - -/*********************************************************************** - * Factory functions - **********************************************************************/ -static std::string default_arch_name(void){ - return gr_prefs::singleton()->get_string("audio", "audio_module", "auto"); -} - -static void do_arch_warning(const std::string &arch){ - if (arch == "auto") return; //no warning when arch not specified - std::cerr << "Could not find audio architecture \"" << arch << "\" in registry." << std::endl; - std::cerr << " Defaulting to the first available architecture..." << std::endl; -} - -audio_source::sptr audio_make_source( - int sampling_rate, - const std::string device_name, - bool ok_to_block -){ - if (get_source_registry().empty()){ - throw std::runtime_error("no available audio source factories"); - } - - std::string arch = default_arch_name(); - source_entry_t entry = get_source_registry().front(); - - BOOST_FOREACH(const source_entry_t &e, get_source_registry()){ - if (e.prio > entry.prio) entry = e; //entry is highest prio - if (arch != e.arch) continue; //continue when no match - return e.source(sampling_rate, device_name, ok_to_block); - } - //std::cout << "Audio source arch: " << entry.name << std::endl; - return entry.source(sampling_rate, device_name, ok_to_block); -} - -audio_sink::sptr audio_make_sink( - int sampling_rate, - const std::string device_name, - bool ok_to_block -){ - if (get_sink_registry().empty()){ - throw std::runtime_error("no available audio sink factories"); - } - - std::string arch = default_arch_name(); - sink_entry_t entry = get_sink_registry().front(); - - BOOST_FOREACH(const sink_entry_t &e, get_sink_registry()){ - if (e.prio > entry.prio) entry = e; //entry is highest prio - if (arch != e.arch) continue; //continue when no match - return e.sink(sampling_rate, device_name, ok_to_block); - } - do_arch_warning(arch); - //std::cout << "Audio sink arch: " << entry.name << std::endl; - return entry.sink(sampling_rate, device_name, ok_to_block); -} diff --git a/gr-audio/lib/gr_audio_registry.h b/gr-audio/lib/gr_audio_registry.h deleted file mode 100644 index c40e15657..000000000 --- a/gr-audio/lib/gr_audio_registry.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_GR_AUDIO_REGISTRY_H -#define INCLUDED_GR_AUDIO_REGISTRY_H - -#include <gr_audio_sink.h> -#include <gr_audio_source.h> -#include <string> - -typedef audio_source::sptr(*source_factory_t)(int, const std::string &, bool); -typedef audio_sink::sptr(*sink_factory_t)(int, const std::string &, bool); - -enum reg_prio_type{ - REG_PRIO_LOW = 100, - REG_PRIO_MED = 200, - REG_PRIO_HIGH = 300 -}; - -void audio_register_source(reg_prio_type prio, const std::string &arch, source_factory_t source); -void audio_register_sink(reg_prio_type prio, const std::string &arch, sink_factory_t sink); - -#define AUDIO_REGISTER_FIXTURE(x) static struct x{x();}x;x::x() - -#define AUDIO_REGISTER_SOURCE(prio, arch) \ - static audio_source::sptr arch##_source_fcn(int, const std::string &, bool); \ - AUDIO_REGISTER_FIXTURE(arch##_source_reg){ \ - audio_register_source(prio, #arch, &arch##_source_fcn); \ - } static audio_source::sptr arch##_source_fcn - -#define AUDIO_REGISTER_SINK(prio, arch) \ - static audio_sink::sptr arch##_sink_fcn(int, const std::string &, bool); \ - AUDIO_REGISTER_FIXTURE(arch##_sink_reg){ \ - audio_register_sink(prio, #arch, &arch##_sink_fcn); \ - } static audio_sink::sptr arch##_sink_fcn - -#endif /* INCLUDED_GR_AUDIO_REGISTRY_H */ diff --git a/gr-audio/lib/jack/audio_jack_sink.cc b/gr-audio/lib/jack/audio_jack_sink.cc deleted file mode 100644 index 9caabe8e2..000000000 --- a/gr-audio/lib/jack/audio_jack_sink.cc +++ /dev/null @@ -1,236 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gr_audio_registry.h" -#include <audio_jack_sink.h> -#include <gr_io_signature.h> -#include <gr_prefs.h> -#include <stdio.h> -#include <iostream> -#include <stdexcept> -#include <gri_jack.h> - -#ifndef NO_PTHREAD -#include <pthread.h> -#endif - -AUDIO_REGISTER_SINK(REG_PRIO_MED, jack)( - int sampling_rate, const std::string &device_name, bool ok_to_block -){ - return audio_sink::sptr(new audio_jack_sink(sampling_rate, device_name, ok_to_block)); -} - -typedef jack_default_audio_sample_t sample_t; - - -// Number of jack buffers in the ringbuffer -// TODO: make it to match at least the quantity of items passed by work() -static const unsigned int N_BUFFERS = 16; - -static std::string -default_device_name () -{ - return gr_prefs::singleton()->get_string("audio_jack", "default_output_device", "gr_sink"); -} - -int -jack_sink_process (jack_nframes_t nframes, void *arg) -{ - audio_jack_sink *self = (audio_jack_sink *)arg; - unsigned int read_size = nframes*sizeof(sample_t); - - if (jack_ringbuffer_read_space (self->d_ringbuffer) < read_size) { - self->d_nunderuns++; - // FIXME: move this fputs out, we shouldn't use blocking calls in process() - fputs ("jU", stderr); - return 0; - } - - char *buffer = (char *) jack_port_get_buffer (self->d_jack_output_port, nframes); - - jack_ringbuffer_read (self->d_ringbuffer, buffer, read_size); - -#ifndef NO_PTHREAD - // Tell the sink thread there is room in the ringbuffer. - // If it is already running, the lock will not be available. - // We can't wait here in the process() thread, but we don't - // need to signal in that case, because the sink thread will - // check for room availability. - - if (pthread_mutex_trylock (&self->d_jack_process_lock) == 0) { - pthread_cond_signal (&self->d_ringbuffer_ready); - pthread_mutex_unlock (&self->d_jack_process_lock); - } -#endif - - return 0; -} - -// ---------------------------------------------------------------- - -audio_jack_sink::audio_jack_sink (int sampling_rate, - const std::string device_name, - bool ok_to_block) - : gr_sync_block ("audio_jack_sink", - gr_make_io_signature (0, 0, 0), - gr_make_io_signature (0, 0, 0)), - d_sampling_rate (sampling_rate), - d_device_name (device_name.empty() ? default_device_name() : device_name), - d_ok_to_block (ok_to_block), - d_jack_client (0), - d_ringbuffer (0), - d_nunderuns (0) -{ -#ifndef NO_PTHREAD - pthread_cond_init(&d_ringbuffer_ready, NULL);; - pthread_mutex_init(&d_jack_process_lock, NULL); -#endif - - // try to become a client of the JACK server - jack_options_t options = JackNullOption; - jack_status_t status; - const char *server_name = NULL; - if ((d_jack_client = jack_client_open (d_device_name.c_str (), - options, &status, - server_name)) == NULL) { - fprintf (stderr, "audio_jack_sink[%s]: jack server not running?\n", - d_device_name.c_str()); - throw std::runtime_error ("audio_jack_sink"); - } - - // tell the JACK server to call `jack_sink_process()' whenever - // there is work to be done. - jack_set_process_callback (d_jack_client, &jack_sink_process, (void*)this); - - // tell the JACK server to call `jack_shutdown()' if - // it ever shuts down, either entirely, or if it - // just decides to stop calling us. - - //jack_on_shutdown (d_jack_client, &jack_shutdown, (void*)this); - - d_jack_output_port = - jack_port_register (d_jack_client, "out", - JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - - - d_jack_buffer_size = jack_get_buffer_size (d_jack_client); - - set_output_multiple (d_jack_buffer_size); - - d_ringbuffer = - jack_ringbuffer_create (N_BUFFERS*d_jack_buffer_size*sizeof(sample_t)); - if (d_ringbuffer == NULL) - bail ("jack_ringbuffer_create failed", 0); - - assert(sizeof(float)==sizeof(sample_t)); - set_input_signature (gr_make_io_signature (1, 1, sizeof (sample_t))); - - - jack_nframes_t sample_rate = jack_get_sample_rate (d_jack_client); - - if ((jack_nframes_t)sampling_rate != sample_rate){ - fprintf (stderr, "audio_jack_sink[%s]: unable to support sampling rate %d\n", - d_device_name.c_str (), sampling_rate); - fprintf (stderr, " card requested %d instead.\n", sample_rate); - } -} - - -bool -audio_jack_sink::check_topology (int ninputs, int noutputs) -{ - if (ninputs != 1) - return false; - - // tell the JACK server that we are ready to roll - if (jack_activate (d_jack_client)) - throw std::runtime_error ("audio_jack_sink"); - - return true; -} - -audio_jack_sink::~audio_jack_sink () -{ - jack_client_close (d_jack_client); - jack_ringbuffer_free (d_ringbuffer); -} - -int -audio_jack_sink::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - // write_size and work_size are in bytes - int work_size = noutput_items*sizeof(sample_t); - unsigned int write_size; - - while (work_size > 0) { - unsigned int write_space; // bytes - -#ifdef NO_PTHREAD - while ((write_space=jack_ringbuffer_write_space (d_ringbuffer)) < - d_jack_buffer_size*sizeof(sample_t)) { - usleep(1000000*((d_jack_buffer_size-write_space/sizeof(sample_t))/d_sampling_rate)); - } -#else - // JACK actually requires POSIX - - pthread_mutex_lock (&d_jack_process_lock); - while ((write_space=jack_ringbuffer_write_space (d_ringbuffer)) < - d_jack_buffer_size*sizeof(sample_t)) { - - // wait until jack_sink_process() signals more room - pthread_cond_wait (&d_ringbuffer_ready, &d_jack_process_lock); - } - pthread_mutex_unlock (&d_jack_process_lock); -#endif - - write_space -= write_space%(d_jack_buffer_size*sizeof(sample_t)); - write_size = std::min(write_space, (unsigned int)work_size); - - if (jack_ringbuffer_write (d_ringbuffer, (char *) input_items[0], - write_size) < write_size) { - bail ("jack_ringbuffer_write failed", 0); - } - work_size -= write_size; - } - - return noutput_items; -} - -void -audio_jack_sink::output_error_msg (const char *msg, int err) -{ - fprintf (stderr, "audio_jack_sink[%s]: %s: %d\n", - d_device_name.c_str (), msg, err); -} - -void -audio_jack_sink::bail (const char *msg, int err) throw (std::runtime_error) -{ - output_error_msg (msg, err); - throw std::runtime_error ("audio_jack_sink"); -} diff --git a/gr-audio/lib/jack/audio_jack_sink.h b/gr-audio/lib/jack/audio_jack_sink.h deleted file mode 100644 index 8cc343937..000000000 --- a/gr-audio/lib/jack/audio_jack_sink.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ -#ifndef INCLUDED_AUDIO_JACK_SINK_H -#define INCLUDED_AUDIO_JACK_SINK_H - -#include <gr_audio_sink.h> -#include <string> -#include <jack/jack.h> -#include <jack/ringbuffer.h> -#include <stdexcept> - -int jack_sink_process (jack_nframes_t nframes, void *arg); - -/*! - * \brief audio sink using JACK - * \ingroup audio_blk - * - * The sink has one input stream of floats. - * - * Input samples must be in the range [-1,1]. - */ -class audio_jack_sink : public audio_sink { - - friend int jack_sink_process (jack_nframes_t nframes, void *arg); - - // typedef for pointer to class work method - typedef int (audio_jack_sink::*work_t)(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - - unsigned int d_sampling_rate; - std::string d_device_name; - bool d_ok_to_block; - - jack_client_t *d_jack_client; - jack_port_t *d_jack_output_port; - jack_ringbuffer_t *d_ringbuffer; - jack_nframes_t d_jack_buffer_size; - pthread_cond_t d_ringbuffer_ready; - pthread_mutex_t d_jack_process_lock; - - // random stats - int d_nunderuns; // count of underruns - - void output_error_msg (const char *msg, int err); - void bail (const char *msg, int err) throw (std::runtime_error); - - -public: - audio_jack_sink (int sampling_rate, const std::string device_name, bool ok_to_block); - - ~audio_jack_sink (); - - bool check_topology (int ninputs, int noutputs); - - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); -}; - -#endif /* INCLUDED_AUDIO_JACK_SINK_H */ diff --git a/gr-audio/lib/jack/audio_jack_source.cc b/gr-audio/lib/jack/audio_jack_source.cc deleted file mode 100644 index 137fd538e..000000000 --- a/gr-audio/lib/jack/audio_jack_source.cc +++ /dev/null @@ -1,237 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005,2006,2010 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gr_audio_registry.h" -#include <audio_jack_source.h> -#include <gr_io_signature.h> -#include <gr_prefs.h> -#include <stdio.h> -#include <iostream> -#include <stdexcept> -#include <gri_jack.h> - -#ifndef NO_PTHREAD -#include <pthread.h> -#endif - -AUDIO_REGISTER_SOURCE(REG_PRIO_MED, jack)( - int sampling_rate, const std::string &device_name, bool ok_to_block -){ - return audio_source::sptr(new audio_jack_source(sampling_rate, device_name, ok_to_block)); -} - -typedef jack_default_audio_sample_t sample_t; - - -// Number of jack buffers in the ringbuffer -// TODO: make it to match at least the quantity of items passed to work() -static const unsigned int N_BUFFERS = 16; - -static std::string -default_device_name () -{ - return gr_prefs::singleton()->get_string("audio_jack", "default_input_device", "gr_source"); -} - - -int -jack_source_process (jack_nframes_t nframes, void *arg) -{ - audio_jack_source *self = (audio_jack_source *)arg; - unsigned int write_size = nframes*sizeof(sample_t); - - if (jack_ringbuffer_write_space (self->d_ringbuffer) < write_size) { - self->d_noverruns++; - // FIXME: move this fputs out, we shouldn't use blocking calls in process() - fputs ("jO", stderr); - return 0; - } - - char *buffer = (char *) jack_port_get_buffer (self->d_jack_input_port, nframes); - - jack_ringbuffer_write (self->d_ringbuffer, buffer, write_size); - -#ifndef NO_PTHREAD - // Tell the source thread there is data in the ringbuffer. - // If it is already running, the lock will not be available. - // We can't wait here in the process() thread, but we don't - // need to signal in that case, because the source thread will - // check for data availability. - - if (pthread_mutex_trylock (&self->d_jack_process_lock) == 0) { - pthread_cond_signal (&self->d_ringbuffer_ready); - pthread_mutex_unlock (&self->d_jack_process_lock); - } -#endif - - return 0; -} - -// ---------------------------------------------------------------- - -audio_jack_source::audio_jack_source (int sampling_rate, - const std::string device_name, - bool ok_to_block) - : gr_sync_block ("audio_jack_source", - gr_make_io_signature (0, 0, 0), - gr_make_io_signature (0, 0, 0)), - d_sampling_rate (sampling_rate), - d_device_name (device_name.empty() ? default_device_name() : device_name), - d_ok_to_block(ok_to_block), - d_jack_client (0), - d_ringbuffer (0), - d_noverruns (0) -{ -#ifndef NO_PTHREAD - pthread_cond_init(&d_ringbuffer_ready, NULL);; - pthread_mutex_init(&d_jack_process_lock, NULL); -#endif - - // try to become a client of the JACK server - jack_options_t options = JackNullOption; - jack_status_t status; - const char *server_name = NULL; - if ((d_jack_client = jack_client_open (d_device_name.c_str (), - options, &status, - server_name)) == NULL) { - fprintf (stderr, "audio_jack_source[%s]: jack server not running?\n", - d_device_name.c_str()); - throw std::runtime_error ("audio_jack_source"); - } - - // tell the JACK server to call `jack_source_process()' whenever - // there is work to be done. - jack_set_process_callback (d_jack_client, &jack_source_process, (void*)this); - - // tell the JACK server to call `jack_shutdown()' if - // it ever shuts down, either entirely, or if it - // just decides to stop calling us. - - //jack_on_shutdown (d_jack_client, &jack_shutdown, (void*)this); - - d_jack_input_port = jack_port_register (d_jack_client, "in", - JACK_DEFAULT_AUDIO_TYPE, - JackPortIsInput, 0); - - - d_jack_buffer_size = jack_get_buffer_size (d_jack_client); - - set_output_multiple (d_jack_buffer_size); - - d_ringbuffer = jack_ringbuffer_create (N_BUFFERS*d_jack_buffer_size*sizeof(sample_t)); - if (d_ringbuffer == NULL) - bail ("jack_ringbuffer_create failed", 0); - - assert(sizeof(float)==sizeof(sample_t)); - set_output_signature (gr_make_io_signature (1, 1, sizeof (sample_t))); - - - jack_nframes_t sample_rate = jack_get_sample_rate (d_jack_client); - - if ((jack_nframes_t)sampling_rate != sample_rate){ - fprintf (stderr, "audio_jack_source[%s]: unable to support sampling rate %d\n", - d_device_name.c_str (), sampling_rate); - fprintf (stderr, " card requested %d instead.\n", sample_rate); - } -} - - -bool -audio_jack_source::check_topology (int ninputs, int noutputs) -{ - // tell the JACK server that we are ready to roll - if (jack_activate (d_jack_client)) - throw std::runtime_error ("audio_jack_source"); - - return true; -} - -audio_jack_source::~audio_jack_source () -{ - jack_client_close (d_jack_client); - jack_ringbuffer_free (d_ringbuffer); -} - -int -audio_jack_source::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - // read_size and work_size are in bytes - unsigned int read_size; - - // Minimize latency - noutput_items = std::min (noutput_items, (int)d_jack_buffer_size); - - int work_size = noutput_items*sizeof(sample_t); - - while (work_size > 0) { - unsigned int read_space; // bytes - -#ifdef NO_PTHREAD - while ((read_space=jack_ringbuffer_read_space (d_ringbuffer)) < - d_jack_buffer_size*sizeof(sample_t)) { - usleep(1000000*((d_jack_buffer_size-read_space/sizeof(sample_t))/d_sampling_rate)); - } -#else - // JACK actually requires POSIX - - pthread_mutex_lock (&d_jack_process_lock); - while ((read_space=jack_ringbuffer_read_space (d_ringbuffer)) < - d_jack_buffer_size*sizeof(sample_t)) { - - // wait until jack_source_process() signals more data - pthread_cond_wait (&d_ringbuffer_ready, &d_jack_process_lock); - } - pthread_mutex_unlock (&d_jack_process_lock); -#endif - - read_space -= read_space%(d_jack_buffer_size*sizeof(sample_t)); - read_size = std::min(read_space, (unsigned int)work_size); - - if (jack_ringbuffer_read (d_ringbuffer, (char *) output_items[0], - read_size) < read_size) { - bail ("jack_ringbuffer_read failed", 0); - } - work_size -= read_size; - } - - return noutput_items; -} - -void -audio_jack_source::output_error_msg (const char *msg, int err) -{ - fprintf (stderr, "audio_jack_source[%s]: %s: %d\n", - d_device_name.c_str (), msg, err); -} - -void -audio_jack_source::bail (const char *msg, int err) throw (std::runtime_error) -{ - output_error_msg (msg, err); - throw std::runtime_error ("audio_jack_source"); -} diff --git a/gr-audio/lib/jack/audio_jack_source.h b/gr-audio/lib/jack/audio_jack_source.h deleted file mode 100644 index 2849c84b0..000000000 --- a/gr-audio/lib/jack/audio_jack_source.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ -#ifndef INCLUDED_AUDIO_JACK_SOURCE_H -#define INCLUDED_AUDIO_JACK_SOURCE_H - -#include <gr_audio_source.h> -#include <string> -#include <jack/jack.h> -#include <jack/ringbuffer.h> -#include <stdexcept> - -int jack_source_process (jack_nframes_t nframes, void *arg); - -/*! - * \brief audio source using JACK - * \ingroup audio_blk - * - * The source has one input stream of floats. - * - * Output samples will be in the range [-1,1]. - */ -class audio_jack_source : public audio_source { - - friend int jack_source_process (jack_nframes_t nframes, void *arg); - - // typedef for pointer to class work method - typedef int (audio_jack_source::*work_t)(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - - unsigned int d_sampling_rate; - std::string d_device_name; - bool d_ok_to_block; - - jack_client_t *d_jack_client; - jack_port_t *d_jack_input_port; - jack_ringbuffer_t *d_ringbuffer; - jack_nframes_t d_jack_buffer_size; - pthread_cond_t d_ringbuffer_ready; - pthread_mutex_t d_jack_process_lock; - - // random stats - int d_noverruns; // count of overruns - - void output_error_msg (const char *msg, int err); - void bail (const char *msg, int err) throw (std::runtime_error); - - -public: - audio_jack_source (int sampling_rate, const std::string device_name, bool ok_to_block); - - ~audio_jack_source (); - - bool check_topology (int ninputs, int noutputs); - - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); -}; - -#endif /* INCLUDED_AUDIO_JACK_SOURCE_H */ diff --git a/gr-audio/lib/jack/gr-audio-jack.conf b/gr-audio/lib/jack/gr-audio-jack.conf deleted file mode 100644 index bdbc1fd1d..000000000 --- a/gr-audio/lib/jack/gr-audio-jack.conf +++ /dev/null @@ -1,8 +0,0 @@ -# This file contains system wide configuration data for GNU Radio. -# You may override any setting on a per-user basis by editing -# ~/.gnuradio/config.conf - -[audio_jack] - -default_input_device = gr_source -default_output_device = gr_sink diff --git a/gr-audio/lib/jack/gri_jack.cc b/gr-audio/lib/jack/gri_jack.cc deleted file mode 100644 index 793ed8336..000000000 --- a/gr-audio/lib/jack/gri_jack.cc +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gri_jack.h> -#include <algorithm> - - diff --git a/gr-audio/lib/jack/gri_jack.h b/gr-audio/lib/jack/gri_jack.h deleted file mode 100644 index 5dcd3b811..000000000 --- a/gr-audio/lib/jack/gri_jack.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_GRI_JACK_H -#define INCLUDED_GRI_JACK_H - -#include <stdio.h> - -#endif /* INCLUDED_GRI_JACK_H */ diff --git a/gr-audio/lib/oss/audio_oss_sink.cc b/gr-audio/lib/oss/audio_oss_sink.cc deleted file mode 100644 index 26b71be24..000000000 --- a/gr-audio/lib/oss/audio_oss_sink.cc +++ /dev/null @@ -1,161 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gr_audio_registry.h" -#include <audio_oss_sink.h> -#include <gr_io_signature.h> -#include <gr_prefs.h> -#include <sys/soundcard.h> -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdio.h> -#include <iostream> -#include <stdexcept> - -AUDIO_REGISTER_SINK(REG_PRIO_LOW, oss)( - int sampling_rate, const std::string &device_name, bool ok_to_block -){ - return audio_sink::sptr(new audio_oss_sink(sampling_rate, device_name, ok_to_block)); -} - -static std::string -default_device_name () -{ - return gr_prefs::singleton()->get_string("audio_oss", "default_output_device", "/dev/dsp"); -} - -audio_oss_sink::audio_oss_sink (int sampling_rate, - const std::string device_name, - bool ok_to_block) - : gr_sync_block ("audio_oss_sink", - gr_make_io_signature (1, 2, sizeof (float)), - gr_make_io_signature (0, 0, 0)), - d_sampling_rate (sampling_rate), - d_device_name (device_name.empty() ? default_device_name() : device_name), - d_fd (-1), d_buffer (0), d_chunk_size (0) -{ - if ((d_fd = open (d_device_name.c_str (), O_WRONLY)) < 0){ - fprintf (stderr, "audio_oss_sink: "); - perror (d_device_name.c_str ()); - throw std::runtime_error ("audio_oss_sink"); - } - - double CHUNK_TIME = - std::max(0.001, gr_prefs::singleton()->get_double("audio_oss", "latency", 0.005)); - - d_chunk_size = (int) (d_sampling_rate * CHUNK_TIME); - set_output_multiple (d_chunk_size); - - d_buffer = new short [d_chunk_size * 2]; - - int format = AFMT_S16_NE; - int orig_format = format; - if (ioctl (d_fd, SNDCTL_DSP_SETFMT, &format) < 0){ - std::cerr << "audio_oss_sink: " << d_device_name << " ioctl failed\n"; - perror (d_device_name.c_str ()); - throw std::runtime_error ("audio_oss_sink"); - } - - if (format != orig_format){ - fprintf (stderr, "audio_oss_sink: unable to support format %d\n", orig_format); - fprintf (stderr, " card requested %d instead.\n", format); - } - - // set to stereo no matter what. Some hardware only does stereo - int channels = 2; - if (ioctl (d_fd, SNDCTL_DSP_CHANNELS, &channels) < 0 || channels != 2){ - perror ("audio_oss_sink: could not set STEREO mode"); - throw std::runtime_error ("audio_oss_sink"); - } - - // set sampling freq - int sf = sampling_rate; - if (ioctl (d_fd, SNDCTL_DSP_SPEED, &sf) < 0){ - std::cerr << "audio_oss_sink: " - << d_device_name << ": invalid sampling_rate " - << sampling_rate << "\n"; - sampling_rate = 8000; - if (ioctl (d_fd, SNDCTL_DSP_SPEED, &sf) < 0){ - std::cerr << "audio_oss_sink: failed to set sampling_rate to 8000\n"; - throw std::runtime_error ("audio_oss_sink"); - } - } -} - -audio_oss_sink::~audio_oss_sink () -{ - close (d_fd); - delete [] d_buffer; -} - - -int -audio_oss_sink::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const float *f0, *f1; - - switch (input_items.size ()){ - - case 1: // mono input - - f0 = (const float *) input_items[0]; - - for (int i = 0; i < noutput_items; i += d_chunk_size){ - for (int j = 0; j < d_chunk_size; j++){ - d_buffer[2*j+0] = (short) (f0[j] * 32767); - d_buffer[2*j+1] = (short) (f0[j] * 32767); - } - f0 += d_chunk_size; - if (write (d_fd, d_buffer, 2 * d_chunk_size * sizeof (short)) < 0) - perror ("audio_oss_sink: write"); - } - break; - - case 2: // stereo input - - f0 = (const float *) input_items[0]; - f1 = (const float *) input_items[1]; - - for (int i = 0; i < noutput_items; i += d_chunk_size){ - for (int j = 0; j < d_chunk_size; j++){ - d_buffer[2*j+0] = (short) (f0[j] * 32767); - d_buffer[2*j+1] = (short) (f1[j] * 32767); - } - f0 += d_chunk_size; - f1 += d_chunk_size; - if (write (d_fd, d_buffer, 2 * d_chunk_size * sizeof (short)) < 0) - perror ("audio_oss_sink: write"); - } - break; - } - - return noutput_items; -} diff --git a/gr-audio/lib/oss/audio_oss_sink.h b/gr-audio/lib/oss/audio_oss_sink.h deleted file mode 100644 index 8148ec34b..000000000 --- a/gr-audio/lib/oss/audio_oss_sink.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_AUDIO_OSS_SINK_H -#define INCLUDED_AUDIO_OSS_SINK_H - -#include <gr_audio_sink.h> -#include <string> - -/*! - * \brief audio sink using OSS - * \ingroup audio_blk - * - * input signature is one or two streams of floats. - * Input samples must be in the range [-1,1]. - */ - -class audio_oss_sink : public audio_sink { - - int d_sampling_rate; - std::string d_device_name; - int d_fd; - short *d_buffer; - int d_chunk_size; - -public: - audio_oss_sink (int sampling_rate, const std::string device_name = "", bool ok_to_block = true); - - ~audio_oss_sink (); - - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); -}; - -#endif /* INCLUDED_AUDIO_OSS_SINK_H */ diff --git a/gr-audio/lib/oss/audio_oss_source.cc b/gr-audio/lib/oss/audio_oss_source.cc deleted file mode 100644 index e186e30ae..000000000 --- a/gr-audio/lib/oss/audio_oss_source.cc +++ /dev/null @@ -1,177 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gr_audio_registry.h" -#include <audio_oss_source.h> -#include <gr_io_signature.h> -#include <gr_prefs.h> -#include <sys/soundcard.h> -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdio.h> -#include <iostream> -#include <stdexcept> - -AUDIO_REGISTER_SOURCE(REG_PRIO_LOW, oss)( - int sampling_rate, const std::string &device_name, bool ok_to_block -){ - return audio_source::sptr(new audio_oss_source(sampling_rate, device_name, ok_to_block)); -} - -static std::string -default_device_name () -{ - return gr_prefs::singleton()->get_string("audio_oss", "default_input_device", "/dev/dsp"); -} - -audio_oss_source::audio_oss_source (int sampling_rate, - const std::string device_name, - bool ok_to_block) - : gr_sync_block ("audio_oss_source", - gr_make_io_signature (0, 0, 0), - gr_make_io_signature (1, 2, sizeof (float))), - d_sampling_rate (sampling_rate), - d_device_name (device_name.empty() ? default_device_name() : device_name), - d_fd (-1), d_buffer (0), d_chunk_size (0) -{ - if ((d_fd = open (d_device_name.c_str (), O_RDONLY)) < 0){ - fprintf (stderr, "audio_oss_source: "); - perror (d_device_name.c_str ()); - throw std::runtime_error ("audio_oss_source"); - } - - double CHUNK_TIME = - std::max(0.001, gr_prefs::singleton()->get_double("audio_oss", "latency", 0.005)); - - d_chunk_size = (int) (d_sampling_rate * CHUNK_TIME); - set_output_multiple (d_chunk_size); - - d_buffer = new short [d_chunk_size * 2]; - - int format = AFMT_S16_NE; - int orig_format = format; - if (ioctl (d_fd, SNDCTL_DSP_SETFMT, &format) < 0){ - std::cerr << "audio_oss_source: " << d_device_name << " ioctl failed\n"; - perror (d_device_name.c_str ()); - throw std::runtime_error ("audio_oss_source"); - } - - if (format != orig_format){ - fprintf (stderr, "audio_oss_source: unable to support format %d\n", orig_format); - fprintf (stderr, " card requested %d instead.\n", format); - } - - // set to stereo no matter what. Some hardware only does stereo - int channels = 2; - if (ioctl (d_fd, SNDCTL_DSP_CHANNELS, &channels) < 0 || channels != 2){ - perror ("audio_oss_source: could not set STEREO mode"); - throw std::runtime_error ("audio_oss_source"); - } - - // set sampling freq - int sf = sampling_rate; - if (ioctl (d_fd, SNDCTL_DSP_SPEED, &sf) < 0){ - std::cerr << "audio_oss_source: " - << d_device_name << ": invalid sampling_rate " - << sampling_rate << "\n"; - sampling_rate = 8000; - if (ioctl (d_fd, SNDCTL_DSP_SPEED, &sf) < 0){ - std::cerr << "audio_oss_source: failed to set sampling_rate to 8000\n"; - throw std::runtime_error ("audio_oss_source"); - } - } -} - -audio_oss_source::~audio_oss_source () -{ - close (d_fd); - delete [] d_buffer; -} - -int -audio_oss_source::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - float *f0 = (float *) output_items[0]; - float *f1 = (float *) output_items[1]; // will be invalid if this is mono output - - const int shorts_per_item = 2; // L + R - const int bytes_per_item = shorts_per_item * sizeof (short); - - // To minimize latency, never return more than CHUNK_TIME - // worth of samples per call to work. - - noutput_items = std::min (noutput_items, d_chunk_size); - - int base = 0; - int ntogo = noutput_items; - - while (ntogo > 0){ - int nbytes = std::min (ntogo, d_chunk_size) * bytes_per_item; - int result_nbytes = read (d_fd, d_buffer, nbytes); - - if (result_nbytes < 0){ - perror ("audio_oss_source"); - return -1; // say we're done - } - - if ((result_nbytes & (bytes_per_item - 1)) != 0){ - fprintf (stderr, "audio_oss_source: internal error.\n"); - throw std::runtime_error ("internal error"); - } - - int result_nitems = result_nbytes / bytes_per_item; - - // now unpack samples into output streams - - switch (output_items.size ()){ - case 1: // mono output - for (int i = 0; i < result_nitems; i++){ - f0[base+i] = d_buffer[2*i+0] * (1.0 / 32767); - } - break; - - case 2: // stereo output - for (int i = 0; i < result_nitems; i++){ - f0[base+i] = d_buffer[2*i+0] * (1.0 / 32767); - f1[base+i] = d_buffer[2*i+1] * (1.0 / 32767); - } - break; - - default: - assert (0); - } - - ntogo -= result_nitems; - base += result_nitems; - } - - return noutput_items - ntogo; -} diff --git a/gr-audio/lib/oss/audio_oss_source.h b/gr-audio/lib/oss/audio_oss_source.h deleted file mode 100644 index abb2db1f8..000000000 --- a/gr-audio/lib/oss/audio_oss_source.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_AUDIO_OSS_SOURCE_H -#define INCLUDED_AUDIO_OSS_SOURCE_H - -#include <gr_audio_source.h> -#include <string> - -/*! - * \brief audio source using OSS - * \ingroup audio_blk - * - * Output signature is one or two streams of floats. - * Output samples will be in the range [-1,1]. - */ - -class audio_oss_source : public audio_source { - - int d_sampling_rate; - std::string d_device_name; - int d_fd; - short *d_buffer; - int d_chunk_size; - -public: - audio_oss_source (int sampling_rate, - const std::string device_name = "", - bool ok_to_block = true); - - ~audio_oss_source (); - - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); -}; - - - -#endif /* INCLUDED_AUDIO_OSS_SOURCE_H */ diff --git a/gr-audio/lib/oss/gr-audio-oss.conf b/gr-audio/lib/oss/gr-audio-oss.conf deleted file mode 100644 index 6ea14d67e..000000000 --- a/gr-audio/lib/oss/gr-audio-oss.conf +++ /dev/null @@ -1,9 +0,0 @@ -# This file contains system wide configuration data for GNU Radio. -# You may override any setting on a per-user basis by editing -# ~/.gnuradio/config.conf - -[audio_oss] - -default_input_device = /dev/dsp -default_output_device = /dev/dsp -latency = 0.005 # in seconds diff --git a/gr-audio/lib/osx/audio_osx.h b/gr-audio/lib/osx/audio_osx.h deleted file mode 100644 index 8c9543d0d..000000000 --- a/gr-audio/lib/osx/audio_osx.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio. - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_AUDIO_OSX_H -#define INCLUDED_AUDIO_OSX_H - -#include <iostream> -#include <string.h> - -#define CheckErrorAndThrow(err,what,throw_str) \ - if (err) { \ - OSStatus error = static_cast<OSStatus>(err); \ - char err_str[4]; \ - strncpy (err_str, (char*)(&err), 4); \ - std::cerr << what << std::endl; \ - std::cerr << " Error# " << error << " ('" << err_str \ - << "')" << std::endl; \ - std::cerr << " " << __FILE__ << ":" << __LINE__ << std::endl; \ - fflush (stderr); \ - throw std::runtime_error (throw_str); \ - } - -#define CheckError(err,what) \ - if (err) { \ - OSStatus error = static_cast<OSStatus>(err); \ - char err_str[4]; \ - strncpy (err_str, (char*)(&err), 4); \ - std::cerr << what << std::endl; \ - std::cerr << " Error# " << error << " ('" << err_str \ - << "')" << std::endl; \ - std::cerr << " " << __FILE__ << ":" << __LINE__ << std::endl; \ - fflush (stderr); \ - } - -#include <boost/detail/endian.hpp> //BOOST_BIG_ENDIAN -#ifdef BOOST_BIG_ENDIAN -#define GR_PCM_ENDIANNESS kLinearPCMFormatFlagIsBigEndian -#else -#define GR_PCM_ENDIANNESS 0 -#endif - -// Check the version of MacOSX being used -#ifdef __APPLE_CC__ -#include <AvailabilityMacros.h> -#ifndef MAC_OS_X_VERSION_10_6 -#define MAC_OS_X_VERSION_10_6 1060 -#endif -#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 -#define GR_USE_OLD_AUDIO_UNIT -#endif -#endif - -#endif /* INCLUDED_AUDIO_OSX_H */ diff --git a/gr-audio/lib/osx/audio_osx_sink.cc b/gr-audio/lib/osx/audio_osx_sink.cc deleted file mode 100644 index 939e5e0a1..000000000 --- a/gr-audio/lib/osx/audio_osx_sink.cc +++ /dev/null @@ -1,404 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio. - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gr_audio_registry.h" -#include <audio_osx_sink.h> -#include <gr_io_signature.h> -#include <stdexcept> -#include <audio_osx.h> - -#define _OSX_AU_DEBUG_ 0 - -AUDIO_REGISTER_SINK(REG_PRIO_HIGH, osx)( - int sampling_rate, const std::string &device_name, bool ok_to_block -){ - return audio_sink::sptr(new audio_osx_sink(sampling_rate, device_name, ok_to_block)); -} - -audio_osx_sink::audio_osx_sink (int sample_rate, - const std::string device_name, - bool do_block, - int channel_config, - int max_sample_count) - : gr_sync_block ("audio_osx_sink", - gr_make_io_signature (0, 0, 0), - gr_make_io_signature (0, 0, 0)), - d_sample_rate (0.0), d_channel_config (0), d_n_channels (0), - d_queueSampleCount (0), d_max_sample_count (0), - d_do_block (do_block), d_internal (0), d_cond_data (0), - d_OutputAU (0) -{ - if (sample_rate <= 0) { - std::cerr << "Invalid Sample Rate: " << sample_rate << std::endl; - throw std::invalid_argument ("audio_osx_sink::audio_osx_sink"); - } else - d_sample_rate = (Float64) sample_rate; - - if (channel_config <= 0 & channel_config != -1) { - std::cerr << "Invalid Channel Config: " << channel_config << std::endl; - throw std::invalid_argument ("audio_osx_sink::audio_osx_sink"); - } else if (channel_config == -1) { -// no user input; try "device name" instead - int l_n_channels = (int) strtol (device_name.data(), (char **)NULL, 10); - if (l_n_channels == 0 & errno) { - std::cerr << "Error Converting Device Name: " << errno << std::endl; - throw std::invalid_argument ("audio_osx_sink::audio_osx_sink"); - } - if (l_n_channels <= 0) - channel_config = 2; - else - channel_config = l_n_channels; - } - - d_n_channels = d_channel_config = channel_config; - -// set the input signature - - set_input_signature (gr_make_io_signature (1, d_n_channels, sizeof (float))); - -// check that the max # of samples to store is valid - - if (max_sample_count == -1) - max_sample_count = sample_rate; - else if (max_sample_count <= 0) { - std::cerr << "Invalid Max Sample Count: " << max_sample_count << std::endl; - throw std::invalid_argument ("audio_osx_sink::audio_osx_sink"); - } - - d_max_sample_count = max_sample_count; - -// allocate the output circular buffer(s), one per channel - - d_buffers = (circular_buffer<float>**) new - circular_buffer<float>* [d_n_channels]; - UInt32 n_alloc = (UInt32) ceil ((double) d_max_sample_count); - for (UInt32 n = 0; n < d_n_channels; n++) { - d_buffers[n] = new circular_buffer<float> (n_alloc, false, false); - } - -// create the default AudioUnit for output - OSStatus err = noErr; - -// Open the default output unit -#ifndef GR_USE_OLD_AUDIO_UNIT - AudioComponentDescription desc; -#else - ComponentDescription desc; -#endif - - desc.componentType = kAudioUnitType_Output; - desc.componentSubType = kAudioUnitSubType_DefaultOutput; - desc.componentManufacturer = kAudioUnitManufacturer_Apple; - desc.componentFlags = 0; - desc.componentFlagsMask = 0; - -#ifndef GR_USE_OLD_AUDIO_UNIT - AudioComponent comp = AudioComponentFindNext(NULL, &desc); - if (comp == NULL) { - std::cerr << "AudioComponentFindNext Error" << std::endl; - throw std::runtime_error ("audio_osx_sink::audio_osx_sink"); - } -#else - Component comp = FindNextComponent (NULL, &desc); - if (comp == NULL) { - std::cerr << "FindNextComponent Error" << std::endl; - throw std::runtime_error ("audio_osx_sink::audio_osx_sink"); - } -#endif - -#ifndef GR_USE_OLD_AUDIO_UNIT - err = AudioComponentInstanceNew (comp, &d_OutputAU); - CheckErrorAndThrow (err, "AudioComponentInstanceNew", "audio_osx_sink::audio_osx_sink"); -#else - err = OpenAComponent (comp, &d_OutputAU); - CheckErrorAndThrow (err, "OpenAComponent", "audio_osx_sink::audio_osx_sink"); -#endif - -// Set up a callback function to generate output to the output unit - - AURenderCallbackStruct input; - input.inputProc = (AURenderCallback)(audio_osx_sink::AUOutputCallback); - input.inputProcRefCon = this; - - err = AudioUnitSetProperty (d_OutputAU, - kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, - 0, - &input, - sizeof (input)); - CheckErrorAndThrow (err, "AudioUnitSetProperty Render Callback", "audio_osx_sink::audio_osx_sink"); - -// tell the Output Unit what format data will be supplied to it -// so that it handles any format conversions - - AudioStreamBasicDescription streamFormat; - streamFormat.mSampleRate = (Float64)(sample_rate); - streamFormat.mFormatID = kAudioFormatLinearPCM; - streamFormat.mFormatFlags = (kLinearPCMFormatFlagIsFloat | - GR_PCM_ENDIANNESS | - kLinearPCMFormatFlagIsPacked | - kAudioFormatFlagIsNonInterleaved); - streamFormat.mBytesPerPacket = 4; - streamFormat.mFramesPerPacket = 1; - streamFormat.mBytesPerFrame = 4; - streamFormat.mChannelsPerFrame = d_n_channels; - streamFormat.mBitsPerChannel = 32; - - err = AudioUnitSetProperty (d_OutputAU, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, - 0, - &streamFormat, - sizeof (AudioStreamBasicDescription)); - CheckErrorAndThrow (err, "AudioUnitSetProperty StreamFormat", "audio_osx_sink::audio_osx_sink"); - -// create the stuff to regulate I/O - - d_cond_data = new gruel::condition_variable (); - if (d_cond_data == NULL) - CheckErrorAndThrow (errno, "new condition (data)", - "audio_osx_sink::audio_osx_sink"); - - d_internal = new gruel::mutex (); - if (d_internal == NULL) - CheckErrorAndThrow (errno, "new mutex (internal)", - "audio_osx_sink::audio_osx_sink"); - -// initialize the AU for output - - err = AudioUnitInitialize (d_OutputAU); - CheckErrorAndThrow (err, "AudioUnitInitialize", - "audio_osx_sink::audio_osx_sink"); - -#if _OSX_AU_DEBUG_ - std::cerr << "audio_osx_sink Parameters:" << std::endl; - std::cerr << " Sample Rate is " << d_sample_rate << std::endl; - std::cerr << " Number of Channels is " << d_n_channels << std::endl; - std::cerr << " Max # samples to store per channel is " << d_max_sample_count << std::endl; -#endif -} - -bool audio_osx_sink::IsRunning () -{ - UInt32 AURunning = 0, AUSize = sizeof (UInt32); - - OSStatus err = AudioUnitGetProperty (d_OutputAU, - kAudioOutputUnitProperty_IsRunning, - kAudioUnitScope_Global, - 0, - &AURunning, - &AUSize); - CheckErrorAndThrow (err, "AudioUnitGetProperty IsRunning", - "audio_osx_sink::IsRunning"); - - return (AURunning); -} - -bool audio_osx_sink::start () -{ - if (! IsRunning ()) { - OSStatus err = AudioOutputUnitStart (d_OutputAU); - CheckErrorAndThrow (err, "AudioOutputUnitStart", "audio_osx_sink::start"); - } - - return (true); -} - -bool audio_osx_sink::stop () -{ - if (IsRunning ()) { - OSStatus err = AudioOutputUnitStop (d_OutputAU); - CheckErrorAndThrow (err, "AudioOutputUnitStop", "audio_osx_sink::stop"); - - for (UInt32 n = 0; n < d_n_channels; n++) { - d_buffers[n]->abort (); - } - } - - return (true); -} - -audio_osx_sink::~audio_osx_sink () -{ -// stop and close the AudioUnit - stop (); - AudioUnitUninitialize (d_OutputAU); -#ifndef GR_USE_OLD_AUDIO_UNIT - AudioComponentInstanceDispose (d_OutputAU); -#else - CloseComponent (d_OutputAU); -#endif - -// empty and delete the queues - for (UInt32 n = 0; n < d_n_channels; n++) { - delete d_buffers[n]; - d_buffers[n] = 0; - } - delete [] d_buffers; - d_buffers = 0; - -// close and delete control stuff - delete d_cond_data; - d_cond_data = 0; - delete d_internal; - d_internal = 0; -} - -int -audio_osx_sink::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - gruel::scoped_lock l (*d_internal); - - /* take the input data, copy it, and push it to the bottom of the queue - mono input are pushed onto queue[0]; - stereo input are pushed onto queue[1]. - Start the AudioUnit if necessary. */ - - UInt32 l_max_count; - int diff_count = d_max_sample_count - noutput_items; - if (diff_count < 0) - l_max_count = 0; - else - l_max_count = (UInt32) diff_count; - -#if 0 - if (l_max_count < d_queueItemLength->back()) { -// allow 2 buffers at a time, regardless of length - l_max_count = d_queueItemLength->back(); - } -#endif - -#if _OSX_AU_DEBUG_ - std::cerr << "work1: qSC = " << d_queueSampleCount << ", lMC = "<< l_max_count - << ", dmSC = " << d_max_sample_count << ", nOI = " << noutput_items << std::endl; -#endif - - if (d_queueSampleCount > l_max_count) { -// data coming in too fast; do_block decides what to do - if (d_do_block == true) { -// block until there is data to return - while (d_queueSampleCount > l_max_count) { -// release control so-as to allow data to be retrieved; -// block until there is data to return - d_cond_data->wait (l); -// the condition's 'notify' was called; acquire control -// to keep thread safe - } - } - } -// not blocking case and overflow is handled by the circular buffer - -// add the input frames to the buffers' queue, checking for overflow - - UInt32 l_counter; - int res = 0; - float* inBuffer = (float*) input_items[0]; - const UInt32 l_size = input_items.size(); - for (l_counter = 0; l_counter < l_size; l_counter++) { - inBuffer = (float*) input_items[l_counter]; - int l_res = d_buffers[l_counter]->enqueue (inBuffer, - noutput_items); - if (l_res == -1) - res = -1; - } - while (l_counter < d_n_channels) { -// for extra channels, copy the last input's data - int l_res = d_buffers[l_counter++]->enqueue (inBuffer, - noutput_items); - if (l_res == -1) - res = -1; - } - - if (res == -1) { -// data coming in too fast -// drop oldest buffer - fputs ("aO", stderr); - fflush (stderr); -// set the local number of samples available to the max - d_queueSampleCount = d_buffers[0]->buffer_length_items (); - } else { -// keep up the local sample count - d_queueSampleCount += noutput_items; - } - -#if _OSX_AU_DEBUG_ - std::cerr << "work2: #OI = " << noutput_items << ", #Cnt = " - << d_queueSampleCount << ", mSC = " << d_max_sample_count << std::endl; -#endif - - return (noutput_items); -} - -OSStatus audio_osx_sink::AUOutputCallback -(void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList *ioData) -{ - audio_osx_sink* This = (audio_osx_sink*) inRefCon; - OSStatus err = noErr; - - gruel::scoped_lock l (*This->d_internal); - -#if _OSX_AU_DEBUG_ - std::cerr << "cb_in: SC = " << This->d_queueSampleCount - << ", in#F = " << inNumberFrames << std::endl; -#endif - - if (This->d_queueSampleCount < inNumberFrames) { -// not enough data to fill request - err = -1; - } else { -// enough data; remove data from our buffers into the AU's buffers - int l_counter = This->d_n_channels; - - while (--l_counter >= 0) { - size_t t_n_output_items = inNumberFrames; - float* outBuffer = (float*) ioData->mBuffers[l_counter].mData; - This->d_buffers[l_counter]->dequeue (outBuffer, &t_n_output_items); - if (t_n_output_items != inNumberFrames) { - throw std::runtime_error ("audio_osx_sink::AUOutputCallback(): " - "number of available items changing " - "unexpectedly.\n"); - } - } - - This->d_queueSampleCount -= inNumberFrames; - } - -#if _OSX_AU_DEBUG_ - std::cerr << "cb_out: SC = " << This->d_queueSampleCount << std::endl; -#endif - -// signal that data is available - This->d_cond_data->notify_one (); - - return (err); -} diff --git a/gr-audio/lib/osx/audio_osx_sink.h b/gr-audio/lib/osx/audio_osx_sink.h deleted file mode 100644 index 73b3db40d..000000000 --- a/gr-audio/lib/osx/audio_osx_sink.h +++ /dev/null @@ -1,80 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio. - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_AUDIO_OSX_SINK_H -#define INCLUDED_AUDIO_OSX_SINK_H - -#include <gr_audio_sink.h> -#include <string> -#include <list> -#include <AudioUnit/AudioUnit.h> -#include <circular_buffer.h> - -/*! - * \brief audio sink using OSX - * \ingroup audio_blk - * - * input signature is one or two streams of floats. - * Input samples must be in the range [-1,1]. - */ - -class audio_osx_sink : public audio_sink { - - Float64 d_sample_rate; - int d_channel_config; - UInt32 d_n_channels; - UInt32 d_queueSampleCount, d_max_sample_count; - bool d_do_block; - gruel::mutex* d_internal; - gruel::condition_variable* d_cond_data; - circular_buffer<float>** d_buffers; - -// AudioUnits and Such - AudioUnit d_OutputAU; - -public: - audio_osx_sink (int sample_rate = 44100, - const std::string device_name = "2", - bool do_block = true, - int channel_config = -1, - int max_sample_count = -1); - - ~audio_osx_sink (); - - bool IsRunning (); - bool start (); - bool stop (); - - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - -private: - static OSStatus AUOutputCallback (void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList *ioData); -}; - -#endif /* INCLUDED_AUDIO_OSX_SINK_H */ diff --git a/gr-audio/lib/osx/audio_osx_source.cc b/gr-audio/lib/osx/audio_osx_source.cc deleted file mode 100644 index 29f0ac381..000000000 --- a/gr-audio/lib/osx/audio_osx_source.cc +++ /dev/null @@ -1,1065 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio. - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gr_audio_registry.h" -#include <audio_osx_source.h> -#include <gr_io_signature.h> -#include <stdexcept> -#include <audio_osx.h> - -#define _OSX_AU_DEBUG_ 0 -#define _OSX_DO_LISTENERS_ 0 - -AUDIO_REGISTER_SOURCE(REG_PRIO_HIGH, osx)( - int sampling_rate, const std::string &device_name, bool ok_to_block -){ - return audio_source::sptr(new audio_osx_source(sampling_rate, device_name, ok_to_block)); -} - -void PrintStreamDesc (AudioStreamBasicDescription *inDesc) -{ - if (inDesc == NULL) { - std::cerr << "PrintStreamDesc: Can't print a NULL desc!" << std::endl; - return; - } - - std::cerr << " Sample Rate : " << inDesc->mSampleRate << std::endl; - char format_id[4]; - strncpy (format_id, (char*)(&inDesc->mFormatID), 4); - std::cerr << " Format ID : " << format_id << std::endl; - std::cerr << " Format Flags : " << inDesc->mFormatFlags << std::endl; - std::cerr << " Bytes per Packet : " << inDesc->mBytesPerPacket << std::endl; - std::cerr << " Frames per Packet : " << inDesc->mFramesPerPacket << std::endl; - std::cerr << " Bytes per Frame : " << inDesc->mBytesPerFrame << std::endl; - std::cerr << " Channels per Frame : " << inDesc->mChannelsPerFrame << std::endl; - std::cerr << " Bits per Channel : " << inDesc->mBitsPerChannel << std::endl; -} - -// FIXME these should query some kind of user preference - -audio_osx_source::audio_osx_source (int sample_rate, - const std::string device_name, - bool do_block, - int channel_config, - int max_sample_count) - : gr_sync_block ("audio_osx_source", - gr_make_io_signature (0, 0, 0), - gr_make_io_signature (0, 0, 0)), - d_deviceSampleRate (0.0), d_outputSampleRate (0.0), - d_channel_config (0), - d_inputBufferSizeFrames (0), d_inputBufferSizeBytes (0), - d_outputBufferSizeFrames (0), d_outputBufferSizeBytes (0), - d_deviceBufferSizeFrames (0), d_deviceBufferSizeBytes (0), - d_leadSizeFrames (0), d_leadSizeBytes (0), - d_trailSizeFrames (0), d_trailSizeBytes (0), - d_extraBufferSizeFrames (0), d_extraBufferSizeBytes (0), - d_queueSampleCount (0), d_max_sample_count (0), - d_n_AvailableInputFrames (0), d_n_ActualInputFrames (0), - d_n_user_channels (0), d_n_max_channels (0), d_n_deviceChannels (0), - d_do_block (do_block), d_passThrough (false), - d_internal (0), d_cond_data (0), - d_buffers (0), - d_InputAU (0), d_InputBuffer (0), d_OutputBuffer (0), - d_AudioConverter (0) -{ - if (sample_rate <= 0) { - std::cerr << "Invalid Sample Rate: " << sample_rate << std::endl; - throw std::invalid_argument ("audio_osx_source::audio_osx_source"); - } else - d_outputSampleRate = (Float64) sample_rate; - - if (channel_config <= 0 & channel_config != -1) { - std::cerr << "Invalid Channel Config: " << channel_config << std::endl; - throw std::invalid_argument ("audio_osx_source::audio_osx_source"); - } else if (channel_config == -1) { -// no user input; try "device name" instead - int l_n_channels = (int) strtol (device_name.data(), (char **)NULL, 10); - if (l_n_channels == 0 & errno) { - std::cerr << "Error Converting Device Name: " << errno << std::endl; - throw std::invalid_argument ("audio_osx_source::audio_osx_source"); - } - if (l_n_channels <= 0) - channel_config = 2; - else - channel_config = l_n_channels; - } - - d_channel_config = channel_config; - -// check that the max # of samples to store is valid - - if (max_sample_count == -1) - max_sample_count = sample_rate; - else if (max_sample_count <= 0) { - std::cerr << "Invalid Max Sample Count: " << max_sample_count << std::endl; - throw std::invalid_argument ("audio_osx_source::audio_osx_source"); - } - - d_max_sample_count = max_sample_count; - -#if _OSX_AU_DEBUG_ - std::cerr << "source(): max # samples = " << d_max_sample_count << std::endl; -#endif - - OSStatus err = noErr; - -// create the default AudioUnit for input - -// Open the default input unit -#ifndef GR_USE_OLD_AUDIO_UNIT - AudioComponentDescription InputDesc; -#else - ComponentDescription InputDesc; -#endif - - - InputDesc.componentType = kAudioUnitType_Output; - InputDesc.componentSubType = kAudioUnitSubType_HALOutput; - InputDesc.componentManufacturer = kAudioUnitManufacturer_Apple; - InputDesc.componentFlags = 0; - InputDesc.componentFlagsMask = 0; - -#ifndef GR_USE_OLD_AUDIO_UNIT - AudioComponent comp = AudioComponentFindNext (NULL, &InputDesc); -#else - Component comp = FindNextComponent (NULL, &InputDesc); -#endif - - if (comp == NULL) { -#ifndef GR_USE_OLD_AUDIO_UNIT - std::cerr << "AudioComponentFindNext Error" << std::endl; -#else - std::cerr << "FindNextComponent Error" << std::endl; -#endif - throw std::runtime_error ("audio_osx_source::audio_osx_source"); - } - -#ifndef GR_USE_OLD_AUDIO_UNIT - err = AudioComponentInstanceNew (comp, &d_InputAU); - CheckErrorAndThrow (err, "AudioComponentInstanceNew", - "audio_osx_source::audio_osx_source"); -#else - err = OpenAComponent (comp, &d_InputAU); - CheckErrorAndThrow (err, "OpenAComponent", - "audio_osx_source::audio_osx_source"); -#endif - - - UInt32 enableIO; - -// must enable the AUHAL for input and disable output -// before setting the AUHAL's current device - -// Enable input on the AUHAL - enableIO = 1; - err = AudioUnitSetProperty (d_InputAU, - kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Input, - 1, // input element - &enableIO, - sizeof (UInt32)); - CheckErrorAndThrow (err, "AudioUnitSetProperty Input Enable", - "audio_osx_source::audio_osx_source"); - -// Disable output on the AUHAL - enableIO = 0; - err = AudioUnitSetProperty (d_InputAU, - kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Output, - 0, // output element - &enableIO, - sizeof (UInt32)); - CheckErrorAndThrow (err, "AudioUnitSetProperty Output Disable", - "audio_osx_source::audio_osx_source"); - -// set the default input device for our input AU - - SetDefaultInputDeviceAsCurrent (); - -#if _OSX_DO_LISTENERS_ -// set up a listener if default hardware input device changes - - err = AudioHardwareAddPropertyListener - (kAudioHardwarePropertyDefaultInputDevice, - (AudioHardwarePropertyListenerProc) HardwareListener, - this); - - CheckErrorAndThrow (err, "AudioHardwareAddPropertyListener", - "audio_osx_source::audio_osx_source"); - -// Add a listener for any changes in the input AU's output stream -// the function "UnitListener" will be called if the stream format -// changes for whatever reason - - err = AudioUnitAddPropertyListener - (d_InputAU, - kAudioUnitProperty_StreamFormat, - (AudioUnitPropertyListenerProc) UnitListener, - this); - CheckErrorAndThrow (err, "Adding Unit Property Listener", - "audio_osx_source::audio_osx_source"); -#endif - -// Now find out if it actually can do input. - - UInt32 hasInput = 0; - UInt32 dataSize = sizeof (hasInput); - err = AudioUnitGetProperty (d_InputAU, - kAudioOutputUnitProperty_HasIO, - kAudioUnitScope_Input, - 1, - &hasInput, - &dataSize); - CheckErrorAndThrow (err, "AudioUnitGetProperty HasIO", - "audio_osx_source::audio_osx_source"); - if (hasInput == 0) { - std::cerr << "Selected Audio Device does not support Input." << std::endl; - throw std::runtime_error ("audio_osx_source::audio_osx_source"); - } - -// Set up a callback function to retrieve input from the Audio Device - - AURenderCallbackStruct AUCallBack; - - AUCallBack.inputProc = (AURenderCallback)(audio_osx_source::AUInputCallback); - AUCallBack.inputProcRefCon = this; - - err = AudioUnitSetProperty (d_InputAU, - kAudioOutputUnitProperty_SetInputCallback, - kAudioUnitScope_Global, - 0, - &AUCallBack, - sizeof (AURenderCallbackStruct)); - CheckErrorAndThrow (err, "AudioUnitSetProperty Input Callback", - "audio_osx_source::audio_osx_source"); - - UInt32 propertySize; - AudioStreamBasicDescription asbd_device, asbd_client, asbd_user; - -// asbd_device: ASBD of the device that is creating the input data stream -// asbd_client: ASBD of the client size (output) of the hardware device -// asbd_user: ASBD of the user's arguments - -// Get the Stream Format (device side) - - propertySize = sizeof (asbd_device); - err = AudioUnitGetProperty (d_InputAU, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, - 1, - &asbd_device, - &propertySize); - CheckErrorAndThrow (err, "AudioUnitGetProperty Device Input Stream Format", - "audio_osx_source::audio_osx_source"); - -#if _OSX_AU_DEBUG_ - std::cerr << std::endl << "---- Device Stream Format ----" << std::endl; - PrintStreamDesc (&asbd_device); -#endif - -// Get the Stream Format (client side) - propertySize = sizeof (asbd_client); - err = AudioUnitGetProperty (d_InputAU, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, - 1, - &asbd_client, - &propertySize); - CheckErrorAndThrow (err, "AudioUnitGetProperty Device Ouput Stream Format", - "audio_osx_source::audio_osx_source"); - -#if _OSX_AU_DEBUG_ - std::cerr << std::endl << "---- Client Stream Format ----" << std::endl; - PrintStreamDesc (&asbd_client); -#endif - -// Set the format of all the AUs to the input/output devices channel count - -// get the max number of input (& thus output) channels supported by -// this device - d_n_max_channels = asbd_device.mChannelsPerFrame; - -// create the output io signature; -// no input siganture to set (source is hardware) - set_output_signature (gr_make_io_signature (1, - d_n_max_channels, - sizeof (float))); - -// allocate the output circular buffer(s), one per channel - d_buffers = (circular_buffer<float>**) new - circular_buffer<float>* [d_n_max_channels]; - UInt32 n_alloc = (UInt32) ceil ((double) d_max_sample_count); - for (UInt32 n = 0; n < d_n_max_channels; n++) { - d_buffers[n] = new circular_buffer<float> (n_alloc, false, false); - } - - d_deviceSampleRate = asbd_device.mSampleRate; - d_n_deviceChannels = asbd_device.mChannelsPerFrame; - - asbd_client.mSampleRate = asbd_device.mSampleRate; - asbd_client.mFormatID = kAudioFormatLinearPCM; - asbd_client.mFormatFlags = (kAudioFormatFlagIsFloat | - kAudioFormatFlagIsPacked | - kAudioFormatFlagIsNonInterleaved); - if ((asbd_client.mFormatID == kAudioFormatLinearPCM) && - (d_n_deviceChannels == 1)) { - asbd_client.mFormatFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; - } - asbd_client.mBytesPerFrame = sizeof (float); - asbd_client.mFramesPerPacket = 1; - asbd_client.mBitsPerChannel = asbd_client.mBytesPerFrame * 8; - asbd_client.mChannelsPerFrame = d_n_deviceChannels; - asbd_client.mBytesPerPacket = asbd_client.mBytesPerFrame; - - propertySize = sizeof(AudioStreamBasicDescription); - err = AudioUnitSetProperty (d_InputAU, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, - 1, - &asbd_client, - propertySize); - CheckErrorAndThrow (err, "AudioUnitSetProperty Device Ouput Stream Format", - "audio_osx_source::audio_osx_source"); - -// create an ASBD for the user's wants - - asbd_user.mSampleRate = d_outputSampleRate; - asbd_user.mFormatID = kAudioFormatLinearPCM; - asbd_user.mFormatFlags = (kLinearPCMFormatFlagIsFloat | - GR_PCM_ENDIANNESS | - kLinearPCMFormatFlagIsPacked | - kAudioFormatFlagIsNonInterleaved); - asbd_user.mBytesPerPacket = sizeof (float); - asbd_user.mFramesPerPacket = 1; - asbd_user.mBytesPerFrame = asbd_user.mBytesPerPacket; - asbd_user.mChannelsPerFrame = d_n_deviceChannels; - asbd_user.mBitsPerChannel = asbd_user.mBytesPerPacket * 8; - - if (d_deviceSampleRate == d_outputSampleRate) { -// no need to do conversion if asbd_client matches user wants - d_passThrough = true; - d_leadSizeFrames = d_trailSizeFrames = 0L; - } else { - d_passThrough = false; -// Create the audio converter - - err = AudioConverterNew (&asbd_client, &asbd_user, &d_AudioConverter); - CheckErrorAndThrow (err, "AudioConverterNew", - "audio_osx_source::audio_osx_source"); - -// Set the audio converter sample rate quality to "max" ... -// requires more samples, but should sound nicer - - UInt32 ACQuality = kAudioConverterQuality_Max; - propertySize = sizeof (ACQuality); - err = AudioConverterSetProperty (d_AudioConverter, - kAudioConverterSampleRateConverterQuality, - propertySize, - &ACQuality); - CheckErrorAndThrow (err, "AudioConverterSetProperty " - "SampleRateConverterQuality", - "audio_osx_source::audio_osx_source"); - -// set the audio converter's prime method to "pre", -// which uses both leading and trailing frames -// from the "current input". All of this is handled -// internally by the AudioConverter; we just supply -// the frames for conversion. - -// UInt32 ACPrimeMethod = kConverterPrimeMethod_None; - UInt32 ACPrimeMethod = kConverterPrimeMethod_Pre; - propertySize = sizeof (ACPrimeMethod); - err = AudioConverterSetProperty (d_AudioConverter, - kAudioConverterPrimeMethod, - propertySize, - &ACPrimeMethod); - CheckErrorAndThrow (err, "AudioConverterSetProperty PrimeMethod", - "audio_osx_source::audio_osx_source"); - -// Get the size of the I/O buffer(s) to allow for pre-allocated buffers - -// lead frame info (trail frame info is ignored) - - AudioConverterPrimeInfo ACPrimeInfo = {0, 0}; - propertySize = sizeof (ACPrimeInfo); - err = AudioConverterGetProperty (d_AudioConverter, - kAudioConverterPrimeInfo, - &propertySize, - &ACPrimeInfo); - CheckErrorAndThrow (err, "AudioConverterGetProperty PrimeInfo", - "audio_osx_source::audio_osx_source"); - - switch (ACPrimeMethod) { - case (kConverterPrimeMethod_None): - d_leadSizeFrames = - d_trailSizeFrames = 0L; - break; - case (kConverterPrimeMethod_Normal): - d_leadSizeFrames = 0L; - d_trailSizeFrames = ACPrimeInfo.trailingFrames; - break; - default: - d_leadSizeFrames = ACPrimeInfo.leadingFrames; - d_trailSizeFrames = ACPrimeInfo.trailingFrames; - } - } - d_leadSizeBytes = d_leadSizeFrames * sizeof (Float32); - d_trailSizeBytes = d_trailSizeFrames * sizeof (Float32); - - propertySize = sizeof (d_deviceBufferSizeFrames); - err = AudioUnitGetProperty (d_InputAU, - kAudioDevicePropertyBufferFrameSize, - kAudioUnitScope_Global, - 0, - &d_deviceBufferSizeFrames, - &propertySize); - CheckErrorAndThrow (err, "AudioUnitGetProperty Buffer Frame Size", - "audio_osx_source::audio_osx_source"); - - d_deviceBufferSizeBytes = d_deviceBufferSizeFrames * sizeof (Float32); - d_inputBufferSizeBytes = d_deviceBufferSizeBytes + d_leadSizeBytes; - d_inputBufferSizeFrames = d_deviceBufferSizeFrames + d_leadSizeFrames; - -// outBufSizeBytes = floor (inBufSizeBytes * rate_out / rate_in) -// since this is rarely exact, we need another buffer to hold -// "extra" samples not processed at any given sampling period -// this buffer must be at least 4 floats in size, but generally -// follows the rule that -// extraBufSize = ceil (rate_in / rate_out)*sizeof(float) - - d_extraBufferSizeFrames = ((UInt32) ceil (d_deviceSampleRate - / d_outputSampleRate) - * sizeof (float)); - if (d_extraBufferSizeFrames < 4) - d_extraBufferSizeFrames = 4; - d_extraBufferSizeBytes = d_extraBufferSizeFrames * sizeof (float); - - d_outputBufferSizeFrames = (UInt32) ceil (((Float64) d_inputBufferSizeFrames) - * d_outputSampleRate - / d_deviceSampleRate); - d_outputBufferSizeBytes = d_outputBufferSizeFrames * sizeof (float); - d_inputBufferSizeFrames += d_extraBufferSizeFrames; - -// pre-alloc all buffers - - AllocAudioBufferList (&d_InputBuffer, d_n_deviceChannels, - d_inputBufferSizeBytes); - if (d_passThrough == false) { - AllocAudioBufferList (&d_OutputBuffer, d_n_max_channels, - d_outputBufferSizeBytes); - } else { - d_OutputBuffer = d_InputBuffer; - } - -// create the stuff to regulate I/O - - d_cond_data = new gruel::condition_variable (); - if (d_cond_data == NULL) - CheckErrorAndThrow (errno, "new condition (data)", - "audio_osx_source::audio_osx_source"); - - d_internal = new gruel::mutex (); - if (d_internal == NULL) - CheckErrorAndThrow (errno, "new mutex (internal)", - "audio_osx_source::audio_osx_source"); - -// initialize the AU for input - - err = AudioUnitInitialize (d_InputAU); - CheckErrorAndThrow (err, "AudioUnitInitialize", - "audio_osx_source::audio_osx_source"); - -#if _OSX_AU_DEBUG_ - std::cerr << "audio_osx_source Parameters:" << std::endl; - std::cerr << " Device Sample Rate is " << d_deviceSampleRate << std::endl; - std::cerr << " User Sample Rate is " << d_outputSampleRate << std::endl; - std::cerr << " Max Sample Count is " << d_max_sample_count << std::endl; - std::cerr << " # Device Channels is " << d_n_deviceChannels << std::endl; - std::cerr << " # Max Channels is " << d_n_max_channels << std::endl; - std::cerr << " Device Buffer Size is Frames = " << d_deviceBufferSizeFrames << std::endl; - std::cerr << " Lead Size is Frames = " << d_leadSizeFrames << std::endl; - std::cerr << " Trail Size is Frames = " << d_trailSizeFrames << std::endl; - std::cerr << " Input Buffer Size is Frames = " << d_inputBufferSizeFrames << std::endl; - std::cerr << " Output Buffer Size is Frames = " << d_outputBufferSizeFrames << std::endl; -#endif -} - -void -audio_osx_source::AllocAudioBufferList (AudioBufferList** t_ABL, - UInt32 n_channels, - UInt32 bufferSizeBytes) -{ - FreeAudioBufferList (t_ABL); - UInt32 propertySize = (offsetof (AudioBufferList, mBuffers[0]) + - (sizeof (AudioBuffer) * n_channels)); - *t_ABL = (AudioBufferList*) calloc (1, propertySize); - (*t_ABL)->mNumberBuffers = n_channels; - - int counter = n_channels; - - while (--counter >= 0) { - (*t_ABL)->mBuffers[counter].mNumberChannels = 1; - (*t_ABL)->mBuffers[counter].mDataByteSize = bufferSizeBytes; - (*t_ABL)->mBuffers[counter].mData = calloc (1, bufferSizeBytes); - } -} - -void -audio_osx_source::FreeAudioBufferList (AudioBufferList** t_ABL) -{ -// free pre-allocated audio buffer, if it exists - if (*t_ABL != NULL) { - int counter = (*t_ABL)->mNumberBuffers; - while (--counter >= 0) - free ((*t_ABL)->mBuffers[counter].mData); - free (*t_ABL); - (*t_ABL) = 0; - } -} - -bool audio_osx_source::IsRunning () -{ - UInt32 AURunning = 0, AUSize = sizeof (UInt32); - - OSStatus err = AudioUnitGetProperty (d_InputAU, - kAudioOutputUnitProperty_IsRunning, - kAudioUnitScope_Global, - 0, - &AURunning, - &AUSize); - CheckErrorAndThrow (err, "AudioUnitGetProperty IsRunning", - "audio_osx_source::IsRunning"); - - return (AURunning); -} - -bool audio_osx_source::start () -{ - if (! IsRunning ()) { - OSStatus err = AudioOutputUnitStart (d_InputAU); - CheckErrorAndThrow (err, "AudioOutputUnitStart", - "audio_osx_source::start"); - } - - return (true); -} - -bool audio_osx_source::stop () -{ - if (IsRunning ()) { - OSStatus err = AudioOutputUnitStop (d_InputAU); - CheckErrorAndThrow (err, "AudioOutputUnitStart", - "audio_osx_source::stop"); - for (UInt32 n = 0; n < d_n_user_channels; n++) { - d_buffers[n]->abort (); - } - } - - return (true); -} - -audio_osx_source::~audio_osx_source () -{ - OSStatus err = noErr; - -// stop the AudioUnit - stop(); - -#if _OSX_DO_LISTENERS_ -// remove the listeners - - err = AudioUnitRemovePropertyListener - (d_InputAU, - kAudioUnitProperty_StreamFormat, - (AudioUnitPropertyListenerProc) UnitListener); - CheckError (err, "~audio_osx_source: AudioUnitRemovePropertyListener"); - - err = AudioHardwareRemovePropertyListener - (kAudioHardwarePropertyDefaultInputDevice, - (AudioHardwarePropertyListenerProc) HardwareListener); - CheckError (err, "~audio_osx_source: AudioHardwareRemovePropertyListener"); -#endif - -// free pre-allocated audio buffers - FreeAudioBufferList (&d_InputBuffer); - - if (d_passThrough == false) { - err = AudioConverterDispose (d_AudioConverter); - CheckError (err, "~audio_osx_source: AudioConverterDispose"); - FreeAudioBufferList (&d_OutputBuffer); - } - -// remove the audio unit - err = AudioUnitUninitialize (d_InputAU); - CheckError (err, "~audio_osx_source: AudioUnitUninitialize"); - -#ifndef GR_USE_OLD_AUDIO_UNIT - err = AudioComponentInstanceDispose (d_InputAU); - CheckError (err, "~audio_osx_source: AudioComponentInstanceDispose"); -#else - err = CloseComponent (d_InputAU); - CheckError (err, "~audio_osx_source: CloseComponent"); -#endif - -// empty and delete the queues - for (UInt32 n = 0; n < d_n_max_channels; n++) { - delete d_buffers[n]; - d_buffers[n] = 0; - } - delete [] d_buffers; - d_buffers = 0; - -// close and delete the control stuff - delete d_cond_data; - d_cond_data = 0; - delete d_internal; - d_internal = 0; -} - -bool -audio_osx_source::check_topology (int ninputs, int noutputs) -{ -// check # inputs to make sure it's valid - if (ninputs != 0) { - std::cerr << "audio_osx_source::check_topology(): number of input " - << "streams provided (" << ninputs - << ") should be 0." << std::endl; - throw std::runtime_error ("audio_osx_source::check_topology()"); - } - -// check # outputs to make sure it's valid - if ((noutputs < 1) | (noutputs > (int) d_n_max_channels)) { - std::cerr << "audio_osx_source::check_topology(): number of output " - << "streams provided (" << noutputs << ") should be in [1," - << d_n_max_channels << "] for the selected audio device." - << std::endl; - throw std::runtime_error ("audio_osx_source::check_topology()"); - } - -// save the actual number of output (user) channels - d_n_user_channels = noutputs; - -#if _OSX_AU_DEBUG_ - std::cerr << "chk_topo: Actual # user output channels = " - << noutputs << std::endl; -#endif - - return (true); -} - -int -audio_osx_source::work -(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - // acquire control to do processing here only - gruel::scoped_lock l (*d_internal); - -#if _OSX_AU_DEBUG_ - std::cerr << "work1: SC = " << d_queueSampleCount - << ", #OI = " << noutput_items - << ", #Chan = " << output_items.size() << std::endl; -#endif - - // set the actual # of output items to the 'desired' amount then - // verify that data is available; if not enough data is available, - // either wait until it is (is "do_block" is true), return (0) is no - // data is available and "do_block" is false, or process the actual - // amount of available data. - - UInt32 actual_noutput_items = noutput_items; - - if (d_queueSampleCount < actual_noutput_items) { - if (d_queueSampleCount == 0) { - // no data; do_block decides what to do - if (d_do_block == true) { - while (d_queueSampleCount == 0) { - // release control so-as to allow data to be retrieved; - // block until there is data to return - d_cond_data->wait (l); - // the condition's 'notify' was called; acquire control to - // keep thread safe - } - } else { - // no data & not blocking; return nothing - return (0); - } - } - // use the actual amount of available data - actual_noutput_items = d_queueSampleCount; - } - - // number of channels - int l_counter = (int) output_items.size(); - - // copy the items from the circular buffer(s) to 'work's output buffers - // verify that the number copied out is as expected. - - while (--l_counter >= 0) { - size_t t_n_output_items = actual_noutput_items; - d_buffers[l_counter]->dequeue ((float*) output_items[l_counter], - &t_n_output_items); - if (t_n_output_items != actual_noutput_items) { - std::cerr << "audio_osx_source::work(): ERROR: number of " - << "available items changing unexpectedly; expecting " - << actual_noutput_items << ", got " - << t_n_output_items << "." << std::endl; - throw std::runtime_error ("audio_osx_source::work()"); - } - } - - // subtract the actual number of items removed from the buffer(s) - // from the local accounting of the number of available samples - - d_queueSampleCount -= actual_noutput_items; - -#if _OSX_AU_DEBUG_ - std::cerr << "work2: SC = " << d_queueSampleCount - << ", act#OI = " << actual_noutput_items << std::endl - << "Returning." << std::endl; -#endif - - return (actual_noutput_items); -} - -OSStatus -audio_osx_source::ConverterCallback -(AudioConverterRef inAudioConverter, - UInt32* ioNumberDataPackets, - AudioBufferList* ioData, - AudioStreamPacketDescription** ioASPD, - void* inUserData) -{ - // take current device buffers and copy them to the tail of the - // input buffers the lead buffer is already there in the first - // d_leadSizeFrames slots - - audio_osx_source* This = static_cast<audio_osx_source*>(inUserData); - AudioBufferList* l_inputABL = This->d_InputBuffer; - UInt32 totalInputBufferSizeBytes = ((*ioNumberDataPackets) * sizeof (float)); - int counter = This->d_n_deviceChannels; - ioData->mNumberBuffers = This->d_n_deviceChannels; - This->d_n_ActualInputFrames = (*ioNumberDataPackets); - -#if _OSX_AU_DEBUG_ - std::cerr << "cc1: io#DP = " << (*ioNumberDataPackets) - << ", TIBSB = " << totalInputBufferSizeBytes - << ", #C = " << counter << std::endl; -#endif - - while (--counter >= 0) { - AudioBuffer* l_ioD_AB = &(ioData->mBuffers[counter]); - l_ioD_AB->mNumberChannels = 1; - l_ioD_AB->mData = (float*)(l_inputABL->mBuffers[counter].mData); - l_ioD_AB->mDataByteSize = totalInputBufferSizeBytes; - } - -#if _OSX_AU_DEBUG_ - std::cerr << "cc2: Returning." << std::endl; -#endif - - return (noErr); -} - -OSStatus -audio_osx_source::AUInputCallback (void* inRefCon, - AudioUnitRenderActionFlags* ioActionFlags, - const AudioTimeStamp* inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList* ioData) -{ - OSStatus err = noErr; - audio_osx_source* This = static_cast<audio_osx_source*>(inRefCon); - - gruel::scoped_lock l (*This->d_internal); - -#if _OSX_AU_DEBUG_ - std::cerr << "cb0: in#F = " << inNumberFrames - << ", inBN = " << inBusNumber - << ", SC = " << This->d_queueSampleCount << std::endl; -#endif - -// Get the new audio data from the input device - - err = AudioUnitRender (This->d_InputAU, - ioActionFlags, - inTimeStamp, - 1, //inBusNumber, - inNumberFrames, - This->d_InputBuffer); - CheckErrorAndThrow (err, "AudioUnitRender", - "audio_osx_source::AUInputCallback"); - - UInt32 AvailableInputFrames = inNumberFrames; - This->d_n_AvailableInputFrames = inNumberFrames; - -// get the number of actual output frames, -// either via converting the buffer or not - - UInt32 ActualOutputFrames; - - if (This->d_passThrough == true) { - ActualOutputFrames = AvailableInputFrames; - } else { - UInt32 AvailableInputBytes = AvailableInputFrames * sizeof (float); - UInt32 AvailableOutputBytes = AvailableInputBytes; - UInt32 AvailableOutputFrames = AvailableOutputBytes / sizeof (float); - UInt32 propertySize = sizeof (AvailableOutputBytes); - err = AudioConverterGetProperty (This->d_AudioConverter, - kAudioConverterPropertyCalculateOutputBufferSize, - &propertySize, - &AvailableOutputBytes); - CheckErrorAndThrow (err, "AudioConverterGetProperty CalculateOutputBufferSize", "audio_osx_source::audio_osx_source"); - - AvailableOutputFrames = AvailableOutputBytes / sizeof (float); - -#if 0 -// when decimating too much, the output sounds warbly due to -// fluctuating # of output frames -// This should not be a surprise, but there's probably some -// clever programming that could lessed the effect ... -// like finding the "ideal" # of output frames, and keeping -// that number constant no matter the # of input frames - UInt32 l_InputBytes = AvailableOutputBytes; - propertySize = sizeof (AvailableOutputBytes); - err = AudioConverterGetProperty (This->d_AudioConverter, - kAudioConverterPropertyCalculateInputBufferSize, - &propertySize, - &l_InputBytes); - CheckErrorAndThrow (err, "AudioConverterGetProperty CalculateInputBufferSize", "audio_osx_source::audio_osx_source"); - - if (l_InputBytes < AvailableInputBytes) { -// OK to zero pad the input a little - AvailableOutputFrames += 1; - AvailableOutputBytes = AvailableOutputFrames * sizeof (float); - } -#endif - -#if _OSX_AU_DEBUG_ - std::cerr << "cb1: avail: #IF = " << AvailableInputFrames - << ", #OF = " << AvailableOutputFrames << std::endl; -#endif - ActualOutputFrames = AvailableOutputFrames; - -// convert the data to the correct rate -// on input, ActualOutputFrames is the number of available output frames - - err = AudioConverterFillComplexBuffer (This->d_AudioConverter, - (AudioConverterComplexInputDataProc)(This->ConverterCallback), - inRefCon, - &ActualOutputFrames, - This->d_OutputBuffer, - NULL); - CheckErrorAndThrow (err, "AudioConverterFillComplexBuffer", - "audio_osx_source::AUInputCallback"); - -// on output, ActualOutputFrames is the actual number of output frames - -#if _OSX_AU_DEBUG_ - std::cerr << "cb2: actual: #IF = " << This->d_n_ActualInputFrames - << ", #OF = " << AvailableOutputFrames << std::endl; - if (This->d_n_ActualInputFrames != AvailableInputFrames) - std::cerr << "cb2.1: avail#IF = " << AvailableInputFrames - << ", actual#IF = " << This->d_n_ActualInputFrames << std::endl; -#endif - } - -// add the output frames to the buffers' queue, checking for overflow - - int l_counter = This->d_n_user_channels; - int res = 0; - - while (--l_counter >= 0) { - float* inBuffer = (float*) This->d_OutputBuffer->mBuffers[l_counter].mData; - -#if _OSX_AU_DEBUG_ - std::cerr << "cb3: enqueuing audio data." << std::endl; -#endif - - int l_res = This->d_buffers[l_counter]->enqueue (inBuffer, ActualOutputFrames); - if (l_res == -1) - res = -1; - } - - if (res == -1) { -// data coming in too fast -// drop oldest buffer - fputs ("aO", stderr); - fflush (stderr); -// set the local number of samples available to the max - This->d_queueSampleCount = This->d_buffers[0]->buffer_length_items (); - } else { -// keep up the local sample count - This->d_queueSampleCount += ActualOutputFrames; - } - -#if _OSX_AU_DEBUG_ - std::cerr << "cb4: #OI = " << ActualOutputFrames - << ", #Cnt = " << This->d_queueSampleCount - << ", mSC = " << This->d_max_sample_count << std::endl; -#endif - -// signal that data is available, if appropraite - This->d_cond_data->notify_one (); - -#if _OSX_AU_DEBUG_ - std::cerr << "cb5: returning." << std::endl; -#endif - - return (err); -} - -void -audio_osx_source::SetDefaultInputDeviceAsCurrent -() -{ -// set the default input device - AudioDeviceID deviceID = 0; - UInt32 dataSize = sizeof (AudioDeviceID); - OSStatus err = noErr; - -#ifndef GR_USE_OLD_AUDIO_UNIT - AudioObjectPropertyAddress theAddress = - { kAudioHardwarePropertyDefaultInputDevice, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster }; - - err = AudioObjectGetPropertyData - (kAudioObjectSystemObject, - &theAddress, - 0, - NULL, - &dataSize, - &deviceID); -#else - err = AudioHardwareGetProperty - (kAudioHardwarePropertyDefaultInputDevice, - &dataSize, - &deviceID); -#endif - - CheckErrorAndThrow (err, "Get Audio Unit Property for Current Device", - "audio_osx_source::SetDefaultInputDeviceAsCurrent"); - - err = AudioUnitSetProperty - (d_InputAU, - kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, - 0, - &deviceID, - sizeof (AudioDeviceID)); - - CheckErrorAndThrow (err, "AudioUnitSetProperty Current Device", - "audio_osx_source::SetDefaultInputDeviceAsCurrent"); -} - -#if _OSX_DO_LISTENERS_ -OSStatus -audio_osx_source::HardwareListener -(AudioHardwarePropertyID inPropertyID, - void *inClientData) -{ - OSStatus err = noErr; - audio_osx_source* This = static_cast<audio_osx_source*>(inClientData); - - std::cerr << "a_o_s::HardwareListener" << std::endl; - -// set the new default hardware input device for use by our AU - - This->SetDefaultInputDeviceAsCurrent (); - -// reset the converter to tell it that the stream has changed - - err = AudioConverterReset (This->d_AudioConverter); - CheckErrorAndThrow (err, "AudioConverterReset", - "audio_osx_source::UnitListener"); - - return (err); -} - -OSStatus -audio_osx_source::UnitListener -(void *inRefCon, - AudioUnit ci, - AudioUnitPropertyID inID, - AudioUnitScope inScope, - AudioUnitElement inElement) -{ - OSStatus err = noErr; - audio_osx_source* This = static_cast<audio_osx_source*>(inRefCon); - AudioStreamBasicDescription asbd; - - std::cerr << "a_o_s::UnitListener" << std::endl; - -// get the converter's input ASBD (for printing) - - UInt32 propertySize = sizeof (asbd); - err = AudioConverterGetProperty (This->d_AudioConverter, - kAudioConverterCurrentInputStreamDescription, - &propertySize, - &asbd); - CheckErrorAndThrow (err, "AudioConverterGetProperty " - "CurrentInputStreamDescription", - "audio_osx_source::UnitListener"); - - std::cerr << "UnitListener: Input Source changed." << std::endl - << "Old Source Output Info:" << std::endl; - PrintStreamDesc (&asbd); - -// get the new input unit's output ASBD - - propertySize = sizeof (asbd); - err = AudioUnitGetProperty (This->d_InputAU, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, 1, - &asbd, &propertySize); - CheckErrorAndThrow (err, "AudioUnitGetProperty StreamFormat", - "audio_osx_source::UnitListener"); - - std::cerr << "New Source Output Info:" << std::endl; - PrintStreamDesc (&asbd); - -// set the converter's input ASBD to this - - err = AudioConverterSetProperty (This->d_AudioConverter, - kAudioConverterCurrentInputStreamDescription, - propertySize, - &asbd); - CheckErrorAndThrow (err, "AudioConverterSetProperty " - "CurrentInputStreamDescription", - "audio_osx_source::UnitListener"); - -// reset the converter to tell it that the stream has changed - - err = AudioConverterReset (This->d_AudioConverter); - CheckErrorAndThrow (err, "AudioConverterReset", - "audio_osx_source::UnitListener"); - - return (err); -} -#endif diff --git a/gr-audio/lib/osx/audio_osx_source.h b/gr-audio/lib/osx/audio_osx_source.h deleted file mode 100644 index bb34d972c..000000000 --- a/gr-audio/lib/osx/audio_osx_source.h +++ /dev/null @@ -1,116 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio. - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_AUDIO_OSX_SOURCE_H -#define INCLUDED_AUDIO_OSX_SOURCE_H - -#include <gr_audio_source.h> -#include <string> -#include <AudioToolbox/AudioToolbox.h> -#include <AudioUnit/AudioUnit.h> -#include <circular_buffer.h> - -/*! - * \brief audio source using OSX - * \ingroup audio_blk - * - * Input signature is one or two streams of floats. - * Samples must be in the range [-1,1]. - */ - -class audio_osx_source : public audio_source { - - Float64 d_deviceSampleRate, d_outputSampleRate; - int d_channel_config; - UInt32 d_inputBufferSizeFrames, d_inputBufferSizeBytes; - UInt32 d_outputBufferSizeFrames, d_outputBufferSizeBytes; - UInt32 d_deviceBufferSizeFrames, d_deviceBufferSizeBytes; - UInt32 d_leadSizeFrames, d_leadSizeBytes; - UInt32 d_trailSizeFrames, d_trailSizeBytes; - UInt32 d_extraBufferSizeFrames, d_extraBufferSizeBytes; - UInt32 d_queueSampleCount, d_max_sample_count; - UInt32 d_n_AvailableInputFrames, d_n_ActualInputFrames; - UInt32 d_n_user_channels, d_n_max_channels, d_n_deviceChannels; - bool d_do_block, d_passThrough, d_waiting_for_data; - gruel::mutex* d_internal; - gruel::condition_variable* d_cond_data; - circular_buffer<float>** d_buffers; - -// AudioUnits and Such - AudioUnit d_InputAU; - AudioBufferList* d_InputBuffer; - AudioBufferList* d_OutputBuffer; - AudioConverterRef d_AudioConverter; - -public: - audio_osx_source (int sample_rate = 44100, - const std::string device_name = "", - bool do_block = true, - int channel_config = -1, - int max_sample_count = -1); - - ~audio_osx_source (); - - bool start (); - bool stop (); - bool IsRunning (); - - bool check_topology (int ninputs, int noutputs); - - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - -private: - void SetDefaultInputDeviceAsCurrent (); - - void AllocAudioBufferList (AudioBufferList** t_ABL, - UInt32 n_channels, - UInt32 inputBufferSizeBytes); - - void FreeAudioBufferList (AudioBufferList** t_ABL); - - static OSStatus ConverterCallback (AudioConverterRef inAudioConverter, - UInt32* ioNumberDataPackets, - AudioBufferList* ioData, - AudioStreamPacketDescription** outASPD, - void* inUserData); - - static OSStatus AUInputCallback (void *inRefCon, - AudioUnitRenderActionFlags *ioActionFlags, - const AudioTimeStamp *inTimeStamp, - UInt32 inBusNumber, - UInt32 inNumberFrames, - AudioBufferList *ioData); -#if _OSX_DO_LISTENERS_ - static OSStatus UnitListener (void *inRefCon, - AudioUnit ci, - AudioUnitPropertyID inID, - AudioUnitScope inScope, - AudioUnitElement inElement); - - static OSStatus HardwareListener (AudioHardwarePropertyID inPropertyID, - void *inClientData); -#endif -}; - -#endif /* INCLUDED_AUDIO_OSX_SOURCE_H */ diff --git a/gr-audio/lib/osx/circular_buffer.h b/gr-audio/lib/osx/circular_buffer.h deleted file mode 100644 index 65788d482..000000000 --- a/gr-audio/lib/osx/circular_buffer.h +++ /dev/null @@ -1,315 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2009,2010 Free Software Foundation, Inc. - * - * This file is part of GNU Radio. - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef _CIRCULAR_BUFFER_H_ -#define _CIRCULAR_BUFFER_H_ - -#include <gruel/thread.h> -#include <iostream> -#include <stdexcept> - -#ifndef DO_DEBUG -#define DO_DEBUG 0 -#endif - -#if DO_DEBUG -#define DEBUG(X) do{X} while(0); -#else -#define DEBUG(X) do{} while(0); -#endif - -template <class T> -class circular_buffer -{ -private: -// the buffer to use - T* d_buffer; - -// the following are in Items (type T) - size_t d_bufLen_I, d_readNdx_I, d_writeNdx_I; - size_t d_n_avail_write_I, d_n_avail_read_I; - -// stuff to control access to class internals - gruel::mutex* d_internal; - gruel::condition_variable* d_readBlock; - gruel::condition_variable* d_writeBlock; - -// booleans to decide how to control reading, writing, and aborting - bool d_doWriteBlock, d_doFullRead, d_doAbort; - - void delete_mutex_cond () { - if (d_internal) { - delete d_internal; - d_internal = NULL; - } - if (d_readBlock) { - delete d_readBlock; - d_readBlock = NULL; - } - if (d_writeBlock) { - delete d_writeBlock; - d_writeBlock = NULL; - } - }; - -public: - circular_buffer (size_t bufLen_I, - bool doWriteBlock = true, bool doFullRead = false) { - if (bufLen_I == 0) - throw std::runtime_error ("circular_buffer(): " - "Number of items to buffer must be > 0.\n"); - d_bufLen_I = bufLen_I; - d_buffer = (T*) new T[d_bufLen_I]; - d_doWriteBlock = doWriteBlock; - d_doFullRead = doFullRead; - d_internal = NULL; - d_readBlock = d_writeBlock = NULL; - reset (); - DEBUG (std::cerr << "c_b(): buf len (items) = " << d_bufLen_ - << ", doWriteBlock = " << (d_doWriteBlock ? "true" : "false") - << ", doFullRead = " << (d_doFullRead ? "true" : "false") - << std::endl); - }; - - ~circular_buffer () { - delete_mutex_cond (); - delete [] d_buffer; - }; - - inline size_t n_avail_write_items () { - gruel::scoped_lock l (*d_internal); - size_t retVal = d_n_avail_write_I; - return (retVal); - }; - - inline size_t n_avail_read_items () { - gruel::scoped_lock l (*d_internal); - size_t retVal = d_n_avail_read_I; - return (retVal); - }; - - inline size_t buffer_length_items () {return (d_bufLen_I);}; - inline bool do_write_block () {return (d_doWriteBlock);}; - inline bool do_full_read () {return (d_doFullRead);}; - - void reset () { - d_doAbort = false; - bzero (d_buffer, d_bufLen_I * sizeof (T)); - d_readNdx_I = d_writeNdx_I = d_n_avail_read_I = 0; - d_n_avail_write_I = d_bufLen_I; - delete_mutex_cond (); - // create a mutex to handle contention of shared resources; - // any routine needed access to shared resources uses lock() - // before doing anything, then unlock() when finished. - d_internal = new gruel::mutex (); - // link the internal mutex to the read and write conditions; - // when wait() is called, the internal mutex will automatically - // be unlock()'ed. Upon return (from a notify_one() to the condition), - // the internal mutex will be lock()'ed. - d_readBlock = new gruel::condition_variable (); - d_writeBlock = new gruel::condition_variable (); - }; - -/* - * enqueue: add the given buffer of item-length to the queue, - * first-in-first-out (FIFO). - * - * inputs: - * buf: a pointer to the buffer holding the data - * - * bufLen_I: the buffer length in items (of the instantiated type) - * - * returns: - * -1: on overflow (write is not blocking, and data is being - * written faster than it is being read) - * 0: if nothing to do (0 length buffer) - * 1: if success - * 2: in the process of aborting, do doing nothing - * - * will throw runtime errors if inputs are improper: - * buffer pointer is NULL - * buffer length is larger than the instantiated buffer length - */ - - int enqueue (T* buf, size_t bufLen_I) { - DEBUG (std::cerr << "enqueue: buf = " << (void*) buf - << ", bufLen = " << bufLen_I - << ", #av_wr = " << d_n_avail_write_I - << ", #av_rd = " << d_n_avail_read_I << std::endl); - if (bufLen_I > d_bufLen_I) { - std::cerr << "ERROR: cannot add buffer longer (" - << bufLen_I << ") than instantiated length (" - << d_bufLen_I << ")." << std::endl; - throw std::runtime_error ("circular_buffer::enqueue()"); - } - - if (bufLen_I == 0) - return (0); - if (!buf) - throw std::runtime_error ("circular_buffer::enqueue(): " - "input buffer is NULL.\n"); - gruel::scoped_lock l (*d_internal); - if (d_doAbort) { - return (2); - } - // set the return value to 1: success; change if needed - int retval = 1; - if (bufLen_I > d_n_avail_write_I) { - if (d_doWriteBlock) { - while (bufLen_I > d_n_avail_write_I) { - DEBUG (std::cerr << "enqueue: #len > #a, waiting." << std::endl); - // wait; will automatically unlock() the internal mutex via - // the scoped lock - d_writeBlock->wait (l); - // and auto re-lock() it here. - if (d_doAbort) { - DEBUG (std::cerr << "enqueue: #len > #a, aborting." << std::endl); - return (2); - } - DEBUG (std::cerr << "enqueue: #len > #a, done waiting." << std::endl); - } - } else { - d_n_avail_read_I = d_bufLen_I - bufLen_I; - d_n_avail_write_I = bufLen_I; - DEBUG (std::cerr << "circular_buffer::enqueue: overflow" << std::endl); - retval = -1; - } - } - size_t n_now_I = d_bufLen_I - d_writeNdx_I, n_start_I = 0; - if (n_now_I > bufLen_I) - n_now_I = bufLen_I; - else if (n_now_I < bufLen_I) - n_start_I = bufLen_I - n_now_I; - bcopy (buf, &(d_buffer[d_writeNdx_I]), n_now_I * sizeof (T)); - if (n_start_I) { - bcopy (&(buf[n_now_I]), d_buffer, n_start_I * sizeof (T)); - d_writeNdx_I = n_start_I; - } else - d_writeNdx_I += n_now_I; - d_n_avail_read_I += bufLen_I; - d_n_avail_write_I -= bufLen_I; - d_readBlock->notify_one (); - return (retval); - }; - -/* - * dequeue: removes from the queue the number of items requested, or - * available, into the given buffer on a FIFO basis. - * - * inputs: - * buf: a pointer to the buffer into which to copy the data - * - * bufLen_I: pointer to the number of items to remove in items - * (of the instantiated type) - * - * returns: - * 0: if nothing to do (0 length buffer) - * 1: if success - * 2: in the process of aborting, do doing nothing - * - * will throw runtime errors if inputs are improper: - * buffer pointer is NULL - * buffer length pointer is NULL - * buffer length is larger than the instantiated buffer length - */ - - int dequeue (T* buf, size_t* bufLen_I) { - DEBUG (std::cerr << "dequeue: buf = " << ((void*) buf) - << ", *bufLen = " << (*bufLen_I) - << ", #av_wr = " << d_n_avail_write_I - << ", #av_rd = " << d_n_avail_read_I << std::endl); - if (!bufLen_I) - throw std::runtime_error ("circular_buffer::dequeue(): " - "input bufLen pointer is NULL.\n"); - if (!buf) - throw std::runtime_error ("circular_buffer::dequeue(): " - "input buffer pointer is NULL.\n"); - size_t l_bufLen_I = *bufLen_I; - if (l_bufLen_I == 0) - return (0); - if (l_bufLen_I > d_bufLen_I) { - std::cerr << "ERROR: cannot remove buffer longer (" - << l_bufLen_I << ") than instantiated length (" - << d_bufLen_I << ")." << std::endl; - throw std::runtime_error ("circular_buffer::dequeue()"); - } - - gruel::scoped_lock l (*d_internal); - if (d_doAbort) { - return (2); - } - if (d_doFullRead) { - while (d_n_avail_read_I < l_bufLen_I) { - DEBUG (std::cerr << "dequeue: #a < #len, waiting." << std::endl); - // wait; will automatically unlock() the internal mutex via - // the scoped lock - d_readBlock->wait (l); - // and re-lock() it here. - if (d_doAbort) { - DEBUG (std::cerr << "dequeue: #a < #len, aborting." << std::endl); - return (2); - } - DEBUG (std::cerr << "dequeue: #a < #len, done waiting." << std::endl); - } - } else { - while (d_n_avail_read_I == 0) { - DEBUG (std::cerr << "dequeue: #a == 0, waiting." << std::endl); - // wait; will automatically unlock() the internal mutex via - // the scoped lock - d_readBlock->wait (l); - // and re-lock() it here. - if (d_doAbort) { - DEBUG (std::cerr << "dequeue: #a == 0, aborting." << std::endl); - return (2); - } - DEBUG (std::cerr << "dequeue: #a == 0, done waiting." << std::endl); - } - } - if (l_bufLen_I > d_n_avail_read_I) - l_bufLen_I = d_n_avail_read_I; - size_t n_now_I = d_bufLen_I - d_readNdx_I, n_start_I = 0; - if (n_now_I > l_bufLen_I) - n_now_I = l_bufLen_I; - else if (n_now_I < l_bufLen_I) - n_start_I = l_bufLen_I - n_now_I; - bcopy (&(d_buffer[d_readNdx_I]), buf, n_now_I * sizeof (T)); - if (n_start_I) { - bcopy (d_buffer, &(buf[n_now_I]), n_start_I * sizeof (T)); - d_readNdx_I = n_start_I; - } else - d_readNdx_I += n_now_I; - *bufLen_I = l_bufLen_I; - d_n_avail_read_I -= l_bufLen_I; - d_n_avail_write_I += l_bufLen_I; - d_writeBlock->notify_one (); - return (1); - }; - - void abort () { - gruel::scoped_lock l (*d_internal); - d_doAbort = true; - d_writeBlock->notify_one (); - d_readBlock->notify_one (); - }; -}; - -#endif /* _CIRCULAR_BUFFER_H_ */ diff --git a/gr-audio/lib/portaudio/audio_portaudio_sink.cc b/gr-audio/lib/portaudio/audio_portaudio_sink.cc deleted file mode 100644 index af7f1e48c..000000000 --- a/gr-audio/lib/portaudio/audio_portaudio_sink.cc +++ /dev/null @@ -1,362 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in he hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gr_audio_registry.h" -#include <audio_portaudio_sink.h> -#include <gr_io_signature.h> -#include <gr_prefs.h> -#include <stdio.h> -#include <iostream> -#include <unistd.h> -#include <stdexcept> -#include <gri_portaudio.h> -#include <string.h> - -AUDIO_REGISTER_SINK(REG_PRIO_MED, portaudio)( - int sampling_rate, const std::string &device_name, bool ok_to_block -){ - return audio_sink::sptr(new audio_portaudio_sink(sampling_rate, device_name, ok_to_block)); -} - -//#define LOGGING 0 // define to 0 or 1 - -#define SAMPLE_FORMAT paFloat32 -typedef float sample_t; - -// Number of portaudio buffers in the ringbuffer -static const unsigned int N_BUFFERS = 4; - -static std::string -default_device_name () -{ - return gr_prefs::singleton()->get_string("audio_portaudio", "default_output_device", ""); -} - -void -audio_portaudio_sink::create_ringbuffer(void) -{ - int bufsize_samples = d_portaudio_buffer_size_frames * d_output_parameters.channelCount; - - if (d_verbose) - fprintf(stderr,"ring buffer size = %d frames\n", - N_BUFFERS*bufsize_samples/d_output_parameters.channelCount); - - // FYI, the buffer indicies are in units of samples. - d_writer = gr_make_buffer(N_BUFFERS * bufsize_samples, sizeof(sample_t)); - d_reader = gr_buffer_add_reader(d_writer, 0); -} - -/* - * This routine will be called by the PortAudio engine when audio is needed. - * It may called at interrupt level on some machines so don't do anything - * that could mess up the system like calling malloc() or free(). - * - * Our job is to write framesPerBuffer frames into outputBuffer. - */ -int -portaudio_sink_callback (const void *inputBuffer, - void *outputBuffer, - unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, - void *arg) -{ - audio_portaudio_sink *self = (audio_portaudio_sink *)arg; - int nreqd_samples = - framesPerBuffer * self->d_output_parameters.channelCount; - - int navail_samples = self->d_reader->items_available(); - - if (nreqd_samples <= navail_samples) { // We've got enough data... - { - gruel::scoped_lock guard(self->d_ringbuffer_mutex); - - memcpy(outputBuffer, - self->d_reader->read_pointer(), - nreqd_samples * sizeof(sample_t)); - self->d_reader->update_read_pointer(nreqd_samples); - - self->d_ringbuffer_ready = true; - } - - // Tell the sink thread there is new room in the ringbuffer. - self->d_ringbuffer_cond.notify_one(); - return paContinue; - } - - else { // underrun - self->d_nunderuns++; - ssize_t r = ::write(2, "aU", 2); // FIXME change to non-blocking call - if(r == -1) { - perror("audio_portaudio_source::portaudio_source_callback write error to stderr."); - } - - // FIXME we should transfer what we've got and pad the rest - memset(outputBuffer, 0, nreqd_samples * sizeof(sample_t)); - - self->d_ringbuffer_ready = true; - self->d_ringbuffer_cond.notify_one(); // Tell the sink to get going! - - return paContinue; - } -} - - -// ---------------------------------------------------------------- - -audio_portaudio_sink::audio_portaudio_sink(int sampling_rate, - const std::string device_name, - bool ok_to_block) - : gr_sync_block ("audio_portaudio_sink", - gr_make_io_signature(0, 0, 0), - gr_make_io_signature(0, 0, 0)), - d_sampling_rate(sampling_rate), - d_device_name(device_name.empty() ? default_device_name() : device_name), - d_ok_to_block(ok_to_block), - d_verbose(gr_prefs::singleton()->get_bool("audio_portaudio", "verbose", false)), - d_portaudio_buffer_size_frames(0), - d_stream(0), - d_ringbuffer_mutex(), - d_ringbuffer_cond(), - d_ringbuffer_ready(false), - d_nunderuns(0) -{ - memset(&d_output_parameters, 0, sizeof(d_output_parameters)); - //if (LOGGING) - // d_log = gri_logger::singleton(); - - PaError err; - int i, numDevices; - PaDeviceIndex device = 0; - const PaDeviceInfo *deviceInfo = NULL; - - err = Pa_Initialize(); - if (err != paNoError) { - bail ("Initialize failed", err); - } - - if (d_verbose) - gri_print_devices(); - - numDevices = Pa_GetDeviceCount(); - if (numDevices < 0) - bail("Pa Device count failed", 0); - if (numDevices == 0) - bail("no devices available", 0); - - if (d_device_name.empty()) - { - // FIXME Get smarter about picking something - fprintf(stderr,"\nUsing Default Device\n"); - device = Pa_GetDefaultOutputDevice(); - deviceInfo = Pa_GetDeviceInfo(device); - fprintf(stderr,"%s is the chosen device using %s as the host\n", - deviceInfo->name, Pa_GetHostApiInfo(deviceInfo->hostApi)->name); - } - else - { - bool found = false; - fprintf(stderr,"\nTest Devices\n"); - for (i=0;i<numDevices;i++) { - deviceInfo = Pa_GetDeviceInfo( i ); - fprintf(stderr,"Testing device name: %s",deviceInfo->name); - if (deviceInfo->maxOutputChannels <= 0) { - fprintf(stderr,"\n"); - continue; - } - if (strstr(deviceInfo->name, d_device_name.c_str())){ - fprintf(stderr," Chosen!\n"); - device = i; - fprintf(stderr,"%s using %s as the host\n",d_device_name.c_str(), - Pa_GetHostApiInfo(deviceInfo->hostApi)->name), fflush(stderr); - found = true; - deviceInfo = Pa_GetDeviceInfo(device); - i = numDevices; // force loop exit - } - else - fprintf(stderr,"\n"),fflush(stderr); - } - - if (!found){ - bail("Failed to find specified device name", 0); - exit(1); - } - } - - - d_output_parameters.device = device; - d_output_parameters.channelCount = deviceInfo->maxOutputChannels; - d_output_parameters.sampleFormat = SAMPLE_FORMAT; - d_output_parameters.suggestedLatency = deviceInfo->defaultLowOutputLatency; - d_output_parameters.hostApiSpecificStreamInfo = NULL; - - // We fill in the real channelCount in check_topology when we know - // how many inputs are connected to us. - - // Now that we know the maximum number of channels (allegedly) - // supported by the h/w, we can compute a reasonable input - // signature. The portaudio specs say that they'll accept any - // number of channels from 1 to max. - set_input_signature(gr_make_io_signature(1, deviceInfo->maxOutputChannels, - sizeof (sample_t))); -} - - -bool -audio_portaudio_sink::check_topology (int ninputs, int noutputs) -{ - PaError err; - - if (Pa_IsStreamActive(d_stream)) - { - Pa_CloseStream(d_stream); - d_stream = 0; - d_reader.reset(); // boost::shared_ptr for d_reader = 0 - d_writer.reset(); // boost::shared_ptr for d_write = 0 - } - - d_output_parameters.channelCount = ninputs; // # of channels we're really using - -#if 1 - d_portaudio_buffer_size_frames = (int)(0.0213333333 * d_sampling_rate + 0.5); // Force 1024 frame buffers at 48000 - fprintf(stderr, "Latency = %8.5f, requested sampling_rate = %g\n", // Force latency to 21.3333333.. ms - 0.0213333333, (double)d_sampling_rate); -#endif - err = Pa_OpenStream(&d_stream, - NULL, // No input - &d_output_parameters, - d_sampling_rate, - d_portaudio_buffer_size_frames, - paClipOff, - &portaudio_sink_callback, - (void*)this); - - if (err != paNoError) { - output_error_msg ("OpenStream failed", err); - return false; - } - -#if 0 - const PaStreamInfo *psi = Pa_GetStreamInfo(d_stream); - - d_portaudio_buffer_size_frames = (int)(d_output_parameters.suggestedLatency * psi->sampleRate); - fprintf(stderr, "Latency = %7.4f, psi->sampleRate = %g\n", - d_output_parameters.suggestedLatency, psi->sampleRate); -#endif - - fprintf(stderr, "d_portaudio_buffer_size_frames = %d\n", d_portaudio_buffer_size_frames); - - assert(d_portaudio_buffer_size_frames != 0); - - create_ringbuffer(); - - err = Pa_StartStream(d_stream); - if (err != paNoError) { - output_error_msg ("StartStream failed", err); - return false; - } - - return true; -} - -audio_portaudio_sink::~audio_portaudio_sink () -{ - Pa_StopStream(d_stream); // wait for output to drain - Pa_CloseStream(d_stream); - Pa_Terminate(); -} - -/* - * This version consumes everything sent to it, blocking if required. - * I think this will allow us better control of the total buffering/latency - * in the audio path. - */ -int -audio_portaudio_sink::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - const float **in = (const float **) &input_items[0]; - const unsigned nchan = d_output_parameters.channelCount; // # of channels == samples/frame - - int k; - - for (k = 0; k < noutput_items; ){ - int nframes = d_writer->space_available() / nchan; // How much space in ringbuffer - if (nframes == 0){ // no room... - if (d_ok_to_block){ - { - gruel::scoped_lock guard(d_ringbuffer_mutex); - while (!d_ringbuffer_ready) - d_ringbuffer_cond.wait(guard); - } - - continue; - } - else { - // There's no room and we're not allowed to block. - // (A USRP is most likely controlling the pacing through the pipeline.) - // We drop the samples on the ground, and say we processed them all ;) - // - // FIXME, there's probably room for a bit more finesse here. - return noutput_items; - } - } - - // We can write the smaller of the request and the room we've got - { - gruel::scoped_lock guard(d_ringbuffer_mutex); - - int nf = std::min(noutput_items - k, nframes); - float *p = (float *) d_writer->write_pointer(); - - for (int i = 0; i < nf; i++) - for (unsigned int c = 0; c < nchan; c++) - *p++ = in[c][k + i]; - - d_writer->update_write_pointer(nf * nchan); - k += nf; - - d_ringbuffer_ready = false; - } - } - - return k; // tell how many we actually did -} - -void -audio_portaudio_sink::output_error_msg (const char *msg, int err) -{ - fprintf (stderr, "audio_portaudio_sink[%s]: %s: %s\n", - d_device_name.c_str (), msg, Pa_GetErrorText(err)); -} - -void -audio_portaudio_sink::bail (const char *msg, int err) throw (std::runtime_error) -{ - output_error_msg (msg, err); - throw std::runtime_error ("audio_portaudio_sink"); -} diff --git a/gr-audio/lib/portaudio/audio_portaudio_sink.h b/gr-audio/lib/portaudio/audio_portaudio_sink.h deleted file mode 100644 index cf64d3da0..000000000 --- a/gr-audio/lib/portaudio/audio_portaudio_sink.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ -#ifndef INCLUDED_AUDIO_PORTAUDIO_SINK_H -#define INCLUDED_AUDIO_PORTAUDIO_SINK_H - -#include <gr_audio_sink.h> -#include <gr_buffer.h> -#include <gruel/thread.h> -#include <string> -#include <portaudio.h> -#include <stdexcept> -//#include <gri_logger.h> - -PaStreamCallback portaudio_sink_callback; - - -/*! - * \brief Audio sink using PORTAUDIO - * \ingroup audio_blk - * - * Input samples must be in the range [-1,1]. - */ -class audio_portaudio_sink : public audio_sink { - - friend PaStreamCallback portaudio_sink_callback; - - - unsigned int d_sampling_rate; - std::string d_device_name; - bool d_ok_to_block; - bool d_verbose; - - unsigned int d_portaudio_buffer_size_frames; // number of frames in a portaudio buffer - - PaStream *d_stream; - PaStreamParameters d_output_parameters; - - gr_buffer_sptr d_writer; // buffer used between work and callback - gr_buffer_reader_sptr d_reader; - - gruel::mutex d_ringbuffer_mutex; - gruel::condition_variable d_ringbuffer_cond; - bool d_ringbuffer_ready; - - // random stats - int d_nunderuns; // count of underruns - //gri_logger_sptr d_log; // handle to non-blocking logging instance - - void output_error_msg (const char *msg, int err); - void bail (const char *msg, int err) throw (std::runtime_error); - void create_ringbuffer(); - - -public: - audio_portaudio_sink (int sampling_rate, const std::string device_name, - bool ok_to_block); - - ~audio_portaudio_sink (); - - bool check_topology (int ninputs, int noutputs); - - int work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); -}; - -#endif /* INCLUDED_AUDIO_PORTAUDIO_SINK_H */ diff --git a/gr-audio/lib/portaudio/audio_portaudio_source.cc b/gr-audio/lib/portaudio/audio_portaudio_source.cc deleted file mode 100644 index ddb1a6fb6..000000000 --- a/gr-audio/lib/portaudio/audio_portaudio_source.cc +++ /dev/null @@ -1,374 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in he hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gr_audio_registry.h" -#include <audio_portaudio_source.h> -#include <gr_io_signature.h> -#include <gr_prefs.h> -#include <stdio.h> -#include <iostream> -#include <unistd.h> -#include <stdexcept> -#include <gri_portaudio.h> -#include <string.h> - -AUDIO_REGISTER_SOURCE(REG_PRIO_MED, portaudio)( - int sampling_rate, const std::string &device_name, bool ok_to_block -){ - return audio_source::sptr(new audio_portaudio_source(sampling_rate, device_name, ok_to_block)); -} - -//#define LOGGING 0 // define to 0 or 1 - -#define SAMPLE_FORMAT paFloat32 -typedef float sample_t; - -// Number of portaudio buffers in the ringbuffer -static const unsigned int N_BUFFERS = 4; - -static std::string -default_device_name () -{ - return gr_prefs::singleton()->get_string("audio_portaudio", "default_input_device", ""); -} - -void -audio_portaudio_source::create_ringbuffer(void) -{ - int bufsize_samples = d_portaudio_buffer_size_frames * d_input_parameters.channelCount; - - if (d_verbose) - fprintf(stderr, "ring buffer size = %d frames\n", - N_BUFFERS*bufsize_samples/d_input_parameters.channelCount); - - // FYI, the buffer indicies are in units of samples. - d_writer = gr_make_buffer(N_BUFFERS * bufsize_samples, sizeof(sample_t)); - d_reader = gr_buffer_add_reader(d_writer, 0); -} - -/* - * This routine will be called by the PortAudio engine when audio is needed. - * It may called at interrupt level on some machines so don't do anything - * that could mess up the system like calling malloc() or free(). - * - * Our job is to copy framesPerBuffer frames from inputBuffer. - */ -int -portaudio_source_callback (const void *inputBuffer, - void *outputBuffer, - unsigned long framesPerBuffer, - const PaStreamCallbackTimeInfo* timeInfo, - PaStreamCallbackFlags statusFlags, - void *arg) -{ - audio_portaudio_source *self = (audio_portaudio_source *)arg; - int nchan = self->d_input_parameters.channelCount; - int nframes_to_copy = framesPerBuffer; - int nframes_room = self->d_writer->space_available() / nchan; - - if (nframes_to_copy <= nframes_room){ // We've got room for the data .. - //if (LOGGING) - // self->d_log->printf("PAsrc cb: f/b = %4ld\n", framesPerBuffer); - - // copy from input buffer to ringbuffer - { - gruel::scoped_lock(d_ringbuffer_mutex); - - memcpy(self->d_writer->write_pointer(), - inputBuffer, - nframes_to_copy * nchan * sizeof(sample_t)); - self->d_writer->update_write_pointer(nframes_to_copy * nchan); - - // Tell the source thread there is new data in the ringbuffer. - self->d_ringbuffer_ready = true; - } - - self->d_ringbuffer_cond.notify_one(); - return paContinue; - } - - else { // overrun - self->d_noverruns++; - ssize_t r = ::write(2, "aO", 2); // FIXME change to non-blocking call - if(r == -1) { - perror("audio_portaudio_source::portaudio_source_callback write error to stderr."); - } - - self->d_ringbuffer_ready = false; - self->d_ringbuffer_cond.notify_one(); // Tell the sink to get going! - return paContinue; - } -} - - -// ---------------------------------------------------------------- - -audio_portaudio_source::audio_portaudio_source(int sampling_rate, - const std::string device_name, - bool ok_to_block) - : gr_sync_block ("audio_portaudio_source", - gr_make_io_signature(0, 0, 0), - gr_make_io_signature(0, 0, 0)), - d_sampling_rate(sampling_rate), - d_device_name(device_name.empty() ? default_device_name() : device_name), - d_ok_to_block(ok_to_block), - d_verbose(gr_prefs::singleton()->get_bool("audio_portaudio", "verbose", false)), - d_portaudio_buffer_size_frames(0), - d_stream(0), - d_ringbuffer_mutex(), - d_ringbuffer_cond(), - d_ringbuffer_ready(false), - d_noverruns(0) -{ - memset(&d_input_parameters, 0, sizeof(d_input_parameters)); - //if (LOGGING) - // d_log = gri_logger::singleton(); - - PaError err; - int i, numDevices; - PaDeviceIndex device = 0; - const PaDeviceInfo *deviceInfo = NULL; - - - err = Pa_Initialize(); - if (err != paNoError) { - bail ("Initialize failed", err); - } - - if (d_verbose) - gri_print_devices(); - - numDevices = Pa_GetDeviceCount(); - if (numDevices < 0) - bail("Pa Device count failed", 0); - if (numDevices == 0) - bail("no devices available", 0); - - if (d_device_name.empty()) - { - // FIXME Get smarter about picking something - device = Pa_GetDefaultInputDevice(); - deviceInfo = Pa_GetDeviceInfo(device); - fprintf(stderr,"%s is the chosen device using %s as the host\n", - deviceInfo->name, Pa_GetHostApiInfo(deviceInfo->hostApi)->name); - } - else - { - bool found = false; - - for (i=0;i<numDevices;i++) { - deviceInfo = Pa_GetDeviceInfo( i ); - fprintf(stderr,"Testing device name: %s",deviceInfo->name); - if (deviceInfo->maxInputChannels <= 0) { - fprintf(stderr,"\n"); - continue; - } - if (strstr(deviceInfo->name, d_device_name.c_str())){ - fprintf(stderr," Chosen!\n"); - device = i; - fprintf(stderr,"%s using %s as the host\n",d_device_name.c_str(), - Pa_GetHostApiInfo(deviceInfo->hostApi)->name), fflush(stderr); - found = true; - deviceInfo = Pa_GetDeviceInfo(device); - i = numDevices; // force loop exit - } - else - fprintf(stderr,"\n"),fflush(stderr); - } - - if (!found){ - bail("Failed to find specified device name", 0); - } - } - - - d_input_parameters.device = device; - d_input_parameters.channelCount = deviceInfo->maxInputChannels; - d_input_parameters.sampleFormat = SAMPLE_FORMAT; - d_input_parameters.suggestedLatency = deviceInfo->defaultLowInputLatency; - d_input_parameters.hostApiSpecificStreamInfo = NULL; - - // We fill in the real channelCount in check_topology when we know - // how many inputs are connected to us. - - // Now that we know the maximum number of channels (allegedly) - // supported by the h/w, we can compute a reasonable output - // signature. The portaudio specs say that they'll accept any - // number of channels from 1 to max. - set_output_signature(gr_make_io_signature(1, deviceInfo->maxInputChannels, - sizeof (sample_t))); -} - - -bool -audio_portaudio_source::check_topology (int ninputs, int noutputs) -{ - PaError err; - - if (Pa_IsStreamActive(d_stream)) - { - Pa_CloseStream(d_stream); - d_stream = 0; - d_reader.reset(); // boost::shared_ptr for d_reader = 0 - d_writer.reset(); // boost::shared_ptr for d_write = 0 - } - - d_input_parameters.channelCount = noutputs; // # of channels we're really using - -#if 1 - d_portaudio_buffer_size_frames = (int)(0.0213333333 * d_sampling_rate + 0.5); // Force 512 frame buffers at 48000 - fprintf(stderr, "Latency = %8.5f, requested sampling_rate = %g\n", // Force latency to 21.3333333.. ms - 0.0213333333, (double)d_sampling_rate); -#endif - err = Pa_OpenStream(&d_stream, - &d_input_parameters, - NULL, // No output - d_sampling_rate, - d_portaudio_buffer_size_frames, - paClipOff, - &portaudio_source_callback, - (void*)this); - - if (err != paNoError) { - output_error_msg ("OpenStream failed", err); - return false; - } - -#if 0 - const PaStreamInfo *psi = Pa_GetStreamInfo(d_stream); - - d_portaudio_buffer_size_frames = (int)(d_input_parameters.suggestedLatency * psi->sampleRate); - fprintf(stderr, "Latency = %7.4f, psi->sampleRate = %g\n", - d_input_parameters.suggestedLatency, psi->sampleRate); -#endif - - fprintf(stderr, "d_portaudio_buffer_size_frames = %d\n", d_portaudio_buffer_size_frames); - - assert(d_portaudio_buffer_size_frames != 0); - - create_ringbuffer(); - - err = Pa_StartStream(d_stream); - if (err != paNoError) { - output_error_msg ("StartStream failed", err); - return false; - } - - return true; -} - -audio_portaudio_source::~audio_portaudio_source () -{ - Pa_StopStream(d_stream); // wait for output to drain - Pa_CloseStream(d_stream); - Pa_Terminate(); -} - -int -audio_portaudio_source::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - float **out = (float **) &output_items[0]; - const unsigned nchan = d_input_parameters.channelCount; // # of channels == samples/frame - - int k; - for (k = 0; k < noutput_items; ){ - - int nframes = d_reader->items_available() / nchan; // # of frames in ringbuffer - if (nframes == 0){ // no data right now... - if (k > 0) // If we've produced anything so far, return that - return k; - - if (d_ok_to_block) { - gruel:: scoped_lock guard(d_ringbuffer_mutex); - while (d_ringbuffer_ready == false) - d_ringbuffer_cond.wait(guard); // block here, then try again - continue; - } - - assert(k == 0); - - // There's no data and we're not allowed to block. - // (A USRP is most likely controlling the pacing through the pipeline.) - // This is an underun. The scheduler wouldn't have called us if it - // had anything better to do. Thus we really need to produce some amount - // of "fill". - // - // There are lots of options for comfort noise, etc. - // FIXME We'll fill with zeros for now. Yes, it will "click"... - - // Fill with some frames of zeros - { - gruel::scoped_lock guard(d_ringbuffer_mutex); - - int nf = std::min(noutput_items - k, (int) d_portaudio_buffer_size_frames); - for (int i = 0; i < nf; i++){ - for (unsigned int c = 0; c < nchan; c++){ - out[c][k + i] = 0; - } - } - k += nf; - - d_ringbuffer_ready = false; - return k; - } - } - - // We can read the smaller of the request and what's in the buffer. - { - gruel::scoped_lock guard(d_ringbuffer_mutex); - - int nf = std::min(noutput_items - k, nframes); - - const float *p = (const float *) d_reader->read_pointer(); - for (int i = 0; i < nf; i++){ - for (unsigned int c = 0; c < nchan; c++){ - out[c][k + i] = *p++; - } - } - d_reader->update_read_pointer(nf * nchan); - k += nf; - d_ringbuffer_ready = false; - } - } - - return k; // tell how many we actually did -} - -void -audio_portaudio_source::output_error_msg (const char *msg, int err) -{ - fprintf (stderr, "audio_portaudio_source[%s]: %s: %s\n", - d_device_name.c_str (), msg, Pa_GetErrorText(err)); -} - -void -audio_portaudio_source::bail (const char *msg, int err) throw (std::runtime_error) -{ - output_error_msg (msg, err); - throw std::runtime_error ("audio_portaudio_source"); -} diff --git a/gr-audio/lib/portaudio/audio_portaudio_source.h b/gr-audio/lib/portaudio/audio_portaudio_source.h deleted file mode 100644 index e81389a3b..000000000 --- a/gr-audio/lib/portaudio/audio_portaudio_source.h +++ /dev/null @@ -1,84 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ -#ifndef INCLUDED_AUDIO_PORTAUDIO_SOURCE_H -#define INCLUDED_AUDIO_PORTAUDIO_SOURCE_H - -#include <gr_audio_source.h> -#include <gr_buffer.h> -#include <gruel/thread.h> -#include <string> -#include <portaudio.h> -#include <stdexcept> - -PaStreamCallback portaudio_source_callback; - - -/*! - * \brief Audio source using PORTAUDIO - * \ingroup audio_blk - * - * Input samples must be in the range [-1,1]. - */ -class audio_portaudio_source : public audio_source { - - friend PaStreamCallback portaudio_source_callback; - - - unsigned int d_sampling_rate; - std::string d_device_name; - bool d_ok_to_block; - bool d_verbose; - - unsigned int d_portaudio_buffer_size_frames; // number of frames in a portaudio buffer - - PaStream *d_stream; - PaStreamParameters d_input_parameters; - - gr_buffer_sptr d_writer; // buffer used between work and callback - gr_buffer_reader_sptr d_reader; - - gruel::mutex d_ringbuffer_mutex; - gruel::condition_variable d_ringbuffer_cond; - bool d_ringbuffer_ready; - - // random stats - int d_noverruns; // count of overruns - - void output_error_msg (const char *msg, int err); - void bail (const char *msg, int err) throw (std::runtime_error); - void create_ringbuffer(); - - -public: - audio_portaudio_source (int sampling_rate, const std::string device_name, - bool ok_to_block); - - ~audio_portaudio_source (); - - bool check_topology (int ninputs, int noutputs); - - int work (int ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); -}; - -#endif /* INCLUDED_AUDIO_PORTAUDIO_SOURCE_H */ diff --git a/gr-audio/lib/portaudio/gr-audio-portaudio.conf b/gr-audio/lib/portaudio/gr-audio-portaudio.conf deleted file mode 100644 index 0dd147443..000000000 --- a/gr-audio/lib/portaudio/gr-audio-portaudio.conf +++ /dev/null @@ -1,10 +0,0 @@ -# This file contains system wide configuration data for GNU Radio. -# You may override any setting on a per-user basis by editing -# ~/.gnuradio/config.conf - -[audio_portaudio] - -#default_input_device = hw:0,0 -#default_output_device = hw:0,0 - -verbose = false diff --git a/gr-audio/lib/portaudio/gri_portaudio.cc b/gr-audio/lib/portaudio/gri_portaudio.cc deleted file mode 100644 index 66f3d4647..000000000 --- a/gr-audio/lib/portaudio/gri_portaudio.cc +++ /dev/null @@ -1,111 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gri_portaudio.h> -#include <portaudio.h> -#include <string.h> - - -PaDeviceIndex -gri_pa_find_device_by_name(const char *name) -{ - int i; - int numDevices; - const PaDeviceInfo *pdi; - int len = strlen( name ); - PaDeviceIndex result = paNoDevice; - numDevices = Pa_GetDeviceCount(); - for( i=0; i<numDevices; i++ ) - { - pdi = Pa_GetDeviceInfo( i ); - if( strncmp( name, pdi->name, len ) == 0 ) - { - result = i; - break; - } - } - return result; -} - - -void -gri_print_devices() -{ - int numDevices, defaultDisplayed, myDevice=0; - const PaDeviceInfo *deviceInfo; - - numDevices = Pa_GetDeviceCount(); - if (numDevices < 0) - return; - - printf("Number of devices found = %d\n", numDevices); - - for (int i=0; i < numDevices; i++ ) { - deviceInfo = Pa_GetDeviceInfo( i ); - printf( "--------------------------------------- device #%d\n", i ); - /* Mark global and API specific default devices */ - defaultDisplayed = 0; - if( i == Pa_GetDefaultInputDevice() ) - { - myDevice = i; - printf( "[ Default Input" ); - defaultDisplayed = 1; - } - else if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultInputDevice ) - { - const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi ); - printf( "[ Default %s Input", hostInfo->name ); - defaultDisplayed = 1; - } - - if( i == Pa_GetDefaultOutputDevice() ) - { - printf( (defaultDisplayed ? "," : "[") ); - printf( " Default Output" ); - defaultDisplayed = 1; - } - else if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultOutputDevice ) - { - const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi ); - printf( (defaultDisplayed ? "," : "[") ); - printf( " Default %s Output", hostInfo->name ); - defaultDisplayed = 1; - } - if( defaultDisplayed ) - printf( " ]\n" ); - - /* print device info fields */ - printf( "Name = %s\n", deviceInfo->name ); - printf( "Host API = %s\n", Pa_GetHostApiInfo( deviceInfo->hostApi )->name ); - printf( "Max inputs = %d", deviceInfo->maxInputChannels ); - printf( ", Max outputs = %d\n", deviceInfo->maxOutputChannels ); - - printf( "Default low input latency = %8.3f\n", deviceInfo->defaultLowInputLatency ); - printf( "Default low output latency = %8.3f\n", deviceInfo->defaultLowOutputLatency ); - printf( "Default high input latency = %8.3f\n", deviceInfo->defaultHighInputLatency ); - printf( "Default high output latency = %8.3f\n", deviceInfo->defaultHighOutputLatency ); - } -} diff --git a/gr-audio/lib/portaudio/gri_portaudio.h b/gr-audio/lib/portaudio/gri_portaudio.h deleted file mode 100644 index c3ea7d064..000000000 --- a/gr-audio/lib/portaudio/gri_portaudio.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_GRI_PORTAUDIO_H -#define INCLUDED_GRI_PORTAUDIO_H - -#include <stdio.h> -#include <portaudio.h> - -PaDeviceIndex gri_pa_find_device_by_name(const char *name); -void gri_print_devices(); - -#endif /* INCLUDED_GRI_PORTAUDIO_H */ diff --git a/gr-audio/lib/windows/audio_windows_sink.cc b/gr-audio/lib/windows/audio_windows_sink.cc deleted file mode 100644 index 5284ce173..000000000 --- a/gr-audio/lib/windows/audio_windows_sink.cc +++ /dev/null @@ -1,323 +0,0 @@ -/* -*- c++ -*- */ -/* -* Copyright 2004-2011 Free Software Foundation, Inc. -* -* This file is part of GNU Radio -* -* GNU Radio is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 3, or (at your option) -* any later version. -* -* GNU Radio is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with GNU Radio; see the file COPYING. If not, write to -* the Free Software Foundation, Inc., 51 Franklin Street, -* Boston, MA 02110-1301, USA. -*/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gr_audio_registry.h" -#include <audio_windows_sink.h> -#include <gr_io_signature.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdio.h> -#include <iostream> -#include <stdexcept> -#include <string> -#include <sstream> - -AUDIO_REGISTER_SINK(REG_PRIO_HIGH, windows)( - int sampling_rate, const std::string &device_name, bool -){ - return audio_sink::sptr(new audio_windows_sink(sampling_rate, device_name)); -} - -static const double CHUNK_TIME = 0.1; //0.001; // 100 ms - -// FIXME these should query some kind of user preference - -static std::string -default_device_name () -{ - return "WAVE_MAPPER"; -} - -audio_windows_sink::audio_windows_sink (int sampling_freq, const std::string device_name) - : gr_sync_block ("audio_windows_sink", - gr_make_io_signature (1, 2, sizeof (float)), - gr_make_io_signature (0, 0, 0)), - d_sampling_freq (sampling_freq), - d_device_name (device_name.empty ()? default_device_name () : device_name), - d_fd (-1), d_buffer (0), d_chunk_size (0) -{ - d_wave_write_event = CreateEvent (NULL, FALSE, FALSE, NULL); - if (open_waveout_device () < 0) - { - //fprintf (stderr, "audio_windows_sink:open_waveout_device() failed\n"); - perror ("audio_windows_sink:open_waveout_device( ) failed\n"); - throw - std::runtime_error ("audio_windows_sink:open_waveout_device() failed"); - } - - d_chunk_size = (int) (d_sampling_freq * CHUNK_TIME); - set_output_multiple (d_chunk_size); - - d_buffer = new short[d_chunk_size * 2]; - -} - -audio_windows_sink::~audio_windows_sink () -{ - /* Free the callback Event */ - CloseHandle (d_wave_write_event); - waveOutClose (d_h_waveout); - delete[]d_buffer; -} - -int -audio_windows_sink::work (int noutput_items, - gr_vector_const_void_star & input_items, - gr_vector_void_star & output_items) -{ - const float *f0, *f1; - bool playtestsound = false; - if (playtestsound) - { - // dummy - - f0 = (const float *) input_items[0]; - - for (int i = 0; i < noutput_items; i += d_chunk_size) - { - for (int j = 0; j < d_chunk_size; j++) - { - d_buffer[2 * j + 0] = (short) (sin (2.0 * 3.1415926535897932384626 * (float) j * 1000.0 / (float) d_sampling_freq) * 8192 + 0); //+32767 - d_buffer[2 * j + 1] = d_buffer[2 * j + 0]; - } - f0 += d_chunk_size; - if (write_waveout - ((HPSTR) d_buffer, 2 * d_chunk_size * sizeof (short)) < 0) - { - fprintf (stderr, "audio_windows_sink: write failed\n"); - perror ("audio_windows_sink: write failed"); - } - } - // break; - } - else - { - switch (input_items.size ()) - { - - case 1: // mono input - - f0 = (const float *) input_items[0]; - - for (int i = 0; i < noutput_items; i += d_chunk_size) - { - for (int j = 0; j < d_chunk_size; j++) - { - d_buffer[2 * j + 0] = (short) (f0[j] * 32767); - d_buffer[2 * j + 1] = (short) (f0[j] * 32767); - } - f0 += d_chunk_size; - if (write_waveout - ((HPSTR) d_buffer, 2 * d_chunk_size * sizeof (short)) < 0) - { - //fprintf (stderr, "audio_windows_sink: write failed\n"); - perror ("audio_windows_sink: write failed"); - } - } - break; - - case 2: // stereo input - - f0 = (const float *) input_items[0]; - f1 = (const float *) input_items[1]; - - for (int i = 0; i < noutput_items; i += d_chunk_size) - { - for (int j = 0; j < d_chunk_size; j++) - { - d_buffer[2 * j + 0] = (short) (f0[j] * 32767); - d_buffer[2 * j + 1] = (short) (f1[j] * 32767); - } - f0 += d_chunk_size; - f1 += d_chunk_size; - if (write_waveout - ((HPSTR) d_buffer, 2 * d_chunk_size * sizeof (short)) < 0) - { - //fprintf (stderr, "audio_windows_sink: write failed\n"); - perror ("audio_windows_sink: write failed"); - } - } - break; - } - } - return noutput_items; -} - -int -audio_windows_sink::string_to_int (const std::string & s) -{ - int i; - std::istringstream (s) >> i; - return i; -} //ToInt() - -int -audio_windows_sink::open_waveout_device (void) -{ - - UINT /*UINT_PTR */ u_device_id; - /** Identifier of the waveform-audio output device to open. It can be either a device identifier or a handle of an open waveform-audio input device. You can use the following flag instead of a device identifier. - * - * Value Meaning - * WAVE_MAPPER The function selects a waveform-audio output device capable of playing the given format. - */ - if (d_device_name.empty () || default_device_name () == d_device_name) - u_device_id = WAVE_MAPPER; - else - u_device_id = (UINT) string_to_int (d_device_name); - // Open a waveform device for output using event callback. - - unsigned long result; - //HWAVEOUT outHandle; - WAVEFORMATEX wave_format; - - /* Initialize the WAVEFORMATEX for 16-bit, 44KHz, stereo */ - wave_format.wFormatTag = WAVE_FORMAT_PCM; - wave_format.nChannels = 2; - wave_format.nSamplesPerSec = d_sampling_freq; //44100; - wave_format.wBitsPerSample = 16; - wave_format.nBlockAlign = - wave_format.nChannels * (wave_format.wBitsPerSample / 8); - wave_format.nAvgBytesPerSec = - wave_format.nSamplesPerSec * wave_format.nBlockAlign; - wave_format.cbSize = 0; - - /* Open the (preferred) Digital Audio Out device. */ - result = waveOutOpen (&d_h_waveout, WAVE_MAPPER, &wave_format, (DWORD_PTR) d_wave_write_event, 0, CALLBACK_EVENT | WAVE_ALLOWSYNC); //|WAVE_FORMAT_DIRECT | CALLBACK_EVENT| WAVE_ALLOWSYNC - if (result) - { - fprintf (stderr, - "audio_windows_sink: Failed to open waveform output device.\n"); - perror ("audio_windows_sink: Failed to open waveform output device."); - //LocalUnlock(hFormat); - //LocalFree(hFormat); - //mmioClose(hmmio, 0); - return -1; - } - - // - // Do not Swallow the "open" event. - // - //WaitForSingleObject(d_wave_write_event, INFINITE); - - // Allocate and lock memory for the header. - - d_h_wave_hdr = GlobalAlloc (GMEM_MOVEABLE | GMEM_SHARE, - (DWORD) sizeof (WAVEHDR)); - if (d_h_wave_hdr == NULL) - { - //GlobalUnlock(hData); - //GlobalFree(hData); - //fprintf (stderr, "audio_windows_sink: Not enough memory for header.\n"); - perror ("audio_windows_sink: Not enough memory for header."); - return -1; - } - - d_lp_wave_hdr = (LPWAVEHDR) GlobalLock (d_h_wave_hdr); - if (d_lp_wave_hdr == NULL) - { - //GlobalUnlock(hData); - //GlobalFree(hData); - //fprintf (stderr, "audio_windows_sink: Failed to lock memory for header.\n"); - perror ("audio_windows_sink: Failed to lock memory for header."); - return -1; - } - //d_lp_wave_hdr->dwFlags = WHDR_DONE; - return 0; -} - -int -audio_windows_sink::write_waveout (HPSTR lp_data, DWORD dw_data_size) -{ - UINT w_result; - int teller = 100; - // After allocation, set up and prepare header. - /*while ((d_lp_wave_hdr->dwFlags & WHDR_DONE)==0 && teller>0) - { - teller--; - Sleep(1); - } */ - // Wait until previous wave write completes (first event is the open event). - WaitForSingleObject (d_wave_write_event, 100); //INFINITE - d_lp_wave_hdr->lpData = lp_data; - d_lp_wave_hdr->dwBufferLength = dw_data_size; - d_lp_wave_hdr->dwFlags = 0L; - /* Clear the WHDR_DONE bit (which the driver set last time that - this WAVEHDR was sent via waveOutWrite and was played). Some - drivers need this to be cleared */ - //d_lp_wave_hdr->dwFlags &= ~WHDR_DONE; - - d_lp_wave_hdr->dwLoops = 0L; - w_result = - waveOutPrepareHeader (d_h_waveout, d_lp_wave_hdr, sizeof (WAVEHDR)); - if (w_result != 0) - { - //GlobalUnlock( hData); - //GlobalFree(hData); - //fprintf (stderr, "audio_windows_sink: Failed to waveOutPrepareHeader. error %i\n",w_result); - perror ("audio_windows_sink: Failed to waveOutPrepareHeader"); - } - // Now the data block can be sent to the output device. The - // waveOutWrite function returns immediately and waveform - // data is sent to the output device in the background. - //while (! readyforplayback) Sleep(1); - //readyforplayback=false; - // - // - - w_result = waveOutWrite (d_h_waveout, d_lp_wave_hdr, sizeof (WAVEHDR)); - if (w_result != 0) - { - //GlobalUnlock( hData); - //GlobalFree(hData); - //fprintf (stderr, "audio_windows_sink: Failed to write block to device.error %i\n",w_result); - perror ("audio_windows_sink: Failed to write block to device"); - switch (w_result) - { - case MMSYSERR_INVALHANDLE: - fprintf (stderr, "Specified device handle is invalid. \n"); - break; - case MMSYSERR_NODRIVER: - fprintf (stderr, " No device driver is present. \n"); - break; - case MMSYSERR_NOMEM: - fprintf (stderr, " Unable to allocate or lock memory. \n"); - break; - case WAVERR_UNPREPARED: - fprintf (stderr, - " The data block pointed to by the pwh parameter hasn't been prepared. \n"); - break; - default: - fprintf (stderr, "Unknown error %i\n", w_result); - } - waveOutUnprepareHeader (d_h_waveout, d_lp_wave_hdr, sizeof (WAVEHDR)); - return -1; - } - // WaitForSingleObject(d_wave_write_event, INFINITE); - return 0; -} diff --git a/gr-audio/lib/windows/audio_windows_sink.h b/gr-audio/lib/windows/audio_windows_sink.h deleted file mode 100644 index d4ca259b3..000000000 --- a/gr-audio/lib/windows/audio_windows_sink.h +++ /dev/null @@ -1,73 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_AUDIO_WINDOWS_SINK_H -#define INCLUDED_AUDIO_WINDOWS_SINK_H - -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX // stops windef.h defining max/min under cygwin - -#include <windows.h> -#include <mmsystem.h> - -#include <gr_audio_sink.h> -#include <string> - -/*! - * \brief audio sink using winmm mmsystem (win32 only) - * \ingroup audio_blk - * - * input signature is one or two streams of floats. - * Input samples must be in the range [-1,1]. - */ - -class audio_windows_sink : public audio_sink -{ - int d_sampling_freq; - std::string d_device_name; - int d_fd; - short *d_buffer; - int d_chunk_size; - HWAVEOUT d_h_waveout; - HGLOBAL d_h_wave_hdr; - LPWAVEHDR d_lp_wave_hdr; - HANDLE d_wave_write_event; - -protected: - int - string_to_int (const std::string & s); - int - open_waveout_device (void); - int - write_waveout (HPSTR lp_data, DWORD dw_data_size); - -public: - audio_windows_sink (int sampling_freq, const std::string device_name = ""); - ~audio_windows_sink (); - - int - work (int noutput_items, - gr_vector_const_void_star & input_items, - gr_vector_void_star & output_items); -}; - -#endif /* INCLUDED_AUDIO_WINDOWS_SINK_H */ diff --git a/gr-audio/lib/windows/audio_windows_source.cc b/gr-audio/lib/windows/audio_windows_source.cc deleted file mode 100644 index 75b0a33bb..000000000 --- a/gr-audio/lib/windows/audio_windows_source.cc +++ /dev/null @@ -1,205 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gr_audio_registry.h" -#include <audio_windows_source.h> -#include <gr_io_signature.h> -//include <sys/soundcard.h> -//include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdio.h> -#include <iostream> -#include <stdexcept> - -AUDIO_REGISTER_SOURCE(REG_PRIO_HIGH, windows)( - int sampling_rate, const std::string &device_name, bool -){ - return audio_source::sptr(new audio_windows_source(sampling_rate, device_name)); -} - -static const double CHUNK_TIME = 0.005; // 5 ms - -// FIXME these should query some kind of user preference - -static std::string -default_device_name () -{ - return "/dev/dsp"; -} - -audio_windows_source::audio_windows_source (int sampling_freq, const std::string device_name) - : gr_sync_block ("audio_windows_source", - gr_make_io_signature (0, 0, 0), - gr_make_io_signature (1, 2, sizeof (float))), - d_sampling_freq (sampling_freq), - d_device_name (device_name.empty ()? default_device_name () : device_name), - d_fd (-1), d_buffer (0), d_chunk_size (0) -{ - //FIXME TODO implement me -#if 0 - if ((d_fd = open (d_device_name.c_str (), O_RDONLY)) < 0) - { - fprintf (stderr, "audio_windows_source: "); - perror (d_device_name.c_str ()); - throw - std::runtime_error ("audio_windows_source"); - } - - d_chunk_size = (int) (d_sampling_freq * CHUNK_TIME); - set_output_multiple (d_chunk_size); - - d_buffer = new short[d_chunk_size * 2]; - - int format = AFMT_S16_NE; - int orig_format = format; - if (ioctl (d_fd, SNDCTL_DSP_SETFMT, &format) < 0) - { - std:: - cerr << "audio_windows_source: " << d_device_name << - " ioctl failed\n"; - perror (d_device_name.c_str ()); - throw - std::runtime_error ("audio_windows_source"); - } - - if (format != orig_format) - { - fprintf (stderr, "audio_windows_source: unable to support format %d\n", - orig_format); - fprintf (stderr, " card requested %d instead.\n", format); - } - - // set to stereo no matter what. Some hardware only does stereo - int channels = 2; - if (ioctl (d_fd, SNDCTL_DSP_CHANNELS, &channels) < 0 || channels != 2) - { - perror ("audio_windows_source: could not set STEREO mode"); - throw - std::runtime_error ("audio_windows_source"); - } - - // set sampling freq - int sf = sampling_freq; - if (ioctl (d_fd, SNDCTL_DSP_SPEED, &sf) < 0) - { - std::cerr << "audio_windows_source: " - << d_device_name << ": invalid sampling_freq " - << sampling_freq << "\n"; - sampling_freq = 8000; - if (ioctl (d_fd, SNDCTL_DSP_SPEED, &sf) < 0) - { - std:: - cerr << - "audio_windows_source: failed to set sampling_freq to 8000\n"; - throw - std::runtime_error ("audio_windows_source"); - } - } -#endif -} - -audio_windows_source::~audio_windows_source () -{ - /*close (d_fd); - delete [] d_buffer; - */ -} - -int -audio_windows_source::work (int noutput_items, - gr_vector_const_void_star & input_items, - gr_vector_void_star & output_items) -{ - //FIXME TODO implement me -#if 0 - float *f0 = (float *) output_items[0]; - float *f1 = (float *) output_items[1]; // will be invalid if this is mono output - - const int shorts_per_item = 2; // L + R - const int bytes_per_item = shorts_per_item * sizeof (short); - - // To minimize latency, never return more than CHUNK_TIME - // worth of samples per call to work. - // FIXME, we need an API to set this value - - noutput_items = std::min (noutput_items, d_chunk_size); - - int base = 0; - int ntogo = noutput_items; - - while (ntogo > 0) - { - int nbytes = std::min (ntogo, d_chunk_size) * bytes_per_item; - int result_nbytes = read (d_fd, d_buffer, nbytes); - - if (result_nbytes < 0) - { - perror ("audio_windows_source"); - return -1; // say we're done - } - - if ((result_nbytes & (bytes_per_item - 1)) != 0) - { - fprintf (stderr, "audio_windows_source: internal error.\n"); - throw std::runtime_error ("internal error"); - } - - int result_nitems = result_nbytes / bytes_per_item; - - // now unpack samples into output streams - - switch (output_items.size ()) - { - case 1: // mono output - for (int i = 0; i < result_nitems; i++) - { - f0[base + i] = d_buffer[2 * i + 0] * (1.0 / 32767); - } - break; - - case 2: // stereo output - for (int i = 0; i < result_nitems; i++) - { - f0[base + i] = d_buffer[2 * i + 0] * (1.0 / 32767); - f1[base + i] = d_buffer[2 * i + 1] * (1.0 / 32767); - } - break; - - default: - assert (0); - } - - ntogo -= result_nitems; - base += result_nitems; - } - - return noutput_items - ntogo; -#endif - return -1; // EOF -} diff --git a/gr-audio/lib/windows/audio_windows_source.h b/gr-audio/lib/windows/audio_windows_source.h deleted file mode 100644 index 9cb789576..000000000 --- a/gr-audio/lib/windows/audio_windows_source.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004-2011 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, - * Boston, MA 02110-1301, USA. - */ - -#ifndef INCLUDED_AUDIO_WINDOWS_SOURCE_H -#define INCLUDED_AUDIO_WINDOWS_SOURCE_H - -#include <gr_audio_source.h> -#include <string> - -/*! - * \brief audio source using winmm mmsystem (win32 only) - * \ingroup audio_blk - * - * Output signature is one or two streams of floats. - * Output samples will be in the range [-1,1]. - */ - -class audio_windows_source : public audio_source -{ - - int d_sampling_freq; - std::string d_device_name; - int d_fd; - short *d_buffer; - int d_chunk_size; - -public: - audio_windows_source (int sampling_freq, const std::string device_name = ""); - - ~audio_windows_source (); - - int - work (int noutput_items, - gr_vector_const_void_star & input_items, - gr_vector_void_star & output_items); -}; - -#endif /* INCLUDED_AUDIO_WINDOWS_SOURCE_H */ |