diff options
author | Marcus Müller <mmueller@gnuradio.org> | 2019-08-07 21:45:12 +0200 |
---|---|---|
committer | Marcus Müller <marcus@hostalia.de> | 2019-08-09 23:04:28 +0200 |
commit | f7bbf2c1d8d780294f3e016aff239ca35eb6516e (patch) | |
tree | e09ab6112e02b2215b2d59ac24d3d6ea2edac745 /gr-audio/lib | |
parent | 78431dc6941e3acc67c858277dfe4a0ed583643c (diff) |
Tree: clang-format without the include sorting
Diffstat (limited to 'gr-audio/lib')
33 files changed, 5327 insertions, 5635 deletions
diff --git a/gr-audio/lib/alsa/alsa_impl.cc b/gr-audio/lib/alsa/alsa_impl.cc index 7080ae8f7a..839dca5fc6 100644 --- a/gr-audio/lib/alsa/alsa_impl.cc +++ b/gr-audio/lib/alsa/alsa_impl.cc @@ -27,149 +27,156 @@ #include "alsa_impl.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_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 + // 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 -}; +static unsigned int test_rates[] = { 8000, 16000, 22050, 32000, + 44100, 48000, 96000, 192000 }; -#define NELEMS(x) (sizeof(x)/sizeof(x[0])) +#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) +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, "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, "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); + + 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) +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; + 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; + 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/alsa_impl.h b/gr-audio/lib/alsa/alsa_impl.h index 1340ce403a..a85ef166f7 100644 --- a/gr-audio/lib/alsa/alsa_impl.h +++ b/gr-audio/lib/alsa/alsa_impl.h @@ -26,19 +26,15 @@ #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); +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); +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/alsa/alsa_sink.cc b/gr-audio/lib/alsa/alsa_sink.cc index 924e4f88a2..5df5a83dc6 100644 --- a/gr-audio/lib/alsa/alsa_sink.cc +++ b/gr-audio/lib/alsa/alsa_sink.cc @@ -34,515 +34,504 @@ #include <stdexcept> namespace gr { - namespace audio { - - sink::sptr - alsa_sink_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block) - { - return sink::sptr - (new alsa_sink(sampling_rate, device_name, ok_to_block)); - } - - static bool CHATTY_DEBUG = true; - - static snd_pcm_format_t acceptable_formats[] = { - // these are in our preferred order... - SND_PCM_FORMAT_S32, - SND_PCM_FORMAT_S16 - }; - -#define NELEMS(x) (sizeof(x)/sizeof(x[0])) - - static std::string - default_device_name() - { - return prefs::singleton()->get_string("audio_alsa", "default_output_device", "default"); - } - - static double - default_period_time() - { - return std::max(0.001, - prefs::singleton()->get_double("audio_alsa", "period_time", 0.010)); - } - - static int - default_nperiods() - { - return std::max(2L, - prefs::singleton()->get_long("audio_alsa", "nperiods", 4)); - } - - // ---------------------------------------------------------------- - - alsa_sink::alsa_sink(int sampling_rate, - const std::string device_name, - bool ok_to_block) - : sync_block("audio_alsa_sink", - io_signature::make(0, 0, 0), - io_signature::make(0, 0, 0)), - d_sampling_rate(sampling_rate), - d_device_name(device_name.empty() ? default_device_name() : device_name), - d_pcm_handle(0), - d_hw_params((snd_pcm_hw_params_t*)(new char[snd_pcm_hw_params_sizeof()])), - d_sw_params((snd_pcm_sw_params_t*)(new char[snd_pcm_sw_params_sizeof()])), - d_nperiods(default_nperiods()), - d_period_time_us((unsigned int)(default_period_time() * 1e6)), - d_period_size(0), - d_buffer_size_bytes(0), d_buffer(0), - d_worker(0), d_special_case_mono_to_stereo(false), - d_nunderuns(0), d_nsuspends(0), d_ok_to_block(ok_to_block) - { - CHATTY_DEBUG = prefs::singleton()->get_bool("audio_alsa", "verbose", false); - - int error=-1; - int dir; - - // open the device for playback - int attempts = 10; - while((error!=0)&&(attempts-->0)){ - error = snd_pcm_open(&d_pcm_handle, d_device_name.c_str(), - SND_PCM_STREAM_PLAYBACK, 0); - if(error<0){ - boost::this_thread::sleep( boost::posix_time::milliseconds(10)); - } +namespace audio { + +sink::sptr +alsa_sink_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block) +{ + return sink::sptr(new alsa_sink(sampling_rate, device_name, ok_to_block)); +} + +static bool CHATTY_DEBUG = true; + +static snd_pcm_format_t acceptable_formats[] = { + // these are in our preferred order... + SND_PCM_FORMAT_S32, + SND_PCM_FORMAT_S16 +}; + +#define NELEMS(x) (sizeof(x) / sizeof(x[0])) + +static std::string default_device_name() +{ + return prefs::singleton()->get_string( + "audio_alsa", "default_output_device", "default"); +} + +static double default_period_time() +{ + return std::max(0.001, + prefs::singleton()->get_double("audio_alsa", "period_time", 0.010)); +} + +static int default_nperiods() +{ + return std::max(2L, prefs::singleton()->get_long("audio_alsa", "nperiods", 4)); +} + +// ---------------------------------------------------------------- + +alsa_sink::alsa_sink(int sampling_rate, const std::string device_name, bool ok_to_block) + : sync_block( + "audio_alsa_sink", io_signature::make(0, 0, 0), io_signature::make(0, 0, 0)), + d_sampling_rate(sampling_rate), + d_device_name(device_name.empty() ? default_device_name() : device_name), + d_pcm_handle(0), + d_hw_params((snd_pcm_hw_params_t*)(new char[snd_pcm_hw_params_sizeof()])), + d_sw_params((snd_pcm_sw_params_t*)(new char[snd_pcm_sw_params_sizeof()])), + d_nperiods(default_nperiods()), + d_period_time_us((unsigned int)(default_period_time() * 1e6)), + d_period_size(0), + d_buffer_size_bytes(0), + d_buffer(0), + d_worker(0), + d_special_case_mono_to_stereo(false), + d_nunderuns(0), + d_nsuspends(0), + d_ok_to_block(ok_to_block) +{ + CHATTY_DEBUG = prefs::singleton()->get_bool("audio_alsa", "verbose", false); + + int error = -1; + int dir; + + // open the device for playback + int attempts = 10; + while ((error != 0) && (attempts-- > 0)) { + error = snd_pcm_open( + &d_pcm_handle, d_device_name.c_str(), SND_PCM_STREAM_PLAYBACK, 0); + if (error < 0) { + boost::this_thread::sleep(boost::posix_time::milliseconds(10)); } - if(ok_to_block == false) + } + if (ok_to_block == false) snd_pcm_nonblock(d_pcm_handle, !ok_to_block); - if(error < 0){ - GR_LOG_ERROR(d_logger, boost::format("[%1%]: %2%") \ - % (d_device_name) % (snd_strerror(error))); + if (error < 0) { + GR_LOG_ERROR(d_logger, + boost::format("[%1%]: %2%") % (d_device_name) % + (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) + // Fill params with a full configuration space for a PCM. + error = snd_pcm_hw_params_any(d_pcm_handle, d_hw_params); + if (error < 0) bail("broken configuration for playback", error); - if(CHATTY_DEBUG) + if (CHATTY_DEBUG) gri_alsa_dump_hw_params(d_pcm_handle, d_hw_params, stdout); - // now that we know how many channels the h/w can handle, set 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); + // 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) { + // 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(io_signature::make(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) + } + set_input_signature(io_signature::make(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)) + // 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) + // sampling rate + unsigned int orig_sampling_rate = d_sampling_rate; + if ((error = snd_pcm_hw_params_set_rate_near( + d_pcm_handle, d_hw_params, &d_sampling_rate, 0)) < 0) bail("failed to set rate near", error); - if(orig_sampling_rate != d_sampling_rate) { - GR_LOG_INFO(d_logger, boost::format("[%1%]: unable to support sampling rate %2%\n\tCard requested %3% instead.") \ - % snd_pcm_name(d_pcm_handle) % orig_sampling_rate \ - % d_sampling_rate); - } - - /* - * ALSA transfers data in units of "periods". - * We indirectly determine the underlying buffersize by specifying - * the number of periods we want (typically 4) and the length of each - * period in units of time (typically 1ms). - */ - unsigned int min_nperiods, max_nperiods; - snd_pcm_hw_params_get_periods_min(d_hw_params, &min_nperiods, &dir); - snd_pcm_hw_params_get_periods_max(d_hw_params, &max_nperiods, &dir); - - unsigned int orig_nperiods = d_nperiods; - d_nperiods = std::min (std::max (min_nperiods, d_nperiods), max_nperiods); - - // adjust period time so that total buffering remains more-or-less constant - d_period_time_us = (d_period_time_us * orig_nperiods) / d_nperiods; - - error = snd_pcm_hw_params_set_periods(d_pcm_handle, d_hw_params, - d_nperiods, 0); - if(error < 0) + if (orig_sampling_rate != d_sampling_rate) { + GR_LOG_INFO(d_logger, + boost::format("[%1%]: unable to support sampling rate %2%\n\tCard " + "requested %3% instead.") % + snd_pcm_name(d_pcm_handle) % orig_sampling_rate % + d_sampling_rate); + } + + /* + * ALSA transfers data in units of "periods". + * We indirectly determine the underlying buffersize by specifying + * the number of periods we want (typically 4) and the length of each + * period in units of time (typically 1ms). + */ + unsigned int min_nperiods, max_nperiods; + snd_pcm_hw_params_get_periods_min(d_hw_params, &min_nperiods, &dir); + snd_pcm_hw_params_get_periods_max(d_hw_params, &max_nperiods, &dir); + + unsigned int orig_nperiods = d_nperiods; + d_nperiods = std::min(std::max(min_nperiods, d_nperiods), max_nperiods); + + // adjust period time so that total buffering remains more-or-less constant + d_period_time_us = (d_period_time_us * orig_nperiods) / d_nperiods; + + error = snd_pcm_hw_params_set_periods(d_pcm_handle, d_hw_params, d_nperiods, 0); + if (error < 0) bail("set_periods failed", error); - dir = 0; - error = snd_pcm_hw_params_set_period_time_near(d_pcm_handle, d_hw_params, - &d_period_time_us, &dir); - if(error < 0) + dir = 0; + error = snd_pcm_hw_params_set_period_time_near( + d_pcm_handle, d_hw_params, &d_period_time_us, &dir); + if (error < 0) bail("set_period_time_near failed", error); - dir = 0; - error = snd_pcm_hw_params_get_period_size(d_hw_params, - &d_period_size, &dir); - if(error < 0) + dir = 0; + error = snd_pcm_hw_params_get_period_size(d_hw_params, &d_period_size, &dir); + if (error < 0) bail("get_period_size failed", error); - set_output_multiple(d_period_size); - } - - bool - alsa_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) + set_output_multiple(d_period_size); +} + +bool 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); + err = snd_pcm_hw_params_set_channels(d_pcm_handle, d_hw_params, nchan); - if(err < 0) { + if (err < 0) { output_error_msg("set_channels failed", err); return false; - } + } - // set the parameters into the driver... - err = snd_pcm_hw_params(d_pcm_handle, d_hw_params); - if(err < 0) { + // set the parameters into the driver... + err = snd_pcm_hw_params(d_pcm_handle, d_hw_params); + if (err < 0) { output_error_msg("snd_pcm_hw_params failed", err); return false; - } + } - // get current s/w params - err = snd_pcm_sw_params_current(d_pcm_handle, d_sw_params); - if(err < 0) + // 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. + // 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) + 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) + // 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_size_bytes = d_period_size * nchan * snd_pcm_format_size(d_format, 1); - d_buffer = new char[d_buffer_size_bytes]; + d_buffer = new char[d_buffer_size_bytes]; - if(CHATTY_DEBUG) { - GR_LOG_DEBUG(d_logger,boost::format("[%1%]: sample resolution = %2% bits") \ - % snd_pcm_name(d_pcm_handle) \ - % snd_pcm_hw_params_get_sbits(d_hw_params)); - } + if (CHATTY_DEBUG) { + GR_LOG_DEBUG(d_logger, + boost::format("[%1%]: sample resolution = %2% bits") % + snd_pcm_name(d_pcm_handle) % + snd_pcm_hw_params_get_sbits(d_hw_params)); + } - switch(d_format) { - case SND_PCM_FORMAT_S16: - if(special_case) - d_worker = &alsa_sink::work_s16_1x2; + switch (d_format) { + case SND_PCM_FORMAT_S16: + if (special_case) + d_worker = &alsa_sink::work_s16_1x2; else - d_worker = &alsa_sink::work_s16; + d_worker = &alsa_sink::work_s16; break; - case SND_PCM_FORMAT_S32: - if(special_case) - d_worker = &alsa_sink::work_s32_1x2; + case SND_PCM_FORMAT_S32: + if (special_case) + d_worker = &alsa_sink::work_s32_1x2; else - d_worker = &alsa_sink::work_s32; + d_worker = &alsa_sink::work_s32; break; - default: + default: assert(0); - } - return true; } + return true; +} - alsa_sink::~alsa_sink() - { - if(snd_pcm_state(d_pcm_handle) == SND_PCM_STATE_RUNNING) +alsa_sink::~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; - } + snd_pcm_close(d_pcm_handle); + delete[]((char*)d_hw_params); + delete[]((char*)d_sw_params); + delete[] d_buffer; +} - int - 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); +int 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); - } + // this is a call through a pointer to a method... + return (this->*d_worker)(noutput_items, input_items, output_items); +} - /* - * Work function that deals with float to S16 conversion - */ - int - alsa_sink::work_s16(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - typedef int16_t sample_t; // the type of samples we're creating - static const float scale_factor = 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) { +/* + * Work function that deals with float to S16 conversion + */ +int alsa_sink::work_s16(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + typedef int16_t sample_t; // the type of samples we're creating + static const float scale_factor = 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); - } + 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; + 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; + if (!write_buffer(buf, d_period_size, sizeof_frame)) + return -1; // No fixing this problem. Say we're done. } - /* - * Work function that deals with float to S32 conversion - */ - int - alsa_sink::work_s32(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - typedef int32_t sample_t; // the type of samples we're creating - static const float scale_factor = 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) { + return n; +} + +/* + * Work function that deals with float to S32 conversion + */ +int alsa_sink::work_s32(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + typedef int32_t sample_t; // the type of samples we're creating + static const float scale_factor = 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); - } + 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. - } + for (unsigned int chan = 0; chan < nchan; chan++) + in[chan] += d_period_size; - return n; + if (!write_buffer(buf, d_period_size, sizeof_frame)) + return -1; // No fixing this problem. Say we're done. } - /* - * Work function that deals with float to S16 conversion and - * mono to stereo kludge. - */ - int - alsa_sink::work_s16_1x2(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - typedef int16_t sample_t; // the type of samples we're creating - static const float scale_factor = 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) { + return n; +} + +/* + * Work function that deals with float to S16 conversion and + * mono to stereo kludge. + */ +int alsa_sink::work_s16_1x2(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + typedef int16_t sample_t; // the type of samples we're creating + static const float scale_factor = 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; + 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; + if (!write_buffer(buf, d_period_size, sizeof_frame)) + return -1; // No fixing this problem. Say we're done. } - /* - * Work function that deals with float to S32 conversion and - * mono to stereo kludge. - */ - int - alsa_sink::work_s32_1x2(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - typedef int32_t sample_t; // the type of samples we're creating - static const float scale_factor = 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) { + return n; +} + +/* + * Work function that deals with float to S32 conversion and + * mono to stereo kludge. + */ +int alsa_sink::work_s32_1x2(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + typedef int32_t sample_t; // the type of samples we're creating + static const float scale_factor = 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; + 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; + if (!write_buffer(buf, d_period_size, sizeof_frame)) + return -1; // No fixing this problem. Say we're done. } - bool - alsa_sink::write_buffer(const void *vbuffer, - unsigned nframes, unsigned sizeof_frame) - { - const unsigned char *buffer = (const unsigned char *)vbuffer; + return n; +} - while(nframes > 0){ +bool 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; + 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 == -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 } #ifdef ESTRPIPE - else if(r == -ESTRPIPE) { // h/w is suspended (whatever that means) - // This is apparently related to power management - d_nsuspends++; - if((r = snd_pcm_resume (d_pcm_handle)) < 0) { - output_error_msg("failed to resume from suspend", r); - return false; - } - continue; // try again + else if (r == -ESTRPIPE) { // h/w is suspended (whatever that means) + // This is apparently related to power management + d_nsuspends++; + if ((r = snd_pcm_resume(d_pcm_handle)) < 0) { + output_error_msg("failed to resume from suspend", r); + return false; + } + continue; // try again } #endif else if (r < 0) { - output_error_msg("snd_pcm_writei failed", r); - return false; + output_error_msg("snd_pcm_writei failed", r); + return false; } nframes -= r; buffer += r * sizeof_frame; - } - - return true; } - void - alsa_sink::output_error_msg (const char *msg, int err) - { - GR_LOG_ERROR(d_logger, boost::format("[%1%]: %2%: %3%") \ - % snd_pcm_name(d_pcm_handle) % msg % snd_strerror(err)); - } + return true; +} - void - alsa_sink::bail(const char *msg, int err) - { - output_error_msg(msg, err); - throw std::runtime_error("audio_alsa_sink"); - } +void alsa_sink::output_error_msg(const char* msg, int err) +{ + GR_LOG_ERROR(d_logger, + boost::format("[%1%]: %2%: %3%") % snd_pcm_name(d_pcm_handle) % msg % + snd_strerror(err)); +} + +void alsa_sink::bail(const char* msg, int err) +{ + output_error_msg(msg, err); + throw std::runtime_error("audio_alsa_sink"); +} - } /* namespace audio */ +} /* namespace audio */ } /* namespace gr */ diff --git a/gr-audio/lib/alsa/alsa_sink.h b/gr-audio/lib/alsa/alsa_sink.h index 27ca047507..50edc99616 100644 --- a/gr-audio/lib/alsa/alsa_sink.h +++ b/gr-audio/lib/alsa/alsa_sink.h @@ -33,79 +33,77 @@ #include <stdexcept> namespace gr { - namespace audio { - - /*! - * \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 alsa_sink : public sink - { - // typedef for pointer to class work method - typedef int(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); - - public: - alsa_sink(int sampling_rate, - const std::string device_name, - bool ok_to_block); - ~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); - }; - - } /* namespace audio */ +namespace audio { + +/*! + * \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 alsa_sink : public sink +{ + // typedef for pointer to class work method + typedef int (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); + +public: + alsa_sink(int sampling_rate, const std::string device_name, bool ok_to_block); + ~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); +}; + +} /* namespace audio */ } /* namespace gr */ #endif /* INCLUDED_AUDIO_ALSA_SINK_H */ diff --git a/gr-audio/lib/alsa/alsa_source.cc b/gr-audio/lib/alsa/alsa_source.cc index 6655849362..82443268c4 100644 --- a/gr-audio/lib/alsa/alsa_source.cc +++ b/gr-audio/lib/alsa/alsa_source.cc @@ -34,480 +34,468 @@ #include <stdexcept> namespace gr { - namespace audio { - - source::sptr - alsa_source_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block) - { - return source::sptr - (new alsa_source(sampling_rate, device_name, ok_to_block)); - } - - static bool CHATTY_DEBUG = false; - - static snd_pcm_format_t acceptable_formats[] = { - // these are in our preferred order... - SND_PCM_FORMAT_S32, - SND_PCM_FORMAT_S16 - }; - -#define NELEMS(x) (sizeof(x)/sizeof(x[0])) - - static std::string - default_device_name() - { - return prefs::singleton()->get_string("audio_alsa", - "default_input_device", - "default"); - } - - static double - default_period_time() - { - return std::max(0.001, - prefs::singleton()->get_double("audio_alsa", "period_time", 0.010)); - } - - static int - default_nperiods() - { - return std::max(2L, - prefs::singleton()->get_long("audio_alsa", "nperiods", 4)); - } - - // ---------------------------------------------------------------- - - alsa_source::alsa_source(int sampling_rate, - const std::string device_name, - bool ok_to_block) - : sync_block("audio_alsa_source", - io_signature::make(0, 0, 0), - io_signature::make(0, 0, 0)), - d_sampling_rate(sampling_rate), - d_device_name(device_name.empty() ? default_device_name() : device_name), - d_pcm_handle(0), - d_hw_params((snd_pcm_hw_params_t*)(new char[snd_pcm_hw_params_sizeof()])), - d_sw_params((snd_pcm_sw_params_t*)(new char[snd_pcm_sw_params_sizeof()])), - d_nperiods(default_nperiods()), - d_period_time_us((unsigned int)(default_period_time() * 1e6)), - d_period_size(0), - d_buffer_size_bytes(0), d_buffer(0), - d_worker(0), d_hw_nchan(0), - d_special_case_stereo_to_mono(false), - d_noverruns(0), d_nsuspends(0) - { - CHATTY_DEBUG = prefs::singleton()->get_bool("audio_alsa", "verbose", false); - - int error; - int dir; - - // open the device for capture - error = snd_pcm_open(&d_pcm_handle, d_device_name.c_str(), - SND_PCM_STREAM_CAPTURE, 0); - if(error < 0){ - GR_LOG_ERROR(d_logger, boost::format("[%1%]: %2%") \ - % (d_device_name) % (snd_strerror(error))); +namespace audio { + +source::sptr +alsa_source_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block) +{ + return source::sptr(new alsa_source(sampling_rate, device_name, ok_to_block)); +} + +static bool CHATTY_DEBUG = false; + +static snd_pcm_format_t acceptable_formats[] = { + // these are in our preferred order... + SND_PCM_FORMAT_S32, + SND_PCM_FORMAT_S16 +}; + +#define NELEMS(x) (sizeof(x) / sizeof(x[0])) + +static std::string default_device_name() +{ + return prefs::singleton()->get_string( + "audio_alsa", "default_input_device", "default"); +} + +static double default_period_time() +{ + return std::max(0.001, + prefs::singleton()->get_double("audio_alsa", "period_time", 0.010)); +} + +static int default_nperiods() +{ + return std::max(2L, prefs::singleton()->get_long("audio_alsa", "nperiods", 4)); +} + +// ---------------------------------------------------------------- + +alsa_source::alsa_source(int sampling_rate, + const std::string device_name, + bool ok_to_block) + : sync_block( + "audio_alsa_source", io_signature::make(0, 0, 0), io_signature::make(0, 0, 0)), + d_sampling_rate(sampling_rate), + d_device_name(device_name.empty() ? default_device_name() : device_name), + d_pcm_handle(0), + d_hw_params((snd_pcm_hw_params_t*)(new char[snd_pcm_hw_params_sizeof()])), + d_sw_params((snd_pcm_sw_params_t*)(new char[snd_pcm_sw_params_sizeof()])), + d_nperiods(default_nperiods()), + d_period_time_us((unsigned int)(default_period_time() * 1e6)), + d_period_size(0), + d_buffer_size_bytes(0), + d_buffer(0), + d_worker(0), + d_hw_nchan(0), + d_special_case_stereo_to_mono(false), + d_noverruns(0), + d_nsuspends(0) +{ + CHATTY_DEBUG = prefs::singleton()->get_bool("audio_alsa", "verbose", false); + + int error; + int dir; + + // open the device for capture + error = snd_pcm_open(&d_pcm_handle, d_device_name.c_str(), SND_PCM_STREAM_CAPTURE, 0); + if (error < 0) { + GR_LOG_ERROR(d_logger, + boost::format("[%1%]: %2%") % (d_device_name) % + (snd_strerror(error))); throw std::runtime_error("audio_alsa_source"); - } + } - // Fill params with a full configuration space for a PCM. - error = snd_pcm_hw_params_any(d_pcm_handle, d_hw_params); - if(error < 0) + // Fill params with a full configuration space for a PCM. + error = snd_pcm_hw_params_any(d_pcm_handle, d_hw_params); + if (error < 0) bail("broken configuration for playback", error); - if(CHATTY_DEBUG) + if (CHATTY_DEBUG) gri_alsa_dump_hw_params(d_pcm_handle, d_hw_params, stdout); - // now that we know how many channels the h/w can handle, set output signature - unsigned int umax_chan; - unsigned int umin_chan; - snd_pcm_hw_params_get_channels_min(d_hw_params, &umin_chan); - snd_pcm_hw_params_get_channels_max(d_hw_params, &umax_chan); - int min_chan = std::min(umin_chan, 1000U); - int max_chan = std::min(umax_chan, 1000U); - - // As a special case, if the hw's min_chan is two, we'll accept - // a single output and handle the demux ourselves. - if(min_chan == 2) { + // now that we know how many channels the h/w can handle, set output signature + unsigned int umax_chan; + unsigned int umin_chan; + snd_pcm_hw_params_get_channels_min(d_hw_params, &umin_chan); + snd_pcm_hw_params_get_channels_max(d_hw_params, &umax_chan); + int min_chan = std::min(umin_chan, 1000U); + int max_chan = std::min(umax_chan, 1000U); + + // As a special case, if the hw's min_chan is two, we'll accept + // a single output and handle the demux ourselves. + if (min_chan == 2) { min_chan = 1; d_special_case_stereo_to_mono = true; - } + } - set_output_signature(io_signature::make(min_chan, max_chan, - sizeof(float))); + set_output_signature(io_signature::make(min_chan, max_chan, sizeof(float))); - // fill in portions of the d_hw_params that we know now... + // fill in portions of the d_hw_params that we know now... - // Specify the access methods we implement - // For now, we only handle RW_INTERLEAVED... - snd_pcm_access_mask_t *access_mask; - snd_pcm_access_mask_t **access_mask_ptr = &access_mask; // FIXME: workaround for compiler warning - snd_pcm_access_mask_alloca(access_mask_ptr); - snd_pcm_access_mask_none(access_mask); - snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED); - // snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED); + // Specify the access methods we implement + // For now, we only handle RW_INTERLEAVED... + snd_pcm_access_mask_t* access_mask; + snd_pcm_access_mask_t** access_mask_ptr = + &access_mask; // FIXME: workaround for compiler warning + snd_pcm_access_mask_alloca(access_mask_ptr); + snd_pcm_access_mask_none(access_mask); + snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_RW_INTERLEAVED); + // snd_pcm_access_mask_set(access_mask, SND_PCM_ACCESS_RW_NONINTERLEAVED); - if((error = snd_pcm_hw_params_set_access_mask(d_pcm_handle, - d_hw_params, access_mask)) < 0) + if ((error = snd_pcm_hw_params_set_access_mask( + d_pcm_handle, d_hw_params, access_mask)) < 0) bail("failed to set access mask", error); - // set sample format - if(!gri_alsa_pick_acceptable_format(d_pcm_handle, d_hw_params, - acceptable_formats, - NELEMS(acceptable_formats), - &d_format, - "audio_alsa_source", - CHATTY_DEBUG)) + // set sample format + if (!gri_alsa_pick_acceptable_format(d_pcm_handle, + d_hw_params, + acceptable_formats, + NELEMS(acceptable_formats), + &d_format, + "audio_alsa_source", + CHATTY_DEBUG)) throw std::runtime_error("audio_alsa_source"); - // sampling rate - unsigned int orig_sampling_rate = d_sampling_rate; - if((error = snd_pcm_hw_params_set_rate_near(d_pcm_handle, d_hw_params, - &d_sampling_rate, 0)) < 0) + // sampling rate + unsigned int orig_sampling_rate = d_sampling_rate; + if ((error = snd_pcm_hw_params_set_rate_near( + d_pcm_handle, d_hw_params, &d_sampling_rate, 0)) < 0) bail("failed to set rate near", error); - if(orig_sampling_rate != d_sampling_rate){ - GR_LOG_INFO(d_logger, boost::format("[%1%]: unable to support sampling rate %2%\n\tCard requested %3% instead.") \ - % snd_pcm_name(d_pcm_handle) % orig_sampling_rate \ - % d_sampling_rate); - } - - /* - * ALSA transfers data in units of "periods". - * We indirectly determine the underlying buffersize by specifying - * the number of periods we want (typically 4) and the length of each - * period in units of time (typically 1ms). - */ - unsigned int min_nperiods, max_nperiods; - snd_pcm_hw_params_get_periods_min(d_hw_params, &min_nperiods, &dir); - snd_pcm_hw_params_get_periods_max(d_hw_params, &max_nperiods, &dir); - - unsigned int orig_nperiods = d_nperiods; - d_nperiods = std::min(std::max (min_nperiods, d_nperiods), max_nperiods); - - // adjust period time so that total buffering remains more-or-less constant - d_period_time_us = (d_period_time_us * orig_nperiods) / d_nperiods; - - error = snd_pcm_hw_params_set_periods(d_pcm_handle, d_hw_params, - d_nperiods, 0); - if(error < 0) + if (orig_sampling_rate != d_sampling_rate) { + GR_LOG_INFO(d_logger, + boost::format("[%1%]: unable to support sampling rate %2%\n\tCard " + "requested %3% instead.") % + snd_pcm_name(d_pcm_handle) % orig_sampling_rate % + d_sampling_rate); + } + + /* + * ALSA transfers data in units of "periods". + * We indirectly determine the underlying buffersize by specifying + * the number of periods we want (typically 4) and the length of each + * period in units of time (typically 1ms). + */ + unsigned int min_nperiods, max_nperiods; + snd_pcm_hw_params_get_periods_min(d_hw_params, &min_nperiods, &dir); + snd_pcm_hw_params_get_periods_max(d_hw_params, &max_nperiods, &dir); + + unsigned int orig_nperiods = d_nperiods; + d_nperiods = std::min(std::max(min_nperiods, d_nperiods), max_nperiods); + + // adjust period time so that total buffering remains more-or-less constant + d_period_time_us = (d_period_time_us * orig_nperiods) / d_nperiods; + + error = snd_pcm_hw_params_set_periods(d_pcm_handle, d_hw_params, d_nperiods, 0); + if (error < 0) bail("set_periods failed", error); - dir = 0; - error = snd_pcm_hw_params_set_period_time_near(d_pcm_handle, d_hw_params, - &d_period_time_us, &dir); - if(error < 0) + dir = 0; + error = snd_pcm_hw_params_set_period_time_near( + d_pcm_handle, d_hw_params, &d_period_time_us, &dir); + if (error < 0) bail("set_period_time_near failed", error); - dir = 0; - error = snd_pcm_hw_params_get_period_size(d_hw_params, - &d_period_size, &dir); - if(error < 0) + dir = 0; + error = snd_pcm_hw_params_get_period_size(d_hw_params, &d_period_size, &dir); + if (error < 0) bail("get_period_size failed", error); - set_output_multiple(d_period_size); - } - - bool - alsa_source::check_topology(int ninputs, int noutputs) - { - // noutputs is how many channels the user has connected. - // Now we can finish up setting up the hw params... - - unsigned int nchan = noutputs; - int err; - - // Check the state of the stream - // Ensure that the pcm is in a state where we can still mess with the hw_params - snd_pcm_state_t state; - state=snd_pcm_state(d_pcm_handle); - if(state== SND_PCM_STATE_RUNNING) - return true; // If stream is running, don't change any parameters - else if(state == SND_PCM_STATE_XRUN) - snd_pcm_prepare(d_pcm_handle); // Prepare stream on underrun, and we can set parameters; - - bool special_case = nchan == 1 && d_special_case_stereo_to_mono; - if(special_case) + set_output_multiple(d_period_size); +} + +bool alsa_source::check_topology(int ninputs, int noutputs) +{ + // noutputs is how many channels the user has connected. + // Now we can finish up setting up the hw params... + + unsigned int nchan = noutputs; + int err; + + // Check the state of the stream + // Ensure that the pcm is in a state where we can still mess with the hw_params + snd_pcm_state_t state; + state = snd_pcm_state(d_pcm_handle); + if (state == SND_PCM_STATE_RUNNING) + return true; // If stream is running, don't change any parameters + else if (state == SND_PCM_STATE_XRUN) + snd_pcm_prepare( + d_pcm_handle); // Prepare stream on underrun, and we can set parameters; + + bool special_case = nchan == 1 && d_special_case_stereo_to_mono; + if (special_case) nchan = 2; - d_hw_nchan = nchan; - err = snd_pcm_hw_params_set_channels(d_pcm_handle, d_hw_params, d_hw_nchan); - if(err < 0) { + d_hw_nchan = nchan; + err = snd_pcm_hw_params_set_channels(d_pcm_handle, d_hw_params, d_hw_nchan); + if (err < 0) { output_error_msg("set_channels failed", err); return false; - } + } - // set the parameters into the driver... - err = snd_pcm_hw_params(d_pcm_handle, d_hw_params); - if(err < 0) { + // set the parameters into the driver... + err = snd_pcm_hw_params(d_pcm_handle, d_hw_params); + if (err < 0) { output_error_msg("snd_pcm_hw_params failed", err); return false; - } + } - d_buffer_size_bytes = - d_period_size * d_hw_nchan * snd_pcm_format_size(d_format, 1); + d_buffer_size_bytes = d_period_size * d_hw_nchan * snd_pcm_format_size(d_format, 1); - d_buffer = new char[d_buffer_size_bytes]; + d_buffer = new char[d_buffer_size_bytes]; - if(CHATTY_DEBUG) { - GR_LOG_DEBUG(d_logger, boost::format("[%1%]: sample resolution = %2% bits") \ - % snd_pcm_name(d_pcm_handle) \ - % snd_pcm_hw_params_get_sbits(d_hw_params)); - } + if (CHATTY_DEBUG) { + GR_LOG_DEBUG(d_logger, + boost::format("[%1%]: sample resolution = %2% bits") % + snd_pcm_name(d_pcm_handle) % + snd_pcm_hw_params_get_sbits(d_hw_params)); + } - switch(d_format) { - case SND_PCM_FORMAT_S16: - if(special_case) - d_worker = &alsa_source::work_s16_2x1; + switch (d_format) { + case SND_PCM_FORMAT_S16: + if (special_case) + d_worker = &alsa_source::work_s16_2x1; else - d_worker = &alsa_source::work_s16; + d_worker = &alsa_source::work_s16; break; - case SND_PCM_FORMAT_S32: - if(special_case) - d_worker = &alsa_source::work_s32_2x1; + case SND_PCM_FORMAT_S32: + if (special_case) + d_worker = &alsa_source::work_s32_2x1; else - d_worker = &alsa_source::work_s32; + d_worker = &alsa_source::work_s32; break; - default: + default: assert(0); - } - - return true; } - alsa_source::~alsa_source() - { - if(snd_pcm_state(d_pcm_handle) == SND_PCM_STATE_RUNNING) + return true; +} + +alsa_source::~alsa_source() +{ + if (snd_pcm_state(d_pcm_handle) == SND_PCM_STATE_RUNNING) snd_pcm_drop(d_pcm_handle); - snd_pcm_close(d_pcm_handle); - delete [] ((char*)d_hw_params); - delete [] ((char*)d_sw_params); - delete [] d_buffer; - } + snd_pcm_close(d_pcm_handle); + delete[]((char*)d_hw_params); + delete[]((char*)d_sw_params); + delete[] d_buffer; +} - int - alsa_source::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - assert((noutput_items % d_period_size) == 0); - assert(noutput_items != 0); +int alsa_source::work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + assert((noutput_items % d_period_size) == 0); + assert(noutput_items != 0); - // this is a call through a pointer to a method... - return (this->*d_worker)(noutput_items, input_items, output_items); - } + // this is a call through a pointer to a method... + return (this->*d_worker)(noutput_items, input_items, output_items); +} - /* - * Work function that deals with float to S16 conversion - */ - int - alsa_source::work_s16(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - typedef int16_t sample_t; // the type of samples we're creating - static const float scale_factor = 1.0 / std::pow(2.0f, 16-1); - - unsigned int nchan = output_items.size (); - float **out = (float **)&output_items[0]; - sample_t *buf = (sample_t *)d_buffer; - int bi; - - unsigned int sizeof_frame = d_hw_nchan * sizeof (sample_t); - assert(d_buffer_size_bytes == d_period_size * sizeof_frame); - - // To minimize latency, return at most a single period's worth of samples. - // [We could also read the first one in a blocking mode and subsequent - // ones in non-blocking mode, but we'll leave that for later (or never).] - - if(!read_buffer(buf, d_period_size, sizeof_frame)) - return -1; // No fixing this problem. Say we're done. - - // process one period of data - bi = 0; - for(unsigned int i = 0; i < d_period_size; i++) { - for(unsigned int chan = 0; chan < nchan; chan++) { - out[chan][i] = (float) buf[bi++] * scale_factor; +/* + * Work function that deals with float to S16 conversion + */ +int alsa_source::work_s16(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + typedef int16_t sample_t; // the type of samples we're creating + static const float scale_factor = 1.0 / std::pow(2.0f, 16 - 1); + + unsigned int nchan = output_items.size(); + float** out = (float**)&output_items[0]; + sample_t* buf = (sample_t*)d_buffer; + int bi; + + unsigned int sizeof_frame = d_hw_nchan * sizeof(sample_t); + assert(d_buffer_size_bytes == d_period_size * sizeof_frame); + + // To minimize latency, return at most a single period's worth of samples. + // [We could also read the first one in a blocking mode and subsequent + // ones in non-blocking mode, but we'll leave that for later (or never).] + + if (!read_buffer(buf, d_period_size, sizeof_frame)) + return -1; // No fixing this problem. Say we're done. + + // process one period of data + bi = 0; + for (unsigned int i = 0; i < d_period_size; i++) { + for (unsigned int chan = 0; chan < nchan; chan++) { + out[chan][i] = (float)buf[bi++] * scale_factor; } - } - - return d_period_size; } - /* - * Work function that deals with float to S16 conversion - * and stereo to mono kludge... - */ - int - alsa_source::work_s16_2x1(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - typedef int16_t sample_t; // the type of samples we're creating - static const float scale_factor = 1.0 / std::pow(2.0f, 16-1); - - float **out = (float**)&output_items[0]; - sample_t *buf = (sample_t*)d_buffer; - int bi; - - assert(output_items.size () == 1); - - unsigned int sizeof_frame = d_hw_nchan * sizeof(sample_t); - assert(d_buffer_size_bytes == d_period_size * sizeof_frame); - - // To minimize latency, return at most a single period's worth of samples. - // [We could also read the first one in a blocking mode and subsequent - // ones in non-blocking mode, but we'll leave that for later (or never).] - if(!read_buffer (buf, d_period_size, sizeof_frame)) - return -1; // No fixing this problem. Say we're done. - - // process one period of data - bi = 0; - for(unsigned int i = 0; i < d_period_size; i++) { - int t = (buf[bi] + buf[bi+1]) / 2; - bi += 2; - out[0][i] = (float) t * scale_factor; - } + return d_period_size; +} - return d_period_size; +/* + * Work function that deals with float to S16 conversion + * and stereo to mono kludge... + */ +int alsa_source::work_s16_2x1(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + typedef int16_t sample_t; // the type of samples we're creating + static const float scale_factor = 1.0 / std::pow(2.0f, 16 - 1); + + float** out = (float**)&output_items[0]; + sample_t* buf = (sample_t*)d_buffer; + int bi; + + assert(output_items.size() == 1); + + unsigned int sizeof_frame = d_hw_nchan * sizeof(sample_t); + assert(d_buffer_size_bytes == d_period_size * sizeof_frame); + + // To minimize latency, return at most a single period's worth of samples. + // [We could also read the first one in a blocking mode and subsequent + // ones in non-blocking mode, but we'll leave that for later (or never).] + if (!read_buffer(buf, d_period_size, sizeof_frame)) + return -1; // No fixing this problem. Say we're done. + + // process one period of data + bi = 0; + for (unsigned int i = 0; i < d_period_size; i++) { + int t = (buf[bi] + buf[bi + 1]) / 2; + bi += 2; + out[0][i] = (float)t * scale_factor; } - /* - * Work function that deals with float to S32 conversion - */ - int - alsa_source::work_s32(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - typedef int32_t sample_t; // the type of samples we're creating - static const float scale_factor = 1.0 / std::pow(2.0f, 32-1); - - unsigned int nchan = output_items.size (); - float **out = (float**)&output_items[0]; - sample_t *buf = (sample_t*)d_buffer; - int bi; - - unsigned int sizeof_frame = d_hw_nchan * sizeof(sample_t); - assert(d_buffer_size_bytes == d_period_size * sizeof_frame); - - // To minimize latency, return at most a single period's worth of samples. - // [We could also read the first one in a blocking mode and subsequent - // ones in non-blocking mode, but we'll leave that for later (or never).] - - if(!read_buffer(buf, d_period_size, sizeof_frame)) - return -1; // No fixing this problem. Say we're done. - - // process one period of data - bi = 0; - for(unsigned int i = 0; i < d_period_size; i++) { - for(unsigned int chan = 0; chan < nchan; chan++) { - out[chan][i] = (float) buf[bi++] * scale_factor; - } - } + return d_period_size; +} - return d_period_size; +/* + * Work function that deals with float to S32 conversion + */ +int alsa_source::work_s32(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + typedef int32_t sample_t; // the type of samples we're creating + static const float scale_factor = 1.0 / std::pow(2.0f, 32 - 1); + + unsigned int nchan = output_items.size(); + float** out = (float**)&output_items[0]; + sample_t* buf = (sample_t*)d_buffer; + int bi; + + unsigned int sizeof_frame = d_hw_nchan * sizeof(sample_t); + assert(d_buffer_size_bytes == d_period_size * sizeof_frame); + + // To minimize latency, return at most a single period's worth of samples. + // [We could also read the first one in a blocking mode and subsequent + // ones in non-blocking mode, but we'll leave that for later (or never).] + + if (!read_buffer(buf, d_period_size, sizeof_frame)) + return -1; // No fixing this problem. Say we're done. + + // process one period of data + bi = 0; + for (unsigned int i = 0; i < d_period_size; i++) { + for (unsigned int chan = 0; chan < nchan; chan++) { + out[chan][i] = (float)buf[bi++] * scale_factor; + } } - /* - * Work function that deals with float to S32 conversion - * and stereo to mono kludge... - */ - int - alsa_source::work_s32_2x1(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - typedef int32_t sample_t; // the type of samples we're creating - static const float scale_factor = 1.0 / std::pow(2.0f, 32-1); - - float **out = (float**)&output_items[0]; - sample_t *buf = (sample_t*)d_buffer; - int bi; - - assert(output_items.size () == 1); - - unsigned int sizeof_frame = d_hw_nchan * sizeof(sample_t); - assert(d_buffer_size_bytes == d_period_size * sizeof_frame); - - // To minimize latency, return at most a single period's worth of samples. - // [We could also read the first one in a blocking mode and subsequent - // ones in non-blocking mode, but we'll leave that for later (or never).] - - if(!read_buffer(buf, d_period_size, sizeof_frame)) - return -1; // No fixing this problem. Say we're done. - - // process one period of data - bi = 0; - for(unsigned int i = 0; i < d_period_size; i++) { - int t = (buf[bi] + buf[bi+1]) / 2; + return d_period_size; +} + +/* + * Work function that deals with float to S32 conversion + * and stereo to mono kludge... + */ +int alsa_source::work_s32_2x1(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + typedef int32_t sample_t; // the type of samples we're creating + static const float scale_factor = 1.0 / std::pow(2.0f, 32 - 1); + + float** out = (float**)&output_items[0]; + sample_t* buf = (sample_t*)d_buffer; + int bi; + + assert(output_items.size() == 1); + + unsigned int sizeof_frame = d_hw_nchan * sizeof(sample_t); + assert(d_buffer_size_bytes == d_period_size * sizeof_frame); + + // To minimize latency, return at most a single period's worth of samples. + // [We could also read the first one in a blocking mode and subsequent + // ones in non-blocking mode, but we'll leave that for later (or never).] + + if (!read_buffer(buf, d_period_size, sizeof_frame)) + return -1; // No fixing this problem. Say we're done. + + // process one period of data + bi = 0; + for (unsigned int i = 0; i < d_period_size; i++) { + int t = (buf[bi] + buf[bi + 1]) / 2; bi += 2; out[0][i] = (float)t * scale_factor; - } - - return d_period_size; } - bool - alsa_source::read_buffer(void *vbuffer, unsigned nframes, unsigned sizeof_frame) - { - unsigned char *buffer = (unsigned char*)vbuffer; - - while(nframes > 0) { - int r = snd_pcm_readi (d_pcm_handle, buffer, nframes); - if(r == -EAGAIN) - continue; // try again - - else if(r == -EPIPE) { // overrun - d_noverruns++; - fputs("aO", stderr); - if((r = snd_pcm_prepare (d_pcm_handle)) < 0) { - output_error_msg("snd_pcm_prepare failed. Can't recover from overrun", r); - return false; - } - continue; // try again + return d_period_size; +} + +bool alsa_source::read_buffer(void* vbuffer, unsigned nframes, unsigned sizeof_frame) +{ + unsigned char* buffer = (unsigned char*)vbuffer; + + while (nframes > 0) { + int r = snd_pcm_readi(d_pcm_handle, buffer, nframes); + if (r == -EAGAIN) + continue; // try again + + else if (r == -EPIPE) { // overrun + d_noverruns++; + fputs("aO", stderr); + if ((r = snd_pcm_prepare(d_pcm_handle)) < 0) { + output_error_msg("snd_pcm_prepare failed. Can't recover from overrun", r); + return false; + } + continue; // try again } #ifdef ESTRPIPE - else if(r == -ESTRPIPE) { // h/w is suspended (whatever that means) - // This is apparently related to power management - d_nsuspends++; - if((r = snd_pcm_resume (d_pcm_handle)) < 0) { - output_error_msg ("failed to resume from suspend", r); - return false; - } - continue; // try again + else if (r == -ESTRPIPE) { // h/w is suspended (whatever that means) + // This is apparently related to power management + d_nsuspends++; + if ((r = snd_pcm_resume(d_pcm_handle)) < 0) { + output_error_msg("failed to resume from suspend", r); + return false; + } + continue; // try again } #endif - else if(r < 0) { - output_error_msg("snd_pcm_readi failed", r); - return false; + else if (r < 0) { + output_error_msg("snd_pcm_readi failed", r); + return false; } nframes -= r; buffer += r * sizeof_frame; - } - - return true; } - void - alsa_source::output_error_msg(const char *msg, int err) - { - GR_LOG_ERROR(d_logger, boost::format("[%1%]: %2%: %3%") \ - % snd_pcm_name(d_pcm_handle) % msg % snd_strerror(err)); - } + return true; +} - void - alsa_source::bail(const char *msg, int err) - { - output_error_msg(msg, err); - throw std::runtime_error("audio_alsa_source"); - } +void alsa_source::output_error_msg(const char* msg, int err) +{ + GR_LOG_ERROR(d_logger, + boost::format("[%1%]: %2%: %3%") % snd_pcm_name(d_pcm_handle) % msg % + snd_strerror(err)); +} + +void alsa_source::bail(const char* msg, int err) +{ + output_error_msg(msg, err); + throw std::runtime_error("audio_alsa_source"); +} - } /* namespace audio */ +} /* namespace audio */ } /* namespace gr */ diff --git a/gr-audio/lib/alsa/alsa_source.h b/gr-audio/lib/alsa/alsa_source.h index 61c50be754..66d349a840 100644 --- a/gr-audio/lib/alsa/alsa_source.h +++ b/gr-audio/lib/alsa/alsa_source.h @@ -33,82 +33,80 @@ #include <stdexcept> namespace gr { - namespace audio { - - class alsa_source; - typedef boost::shared_ptr<alsa_source> 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 alsa_source : public source - { - // typedef for pointer to class work method - typedef int(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); - - public: - alsa_source(int sampling_rate, - const std::string device_name, - bool ok_to_block); - ~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); - }; - - } /* namespace audio */ +namespace audio { + +class alsa_source; +typedef boost::shared_ptr<alsa_source> 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 alsa_source : public source +{ + // typedef for pointer to class work method + typedef int (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); + +public: + alsa_source(int sampling_rate, const std::string device_name, bool ok_to_block); + ~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); +}; + +} /* namespace audio */ } /* namespace gr */ #endif /* INCLUDED_AUDIO_ALSA_SOURCE_H */ diff --git a/gr-audio/lib/audio_registry.cc b/gr-audio/lib/audio_registry.cc index 421806558a..5c0c6317cb 100644 --- a/gr-audio/lib/audio_registry.cc +++ b/gr-audio/lib/audio_registry.cc @@ -28,19 +28,18 @@ #include <iostream> namespace gr { - namespace audio { +namespace audio { - /*********************************************************************** - * Create registries - **********************************************************************/ +/*********************************************************************** + * Create registries + **********************************************************************/ - static std::vector<source_entry_t> & - get_source_registry(void) - { - static bool src_reg = false; - static std::vector<source_entry_t> s_registry; +static std::vector<source_entry_t>& get_source_registry(void) +{ + static bool src_reg = false; + static std::vector<source_entry_t> s_registry; - if(!src_reg) { + if (!src_reg) { #ifdef ALSA_FOUND s_registry.push_back(register_source(REG_PRIO_HIGH, "alsa", alsa_source_fcn)); #endif /* ALSA_FOUND */ @@ -50,7 +49,8 @@ namespace gr { #endif /* OSS_FOUND */ #ifdef PORTAUDIO_FOUND - s_registry.push_back(register_source(REG_PRIO_MED, "portaudio", portaudio_source_fcn)); + s_registry.push_back( + register_source(REG_PRIO_MED, "portaudio", portaudio_source_fcn)); #endif /* PORTAUDIO_FOUND */ #ifdef JACK_FOUND @@ -62,23 +62,23 @@ namespace gr { #endif /* OSX_FOUND */ #ifdef WIN32_FOUND - s_registry.push_back(register_source(REG_PRIO_HIGH, "windows", windows_source_fcn)); + s_registry.push_back( + register_source(REG_PRIO_HIGH, "windows", windows_source_fcn)); #endif /* WIN32_FOUND */ src_reg = true; - } + } - return s_registry; - } + return s_registry; +} - static std::vector<sink_entry_t> & - get_sink_registry(void) - { - static bool snk_reg = false; - static std::vector<sink_entry_t> s_registry; +static std::vector<sink_entry_t>& get_sink_registry(void) +{ + static bool snk_reg = false; + static std::vector<sink_entry_t> s_registry; - if(!snk_reg) { + if (!snk_reg) { #if ALSA_FOUND s_registry.push_back(register_sink(REG_PRIO_HIGH, "alsa", alsa_sink_fcn)); #endif /* ALSA_FOUND */ @@ -88,7 +88,8 @@ namespace gr { #endif /* OSS_FOUND */ #if PORTAUDIO_FOUND - s_registry.push_back(register_sink(REG_PRIO_MED, "portaudio", portaudio_sink_fcn)); + s_registry.push_back( + register_sink(REG_PRIO_MED, "portaudio", portaudio_sink_fcn)); #endif /* PORTAUDIO_FOUND */ #if JACK_FOUND @@ -104,109 +105,100 @@ namespace gr { #endif /* WIN32_FOUND */ snk_reg = true; - } - - return s_registry; - } - - /*********************************************************************** - * Register functions - **********************************************************************/ - source_entry_t - 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; - return entry; - } - - sink_entry_t - 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; - return entry; - } - - /*********************************************************************** - * Factory functions - **********************************************************************/ - static std::string default_arch_name(void) - { - return 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; - } - - source::sptr - source::make(int sampling_rate, - const std::string device_name, - bool ok_to_block) - { - gr::logger_ptr logger, debug_logger; - configure_default_loggers(logger, debug_logger, "audio source"); - - if(get_source_registry().empty()) { + return s_registry; +} + +/*********************************************************************** + * Register functions + **********************************************************************/ +source_entry_t +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; + return entry; +} + +sink_entry_t +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; + return entry; +} + +/*********************************************************************** + * Factory functions + **********************************************************************/ +static std::string default_arch_name(void) +{ + return 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; +} + +source::sptr +source::make(int sampling_rate, const std::string device_name, bool ok_to_block) +{ + gr::logger_ptr logger, debug_logger; + configure_default_loggers(logger, debug_logger, "audio source"); + + 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(); + 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 + 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); - } - - GR_LOG_INFO(logger, boost::format("Audio source arch: %1%") % (entry.arch)); - return entry.source(sampling_rate, device_name, ok_to_block); } - sink::sptr - sink::make(int sampling_rate, - const std::string device_name, - bool ok_to_block) - { - gr::logger_ptr logger, debug_logger; - configure_default_loggers(logger, debug_logger, "audio source"); + GR_LOG_INFO(logger, boost::format("Audio source arch: %1%") % (entry.arch)); + return entry.source(sampling_rate, device_name, ok_to_block); +} - if(get_sink_registry().empty()) { +sink::sptr sink::make(int sampling_rate, const std::string device_name, bool ok_to_block) +{ + gr::logger_ptr logger, debug_logger; + configure_default_loggers(logger, debug_logger, "audio source"); + + 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(); + 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 + 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); - GR_LOG_INFO(logger, boost::format("Audio sink arch: %1%") % (entry.arch)); - return entry.sink(sampling_rate, device_name, ok_to_block); } - } /* namespace audio */ + do_arch_warning(arch); + GR_LOG_INFO(logger, boost::format("Audio sink arch: %1%") % (entry.arch)); + return entry.sink(sampling_rate, device_name, ok_to_block); +} + +} /* namespace audio */ } /* namespace gr */ diff --git a/gr-audio/lib/audio_registry.h b/gr-audio/lib/audio_registry.h index d18d5c5387..ad76106787 100644 --- a/gr-audio/lib/audio_registry.h +++ b/gr-audio/lib/audio_registry.h @@ -27,90 +27,73 @@ #include <string> namespace gr { - namespace audio { - - typedef source::sptr(*source_factory_t)(int, const std::string &, bool); - typedef 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 - }; - - struct source_entry_t { - reg_prio_type prio; - std::string arch; - source_factory_t source; - }; - - struct sink_entry_t - { - reg_prio_type prio; - std::string arch; - sink_factory_t sink; - }; - - source_entry_t register_source(reg_prio_type prio, const std::string &arch, - source_factory_t source); - sink_entry_t register_sink(reg_prio_type prio, const std::string &arch, - sink_factory_t sink); +namespace audio { + +typedef source::sptr (*source_factory_t)(int, const std::string&, bool); +typedef 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 }; + +struct source_entry_t { + reg_prio_type prio; + std::string arch; + source_factory_t source; +}; + +struct sink_entry_t { + reg_prio_type prio; + std::string arch; + sink_factory_t sink; +}; + +source_entry_t +register_source(reg_prio_type prio, const std::string& arch, source_factory_t source); +sink_entry_t +register_sink(reg_prio_type prio, const std::string& arch, sink_factory_t sink); #ifdef ALSA_FOUND - source::sptr alsa_source_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block); - sink::sptr alsa_sink_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block); +source::sptr +alsa_source_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block); +sink::sptr +alsa_sink_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block); #endif /* ALSA_FOUND */ #ifdef OSS_FOUND - source::sptr oss_source_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block); - sink::sptr oss_sink_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block); +source::sptr +oss_source_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block); +sink::sptr +oss_sink_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block); #endif /* OSS_FOUND */ #ifdef PORTAUDIO_FOUND - source::sptr portaudio_source_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block); - sink::sptr portaudio_sink_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block); +source::sptr +portaudio_source_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block); +sink::sptr +portaudio_sink_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block); #endif /* PORTAUDIO_FOUND */ #ifdef JACK_FOUND - source::sptr jack_source_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block); - sink::sptr jack_sink_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block); +source::sptr +jack_source_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block); +sink::sptr +jack_sink_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block); #endif /* JACK_FOUND */ #ifdef OSX_FOUND - source::sptr osx_source_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block); - sink::sptr osx_sink_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block); +source::sptr +osx_source_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block); +sink::sptr +osx_sink_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block); #endif /* OSX_FOUND */ #ifdef WIN32_FOUND - source::sptr windows_source_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block); - sink::sptr windows_sink_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block); +source::sptr +windows_source_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block); +sink::sptr +windows_sink_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block); #endif /* WIN32_FOUND */ - } /* namespace audio */ +} /* namespace audio */ } /* namespace gr */ #endif /* INCLUDED_GR_AUDIO_REGISTRY_H */ diff --git a/gr-audio/lib/jack/jack_sink.cc b/gr-audio/lib/jack/jack_sink.cc index c82c576174..7a7e14706d 100644 --- a/gr-audio/lib/jack/jack_sink.cc +++ b/gr-audio/lib/jack/jack_sink.cc @@ -38,229 +38,221 @@ #endif namespace gr { - namespace audio { - - sink::sptr - jack_sink_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block) - { - return sink::sptr - (new 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 prefs::singleton()->get_string - ("audio_jack", "default_output_device", "gr_sink"); - } - - int - jack_sink_process(jack_nframes_t nframes, void *arg) - { - jack_sink *self = (jack_sink *)arg; - unsigned int read_size = nframes*sizeof(sample_t); - - for(int i = 0; i < self->d_portcount; i++) { - - if(jack_ringbuffer_read_space(self->d_ringbuffer[i]) < read_size) { - self->d_nunderuns++; - // FIXME: move this fputs out, we shouldn't use blocking calls in process() - fputs("jU", stderr); - return 0; +namespace audio { + +sink::sptr +jack_sink_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block) +{ + return sink::sptr(new 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 prefs::singleton()->get_string( + "audio_jack", "default_output_device", "gr_sink"); +} + +int jack_sink_process(jack_nframes_t nframes, void* arg) +{ + jack_sink* self = (jack_sink*)arg; + unsigned int read_size = nframes * sizeof(sample_t); + + for (int i = 0; i < self->d_portcount; i++) { + + if (jack_ringbuffer_read_space(self->d_ringbuffer[i]) < 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[i], nframes); + char* buffer = (char*)jack_port_get_buffer(self->d_jack_output_port[i], nframes); jack_ringbuffer_read(self->d_ringbuffer[i], 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) { + // 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; } +#endif - // ---------------------------------------------------------------- - - jack_sink::jack_sink(int sampling_rate, - const std::string device_name, - bool ok_to_block) - : sync_block("audio_jack_sink", - io_signature::make(0, 0, 0), - io_signature::make(0, 0, 0)), - d_sampling_rate(sampling_rate), - d_device_name(device_name.empty() ? default_device_name() : device_name), - d_ok_to_block(ok_to_block), - d_jack_client(0), - d_portcount(0), - d_jack_output_port(), - d_ringbuffer(), - d_nunderuns(0) - { + return 0; +} + +// ---------------------------------------------------------------- + +jack_sink::jack_sink(int sampling_rate, const std::string device_name, bool ok_to_block) + : sync_block( + "audio_jack_sink", io_signature::make(0, 0, 0), io_signature::make(0, 0, 0)), + d_sampling_rate(sampling_rate), + d_device_name(device_name.empty() ? default_device_name() : device_name), + d_ok_to_block(ok_to_block), + d_jack_client(0), + d_portcount(0), + d_jack_output_port(), + d_ringbuffer(), + d_nunderuns(0) +{ #ifndef NO_PTHREAD - pthread_cond_init(&d_ringbuffer_ready, NULL);; - pthread_mutex_init(&d_jack_process_lock, NULL); + 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) { - GR_LOG_ERROR(d_logger, boost::format("[%1%]: jack server not running?") \ - % d_device_name); + // 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) { + GR_LOG_ERROR(d_logger, + boost::format("[%1%]: jack server not running?") % d_device_name); 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_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. + // 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); + // jack_on_shutdown (d_jack_client, &jack_shutdown, (void*)this); - d_jack_buffer_size = jack_get_buffer_size(d_jack_client); + d_jack_buffer_size = jack_get_buffer_size(d_jack_client); - set_output_multiple(d_jack_buffer_size); + set_output_multiple(d_jack_buffer_size); - assert(sizeof(float)==sizeof(sample_t)); - // Real number of outputs is set in check_topology - set_input_signature(io_signature::make(1, MAX_PORTS, sizeof(sample_t))); + assert(sizeof(float) == sizeof(sample_t)); + // Real number of outputs is set in check_topology + set_input_signature(io_signature::make(1, MAX_PORTS, sizeof(sample_t))); - jack_nframes_t sample_rate = jack_get_sample_rate(d_jack_client); + jack_nframes_t sample_rate = jack_get_sample_rate(d_jack_client); - if((jack_nframes_t)sampling_rate != sample_rate) { - GR_LOG_INFO(d_logger, boost::format("[%1%]: unable to support sampling rate %2%\n\tCard requested %3% instead.") \ - % d_device_name % sampling_rate % d_sampling_rate); - } + if ((jack_nframes_t)sampling_rate != sample_rate) { + GR_LOG_INFO(d_logger, + boost::format("[%1%]: unable to support sampling rate %2%\n\tCard " + "requested %3% instead.") % + d_device_name % sampling_rate % d_sampling_rate); } +} - bool - jack_sink::check_topology (int ninputs, int noutputs) - { - if(ninputs > MAX_PORTS) +bool jack_sink::check_topology(int ninputs, int noutputs) +{ + if (ninputs > MAX_PORTS) return false; - d_portcount = ninputs; // # of channels we're really using + d_portcount = ninputs; // # of channels we're really using - // Create ports and ringbuffers - for(int i = 0; i < d_portcount; i++) { + // Create ports and ringbuffers + for (int i = 0; i < d_portcount; i++) { std::string portname("out" + boost::to_string(i)); - d_jack_output_port[i] = - jack_port_register(d_jack_client, portname.c_str(), - JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); + d_jack_output_port[i] = jack_port_register(d_jack_client, + portname.c_str(), + JACK_DEFAULT_AUDIO_TYPE, + JackPortIsOutput, + 0); d_ringbuffer[i] = - jack_ringbuffer_create(N_BUFFERS*d_jack_buffer_size*sizeof(sample_t)); - if(d_ringbuffer[i] == NULL) - bail("jack_ringbuffer_create failed", 0); - } + jack_ringbuffer_create(N_BUFFERS * d_jack_buffer_size * sizeof(sample_t)); + if (d_ringbuffer[i] == NULL) + bail("jack_ringbuffer_create failed", 0); + } - // tell the JACK server that we are ready to roll - if(jack_activate (d_jack_client)) + // 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; - } + return true; +} - jack_sink::~jack_sink() - { - jack_client_close(d_jack_client); +jack_sink::~jack_sink() +{ + jack_client_close(d_jack_client); - for(int i = 0; i < d_portcount; i++) + for (int i = 0; i < d_portcount; i++) jack_ringbuffer_free(d_ringbuffer[i]); - } +} - int - jack_sink::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { +int jack_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 float** in = (const float**)&input_items[0]; - for(int i = 0; i < d_portcount; i++) { + for (int i = 0; i < d_portcount; i++) { int k = 0; // write_size and work_size are in bytes - int work_size = noutput_items*sizeof(sample_t); + int work_size = noutput_items * sizeof(sample_t); unsigned int write_size; - while(work_size > 0) { - unsigned int write_space; // bytes + while (work_size > 0) { + unsigned int write_space; // bytes #ifdef NO_PTHREAD - while((write_space=jack_ringbuffer_write_space(d_ringbuffer[i])) < - d_jack_buffer_size*sizeof(sample_t)) { - usleep(1000000*((d_jack_buffer_size-write_space/sizeof(sample_t))/d_sampling_rate)); - } + while ((write_space = jack_ringbuffer_write_space(d_ringbuffer[i])) < + 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 + // JACK actually requires POSIX - pthread_mutex_lock(&d_jack_process_lock); - while((write_space = jack_ringbuffer_write_space(d_ringbuffer[i])) < - d_jack_buffer_size*sizeof(sample_t)) { + pthread_mutex_lock(&d_jack_process_lock); + while ((write_space = jack_ringbuffer_write_space(d_ringbuffer[i])) < + 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); + // 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); + 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[i], (char *) &(in[i][k]), - write_size) < write_size) { - bail("jack_ringbuffer_write failed", 0); - } - work_size -= write_size; - k += write_size/sizeof(sample_t); + if (jack_ringbuffer_write(d_ringbuffer[i], (char*)&(in[i][k]), write_size) < + write_size) { + bail("jack_ringbuffer_write failed", 0); + } + work_size -= write_size; + k += write_size / sizeof(sample_t); } - } - - return noutput_items; } - void - jack_sink::output_error_msg(const char *msg, int err) - { - GR_LOG_ERROR(d_logger, boost::format("[%1%]: %2%: %3%") \ - % d_device_name % msg % err); - } + return noutput_items; +} - void - jack_sink::bail(const char *msg, int err) - { - output_error_msg(msg, err); - throw std::runtime_error("audio_jack_sink"); - } +void jack_sink::output_error_msg(const char* msg, int err) +{ + GR_LOG_ERROR(d_logger, boost::format("[%1%]: %2%: %3%") % d_device_name % msg % err); +} + +void jack_sink::bail(const char* msg, int err) +{ + output_error_msg(msg, err); + throw std::runtime_error("audio_jack_sink"); +} - } /* namespace audio */ +} /* namespace audio */ } /* namespace gr */ diff --git a/gr-audio/lib/jack/jack_sink.h b/gr-audio/lib/jack/jack_sink.h index 23f5d298e5..80fc7312d1 100644 --- a/gr-audio/lib/jack/jack_sink.h +++ b/gr-audio/lib/jack/jack_sink.h @@ -29,60 +29,58 @@ #include <stdexcept> namespace gr { - namespace audio { +namespace audio { - int sink_process(jack_nframes_t nframes, void *arg); +int 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 jack_sink : public sink - { - friend 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 jack_sink : public sink +{ + friend int jack_sink_process(jack_nframes_t nframes, void* arg); - // typedef for pointer to class work method - typedef int (jack_sink::*work_t)(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + // typedef for pointer to class work method + typedef int (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; + unsigned int d_sampling_rate; + std::string d_device_name; + bool d_ok_to_block; - jack_client_t *d_jack_client; - static const int MAX_PORTS = 10; - int d_portcount; - jack_port_t *d_jack_output_port[MAX_PORTS]; - jack_ringbuffer_t *d_ringbuffer[MAX_PORTS]; - jack_nframes_t d_jack_buffer_size; - pthread_cond_t d_ringbuffer_ready; - pthread_mutex_t d_jack_process_lock; + jack_client_t* d_jack_client; + static const int MAX_PORTS = 10; + int d_portcount; + jack_port_t* d_jack_output_port[MAX_PORTS]; + jack_ringbuffer_t* d_ringbuffer[MAX_PORTS]; + 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 + // random stats + int d_nunderuns; // count of underruns - void output_error_msg(const char *msg, int err); - void bail(const char *msg, int err); + void output_error_msg(const char* msg, int err); + void bail(const char* msg, int err); - public: - jack_sink(int sampling_rate, - const std::string device_name, - bool ok_to_block); - ~jack_sink(); +public: + jack_sink(int sampling_rate, const std::string device_name, bool ok_to_block); + ~jack_sink(); - bool check_topology(int ninputs, int noutputs); + 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); - }; + int work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; - } /* namespace audio */ +} /* namespace audio */ } /* namespace gr */ #endif /* INCLUDED_AUDIO_JACK_SINK_H */ diff --git a/gr-audio/lib/jack/jack_source.cc b/gr-audio/lib/jack/jack_source.cc index 6ca93989c4..e24e1af637 100644 --- a/gr-audio/lib/jack/jack_source.cc +++ b/gr-audio/lib/jack/jack_source.cc @@ -38,229 +38,222 @@ #endif namespace gr { - namespace audio { - - source::sptr - jack_source_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block) - { - return source::sptr - (new 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 prefs::singleton()->get_string - ("audio_jack", "default_input_device", "gr_source"); - } - - int - jack_source_process(jack_nframes_t nframes, void *arg) - { - jack_source *self = (jack_source *)arg; - unsigned int write_size = nframes*sizeof(sample_t); - - for(int i = 0; i < self->d_portcount; i++) { - if(jack_ringbuffer_write_space (self->d_ringbuffer[i]) < write_size) { - self->d_noverruns++; - // FIXME: move this fputs out, we shouldn't use blocking calls in process() - fputs ("jO", stderr); - return 0; +namespace audio { + +source::sptr +jack_source_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block) +{ + return source::sptr(new 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 prefs::singleton()->get_string( + "audio_jack", "default_input_device", "gr_source"); +} + +int jack_source_process(jack_nframes_t nframes, void* arg) +{ + jack_source* self = (jack_source*)arg; + unsigned int write_size = nframes * sizeof(sample_t); + + for (int i = 0; i < self->d_portcount; i++) { + if (jack_ringbuffer_write_space(self->d_ringbuffer[i]) < 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[i], nframes); + char* buffer = (char*)jack_port_get_buffer(self->d_jack_input_port[i], nframes); - jack_ringbuffer_write (self->d_ringbuffer[i], buffer, write_size); - } + jack_ringbuffer_write(self->d_ringbuffer[i], 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. + // 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) { + 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; } +#endif - // ---------------------------------------------------------------- - - jack_source::jack_source(int sampling_rate, - const std::string device_name, - bool ok_to_block) - : sync_block("audio_jack_source", - io_signature::make(0, 0, 0), - io_signature::make(0, 0, 0)), - d_sampling_rate(sampling_rate), - d_device_name(device_name.empty() ? default_device_name() : device_name), - d_ok_to_block(ok_to_block), - d_jack_client(0), - d_portcount(0), - d_jack_input_port(), - d_ringbuffer(), - d_noverruns(0) - { + return 0; +} + +// ---------------------------------------------------------------- + +jack_source::jack_source(int sampling_rate, + const std::string device_name, + bool ok_to_block) + : sync_block( + "audio_jack_source", io_signature::make(0, 0, 0), io_signature::make(0, 0, 0)), + d_sampling_rate(sampling_rate), + d_device_name(device_name.empty() ? default_device_name() : device_name), + d_ok_to_block(ok_to_block), + d_jack_client(0), + d_portcount(0), + d_jack_input_port(), + d_ringbuffer(), + d_noverruns(0) +{ #ifndef NO_PTHREAD - pthread_cond_init(&d_ringbuffer_ready, NULL);; - pthread_mutex_init(&d_jack_process_lock, NULL); + 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) { - GR_LOG_ERROR(d_logger, boost::format("[%1%]: jack server not running?") \ - % d_device_name); + // 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) { + GR_LOG_ERROR(d_logger, + boost::format("[%1%]: jack server not running?") % d_device_name); 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_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. + // 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); + // jack_on_shutdown (d_jack_client, &jack_shutdown, (void*)this); - d_jack_buffer_size = jack_get_buffer_size(d_jack_client); + d_jack_buffer_size = jack_get_buffer_size(d_jack_client); - set_output_multiple(d_jack_buffer_size); + set_output_multiple(d_jack_buffer_size); - assert(sizeof(float)==sizeof(sample_t)); - set_output_signature(io_signature::make(1, MAX_PORTS, sizeof(sample_t))); + assert(sizeof(float) == sizeof(sample_t)); + set_output_signature(io_signature::make(1, MAX_PORTS, sizeof(sample_t))); - jack_nframes_t sample_rate = jack_get_sample_rate(d_jack_client); + jack_nframes_t sample_rate = jack_get_sample_rate(d_jack_client); - if((jack_nframes_t)sampling_rate != sample_rate) { - GR_LOG_INFO(d_logger, boost::format("[%1%]: unable to support sampling rate %2%\n\tCard requested %3% instead.") \ - % d_device_name % sampling_rate % d_sampling_rate); - } + if ((jack_nframes_t)sampling_rate != sample_rate) { + GR_LOG_INFO(d_logger, + boost::format("[%1%]: unable to support sampling rate %2%\n\tCard " + "requested %3% instead.") % + d_device_name % sampling_rate % d_sampling_rate); } +} - bool - jack_source::check_topology(int ninputs, int noutputs) - { +bool jack_source::check_topology(int ninputs, int noutputs) +{ - if(noutputs > MAX_PORTS) + if (noutputs > MAX_PORTS) return false; - d_portcount = noutputs; // # of channels we're really using + d_portcount = noutputs; // # of channels we're really using - // Create ports and ringbuffers - for(int i = 0; i < d_portcount; i++) { + // Create ports and ringbuffers + for (int i = 0; i < d_portcount; i++) { std::string portname("in" + boost::to_string(i)); - d_jack_input_port[i] = jack_port_register(d_jack_client, portname.c_str(), - JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); + d_jack_input_port[i] = jack_port_register( + d_jack_client, portname.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); - d_ringbuffer[i] = jack_ringbuffer_create(N_BUFFERS*d_jack_buffer_size*sizeof(sample_t)); - if(d_ringbuffer[i] == NULL) - bail("jack_ringbuffer_create failed", 0); - } + d_ringbuffer[i] = + jack_ringbuffer_create(N_BUFFERS * d_jack_buffer_size * sizeof(sample_t)); + if (d_ringbuffer[i] == NULL) + bail("jack_ringbuffer_create failed", 0); + } - // tell the JACK server that we are ready to roll - if(jack_activate (d_jack_client)) + // 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; - } + return true; +} - jack_source::~jack_source() - { - jack_client_close(d_jack_client); +jack_source::~jack_source() +{ + jack_client_close(d_jack_client); - for(int i = 0; i < d_portcount; i++) + for (int i = 0; i < d_portcount; i++) jack_ringbuffer_free(d_ringbuffer[i]); - } +} - int - jack_source::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { +int jack_source::work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ - const float **out = (const float **)&output_items[0]; + const float** out = (const float**)&output_items[0]; - // Minimize latency - noutput_items = std::min (noutput_items, (int)d_jack_buffer_size); + // Minimize latency + noutput_items = std::min(noutput_items, (int)d_jack_buffer_size); - for(int i = 0; i < d_portcount; i++) { + for (int i = 0; i < d_portcount; i++) { int k = 0; // read_size and work_size are in bytes unsigned int read_size; - int work_size = noutput_items*sizeof(sample_t); + int work_size = noutput_items * sizeof(sample_t); - while(work_size > 0) { - unsigned int read_space; // bytes + while (work_size > 0) { + unsigned int read_space; // bytes #ifdef NO_PTHREAD - while((read_space=jack_ringbuffer_read_space (d_ringbuffer[i])) < - d_jack_buffer_size*sizeof(sample_t)) { - usleep(1000000*((d_jack_buffer_size-read_space/sizeof(sample_t))/d_sampling_rate)); - } + while ((read_space = jack_ringbuffer_read_space(d_ringbuffer[i])) < + 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[i])) < - 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); + // JACK actually requires POSIX + pthread_mutex_lock(&d_jack_process_lock); + while ((read_space = jack_ringbuffer_read_space(d_ringbuffer[i])) < + 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); + 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[i], (char *) &(out[i][k]), - read_size) < read_size) { - bail("jack_ringbuffer_read failed", 0); - } - work_size -= read_size; - k += read_size/sizeof(sample_t); + if (jack_ringbuffer_read(d_ringbuffer[i], (char*)&(out[i][k]), read_size) < + read_size) { + bail("jack_ringbuffer_read failed", 0); + } + work_size -= read_size; + k += read_size / sizeof(sample_t); } - } - - return noutput_items; } - void - jack_source::output_error_msg(const char *msg, int err) - { - GR_LOG_ERROR(d_logger, boost::format("[%1%]: %2%: %3%") \ - % d_device_name % msg % err); - } + return noutput_items; +} - void - jack_source::bail(const char *msg, int err) - { - output_error_msg(msg, err); - throw std::runtime_error("audio_jack_source"); - } +void jack_source::output_error_msg(const char* msg, int err) +{ + GR_LOG_ERROR(d_logger, boost::format("[%1%]: %2%: %3%") % d_device_name % msg % err); +} + +void jack_source::bail(const char* msg, int err) +{ + output_error_msg(msg, err); + throw std::runtime_error("audio_jack_source"); +} - } /* namespace audio */ +} /* namespace audio */ } /* namespace gr */ diff --git a/gr-audio/lib/jack/jack_source.h b/gr-audio/lib/jack/jack_source.h index f40e46d4f0..f91b2fad5a 100644 --- a/gr-audio/lib/jack/jack_source.h +++ b/gr-audio/lib/jack/jack_source.h @@ -29,60 +29,58 @@ #include <stdexcept> namespace gr { - namespace audio { +namespace audio { - int jack_source_process(jack_nframes_t nframes, void *arg); +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 jack_source : public source - { - friend 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 jack_source : public source +{ + friend int jack_source_process(jack_nframes_t nframes, void* arg); - // typedef for pointer to class work method - typedef int(jack_source::*work_t)(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + // typedef for pointer to class work method + typedef int (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; + unsigned int d_sampling_rate; + std::string d_device_name; + bool d_ok_to_block; - jack_client_t *d_jack_client; - static const int MAX_PORTS = 10; - int d_portcount; - jack_port_t *d_jack_input_port[MAX_PORTS]; - jack_ringbuffer_t *d_ringbuffer[MAX_PORTS]; - jack_nframes_t d_jack_buffer_size; - pthread_cond_t d_ringbuffer_ready; - pthread_mutex_t d_jack_process_lock; + jack_client_t* d_jack_client; + static const int MAX_PORTS = 10; + int d_portcount; + jack_port_t* d_jack_input_port[MAX_PORTS]; + jack_ringbuffer_t* d_ringbuffer[MAX_PORTS]; + 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 + // random stats + int d_noverruns; // count of overruns - void output_error_msg(const char *msg, int err); - void bail(const char *msg, int err); + void output_error_msg(const char* msg, int err); + void bail(const char* msg, int err); - public: - jack_source(int sampling_rate, - const std::string device_name, - bool ok_to_block); - ~jack_source(); +public: + jack_source(int sampling_rate, const std::string device_name, bool ok_to_block); + ~jack_source(); - bool check_topology(int ninputs, int noutputs); + 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); - }; + int work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; - } /* namespace audio */ +} /* namespace audio */ } /* namespace gr */ #endif /* INCLUDED_AUDIO_JACK_SOURCE_H */ diff --git a/gr-audio/lib/oss/oss_sink.cc b/gr-audio/lib/oss/oss_sink.cc index 36aca18e7a..972271d6d1 100644 --- a/gr-audio/lib/oss/oss_sink.cc +++ b/gr-audio/lib/oss/oss_sink.cc @@ -39,130 +39,123 @@ #include <stdexcept> namespace gr { - namespace audio { - - sink::sptr - oss_sink_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block) - { - return sink::sptr - (new oss_sink(sampling_rate, device_name, ok_to_block)); - } - - static std::string - default_device_name() - { - return prefs::singleton()->get_string - ("audio_oss", "default_output_device", "/dev/dsp"); - } - - oss_sink::oss_sink(int sampling_rate, - const std::string device_name, - bool ok_to_block) - : sync_block("audio_oss_sink", - io_signature::make(1, 2, sizeof(float)), - io_signature::make(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) { +namespace audio { + +sink::sptr +oss_sink_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block) +{ + return sink::sptr(new oss_sink(sampling_rate, device_name, ok_to_block)); +} + +static std::string default_device_name() +{ + return prefs::singleton()->get_string( + "audio_oss", "default_output_device", "/dev/dsp"); +} + +oss_sink::oss_sink(int sampling_rate, const std::string device_name, bool ok_to_block) + : sync_block("audio_oss_sink", + io_signature::make(1, 2, sizeof(float)), + io_signature::make(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, - prefs::singleton()->get_double("audio_oss", "latency", 0.005)); + double CHUNK_TIME = + std::max(0.001, 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_chunk_size = (int)(d_sampling_rate * CHUNK_TIME); + set_output_multiple(d_chunk_size); - d_buffer = new short[d_chunk_size * 2]; + 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) { + 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 ()); + perror(d_device_name.c_str()); throw std::runtime_error("audio_oss_sink"); - } + } - if(format != orig_format) { + 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) { + // 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 " + // 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"); + 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"); } - } - } - - oss_sink::~oss_sink() - { - close(d_fd); - delete [] d_buffer; } - - int - 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"); +} + +oss_sink::~oss_sink() +{ + close(d_fd); + delete[] d_buffer; +} + +int 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"); + 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; } - } /* namespace audio */ + return noutput_items; +} + +} /* namespace audio */ } /* namespace gr */ diff --git a/gr-audio/lib/oss/oss_sink.h b/gr-audio/lib/oss/oss_sink.h index 3b17348c41..2e4d90cfea 100644 --- a/gr-audio/lib/oss/oss_sink.h +++ b/gr-audio/lib/oss/oss_sink.h @@ -27,35 +27,35 @@ #include <string> namespace gr { - namespace audio { - - /*! - * \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 oss_sink : public sink - { - int d_sampling_rate; - std::string d_device_name; - int d_fd; - short *d_buffer; - int d_chunk_size; - - public: - oss_sink(int sampling_rate, - const std::string device_name = "", - bool ok_to_block = true); - ~oss_sink(); - - int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - }; - - } /* namespace audio */ +namespace audio { + +/*! + * \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 oss_sink : public sink +{ + int d_sampling_rate; + std::string d_device_name; + int d_fd; + short* d_buffer; + int d_chunk_size; + +public: + oss_sink(int sampling_rate, + const std::string device_name = "", + bool ok_to_block = true); + ~oss_sink(); + + int work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; + +} /* namespace audio */ } /* namespace gr */ #endif /* INCLUDED_AUDIO_OSS_SINK_H */ diff --git a/gr-audio/lib/oss/oss_source.cc b/gr-audio/lib/oss/oss_source.cc index 4c6365d057..14b8a0c969 100644 --- a/gr-audio/lib/oss/oss_source.cc +++ b/gr-audio/lib/oss/oss_source.cc @@ -39,149 +39,143 @@ #include <stdexcept> namespace gr { - namespace audio { - - source::sptr - oss_source_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block) - { - return source::sptr - (new oss_source(sampling_rate, device_name, ok_to_block)); - } - - static std::string - default_device_name() - { - return prefs::singleton()->get_string - ("audio_oss", "default_input_device", "/dev/dsp"); - } - - oss_source::oss_source(int sampling_rate, - const std::string device_name, - bool ok_to_block) - : sync_block("audio_oss_source", - io_signature::make(0, 0, 0), - io_signature::make(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) { +namespace audio { + +source::sptr +oss_source_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block) +{ + return source::sptr(new oss_source(sampling_rate, device_name, ok_to_block)); +} + +static std::string default_device_name() +{ + return prefs::singleton()->get_string( + "audio_oss", "default_input_device", "/dev/dsp"); +} + +oss_source::oss_source(int sampling_rate, const std::string device_name, bool ok_to_block) + : sync_block("audio_oss_source", + io_signature::make(0, 0, 0), + io_signature::make(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 = + double CHUNK_TIME = std::max(0.001, 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_chunk_size = (int)(d_sampling_rate * CHUNK_TIME); + set_output_multiple(d_chunk_size); - d_buffer = new short[d_chunk_size * 2]; + 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) { + 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 ()); + perror(d_device_name.c_str()); throw std::runtime_error("audio_oss_source"); - } + } - if(format != orig_format) { + 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) { + // 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 " + // 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"); + 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"); } - } } +} - oss_source::~oss_source() - { - close(d_fd); - delete [] d_buffer; - } +oss_source::~oss_source() +{ + close(d_fd); + delete[] d_buffer; +} - int - 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 +int 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); + 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. + // 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); + noutput_items = std::min(noutput_items, d_chunk_size); - int base = 0; - int ntogo = noutput_items; + int base = 0; + int ntogo = noutput_items; - while(ntogo > 0) { + 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 < 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"); + 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; + 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; + 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); + assert(0); } ntogo -= result_nitems; base += result_nitems; - } - - return noutput_items - ntogo; } - } /* namespace audio */ + return noutput_items - ntogo; +} + +} /* namespace audio */ } /* namespace gr */ diff --git a/gr-audio/lib/oss/oss_source.h b/gr-audio/lib/oss/oss_source.h index 1180a7b35a..ec9972bd43 100644 --- a/gr-audio/lib/oss/oss_source.h +++ b/gr-audio/lib/oss/oss_source.h @@ -27,36 +27,36 @@ #include <string> namespace gr { - namespace audio { - - /*! - * \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 oss_source : public source - { - int d_sampling_rate; - std::string d_device_name; - int d_fd; - short *d_buffer; - int d_chunk_size; - - public: - oss_source(int sampling_rate, - const std::string device_name = "", - bool ok_to_block = true); - - ~oss_source(); - - int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - }; - - } /* namespace audio */ +namespace audio { + +/*! + * \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 oss_source : public source +{ + int d_sampling_rate; + std::string d_device_name; + int d_fd; + short* d_buffer; + int d_chunk_size; + +public: + oss_source(int sampling_rate, + const std::string device_name = "", + bool ok_to_block = true); + + ~oss_source(); + + int work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; + +} /* namespace audio */ } /* namespace gr */ #endif /* INCLUDED_AUDIO_OSS_SOURCE_H */ diff --git a/gr-audio/lib/osx/circular_buffer.h b/gr-audio/lib/osx/circular_buffer.h index 5193a982d3..c18f2464cb 100644 --- a/gr-audio/lib/osx/circular_buffer.h +++ b/gr-audio/lib/osx/circular_buffer.h @@ -32,291 +32,302 @@ #endif #if DO_DEBUG -#define DEBUG(X) do{X} while(0); +#define DEBUG(X) \ + do { \ + X \ + } while (0); #else -#define DEBUG(X) do{} while(0); +#define DEBUG(X) \ + do { \ + } while (0); #endif template <class T> class circular_buffer { private: -// the buffer to use - T* d_buffer; + // 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; + // 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 - gr::thread::mutex* d_internal; - gr::thread::condition_variable* d_readBlock; - gr::thread::condition_variable* d_writeBlock; + // stuff to control access to class internals + gr::thread::mutex* d_internal; + gr::thread::condition_variable* d_readBlock; + gr::thread::condition_variable* d_writeBlock; -// booleans to decide how to control reading, writing, and aborting - bool d_doWriteBlock, d_doFullRead, d_doAbort; + // 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; - } - }; + 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(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; - }; + ~circular_buffer() + { + delete_mutex_cond(); + delete[] d_buffer; + }; - inline size_t n_avail_write_items () { - gr::thread::scoped_lock l (*d_internal); - size_t retVal = d_n_avail_write_I; - return (retVal); - }; + inline size_t n_avail_write_items() + { + gr::thread::scoped_lock l(*d_internal); + size_t retVal = d_n_avail_write_I; + return (retVal); + }; - inline size_t n_avail_read_items () { - gr::thread::scoped_lock l (*d_internal); - size_t retVal = d_n_avail_read_I; - return (retVal); - }; + inline size_t n_avail_read_items() + { + gr::thread::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);}; + 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 gr::thread::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 gr::thread::condition_variable (); - d_writeBlock = new gr::thread::condition_variable (); - }; + 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 gr::thread::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 gr::thread::condition_variable(); + d_writeBlock = new gr::thread::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 - */ + /* + * 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()"); - } + 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"); - gr::thread::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; - memcpy (&(d_buffer[d_writeNdx_I]), buf, n_now_I * sizeof (T)); - if (n_start_I) { - memcpy (d_buffer, &(buf[n_now_I]), 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); - }; + if (bufLen_I == 0) + return (0); + if (!buf) + throw std::runtime_error("circular_buffer::enqueue(): " + "input buffer is NULL.\n"); + gr::thread::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; + memcpy(&(d_buffer[d_writeNdx_I]), buf, n_now_I * sizeof(T)); + if (n_start_I) { + memcpy(d_buffer, &(buf[n_now_I]), 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 requested number of items to remove - * - * outputs: - * bufLen_I: pointer to the actual number of items removed - * - * returns: - * 0: if nothing to do (0 length buffer) - * 1: if success - * 2: in the process of aborting, do doing nothing - * 3: if the number of requested items to remove is not the same - * as the actual number of items removed. - * - * 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 - */ + /* + * 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 requested number of items to remove + * + * outputs: + * bufLen_I: pointer to the actual number of items removed + * + * returns: + * 0: if nothing to do (0 length buffer) + * 1: if success + * 2: in the process of aborting, do doing nothing + * 3: if the number of requested items to remove is not the same + * as the actual number of items removed. + * + * 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()"); - } + 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()"); + } - gr::thread::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; - memcpy (buf, &(d_buffer[d_readNdx_I]), n_now_I * sizeof (T)); - if (n_start_I) { - memcpy (&(buf[n_now_I]), d_buffer, n_start_I * sizeof (T)); - d_readNdx_I = n_start_I; - } else - d_readNdx_I += n_now_I; - int rv = 1; - if (*bufLen_I != l_bufLen_I) - rv = 3; - *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 (rv); - }; + gr::thread::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; + memcpy(buf, &(d_buffer[d_readNdx_I]), n_now_I * sizeof(T)); + if (n_start_I) { + memcpy(&(buf[n_now_I]), d_buffer, n_start_I * sizeof(T)); + d_readNdx_I = n_start_I; + } else + d_readNdx_I += n_now_I; + int rv = 1; + if (*bufLen_I != l_bufLen_I) + rv = 3; + *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 (rv); + }; - void abort () { - gr::thread::scoped_lock l (*d_internal); - d_doAbort = true; - d_writeBlock->notify_one (); - d_readBlock->notify_one (); - }; + void abort() + { + gr::thread::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/osx/osx_common.h b/gr-audio/lib/osx/osx_common.h index 5d8a3800a5..3a578a4719 100644 --- a/gr-audio/lib/osx/osx_common.h +++ b/gr-audio/lib/osx/osx_common.h @@ -37,32 +37,28 @@ namespace osx { #define _OSX_AU_DEBUG_RENDER_ 0 #endif -#define check_error_and_throw(err,what,throw_str) \ - if(err) { \ - OSStatus error = static_cast<OSStatus>(err); \ - char err_str[sizeof(OSStatus)+1]; \ - memcpy((void*)(&err_str), (void*)(&error), sizeof(OSStatus)); \ - err_str[sizeof(OSStatus)] = 0; \ - GR_LOG_FATAL(d_logger, boost::format(what)); \ - GR_LOG_FATAL(d_logger, boost::format(" Error# %u ('%s')") \ - % error % err_str); \ - GR_LOG_FATAL(d_logger, boost::format(" %s:%d") \ - % __FILE__ %__LINE__); \ - throw std::runtime_error(throw_str); \ - } +#define check_error_and_throw(err, what, throw_str) \ + if (err) { \ + OSStatus error = static_cast<OSStatus>(err); \ + char err_str[sizeof(OSStatus) + 1]; \ + memcpy((void*)(&err_str), (void*)(&error), sizeof(OSStatus)); \ + err_str[sizeof(OSStatus)] = 0; \ + GR_LOG_FATAL(d_logger, boost::format(what)); \ + GR_LOG_FATAL(d_logger, boost::format(" Error# %u ('%s')") % error % err_str); \ + GR_LOG_FATAL(d_logger, boost::format(" %s:%d") % __FILE__ % __LINE__); \ + throw std::runtime_error(throw_str); \ + } -#define check_error(err,what) \ - if(err) { \ - OSStatus error = static_cast<OSStatus>(err); \ - char err_str[sizeof(OSStatus)+1]; \ - memcpy((void*)(&err_str), (void*)(&error), sizeof(OSStatus)); \ - err_str[sizeof(OSStatus)] = 0; \ - GR_LOG_WARN(d_logger, boost::format(what)); \ - GR_LOG_WARN(d_logger, boost::format(" Error# %u ('%s')") \ - % error % err_str); \ - GR_LOG_WARN(d_logger, boost::format(" %s:%d") \ - % __FILE__ %__LINE__); \ - } +#define check_error(err, what) \ + if (err) { \ + OSStatus error = static_cast<OSStatus>(err); \ + char err_str[sizeof(OSStatus) + 1]; \ + memcpy((void*)(&err_str), (void*)(&error), sizeof(OSStatus)); \ + err_str[sizeof(OSStatus)] = 0; \ + GR_LOG_WARN(d_logger, boost::format(what)); \ + GR_LOG_WARN(d_logger, boost::format(" Error# %u ('%s')") % error % err_str); \ + GR_LOG_WARN(d_logger, boost::format(" %s:%d") % __FILE__ % __LINE__); \ + } #include <boost/detail/endian.hpp> //BOOST_BIG_ENDIAN #ifdef BOOST_BIG_ENDIAN diff --git a/gr-audio/lib/osx/osx_impl.cc b/gr-audio/lib/osx/osx_impl.cc index 2a73375114..c3ef76ba8f 100644 --- a/gr-audio/lib/osx/osx_impl.cc +++ b/gr-audio/lib/osx/osx_impl.cc @@ -33,275 +33,253 @@ #include <locale> #include <stdexcept> -std::ostream& -operator<< -(std::ostream& s, - const AudioStreamBasicDescription& asbd) +std::ostream& operator<<(std::ostream& s, const AudioStreamBasicDescription& asbd) { - char format_id[sizeof(asbd.mFormatID)+1]; - memcpy(format_id, (void*)(&asbd.mFormatID), sizeof(asbd.mFormatID)); - format_id[sizeof(asbd.mFormatID)] = 0; - s << " Sample Rate : " << asbd.mSampleRate << std::endl; - s << " Format ID : " << format_id << std::endl; - s << " Format Flags : " << asbd.mFormatFlags << std::endl; - s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsFloat) != 0) - << " : Is Float" << std::endl; - s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0) - << " : Is Big Endian" << std::endl; - s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0) - << " : Is Signed Integer" << std::endl; - s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsPacked) != 0) - << " : Is Packed" << std::endl; - s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0) - << " : Is Aligned High" << std::endl; - s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsNonInterleaved) != 0) - << " : Is Non-Interleaved" << std::endl; - s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsNonMixable) != 0) - << " : Is Non-Mixable" << std::endl; - s << " Bytes / Packet : " << asbd.mBytesPerPacket << std::endl; - s << " Frames / Packet : " << asbd.mFramesPerPacket << std::endl; - s << " Bytes / Frame : " << asbd.mBytesPerFrame << std::endl; - s << " Channels / Frame : " << asbd.mChannelsPerFrame << std::endl; - s << " Bits / Channel : " << asbd.mBitsPerChannel; - return(s); + char format_id[sizeof(asbd.mFormatID) + 1]; + memcpy(format_id, (void*)(&asbd.mFormatID), sizeof(asbd.mFormatID)); + format_id[sizeof(asbd.mFormatID)] = 0; + s << " Sample Rate : " << asbd.mSampleRate << std::endl; + s << " Format ID : " << format_id << std::endl; + s << " Format Flags : " << asbd.mFormatFlags << std::endl; + s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsFloat) != 0) << " : Is Float" + << std::endl; + s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0) + << " : Is Big Endian" << std::endl; + s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0) + << " : Is Signed Integer" << std::endl; + s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsPacked) != 0) << " : Is Packed" + << std::endl; + s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0) + << " : Is Aligned High" << std::endl; + s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsNonInterleaved) != 0) + << " : Is Non-Interleaved" << std::endl; + s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsNonMixable) != 0) + << " : Is Non-Mixable" << std::endl; + s << " Bytes / Packet : " << asbd.mBytesPerPacket << std::endl; + s << " Frames / Packet : " << asbd.mFramesPerPacket << std::endl; + s << " Bytes / Frame : " << asbd.mBytesPerFrame << std::endl; + s << " Channels / Frame : " << asbd.mChannelsPerFrame << std::endl; + s << " Bits / Channel : " << asbd.mBitsPerChannel; + return (s); }; namespace gr { namespace audio { namespace osx { -static UInt32 -_get_num_channels -(AudioDeviceID ad_id, - AudioObjectPropertyScope scope) +static UInt32 _get_num_channels(AudioDeviceID ad_id, AudioObjectPropertyScope scope) { - // retrieve the AudioBufferList associated with this ID using - // the provided scope - - UInt32 num_channels = 0; - UInt32 prop_size = 0; - AudioObjectPropertyAddress ao_address = { - kAudioDevicePropertyStreamConfiguration, scope, 0 - }; - OSStatus err = noErr; - if ((err = AudioObjectGetPropertyDataSize - (ad_id, &ao_address, 0, NULL, - &prop_size)) == noErr) { - boost::scoped_array<AudioBufferList> buf_list - (reinterpret_cast<AudioBufferList*> - (new char[prop_size])); - if ((err = AudioObjectGetPropertyData - (ad_id, &ao_address, 0, NULL, - &prop_size, buf_list.get())) == noErr) { - for (UInt32 mm = 0; mm < buf_list.get()->mNumberBuffers; ++mm) { - num_channels += buf_list.get()->mBuffers[mm].mNumberChannels; - } - } - else { - // assume 2 channels - num_channels = 2; + // retrieve the AudioBufferList associated with this ID using + // the provided scope + + UInt32 num_channels = 0; + UInt32 prop_size = 0; + AudioObjectPropertyAddress ao_address = { kAudioDevicePropertyStreamConfiguration, + scope, + 0 }; + OSStatus err = noErr; + if ((err = AudioObjectGetPropertyDataSize(ad_id, &ao_address, 0, NULL, &prop_size)) == + noErr) { + boost::scoped_array<AudioBufferList> buf_list( + reinterpret_cast<AudioBufferList*>(new char[prop_size])); + if ((err = AudioObjectGetPropertyData( + ad_id, &ao_address, 0, NULL, &prop_size, buf_list.get())) == noErr) { + for (UInt32 mm = 0; mm < buf_list.get()->mNumberBuffers; ++mm) { + num_channels += buf_list.get()->mBuffers[mm].mNumberChannels; + } + } else { + // assume 2 channels + num_channels = 2; + } + } else { + // assume 2 channels + num_channels = 2; } - } - else { - // assume 2 channels - num_channels = 2; - } - return(num_channels); + return (num_channels); } // works with both char and wchar_t -template<typename charT> +template <typename charT> struct ci_equal { - ci_equal( const std::locale& loc ) : loc_(loc) {} - bool operator()(charT ch1, charT ch2) { - return std::tolower(ch1, loc_) == std::tolower(ch2, loc_); - } + ci_equal(const std::locale& loc) : loc_(loc) {} + bool operator()(charT ch1, charT ch2) + { + return std::tolower(ch1, loc_) == std::tolower(ch2, loc_); + } + private: - const std::locale& loc_; + const std::locale& loc_; }; // find substring (case insensitive) -static std::string::size_type ci_find_substr -(const std::string& str1, const std::string& str2, - const std::locale& loc = std::locale()) +static std::string::size_type ci_find_substr(const std::string& str1, + const std::string& str2, + const std::locale& loc = std::locale()) { - std::string::const_iterator it = std::search - (str1.begin(), str1.end(), - str2.begin(), str2.end(), - ci_equal<std::string::value_type>(loc)); - if (it != str1.end()) { - return(it - str1.begin()); - } - // not found - return(std::string::npos); + std::string::const_iterator it = std::search(str1.begin(), + str1.end(), + str2.begin(), + str2.end(), + ci_equal<std::string::value_type>(loc)); + if (it != str1.end()) { + return (it - str1.begin()); + } + // not found + return (std::string::npos); } -void -get_num_channels_for_audio_device_id -(AudioDeviceID ad_id, - UInt32* n_input, - UInt32* n_output) +void get_num_channels_for_audio_device_id(AudioDeviceID ad_id, + UInt32* n_input, + UInt32* n_output) { - if (n_input) { - *n_input = _get_num_channels - (ad_id, kAudioDevicePropertyScopeInput); - } - if (n_output) { - *n_output = _get_num_channels - (ad_id, kAudioDevicePropertyScopeOutput); - } + if (n_input) { + *n_input = _get_num_channels(ad_id, kAudioDevicePropertyScopeInput); + } + if (n_output) { + *n_output = _get_num_channels(ad_id, kAudioDevicePropertyScopeOutput); + } } -void -find_audio_devices -(const std::string& device_name, - bool is_input, - std::vector < AudioDeviceID >* all_ad_ids, - std::vector < std::string >* all_names) +void find_audio_devices(const std::string& device_name, + bool is_input, + std::vector<AudioDeviceID>* all_ad_ids, + std::vector<std::string>* all_names) { - if ((!all_ad_ids) && (!all_names)) { - // if nothing is requested, no point in doing anything! - return; - } + if ((!all_ad_ids) && (!all_names)) { + // if nothing is requested, no point in doing anything! + return; + } - OSStatus err = noErr; + OSStatus err = noErr; - // retrieve the size of the array of known audio device IDs + // retrieve the size of the array of known audio device IDs - UInt32 prop_size = 0; + UInt32 prop_size = 0; - AudioObjectPropertyAddress ao_address = { - kAudioHardwarePropertyDevices, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; + AudioObjectPropertyAddress ao_address = { kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; - if ((err = AudioObjectGetPropertyDataSize - (kAudioObjectSystemObject, &ao_address, - 0, NULL, &prop_size)) != noErr) { + if ((err = AudioObjectGetPropertyDataSize( + kAudioObjectSystemObject, &ao_address, 0, NULL, &prop_size)) != noErr) { #if _OSX_AU_DEBUG_ - std::cerr << "audio_osx::find_audio_devices: " - << "Unable to retrieve number of audio objects: " - << err << std::endl; + std::cerr << "audio_osx::find_audio_devices: " + << "Unable to retrieve number of audio objects: " << err << std::endl; #endif - return; - } + return; + } - // get the total number of audio devices (input and output) + // get the total number of audio devices (input and output) - UInt32 num_devices = prop_size / sizeof(AudioDeviceID); + UInt32 num_devices = prop_size / sizeof(AudioDeviceID); - // retrieve all audio device ids + // retrieve all audio device ids - boost::scoped_array < AudioDeviceID > all_dev_ids - (new AudioDeviceID[num_devices]); + boost::scoped_array<AudioDeviceID> all_dev_ids(new AudioDeviceID[num_devices]); - if ((err = AudioObjectGetPropertyData - (kAudioObjectSystemObject, &ao_address, - 0, NULL, &prop_size, all_dev_ids.get())) != noErr) { + if ((err = AudioObjectGetPropertyData(kAudioObjectSystemObject, + &ao_address, + 0, + NULL, + &prop_size, + all_dev_ids.get())) != noErr) { #if _OSX_AU_DEBUG_ - std::cerr << "audio_osx::find_audio_devices: " - << "Unable to retrieve audio object ids: " - << err << std::endl; + std::cerr << "audio_osx::find_audio_devices: " + << "Unable to retrieve audio object ids: " << err << std::endl; #endif - return; - } - - // success; loop over all retrieved output device ids, retrieving - // the name for each and comparing with the desired name. - - std::vector< std::string > valid_names(num_devices); - std::vector< UInt32 > valid_indices(num_devices); - UInt32 num_found_devices = 0; - AudioObjectPropertyScope scope = is_input ? - kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; - - for (UInt32 nn = 0; nn < num_devices; ++nn) { - - // make sure this device has input / output channels (it might - // also have output / input channels, too, but we do not care - // about that here) - - AudioDeviceID t_id = all_dev_ids[nn]; - - if (is_input) { - UInt32 n_input_channels = 0; - get_num_channels_for_audio_device_id - (t_id, &n_input_channels, NULL); - if (n_input_channels == 0) { - // no input channels; must be output device; just continue - // to the next audio device. - continue; - } - } else { - UInt32 n_output_channels = 0; - get_num_channels_for_audio_device_id - (t_id, NULL, &n_output_channels); - if (n_output_channels == 0) { - // no output channels; must be input device; just continue - // to the next audio device. - continue; - } + return; } - // retrieve the device name; max name length is 64 characters. - - prop_size = 65; - char c_name_buf[prop_size]; - bzero((void*)c_name_buf, prop_size); - --prop_size; - - AudioObjectPropertyAddress ao_address = { - kAudioDevicePropertyDeviceName, scope, 0 - }; - - if ((err = AudioObjectGetPropertyData - (t_id, &ao_address, 0, NULL, - &prop_size, (void*)c_name_buf)) != noErr) { + // success; loop over all retrieved output device ids, retrieving + // the name for each and comparing with the desired name. + + std::vector<std::string> valid_names(num_devices); + std::vector<UInt32> valid_indices(num_devices); + UInt32 num_found_devices = 0; + AudioObjectPropertyScope scope = + is_input ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput; + + for (UInt32 nn = 0; nn < num_devices; ++nn) { + + // make sure this device has input / output channels (it might + // also have output / input channels, too, but we do not care + // about that here) + + AudioDeviceID t_id = all_dev_ids[nn]; + + if (is_input) { + UInt32 n_input_channels = 0; + get_num_channels_for_audio_device_id(t_id, &n_input_channels, NULL); + if (n_input_channels == 0) { + // no input channels; must be output device; just continue + // to the next audio device. + continue; + } + } else { + UInt32 n_output_channels = 0; + get_num_channels_for_audio_device_id(t_id, NULL, &n_output_channels); + if (n_output_channels == 0) { + // no output channels; must be input device; just continue + // to the next audio device. + continue; + } + } + + // retrieve the device name; max name length is 64 characters. + + prop_size = 65; + char c_name_buf[prop_size]; + bzero((void*)c_name_buf, prop_size); + --prop_size; + + AudioObjectPropertyAddress ao_address = { kAudioDevicePropertyDeviceName, + scope, + 0 }; + + if ((err = AudioObjectGetPropertyData( + t_id, &ao_address, 0, NULL, &prop_size, (void*)c_name_buf)) != noErr) { #if _OSX_AU_DEBUG_ - std::cerr << "audio_osx::find_audio_devices: " - << "Unable to retrieve audio device name #" - << (nn+1) << ": " << err << std::endl; + std::cerr << "audio_osx::find_audio_devices: " + << "Unable to retrieve audio device name #" << (nn + 1) << ": " + << err << std::endl; #endif - continue; - } - std::string name_buf(c_name_buf); - - // compare the retrieved name with the desired one, if - // provided; case insensitive. + continue; + } + std::string name_buf(c_name_buf); - if (device_name.length() > 0) { + // compare the retrieved name with the desired one, if + // provided; case insensitive. - std::string::size_type found = - ci_find_substr(name_buf, device_name); - if (found == std::string::npos) { - // not found; continue to the next ID - continue; - } - } + if (device_name.length() > 0) { - // store this info + std::string::size_type found = ci_find_substr(name_buf, device_name); + if (found == std::string::npos) { + // not found; continue to the next ID + continue; + } + } - valid_names[nn] = name_buf; - valid_indices[num_found_devices++] = nn; + // store this info - } + valid_names[nn] = name_buf; + valid_indices[num_found_devices++] = nn; + } - // resize valid function arguments, then copy found values + // resize valid function arguments, then copy found values - if (all_ad_ids) { - all_ad_ids->resize(num_found_devices); - for (UInt32 nn = 0; nn < num_found_devices; ++nn) { - (*all_ad_ids)[nn] = all_dev_ids[valid_indices[nn]]; + if (all_ad_ids) { + all_ad_ids->resize(num_found_devices); + for (UInt32 nn = 0; nn < num_found_devices; ++nn) { + (*all_ad_ids)[nn] = all_dev_ids[valid_indices[nn]]; + } } - } - if (all_names) { - all_names->resize(num_found_devices); - for (UInt32 nn = 0; nn < num_found_devices; ++nn) { - (*all_names)[nn] = valid_names[valid_indices[nn]]; + if (all_names) { + all_names->resize(num_found_devices); + for (UInt32 nn = 0; nn < num_found_devices; ++nn) { + (*all_names)[nn] = valid_names[valid_indices[nn]]; + } } - } } } /* namespace osx */ diff --git a/gr-audio/lib/osx/osx_sink.cc b/gr-audio/lib/osx/osx_sink.cc index 80dc5fe5fa..88e6d72fc6 100644 --- a/gr-audio/lib/osx/osx_sink.cc +++ b/gr-audio/lib/osx/osx_sink.cc @@ -32,637 +32,595 @@ #include <stdexcept> namespace gr { - namespace audio { - - sink::sptr - osx_sink_fcn(int sampling_rate, - const std::string& device_name, - bool ok_to_block) - { - return sink::sptr - (new osx_sink(sampling_rate, device_name, ok_to_block)); - } - - static std::string - default_device_name() - { - return prefs::singleton()->get_string - ("audio_osx", "default_output_device", "built-in"); - } - - osx_sink::osx_sink(int sample_rate, - const std::string& device_name, - bool ok_to_block) - : sync_block("audio_osx_sink", - io_signature::make(0, 0, 0), - io_signature::make(0, 0, 0)), - d_input_sample_rate(0.0), d_n_user_channels(0), - d_n_dev_channels(0), d_queue_sample_count(0), - d_buffer_size_samples(0), d_ok_to_block(ok_to_block), - d_do_reset(false), d_hardware_changed(false), - d_using_default_device(false), d_waiting_for_data(false), - d_desired_name(device_name.empty() ? default_device_name() - : device_name), - d_output_au(0), d_output_ad_id(0) - { - if(sample_rate <= 0) { - GR_LOG_ERROR(d_logger, boost::format - ("Invalid Sample Rate: %d") - % sample_rate); +namespace audio { + +sink::sptr +osx_sink_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block) +{ + return sink::sptr(new osx_sink(sampling_rate, device_name, ok_to_block)); +} + +static std::string default_device_name() +{ + return prefs::singleton()->get_string( + "audio_osx", "default_output_device", "built-in"); +} + +osx_sink::osx_sink(int sample_rate, const std::string& device_name, bool ok_to_block) + : sync_block( + "audio_osx_sink", io_signature::make(0, 0, 0), io_signature::make(0, 0, 0)), + d_input_sample_rate(0.0), + d_n_user_channels(0), + d_n_dev_channels(0), + d_queue_sample_count(0), + d_buffer_size_samples(0), + d_ok_to_block(ok_to_block), + d_do_reset(false), + d_hardware_changed(false), + d_using_default_device(false), + d_waiting_for_data(false), + d_desired_name(device_name.empty() ? default_device_name() : device_name), + d_output_au(0), + d_output_ad_id(0) +{ + if (sample_rate <= 0) { + GR_LOG_ERROR(d_logger, boost::format("Invalid Sample Rate: %d") % sample_rate); throw std::invalid_argument("audio_osx_sink"); - } - else { + } else { d_input_sample_rate = (Float64)sample_rate; - } + } - // set up for audio output using the stored desired parameters + // set up for audio output using the stored desired parameters - setup(); - } + setup(); +} - void osx_sink::setup() - { - OSStatus err = noErr; +void osx_sink::setup() +{ + OSStatus err = noErr; - // set the default output audio device id to "unknown" + // set the default output audio device id to "unknown" - d_output_ad_id = kAudioDeviceUnknown; + d_output_ad_id = kAudioDeviceUnknown; - // try to find the output audio device, if specified + // try to find the output audio device, if specified - std::vector < AudioDeviceID > all_ad_ids; - std::vector < std::string > all_names; + std::vector<AudioDeviceID> all_ad_ids; + std::vector<std::string> all_names; - osx::find_audio_devices - (d_desired_name, false, - &all_ad_ids, &all_names); + osx::find_audio_devices(d_desired_name, false, &all_ad_ids, &all_names); - // check number of device(s) returned + // check number of device(s) returned - if (d_desired_name.length() != 0) { + if (d_desired_name.length() != 0) { if (all_ad_ids.size() == 1) { - // exactly 1 match was found; see if it was partial - - if (all_names[0].compare(d_desired_name) != 0) { + // exactly 1 match was found; see if it was partial - // yes: log the full device name - GR_LOG_INFO(d_logger, boost::format - ("Using output audio device '%s'.") - % all_names[0]); + if (all_names[0].compare(d_desired_name) != 0) { - } + // yes: log the full device name + GR_LOG_INFO(d_logger, + boost::format("Using output audio device '%s'.") % + all_names[0]); + } - // store info on this device + // store info on this device - d_output_ad_id = all_ad_ids[0]; - d_selected_name = all_names[0]; + d_output_ad_id = all_ad_ids[0]; + d_selected_name = all_names[0]; } else { - // either 0 or more than 1 device was found; get all output - // device names, print those, and error out. - - osx::find_audio_devices("", false, NULL, &all_names); + // either 0 or more than 1 device was found; get all output + // device names, print those, and error out. - std::string err_str("\n\nA unique output audio device name " - "matching the string '"); - err_str += d_desired_name; - err_str += "' was not found.\n\n"; - err_str += "The current known output audio device name"; - err_str += ((all_names.size() > 1) ? "s are" : " is"); - err_str += ":\n"; - for (UInt32 nn = 0; nn < all_names.size(); ++nn) { - err_str += " " + all_names[nn] + "\n"; - } - GR_LOG_ERROR(d_logger, boost::format(err_str)); - throw std::runtime_error("audio_osx_sink::setup"); + osx::find_audio_devices("", false, NULL, &all_names); + std::string err_str("\n\nA unique output audio device name " + "matching the string '"); + err_str += d_desired_name; + err_str += "' was not found.\n\n"; + err_str += "The current known output audio device name"; + err_str += ((all_names.size() > 1) ? "s are" : " is"); + err_str += ":\n"; + for (UInt32 nn = 0; nn < all_names.size(); ++nn) { + err_str += " " + all_names[nn] + "\n"; + } + GR_LOG_ERROR(d_logger, boost::format(err_str)); + throw std::runtime_error("audio_osx_sink::setup"); } - } + } - // if no output audio device id was found, use the default - // output audio device as set in System Preferences. + // if no output audio device id was found, use the default + // output audio device as set in System Preferences. - if (d_output_ad_id == kAudioDeviceUnknown) { + if (d_output_ad_id == kAudioDeviceUnknown) { UInt32 size = sizeof(AudioDeviceID); AudioObjectPropertyAddress ao_address = { - kAudioHardwarePropertyDefaultOutputDevice, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster + kAudioHardwarePropertyDefaultOutputDevice, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; - err = AudioObjectGetPropertyData - (kAudioObjectSystemObject, &ao_address, - 0, NULL, &size, &d_output_ad_id); - check_error_and_throw - (err, "Getting the default output audio device ID failed", - "audio_osx_sink::setup"); + err = AudioObjectGetPropertyData( + kAudioObjectSystemObject, &ao_address, 0, NULL, &size, &d_output_ad_id); + check_error_and_throw(err, + "Getting the default output audio device ID failed", + "audio_osx_sink::setup"); { - // retrieve the device name; max name length is 64 characters. - - UInt32 prop_size = 65; - char c_name_buf[prop_size]; - bzero((void*)c_name_buf, prop_size); - --prop_size; - - AudioObjectPropertyAddress ao_address = { - kAudioDevicePropertyDeviceName, - kAudioDevicePropertyScopeOutput, 0 - }; - - if ((err = AudioObjectGetPropertyData - (d_output_ad_id, &ao_address, 0, NULL, - &prop_size, (void*)c_name_buf)) != noErr) { - - check_error(err, "Unable to retrieve output audio device name"); - - } else { - - GR_LOG_INFO(d_logger, boost::format - ("\n\nUsing output audio device '%s'.\n ... " - "which is the current default output audio" - " device.\n Changing the default output" - " audio device in the System Preferences" - " will \n result in changing it here, too " - "(with an internal reconfiguration).\n") % - std::string(c_name_buf)); - - } - - d_selected_name = c_name_buf; + // retrieve the device name; max name length is 64 characters. + + UInt32 prop_size = 65; + char c_name_buf[prop_size]; + bzero((void*)c_name_buf, prop_size); + --prop_size; + + AudioObjectPropertyAddress ao_address = { kAudioDevicePropertyDeviceName, + kAudioDevicePropertyScopeOutput, + 0 }; + + if ((err = AudioObjectGetPropertyData(d_output_ad_id, + &ao_address, + 0, + NULL, + &prop_size, + (void*)c_name_buf)) != noErr) { + + check_error(err, "Unable to retrieve output audio device name"); + + } else { + + GR_LOG_INFO(d_logger, + boost::format("\n\nUsing output audio device '%s'.\n ... " + "which is the current default output audio" + " device.\n Changing the default output" + " audio device in the System Preferences" + " will \n result in changing it here, too " + "(with an internal reconfiguration).\n") % + std::string(c_name_buf)); + } + d_selected_name = c_name_buf; } d_using_default_device = true; + } - } - - // retrieve the total number of channels for the selected audio - // output device + // retrieve the total number of channels for the selected audio + // output device - osx::get_num_channels_for_audio_device_id - (d_output_ad_id, NULL, &d_n_dev_channels); + osx::get_num_channels_for_audio_device_id(d_output_ad_id, NULL, &d_n_dev_channels); - // set the block input signature, if not already set - // (d_n_user_channels is set in check_topology, which is called - // before the flow-graph is running) + // set the block input signature, if not already set + // (d_n_user_channels is set in check_topology, which is called + // before the flow-graph is running) - if (d_n_user_channels == 0) { - set_input_signature(io_signature::make - (1, d_n_dev_channels, sizeof(float))); - } + if (d_n_user_channels == 0) { + set_input_signature(io_signature::make(1, d_n_dev_channels, sizeof(float))); + } - // set the interim buffer size; to work with the GR scheduler, - // must be at least 16kB. Pick 50 kS since that's plenty yet - // not very much. + // set the interim buffer size; to work with the GR scheduler, + // must be at least 16kB. Pick 50 kS since that's plenty yet + // not very much. - d_buffer_size_samples = (d_input_sample_rate < 50000.0 ? - 50000 : (UInt32)d_input_sample_rate); + d_buffer_size_samples = + (d_input_sample_rate < 50000.0 ? 50000 : (UInt32)d_input_sample_rate); #if _OSX_AU_DEBUG_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink: max # samples = " - << d_buffer_size_samples << std::endl; + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_sink: max # samples = " << d_buffer_size_samples + << std::endl; #endif - // create the default AudioUnit for output: + // create the default AudioUnit for output: - // Open the default output unit + // Open the default output unit #ifndef GR_USE_OLD_AUDIO_UNIT - AudioComponentDescription desc; + AudioComponentDescription desc; #else - ComponentDescription desc; + ComponentDescription desc; #endif - desc.componentType = kAudioUnitType_Output; - desc.componentSubType = kAudioUnitSubType_DefaultOutput; - desc.componentManufacturer = kAudioUnitManufacturer_Apple; - desc.componentFlags = 0; - desc.componentFlagsMask = 0; + 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) { - GR_LOG_FATAL(d_logger, boost::format - ("AudioComponentFindNext Failed")); + AudioComponent comp = AudioComponentFindNext(NULL, &desc); + if (!comp) { + GR_LOG_FATAL(d_logger, boost::format("AudioComponentFindNext Failed")); throw std::runtime_error("audio_osx_sink::setup"); - } - err = AudioComponentInstanceNew(comp, &d_output_au); - check_error_and_throw(err, "AudioComponentInstanceNew Failed", - "audio_osx_sink::setup"); + } + err = AudioComponentInstanceNew(comp, &d_output_au); + check_error_and_throw( + err, "AudioComponentInstanceNew Failed", "audio_osx_sink::setup"); #else - Component comp = FindNextComponent(NULL, &desc); - if(comp == NULL) { - GR_LOG_FATAL(d_logger, boost::format - ("FindNextComponent Failed")); + Component comp = FindNextComponent(NULL, &desc); + if (comp == NULL) { + GR_LOG_FATAL(d_logger, boost::format("FindNextComponent Failed")); throw std::runtime_error("audio_osx_sink::setup"); - } - err = OpenAComponent(comp, &d_output_au); - check_error_and_throw(err, "OpenAComponent Failed", - "audio_osx_sink::setup"); - -#endif + } + err = OpenAComponent(comp, &d_output_au); + check_error_and_throw(err, "OpenAComponent Failed", "audio_osx_sink::setup"); + +#endif + + // set the selected device ID as the current output device + + err = AudioUnitSetProperty(d_output_au, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + 0, + &d_output_ad_id, + sizeof(d_output_ad_id)); + check_error_and_throw( + err, "Setting selected output device as current failed", "audio_osx_sink::setup"); + + // Set up a callback function to generate output to the output unit + + AURenderCallbackStruct au_callback = { reinterpret_cast<AURenderCallback>( + &osx_sink::au_output_callback), + reinterpret_cast<void*>(this) }; + UInt32 prop_size = (UInt32)sizeof(au_callback); + + err = AudioUnitSetProperty(d_output_au, + kAudioUnitProperty_SetRenderCallback, + kAudioUnitScope_Input, + 0, + &au_callback, + prop_size); + check_error_and_throw(err, "Set Render Callback", "audio_osx_sink::setup"); + + // create the stream format for the output unit, so that it + // handles any format conversions. Set number of channels in + // ::start, once the actual number of channels is known. + + memset((void*)(&d_stream_format), 0, sizeof(d_stream_format)); + d_stream_format.mSampleRate = d_input_sample_rate; + d_stream_format.mFormatID = kAudioFormatLinearPCM; + d_stream_format.mFormatFlags = + (kLinearPCMFormatFlagIsFloat | GR_PCM_ENDIANNESS | kLinearPCMFormatFlagIsPacked | + kAudioFormatFlagIsNonInterleaved); + d_stream_format.mBytesPerPacket = sizeof(float); + d_stream_format.mFramesPerPacket = 1; + d_stream_format.mBytesPerFrame = sizeof(float); + d_stream_format.mBitsPerChannel = 8 * sizeof(float); + + // set the render quality to maximum + + UInt32 render_quality = kRenderQuality_Max; + prop_size = (UInt32)sizeof(render_quality); + err = AudioUnitSetProperty(d_output_au, + kAudioUnitProperty_RenderQuality, + kAudioUnitScope_Global, + 0, + &render_quality, + prop_size); + check_error(err, "Setting render quality failed"); + + // clear the RunLoop (whatever that is); needed, for some + // reason, before a listener will work. - // set the selected device ID as the current output device - - err = AudioUnitSetProperty - (d_output_au, kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, 0, - &d_output_ad_id, sizeof(d_output_ad_id)); - check_error_and_throw - (err, "Setting selected output device as current failed", - "audio_osx_sink::setup"); - - // Set up a callback function to generate output to the output unit - - AURenderCallbackStruct au_callback = { - reinterpret_cast<AURenderCallback> - (&osx_sink::au_output_callback), - reinterpret_cast<void*>(this) - }; - UInt32 prop_size = (UInt32)sizeof(au_callback); - - err = AudioUnitSetProperty - (d_output_au, - kAudioUnitProperty_SetRenderCallback, - kAudioUnitScope_Input, 0, - &au_callback, prop_size); - check_error_and_throw - (err, "Set Render Callback", - "audio_osx_sink::setup"); - - // create the stream format for the output unit, so that it - // handles any format conversions. Set number of channels in - // ::start, once the actual number of channels is known. - - memset((void*)(&d_stream_format), 0, sizeof(d_stream_format)); - d_stream_format.mSampleRate = d_input_sample_rate; - d_stream_format.mFormatID = kAudioFormatLinearPCM; - d_stream_format.mFormatFlags = (kLinearPCMFormatFlagIsFloat | - GR_PCM_ENDIANNESS | - kLinearPCMFormatFlagIsPacked | - kAudioFormatFlagIsNonInterleaved); - d_stream_format.mBytesPerPacket = sizeof(float); - d_stream_format.mFramesPerPacket = 1; - d_stream_format.mBytesPerFrame = sizeof(float); - d_stream_format.mBitsPerChannel = 8*sizeof(float); - - // set the render quality to maximum - - UInt32 render_quality = kRenderQuality_Max; - prop_size = (UInt32)sizeof(render_quality); - err = AudioUnitSetProperty - (d_output_au, - kAudioUnitProperty_RenderQuality, - kAudioUnitScope_Global, 0, - &render_quality, prop_size); - check_error(err, "Setting render quality failed"); - - // clear the RunLoop (whatever that is); needed, for some - // reason, before a listener will work. - - { + { CFRunLoopRef the_run_loop = NULL; - AudioObjectPropertyAddress property = { - kAudioHardwarePropertyRunLoop, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; + AudioObjectPropertyAddress property = { kAudioHardwarePropertyRunLoop, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; prop_size = (UInt32)sizeof(the_run_loop); - err = AudioObjectSetPropertyData - (kAudioObjectSystemObject, &property, 0, NULL, - prop_size, &the_run_loop); - check_error(err, "Clearing RunLoop failed; " + err = AudioObjectSetPropertyData( + kAudioObjectSystemObject, &property, 0, NULL, prop_size, &the_run_loop); + check_error(err, + "Clearing RunLoop failed; " "Audio Output Device Listener might not work."); - } + } - // set up listeners + // set up listeners #ifndef GR_USE_OLD_AUDIO_UNIT - // 10.4 and newer + // 10.4 and newer - { + { // set up a listener if hardware changes (at all) - AudioObjectPropertyAddress property = { - kAudioHardwarePropertyDevices, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; + AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; - err = AudioObjectAddPropertyListener - (kAudioObjectSystemObject, &property, - reinterpret_cast<AudioObjectPropertyListenerProc> - (&osx_sink::hardware_listener), - reinterpret_cast<void*>(this)); + err = AudioObjectAddPropertyListener( + kAudioObjectSystemObject, + &property, + reinterpret_cast<AudioObjectPropertyListenerProc>( + &osx_sink::hardware_listener), + reinterpret_cast<void*>(this)); check_error(err, "Adding Audio Hardware Listener failed"); - } + } - if (d_using_default_device) { + if (d_using_default_device) { // set up a listener for the default output device so that if // the device changes, this routine will be called and we can // internally handle this change (if/as necessary) { - AudioObjectPropertyAddress property = { - kAudioHardwarePropertyDefaultOutputDevice, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - err = AudioObjectAddPropertyListener - (kAudioObjectSystemObject, &property, - reinterpret_cast<AudioObjectPropertyListenerProc> - (&osx_sink::hardware_listener), - reinterpret_cast<void*>(this)); - check_error(err, "Adding Default Output Audio Listener failed"); + AudioObjectPropertyAddress property = { + kAudioHardwarePropertyDefaultOutputDevice, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster + }; + err = AudioObjectAddPropertyListener( + kAudioObjectSystemObject, + &property, + reinterpret_cast<AudioObjectPropertyListenerProc>( + &osx_sink::hardware_listener), + reinterpret_cast<void*>(this)); + check_error(err, "Adding Default Output Audio Listener failed"); } - } + } #else - // 10.5 and older + // 10.5 and older - err = AudioHardwareAddPropertyListener - (kAudioHardwarePropertyDevices, - reinterpret_cast<AudioHardwarePropertyListenerProc> - (&osx_sink::hardware_listener), - reinterpret_cast<void*>(this)); - check_error(err, "Adding Audio Hardware Listener failed"); + err = AudioHardwareAddPropertyListener( + kAudioHardwarePropertyDevices, + reinterpret_cast<AudioHardwarePropertyListenerProc>(&osx_sink::hardware_listener), + reinterpret_cast<void*>(this)); + check_error(err, "Adding Audio Hardware Listener failed"); - if (d_using_default_device) { + if (d_using_default_device) { - err = AudioHardwareAddPropertyListener - (kAudioHardwarePropertyDefaultOutputDevice, - reinterpret_cast<AudioHardwarePropertyListenerProc> - (&osx_sink::default_listener), - reinterpret_cast<void*>(this)); + err = AudioHardwareAddPropertyListener( + kAudioHardwarePropertyDefaultOutputDevice, + reinterpret_cast<AudioHardwarePropertyListenerProc>( + &osx_sink::default_listener), + reinterpret_cast<void*>(this)); check_error(err, "Adding Default Output Audio Listener failed"); - - } + } #endif - // initialize the AU for output, so that it is ready to be used + // initialize the AU for output, so that it is ready to be used - err = AudioUnitInitialize(d_output_au); - check_error_and_throw - (err, "AudioUnit Initialize Failed", - "audio_osx_sink::setup"); + err = AudioUnitInitialize(d_output_au); + check_error_and_throw(err, "AudioUnit Initialize Failed", "audio_osx_sink::setup"); #if _OSX_AU_DEBUG_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink Parameters:" << std::endl - << " Sample Rate is " << d_input_sample_rate << std::endl - << " Max # samples to store per channel is " - << d_buffer_size_samples << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink Parameters:" << std::endl + << " Sample Rate is " << d_input_sample_rate << std::endl + << " Max # samples to store per channel is " << d_buffer_size_samples + << std::endl; #endif - } +} - void osx_sink::teardown() - { +void osx_sink::teardown() +{ #if _OSX_AU_DEBUG_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::teardown: starting" - << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::teardown: starting" + << std::endl; #endif - OSStatus err = noErr; + OSStatus err = noErr; - // stop the AudioUnit + // stop the AudioUnit - stop(); + stop(); - if (d_using_default_device) { + if (d_using_default_device) { // remove the listener OSStatus err = noErr; - AudioObjectPropertyAddress property = { - kAudioHardwarePropertyDefaultOutputDevice, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - err = AudioObjectRemovePropertyListener - (kAudioObjectSystemObject, &property, - reinterpret_cast<AudioObjectPropertyListenerProc> - (&osx_sink::hardware_listener), - reinterpret_cast<void*>(this)); + AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultOutputDevice, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; + err = AudioObjectRemovePropertyListener( + kAudioObjectSystemObject, + &property, + reinterpret_cast<AudioObjectPropertyListenerProc>( + &osx_sink::hardware_listener), + reinterpret_cast<void*>(this)); #if _OSX_AU_DEBUG_ - check_error(err, "teardown: AudioObjectRemovePropertyListener " + check_error(err, + "teardown: AudioObjectRemovePropertyListener " "hardware failed"); #endif - } + } - // uninitialize the AudioUnit + // uninitialize the AudioUnit - err = AudioUnitUninitialize(d_output_au); + err = AudioUnitUninitialize(d_output_au); #if _OSX_AU_DEBUG_ - check_error(err, "teardown: AudioUnitUninitialize failed"); + check_error(err, "teardown: AudioUnitUninitialize failed"); #endif - // dispose / close the AudioUnit + // dispose / close the AudioUnit #ifndef GR_USE_OLD_AUDIO_UNIT - err = AudioComponentInstanceDispose(d_output_au); + err = AudioComponentInstanceDispose(d_output_au); #if _OSX_AU_DEBUG_ - check_error(err, "teardown: AudioComponentInstanceDispose failed"); + check_error(err, "teardown: AudioComponentInstanceDispose failed"); #endif #else - CloseComponent(d_output_au); + CloseComponent(d_output_au); #if _OSX_AU_DEBUG_ - check_error(err, "teardown: CloseComponent failed"); + check_error(err, "teardown: CloseComponent failed"); #endif #endif - // delete buffers + // delete buffers - for(UInt32 nn = 0; nn < d_buffers.size(); ++nn) { + for (UInt32 nn = 0; nn < d_buffers.size(); ++nn) { delete d_buffers[nn]; d_buffers[nn] = 0; - } - d_buffers.resize(0); + } + d_buffers.resize(0); - // clear important variables; not # user channels + // clear important variables; not # user channels - d_n_dev_channels = d_n_buffer_channels = - d_queue_sample_count = d_buffer_size_samples = 0; - d_using_default_device = false; - d_output_au = 0; - d_output_ad_id = 0; + d_n_dev_channels = d_n_buffer_channels = d_queue_sample_count = + d_buffer_size_samples = 0; + d_using_default_device = false; + d_output_au = 0; + d_output_ad_id = 0; #if _OSX_AU_DEBUG_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::teardown: finished" - << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::teardown: finished" + << std::endl; #endif - } +} - bool - osx_sink::is_running() - { - UInt32 au_running = 0; +bool osx_sink::is_running() +{ + UInt32 au_running = 0; - if (d_output_au) { + if (d_output_au) { UInt32 prop_size = (UInt32)sizeof(UInt32); - OSStatus err = AudioUnitGetProperty - (d_output_au, - kAudioOutputUnitProperty_IsRunning, - kAudioUnitScope_Global, 0, - &au_running, &prop_size); - check_error_and_throw - (err, "AudioUnitGetProperty IsRunning", - "audio_osx_sink::is_running"); - - } - - return(au_running != 0); + OSStatus err = AudioUnitGetProperty(d_output_au, + kAudioOutputUnitProperty_IsRunning, + kAudioUnitScope_Global, + 0, + &au_running, + &prop_size); + check_error_and_throw( + err, "AudioUnitGetProperty IsRunning", "audio_osx_sink::is_running"); } - bool - osx_sink::check_topology(int ninputs, int noutputs) - { - // check # output to make sure it's valid - if(noutputs != 0) { - - GR_LOG_FATAL(d_logger, boost::format - ("check_topology(): number of output " - "streams provided (%d) should be 0.") - % noutputs); - throw std::runtime_error - ("audio_osx_sink::check_topology"); - - } - - // check # outputs to make sure it's valid - if((ninputs < 1) | (ninputs > (int) d_n_dev_channels)) { - - GR_LOG_FATAL(d_logger, boost::format - ("check_topology(): number of input " - "streams provided (%d) should be in [1,%d] " - "for the selected output audio device.") - % ninputs % d_n_dev_channels); + return (au_running != 0); +} + +bool osx_sink::check_topology(int ninputs, int noutputs) +{ + // check # output to make sure it's valid + if (noutputs != 0) { + + GR_LOG_FATAL(d_logger, + boost::format("check_topology(): number of output " + "streams provided (%d) should be 0.") % + noutputs); throw std::runtime_error("audio_osx_sink::check_topology"); + } + + // check # outputs to make sure it's valid + if ((ninputs < 1) | (ninputs > (int)d_n_dev_channels)) { - } + GR_LOG_FATAL(d_logger, + boost::format("check_topology(): number of input " + "streams provided (%d) should be in [1,%d] " + "for the selected output audio device.") % + ninputs % d_n_dev_channels); + throw std::runtime_error("audio_osx_sink::check_topology"); + } - // save the actual number of input (user) channels + // save the actual number of input (user) channels - d_n_user_channels = ninputs; + d_n_user_channels = ninputs; #if _OSX_AU_DEBUG_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::check_topology: " - << "Actual # user input channels = " - << d_n_user_channels << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::check_topology: " + << "Actual # user input channels = " << d_n_user_channels << std::endl; #endif - return (true); - } + return (true); +} - void - osx_sink::check_channels(bool force_reset) - { - if (d_buffers.size() == 0) { +void osx_sink::check_channels(bool force_reset) +{ + if (d_buffers.size() == 0) { // allocate the output circular buffer(s), one per user channel d_buffers.resize(d_n_user_channels); - for(UInt32 nn = 0; nn < d_n_user_channels; ++nn) { - d_buffers[nn] = new circular_buffer<float> - (d_buffer_size_samples, false, false); + for (UInt32 nn = 0; nn < d_n_user_channels; ++nn) { + d_buffers[nn] = + new circular_buffer<float>(d_buffer_size_samples, false, false); } - } - else { - if(d_buffers.size() == d_n_user_channels) { - if (force_reset) { - for(UInt32 nn = 0; nn < d_buffers.size(); ++nn) { - d_buffers[nn]->reset(); + } else { + if (d_buffers.size() == d_n_user_channels) { + if (force_reset) { + for (UInt32 nn = 0; nn < d_buffers.size(); ++nn) { + d_buffers[nn]->reset(); + } } - } - return; + return; } // reallocate the output circular buffer(s) if (d_n_user_channels < d_buffers.size()) { - // too many buffers; delete some + // too many buffers; delete some - for (UInt32 nn = d_n_user_channels; nn < d_buffers.size(); ++nn) { - delete d_buffers[nn]; - d_buffers[nn] = 0; - } - d_buffers.resize(d_n_user_channels); + for (UInt32 nn = d_n_user_channels; nn < d_buffers.size(); ++nn) { + delete d_buffers[nn]; + d_buffers[nn] = 0; + } + d_buffers.resize(d_n_user_channels); - // reset remaining buffers + // reset remaining buffers - for(UInt32 nn = 0; nn < d_buffers.size(); ++nn) { - d_buffers[nn]->reset(); - } - } - else { + for (UInt32 nn = 0; nn < d_buffers.size(); ++nn) { + d_buffers[nn]->reset(); + } + } else { - // too few buffers; create some more + // too few buffers; create some more - // reset old buffers first + // reset old buffers first - for(UInt32 nn = 0; nn < d_buffers.size(); ++nn) { - d_buffers[nn]->reset(); - } + for (UInt32 nn = 0; nn < d_buffers.size(); ++nn) { + d_buffers[nn]->reset(); + } - d_buffers.resize(d_n_user_channels); - for (UInt32 nn = d_buffers.size(); nn < d_n_user_channels; ++nn) { - d_buffers[nn] = new circular_buffer<float> - (d_buffer_size_samples, false, false); - } + d_buffers.resize(d_n_user_channels); + for (UInt32 nn = d_buffers.size(); nn < d_n_user_channels; ++nn) { + d_buffers[nn] = + new circular_buffer<float>(d_buffer_size_samples, false, false); + } } - } + } - // reset the output audio unit for the correct number of channels - // have to uninitialize, set, initialize. + // reset the output audio unit for the correct number of channels + // have to uninitialize, set, initialize. - OSStatus err = AudioUnitUninitialize(d_output_au); - check_error(err, "AudioUnitUninitialize"); + OSStatus err = AudioUnitUninitialize(d_output_au); + check_error(err, "AudioUnitUninitialize"); - d_stream_format.mChannelsPerFrame = d_n_user_channels; + d_stream_format.mChannelsPerFrame = d_n_user_channels; - err = AudioUnitSetProperty - (d_output_au, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, 0, - &d_stream_format, sizeof(d_stream_format)); - check_error_and_throw - (err, "AudioUnitSetProperty StreamFormat", - "audio_osx_sink::check_channels"); + err = AudioUnitSetProperty(d_output_au, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 0, + &d_stream_format, + sizeof(d_stream_format)); + check_error_and_throw( + err, "AudioUnitSetProperty StreamFormat", "audio_osx_sink::check_channels"); - // initialize the AU for output, so that it is ready to be used + // initialize the AU for output, so that it is ready to be used - err = AudioUnitInitialize(d_output_au); - check_error_and_throw - (err, "AudioUnitInitialize", - "audio_osx_sink::check_channels"); - } + err = AudioUnitInitialize(d_output_au); + check_error_and_throw(err, "AudioUnitInitialize", "audio_osx_sink::check_channels"); +} - bool - osx_sink::start() - { - if(!is_running() && d_output_au) { +bool osx_sink::start() +{ + if (!is_running() && d_output_au) { #if _OSX_AU_DEBUG_ std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::start: starting Output AudioUnit." - << std::endl; + << " : audio_osx_sink::start: starting Output AudioUnit." << std::endl; #endif // check channels, (re)allocate and reset buffers if/as necessary @@ -672,302 +630,268 @@ namespace gr { // start the audio unit (should never fail) OSStatus err = AudioOutputUnitStart(d_output_au); - check_error_and_throw - (err, "AudioOutputUnitStart", - "audio_osx_sink::start"); - } + check_error_and_throw(err, "AudioOutputUnitStart", "audio_osx_sink::start"); + } #if _OSX_AU_DEBUG_ - else { - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::start: " + else { + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::start: " << "already running." << std::endl; - } + } #endif - return (true); - } + return (true); +} - bool - osx_sink::stop() - { - if(is_running()) { +bool osx_sink::stop() +{ + if (is_running()) { #if _OSX_AU_DEBUG_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::stop: " - << "stopping Output AudioUnit." - << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::stop: " + << "stopping Output AudioUnit." << std::endl; #endif // if waiting in ::work, signal to wake up if (d_waiting_for_data) { #if _OSX_AU_DEBUG_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::stop: " - << "signaling waiting condition" << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::stop: " + << "signaling waiting condition" << std::endl; #endif - d_cond_data.notify_one(); + d_cond_data.notify_one(); } // stop the audio unit (should never fail) OSStatus err = AudioOutputUnitStop(d_output_au); - check_error_and_throw - (err, "AudioOutputUnitStop", - "audio_osx_sink::stop"); + check_error_and_throw(err, "AudioOutputUnitStop", "audio_osx_sink::stop"); // abort and reset all buffers - for(UInt32 nn = 0; nn < d_n_user_channels; ++nn) { - d_buffers[nn]->abort(); - d_buffers[nn]->reset(); + for (UInt32 nn = 0; nn < d_n_user_channels; ++nn) { + d_buffers[nn]->abort(); + d_buffers[nn]->reset(); } // reset local knowledge of amount of data in queues d_queue_sample_count = 0; - } + } #if _OSX_AU_DEBUG_ - else { - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::stop: " + else { + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::stop: " << "already stopped." << std::endl; - } + } #endif - return(true); - } + return (true); +} - int - osx_sink::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { +int osx_sink::work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ #if _OSX_AU_DEBUG_RENDER_ - { + { gr::thread::scoped_lock l(d_internal); - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::work: " - << "Starting: #OI = " - << noutput_items << ", reset = " - << (d_do_reset ? "true" : "false") << std::endl; - } + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::work: " + << "Starting: #OI = " << noutput_items + << ", reset = " << (d_do_reset ? "true" : "false") << std::endl; + } #endif - if (d_do_reset) { + if (d_do_reset) { if (d_hardware_changed) { - // see if the current AudioDeviceID is still available - - std::vector < AudioDeviceID > all_ad_ids; - osx::find_audio_devices - (d_desired_name, false, - &all_ad_ids, NULL); - bool found = false; - for (UInt32 nn = 0; (nn < all_ad_ids.size()) && (!found); - ++nn) { - found = (all_ad_ids[nn] == d_output_ad_id); - } - if (!found) { + // see if the current AudioDeviceID is still available - GR_LOG_FATAL(d_logger, boost::format - ("The selected output audio device ('%s') " - "is no longer available.\n") - % d_selected_name); - return(gr::block::WORK_DONE); + std::vector<AudioDeviceID> all_ad_ids; + osx::find_audio_devices(d_desired_name, false, &all_ad_ids, NULL); + bool found = false; + for (UInt32 nn = 0; (nn < all_ad_ids.size()) && (!found); ++nn) { + found = (all_ad_ids[nn] == d_output_ad_id); + } + if (!found) { - } + GR_LOG_FATAL(d_logger, + boost::format("The selected output audio device ('%s') " + "is no longer available.\n") % + d_selected_name); + return (gr::block::WORK_DONE); + } - d_do_reset = d_hardware_changed = false; + d_do_reset = d_hardware_changed = false; - } - else { + } else { #if _OSX_AU_DEBUG_RENDER_ - { - gr::thread::scoped_lock l(d_internal); - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::work: " - << "doing reset." << std::endl; - } + { + gr::thread::scoped_lock l(d_internal); + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::work: " + << "doing reset." << std::endl; + } #endif - GR_LOG_WARN(d_logger, boost::format - ("\n\nThe default output audio device has " - "changed; resetting audio.\nThere may " - "be a sound glitch while resetting.\n")); + GR_LOG_WARN(d_logger, + boost::format("\n\nThe default output audio device has " + "changed; resetting audio.\nThere may " + "be a sound glitch while resetting.\n")); - // for any changes, just tear down the current - // configuration, then set it up again using the user's - // parameters to try to make selections. + // for any changes, just tear down the current + // configuration, then set it up again using the user's + // parameters to try to make selections. - teardown(); + teardown(); - gr::thread::scoped_lock l(d_internal); + gr::thread::scoped_lock l(d_internal); - setup(); - start(); + setup(); + start(); #if _OSX_AU_DEBUG_RENDER_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink: " - << "returning 0 after reset." - << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink: " + << "returning 0 after reset." << std::endl; #endif - return(0); + return (0); } - } + } - gr::thread::scoped_lock l(d_internal); + gr::thread::scoped_lock l(d_internal); - // take the input data, copy it, and push it to the bottom of - // the queue. mono input is pushed onto queue[0]; stereo input - // is pushed onto queue[1]. If the number of user/graph - // channels is less than the number of device channels, copy the - // data from the last / highest number channel to remaining - // device channels. + // take the input data, copy it, and push it to the bottom of + // the queue. mono input is pushed onto queue[0]; stereo input + // is pushed onto queue[1]. If the number of user/graph + // channels is less than the number of device channels, copy the + // data from the last / highest number channel to remaining + // device channels. - // find the maximum amount of buffer space available right now + // find the maximum amount of buffer space available right now - UInt32 l_max_count; - int diff_count = ((int)d_buffer_size_samples) - noutput_items; - if(diff_count < 0) { + UInt32 l_max_count; + int diff_count = ((int)d_buffer_size_samples) - noutput_items; + if (diff_count < 0) { l_max_count = 0; - } - else { + } else { l_max_count = (UInt32)diff_count; - } + } #if _OSX_AU_DEBUG_RENDER_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::work: " - << "qSC = " << d_queue_sample_count - << ", lMC = "<< l_max_count - << ", dBSC = " << d_buffer_size_samples - << ", #OI = " << noutput_items << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::work: " + << "qSC = " << d_queue_sample_count << ", lMC = " << l_max_count + << ", dBSC = " << d_buffer_size_samples << ", #OI = " << noutput_items + << std::endl; #endif - if(d_queue_sample_count > l_max_count) { + if (d_queue_sample_count > l_max_count) { // data coming in too fast; ok_to_block decides what to do: if // ok to block, then wait until the render callback makes // enough space. If not blocking, detect overflow via writing // data to the circular buffer. - if(d_ok_to_block == true) { - // block until there is data to return, or on reset - while(d_queue_sample_count > l_max_count) { - // release control so-as to allow data to be retrieved; - // block until there is data to return + if (d_ok_to_block == true) { + // block until there is data to return, or on reset + while (d_queue_sample_count > l_max_count) { + // release control so-as to allow data to be retrieved; + // block until there is data to return #if _OSX_AU_DEBUG_RENDER_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::work: " - << "waiting." << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::work: " + << "waiting." << std::endl; #endif - d_waiting_for_data = true; - d_cond_data.wait(l); - d_waiting_for_data = false; + d_waiting_for_data = true; + d_cond_data.wait(l); + d_waiting_for_data = false; #if _OSX_AU_DEBUG_RENDER_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::work: " - << "done waiting." << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::work: " + << "done waiting." << std::endl; #endif - // the condition's 'notify' was called; acquire control to - // keep thread safe + // the condition's 'notify' was called; acquire control to + // keep thread safe - // if doing a reset, just return here; reset will pick - // up the next time this method is called. - if (d_do_reset) { + // if doing a reset, just return here; reset will pick + // up the next time this method is called. + if (d_do_reset) { #if _OSX_AU_DEBUG_RENDER_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::work: " - << "returning 0 for reset." << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::work: " + << "returning 0 for reset." << std::endl; #endif - return(0); + return (0); + } } - } } - } + } - // not blocking and overflow is handled by the circular buffer, - // or enough data space is available + // not blocking and overflow is handled by the circular buffer, + // or enough data space is available - // add the input frames to the buffers' queue, checking for overflow + // add the input frames to the buffers' queue, checking for overflow - UInt32 nn; - int res = 0; - float* inBuffer = (float*)input_items[0]; - const UInt32 l_size = input_items.size(); - for(nn = 0; nn < l_size; ++nn) { + UInt32 nn; + int res = 0; + float* inBuffer = (float*)input_items[0]; + const UInt32 l_size = input_items.size(); + for (nn = 0; nn < l_size; ++nn) { inBuffer = (float*)input_items[nn]; int l_res = d_buffers[nn]->enqueue(inBuffer, noutput_items); - if(l_res == -1) { - res = -1; + if (l_res == -1) { + res = -1; } - } - while(nn < d_n_user_channels) { + } + while (nn < d_n_user_channels) { // for extra channels, copy the last input's data int l_res = d_buffers[nn++]->enqueue(inBuffer, noutput_items); - if(l_res == -1) { - res = -1; + if (l_res == -1) { + res = -1; } - } + } - // did overflow occur? + // did overflow occur? - if(res == -1) { + if (res == -1) { // yes: data coming in too fast; drop oldest data. fputs("aO", stderr); fflush(stderr); // set the local number of samples available to the max d_queue_sample_count = d_buffers[0]->buffer_length_items(); - } - else { + } else { // no: keep up the local sample count d_queue_sample_count += noutput_items; - } + } #if _OSX_AU_DEBUG_RENDER_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::work: " - << "returning: #OI = " - << noutput_items << ", qSC = " - << d_queue_sample_count << ", bSS = " - << d_buffer_size_samples << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::work: " + << "returning: #OI = " << noutput_items + << ", qSC = " << d_queue_sample_count << ", bSS = " << d_buffer_size_samples + << std::endl; #endif - return (noutput_items); - } + return (noutput_items); +} - OSStatus - osx_sink::au_output_callback - (void* in_ref_con, - AudioUnitRenderActionFlags* io_action_flags, - const AudioTimeStamp* in_time_stamp, - UInt32 in_bus_number, - UInt32 in_number_frames, - AudioBufferList* io_data) - { - // NOTE: This is a callback from the OS, so throwing here does - // not work; return an error instead when something does not go - // as planned. +OSStatus osx_sink::au_output_callback(void* in_ref_con, + AudioUnitRenderActionFlags* io_action_flags, + const AudioTimeStamp* in_time_stamp, + UInt32 in_bus_number, + UInt32 in_number_frames, + AudioBufferList* io_data) +{ + // NOTE: This is a callback from the OS, so throwing here does + // not work; return an error instead when something does not go + // as planned. - osx_sink* This = reinterpret_cast<osx_sink*>(in_ref_con); - OSStatus err = noErr; + osx_sink* This = reinterpret_cast<osx_sink*>(in_ref_con); + OSStatus err = noErr; - gr::thread::scoped_lock l(This->d_internal); + gr::thread::scoped_lock l(This->d_internal); #if _OSX_AU_DEBUG_RENDER_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::au_output_callback: " - << "starting: qSC = " - << This->d_queue_sample_count - << ", in#F = " << in_number_frames - << ", in#C = " << This->d_n_user_channels << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::au_output_callback: " + << "starting: qSC = " << This->d_queue_sample_count + << ", in#F = " << in_number_frames << ", in#C = " << This->d_n_user_channels + << std::endl; #endif - if(This->d_queue_sample_count < in_number_frames) { + if (This->d_queue_sample_count < in_number_frames) { // not enough data to fill request; probably happened on // start-up, where this callback was called before ::work was. @@ -976,101 +900,85 @@ namespace gr { fflush(stderr); err = kAudioUnitErr_Initialized; - } - else { + } else { // enough data; remove data from our buffers into the AU's buffers int nn = This->d_n_user_channels; - while(--nn >= 0) { - - size_t t_n_output_items = in_number_frames; - float* out_buffer = (float*)(io_data->mBuffers[nn].mData); - int rv = This->d_buffers[nn]->dequeue - (out_buffer, &t_n_output_items); + while (--nn >= 0) { - if((rv != 1) || (t_n_output_items != in_number_frames)) { + size_t t_n_output_items = in_number_frames; + float* out_buffer = (float*)(io_data->mBuffers[nn].mData); + int rv = This->d_buffers[nn]->dequeue(out_buffer, &t_n_output_items); - std::cerr << "audio_osx_sink::au_output_callback: " - << "number of available items changing " - << "unexpectedly (should never happen): was " - << in_number_frames << " now " - << t_n_output_items<< std::endl; - err = kAudioUnitErr_TooManyFramesToProcess; + if ((rv != 1) || (t_n_output_items != in_number_frames)) { - } + std::cerr << "audio_osx_sink::au_output_callback: " + << "number of available items changing " + << "unexpectedly (should never happen): was " + << in_number_frames << " now " << t_n_output_items << std::endl; + err = kAudioUnitErr_TooManyFramesToProcess; + } } This->d_queue_sample_count -= in_number_frames; - } + } - // signal that data is available, if appropriate + // signal that data is available, if appropriate - if (This->d_waiting_for_data) { + if (This->d_waiting_for_data) { #if _OSX_AU_DEBUG_RENDER_ std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::au_output_callback: " << "signaling waiting condition" << std::endl; #endif This->d_cond_data.notify_one(); - } + } #if _OSX_AU_DEBUG_RENDER_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_sink::au_output_callback: " - << "returning: qSC = " - << This->d_queue_sample_count - << ", err = " << err << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_sink::au_output_callback: " + << "returning: qSC = " << This->d_queue_sample_count << ", err = " << err + << std::endl; #endif - return (err); - } + return (err); +} #ifndef GR_USE_OLD_AUDIO_UNIT - OSStatus - osx_sink::hardware_listener - (AudioObjectID in_object_id, - UInt32 in_num_addresses, - const AudioObjectPropertyAddress in_addresses[], - void* in_client_data) +OSStatus osx_sink::hardware_listener(AudioObjectID in_object_id, + UInt32 in_num_addresses, + const AudioObjectPropertyAddress in_addresses[], + void* in_client_data) #else - OSStatus - osx_sink::hardware_listener - (AudioHardwarePropertyID in_property_id, - void* in_client_data) +OSStatus osx_sink::hardware_listener(AudioHardwarePropertyID in_property_id, + void* in_client_data) #endif - { - osx_sink* This = static_cast - <osx_sink*>(in_client_data); - This->reset(true); - return(noErr); - } +{ + osx_sink* This = static_cast<osx_sink*>(in_client_data); + This->reset(true); + return (noErr); +} #ifndef GR_USE_OLD_AUDIO_UNIT - OSStatus - osx_sink::default_listener - (AudioObjectID in_object_id, - UInt32 in_num_addresses, - const AudioObjectPropertyAddress in_addresses[], - void* in_client_data) +OSStatus osx_sink::default_listener(AudioObjectID in_object_id, + UInt32 in_num_addresses, + const AudioObjectPropertyAddress in_addresses[], + void* in_client_data) #else - OSStatus - osx_sink::default_listener - (AudioHardwarePropertyID in_property_id, - void* in_client_data) +OSStatus osx_sink::default_listener(AudioHardwarePropertyID in_property_id, + void* in_client_data) #endif - { - osx_sink* This = reinterpret_cast - <osx_sink*>(in_client_data); - This->reset(false); - return(noErr); - } +{ + osx_sink* This = reinterpret_cast<osx_sink*>(in_client_data); + This->reset(false); + return (noErr); +} - } /* namespace audio */ +} /* namespace audio */ } /* namespace gr */ diff --git a/gr-audio/lib/osx/osx_sink.h b/gr-audio/lib/osx/osx_sink.h index 127f243495..db7763e188 100644 --- a/gr-audio/lib/osx/osx_sink.h +++ b/gr-audio/lib/osx/osx_sink.h @@ -29,109 +29,97 @@ #include "circular_buffer.h" namespace gr { - namespace audio { +namespace audio { - /*! - * \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 osx_sink : public sink - { - protected: - - Float64 d_input_sample_rate; - UInt32 d_n_user_channels, d_n_dev_channels, d_n_buffer_channels; - UInt32 d_queue_sample_count, d_buffer_size_samples; - bool d_ok_to_block, d_do_reset, d_hardware_changed; - bool d_using_default_device, d_waiting_for_data; - gr::thread::mutex d_internal; - gr::thread::condition_variable d_cond_data; - std::vector < circular_buffer < float > *> d_buffers; - std::string d_desired_name, d_selected_name; - - // AudioUnits and Such +/*! + * \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]. + */ - AudioUnit d_output_au; - AudioDeviceID d_output_ad_id; - AudioStreamBasicDescription d_stream_format; +class osx_sink : public sink +{ +protected: + Float64 d_input_sample_rate; + UInt32 d_n_user_channels, d_n_dev_channels, d_n_buffer_channels; + UInt32 d_queue_sample_count, d_buffer_size_samples; + bool d_ok_to_block, d_do_reset, d_hardware_changed; + bool d_using_default_device, d_waiting_for_data; + gr::thread::mutex d_internal; + gr::thread::condition_variable d_cond_data; + std::vector<circular_buffer<float>*> d_buffers; + std::string d_desired_name, d_selected_name; - public: + // AudioUnits and Such - osx_sink(int sample_rate, - const std::string& device_name, - bool ok_to_block); + AudioUnit d_output_au; + AudioDeviceID d_output_ad_id; + AudioStreamBasicDescription d_stream_format; - inline virtual ~osx_sink() { - teardown(); - } +public: + osx_sink(int sample_rate, const std::string& device_name, bool ok_to_block); - virtual bool check_topology(int ninputs, int noutputs); - virtual bool start(); - virtual bool stop(); + inline virtual ~osx_sink() { teardown(); } - virtual int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + virtual bool check_topology(int ninputs, int noutputs); + virtual bool start(); + virtual bool stop(); - inline void reset(bool hardware_changed) { - d_hardware_changed = hardware_changed; - d_do_reset = true; - } + virtual int work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); - private: + inline void reset(bool hardware_changed) + { + d_hardware_changed = hardware_changed; + d_do_reset = true; + } - bool is_running(); +private: + bool is_running(); - void setup(); + void setup(); - void teardown(); + void teardown(); - void check_channels(bool force_reset); + void check_channels(bool force_reset); - static OSStatus au_output_callback - (void* in_ref_con, - AudioUnitRenderActionFlags* io_action_flags, - const AudioTimeStamp* in_time_stamp, - UInt32 in_bus_number, - UInt32 in_number_frames, - AudioBufferList* io_data); + static OSStatus au_output_callback(void* in_ref_con, + AudioUnitRenderActionFlags* io_action_flags, + const AudioTimeStamp* in_time_stamp, + UInt32 in_bus_number, + UInt32 in_number_frames, + AudioBufferList* io_data); #ifndef GR_USE_OLD_AUDIO_UNIT - // OSX 10.4 and newer + // OSX 10.4 and newer - static OSStatus hardware_listener - (AudioObjectID in_object_id, - UInt32 in_num_addresses, - const AudioObjectPropertyAddress in_addresses[], - void* in_client_data); + static OSStatus hardware_listener(AudioObjectID in_object_id, + UInt32 in_num_addresses, + const AudioObjectPropertyAddress in_addresses[], + void* in_client_data); - static OSStatus default_listener - (AudioObjectID in_object_id, - UInt32 in_num_addresses, - const AudioObjectPropertyAddress in_addresses[], - void* in_client_data); + static OSStatus default_listener(AudioObjectID in_object_id, + UInt32 in_num_addresses, + const AudioObjectPropertyAddress in_addresses[], + void* in_client_data); #else - // OSX 10.6 and older; removed as of 10.7 + // OSX 10.6 and older; removed as of 10.7 - static OSStatus hardware_listener - (AudioHardwarePropertyID in_property_id, - void* in_client_data); + static OSStatus hardware_listener(AudioHardwarePropertyID in_property_id, + void* in_client_data); - static OSStatus default_listener - (AudioHardwarePropertyID in_property_id, - void* in_client_data); + static OSStatus default_listener(AudioHardwarePropertyID in_property_id, + void* in_client_data); #endif - - }; - } /* namespace audio */ +}; +} /* namespace audio */ } /* namespace gr */ #endif /* INCLUDED_AUDIO_OSX_SINK_H */ diff --git a/gr-audio/lib/osx/osx_source.cc b/gr-audio/lib/osx/osx_source.cc index 48001e2638..5dfd2b8390 100644 --- a/gr-audio/lib/osx/osx_source.cc +++ b/gr-audio/lib/osx/osx_source.cc @@ -32,477 +32,466 @@ #include <stdexcept> namespace gr { - namespace audio { - - source::sptr - osx_source_fcn(int sampling_rate, - const std::string& device_name, - bool ok_to_block) - { - return source::sptr - (new osx_source(sampling_rate, device_name, ok_to_block)); - } - - static std::string - default_device_name() - { - return prefs::singleton()->get_string - ("audio_osx", "default_input_device", "built-in"); - } - - osx_source::osx_source - (int sample_rate, - const std::string& device_name, - bool ok_to_block) - : sync_block("audio_osx_source", - io_signature::make(0, 0, 0), - io_signature::make(0, 0, 0)), - d_device_sample_rate(0.0), d_output_sample_rate(0.0), - d_input_buffer_size_frames(0), d_input_buffer_size_bytes(0), - d_output_buffer_size_frames(0), d_output_buffer_size_bytes(0), - d_device_buffer_size_frames(0), d_device_buffer_size_bytes(0), - d_lead_size_frames(0), d_lead_size_bytes(0), - d_trail_size_frames(0), d_trail_size_bytes(0), - d_extra_buffer_size_frames(0), d_extra_buffer_size_bytes(0), - d_queue_sample_count(0), d_buffer_sample_count(0), - d_n_available_input_frames(0), d_n_actual_input_frames(0), - d_n_user_channels(0), d_n_dev_channels(0), - d_ok_to_block(ok_to_block), d_pass_through(false), - d_waiting_for_data(false), d_do_reset(false), - d_hardware_changed(false), d_using_default_device(false), - d_desired_name(device_name.empty() ? default_device_name() - : device_name), - d_input_ad_id(0), d_input_au(0), d_input_buffer(0), - d_output_buffer(0), d_audio_converter(0) - { - // set the desired output sample rate - - if(sample_rate <= 0) { - GR_LOG_ERROR(d_logger, boost::format - ("Invalid Sample Rate: %d") - % sample_rate); +namespace audio { + +source::sptr +osx_source_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block) +{ + return source::sptr(new osx_source(sampling_rate, device_name, ok_to_block)); +} + +static std::string default_device_name() +{ + return prefs::singleton()->get_string( + "audio_osx", "default_input_device", "built-in"); +} + +osx_source::osx_source(int sample_rate, const std::string& device_name, bool ok_to_block) + : sync_block( + "audio_osx_source", io_signature::make(0, 0, 0), io_signature::make(0, 0, 0)), + d_device_sample_rate(0.0), + d_output_sample_rate(0.0), + d_input_buffer_size_frames(0), + d_input_buffer_size_bytes(0), + d_output_buffer_size_frames(0), + d_output_buffer_size_bytes(0), + d_device_buffer_size_frames(0), + d_device_buffer_size_bytes(0), + d_lead_size_frames(0), + d_lead_size_bytes(0), + d_trail_size_frames(0), + d_trail_size_bytes(0), + d_extra_buffer_size_frames(0), + d_extra_buffer_size_bytes(0), + d_queue_sample_count(0), + d_buffer_sample_count(0), + d_n_available_input_frames(0), + d_n_actual_input_frames(0), + d_n_user_channels(0), + d_n_dev_channels(0), + d_ok_to_block(ok_to_block), + d_pass_through(false), + d_waiting_for_data(false), + d_do_reset(false), + d_hardware_changed(false), + d_using_default_device(false), + d_desired_name(device_name.empty() ? default_device_name() : device_name), + d_input_ad_id(0), + d_input_au(0), + d_input_buffer(0), + d_output_buffer(0), + d_audio_converter(0) +{ + // set the desired output sample rate + + if (sample_rate <= 0) { + GR_LOG_ERROR(d_logger, boost::format("Invalid Sample Rate: %d") % sample_rate); throw std::invalid_argument("audio_osx_source"); - } - else { + } else { d_output_sample_rate = (Float64)sample_rate; - } - - // set up for audio input using the stored desired parameters - - setup(); } - void osx_source::setup() - { - OSStatus err = noErr; + // set up for audio input using the stored desired parameters - // set the default input audio device id to "unknown" + setup(); +} - d_input_ad_id = kAudioDeviceUnknown; +void osx_source::setup() +{ + OSStatus err = noErr; - // try to find the input audio device, if specified + // set the default input audio device id to "unknown" - std::vector < AudioDeviceID > all_ad_ids; - std::vector < std::string > all_names; + d_input_ad_id = kAudioDeviceUnknown; - osx::find_audio_devices - (d_desired_name, true, - &all_ad_ids, &all_names); + // try to find the input audio device, if specified - // check number of device(s) returned + std::vector<AudioDeviceID> all_ad_ids; + std::vector<std::string> all_names; - if (d_desired_name.length() != 0) { - if (all_ad_ids.size() == 1) { + osx::find_audio_devices(d_desired_name, true, &all_ad_ids, &all_names); - // exactly 1 match was found; see if it was partial + // check number of device(s) returned - if (all_names[0].compare(d_desired_name) != 0) { + if (d_desired_name.length() != 0) { + if (all_ad_ids.size() == 1) { - // yes: log the full device name - GR_LOG_INFO(d_logger, boost::format - ("Using input audio device '%s'.") - % all_names[0]); + // exactly 1 match was found; see if it was partial - } + if (all_names[0].compare(d_desired_name) != 0) { - // store info on this device + // yes: log the full device name + GR_LOG_INFO(d_logger, + boost::format("Using input audio device '%s'.") % + all_names[0]); + } - d_input_ad_id = all_ad_ids[0]; - d_selected_name = all_names[0]; + // store info on this device - } else { + d_input_ad_id = all_ad_ids[0]; + d_selected_name = all_names[0]; - // either 0 or more than 1 device was found; get all input - // device names, print those, and error out. + } else { - osx::find_audio_devices("", true, NULL, &all_names); + // either 0 or more than 1 device was found; get all input + // device names, print those, and error out. - std::string err_str("\n\nA unique input audio device name " - "matching the string '"); - err_str += d_desired_name; - err_str += "' was not found.\n\n"; - err_str += "The current known input audio device name"; - err_str += ((all_names.size() > 1) ? "s are" : " is"); - err_str += ":\n"; - for (UInt32 nn = 0; nn < all_names.size(); ++nn) { - err_str += " " + all_names[nn] + "\n"; - } - GR_LOG_ERROR(d_logger, boost::format(err_str)); - throw std::runtime_error("audio_osx_source::setup"); + osx::find_audio_devices("", true, NULL, &all_names); - } - } + std::string err_str("\n\nA unique input audio device name " + "matching the string '"); + err_str += d_desired_name; + err_str += "' was not found.\n\n"; + err_str += "The current known input audio device name"; + err_str += ((all_names.size() > 1) ? "s are" : " is"); + err_str += ":\n"; + for (UInt32 nn = 0; nn < all_names.size(); ++nn) { + err_str += " " + all_names[nn] + "\n"; + } + GR_LOG_ERROR(d_logger, boost::format(err_str)); + throw std::runtime_error("audio_osx_source::setup"); + } + } - // if no input audio device id was found or no specific device - // name was provided, use the default input audio device id as - // set in System Preferences. + // if no input audio device id was found or no specific device + // name was provided, use the default input audio device id as + // set in System Preferences. - if (d_input_ad_id == kAudioDeviceUnknown) { + if (d_input_ad_id == kAudioDeviceUnknown) { UInt32 prop_size = (UInt32)sizeof(AudioDeviceID); AudioObjectPropertyAddress ao_address = { - kAudioHardwarePropertyDefaultInputDevice, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster + kAudioHardwarePropertyDefaultInputDevice, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; - err = AudioObjectGetPropertyData - (kAudioObjectSystemObject, &ao_address, - 0, NULL, &prop_size, &d_input_ad_id); - check_error_and_throw - (err, "Getting the default input audio device ID failed", - "audio_osx_source::setup"); - - { - // retrieve the device name; max name length is 64 characters. - - UInt32 prop_size = 65; - char c_name_buf[prop_size]; - memset((void*)c_name_buf, 0, (size_t)prop_size); - --prop_size; - - AudioObjectPropertyAddress ao_address = { - kAudioDevicePropertyDeviceName, - kAudioDevicePropertyScopeInput, 0 - }; - - if ((err = AudioObjectGetPropertyData - (d_input_ad_id, &ao_address, 0, NULL, - &prop_size, (void*)c_name_buf)) != noErr) { - - check_error(err, "Unable to retrieve input audio device name"); - - } else { - - GR_LOG_INFO(d_logger, boost::format - ("\n\nUsing input audio device '%s'.\n ... " - "which is the current default input audio" - " device.\n Changing the default input" - " audio device in the System Preferences" - " will \n result in changing it here, too " - "(with an internal reconfiguration).\n") % - std::string(c_name_buf)); - - } - - d_selected_name = c_name_buf; - - } + err = AudioObjectGetPropertyData( + kAudioObjectSystemObject, &ao_address, 0, NULL, &prop_size, &d_input_ad_id); + check_error_and_throw(err, + "Getting the default input audio device ID failed", + "audio_osx_source::setup"); + + { + // retrieve the device name; max name length is 64 characters. + + UInt32 prop_size = 65; + char c_name_buf[prop_size]; + memset((void*)c_name_buf, 0, (size_t)prop_size); + --prop_size; + + AudioObjectPropertyAddress ao_address = { kAudioDevicePropertyDeviceName, + kAudioDevicePropertyScopeInput, + 0 }; + + if ((err = AudioObjectGetPropertyData(d_input_ad_id, + &ao_address, + 0, + NULL, + &prop_size, + (void*)c_name_buf)) != noErr) { + + check_error(err, "Unable to retrieve input audio device name"); + + } else { + + GR_LOG_INFO(d_logger, + boost::format("\n\nUsing input audio device '%s'.\n ... " + "which is the current default input audio" + " device.\n Changing the default input" + " audio device in the System Preferences" + " will \n result in changing it here, too " + "(with an internal reconfiguration).\n") % + std::string(c_name_buf)); + } - d_using_default_device = true; + d_selected_name = c_name_buf; + } - } + d_using_default_device = true; + } - // retrieve the total number of channels for the selected input - // audio device + // retrieve the total number of channels for the selected input + // audio device - osx::get_num_channels_for_audio_device_id - (d_input_ad_id, &d_n_dev_channels, NULL); + osx::get_num_channels_for_audio_device_id(d_input_ad_id, &d_n_dev_channels, NULL); - // set the block output signature, if not already set - // (d_n_user_channels is set in check_topology, which is called - // before the flow-graph is running) + // set the block output signature, if not already set + // (d_n_user_channels is set in check_topology, which is called + // before the flow-graph is running) - if (d_n_user_channels == 0) { - set_output_signature(io_signature::make - (1, d_n_dev_channels, sizeof(float))); - } + if (d_n_user_channels == 0) { + set_output_signature(io_signature::make(1, d_n_dev_channels, sizeof(float))); + } - // set the interim buffer size; to work with the GR scheduler, - // must be at least 16kB. Pick 50 kB since that's plenty yet - // not very much. + // set the interim buffer size; to work with the GR scheduler, + // must be at least 16kB. Pick 50 kB since that's plenty yet + // not very much. - d_buffer_sample_count = (d_output_sample_rate < 50000.0 ? - 50000 : (UInt32)d_output_sample_rate); + d_buffer_sample_count = + (d_output_sample_rate < 50000.0 ? 50000 : (UInt32)d_output_sample_rate); #if _OSX_AU_DEBUG_ - std::cerr << "source(): max # samples = " - << d_buffer_sample_count << std::endl; + std::cerr << "source(): max # samples = " << d_buffer_sample_count << std::endl; #endif - // create the default AudioUnit for input + // create the default AudioUnit for input - // Open the default input unit + // Open the default input unit #ifndef GR_USE_OLD_AUDIO_UNIT - AudioComponentDescription desc; + AudioComponentDescription desc; #else - ComponentDescription desc; + ComponentDescription desc; #endif - desc.componentType = kAudioUnitType_Output; - desc.componentSubType = kAudioUnitSubType_HALOutput; - desc.componentManufacturer = kAudioUnitManufacturer_Apple; - desc.componentFlags = 0; - desc.componentFlagsMask = 0; + desc.componentType = kAudioUnitType_Output; + desc.componentSubType = kAudioUnitSubType_HALOutput; + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + desc.componentFlags = 0; + desc.componentFlagsMask = 0; #ifndef GR_USE_OLD_AUDIO_UNIT - AudioComponent comp = AudioComponentFindNext(NULL, &desc); - if(!comp) { - GR_LOG_FATAL(d_logger, boost::format - ("AudioComponentFindNext Failed")); + AudioComponent comp = AudioComponentFindNext(NULL, &desc); + if (!comp) { + GR_LOG_FATAL(d_logger, boost::format("AudioComponentFindNext Failed")); throw std::runtime_error("audio_osx_source::setup"); - } - err = AudioComponentInstanceNew(comp, &d_input_au); - check_error_and_throw(err, "AudioComponentInstanceNew Failed", - "audio_osx_source::setup"); + } + err = AudioComponentInstanceNew(comp, &d_input_au); + check_error_and_throw( + err, "AudioComponentInstanceNew Failed", "audio_osx_source::setup"); #else - Component comp = FindNextComponent(NULL, &desc); - if(!comp) { - GR_LOG_FATAL(d_logger, boost::format - ("FindNextComponent Failed")); + Component comp = FindNextComponent(NULL, &desc); + if (!comp) { + GR_LOG_FATAL(d_logger, boost::format("FindNextComponent Failed")); throw std::runtime_error("audio_osx_source::setup"); - } - err = OpenAComponent(comp, &d_input_au); - check_error_and_throw(err, "OpenAComponent Failed", - "audio_osx_source::setup"); + } + err = OpenAComponent(comp, &d_input_au); + check_error_and_throw(err, "OpenAComponent Failed", "audio_osx_source::setup"); #endif - // must enable the AUHAL for input and disable output - // before setting the AUHAL's current device - - // Enable input on the AUHAL - - UInt32 enable_io = 1; - err = AudioUnitSetProperty - (d_input_au, - kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Input, 1, // input element - &enable_io, sizeof(enable_io)); - check_error_and_throw - (err, "AudioUnitSetProperty Input Enable", - "audio_osx_source::setup"); - - // Disable output on the AUHAL - - enable_io = 0; - err = AudioUnitSetProperty - (d_input_au, - kAudioOutputUnitProperty_EnableIO, - kAudioUnitScope_Output, 0, // output element - &enable_io, sizeof(enable_io)); - check_error_and_throw - (err, "AudioUnitSetProperty Output Disable", - "audio_osx_source::setup"); - - // set the selected device ID as the current input device - - err = AudioUnitSetProperty - (d_input_au, kAudioOutputUnitProperty_CurrentDevice, - kAudioUnitScope_Global, 0, - &d_input_ad_id, sizeof(d_input_ad_id)); - check_error_and_throw - (err, "Setting selected input device as current failed", - "audio_osx_source::setup"); - - // Set up a callback function to retrieve input from the Audio Device - - AURenderCallbackStruct au_callback = { - reinterpret_cast<AURenderCallback> - (&osx_source::au_input_callback), - reinterpret_cast<void*>(this) - }; - UInt32 prop_size = (UInt32)sizeof(au_callback); - - err = AudioUnitSetProperty - (d_input_au, - kAudioOutputUnitProperty_SetInputCallback, - kAudioUnitScope_Global, 0, - &au_callback, prop_size); - check_error_and_throw - (err, "Set Input Callback", - "audio_osx_source::setup"); - - // Get the Stream Format (device side; cannot generally be changed) - - prop_size = (UInt32)sizeof(d_asbd_device); - memset((void*)(&d_asbd_device), 0, (size_t)prop_size); - err = AudioUnitGetProperty - (d_input_au, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, 1, - &d_asbd_device, &prop_size); - check_error_and_throw - (err, "Get Device Input Stream Format (before) failed", - "audio_osx_source::setup"); + // must enable the AUHAL for input and disable output + // before setting the AUHAL's current device + + // Enable input on the AUHAL + + UInt32 enable_io = 1; + err = AudioUnitSetProperty(d_input_au, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Input, + 1, // input element + &enable_io, + sizeof(enable_io)); + check_error_and_throw( + err, "AudioUnitSetProperty Input Enable", "audio_osx_source::setup"); + + // Disable output on the AUHAL + + enable_io = 0; + err = AudioUnitSetProperty(d_input_au, + kAudioOutputUnitProperty_EnableIO, + kAudioUnitScope_Output, + 0, // output element + &enable_io, + sizeof(enable_io)); + check_error_and_throw( + err, "AudioUnitSetProperty Output Disable", "audio_osx_source::setup"); + + // set the selected device ID as the current input device + + err = AudioUnitSetProperty(d_input_au, + kAudioOutputUnitProperty_CurrentDevice, + kAudioUnitScope_Global, + 0, + &d_input_ad_id, + sizeof(d_input_ad_id)); + check_error_and_throw(err, + "Setting selected input device as current failed", + "audio_osx_source::setup"); + + // Set up a callback function to retrieve input from the Audio Device + + AURenderCallbackStruct au_callback = { reinterpret_cast<AURenderCallback>( + &osx_source::au_input_callback), + reinterpret_cast<void*>(this) }; + UInt32 prop_size = (UInt32)sizeof(au_callback); + + err = AudioUnitSetProperty(d_input_au, + kAudioOutputUnitProperty_SetInputCallback, + kAudioUnitScope_Global, + 0, + &au_callback, + prop_size); + check_error_and_throw(err, "Set Input Callback", "audio_osx_source::setup"); + + // Get the Stream Format (device side; cannot generally be changed) + + prop_size = (UInt32)sizeof(d_asbd_device); + memset((void*)(&d_asbd_device), 0, (size_t)prop_size); + err = AudioUnitGetProperty(d_input_au, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 1, + &d_asbd_device, + &prop_size); + check_error_and_throw( + err, "Get Device Input Stream Format (before) failed", "audio_osx_source::setup"); #if _OSX_AU_DEBUG_ - std::cerr << std::endl << "---- Device Stream Format (before) ----" - << std::endl << d_asbd_device << std::endl << std::endl; + std::cerr << std::endl + << "---- Device Stream Format (before) ----" << std::endl + << d_asbd_device << std::endl + << std::endl; #endif - // try to set the device (input) side of the audio device to the - // sample rate of this source. This will likely fail, and - // that's OK; just ignore the error since we can accomplish - // audio input in other ways. - - prop_size = (UInt32)sizeof(d_asbd_device); - d_asbd_device.mSampleRate = d_output_sample_rate; - err = AudioUnitSetProperty - (d_input_au, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, 1, - &d_asbd_device, prop_size); + // try to set the device (input) side of the audio device to the + // sample rate of this source. This will likely fail, and + // that's OK; just ignore the error since we can accomplish + // audio input in other ways. + + prop_size = (UInt32)sizeof(d_asbd_device); + d_asbd_device.mSampleRate = d_output_sample_rate; + err = AudioUnitSetProperty(d_input_au, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 1, + &d_asbd_device, + prop_size); #if _OSX_AU_DEBUG_ - check_error - (err, "Set Device Input Stream Format failed (expected)"); + check_error(err, "Set Device Input Stream Format failed (expected)"); #endif - memset((void*)(&d_asbd_device), 0, (size_t)prop_size); - err = AudioUnitGetProperty - (d_input_au, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Input, 1, - &d_asbd_device, &prop_size); - check_error_and_throw - (err, "Get Device Input Stream Format (after) failed", - "audio_osx_source::setup"); + memset((void*)(&d_asbd_device), 0, (size_t)prop_size); + err = AudioUnitGetProperty(d_input_au, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Input, + 1, + &d_asbd_device, + &prop_size); + check_error_and_throw( + err, "Get Device Input Stream Format (after) failed", "audio_osx_source::setup"); #if _OSX_AU_DEBUG_ - std::cerr << std::endl << "---- Device Stream Format (after) ----" - << std::endl << d_asbd_device << std::endl << std::endl; + std::cerr << std::endl + << "---- Device Stream Format (after) ----" << std::endl + << d_asbd_device << std::endl + << std::endl; #endif - d_device_sample_rate = d_asbd_device.mSampleRate; + d_device_sample_rate = d_asbd_device.mSampleRate; - // Get the Stream Format (client side; might be changeable) + // Get the Stream Format (client side; might be changeable) - prop_size = (UInt32)sizeof(d_asbd_client); - memset((void*)(&d_asbd_client), 0, (size_t)prop_size); - err = AudioUnitGetProperty - (d_input_au, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, 1, - &d_asbd_client, &prop_size); - check_error_and_throw - (err, "Get Device Output Stream Format (before) failed", - "audio_osx_source::setup"); + prop_size = (UInt32)sizeof(d_asbd_client); + memset((void*)(&d_asbd_client), 0, (size_t)prop_size); + err = AudioUnitGetProperty(d_input_au, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + 1, + &d_asbd_client, + &prop_size); + check_error_and_throw(err, + "Get Device Output Stream Format (before) failed", + "audio_osx_source::setup"); #if _OSX_AU_DEBUG_ - std::cerr << "---- Client Stream Format (Before) ----" - << std::endl << d_asbd_client << std::endl << std::endl; + std::cerr << "---- Client Stream Format (Before) ----" << std::endl + << d_asbd_client << std::endl + << std::endl; #endif - // Set the format of all the AUs to the - // input/output devices channel count + // Set the format of all the AUs to the + // input/output devices channel count - d_asbd_client.mFormatID = kAudioFormatLinearPCM; - d_asbd_client.mFormatFlags = (kAudioFormatFlagIsFloat | - kAudioFormatFlagIsPacked | + d_asbd_client.mFormatID = kAudioFormatLinearPCM; + d_asbd_client.mFormatFlags = (kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved); - if((d_asbd_client.mFormatID == kAudioFormatLinearPCM) && - (d_n_dev_channels == 1)) { + if ((d_asbd_client.mFormatID == kAudioFormatLinearPCM) && (d_n_dev_channels == 1)) { d_asbd_client.mFormatFlags &= ~kLinearPCMFormatFlagIsNonInterleaved; - } - d_asbd_client.mBytesPerFrame = (UInt32)sizeof(float); - d_asbd_client.mFramesPerPacket = 1; - d_asbd_client.mBitsPerChannel = d_asbd_client.mBytesPerFrame * 8; - d_asbd_client.mChannelsPerFrame = d_n_dev_channels; - d_asbd_client.mBytesPerPacket = d_asbd_client.mBytesPerFrame; - - // according to Apple docs [see, e.g., Apple Technical Note - // TN2091 "Device input using the HAL Output Audio Unit"], the - // device input and output sample rate must be the same; do - // sample rate conversion elsewhere. - - d_asbd_client.mSampleRate = d_asbd_device.mSampleRate; - err = AudioUnitSetProperty - (d_input_au, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, 1, - &d_asbd_client, prop_size); - check_error_and_throw - (err, "Set Device Output Stream Format failed", - "audio_osx_source::setup"); - - // Get the Stream Format (client side), again - - prop_size = (UInt32)sizeof(d_asbd_client); - memset((void*)(&d_asbd_client), 0, (size_t)prop_size); - err = AudioUnitGetProperty - (d_input_au, - kAudioUnitProperty_StreamFormat, - kAudioUnitScope_Output, 1, - &d_asbd_client, &prop_size); - check_error_and_throw - (err, "Get Device Output Stream Format (after) failed", - "audio_osx_source::setup"); + } + d_asbd_client.mBytesPerFrame = (UInt32)sizeof(float); + d_asbd_client.mFramesPerPacket = 1; + d_asbd_client.mBitsPerChannel = d_asbd_client.mBytesPerFrame * 8; + d_asbd_client.mChannelsPerFrame = d_n_dev_channels; + d_asbd_client.mBytesPerPacket = d_asbd_client.mBytesPerFrame; + + // according to Apple docs [see, e.g., Apple Technical Note + // TN2091 "Device input using the HAL Output Audio Unit"], the + // device input and output sample rate must be the same; do + // sample rate conversion elsewhere. + + d_asbd_client.mSampleRate = d_asbd_device.mSampleRate; + err = AudioUnitSetProperty(d_input_au, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + 1, + &d_asbd_client, + prop_size); + check_error_and_throw( + err, "Set Device Output Stream Format failed", "audio_osx_source::setup"); + + // Get the Stream Format (client side), again + + prop_size = (UInt32)sizeof(d_asbd_client); + memset((void*)(&d_asbd_client), 0, (size_t)prop_size); + err = AudioUnitGetProperty(d_input_au, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + 1, + &d_asbd_client, + &prop_size); + check_error_and_throw( + err, "Get Device Output Stream Format (after) failed", "audio_osx_source::setup"); #if _OSX_AU_DEBUG_ - std::cerr << "---- Client Stream Format (After) ----" - << std::endl << d_asbd_client << std::endl << std::endl; + std::cerr << "---- Client Stream Format (After) ----" << std::endl + << d_asbd_client << std::endl + << std::endl; #endif - d_pass_through = (d_asbd_client.mSampleRate == d_output_sample_rate); + d_pass_through = (d_asbd_client.mSampleRate == d_output_sample_rate); - if (d_pass_through) { + if (d_pass_through) { // no need to do conversion if d_asbd_client matches user wants d_lead_size_frames = d_trail_size_frames = 0L; - } - else { + } else { - // create an ASBD for the user's wants + // create an ASBD for the user's wants - memset((void*)(&d_asbd_user), 0, sizeof(d_asbd_user)); - d_asbd_user.mSampleRate = d_output_sample_rate; - d_asbd_user.mFormatID = kAudioFormatLinearPCM; - d_asbd_user.mFormatFlags = (kLinearPCMFormatFlagIsFloat | - GR_PCM_ENDIANNESS | - kLinearPCMFormatFlagIsPacked | - kAudioFormatFlagIsNonInterleaved); - d_asbd_user.mBytesPerPacket = (UInt32)sizeof(float); - d_asbd_user.mFramesPerPacket = 1; - d_asbd_user.mBytesPerFrame = d_asbd_user.mBytesPerPacket; - d_asbd_user.mChannelsPerFrame = d_n_dev_channels; - d_asbd_user.mBitsPerChannel = d_asbd_user.mBytesPerPacket * 8; + memset((void*)(&d_asbd_user), 0, sizeof(d_asbd_user)); + d_asbd_user.mSampleRate = d_output_sample_rate; + d_asbd_user.mFormatID = kAudioFormatLinearPCM; + d_asbd_user.mFormatFlags = + (kLinearPCMFormatFlagIsFloat | GR_PCM_ENDIANNESS | + kLinearPCMFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved); + d_asbd_user.mBytesPerPacket = (UInt32)sizeof(float); + d_asbd_user.mFramesPerPacket = 1; + d_asbd_user.mBytesPerFrame = d_asbd_user.mBytesPerPacket; + d_asbd_user.mChannelsPerFrame = d_n_dev_channels; + d_asbd_user.mBitsPerChannel = d_asbd_user.mBytesPerPacket * 8; // Create the audio converter - err = AudioConverterNew(&d_asbd_client, - &d_asbd_user, - &d_audio_converter); - check_error_and_throw - (err, "AudioConverterNew failed", - "audio_osx_source::setup"); + err = AudioConverterNew(&d_asbd_client, &d_asbd_user, &d_audio_converter); + check_error_and_throw(err, "AudioConverterNew failed", "audio_osx_source::setup"); // Set the audio converter sample rate quality to "max" ... // requires more samples, but should sound nicer UInt32 ac_quality = kAudioConverterQuality_Max; prop_size = (UInt32)sizeof(ac_quality); - err = AudioConverterSetProperty - (d_audio_converter, - kAudioConverterSampleRateConverterQuality, - prop_size, &ac_quality); - check_error_and_throw - (err, "Set Sample Rate Converter Quality failed", - "audio_osx_source::setup"); + err = AudioConverterSetProperty(d_audio_converter, + kAudioConverterSampleRateConverterQuality, + prop_size, + &ac_quality); + check_error_and_throw( + err, "Set Sample Rate Converter Quality failed", "audio_osx_source::setup"); // set the audio converter's prime method to "pre", // which uses both leading and trailing frames @@ -512,850 +501,767 @@ namespace gr { UInt32 ac_prime_method = kConverterPrimeMethod_Pre; prop_size = (UInt32)sizeof(ac_prime_method); - err = AudioConverterSetProperty - (d_audio_converter, - kAudioConverterPrimeMethod, - prop_size, &ac_prime_method); - check_error_and_throw - (err, "Set Prime Method failed", - "audio_osx_source::setup"); + err = AudioConverterSetProperty( + d_audio_converter, kAudioConverterPrimeMethod, prop_size, &ac_prime_method); + check_error_and_throw(err, "Set Prime Method failed", "audio_osx_source::setup"); // Get the size of the priming I/O buffer space to allow for // pre-allocated buffers - AudioConverterPrimeInfo ac_prime_info = {0, 0}; + AudioConverterPrimeInfo ac_prime_info = { 0, 0 }; prop_size = (UInt32)sizeof(ac_prime_info); - err = AudioConverterGetProperty - (d_audio_converter, - kAudioConverterPrimeInfo, - &prop_size, &ac_prime_info); - check_error_and_throw - (err, "Get Prime Info failed", - "audio_osx_source::setup"); - - d_lead_size_frames = ac_prime_info.leadingFrames; - d_trail_size_frames = ac_prime_info.trailingFrames; - } - - d_lead_size_bytes = d_lead_size_frames * sizeof(float); - d_trail_size_bytes = d_trail_size_frames * sizeof(float); - - prop_size = (UInt32)sizeof(d_device_buffer_size_frames); - err = AudioUnitGetProperty - (d_input_au, - kAudioDevicePropertyBufferFrameSize, - kAudioUnitScope_Global, 0, - &d_device_buffer_size_frames, &prop_size); - check_error_and_throw - (err, "Get Buffer Frame Size failed", - "audio_osx_source::setup"); - - d_device_buffer_size_bytes = (d_device_buffer_size_frames * - sizeof(float)); - d_input_buffer_size_bytes = (d_device_buffer_size_bytes + - d_lead_size_bytes); - d_input_buffer_size_frames = (d_device_buffer_size_frames + - d_lead_size_frames); - - // 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_extra_buffer_size_frames = - ((UInt32)ceil(d_device_sample_rate / - d_output_sample_rate) * - sizeof(float)); - if(d_extra_buffer_size_frames < 4) + err = AudioConverterGetProperty( + d_audio_converter, kAudioConverterPrimeInfo, &prop_size, &ac_prime_info); + check_error_and_throw(err, "Get Prime Info failed", "audio_osx_source::setup"); + + d_lead_size_frames = ac_prime_info.leadingFrames; + d_trail_size_frames = ac_prime_info.trailingFrames; + } + + d_lead_size_bytes = d_lead_size_frames * sizeof(float); + d_trail_size_bytes = d_trail_size_frames * sizeof(float); + + prop_size = (UInt32)sizeof(d_device_buffer_size_frames); + err = AudioUnitGetProperty(d_input_au, + kAudioDevicePropertyBufferFrameSize, + kAudioUnitScope_Global, + 0, + &d_device_buffer_size_frames, + &prop_size); + check_error_and_throw(err, "Get Buffer Frame Size failed", "audio_osx_source::setup"); + + d_device_buffer_size_bytes = (d_device_buffer_size_frames * sizeof(float)); + d_input_buffer_size_bytes = (d_device_buffer_size_bytes + d_lead_size_bytes); + d_input_buffer_size_frames = (d_device_buffer_size_frames + d_lead_size_frames); + + // 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_extra_buffer_size_frames = + ((UInt32)ceil(d_device_sample_rate / d_output_sample_rate) * sizeof(float)); + if (d_extra_buffer_size_frames < 4) d_extra_buffer_size_frames = 4; - d_extra_buffer_size_bytes = - d_extra_buffer_size_frames * sizeof(float); - - d_output_buffer_size_frames = - (UInt32)ceil(((Float64)d_input_buffer_size_frames) * - d_output_sample_rate / d_device_sample_rate); - d_output_buffer_size_bytes = - d_output_buffer_size_frames * sizeof(float); - d_input_buffer_size_frames += d_extra_buffer_size_frames; - - // pre-alloc all CoreAudio buffers - - alloc_audio_buffer_list - (&d_input_buffer, d_n_dev_channels, - d_input_buffer_size_bytes); - if(!d_pass_through) { - alloc_audio_buffer_list - (&d_output_buffer, d_n_dev_channels, - d_output_buffer_size_bytes); - } - else { + d_extra_buffer_size_bytes = d_extra_buffer_size_frames * sizeof(float); + + d_output_buffer_size_frames = + (UInt32)ceil(((Float64)d_input_buffer_size_frames) * d_output_sample_rate / + d_device_sample_rate); + d_output_buffer_size_bytes = d_output_buffer_size_frames * sizeof(float); + d_input_buffer_size_frames += d_extra_buffer_size_frames; + + // pre-alloc all CoreAudio buffers + + alloc_audio_buffer_list(&d_input_buffer, d_n_dev_channels, d_input_buffer_size_bytes); + if (!d_pass_through) { + alloc_audio_buffer_list( + &d_output_buffer, d_n_dev_channels, d_output_buffer_size_bytes); + } else { d_output_buffer = d_input_buffer; - } - - // allocate the output circular buffer(s), one per device - // channel (the user may select fewer channels; those buffers - // just won't get used). - - d_buffers.resize(d_n_dev_channels); - for(UInt32 nn = 0; nn < d_n_dev_channels; ++nn) { - d_buffers[nn] = new circular_buffer<float> - (d_buffer_sample_count, false, false); - } - - // clear the RunLoop (whatever that is); needed, for some - // reason, before a listener will work. - - { - CFRunLoopRef the_run_loop = NULL; - AudioObjectPropertyAddress property = { - kAudioHardwarePropertyRunLoop, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - prop_size = (UInt32)sizeof(the_run_loop); - err = AudioObjectSetPropertyData - (kAudioObjectSystemObject, &property, 0, NULL, - prop_size, &the_run_loop); - check_error(err, "Clearing RunLoop failed; " - "Audio Input Device Listener might not work."); - } - - // set up listeners + } -#ifndef GR_USE_OLD_AUDIO_UNIT + // allocate the output circular buffer(s), one per device + // channel (the user may select fewer channels; those buffers + // just won't get used). - // 10.4 and newer + d_buffers.resize(d_n_dev_channels); + for (UInt32 nn = 0; nn < d_n_dev_channels; ++nn) { + d_buffers[nn] = new circular_buffer<float>(d_buffer_sample_count, false, false); + } - { + // clear the RunLoop (whatever that is); needed, for some + // reason, before a listener will work. - // set up a listener if hardware changes (at all) + { + CFRunLoopRef the_run_loop = NULL; + AudioObjectPropertyAddress property = { kAudioHardwarePropertyRunLoop, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; + prop_size = (UInt32)sizeof(the_run_loop); + err = AudioObjectSetPropertyData( + kAudioObjectSystemObject, &property, 0, NULL, prop_size, &the_run_loop); + check_error(err, + "Clearing RunLoop failed; " + "Audio Input Device Listener might not work."); + } - AudioObjectPropertyAddress property = { - kAudioHardwarePropertyDevices, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; + // set up listeners - err = AudioObjectAddPropertyListener - (kAudioObjectSystemObject, &property, - reinterpret_cast<AudioObjectPropertyListenerProc> - (&osx_source::hardware_listener), - reinterpret_cast<void*>(this)); - check_error(err, "Adding Audio Hardware Listener failed"); - } +#ifndef GR_USE_OLD_AUDIO_UNIT - if (d_using_default_device) { + // 10.4 and newer - // set up a listener if default hardware input device changes + { + + // set up a listener if hardware changes (at all) - AudioObjectPropertyAddress property = { - kAudioHardwarePropertyDefaultInputDevice, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; + AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; - err = AudioObjectAddPropertyListener - (kAudioObjectSystemObject, &property, - reinterpret_cast<AudioObjectPropertyListenerProc> - (&osx_source::default_listener), - reinterpret_cast<void*>(this)); - check_error(err, "Adding Default Input Audio Listener failed"); + err = AudioObjectAddPropertyListener( + kAudioObjectSystemObject, + &property, + reinterpret_cast<AudioObjectPropertyListenerProc>( + &osx_source::hardware_listener), + reinterpret_cast<void*>(this)); + check_error(err, "Adding Audio Hardware Listener failed"); + } - } + if (d_using_default_device) { -#else + // set up a listener if default hardware input device changes - // 10.5 and older + AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; + + err = AudioObjectAddPropertyListener( + kAudioObjectSystemObject, + &property, + reinterpret_cast<AudioObjectPropertyListenerProc>( + &osx_source::default_listener), + reinterpret_cast<void*>(this)); + check_error(err, "Adding Default Input Audio Listener failed"); + } + +#else - err = AudioHardwareAddPropertyListener - (kAudioHardwarePropertyDevices, - reinterpret_cast<AudioHardwarePropertyListenerProc> - (&osx_source::hardware_listener), - reinterpret_cast<void*>(this)); - check_error(err, "Adding Audio Hardware Listener failed"); + // 10.5 and older - if (d_using_default_device) { + err = AudioHardwareAddPropertyListener( + kAudioHardwarePropertyDevices, + reinterpret_cast<AudioHardwarePropertyListenerProc>( + &osx_source::hardware_listener), + reinterpret_cast<void*>(this)); + check_error(err, "Adding Audio Hardware Listener failed"); - err = AudioHardwareAddPropertyListener - (kAudioHardwarePropertyDefaultInputDevice, - reinterpret_cast<AudioHardwarePropertyListenerProc> - (&osx_source::default_listener), - reinterpret_cast<void*>(this)); - check_error(err, "Adding Default Input Audio Listener failed"); + if (d_using_default_device) { - } + err = AudioHardwareAddPropertyListener( + kAudioHardwarePropertyDefaultInputDevice, + reinterpret_cast<AudioHardwarePropertyListenerProc>( + &osx_source::default_listener), + reinterpret_cast<void*>(this)); + check_error(err, "Adding Default Input Audio Listener failed"); + } #endif - // initialize the AU for input, so that it is ready to be used + // initialize the AU for input, so that it is ready to be used - err = AudioUnitInitialize(d_input_au); - check_error_and_throw - (err, "AudioUnitInitialize", - "audio_osx_source::check_channels"); + err = AudioUnitInitialize(d_input_au); + check_error_and_throw(err, "AudioUnitInitialize", "audio_osx_source::check_channels"); #if _OSX_AU_DEBUG_ - std::cerr << std::endl << "audio_osx_source Parameters:" - << std::endl << " Device Sample Rate is " - << d_device_sample_rate << std::endl - << " Client Sample Rate is " - << (d_pass_through ? d_output_sample_rate : - d_device_sample_rate) << std::endl - << " User Sample Rate is " - << d_output_sample_rate << std::endl - << " Do Passthrough is " - << (d_pass_through ? "true" : "false") << std::endl - << " Max Sample Count is " - << d_buffer_sample_count << std::endl - << " # Device Channels is " - << d_n_dev_channels << std::endl - << " Device Buffer Size in Frames = " - << d_device_buffer_size_frames << std::endl - << " Lead Size in Frames = " - << d_lead_size_frames << std::endl - << " Trail Size in Frames = " - << d_trail_size_frames << std::endl - << " Input Buffer Size in Frames = " - << d_input_buffer_size_frames << std::endl - << " Output Buffer Size in Frames = " - << d_output_buffer_size_frames << std::endl - << std::endl; + std::cerr << std::endl + << "audio_osx_source Parameters:" << std::endl + << " Device Sample Rate is " << d_device_sample_rate << std::endl + << " Client Sample Rate is " + << (d_pass_through ? d_output_sample_rate : d_device_sample_rate) + << std::endl + << " User Sample Rate is " << d_output_sample_rate << std::endl + << " Do Passthrough is " << (d_pass_through ? "true" : "false") + << std::endl + << " Max Sample Count is " << d_buffer_sample_count << std::endl + << " # Device Channels is " << d_n_dev_channels << std::endl + << " Device Buffer Size in Frames = " << d_device_buffer_size_frames + << std::endl + << " Lead Size in Frames = " << d_lead_size_frames << std::endl + << " Trail Size in Frames = " << d_trail_size_frames << std::endl + << " Input Buffer Size in Frames = " << d_input_buffer_size_frames + << std::endl + << " Output Buffer Size in Frames = " << d_output_buffer_size_frames + << std::endl + << std::endl; #endif - } +} - void - osx_source::alloc_audio_buffer_list - (AudioBufferList** t_abl, - UInt32 n_channels, - UInt32 input_buffer_size_bytes) - { - free_audio_buffer_list(t_abl); - UInt32 prop_size = (offsetof(AudioBufferList, mBuffers[0]) + - (sizeof(AudioBuffer) * n_channels)); - *t_abl = (AudioBufferList*)calloc(1, prop_size); - (*t_abl)->mNumberBuffers = n_channels; +void osx_source::alloc_audio_buffer_list(AudioBufferList** t_abl, + UInt32 n_channels, + UInt32 input_buffer_size_bytes) +{ + free_audio_buffer_list(t_abl); + UInt32 prop_size = + (offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * n_channels)); + *t_abl = (AudioBufferList*)calloc(1, prop_size); + (*t_abl)->mNumberBuffers = n_channels; - int counter = n_channels; + int counter = n_channels; #if _OSX_AU_DEBUG_ - std::cerr << "alloc_audio_buffer_list: (#chan, #bytes) == (" - << n_channels << ", " << input_buffer_size_bytes - << ")" << std::endl; + std::cerr << "alloc_audio_buffer_list: (#chan, #bytes) == (" << n_channels << ", " + << input_buffer_size_bytes << ")" << std::endl; #endif - while(--counter >= 0) { - AudioBuffer* t_ab = &((*t_abl)->mBuffers[counter]); - t_ab->mNumberChannels = 1; - t_ab->mDataByteSize = input_buffer_size_bytes; - t_ab->mData = calloc(1, input_buffer_size_bytes); - } + while (--counter >= 0) { + AudioBuffer* t_ab = &((*t_abl)->mBuffers[counter]); + t_ab->mNumberChannels = 1; + t_ab->mDataByteSize = input_buffer_size_bytes; + t_ab->mData = calloc(1, input_buffer_size_bytes); } +} - void - osx_source::free_audio_buffer_list(AudioBufferList** t_abl) - { - // free pre-allocated audio buffer, if it exists - if(*t_abl) { +void osx_source::free_audio_buffer_list(AudioBufferList** t_abl) +{ + // free pre-allocated audio buffer, if it exists + if (*t_abl) { int counter = (*t_abl)->mNumberBuffers; - while(--counter >= 0) { - AudioBuffer* t_ab = &((*t_abl)->mBuffers[counter]); - free(t_ab->mData); - t_ab->mData = 0; - } + while (--counter >= 0) { + AudioBuffer* t_ab = &((*t_abl)->mBuffers[counter]); + free(t_ab->mData); + t_ab->mData = 0; + } free(*t_abl); (*t_abl) = 0; - } } - - bool - osx_source::is_running() - { - UInt32 au_running = 0; - if (d_input_au) { - - UInt32 prop_size = (UInt32)sizeof(au_running); - OSStatus err = AudioUnitGetProperty - (d_input_au, - kAudioOutputUnitProperty_IsRunning, - kAudioUnitScope_Global, 0, - &au_running, &prop_size); - check_error_and_throw - (err, "AudioUnitGetProperty IsRunning", - "audio_osx_source::is_running"); - } - - return(au_running != 0); +} + +bool osx_source::is_running() +{ + UInt32 au_running = 0; + if (d_input_au) { + + UInt32 prop_size = (UInt32)sizeof(au_running); + OSStatus err = AudioUnitGetProperty(d_input_au, + kAudioOutputUnitProperty_IsRunning, + kAudioUnitScope_Global, + 0, + &au_running, + &prop_size); + check_error_and_throw( + err, "AudioUnitGetProperty IsRunning", "audio_osx_source::is_running"); } - bool - osx_source::start() - { + return (au_running != 0); +} + +bool osx_source::start() +{ #if _OSX_AU_DEBUG_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_source::start: Starting." << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_source::start: Starting." + << std::endl; #endif - if((!is_running ()) && d_input_au) { + if ((!is_running()) && d_input_au) { #if _OSX_AU_DEBUG_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_source::start: Starting Audio Unit." - << std::endl; + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_source::start: Starting Audio Unit." << std::endl; #endif - // reset buffers before starting + // reset buffers before starting - for(UInt32 nn = 0; nn < d_buffers.size(); ++nn) { - d_buffers[nn]->reset(); - } + for (UInt32 nn = 0; nn < d_buffers.size(); ++nn) { + d_buffers[nn]->reset(); + } - // start the audio unit + // start the audio unit OSStatus err = AudioOutputUnitStart(d_input_au); - check_error_and_throw(err, "AudioOutputUnitStart", - "audio_osx_source::start"); + check_error_and_throw(err, "AudioOutputUnitStart", "audio_osx_source::start"); - // clear reset (will sometimes be necessary, and it has to - // happen after AudioOutputUnitStart) + // clear reset (will sometimes be necessary, and it has to + // happen after AudioOutputUnitStart) - d_do_reset = false; - - } + d_do_reset = false; + } #if _OSX_AU_DEBUG_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_source::start: Returning." << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_source::start: Returning." + << std::endl; #endif - return (true); - } + return (true); +} - bool - osx_source::stop() - { +bool osx_source::stop() +{ #if _OSX_AU_DEBUG_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_source::stop: Starting." << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_source::stop: Starting." + << std::endl; #endif - if(is_running ()) { + if (is_running()) { #if _OSX_AU_DEBUG_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_source::stop: stopping audio unit." - << std::endl; + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_source::stop: stopping audio unit." << std::endl; #endif - // stop the audio unit + // stop the audio unit OSStatus err = AudioOutputUnitStop(d_input_au); - check_error_and_throw(err, "AudioOutputUnitStart", - "audio_osx_source::stop"); + check_error_and_throw(err, "AudioOutputUnitStart", "audio_osx_source::stop"); - // abort all buffers + // abort all buffers - for(UInt32 nn = 0; nn < d_n_user_channels; ++nn) { - d_buffers[nn]->abort (); + for (UInt32 nn = 0; nn < d_n_user_channels; ++nn) { + d_buffers[nn]->abort(); } - } + } #if _OSX_AU_DEBUG_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_source::stop: Returning." << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_source::stop: Returning." + << std::endl; #endif - return (true); - } + return (true); +} - void - osx_source::teardown() - { +void osx_source::teardown() +{ #if _OSX_AU_DEBUG_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_source::teardown: Starting." << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_source::teardown: Starting." + << std::endl; #endif - OSStatus err = noErr; + OSStatus err = noErr; - // stop the AudioUnit + // stop the AudioUnit - stop(); + stop(); - // remove the listeners + // remove the listeners #ifndef GR_USE_OLD_AUDIO_UNIT - // 10.4 and newer - { - AudioObjectPropertyAddress property = { - kAudioHardwarePropertyDevices, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - err = AudioObjectRemovePropertyListener - (kAudioObjectSystemObject, &property, - reinterpret_cast<AudioObjectPropertyListenerProc> - (&osx_source::hardware_listener), - reinterpret_cast<void*>(this)); + // 10.4 and newer + { + AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; + + err = AudioObjectRemovePropertyListener( + kAudioObjectSystemObject, + &property, + reinterpret_cast<AudioObjectPropertyListenerProc>( + &osx_source::hardware_listener), + reinterpret_cast<void*>(this)); #if _OSX_AU_DEBUG_ - check_error(err, "teardown: AudioObjectRemovePropertyListener " - "hardware failed"); + check_error(err, + "teardown: AudioObjectRemovePropertyListener " + "hardware failed"); #endif + } - } - - if (d_using_default_device) { + if (d_using_default_device) { - AudioObjectPropertyAddress property = { - kAudioHardwarePropertyDefaultInputDevice, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; + AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster }; - err = AudioObjectRemovePropertyListener - (kAudioObjectSystemObject, &property, - reinterpret_cast<AudioObjectPropertyListenerProc> - (&osx_source::default_listener), - reinterpret_cast<void*>(this)); + err = AudioObjectRemovePropertyListener( + kAudioObjectSystemObject, + &property, + reinterpret_cast<AudioObjectPropertyListenerProc>( + &osx_source::default_listener), + reinterpret_cast<void*>(this)); #if _OSX_AU_DEBUG_ - check_error(err, "AudioObjectRemovePropertyListener default"); + check_error(err, "AudioObjectRemovePropertyListener default"); #endif - d_using_default_device = false; - - } + d_using_default_device = false; + } #else - // 10.5 and older + // 10.5 and older - err = AudioHardwareRemovePropertyListener - (kAudioHardwarePropertyDevices, - reinterpret_cast<AudioHardwarePropertyListenerProc> - (&osx_source::hardware_listener)); + err = AudioHardwareRemovePropertyListener( + kAudioHardwarePropertyDevices, + reinterpret_cast<AudioHardwarePropertyListenerProc>( + &osx_source::hardware_listener)); #if _OSX_AU_DEBUG_ - check_error(err, "AudioObjectRemovePropertyListener hardware"); + check_error(err, "AudioObjectRemovePropertyListener hardware"); #endif - if (d_using_default_device) { - err = AudioHardwareRemovePropertyListener - (kAudioHardwarePropertyDefaultInputDevice, - reinterpret_cast<AudioHardwarePropertyListenerProc> - (&osx_source::default_listener)); + if (d_using_default_device) { + err = AudioHardwareRemovePropertyListener( + kAudioHardwarePropertyDefaultInputDevice, + reinterpret_cast<AudioHardwarePropertyListenerProc>( + &osx_source::default_listener)); #if _OSX_AU_DEBUG_ - check_error(err, "AudioObjectRemovePropertyListener default"); + check_error(err, "AudioObjectRemovePropertyListener default"); #endif - d_using_default_device = false; - - } + d_using_default_device = false; + } #endif // GR_USE_OLD_AUDIO_UNIT - // free pre-allocated audio buffers - free_audio_buffer_list(&d_input_buffer); + // free pre-allocated audio buffers + free_audio_buffer_list(&d_input_buffer); - if(!d_pass_through) { + if (!d_pass_through) { err = AudioConverterDispose(d_audio_converter); #if _OSX_AU_DEBUG_ check_error(err, "~audio_osx_source: AudioConverterDispose"); #endif free_audio_buffer_list(&d_output_buffer); - } + } - // remove the audio unit - err = AudioUnitUninitialize(d_input_au); + // remove the audio unit + err = AudioUnitUninitialize(d_input_au); #if _OSX_AU_DEBUG_ - check_error(err, "~audio_osx_source: AudioUnitUninitialize"); + check_error(err, "~audio_osx_source: AudioUnitUninitialize"); #endif #ifndef GR_USE_OLD_AUDIO_UNIT - err = AudioComponentInstanceDispose(d_input_au); + err = AudioComponentInstanceDispose(d_input_au); #if _OSX_AU_DEBUG_ - check_error(err, "~audio_osx_source: AudioComponentInstanceDispose"); + check_error(err, "~audio_osx_source: AudioComponentInstanceDispose"); #endif #else - err = CloseComponent(d_input_au); + err = CloseComponent(d_input_au); #if _OSX_AU_DEBUG_ - check_error(err, "~audio_osx_source: CloseComponent"); + check_error(err, "~audio_osx_source: CloseComponent"); #endif #endif - // empty and delete the queues + // empty and delete the queues - for(UInt32 nn = 0; nn < d_buffers.size(); ++nn) { + for (UInt32 nn = 0; nn < d_buffers.size(); ++nn) { delete d_buffers[nn]; d_buffers[nn] = 0; - } - d_buffers.resize(0); + } + d_buffers.resize(0); - // clear important variables; not # user channels + // clear important variables; not # user channels - d_queue_sample_count = 0; - d_device_sample_rate = 0; - d_n_dev_channels = 0; - d_input_ad_id = 0; - d_input_au = 0; - d_input_buffer = d_output_buffer = 0; - d_audio_converter = 0; - d_using_default_device = false; + d_queue_sample_count = 0; + d_device_sample_rate = 0; + d_n_dev_channels = 0; + d_input_ad_id = 0; + d_input_au = 0; + d_input_buffer = d_output_buffer = 0; + d_audio_converter = 0; + d_using_default_device = false; #if _OSX_AU_DEBUG_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_source::teardown: Returning." << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_source::teardown: Returning." + << std::endl; #endif +} + +bool osx_source::check_topology(int ninputs, int noutputs) +{ + // check # inputs to make sure it's valid + if (ninputs != 0) { + + GR_LOG_FATAL(d_logger, + boost::format("check_topology(): number of input " + "streams provided (%d) should be 0.") % + ninputs); + throw std::runtime_error("audio_osx_source::check_topology"); } - bool - osx_source::check_topology(int ninputs, int noutputs) - { - // check # inputs to make sure it's valid - if(ninputs != 0) { - - GR_LOG_FATAL(d_logger, boost::format - ("check_topology(): number of input " - "streams provided (%d) should be 0.") - % ninputs); - throw std::runtime_error - ("audio_osx_source::check_topology"); + // check # outputs to make sure it's valid + if ((noutputs < 1) | (noutputs > (int)d_n_dev_channels)) { - } - - // check # outputs to make sure it's valid - if((noutputs < 1) | (noutputs > (int) d_n_dev_channels)) { - - GR_LOG_FATAL(d_logger, boost::format - ("check_topology(): number of output " - "streams provided (%d) should be in [1,%d] " - "for the selected input audio device.") - % noutputs % d_n_dev_channels); - throw std::runtime_error - ("audio_osx_source::check_topology"); - } + GR_LOG_FATAL(d_logger, + boost::format("check_topology(): number of output " + "streams provided (%d) should be in [1,%d] " + "for the selected input audio device.") % + noutputs % d_n_dev_channels); + throw std::runtime_error("audio_osx_source::check_topology"); + } - // save the actual number of output (user) channels + // save the actual number of output (user) channels - d_n_user_channels = noutputs; + d_n_user_channels = noutputs; #if _OSX_AU_DEBUG_ - std::cerr << "chk_topo: Actual # user output channels = " - << noutputs << std::endl; + std::cerr << "chk_topo: Actual # user output channels = " << noutputs << std::endl; #endif - return(true); - } + return (true); +} - int - osx_source::work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { +int osx_source::work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ #if _OSX_AU_DEBUG_RENDER_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_source::work: Starting." << std::endl; + std::cerr << ((void*)(pthread_self())) << " : audio_osx_source::work: Starting." + << std::endl; #endif - if (d_do_reset) { - if (d_hardware_changed) { - - // see if the current AudioDeviceID is still available + if (d_do_reset) { + if (d_hardware_changed) { - std::vector < AudioDeviceID > all_ad_ids; - osx::find_audio_devices - (d_desired_name, true, - &all_ad_ids, NULL); - bool found = false; - for (UInt32 nn = 0; (nn < all_ad_ids.size()) && (!found); - ++nn) { - found = (all_ad_ids[nn] == d_input_ad_id); - } - if (!found) { + // see if the current AudioDeviceID is still available - GR_LOG_FATAL(d_logger, boost::format - ("The selected input audio device ('%s') " - "is no longer available.\n") - % d_selected_name); - return(gr::block::WORK_DONE); + std::vector<AudioDeviceID> all_ad_ids; + osx::find_audio_devices(d_desired_name, true, &all_ad_ids, NULL); + bool found = false; + for (UInt32 nn = 0; (nn < all_ad_ids.size()) && (!found); ++nn) { + found = (all_ad_ids[nn] == d_input_ad_id); + } + if (!found) { - } + GR_LOG_FATAL(d_logger, + boost::format("The selected input audio device ('%s') " + "is no longer available.\n") % + d_selected_name); + return (gr::block::WORK_DONE); + } - d_do_reset = d_hardware_changed = false; + d_do_reset = d_hardware_changed = false; - } else { + } else { #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "audio_osx_source::work: doing reset." - << std::endl; + std::cerr << "audio_osx_source::work: doing reset." << std::endl; #endif - GR_LOG_WARN(d_logger, boost::format - ("\n\nThe default input audio device has " - "changed; resetting audio.\nThere may " - "be a sound glitch while resetting.\n")); + GR_LOG_WARN(d_logger, + boost::format("\n\nThe default input audio device has " + "changed; resetting audio.\nThere may " + "be a sound glitch while resetting.\n")); - // for any changes, just tear down the current - // configuration, then set it up again using the user's - // parameters to try to make selections. + // for any changes, just tear down the current + // configuration, then set it up again using the user's + // parameters to try to make selections. - teardown(); + teardown(); - gr::thread::scoped_lock l(d_internal); + gr::thread::scoped_lock l(d_internal); #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "audio_osx_source::work: mutex locked." - << std::endl; + std::cerr << "audio_osx_source::work: mutex locked." << std::endl; #endif - setup(); - start(); + setup(); + start(); #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "audio_osx_source::work: returning after reset." - << std::endl; + std::cerr << "audio_osx_source::work: returning after reset." << std::endl; #endif - return(0); - } - } + return (0); + } + } - gr::thread::scoped_lock l(d_internal); + gr::thread::scoped_lock l(d_internal); #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "audio_osx_source::work: mutex locked." << std::endl; + std::cerr << "audio_osx_source::work: mutex locked." << std::endl; #endif #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "work1: SC = " << d_queue_sample_count - << ", #OI = " << noutput_items - << ", #Chan = " << output_items.size() << std::endl; + std::cerr << "work1: SC = " << d_queue_sample_count << ", #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 "ok_to_block" is - // true), return (0) is no data is available and "ok_to_block" - // is false, or process the actual amount of available data. - - UInt32 actual_noutput_items = noutput_items; - - if(d_queue_sample_count < actual_noutput_items) { - if(d_queue_sample_count == 0) { - // no data; ok_to_block decides what to do - if(d_ok_to_block == true) { - // block until there is data to return, or on reset - while(d_queue_sample_count == 0) { - // release control so-as to allow data to be retrieved; - // block until there is data to return + // 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 "ok_to_block" is + // true), return (0) is no data is available and "ok_to_block" + // is false, or process the actual amount of available data. + + UInt32 actual_noutput_items = noutput_items; + + if (d_queue_sample_count < actual_noutput_items) { + if (d_queue_sample_count == 0) { + // no data; ok_to_block decides what to do + if (d_ok_to_block == true) { + // block until there is data to return, or on reset + while (d_queue_sample_count == 0) { + // release control so-as to allow data to be retrieved; + // block until there is data to return #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "audio_osx_source::work: waiting." - << std::endl; + std::cerr << "audio_osx_source::work: waiting." << std::endl; #endif - d_waiting_for_data = true; - d_cond_data.wait(l); - d_waiting_for_data = false; + d_waiting_for_data = true; + d_cond_data.wait(l); + d_waiting_for_data = false; #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "audio_osx_source::work: done waiting." - << std::endl; + std::cerr << "audio_osx_source::work: done waiting." << std::endl; #endif - // the condition's 'notify' was called; acquire control to - // keep thread safe + // the condition's 'notify' was called; acquire control to + // keep thread safe - // if doing a reset, just return here; reset will pick - // up the next time this method is called. - if (d_do_reset) { + // if doing a reset, just return here; reset will pick + // up the next time this method is called. + if (d_do_reset) { #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "audio_osx_source::work: " - "returning for reset." << std::endl; + std::cerr << "audio_osx_source::work: " + "returning for reset." + << std::endl; #endif - return(0); - } - } - } - else { - // no data & not blocking; return nothing + return (0); + } + } + } else { + // no data & not blocking; return nothing #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "audio_osx_source::work: no data " - "& not blocking; returning 0." << std::endl; + std::cerr << "audio_osx_source::work: no data " + "& not blocking; returning 0." + << std::endl; #endif - return (0); - } + return (0); + } } // use the actual amount of available data actual_noutput_items = d_queue_sample_count; - } + } #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "audio_osx_source::work: copying " - << actual_noutput_items << " items per channel" - << std::endl; + std::cerr << "audio_osx_source::work: copying " << actual_noutput_items + << " items per channel" << std::endl; #endif - // number of channels - int l_counter = (int)output_items.size(); + // 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. + // 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) { + 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); + d_buffers[l_counter]->dequeue((float*)output_items[l_counter], &t_n_output_items); - if(t_n_output_items != actual_noutput_items) { - - GR_LOG_FATAL(d_logger, boost::format - ("work(): ERROR: number of available " - "items changing unexpectedly; expecting %d" - ", got %d.") - % actual_noutput_items % t_n_output_items); - throw std::runtime_error("audio_osx_source::work()"); + if (t_n_output_items != actual_noutput_items) { + GR_LOG_FATAL(d_logger, + boost::format("work(): ERROR: number of available " + "items changing unexpectedly; expecting %d" + ", got %d.") % + actual_noutput_items % t_n_output_items); + 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 + // subtract the actual number of items removed from the buffer(s) + // from the local accounting of the number of available samples - d_queue_sample_count -= actual_noutput_items; + d_queue_sample_count -= actual_noutput_items; #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "work2: SC = " << d_queue_sample_count - << ", act#OI = " << actual_noutput_items << std::endl - << "Returning." << std::endl; + std::cerr << "work2: SC = " << d_queue_sample_count + << ", act#OI = " << actual_noutput_items << std::endl + << "Returning." << std::endl; #endif #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "audio_osx_source::work: returning." << std::endl; + std::cerr << "audio_osx_source::work: returning." << std::endl; #endif - return (actual_noutput_items); - } - - OSStatus - osx_source::converter_callback - (AudioConverterRef in_audio_converter, - UInt32* io_number_data_packets, - AudioBufferList* io_data, - AudioStreamPacketDescription** out_aspd, - void* in_user_data) - { - // This callback is for us to provide the buffers to CoreAudio - // for conversion. We need to set the buffers in the provided - // buffer list (io_data) to the buffers we know about and use to - // do data input (d_input_buffers). - - osx_source* This = static_cast<osx_source*>(in_user_data); - AudioBufferList* l_input_abl = This->d_input_buffer; - UInt32 total_input_buffer_size_bytes = - ((*io_number_data_packets) * sizeof(float)); - int counter = This->d_n_dev_channels; - io_data->mNumberBuffers = This->d_n_dev_channels; - This->d_n_actual_input_frames = (*io_number_data_packets); + return (actual_noutput_items); +} + +OSStatus osx_source::converter_callback(AudioConverterRef in_audio_converter, + UInt32* io_number_data_packets, + AudioBufferList* io_data, + AudioStreamPacketDescription** out_aspd, + void* in_user_data) +{ + // This callback is for us to provide the buffers to CoreAudio + // for conversion. We need to set the buffers in the provided + // buffer list (io_data) to the buffers we know about and use to + // do data input (d_input_buffers). + + osx_source* This = static_cast<osx_source*>(in_user_data); + AudioBufferList* l_input_abl = This->d_input_buffer; + UInt32 total_input_buffer_size_bytes = ((*io_number_data_packets) * sizeof(float)); + int counter = This->d_n_dev_channels; + io_data->mNumberBuffers = This->d_n_dev_channels; + This->d_n_actual_input_frames = (*io_number_data_packets); #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "cc1: io#DP = " << (*io_number_data_packets) - << ", TIBSB = " << total_input_buffer_size_bytes - << ", #C = " << counter << std::endl; + std::cerr << "cc1: io#DP = " << (*io_number_data_packets) + << ", TIBSB = " << total_input_buffer_size_bytes << ", #C = " << counter + << std::endl; #endif - while(--counter >= 0) { + while (--counter >= 0) { AudioBuffer* t_ab = &(io_data->mBuffers[counter]); t_ab->mNumberChannels = 1; t_ab->mData = l_input_abl->mBuffers[counter].mData; t_ab->mDataByteSize = total_input_buffer_size_bytes; - } + } #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "cc2: Returning." << std::endl; + std::cerr << "cc2: Returning." << std::endl; #endif - return (noErr); - } + return (noErr); +} - OSStatus - osx_source::au_input_callback - (void *in_ref_con, - AudioUnitRenderActionFlags *io_action_flags, - const AudioTimeStamp *in_time_stamp, - UInt32 in_bus_number, - UInt32 in_number_frames, - AudioBufferList *io_data) - { +OSStatus osx_source::au_input_callback(void* in_ref_con, + AudioUnitRenderActionFlags* io_action_flags, + const AudioTimeStamp* in_time_stamp, + UInt32 in_bus_number, + UInt32 in_number_frames, + AudioBufferList* io_data) +{ #if _OSX_AU_DEBUG_RENDER_ - std::cerr << ((void*)(pthread_self())) - << " : audio_osx_source::au_input_callback: Starting." - << std::endl; + std::cerr << ((void*)(pthread_self())) + << " : audio_osx_source::au_input_callback: Starting." << std::endl; #endif - osx_source* This = reinterpret_cast - <osx_source*>(in_ref_con); - gr::thread::scoped_lock l(This->d_internal); - gr::logger_ptr d_logger = This->d_logger; + osx_source* This = reinterpret_cast<osx_source*>(in_ref_con); + gr::thread::scoped_lock l(This->d_internal); + gr::logger_ptr d_logger = This->d_logger; #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "audio_osx_source::au_input_callback: mutex locked." - << std::endl; + std::cerr << "audio_osx_source::au_input_callback: mutex locked." << std::endl; #endif - OSStatus err = noErr; + OSStatus err = noErr; #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "cb0: in#Fr = " << in_number_frames - << ", inBus# = " << in_bus_number - << ", idD = " << ((void*)io_data) - << ", d_ib = " << ((void*)(This->d_input_buffer)) - << ", d_ib#c = " << This->d_input_buffer->mNumberBuffers - << ", SC = " << This->d_queue_sample_count << std::endl; + std::cerr << "cb0: in#Fr = " << in_number_frames << ", inBus# = " << in_bus_number + << ", idD = " << ((void*)io_data) + << ", d_ib = " << ((void*)(This->d_input_buffer)) + << ", d_ib#c = " << This->d_input_buffer->mNumberBuffers + << ", SC = " << This->d_queue_sample_count << std::endl; #endif - if (This->d_do_reset) { - - // clear audio data; do not render since it will generate an error - - AudioBufferList* t_abl = This->d_input_buffer; - for (UInt32 nn = 0; nn < t_abl->mNumberBuffers; ++nn) { - AudioBuffer* t_ab = &(t_abl->mBuffers[nn]); - memset(t_ab->mData, 0, (size_t)((t_ab->mDataByteSize) * - (t_ab->mNumberChannels))); - } - } else { + if (This->d_do_reset) { - // Get the new audio data from the input device + // clear audio data; do not render since it will generate an error - err = AudioUnitRender - (This->d_input_au, io_action_flags, - in_time_stamp, 1, //inBusNumber, - in_number_frames, This->d_input_buffer); - check_error_and_throw - (err, "AudioUnitRender", - "audio_osx_source::au_input_callback"); - - } + AudioBufferList* t_abl = This->d_input_buffer; + for (UInt32 nn = 0; nn < t_abl->mNumberBuffers; ++nn) { + AudioBuffer* t_ab = &(t_abl->mBuffers[nn]); + memset(t_ab->mData, + 0, + (size_t)((t_ab->mDataByteSize) * (t_ab->mNumberChannels))); + } + } else { + + // Get the new audio data from the input device + + err = AudioUnitRender(This->d_input_au, + io_action_flags, + in_time_stamp, + 1, // inBusNumber, + in_number_frames, + This->d_input_buffer); + check_error_and_throw( + err, "AudioUnitRender", "audio_osx_source::au_input_callback"); + } - UInt32 available_input_frames = - This->d_n_available_input_frames = in_number_frames; + UInt32 available_input_frames = This->d_n_available_input_frames = in_number_frames; - // get the number of actual output frames, - // either via converting the buffer or not + // get the number of actual output frames, + // either via converting the buffer or not - UInt32 actual_output_frames = available_input_frames; + UInt32 actual_output_frames = available_input_frames; - if(!This->d_pass_through) { - UInt32 available_input_bytes = - available_input_frames * sizeof(float); + if (!This->d_pass_through) { + UInt32 available_input_bytes = available_input_frames * sizeof(float); UInt32 available_output_bytes = available_input_bytes; UInt32 prop_size = sizeof(available_output_bytes); - err = AudioConverterGetProperty - (This->d_audio_converter, - kAudioConverterPropertyCalculateOutputBufferSize, - &prop_size, - &available_output_bytes); - check_error_and_throw - (err, "Get Output Buffer Size failed", - "audio_osx_source::au_input_callback"); + err = AudioConverterGetProperty(This->d_audio_converter, + kAudioConverterPropertyCalculateOutputBufferSize, + &prop_size, + &available_output_bytes); + check_error_and_throw( + err, "Get Output Buffer Size failed", "audio_osx_source::au_input_callback"); - UInt32 available_output_frames = - available_output_bytes / sizeof(float); + UInt32 available_output_frames = available_output_bytes / sizeof(float); #if 0 // when decimating too much, the output sounds warbly due to @@ -1392,17 +1298,17 @@ namespace gr { // convert the data to the correct rate; on input, // actual_output_frames is the number of available output frames - err = AudioConverterFillComplexBuffer - (This->d_audio_converter, - reinterpret_cast<AudioConverterComplexInputDataProc> - (&(This->converter_callback)), - in_ref_con, - &actual_output_frames, - This->d_output_buffer, - NULL); - check_error_and_throw - (err, "AudioConverterFillComplexBuffer failed", - "audio_osx_source::au_input_callback"); + err = AudioConverterFillComplexBuffer( + This->d_audio_converter, + reinterpret_cast<AudioConverterComplexInputDataProc>( + &(This->converter_callback)), + in_ref_con, + &actual_output_frames, + This->d_output_buffer, + NULL); + check_error_and_throw(err, + "AudioConverterFillComplexBuffer failed", + "audio_osx_source::au_input_callback"); // on output, actual_output_frames is the actual number of // output frames @@ -1410,111 +1316,97 @@ namespace gr { #if _OSX_AU_DEBUG_RENDER_ std::cerr << "cb2: actual: #IF = " << This->d_n_actual_input_frames << ", #OF = " << actual_output_frames << std::endl; - if(This->d_n_actual_input_frames != available_input_frames) - std::cerr << "cb2.1: avail#IF = " << available_input_frames - << ", actual#IF = " << This->d_n_actual_input_frames << std::endl; + if (This->d_n_actual_input_frames != available_input_frames) + std::cerr << "cb2.1: avail#IF = " << available_input_frames + << ", actual#IF = " << This->d_n_actual_input_frames << std::endl; #endif - } + } - // add the output frames to the buffers' queue, checking for overflow + // add the output frames to the buffers' queue, checking for overflow - int counter = This->d_n_user_channels; - int res = 0; + int counter = This->d_n_user_channels; + int res = 0; - while(--counter >= 0) { - float* in_buffer = (float*) - This->d_output_buffer->mBuffers[counter].mData; + while (--counter >= 0) { + float* in_buffer = (float*)This->d_output_buffer->mBuffers[counter].mData; #if _OSX_AU_DEBUG_RENDER_ std::cerr << "cb3: enqueuing audio data." << std::endl; #endif - int l_res = This->d_buffers[counter]->enqueue - (in_buffer, actual_output_frames); - if(l_res == -1) - res = -1; - } + int l_res = This->d_buffers[counter]->enqueue(in_buffer, actual_output_frames); + if (l_res == -1) + res = -1; + } - if(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_queue_sample_count = - This->d_buffers[0]->buffer_length_items(); - } - else { + This->d_queue_sample_count = This->d_buffers[0]->buffer_length_items(); + } else { // keep up the local sample count This->d_queue_sample_count += actual_output_frames; - } + } #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "cb4: #OI = " << actual_output_frames - << ", #Cnt = " << This->d_queue_sample_count - << ", mSC = " << This->d_buffer_sample_count << std::endl; + std::cerr << "cb4: #OI = " << actual_output_frames + << ", #Cnt = " << This->d_queue_sample_count + << ", mSC = " << This->d_buffer_sample_count << std::endl; #endif - // signal that data is available, if appropriate + // signal that data is available, if appropriate - if (This->d_waiting_for_data) { - This->d_cond_data.notify_one(); - } + if (This->d_waiting_for_data) { + This->d_cond_data.notify_one(); + } #if _OSX_AU_DEBUG_RENDER_ - std::cerr << "cb5: returning." << std::endl; + std::cerr << "cb5: returning." << std::endl; #endif - return(err); - } + return (err); +} #ifndef GR_USE_OLD_AUDIO_UNIT - OSStatus - osx_source::hardware_listener - (AudioObjectID in_object_id, - UInt32 in_num_addresses, - const AudioObjectPropertyAddress in_addresses[], - void* in_client_data) +OSStatus osx_source::hardware_listener(AudioObjectID in_object_id, + UInt32 in_num_addresses, + const AudioObjectPropertyAddress in_addresses[], + void* in_client_data) #else - OSStatus - osx_source::hardware_listener - (AudioHardwarePropertyID in_property_id, - void* in_client_data) +OSStatus osx_source::hardware_listener(AudioHardwarePropertyID in_property_id, + void* in_client_data) #endif - { - osx_source* This = reinterpret_cast - <osx_source*>(in_client_data); - This->reset(true); - return(noErr); - } +{ + osx_source* This = reinterpret_cast<osx_source*>(in_client_data); + This->reset(true); + return (noErr); +} #ifndef GR_USE_OLD_AUDIO_UNIT - OSStatus - osx_source::default_listener - (AudioObjectID in_object_id, - UInt32 in_num_addresses, - const AudioObjectPropertyAddress in_addresses[], - void* in_client_data) +OSStatus osx_source::default_listener(AudioObjectID in_object_id, + UInt32 in_num_addresses, + const AudioObjectPropertyAddress in_addresses[], + void* in_client_data) #else - OSStatus - osx_source::default_listener - (AudioHardwarePropertyID in_property_id, - void* in_client_data) +OSStatus osx_source::default_listener(AudioHardwarePropertyID in_property_id, + void* in_client_data) #endif - { - osx_source* This = reinterpret_cast - <osx_source*>(in_client_data); - This->reset(false); - return(noErr); - } +{ + osx_source* This = reinterpret_cast<osx_source*>(in_client_data); + This->reset(false); + return (noErr); +} - } /* namespace audio */ +} /* namespace audio */ } /* namespace gr */ diff --git a/gr-audio/lib/osx/osx_source.h b/gr-audio/lib/osx/osx_source.h index 3c9147d26c..688ff3c32d 100644 --- a/gr-audio/lib/osx/osx_source.h +++ b/gr-audio/lib/osx/osx_source.h @@ -29,147 +29,132 @@ #include "circular_buffer.h" namespace gr { - namespace audio { - - /*! - * \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 osx_source : public source - { - private: - - Float64 d_device_sample_rate, d_output_sample_rate; - UInt32 d_input_buffer_size_frames, d_input_buffer_size_bytes; - UInt32 d_output_buffer_size_frames, d_output_buffer_size_bytes; - UInt32 d_device_buffer_size_frames, d_device_buffer_size_bytes; - UInt32 d_lead_size_frames, d_lead_size_bytes; - UInt32 d_trail_size_frames, d_trail_size_bytes; - UInt32 d_extra_buffer_size_frames, d_extra_buffer_size_bytes; - UInt32 d_queue_sample_count, d_buffer_sample_count; - UInt32 d_n_available_input_frames, d_n_actual_input_frames; - UInt32 d_n_user_channels, d_n_dev_channels; - bool d_ok_to_block, d_pass_through; - bool d_waiting_for_data, d_do_reset, d_hardware_changed; - bool d_using_default_device; - gr::thread::mutex d_internal; - gr::thread::condition_variable d_cond_data; - std::vector < circular_buffer<float>* > d_buffers; - std::string d_desired_name, d_selected_name; +namespace audio { - // CoreAudio variables - - AudioDeviceID d_input_ad_id; - AudioUnit d_input_au; - AudioBufferList* d_input_buffer; - AudioBufferList* d_output_buffer; - AudioConverterRef d_audio_converter; +/*! + * \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 osx_source : public source +{ +private: + Float64 d_device_sample_rate, d_output_sample_rate; + UInt32 d_input_buffer_size_frames, d_input_buffer_size_bytes; + UInt32 d_output_buffer_size_frames, d_output_buffer_size_bytes; + UInt32 d_device_buffer_size_frames, d_device_buffer_size_bytes; + UInt32 d_lead_size_frames, d_lead_size_bytes; + UInt32 d_trail_size_frames, d_trail_size_bytes; + UInt32 d_extra_buffer_size_frames, d_extra_buffer_size_bytes; + UInt32 d_queue_sample_count, d_buffer_sample_count; + UInt32 d_n_available_input_frames, d_n_actual_input_frames; + UInt32 d_n_user_channels, d_n_dev_channels; + bool d_ok_to_block, d_pass_through; + bool d_waiting_for_data, d_do_reset, d_hardware_changed; + bool d_using_default_device; + gr::thread::mutex d_internal; + gr::thread::condition_variable d_cond_data; + std::vector<circular_buffer<float>*> d_buffers; + std::string d_desired_name, d_selected_name; - // d_asbd_device: ASBD of the device that is creating the input - // data stream + // CoreAudio variables - AudioStreamBasicDescription d_asbd_device; + AudioDeviceID d_input_ad_id; + AudioUnit d_input_au; + AudioBufferList* d_input_buffer; + AudioBufferList* d_output_buffer; + AudioConverterRef d_audio_converter; - // d_asbd_client: ASBD of the client side (output) of the - // hardware device + // d_asbd_device: ASBD of the device that is creating the input + // data stream - AudioStreamBasicDescription d_asbd_client; + AudioStreamBasicDescription d_asbd_device; - // d_asbd_user: ASBD of the user's arguments, if an audio - // converter is needed outside that provided by the client side. + // d_asbd_client: ASBD of the client side (output) of the + // hardware device - AudioStreamBasicDescription d_asbd_user; + AudioStreamBasicDescription d_asbd_client; - public: + // d_asbd_user: ASBD of the user's arguments, if an audio + // converter is needed outside that provided by the client side. - osx_source(int sample_rate, - const std::string& device_name, - bool ok_to_block); + AudioStreamBasicDescription d_asbd_user; - virtual inline ~osx_source() { - teardown(); - } +public: + osx_source(int sample_rate, const std::string& device_name, bool ok_to_block); - virtual bool start(); - virtual bool stop(); + virtual inline ~osx_source() { teardown(); } - virtual bool check_topology(int ninputs, int noutputs); + virtual bool start(); + virtual bool stop(); - virtual int work(int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); + virtual bool check_topology(int ninputs, int noutputs); - inline void reset(bool hardware_changed) { - d_hardware_changed = hardware_changed; - d_do_reset = true; - } + virtual int work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); - private: + inline void reset(bool hardware_changed) + { + d_hardware_changed = hardware_changed; + d_do_reset = true; + } - bool is_running(); +private: + bool is_running(); - void setup(); + void setup(); - void teardown(); + void teardown(); - void alloc_audio_buffer_list - (AudioBufferList** t_abl, - UInt32 n_channels, - UInt32 input_buffer_size_bytes); + void alloc_audio_buffer_list(AudioBufferList** t_abl, + UInt32 n_channels, + UInt32 input_buffer_size_bytes); - void free_audio_buffer_list - (AudioBufferList** t_abl); + void free_audio_buffer_list(AudioBufferList** t_abl); - static OSStatus converter_callback - (AudioConverterRef in_audio_converter, - UInt32* io_number_data_packets, - AudioBufferList* io_data, - AudioStreamPacketDescription** out_aspd, - void* in_user_data); + static OSStatus converter_callback(AudioConverterRef in_audio_converter, + UInt32* io_number_data_packets, + AudioBufferList* io_data, + AudioStreamPacketDescription** out_aspd, + void* in_user_data); - static OSStatus au_input_callback - (void *in_ref_con, - AudioUnitRenderActionFlags *io_action_flags, - const AudioTimeStamp *in_time_stamp, - UInt32 in_bus_number, - UInt32 in_number_frames, - AudioBufferList *io_data); + static OSStatus au_input_callback(void* in_ref_con, + AudioUnitRenderActionFlags* io_action_flags, + const AudioTimeStamp* in_time_stamp, + UInt32 in_bus_number, + UInt32 in_number_frames, + AudioBufferList* io_data); #ifndef GR_USE_OLD_AUDIO_UNIT - // OSX 10.4 and newer + // OSX 10.4 and newer - static OSStatus hardware_listener - (AudioObjectID in_object_id, - UInt32 in_num_addresses, - const AudioObjectPropertyAddress in_addresses[], - void* in_client_data); + static OSStatus hardware_listener(AudioObjectID in_object_id, + UInt32 in_num_addresses, + const AudioObjectPropertyAddress in_addresses[], + void* in_client_data); - static OSStatus default_listener - (AudioObjectID in_object_id, - UInt32 in_num_addresses, - const AudioObjectPropertyAddress in_addresses[], - void* in_client_data); + static OSStatus default_listener(AudioObjectID in_object_id, + UInt32 in_num_addresses, + const AudioObjectPropertyAddress in_addresses[], + void* in_client_data); #else - // OSX 10.6 and older; removed as of 10.7 + // OSX 10.6 and older; removed as of 10.7 - static OSStatus hardware_listener - (AudioHardwarePropertyID in_property_id, - void* in_client_data); + static OSStatus hardware_listener(AudioHardwarePropertyID in_property_id, + void* in_client_data); - static OSStatus default_listener - (AudioHardwarePropertyID in_property_id, - void* in_client_data); + static OSStatus default_listener(AudioHardwarePropertyID in_property_id, + void* in_client_data); #endif - - }; - } /* namespace audio */ +}; +} /* namespace audio */ } /* namespace gr */ #endif /* INCLUDED_AUDIO_OSX_SOURCE_H */ diff --git a/gr-audio/lib/portaudio/portaudio_impl.cc b/gr-audio/lib/portaudio/portaudio_impl.cc index acc92cf237..38b02d5a27 100644 --- a/gr-audio/lib/portaudio/portaudio_impl.cc +++ b/gr-audio/lib/portaudio/portaudio_impl.cc @@ -29,80 +29,81 @@ #include <string.h> namespace gr { - namespace audio { +namespace audio { - PaDeviceIndex - 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++) { +PaDeviceIndex 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; + if (strncmp(name, pdi->name, len) == 0) { + result = i; + break; } - } - return result; } + return result; +} - void - print_devices() - { - int numDevices, defaultDisplayed; - const PaDeviceInfo *deviceInfo; +void print_devices() +{ + int numDevices, defaultDisplayed; + const PaDeviceInfo* deviceInfo; - numDevices = Pa_GetDeviceCount(); - if(numDevices < 0) + numDevices = Pa_GetDeviceCount(); + if (numDevices < 0) return; - printf("Number of devices found = %d\n", numDevices); + printf("Number of devices found = %d\n", numDevices); - for(int i = 0; i < numDevices; i++) { + 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()) { - 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_GetDefaultInputDevice()) { + 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 (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"); + 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("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); - } + 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); } +} - } /* namespace audio */ +} /* namespace audio */ } /* namespace gr */ diff --git a/gr-audio/lib/portaudio/portaudio_impl.h b/gr-audio/lib/portaudio/portaudio_impl.h index 0cb099e591..f57a601ac7 100644 --- a/gr-audio/lib/portaudio/portaudio_impl.h +++ b/gr-audio/lib/portaudio/portaudio_impl.h @@ -27,12 +27,12 @@ #include <portaudio.h> namespace gr { - namespace audio { +namespace audio { - PaDeviceIndex pa_find_device_by_name(const char *name); - void print_devices(); +PaDeviceIndex pa_find_device_by_name(const char* name); +void print_devices(); - } /* namespace audio */ +} /* namespace audio */ } /* namespace gr */ #endif /* INCLUDED_AUDIO_PORTAUDIO_IMPL_H */ diff --git a/gr-audio/lib/portaudio/portaudio_sink.cc b/gr-audio/lib/portaudio/portaudio_sink.cc index 56ade35b19..e9ff3759da 100644 --- a/gr-audio/lib/portaudio/portaudio_sink.cc +++ b/gr-audio/lib/portaudio/portaudio_sink.cc @@ -43,233 +43,234 @@ #endif namespace gr { - namespace audio { - - sink::sptr - portaudio_sink_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block) - { - return sink::sptr - (new portaudio_sink(sampling_rate, device_name, ok_to_block)); - } +namespace audio { + +sink::sptr +portaudio_sink_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block) +{ + return sink::sptr(new 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; +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 prefs::singleton()->get_string - ("audio_portaudio", "default_output_device", ""); - } +// Number of portaudio buffers in the ringbuffer +static const unsigned int N_BUFFERS = 4; - void - portaudio_sink::create_ringbuffer(void) - { - int bufsize_samples = d_portaudio_buffer_size_frames * d_output_parameters.channelCount; +static std::string default_device_name() +{ + return prefs::singleton()->get_string("audio_portaudio", "default_output_device", ""); +} - if(d_verbose) { - fprintf(stderr,"ring buffer size = %d frames\n", - N_BUFFERS*bufsize_samples/d_output_parameters.channelCount); - } +void portaudio_sink::create_ringbuffer(void) +{ + int bufsize_samples = + d_portaudio_buffer_size_frames * d_output_parameters.channelCount; - // FYI, the buffer indices 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); + if (d_verbose) { + fprintf(stderr, + "ring buffer size = %d frames\n", + N_BUFFERS * bufsize_samples / d_output_parameters.channelCount); } - /* - * 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, + // FYI, the buffer indices 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) - { - portaudio_sink *self = (portaudio_sink *)arg; - int nreqd_samples = - framesPerBuffer * self->d_output_parameters.channelCount; + void* arg) +{ + portaudio_sink* self = (portaudio_sink*)arg; + int nreqd_samples = framesPerBuffer * self->d_output_parameters.channelCount; - int navail_samples = self->d_reader->items_available(); + int navail_samples = self->d_reader->items_available(); - if(nreqd_samples <= navail_samples) { // We've got enough data... + if (nreqd_samples <= navail_samples) { // We've got enough data... { - gr::thread::scoped_lock guard(self->d_ringbuffer_mutex); + gr::thread::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); + 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; + 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 + 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."); + 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! + self->d_ringbuffer_cond.notify_one(); // Tell the sink to get going! return paContinue; - } } - - // ---------------------------------------------------------------- - - portaudio_sink::portaudio_sink(int sampling_rate, - const std::string device_name, - bool ok_to_block) - : sync_block("audio_portaudio_sink", - io_signature::make(0, 0, 0), - io_signature::make(0, 0, 0)), - d_sampling_rate(sampling_rate), - d_device_name(device_name.empty() ? default_device_name() : device_name), - d_ok_to_block(ok_to_block), - d_verbose(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) { +} + +// ---------------------------------------------------------------- + +portaudio_sink::portaudio_sink(int sampling_rate, + const std::string device_name, + bool ok_to_block) + : sync_block("audio_portaudio_sink", + io_signature::make(0, 0, 0), + io_signature::make(0, 0, 0)), + d_sampling_rate(sampling_rate), + d_device_name(device_name.empty() ? default_device_name() : device_name), + d_ok_to_block(ok_to_block), + d_verbose(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) + if (d_verbose) print_devices(); - numDevices = Pa_GetDeviceCount(); - if(numDevices < 0) + numDevices = Pa_GetDeviceCount(); + if (numDevices < 0) bail("Pa Device count failed", 0); - if(numDevices == 0) + if (numDevices == 0) bail("no devices available", 0); - if(d_device_name.empty()) { + if (d_device_name.empty()) { // FIXME Get smarter about picking something - fprintf(stderr,"\nUsing Default Device\n"); + 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 { + 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); + 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); + 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(io_signature::make(1, deviceInfo->maxOutputChannels, - sizeof(sample_t))); } - bool - portaudio_sink::check_topology(int ninputs, int noutputs) - { - PaError err; + 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. - if(Pa_IsStreamActive(d_stream)) { + // 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( + io_signature::make(1, deviceInfo->maxOutputChannels, sizeof(sample_t))); +} + +bool 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_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 + 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); + 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) { + 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); @@ -279,100 +280,100 @@ namespace gr { d_output_parameters.suggestedLatency, psi->sampleRate); #endif - fprintf(stderr, "d_portaudio_buffer_size_frames = %d\n", - d_portaudio_buffer_size_frames); + fprintf( + stderr, "d_portaudio_buffer_size_frames = %d\n", d_portaudio_buffer_size_frames); - assert(d_portaudio_buffer_size_frames != 0); + assert(d_portaudio_buffer_size_frames != 0); - create_ringbuffer(); + create_ringbuffer(); - err = Pa_StartStream(d_stream); - if(err != paNoError) { + err = Pa_StartStream(d_stream); + if (err != paNoError) { output_error_msg("StartStream failed", err); return false; - } - - return true; } - portaudio_sink::~portaudio_sink() - { - Pa_StopStream(d_stream); // wait for output to drain - Pa_CloseStream(d_stream); - Pa_Terminate(); - } + return true; +} + +portaudio_sink::~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 - 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) { - { - gr::thread::scoped_lock guard(d_ringbuffer_mutex); - while(!d_ringbuffer_ready) - d_ringbuffer_cond.wait(guard); +/* + * 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 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) { + { + gr::thread::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; } - 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 { - gr::thread::scoped_lock guard(d_ringbuffer_mutex); + gr::thread::scoped_lock guard(d_ringbuffer_mutex); - int nf = std::min(noutput_items - k, nframes); - float *p = (float*)d_writer->write_pointer(); + 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]; + 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_writer->update_write_pointer(nf * nchan); + k += nf; - d_ringbuffer_ready = false; + d_ringbuffer_ready = false; } - } - - return k; // tell how many we actually did - } - - void - 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 - portaudio_sink::bail(const char *msg, int err) - { - output_error_msg(msg, err); - throw std::runtime_error("audio_portaudio_sink"); } - } /* namespace audio */ + return k; // tell how many we actually did +} + +void 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 portaudio_sink::bail(const char* msg, int err) +{ + output_error_msg(msg, err); + throw std::runtime_error("audio_portaudio_sink"); +} + +} /* namespace audio */ } /* namespace gr */ diff --git a/gr-audio/lib/portaudio/portaudio_sink.h b/gr-audio/lib/portaudio/portaudio_sink.h index d86681036f..98e72fc2c2 100644 --- a/gr-audio/lib/portaudio/portaudio_sink.h +++ b/gr-audio/lib/portaudio/portaudio_sink.h @@ -31,60 +31,58 @@ //#include <gri_logger.h> namespace gr { - namespace audio { +namespace audio { - PaStreamCallback portaudio_sink_callback; +PaStreamCallback portaudio_sink_callback; - /*! - * \brief Audio sink using PORTAUDIO - * \ingroup audio_blk - * - * Input samples must be in the range [-1,1]. - */ - class portaudio_sink : public sink - { - friend PaStreamCallback portaudio_sink_callback; +/*! + * \brief Audio sink using PORTAUDIO + * \ingroup audio_blk + * + * Input samples must be in the range [-1,1]. + */ +class portaudio_sink : public 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_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 + unsigned int d_portaudio_buffer_size_frames; // number of frames in a portaudio buffer - PaStream *d_stream; - PaStreamParameters d_output_parameters; + PaStream* d_stream; + PaStreamParameters d_output_parameters; - gr::buffer_sptr d_writer; // buffer used between work and callback - gr::buffer_reader_sptr d_reader; + gr::buffer_sptr d_writer; // buffer used between work and callback + gr::buffer_reader_sptr d_reader; - gr::thread::mutex d_ringbuffer_mutex; - gr::thread::condition_variable d_ringbuffer_cond; - bool d_ringbuffer_ready; + gr::thread::mutex d_ringbuffer_mutex; + gr::thread::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 + // 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); - void create_ringbuffer(); + void output_error_msg(const char* msg, int err); + void bail(const char* msg, int err); + void create_ringbuffer(); - public: - portaudio_sink(int sampling_rate, - const std::string device_name, - bool ok_to_block); +public: + portaudio_sink(int sampling_rate, const std::string device_name, bool ok_to_block); - ~portaudio_sink(); + ~portaudio_sink(); - bool check_topology(int ninputs, int noutputs); + 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); - }; + int work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; - } /* namespace audio */ +} /* namespace audio */ } /* namespace gr */ #endif /* INCLUDED_AUDIO_PORTAUDIO_SINK_H */ diff --git a/gr-audio/lib/portaudio/portaudio_source.cc b/gr-audio/lib/portaudio/portaudio_source.cc index 767fc8e281..f785362946 100644 --- a/gr-audio/lib/portaudio/portaudio_source.cc +++ b/gr-audio/lib/portaudio/portaudio_source.cc @@ -43,228 +43,230 @@ #endif namespace gr { - namespace audio { - - source::sptr - portaudio_source_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block) - { - return source::sptr - (new portaudio_source(sampling_rate, device_name, ok_to_block)); - } +namespace audio { + +source::sptr +portaudio_source_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block) +{ + return source::sptr(new 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; +typedef float sample_t; - // Number of portaudio buffers in the ringbuffer - static const unsigned int N_BUFFERS = 4; +// Number of portaudio buffers in the ringbuffer +static const unsigned int N_BUFFERS = 4; - static std::string - default_device_name() - { - return prefs::singleton()->get_string - ("audio_portaudio", "default_input_device", ""); - } +static std::string default_device_name() +{ + return prefs::singleton()->get_string("audio_portaudio", "default_input_device", ""); +} - void - portaudio_source::create_ringbuffer(void) - { - int bufsize_samples = d_portaudio_buffer_size_frames * d_input_parameters.channelCount; +void 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 indices 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); + if (d_verbose) { + fprintf(stderr, + "ring buffer size = %d frames\n", + N_BUFFERS * bufsize_samples / d_input_parameters.channelCount); } - /* - * 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, + // FYI, the buffer indices 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) - { - portaudio_source *self = (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) + void* arg) +{ + portaudio_source* self = (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 { - gr::thread::scoped_lock(d_ringbuffer_mutex); + gr::thread::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); + 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; + // 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 + 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."); + 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! + self->d_ringbuffer_cond.notify_one(); // Tell the sink to get going! return paContinue; - } } - - // ---------------------------------------------------------------- - - portaudio_source::portaudio_source(int sampling_rate, - const std::string device_name, - bool ok_to_block) - : sync_block("audio_portaudio_source", - io_signature::make(0, 0, 0), - io_signature::make(0, 0, 0)), - d_sampling_rate(sampling_rate), - d_device_name(device_name.empty() ? default_device_name() : device_name), - d_ok_to_block(ok_to_block), - d_verbose(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) { +} + +// ---------------------------------------------------------------- + +portaudio_source::portaudio_source(int sampling_rate, + const std::string device_name, + bool ok_to_block) + : sync_block("audio_portaudio_source", + io_signature::make(0, 0, 0), + io_signature::make(0, 0, 0)), + d_sampling_rate(sampling_rate), + d_device_name(device_name.empty() ? default_device_name() : device_name), + d_ok_to_block(ok_to_block), + d_verbose(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) + if (d_verbose) print_devices(); - numDevices = Pa_GetDeviceCount(); - if(numDevices < 0) + numDevices = Pa_GetDeviceCount(); + if (numDevices < 0) bail("Pa Device count failed", 0); - if(numDevices == 0) + if (numDevices == 0) bail("no devices available", 0); - if(d_device_name.empty()) { + 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 { + 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); + 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); + 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(io_signature::make(1, deviceInfo->maxInputChannels, - sizeof (sample_t))); } - bool - portaudio_source::check_topology(int ninputs, int noutputs) - { - PaError err; + 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. - if(Pa_IsStreamActive(d_stream)) { + // 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( + io_signature::make(1, deviceInfo->maxInputChannels, sizeof(sample_t))); +} + +bool 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_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 + 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); + 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) { + 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); @@ -274,113 +276,114 @@ namespace gr { d_input_parameters.suggestedLatency, psi->sampleRate); #endif - fprintf(stderr, "d_portaudio_buffer_size_frames = %d\n", - d_portaudio_buffer_size_frames); + fprintf( + stderr, "d_portaudio_buffer_size_frames = %d\n", d_portaudio_buffer_size_frames); - assert(d_portaudio_buffer_size_frames != 0); + assert(d_portaudio_buffer_size_frames != 0); - create_ringbuffer(); + create_ringbuffer(); - err = Pa_StartStream(d_stream); - if(err != paNoError) { + err = Pa_StartStream(d_stream); + if (err != paNoError) { output_error_msg("StartStream failed", err); return false; - } - - return true; - } - - portaudio_source::~portaudio_source() - { - Pa_StopStream(d_stream); // wait for output to drain - Pa_CloseStream(d_stream); - Pa_Terminate(); } - int - 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) { - gr::thread::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 underrun. 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 - { - gr::thread::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; - } + return true; +} + +portaudio_source::~portaudio_source() +{ + Pa_StopStream(d_stream); // wait for output to drain + Pa_CloseStream(d_stream); + Pa_Terminate(); +} + +int 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) { + gr::thread::scoped_lock guard(d_ringbuffer_mutex); + while (d_ringbuffer_ready == false) + d_ringbuffer_cond.wait(guard); // block here, then try again + continue; } - k += nf; - d_ringbuffer_ready = false; - return k; - } + 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 underrun. 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 + { + gr::thread::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. { - gr::thread::scoped_lock guard(d_ringbuffer_mutex); + gr::thread::scoped_lock guard(d_ringbuffer_mutex); - int nf = std::min(noutput_items - k, nframes); + 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++; + 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; + d_reader->update_read_pointer(nf * nchan); + k += nf; + d_ringbuffer_ready = false; } - } - - return k; // tell how many we actually did - } - - void - 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 - portaudio_source::bail(const char *msg, int err) - { - output_error_msg(msg, err); - throw std::runtime_error("audio_portaudio_source"); } - } /* namespace audio */ + return k; // tell how many we actually did +} + +void 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 portaudio_source::bail(const char* msg, int err) +{ + output_error_msg(msg, err); + throw std::runtime_error("audio_portaudio_source"); +} + +} /* namespace audio */ } /* namespace gr */ diff --git a/gr-audio/lib/portaudio/portaudio_source.h b/gr-audio/lib/portaudio/portaudio_source.h index 7d315c5bc1..a72cdd4129 100644 --- a/gr-audio/lib/portaudio/portaudio_source.h +++ b/gr-audio/lib/portaudio/portaudio_source.h @@ -31,59 +31,57 @@ #include <stdexcept> namespace gr { - namespace audio { +namespace audio { - PaStreamCallback portaudio_source_callback; +PaStreamCallback portaudio_source_callback; - /*! - * \brief Audio source using PORTAUDIO - * \ingroup audio_blk - * - * Input samples must be in the range [-1,1]. - */ - class portaudio_source : public source - { - friend PaStreamCallback portaudio_source_callback; +/*! + * \brief Audio source using PORTAUDIO + * \ingroup audio_blk + * + * Input samples must be in the range [-1,1]. + */ +class portaudio_source : public 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_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 + unsigned int d_portaudio_buffer_size_frames; // number of frames in a portaudio buffer - PaStream *d_stream; - PaStreamParameters d_input_parameters; + PaStream* d_stream; + PaStreamParameters d_input_parameters; - gr::buffer_sptr d_writer; // buffer used between work and callback - gr::buffer_reader_sptr d_reader; + gr::buffer_sptr d_writer; // buffer used between work and callback + gr::buffer_reader_sptr d_reader; - gr::thread::mutex d_ringbuffer_mutex; - gr::thread::condition_variable d_ringbuffer_cond; - bool d_ringbuffer_ready; + gr::thread::mutex d_ringbuffer_mutex; + gr::thread::condition_variable d_ringbuffer_cond; + bool d_ringbuffer_ready; - // random stats - int d_noverruns; // count of overruns + // random stats + int d_noverruns; // count of overruns - void output_error_msg(const char *msg, int err); - void bail(const char *msg, int err); - void create_ringbuffer(); + void output_error_msg(const char* msg, int err); + void bail(const char* msg, int err); + void create_ringbuffer(); - public: - portaudio_source(int sampling_rate, - const std::string device_name, - bool ok_to_block); +public: + portaudio_source(int sampling_rate, const std::string device_name, bool ok_to_block); - ~portaudio_source(); + ~portaudio_source(); - bool check_topology(int ninputs, int noutputs); + 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); - }; + int work(int ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; - } /* namespace audio */ +} /* namespace audio */ } /* namespace gr */ #endif /* INCLUDED_AUDIO_PORTAUDIO_SOURCE_H */ diff --git a/gr-audio/lib/windows/windows_sink.cc b/gr-audio/lib/windows/windows_sink.cc index 6c17084c08..7c220ff831 100644 --- a/gr-audio/lib/windows/windows_sink.cc +++ b/gr-audio/lib/windows/windows_sink.cc @@ -1,24 +1,24 @@ /* -*- c++ -*- */ /* -* Copyright 2004-2011,2013-2014 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. -*/ + * Copyright 2004-2011,2013-2014 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" @@ -40,343 +40,357 @@ #include <sstream> namespace gr { - namespace audio { +namespace audio { - sink::sptr - windows_sink_fcn(int sampling_rate, - const std::string &device_name, - bool ok_to_block) - { - return sink::sptr - (new windows_sink(sampling_rate, device_name, ok_to_block)); - } +sink::sptr +windows_sink_fcn(int sampling_rate, const std::string& device_name, bool ok_to_block) +{ + return sink::sptr(new windows_sink(sampling_rate, device_name, ok_to_block)); +} - static const double CHUNK_TIME = prefs::singleton()->get_double("audio_windows", "period_time", 0.1); // 100 ms (below 3ms distortion will likely occur regardless of number of buffers, will likely be a higher limit on slower machines) - static const int nPeriods = prefs::singleton()->get_long("audio_windows", "nperiods", 4); // 4 should be more than enough with a normal chunk time (2 will likely work as well)... at 3ms chunks 10 was enough on a fast machine - static const bool verbose = prefs::singleton()->get_bool("audio_windows", "verbose", false); - static const std::string default_device = prefs::singleton()->get_string("audio_windows", "standard_output_device", "default"); +static const double CHUNK_TIME = prefs::singleton()->get_double( + "audio_windows", + "period_time", + 0.1); // 100 ms (below 3ms distortion will likely occur regardless of number of + // buffers, will likely be a higher limit on slower machines) +static const int nPeriods = prefs::singleton()->get_long( + "audio_windows", + "nperiods", + 4); // 4 should be more than enough with a normal chunk time (2 will likely work as + // well)... at 3ms chunks 10 was enough on a fast machine +static const bool verbose = + prefs::singleton()->get_bool("audio_windows", "verbose", false); +static const std::string default_device = + prefs::singleton()->get_string("audio_windows", "standard_output_device", "default"); - static std::string - default_device_name() - { - return (default_device == "default" ? "WAVE_MAPPER" : default_device); - } +static std::string default_device_name() +{ + return (default_device == "default" ? "WAVE_MAPPER" : default_device); +} - windows_sink::windows_sink(int sampling_freq, const std::string device_name, bool ok_to_block) - : sync_block("audio_windows_sink", - io_signature::make(1, 2, sizeof(float)), - io_signature::make(0, 0, 0)), - d_sampling_freq(sampling_freq), - d_device_name(device_name.empty() ? default_device_name() : device_name), - d_fd(-1), d_buffers(0), d_chunk_size(0), d_ok_to_block(ok_to_block) - { - /* Initialize the WAVEFORMATEX for 16-bit, 44KHz, stereo */ - wave_format.wFormatTag = WAVE_FORMAT_PCM; - wave_format.nChannels = 2; // changing this will require adjustments to the work routine. - wave_format.wBitsPerSample = 16; // changing this will necessitate changing buffer type from short. - wave_format.nSamplesPerSec = d_sampling_freq; // 44100 is default but up to flowgraph settings; - wave_format.nBlockAlign = - wave_format.nChannels * (wave_format.wBitsPerSample / 8); - wave_format.nAvgBytesPerSec = - wave_format.nSamplesPerSec * wave_format.nBlockAlign; - wave_format.cbSize = 0; +windows_sink::windows_sink(int sampling_freq, + const std::string device_name, + bool ok_to_block) + : sync_block("audio_windows_sink", + io_signature::make(1, 2, sizeof(float)), + io_signature::make(0, 0, 0)), + d_sampling_freq(sampling_freq), + d_device_name(device_name.empty() ? default_device_name() : device_name), + d_fd(-1), + d_buffers(0), + d_chunk_size(0), + d_ok_to_block(ok_to_block) +{ + /* Initialize the WAVEFORMATEX for 16-bit, 44KHz, stereo */ + wave_format.wFormatTag = WAVE_FORMAT_PCM; + wave_format.nChannels = + 2; // changing this will require adjustments to the work routine. + wave_format.wBitsPerSample = + 16; // changing this will necessitate changing buffer type from short. + wave_format.nSamplesPerSec = + d_sampling_freq; // 44100 is default but up to flowgraph settings; + wave_format.nBlockAlign = wave_format.nChannels * (wave_format.wBitsPerSample / 8); + wave_format.nAvgBytesPerSec = wave_format.nSamplesPerSec * wave_format.nBlockAlign; + wave_format.cbSize = 0; - d_chunk_size = (int)(d_sampling_freq * CHUNK_TIME); // Samples per chunk - set_output_multiple(d_chunk_size); - d_buffer_size = d_chunk_size * wave_format.nChannels * (wave_format.wBitsPerSample / 8); // room for 16-bit audio on two channels. + d_chunk_size = (int)(d_sampling_freq * CHUNK_TIME); // Samples per chunk + set_output_multiple(d_chunk_size); + d_buffer_size = + d_chunk_size * wave_format.nChannels * + (wave_format.wBitsPerSample / 8); // room for 16-bit audio on two channels. - d_wave_write_event = CreateEvent(NULL, FALSE, FALSE, NULL); - if (open_waveout_device() < 0) { + d_wave_write_event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (open_waveout_device() < 0) { perror("audio_windows_sink:open_waveout_device() failed\n"); - throw - std::runtime_error("audio_windows_sink:open_waveout_device() failed"); - } - else if (verbose) { + throw std::runtime_error("audio_windows_sink:open_waveout_device() failed"); + } else if (verbose) { GR_LOG_INFO(d_logger, "Opened windows waveout device"); - } - d_buffers = new LPWAVEHDR[nPeriods]; - for (int i = 0; i < nPeriods; i++) - { + } + d_buffers = new LPWAVEHDR[nPeriods]; + for (int i = 0; i < nPeriods; i++) { d_buffers[i] = new WAVEHDR; d_buffers[i]->dwLoops = 0L; d_buffers[i]->dwFlags = WHDR_DONE; d_buffers[i]->dwBufferLength = d_buffer_size; d_buffers[i]->lpData = new CHAR[d_buffer_size]; - } - if (verbose) GR_LOG_INFO(d_logger, boost::format("Initialized %1% %2%ms audio buffers, total memory used: %3$0.2fkB") % (nPeriods) % (CHUNK_TIME * 1000) % ((d_buffer_size * nPeriods) / 1024.0)); } + if (verbose) + GR_LOG_INFO( + d_logger, + boost::format( + "Initialized %1% %2%ms audio buffers, total memory used: %3$0.2fkB") % + (nPeriods) % (CHUNK_TIME * 1000) % ((d_buffer_size * nPeriods) / 1024.0)); +} - windows_sink::~windows_sink() - { - // stop playback and set all buffers to DONE. - waveOutReset(d_h_waveout); - // Now we can deallocate the buffers - for (int i = 0; i < nPeriods; i++) - { +windows_sink::~windows_sink() +{ + // stop playback and set all buffers to DONE. + waveOutReset(d_h_waveout); + // Now we can deallocate the buffers + for (int i = 0; i < nPeriods; i++) { if (d_buffers[i]->dwFlags & (WHDR_DONE | WHDR_PREPARED)) { - waveOutUnprepareHeader(d_h_waveout, d_buffers[i], sizeof(d_buffers[i])); - } - else { - + waveOutUnprepareHeader(d_h_waveout, d_buffers[i], sizeof(d_buffers[i])); + } else { } delete d_buffers[i]->lpData; - } - /* Free the callback Event */ - CloseHandle(d_wave_write_event); - waveOutClose(d_h_waveout); - delete [] d_buffers; } + /* Free the callback Event */ + CloseHandle(d_wave_write_event); + waveOutClose(d_h_waveout); + delete[] d_buffers; +} - int - windows_sink::work(int noutput_items, - gr_vector_const_void_star & input_items, - gr_vector_void_star & output_items) - { - const float *f0, *f1; +int windows_sink::work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + const float *f0, *f1; - int samples_sent = 0; - int samples_tosend = 0; - switch (input_items.size()) { - case 1: // mono input + int samples_sent = 0; + int samples_tosend = 0; + switch (input_items.size()) { + case 1: // mono input f0 = (const float*)input_items[0]; break; - case 2: // stereo input + case 2: // stereo input f0 = (const float*)input_items[0]; f1 = (const float*)input_items[1]; break; - } + } - while (samples_sent < noutput_items) { + while (samples_sent < noutput_items) { // Pick the first available wave header (buffer) - // If none available, then wait until the processing event if fired and check again - // Not all events free up a buffer, so it could take more than one loop to get one - // however, to avoid a lock, only wait 1 second for a freed up buffer then abort. + // If none available, then wait until the processing event if fired and check + // again Not all events free up a buffer, so it could take more than one loop to + // get one however, to avoid a lock, only wait 1 second for a freed up buffer then + // abort. LPWAVEHDR chosen_header = NULL; int c = 0; - while (!chosen_header) - { - ResetEvent(d_wave_write_event); - for (int i = 0; i < nPeriods; i++) - { - if (d_buffers[i]->dwFlags & WHDR_DONE) { - // uncomment the below to see which buffers are being consumed - // printf("%d ", i); - chosen_header = d_buffers[i]; - break; - } - } - if (!chosen_header) { - if (!d_ok_to_block) - { - // drop the input data, print warning, and return control. - printf("aO"); - return noutput_items; + while (!chosen_header) { + ResetEvent(d_wave_write_event); + for (int i = 0; i < nPeriods; i++) { + if (d_buffers[i]->dwFlags & WHDR_DONE) { + // uncomment the below to see which buffers are being consumed + // printf("%d ", i); + chosen_header = d_buffers[i]; + break; + } } - else { - WaitForSingleObject(d_wave_write_event, 100); + if (!chosen_header) { + if (!d_ok_to_block) { + // drop the input data, print warning, and return control. + printf("aO"); + return noutput_items; + } else { + WaitForSingleObject(d_wave_write_event, 100); + } } - } - if (c++ > 10) { - // After waiting for 1 second, then something else is seriously wrong so let's - // just fail and give some debugging information about the status - // of the buffers. - for (int i = 0; i < nPeriods; i++) { - printf("%d: %d\n", i, d_buffers[i]->dwFlags); + if (c++ > 10) { + // After waiting for 1 second, then something else is seriously wrong so + // let's just fail and give some debugging information about the status of + // the buffers. + for (int i = 0; i < nPeriods; i++) { + printf("%d: %d\n", i, d_buffers[i]->dwFlags); + } + perror("audio_windows_sink: no audio buffers available"); + return -1; } - perror("audio_windows_sink: no audio buffers available"); - return -1; - } } - short *d_buffer = (short *)chosen_header->lpData; - samples_tosend = noutput_items - samples_sent >= d_chunk_size ? d_chunk_size : noutput_items - samples_sent; + short* d_buffer = (short*)chosen_header->lpData; + samples_tosend = noutput_items - samples_sent >= d_chunk_size + ? d_chunk_size + : noutput_items - samples_sent; switch (input_items.size()) { - case 1: // mono input - for (int j = 0; j < samples_tosend; j++) { - d_buffer[2 * j + 0] = (short)(f0[j] * 32767); - d_buffer[2 * j + 1] = (short)(f0[j] * 32767); - } - f0 += samples_tosend; - break; - case 2: // stereo input - for (int j = 0; j < samples_tosend; j++) { - d_buffer[2 * j + 0] = (short)(f0[j] * 32767); - d_buffer[2 * j + 1] = (short)(f1[j] * 32767); - } - f0 += samples_tosend; - f1 += samples_tosend; - break; + case 1: // mono input + for (int j = 0; j < samples_tosend; j++) { + d_buffer[2 * j + 0] = (short)(f0[j] * 32767); + d_buffer[2 * j + 1] = (short)(f0[j] * 32767); + } + f0 += samples_tosend; + break; + case 2: // stereo input + for (int j = 0; j < samples_tosend; j++) { + d_buffer[2 * j + 0] = (short)(f0[j] * 32767); + d_buffer[2 * j + 1] = (short)(f1[j] * 32767); + } + f0 += samples_tosend; + f1 += samples_tosend; + break; } if (write_waveout(chosen_header) < 0) { - perror("audio_windows_sink: write failed"); + perror("audio_windows_sink: write failed"); } samples_sent += samples_tosend; - } - return samples_sent; } + return samples_sent; +} - int - windows_sink::string_to_int(const std::string & s) - { - int i; - std::istringstream(s) >> i; - return i; - } +int windows_sink::string_to_int(const std::string& s) +{ + int i; + std::istringstream(s) >> i; + return i; +} - MMRESULT windows_sink::is_format_supported(LPWAVEFORMATEX pwfx, UINT uDeviceID) - { - return (waveOutOpen( - NULL, // ptr can be NULL for query - uDeviceID, // the device identifier - pwfx, // defines requested format - NULL, // no callback - NULL, // no instance data - WAVE_FORMAT_QUERY)); // query only, do not open device - } +MMRESULT windows_sink::is_format_supported(LPWAVEFORMATEX pwfx, UINT uDeviceID) +{ + return (waveOutOpen(NULL, // ptr can be NULL for query + uDeviceID, // the device identifier + pwfx, // defines requested format + NULL, // no callback + NULL, // no instance data + WAVE_FORMAT_QUERY)); // query only, do not open device +} - bool windows_sink::is_number(const std::string& s) - { - std::string::const_iterator it = s.begin(); - while (it != s.end() && std::isdigit(*it)) ++it; - return !s.empty() && it == s.end(); - } +bool windows_sink::is_number(const std::string& s) +{ + std::string::const_iterator it = s.begin(); + while (it != s.end() && std::isdigit(*it)) + ++it; + return !s.empty() && it == s.end(); +} - UINT windows_sink::find_device(std::string szDeviceName) - { - UINT result = -1; - UINT num_devices = waveOutGetNumDevs(); - if (num_devices > 0) { +UINT windows_sink::find_device(std::string szDeviceName) +{ + UINT result = -1; + UINT num_devices = waveOutGetNumDevs(); + if (num_devices > 0) { // what the device name passed as a number? - if (is_number(szDeviceName)) - { - // a number, so must be referencing a device ID (which incremement from zero) - UINT num = std::stoul(szDeviceName); - if (num < num_devices) { - result = num; - } - else { - GR_LOG_INFO(d_logger, boost::format("Warning: waveOut deviceID %d was not found, defaulting to WAVE_MAPPER") % num); - result = WAVE_MAPPER; - } + if (is_number(szDeviceName)) { + // a number, so must be referencing a device ID (which incremement from zero) + UINT num = std::stoul(szDeviceName); + if (num < num_devices) { + result = num; + } else { + GR_LOG_INFO(d_logger, + boost::format("Warning: waveOut deviceID %d was not found, " + "defaulting to WAVE_MAPPER") % + num); + result = WAVE_MAPPER; + } - } - else { - // device name passed as string - for (UINT i = 0; i < num_devices; i++) - { - WAVEOUTCAPS woc; - if (waveOutGetDevCaps(i, &woc, sizeof(woc)) != MMSYSERR_NOERROR) - { - perror("Error: Could not retrieve wave out device capabilities for device"); - return -1; + } else { + // device name passed as string + for (UINT i = 0; i < num_devices; i++) { + WAVEOUTCAPS woc; + if (waveOutGetDevCaps(i, &woc, sizeof(woc)) != MMSYSERR_NOERROR) { + perror("Error: Could not retrieve wave out device capabilities for " + "device"); + return -1; + } + if (woc.szPname == szDeviceName) { + result = i; + } + if (verbose) + GR_LOG_INFO(d_logger, + boost::format("WaveOut Device %d: %s") % i % woc.szPname); } - if (woc.szPname == szDeviceName) - { - result = i; + if (result == -1) { + GR_LOG_INFO(d_logger, + boost::format("Warning: waveOut device '%s' was not found, " + "defaulting to WAVE_MAPPER") % + szDeviceName); + result = WAVE_MAPPER; } - if (verbose) GR_LOG_INFO(d_logger, boost::format("WaveOut Device %d: %s") % i % woc.szPname); - } - if (result == -1) { - GR_LOG_INFO(d_logger, boost::format("Warning: waveOut device '%s' was not found, defaulting to WAVE_MAPPER") % szDeviceName); - result = WAVE_MAPPER; - } } - } - else { + } else { perror("Error: No WaveOut devices present or accessible"); - } - return result; } + return result; +} - int - windows_sink::open_waveout_device(void) - { - UINT u_device_id; - unsigned long result; +int windows_sink::open_waveout_device(void) +{ + UINT u_device_id; + unsigned long result; - /** 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. - 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) + /** 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. + 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 + else // The below could be uncommented to allow selection of different device handles // however it is unclear what other devices are out there and how a user // would know the device ID so at the moment we will ignore that setting // and stick with WAVE_MAPPER u_device_id = find_device(d_device_name); - if (verbose) GR_LOG_INFO(d_logger, boost::format("waveOut Device ID: %1%") % (u_device_id)); + if (verbose) + GR_LOG_INFO(d_logger, boost::format("waveOut Device ID: %1%") % (u_device_id)); - // Check if the sampling rate/bits/channels are good to go with the device. - MMRESULT supported = is_format_supported(&wave_format, u_device_id); - if (supported != MMSYSERR_NOERROR) { + // Check if the sampling rate/bits/channels are good to go with the device. + MMRESULT supported = is_format_supported(&wave_format, u_device_id); + if (supported != MMSYSERR_NOERROR) { char err_msg[50]; waveOutGetErrorText(supported, err_msg, 50); GR_LOG_INFO(d_logger, boost::format("format error: %s") % err_msg); - perror("audio_windows_sink: Requested audio format is not supported by device driver"); + perror("audio_windows_sink: Requested audio format is not supported by device " + "driver"); return -1; - } + } - // Open a waveform device for output using event callback. - result = waveOutOpen(&d_h_waveout, u_device_id, - &wave_format, - (DWORD_PTR)d_wave_write_event, - 0, CALLBACK_EVENT | WAVE_ALLOWSYNC); + // Open a waveform device for output using event callback. + result = waveOutOpen(&d_h_waveout, + u_device_id, + &wave_format, + (DWORD_PTR)d_wave_write_event, + 0, + CALLBACK_EVENT | WAVE_ALLOWSYNC); - if (result) { + if (result) { perror("audio_windows_sink: Failed to open waveform output device."); return -1; - } - return 0; } + return 0; +} - int - windows_sink::write_waveout(LPWAVEHDR lp_wave_hdr) - { - UINT w_result; +int windows_sink::write_waveout(LPWAVEHDR lp_wave_hdr) +{ + UINT w_result; - /* 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 */ - 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 */ + lp_wave_hdr->dwFlags = 0L; - w_result = - waveOutPrepareHeader(d_h_waveout, lp_wave_hdr, sizeof(WAVEHDR)); - if (w_result != 0) { + w_result = waveOutPrepareHeader(d_h_waveout, lp_wave_hdr, sizeof(WAVEHDR)); + if (w_result != 0) { perror("audio_windows_sink: Failed to waveOutPrepareHeader"); return -1; - } + } - w_result = waveOutWrite(d_h_waveout, lp_wave_hdr, sizeof(WAVEHDR)); - if (w_result != 0) { + w_result = waveOutWrite(d_h_waveout, lp_wave_hdr, sizeof(WAVEHDR)); + if (w_result != 0) { 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; + fprintf(stderr, "Specified device handle is invalid.\n"); + break; case MMSYSERR_NODRIVER: - fprintf(stderr, " No device driver is present.\n"); - break; + fprintf(stderr, " No device driver is present.\n"); + break; case MMSYSERR_NOMEM: - fprintf(stderr, " Unable to allocate or lock memory.\n"); - break; + 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; + 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); + fprintf(stderr, "Unknown error %i\n", w_result); } waveOutUnprepareHeader(d_h_waveout, lp_wave_hdr, sizeof(WAVEHDR)); return -1; - } - return 0; } - } /* namespace audio */ + return 0; +} +} /* namespace audio */ } /* namespace gr */ diff --git a/gr-audio/lib/windows/windows_sink.h b/gr-audio/lib/windows/windows_sink.h index de905c68fd..fcfae94dcb 100644 --- a/gr-audio/lib/windows/windows_sink.h +++ b/gr-audio/lib/windows/windows_sink.h @@ -24,7 +24,7 @@ #define INCLUDED_AUDIO_WINDOWS_SINK_H #define WIN32_LEAN_AND_MEAN -#define NOMINMAX // stops windef.h defining max/min under cygwin +#define NOMINMAX // stops windef.h defining max/min under cygwin #include <windows.h> #include <mmsystem.h> @@ -33,48 +33,46 @@ #include <string> namespace gr { - namespace audio { +namespace audio { - /*! - * \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 windows_sink : public sink - { - int d_sampling_freq; - std::string d_device_name; - int d_fd; - LPWAVEHDR *d_buffers; - DWORD d_chunk_size; - DWORD d_buffer_size; - bool d_ok_to_block; - HWAVEOUT d_h_waveout; - HANDLE d_wave_write_event; - WAVEFORMATEX wave_format; +/*! + * \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 windows_sink : public sink +{ + int d_sampling_freq; + std::string d_device_name; + int d_fd; + LPWAVEHDR* d_buffers; + DWORD d_chunk_size; + DWORD d_buffer_size; + bool d_ok_to_block; + HWAVEOUT d_h_waveout; + HANDLE d_wave_write_event; + WAVEFORMATEX wave_format; - protected: - int string_to_int(const std::string & s); - int open_waveout_device(void); - int write_waveout(LPWAVEHDR lp_wave_hdr); - MMRESULT is_format_supported(LPWAVEFORMATEX pwfx, UINT uDeviceID); - bool is_number(const std::string& s); - UINT find_device(std::string szDeviceName); +protected: + int string_to_int(const std::string& s); + int open_waveout_device(void); + int write_waveout(LPWAVEHDR lp_wave_hdr); + MMRESULT is_format_supported(LPWAVEFORMATEX pwfx, UINT uDeviceID); + bool is_number(const std::string& s); + UINT find_device(std::string szDeviceName); - public: - windows_sink(int sampling_freq, - const std::string device_name, - bool ok_to_block); - ~windows_sink(); +public: + windows_sink(int sampling_freq, const std::string device_name, bool ok_to_block); + ~windows_sink(); - int work(int noutput_items, - gr_vector_const_void_star & input_items, - gr_vector_void_star & output_items); - }; + int work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; - } /* namespace audio */ +} /* namespace audio */ } /* namespace gr */ #endif /* INCLUDED_AUDIO_WINDOWS_SINK_H */ diff --git a/gr-audio/lib/windows/windows_source.cc b/gr-audio/lib/windows/windows_source.cc index b5550a59c2..5389a2383b 100644 --- a/gr-audio/lib/windows/windows_source.cc +++ b/gr-audio/lib/windows/windows_source.cc @@ -40,297 +40,305 @@ namespace gr { - namespace audio { +namespace audio { - // Currently this audio source will only support a single channel input at 16-bits. So a stereo input will likely be turned into a mono by the wave mapper +// Currently this audio source will only support a single channel input at 16-bits. So a +// stereo input will likely be turned into a mono by the wave mapper - source::sptr - windows_source_fcn(int sampling_rate, - const std::string &device_name, - bool) - { - return source::sptr - (new windows_source(sampling_rate, device_name)); - } +source::sptr windows_source_fcn(int sampling_rate, const std::string& device_name, bool) +{ + return source::sptr(new windows_source(sampling_rate, device_name)); +} - static const double CHUNK_TIME = prefs::singleton()->get_double("audio_windows", "period_time", 0.1); // 100 ms (below 3ms distortion will likely occur regardless of number of buffers, will likely be a higher limit on slower machines) - static const int nPeriods = prefs::singleton()->get_long("audio_windows", "nperiods", 4); // 4 should be more than enough with a normal chunk time (2 will likely work as well)... at 3ms chunks 10 was enough on a fast machine - static const bool verbose = prefs::singleton()->get_bool("audio_windows", "verbose", false); - static const std::string default_device = prefs::singleton()->get_string("audio_windows", "standard_input_device", "default"); +static const double CHUNK_TIME = prefs::singleton()->get_double( + "audio_windows", + "period_time", + 0.1); // 100 ms (below 3ms distortion will likely occur regardless of number of + // buffers, will likely be a higher limit on slower machines) +static const int nPeriods = prefs::singleton()->get_long( + "audio_windows", + "nperiods", + 4); // 4 should be more than enough with a normal chunk time (2 will likely work as + // well)... at 3ms chunks 10 was enough on a fast machine +static const bool verbose = + prefs::singleton()->get_bool("audio_windows", "verbose", false); +static const std::string default_device = + prefs::singleton()->get_string("audio_windows", "standard_input_device", "default"); - static std::string - default_device_name() - { - return (default_device == "default" ? "WAVE_MAPPER" : default_device); - } +static std::string default_device_name() +{ + return (default_device == "default" ? "WAVE_MAPPER" : default_device); +} - windows_source::windows_source(int sampling_freq, - const std::string device_name) - : sync_block("audio_windows_source", - io_signature::make(0, 0, 0), - io_signature::make(1, 1, sizeof(float))), - d_sampling_freq(sampling_freq), - d_device_name(device_name.empty() ? default_device_name() : device_name), - d_fd(-1), lp_buffers(0), d_chunk_size(0) - { - /* Initialize the WAVEFORMATEX for 16-bit, mono */ - wave_format.wFormatTag = WAVE_FORMAT_PCM; - wave_format.nChannels = 1; // changing this will require adjustments to the work routine. - wave_format.wBitsPerSample = 16; // changing this will necessitate changing buffer type from short. - wave_format.nSamplesPerSec = d_sampling_freq; // defined by flowgraph settings, but note that the microphone will likely have a native sample rate - // that the audio system may upsample to you desired rate, so check where the cutoff ends up or check your control panel - wave_format.nBlockAlign = - wave_format.nChannels * (wave_format.wBitsPerSample / 8); - wave_format.nAvgBytesPerSec = - wave_format.nSamplesPerSec * wave_format.nBlockAlign; - wave_format.cbSize = 0; +windows_source::windows_source(int sampling_freq, const std::string device_name) + : sync_block("audio_windows_source", + io_signature::make(0, 0, 0), + io_signature::make(1, 1, sizeof(float))), + d_sampling_freq(sampling_freq), + d_device_name(device_name.empty() ? default_device_name() : device_name), + d_fd(-1), + lp_buffers(0), + d_chunk_size(0) +{ + /* Initialize the WAVEFORMATEX for 16-bit, mono */ + wave_format.wFormatTag = WAVE_FORMAT_PCM; + wave_format.nChannels = + 1; // changing this will require adjustments to the work routine. + wave_format.wBitsPerSample = + 16; // changing this will necessitate changing buffer type from short. + wave_format.nSamplesPerSec = + d_sampling_freq; // defined by flowgraph settings, but note that the microphone + // will likely have a native sample rate that the audio system + // may upsample to you desired rate, so check where the cutoff + // ends up or check your control panel + wave_format.nBlockAlign = wave_format.nChannels * (wave_format.wBitsPerSample / 8); + wave_format.nAvgBytesPerSec = wave_format.nSamplesPerSec * wave_format.nBlockAlign; + wave_format.cbSize = 0; - d_chunk_size = (int)(d_sampling_freq * CHUNK_TIME); // Samples per chunk - set_output_multiple(d_chunk_size); - d_buffer_size = d_chunk_size * wave_format.nChannels * (wave_format.wBitsPerSample / 8); // room for 16-bit audio on one channel. + d_chunk_size = (int)(d_sampling_freq * CHUNK_TIME); // Samples per chunk + set_output_multiple(d_chunk_size); + d_buffer_size = + d_chunk_size * wave_format.nChannels * + (wave_format.wBitsPerSample / 8); // room for 16-bit audio on one channel. - if (open_wavein_device() < 0) { - perror("audio_windows_source:open_wavein_device() failed\n"); - throw - std::runtime_error("audio_windows_source:open_wavein_device() failed"); - } - else if (verbose) { - GR_LOG_INFO(d_logger, "Opened windows wavein device"); - } - lp_buffers = new LPWAVEHDR[nPeriods]; - for (int i = 0; i < nPeriods; i++) - { - lp_buffers[i] = new WAVEHDR; - LPWAVEHDR lp_buffer = lp_buffers[i]; - lp_buffer->dwLoops = 0L; - lp_buffer->dwFlags = 0; - lp_buffer->dwBufferLength = d_buffer_size; - lp_buffer->lpData = new CHAR[d_buffer_size]; - MMRESULT w_result = - waveInPrepareHeader(d_h_wavein, lp_buffer, sizeof(WAVEHDR)); - if (w_result != 0) { - perror("audio_windows_source: Failed to waveInPrepareHeader"); - throw - std::runtime_error("audio_windows_source:open_wavein_device() failed"); - } - waveInAddBuffer(d_h_wavein, lp_buffer, sizeof(WAVEHDR)); - } - waveInStart(d_h_wavein); - if (verbose) GR_LOG_INFO(d_logger, boost::format("Initialized %1% %2%ms audio buffers, total memory used: %3$0.2fkB") % (nPeriods) % (CHUNK_TIME * 1000) % ((d_buffer_size * nPeriods) / 1024.0)); - } + if (open_wavein_device() < 0) { + perror("audio_windows_source:open_wavein_device() failed\n"); + throw std::runtime_error("audio_windows_source:open_wavein_device() failed"); + } else if (verbose) { + GR_LOG_INFO(d_logger, "Opened windows wavein device"); + } + lp_buffers = new LPWAVEHDR[nPeriods]; + for (int i = 0; i < nPeriods; i++) { + lp_buffers[i] = new WAVEHDR; + LPWAVEHDR lp_buffer = lp_buffers[i]; + lp_buffer->dwLoops = 0L; + lp_buffer->dwFlags = 0; + lp_buffer->dwBufferLength = d_buffer_size; + lp_buffer->lpData = new CHAR[d_buffer_size]; + MMRESULT w_result = waveInPrepareHeader(d_h_wavein, lp_buffer, sizeof(WAVEHDR)); + if (w_result != 0) { + perror("audio_windows_source: Failed to waveInPrepareHeader"); + throw std::runtime_error("audio_windows_source:open_wavein_device() failed"); + } + waveInAddBuffer(d_h_wavein, lp_buffer, sizeof(WAVEHDR)); + } + waveInStart(d_h_wavein); + if (verbose) + GR_LOG_INFO( + d_logger, + boost::format( + "Initialized %1% %2%ms audio buffers, total memory used: %3$0.2fkB") % + (nPeriods) % (CHUNK_TIME * 1000) % ((d_buffer_size * nPeriods) / 1024.0)); +} - windows_source::~windows_source() - { - // stop playback and set all buffers to DONE. - waveInReset(d_h_wavein); - // Now we can deallocate the buffers - for (int i = 0; i < nPeriods; i++) - { - if (lp_buffers[i]->dwFlags & (WHDR_DONE | WHDR_PREPARED)) { - waveInUnprepareHeader(d_h_wavein, lp_buffers[i], sizeof(WAVEHDR)); - } - else { +windows_source::~windows_source() +{ + // stop playback and set all buffers to DONE. + waveInReset(d_h_wavein); + // Now we can deallocate the buffers + for (int i = 0; i < nPeriods; i++) { + if (lp_buffers[i]->dwFlags & (WHDR_DONE | WHDR_PREPARED)) { + waveInUnprepareHeader(d_h_wavein, lp_buffers[i], sizeof(WAVEHDR)); + } else { + } + delete lp_buffers[i]->lpData; + } + /* Free the callback Event */ + waveInClose(d_h_wavein); + delete[] lp_buffers; +} - } - delete lp_buffers[i]->lpData; - } - /* Free the callback Event */ - waveInClose(d_h_wavein); - delete[] lp_buffers; - } +int windows_source::work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items) +{ + float *f0, *f1; + DWORD dw_items = 0; - int - windows_source::work(int noutput_items, - gr_vector_const_void_star & input_items, - gr_vector_void_star & output_items) - { - float *f0, *f1; - DWORD dw_items = 0; + while (!buffer_queue.empty()) { + // Pull the next incoming buffer off the queue + LPWAVEHDR next_header = buffer_queue.front(); - while (!buffer_queue.empty()) - { - // Pull the next incoming buffer off the queue - LPWAVEHDR next_header = buffer_queue.front(); + // Convert and calculate the number of samples (might not be full) + short* lp_buffer = (short*)next_header->lpData; + DWORD buffer_length = next_header->dwBytesRecorded / sizeof(short); - // Convert and calculate the number of samples (might not be full) - short *lp_buffer = (short *)next_header->lpData; - DWORD buffer_length = next_header->dwBytesRecorded / sizeof(short); + if (buffer_length + dw_items > noutput_items * output_items.size()) { + // There's not enough output buffer space to send the whole input buffer + // so don't try, just leave it in the queue + // or else we'd have to track how much we sent etc + // In theory we should never reach this code because the buffers should all be + // sized the same + return dw_items; + } else { + switch (output_items.size()) { + case 1: // mono output + f0 = (float*)output_items[0]; - if (buffer_length + dw_items > noutput_items * output_items.size()) { - // There's not enough output buffer space to send the whole input buffer - // so don't try, just leave it in the queue - // or else we'd have to track how much we sent etc - // In theory we should never reach this code because the buffers should all be - // sized the same - return dw_items; - } - else { - switch (output_items.size()) { - case 1: // mono output - f0 = (float*)output_items[0]; + for (int j = 0; j < buffer_length; j++) { + f0[dw_items + j] = (float)(lp_buffer[j]) / 32767.0; + } + dw_items += buffer_length; + break; + case 2: // stereo output (interleaved in the buffer) + f0 = (float*)output_items[0]; + f1 = (float*)output_items[1]; - for (int j = 0; j < buffer_length; j++) { - f0[dw_items + j] = (float)(lp_buffer[j]) / 32767.0; - } - dw_items += buffer_length; - break; - case 2: // stereo output (interleaved in the buffer) - f0 = (float*)output_items[0]; - f1 = (float*)output_items[1]; + for (int j = 0; j < buffer_length / 2; j++) { + f0[dw_items + j] = (float)(lp_buffer[2 * j + 0]) / 32767.0; + f1[dw_items + j] = (float)(lp_buffer[2 * j + 1]) / 32767.0; + } + dw_items += buffer_length / 2; + } + buffer_queue.pop(); - for (int j = 0; j < buffer_length / 2; j++) { - f0[dw_items + j] = (float)(lp_buffer[2 * j + 0]) / 32767.0; - f1[dw_items + j] = (float)(lp_buffer[2 * j + 1]) / 32767.0; - } - dw_items += buffer_length / 2; - } - buffer_queue.pop(); + // Recycle the buffer + next_header->dwFlags = 0; + waveInPrepareHeader(d_h_wavein, next_header, sizeof(WAVEHDR)); + waveInAddBuffer(d_h_wavein, next_header, sizeof(WAVEHDR)); + } + } + return dw_items; +} - // Recycle the buffer - next_header->dwFlags = 0; - waveInPrepareHeader(d_h_wavein, next_header, sizeof(WAVEHDR)); - waveInAddBuffer(d_h_wavein, next_header, sizeof(WAVEHDR)); - } - } - return dw_items; - } +int windows_source::string_to_int(const std::string& s) +{ + int i; + std::istringstream(s) >> i; + return i; +} - int - windows_source::string_to_int(const std::string & s) - { - int i; - std::istringstream(s) >> i; - return i; - } +MMRESULT windows_source::is_format_supported(LPWAVEFORMATEX pwfx, UINT uDeviceID) +{ + return (waveInOpen(NULL, // ptr can be NULL for query + uDeviceID, // the device identifier + pwfx, // defines requested format + NULL, // no callback + NULL, // no instance data + WAVE_FORMAT_QUERY)); // query only, do not open device +} - MMRESULT windows_source::is_format_supported(LPWAVEFORMATEX pwfx, UINT uDeviceID) - { - return (waveInOpen( - NULL, // ptr can be NULL for query - uDeviceID, // the device identifier - pwfx, // defines requested format - NULL, // no callback - NULL, // no instance data - WAVE_FORMAT_QUERY)); // query only, do not open device - } +bool windows_source::is_number(const std::string& s) +{ + std::string::const_iterator it = s.begin(); + while (it != s.end() && std::isdigit(*it)) + ++it; + return !s.empty() && it == s.end(); +} - bool windows_source::is_number(const std::string& s) - { - std::string::const_iterator it = s.begin(); - while (it != s.end() && std::isdigit(*it)) ++it; - return !s.empty() && it == s.end(); - } +UINT windows_source::find_device(std::string szDeviceName) +{ + UINT result = -1; + UINT num_devices = waveInGetNumDevs(); + if (num_devices > 0) { + // what the device name passed as a number? + if (is_number(szDeviceName)) { + // a number, so must be referencing a device ID (which incremement from zero) + UINT num = std::stoul(szDeviceName); + if (num < num_devices) { + result = num; + } else { + GR_LOG_INFO(d_logger, + boost::format("Warning: waveIn deviceID %d was not found, " + "defaulting to WAVE_MAPPER") % + num); + result = WAVE_MAPPER; + } - UINT windows_source::find_device(std::string szDeviceName) - { - UINT result = -1; - UINT num_devices = waveInGetNumDevs(); - if (num_devices > 0) { - // what the device name passed as a number? - if (is_number(szDeviceName)) - { - // a number, so must be referencing a device ID (which incremement from zero) - UINT num = std::stoul(szDeviceName); - if (num < num_devices) { - result = num; - } - else { - GR_LOG_INFO(d_logger, boost::format("Warning: waveIn deviceID %d was not found, defaulting to WAVE_MAPPER") % num); - result = WAVE_MAPPER; - } + } else { + // device name passed as string + for (UINT i = 0; i < num_devices; i++) { + WAVEINCAPS woc; + if (waveInGetDevCaps(i, &woc, sizeof(woc)) != MMSYSERR_NOERROR) { + perror("Error: Could not retrieve wave out device capabilities for " + "device"); + return -1; + } + if (woc.szPname == szDeviceName) { + result = i; + } + if (verbose) + GR_LOG_INFO(d_logger, + boost::format("WaveIn Device %d: %s") % i % woc.szPname); + } + if (result == -1) { + GR_LOG_INFO(d_logger, + boost::format("Warning: waveIn device '%s' was not found, " + "defaulting to WAVE_MAPPER") % + szDeviceName); + result = WAVE_MAPPER; + } + } + } else { + perror("Error: No WaveIn devices present or accessible"); + } + return result; +} - } - else { - // device name passed as string - for (UINT i = 0; i < num_devices; i++) - { - WAVEINCAPS woc; - if (waveInGetDevCaps(i, &woc, sizeof(woc)) != MMSYSERR_NOERROR) - { - perror("Error: Could not retrieve wave out device capabilities for device"); - return -1; - } - if (woc.szPname == szDeviceName) - { - result = i; - } - if (verbose) GR_LOG_INFO(d_logger, boost::format("WaveIn Device %d: %s") % i % woc.szPname); - } - if (result == -1) { - GR_LOG_INFO(d_logger, boost::format("Warning: waveIn device '%s' was not found, defaulting to WAVE_MAPPER") % szDeviceName); - result = WAVE_MAPPER; - } - } - } - else { - perror("Error: No WaveIn devices present or accessible"); - } - return result; - } +int windows_source::open_wavein_device(void) +{ + UINT u_device_id; + unsigned long result; - int - windows_source::open_wavein_device(void) - { - UINT u_device_id; - unsigned long result; + /** 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. + 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 + // The below could be uncommented to allow selection of different device handles + // however it is unclear what other devices are out there and how a user + // would know the device ID so at the moment we will ignore that setting + // and stick with WAVE_MAPPER + u_device_id = find_device(d_device_name); + if (verbose) + GR_LOG_INFO(d_logger, boost::format("waveIn Device ID: %1%") % (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. - 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 - // The below could be uncommented to allow selection of different device handles - // however it is unclear what other devices are out there and how a user - // would know the device ID so at the moment we will ignore that setting - // and stick with WAVE_MAPPER - u_device_id = find_device(d_device_name); - if (verbose) GR_LOG_INFO(d_logger, boost::format("waveIn Device ID: %1%") % (u_device_id)); + // Check if the sampling rate/bits/channels are good to go with the device. + MMRESULT supported = is_format_supported(&wave_format, u_device_id); + if (supported != MMSYSERR_NOERROR) { + char err_msg[50]; + waveInGetErrorText(supported, err_msg, 50); + GR_LOG_INFO(d_logger, boost::format("format error: %s") % err_msg); + perror("audio_windows_source: Requested audio format is not supported by device " + "driver"); + return -1; + } - // Check if the sampling rate/bits/channels are good to go with the device. - MMRESULT supported = is_format_supported(&wave_format, u_device_id); - if (supported != MMSYSERR_NOERROR) { - char err_msg[50]; - waveInGetErrorText(supported, err_msg, 50); - GR_LOG_INFO(d_logger, boost::format("format error: %s") % err_msg); - perror("audio_windows_source: Requested audio format is not supported by device driver"); - return -1; - } + // Open a waveform device for output using event callback. + result = waveInOpen(&d_h_wavein, + u_device_id, + &wave_format, + (DWORD_PTR)&read_wavein, + (DWORD_PTR)&buffer_queue, + CALLBACK_FUNCTION | WAVE_ALLOWSYNC); - // Open a waveform device for output using event callback. - result = waveInOpen(&d_h_wavein, u_device_id, - &wave_format, - (DWORD_PTR)&read_wavein, - (DWORD_PTR)&buffer_queue, CALLBACK_FUNCTION | WAVE_ALLOWSYNC); + if (result) { + perror("audio_windows_source: Failed to open waveform output device."); + return -1; + } + return 0; +} - if (result) { - perror("audio_windows_source: Failed to open waveform output device."); - return -1; - } - return 0; - } - - static void CALLBACK read_wavein( - HWAVEIN hwi, - UINT uMsg, - DWORD_PTR dwInstance, - DWORD_PTR dwParam1, - DWORD_PTR dwParam2 - ) - { - // Ignore WIM_OPEN and WIM_CLOSE messages - if (uMsg == WIM_DATA) { - if (!dwInstance) { - perror("audio_windows_source: callback function missing buffer queue"); - } - LPWAVEHDR lp_wave_hdr = (LPWAVEHDR)dwParam1; // The new audio data - boost::lockfree::spsc_queue<LPWAVEHDR> *q = (boost::lockfree::spsc_queue<LPWAVEHDR> *)dwInstance; // The buffer queue we assigned to the device to track the buffers that need to be sent - q->push(lp_wave_hdr); // Add the buffer to that queue - } - } - } /* namespace audio */ +static void CALLBACK read_wavein( + HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ + // Ignore WIM_OPEN and WIM_CLOSE messages + if (uMsg == WIM_DATA) { + if (!dwInstance) { + perror("audio_windows_source: callback function missing buffer queue"); + } + LPWAVEHDR lp_wave_hdr = (LPWAVEHDR)dwParam1; // The new audio data + boost::lockfree::spsc_queue<LPWAVEHDR>* q = + (boost::lockfree::spsc_queue<LPWAVEHDR>*) + dwInstance; // The buffer queue we assigned to the device to track the + // buffers that need to be sent + q->push(lp_wave_hdr); // Add the buffer to that queue + } +} +} /* namespace audio */ } /* namespace gr */ diff --git a/gr-audio/lib/windows/windows_source.h b/gr-audio/lib/windows/windows_source.h index edb89a73ce..cf858647aa 100644 --- a/gr-audio/lib/windows/windows_source.h +++ b/gr-audio/lib/windows/windows_source.h @@ -24,7 +24,7 @@ #define INCLUDED_AUDIO_WINDOWS_SOURCE_H #define WIN32_LEAN_AND_MEAN -#define NOMINMAX // stops windef.h defining max/min under cygwin +#define NOMINMAX // stops windef.h defining max/min under cygwin #include <windows.h> #include <mmsystem.h> @@ -35,53 +35,47 @@ #include <boost/lockfree/spsc_queue.hpp> namespace gr { - namespace audio { +namespace audio { - /*! - * \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 windows_source : public source - { - int d_sampling_freq; - std::string d_device_name; - int d_fd; - LPWAVEHDR *lp_buffers; - DWORD d_chunk_size; - DWORD d_buffer_size; - HWAVEIN d_h_wavein; - WAVEFORMATEX wave_format; +/*! + * \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 windows_source : public source +{ + int d_sampling_freq; + std::string d_device_name; + int d_fd; + LPWAVEHDR* lp_buffers; + DWORD d_chunk_size; + DWORD d_buffer_size; + HWAVEIN d_h_wavein; + WAVEFORMATEX wave_format; - protected: - int string_to_int(const std::string & s); - int open_wavein_device(void); - MMRESULT is_format_supported(LPWAVEFORMATEX pwfx, UINT uDeviceID); - bool is_number(const std::string& s); - UINT find_device(std::string szDeviceName); - boost::lockfree::spsc_queue<LPWAVEHDR> buffer_queue{ 100 }; +protected: + int string_to_int(const std::string& s); + int open_wavein_device(void); + MMRESULT is_format_supported(LPWAVEFORMATEX pwfx, UINT uDeviceID); + bool is_number(const std::string& s); + UINT find_device(std::string szDeviceName); + boost::lockfree::spsc_queue<LPWAVEHDR> buffer_queue{ 100 }; - public: - windows_source(int sampling_freq, - const std::string device_name = ""); - ~windows_source(); +public: + windows_source(int sampling_freq, const std::string device_name = ""); + ~windows_source(); - int work(int noutput_items, - gr_vector_const_void_star & input_items, - gr_vector_void_star & output_items); - }; + int work(int noutput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items); +}; - static void CALLBACK read_wavein( - HWAVEIN hwi, - UINT uMsg, - DWORD_PTR dwInstance, - DWORD_PTR dwParam1, - DWORD_PTR dwParam2 - ); +static void CALLBACK read_wavein( + HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2); - } /* namespace audio */ +} /* namespace audio */ } /* namespace gr */ #endif /* INCLUDED_AUDIO_WINDOWS_SOURCE_H */ |