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