1 /* tinypcminfo.c
2 **
3 ** Copyright 2012, The Android Open Source Project
4 **
5 ** Redistribution and use in source and binary forms, with or without
6 ** modification, are permitted provided that the following conditions are met:
7 ** * Redistributions of source code must retain the above copyright
8 ** notice, this list of conditions and the following disclaimer.
9 ** * Redistributions in binary form must reproduce the above copyright
10 ** notice, this list of conditions and the following disclaimer in the
11 ** documentation and/or other materials provided with the distribution.
12 ** * Neither the name of The Android Open Source Project nor the names of
13 ** its contributors may be used to endorse or promote products derived
14 ** from this software without specific prior written permission.
15 **
16 ** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
17 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 ** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
20 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26 ** DAMAGE.
27 */
28
29 #include <tinyalsa/asoundlib.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #define OPTPARSE_IMPLEMENTATION
35 #include "optparse.h"
36
37 #ifndef ARRAY_SIZE
38 #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
39 #endif
40
41 /* The format_lookup is in order of SNDRV_PCM_FORMAT_##index and
42 * matches the grouping in sound/asound.h. Note this is not
43 * continuous and has an empty gap from (25 - 30).
44 */
45 static const char *format_lookup[] = {
46 /*[0] =*/ "S8",
47 "U8",
48 "S16_LE",
49 "S16_BE",
50 "U16_LE",
51 "U16_BE",
52 "S24_LE",
53 "S24_BE",
54 "U24_LE",
55 "U24_BE",
56 "S32_LE",
57 "S32_BE",
58 "U32_LE",
59 "U32_BE",
60 "FLOAT_LE",
61 "FLOAT_BE",
62 "FLOAT64_LE",
63 "FLOAT64_BE",
64 "IEC958_SUBFRAME_LE",
65 "IEC958_SUBFRAME_BE",
66 "MU_LAW",
67 "A_LAW",
68 "IMA_ADPCM",
69 "MPEG",
70 /*[24] =*/ "GSM",
71 [31] = "SPECIAL",
72 "S24_3LE",
73 "S24_3BE",
74 "U24_3LE",
75 "U24_3BE",
76 "S20_3LE",
77 "S20_3BE",
78 "U20_3LE",
79 "U20_3BE",
80 "S18_3LE",
81 "S18_3BE",
82 "U18_3LE",
83 /*[43] =*/ "U18_3BE",
84 #if 0
85 /* recent additions, may not be present on local asound.h */
86 "G723_24",
87 "G723_24_1B",
88 "G723_40",
89 "G723_40_1B",
90 "DSD_U8",
91 "DSD_U16_LE",
92 #endif
93 };
94
95 /* Returns a human readable name for the format associated with bit_index,
96 * NULL if bit_index is not known.
97 */
pcm_get_format_name(unsigned bit_index)98 static inline const char *pcm_get_format_name(unsigned bit_index)
99 {
100 return bit_index < ARRAY_SIZE(format_lookup) ? format_lookup[bit_index] : NULL;
101 }
102
main(int argc,char ** argv)103 int main(int argc, char **argv)
104 {
105 unsigned int device = 0;
106 unsigned int card = 0;
107 int i;
108 struct optparse opts;
109 struct optparse_long long_options[] = {
110 { "help", 'h', OPTPARSE_NONE },
111 { "card", 'D', OPTPARSE_REQUIRED },
112 { "device", 'd', OPTPARSE_REQUIRED },
113 { 0, 0, 0 }
114 };
115
116 (void)argc; /* silence -Wunused-parameter */
117 /* parse command line arguments */
118 optparse_init(&opts, argv);
119 while ((i = optparse_long(&opts, long_options, NULL)) != -1) {
120 switch (i) {
121 case 'D':
122 card = atoi(opts.optarg);
123 break;
124 case 'd':
125 device = atoi(opts.optarg);
126 break;
127 case 'h':
128 fprintf(stderr, "Usage: %s -D card -d device\n", argv[0]);
129 return 0;
130 case '?':
131 fprintf(stderr, "%s\n", opts.errmsg);
132 return EXIT_FAILURE;
133 }
134 }
135
136 printf("Info for card %u, device %u:\n", card, device);
137
138 for (i = 0; i < 2; i++) {
139 struct pcm_params *params;
140 const struct pcm_mask *m;
141 unsigned int min;
142 unsigned int max;
143
144 printf("\nPCM %s:\n", i == 0 ? "out" : "in");
145
146 params = pcm_params_get(card, device, i == 0 ? PCM_OUT : PCM_IN);
147 if (params == NULL) {
148 printf("Device does not exist.\n");
149 continue;
150 }
151
152 m = pcm_params_get_mask(params, PCM_PARAM_ACCESS);
153 if (m) { /* bitmask, refer to SNDRV_PCM_ACCESS_*, generally interleaved */
154 printf(" Access:\t%#08x\n", m->bits[0]);
155 }
156 m = pcm_params_get_mask(params, PCM_PARAM_FORMAT);
157 if (m) { /* bitmask, refer to: SNDRV_PCM_FORMAT_* */
158 unsigned j, k, count = 0;
159 const unsigned bitcount = sizeof(m->bits[0]) * 8;
160
161 /* we only check first two format masks (out of 8) - others are zero. */
162 printf(" Format[0]:\t%#08x\n", m->bits[0]);
163 printf(" Format[1]:\t%#08x\n", m->bits[1]);
164
165 /* print friendly format names, if they exist */
166 for (k = 0; k < 2; ++k) {
167 for (j = 0; j < bitcount; ++j) {
168 const char *name;
169
170 if (m->bits[k] & (1 << j)) {
171 name = pcm_get_format_name(j + k*bitcount);
172 if (name) {
173 if (count++ == 0) {
174 printf(" Format Name:\t");
175 } else {
176 printf (", ");
177 }
178 printf("%s", name);
179 }
180 }
181 }
182 }
183 if (count) {
184 printf("\n");
185 }
186 }
187 m = pcm_params_get_mask(params, PCM_PARAM_SUBFORMAT);
188 if (m) { /* bitmask, should be 1: SNDRV_PCM_SUBFORMAT_STD */
189 printf(" Subformat:\t%#08x\n", m->bits[0]);
190 }
191 min = pcm_params_get_min(params, PCM_PARAM_RATE);
192 max = pcm_params_get_max(params, PCM_PARAM_RATE);
193 printf(" Rate:\tmin=%uHz\tmax=%uHz\n", min, max);
194 min = pcm_params_get_min(params, PCM_PARAM_CHANNELS);
195 max = pcm_params_get_max(params, PCM_PARAM_CHANNELS);
196 printf(" Channels:\tmin=%u\t\tmax=%u\n", min, max);
197 min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS);
198 max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS);
199 printf(" Sample bits:\tmin=%u\t\tmax=%u\n", min, max);
200 min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE);
201 max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE);
202 printf(" Period size:\tmin=%u\t\tmax=%u\n", min, max);
203 min = pcm_params_get_min(params, PCM_PARAM_PERIODS);
204 max = pcm_params_get_max(params, PCM_PARAM_PERIODS);
205 printf("Period count:\tmin=%u\t\tmax=%u\n", min, max);
206
207 pcm_params_free(params);
208 }
209
210 return 0;
211 }
212