summaryrefslogtreecommitdiff
path: root/gr-audio/lib/alsa/gri_alsa.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gr-audio/lib/alsa/gri_alsa.cc')
-rw-r--r--gr-audio/lib/alsa/gri_alsa.cc175
1 files changed, 175 insertions, 0 deletions
diff --git a/gr-audio/lib/alsa/gri_alsa.cc b/gr-audio/lib/alsa/gri_alsa.cc
new file mode 100644
index 000000000..d9fda0f7d
--- /dev/null
+++ b/gr-audio/lib/alsa/gri_alsa.cc
@@ -0,0 +1,175 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gri_alsa.h>
+#include <algorithm>
+
+static snd_pcm_access_t access_types[] = {
+ SND_PCM_ACCESS_MMAP_INTERLEAVED,
+ SND_PCM_ACCESS_MMAP_NONINTERLEAVED,
+ SND_PCM_ACCESS_MMAP_COMPLEX,
+ SND_PCM_ACCESS_RW_INTERLEAVED,
+ SND_PCM_ACCESS_RW_NONINTERLEAVED
+};
+
+static snd_pcm_format_t format_types[] = {
+ // SND_PCM_FORMAT_UNKNOWN,
+ SND_PCM_FORMAT_S8,
+ SND_PCM_FORMAT_U8,
+ SND_PCM_FORMAT_S16_LE,
+ SND_PCM_FORMAT_S16_BE,
+ SND_PCM_FORMAT_U16_LE,
+ SND_PCM_FORMAT_U16_BE,
+ SND_PCM_FORMAT_S24_LE,
+ SND_PCM_FORMAT_S24_BE,
+ SND_PCM_FORMAT_U24_LE,
+ SND_PCM_FORMAT_U24_BE,
+ SND_PCM_FORMAT_S32_LE,
+ SND_PCM_FORMAT_S32_BE,
+ SND_PCM_FORMAT_U32_LE,
+ SND_PCM_FORMAT_U32_BE,
+ SND_PCM_FORMAT_FLOAT_LE,
+ SND_PCM_FORMAT_FLOAT_BE,
+ SND_PCM_FORMAT_FLOAT64_LE,
+ SND_PCM_FORMAT_FLOAT64_BE,
+ SND_PCM_FORMAT_IEC958_SUBFRAME_LE,
+ SND_PCM_FORMAT_IEC958_SUBFRAME_BE,
+ SND_PCM_FORMAT_MU_LAW,
+ SND_PCM_FORMAT_A_LAW,
+ SND_PCM_FORMAT_IMA_ADPCM,
+ SND_PCM_FORMAT_MPEG,
+ SND_PCM_FORMAT_GSM,
+ SND_PCM_FORMAT_SPECIAL,
+ SND_PCM_FORMAT_S24_3LE,
+ SND_PCM_FORMAT_S24_3BE,
+ SND_PCM_FORMAT_U24_3LE,
+ SND_PCM_FORMAT_U24_3BE,
+ SND_PCM_FORMAT_S20_3LE,
+ SND_PCM_FORMAT_S20_3BE,
+ SND_PCM_FORMAT_U20_3LE,
+ SND_PCM_FORMAT_U20_3BE,
+ SND_PCM_FORMAT_S18_3LE,
+ SND_PCM_FORMAT_S18_3BE,
+ SND_PCM_FORMAT_U18_3LE,
+ SND_PCM_FORMAT_U18_3BE
+};
+
+static unsigned int test_rates[] = {
+ 8000, 16000, 22050, 32000, 44100, 48000, 96000, 192000
+};
+
+#define NELEMS(x) (sizeof(x)/sizeof(x[0]))
+
+void
+gri_alsa_dump_hw_params (snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams, FILE *fp)
+{
+ fprintf (fp, "PCM name: %s\n", snd_pcm_name (pcm));
+
+ fprintf (fp, "Access types:\n");
+ for (unsigned i = 0; i < NELEMS (access_types); i++){
+ snd_pcm_access_t at = access_types[i];
+ fprintf (fp, " %-20s %s\n",
+ snd_pcm_access_name (at),
+ snd_pcm_hw_params_test_access (pcm, hwparams, at) == 0 ? "YES" : "NO");
+ }
+
+ fprintf (fp, "Formats:\n");
+ for (unsigned i = 0; i < NELEMS (format_types); i++){
+ snd_pcm_format_t ft = format_types[i];
+ if (0)
+ fprintf (fp, " %-20s %s\n",
+ snd_pcm_format_name (ft),
+ snd_pcm_hw_params_test_format (pcm, hwparams, ft) == 0 ? "YES" : "NO");
+ else {
+ if (snd_pcm_hw_params_test_format (pcm, hwparams, ft) == 0)
+ fprintf (fp, " %-20s YES\n", snd_pcm_format_name (ft));
+ }
+ }
+
+ fprintf (fp, "Number of channels\n");
+ unsigned int min_chan, max_chan;
+ snd_pcm_hw_params_get_channels_min (hwparams, &min_chan);
+ snd_pcm_hw_params_get_channels_max (hwparams, &max_chan);
+ fprintf (fp, " min channels: %d\n", min_chan);
+ fprintf (fp, " max channels: %d\n", max_chan);
+ unsigned int chan;
+ max_chan = std::min (max_chan, 16U); // truncate display...
+ for (chan = min_chan; chan <= max_chan; chan++){
+ fprintf (fp, " %d channels\t%s\n", chan,
+ snd_pcm_hw_params_test_channels (pcm, hwparams, chan) == 0 ? "YES" : "NO");
+ }
+
+ fprintf (fp, "Sample Rates:\n");
+ unsigned int min_rate, max_rate;
+ int min_dir, max_dir;
+
+ snd_pcm_hw_params_get_rate_min (hwparams, &min_rate, &min_dir);
+ snd_pcm_hw_params_get_rate_max (hwparams, &max_rate, &max_dir);
+ fprintf (fp, " min rate: %7d (dir = %d)\n", min_rate, min_dir);
+ fprintf (fp, " max rate: %7d (dir = %d)\n", max_rate, max_dir);
+ for (unsigned i = 0; i < NELEMS (test_rates); i++){
+ unsigned int rate = test_rates[i];
+ fprintf (fp, " %6u %s\n", rate,
+ snd_pcm_hw_params_test_rate (pcm, hwparams, rate, 0) == 0 ? "YES" : "NO");
+ }
+
+ fflush (fp);
+}
+
+bool
+gri_alsa_pick_acceptable_format (snd_pcm_t *pcm,
+ snd_pcm_hw_params_t *hwparams,
+ snd_pcm_format_t acceptable_formats[],
+ unsigned nacceptable_formats,
+ snd_pcm_format_t *selected_format,
+ const char *error_msg_tag,
+ bool verbose)
+{
+ int err;
+
+ // pick a format that we like...
+ for (unsigned i = 0; i < nacceptable_formats; i++){
+ if (snd_pcm_hw_params_test_format (pcm, hwparams,
+ acceptable_formats[i]) == 0){
+ err = snd_pcm_hw_params_set_format (pcm, hwparams, acceptable_formats[i]);
+ if (err < 0){
+ fprintf (stderr, "%s[%s]: failed to set format: %s\n",
+ error_msg_tag, snd_pcm_name (pcm), snd_strerror (err));
+ return false;
+ }
+ if (verbose)
+ fprintf (stdout, "%s[%s]: using %s\n",
+ error_msg_tag, snd_pcm_name (pcm),
+ snd_pcm_format_name (acceptable_formats[i]));
+ *selected_format = acceptable_formats[i];
+ return true;
+ }
+ }
+
+ fprintf (stderr, "%s[%s]: failed to find acceptable format",
+ error_msg_tag, snd_pcm_name (pcm));
+ return false;
+}