Imported Upstream version 3.0.4
[debian/gnuradio] / gr-audio-alsa / src / gri_alsa.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2004 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <gri_alsa.h>
28 #include <algorithm>
29
30 static snd_pcm_access_t access_types[] = {
31   SND_PCM_ACCESS_MMAP_INTERLEAVED,
32   SND_PCM_ACCESS_MMAP_NONINTERLEAVED,
33   SND_PCM_ACCESS_MMAP_COMPLEX,
34   SND_PCM_ACCESS_RW_INTERLEAVED,
35   SND_PCM_ACCESS_RW_NONINTERLEAVED
36 };
37
38 static snd_pcm_format_t format_types[] = {
39   // SND_PCM_FORMAT_UNKNOWN,
40   SND_PCM_FORMAT_S8,
41   SND_PCM_FORMAT_U8,
42   SND_PCM_FORMAT_S16_LE,
43   SND_PCM_FORMAT_S16_BE,
44   SND_PCM_FORMAT_U16_LE,
45   SND_PCM_FORMAT_U16_BE,
46   SND_PCM_FORMAT_S24_LE,
47   SND_PCM_FORMAT_S24_BE,
48   SND_PCM_FORMAT_U24_LE,
49   SND_PCM_FORMAT_U24_BE,
50   SND_PCM_FORMAT_S32_LE,
51   SND_PCM_FORMAT_S32_BE,
52   SND_PCM_FORMAT_U32_LE,
53   SND_PCM_FORMAT_U32_BE,
54   SND_PCM_FORMAT_FLOAT_LE,
55   SND_PCM_FORMAT_FLOAT_BE,
56   SND_PCM_FORMAT_FLOAT64_LE,
57   SND_PCM_FORMAT_FLOAT64_BE,
58   SND_PCM_FORMAT_IEC958_SUBFRAME_LE,
59   SND_PCM_FORMAT_IEC958_SUBFRAME_BE,
60   SND_PCM_FORMAT_MU_LAW,
61   SND_PCM_FORMAT_A_LAW,
62   SND_PCM_FORMAT_IMA_ADPCM,
63   SND_PCM_FORMAT_MPEG,
64   SND_PCM_FORMAT_GSM,
65   SND_PCM_FORMAT_SPECIAL,
66   SND_PCM_FORMAT_S24_3LE,
67   SND_PCM_FORMAT_S24_3BE,
68   SND_PCM_FORMAT_U24_3LE,
69   SND_PCM_FORMAT_U24_3BE,
70   SND_PCM_FORMAT_S20_3LE,
71   SND_PCM_FORMAT_S20_3BE,
72   SND_PCM_FORMAT_U20_3LE,
73   SND_PCM_FORMAT_U20_3BE,
74   SND_PCM_FORMAT_S18_3LE,
75   SND_PCM_FORMAT_S18_3BE,
76   SND_PCM_FORMAT_U18_3LE,
77   SND_PCM_FORMAT_U18_3BE
78 };
79
80 static unsigned int test_rates[] = {
81   8000, 16000, 22050, 32000, 44100, 48000, 96000, 192000
82 };
83
84 #define NELEMS(x) (sizeof(x)/sizeof(x[0]))
85
86 void
87 gri_alsa_dump_hw_params (snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams, FILE *fp)
88 {
89   fprintf (fp, "PCM name: %s\n", snd_pcm_name (pcm));
90   
91   fprintf (fp, "Access types:\n");
92   for (unsigned i = 0; i < NELEMS (access_types); i++){
93     snd_pcm_access_t    at = access_types[i];
94     fprintf (fp, "    %-20s %s\n",
95              snd_pcm_access_name (at),
96              snd_pcm_hw_params_test_access (pcm, hwparams, at) == 0 ? "YES" : "NO");
97   }
98
99   fprintf (fp, "Formats:\n");
100   for (unsigned i = 0; i < NELEMS (format_types); i++){
101     snd_pcm_format_t    ft = format_types[i];
102     if (0)
103       fprintf (fp, "    %-20s %s\n",
104                snd_pcm_format_name (ft),
105                snd_pcm_hw_params_test_format (pcm, hwparams, ft) == 0 ? "YES" : "NO");
106     else {
107       if (snd_pcm_hw_params_test_format (pcm, hwparams, ft) == 0)
108         fprintf (fp, "    %-20s YES\n", snd_pcm_format_name (ft));
109     }
110   }
111
112   fprintf (fp, "Number of channels\n");
113   unsigned int min_chan, max_chan;
114   snd_pcm_hw_params_get_channels_min (hwparams, &min_chan);
115   snd_pcm_hw_params_get_channels_max (hwparams, &max_chan);
116   fprintf (fp, "    min channels: %d\n", min_chan);
117   fprintf (fp, "    max channels: %d\n", max_chan);
118   unsigned int chan;
119   max_chan = std::min (max_chan, 16U);  // truncate display...
120   for (chan = min_chan; chan <= max_chan; chan++){
121     fprintf (fp, "    %d channels\t%s\n", chan,
122              snd_pcm_hw_params_test_channels (pcm, hwparams, chan) == 0 ? "YES" : "NO");
123   }
124
125   fprintf (fp, "Sample Rates:\n");
126   unsigned int min_rate, max_rate;
127   int   min_dir, max_dir;
128
129   snd_pcm_hw_params_get_rate_min (hwparams, &min_rate, &min_dir);
130   snd_pcm_hw_params_get_rate_max (hwparams, &max_rate, &max_dir);
131   fprintf (fp, "    min rate: %7d (dir = %d)\n", min_rate, min_dir);
132   fprintf (fp, "    max rate: %7d (dir = %d)\n", max_rate, max_dir);
133   for (unsigned i = 0; i < NELEMS (test_rates); i++){
134     unsigned int rate = test_rates[i];
135     fprintf (fp, "    %6u  %s\n", rate,
136              snd_pcm_hw_params_test_rate (pcm, hwparams, rate, 0) == 0 ? "YES" : "NO");
137   }
138
139   fflush (fp);
140 }
141
142 bool
143 gri_alsa_pick_acceptable_format (snd_pcm_t *pcm,
144                                  snd_pcm_hw_params_t *hwparams,
145                                  snd_pcm_format_t acceptable_formats[],
146                                  unsigned nacceptable_formats,
147                                  snd_pcm_format_t *selected_format,
148                                  const char *error_msg_tag,
149                                  bool verbose)
150 {
151   int err;
152
153   // pick a format that we like...
154   for (unsigned i = 0; i < nacceptable_formats; i++){
155     if (snd_pcm_hw_params_test_format (pcm, hwparams,
156                                        acceptable_formats[i]) == 0){
157       err = snd_pcm_hw_params_set_format (pcm, hwparams, acceptable_formats[i]);
158       if (err < 0){
159         fprintf (stderr, "%s[%s]: failed to set format: %s\n",
160                  error_msg_tag, snd_pcm_name (pcm), snd_strerror (err));
161         return false;
162       }
163       if (verbose)
164         fprintf (stdout, "%s[%s]: using %s\n",
165                  error_msg_tag, snd_pcm_name (pcm),
166                  snd_pcm_format_name (acceptable_formats[i]));
167       *selected_format = acceptable_formats[i];
168       return true;
169     }
170   }
171   
172   fprintf (stderr, "%s[%s]: failed to find acceptable format",
173            error_msg_tag, snd_pcm_name (pcm));
174   return false;
175 }