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#ifndef ARRAY_SIZE
35#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
36#endif
37
38/* The format_lookup is in order of SNDRV_PCM_FORMAT_##index and
39 * matches the grouping in sound/asound.h.  Note this is not
40 * continuous and has an empty gap from (25 - 30).
41 */
42static const char *format_lookup[] = {
43        /*[0] =*/ "S8",
44        "U8",
45        "S16_LE",
46        "S16_BE",
47        "U16_LE",
48        "U16_BE",
49        "S24_LE",
50        "S24_BE",
51        "U24_LE",
52        "U24_BE",
53        "S32_LE",
54        "S32_BE",
55        "U32_LE",
56        "U32_BE",
57        "FLOAT_LE",
58        "FLOAT_BE",
59        "FLOAT64_LE",
60        "FLOAT64_BE",
61        "IEC958_SUBFRAME_LE",
62        "IEC958_SUBFRAME_BE",
63        "MU_LAW",
64        "A_LAW",
65        "IMA_ADPCM",
66        "MPEG",
67        /*[24] =*/ "GSM",
68        [31] = "SPECIAL",
69        "S24_3LE",
70        "S24_3BE",
71        "U24_3LE",
72        "U24_3BE",
73        "S20_3LE",
74        "S20_3BE",
75        "U20_3LE",
76        "U20_3BE",
77        "S18_3LE",
78        "S18_3BE",
79        "U18_3LE",
80        /*[43] =*/ "U18_3BE",
81#if 0
82        /* recent additions, may not be present on local asound.h */
83        "G723_24",
84        "G723_24_1B",
85        "G723_40",
86        "G723_40_1B",
87        "DSD_U8",
88        "DSD_U16_LE",
89#endif
90};
91
92/* Returns a human readable name for the format associated with bit_index,
93 * NULL if bit_index is not known.
94 */
95inline const char *pcm_get_format_name(unsigned bit_index)
96{
97    return bit_index < ARRAY_SIZE(format_lookup) ? format_lookup[bit_index] : NULL;
98}
99
100int main(int argc, char **argv)
101{
102    unsigned int device = 0;
103    unsigned int card = 0;
104    int i;
105
106    if (argc < 3) {
107        fprintf(stderr, "Usage: %s -D card -d device\n", argv[0]);
108        return 1;
109    }
110
111    /* parse command line arguments */
112    argv += 1;
113    while (*argv) {
114        if (strcmp(*argv, "-D") == 0) {
115            argv++;
116            if (*argv)
117                card = atoi(*argv);
118        }
119        if (strcmp(*argv, "-d") == 0) {
120            argv++;
121            if (*argv)
122                device = atoi(*argv);
123        }
124        if (*argv)
125            argv++;
126    }
127
128    printf("Info for card %d, device %d:\n", card, device);
129
130    for (i = 0; i < 2; i++) {
131        struct pcm_params *params;
132        struct pcm_mask *m;
133        unsigned int min;
134        unsigned int max;
135
136        printf("\nPCM %s:\n", i == 0 ? "out" : "in");
137
138        params = pcm_params_get(card, device, i == 0 ? PCM_OUT : PCM_IN);
139        if (params == NULL) {
140            printf("Device does not exist.\n");
141            continue;
142        }
143
144        m = pcm_params_get_mask(params, PCM_PARAM_ACCESS);
145        if (m) { /* bitmask, refer to SNDRV_PCM_ACCESS_*, generally interleaved */
146            printf("      Access:\t%#08x\n", m->bits[0]);
147        }
148        m = pcm_params_get_mask(params, PCM_PARAM_FORMAT);
149        if (m) { /* bitmask, refer to: SNDRV_PCM_FORMAT_* */
150            unsigned j, k, count = 0;
151            const unsigned bitcount = sizeof(m->bits[0]) * 8;
152
153            /* we only check first two format masks (out of 8) - others are zero. */
154            printf("   Format[0]:\t%#08x\n", m->bits[0]);
155            printf("   Format[1]:\t%#08x\n", m->bits[1]);
156
157            /* print friendly format names, if they exist */
158            for (k = 0; k < 2; ++k) {
159                for (j = 0; j < bitcount; ++j) {
160                    const char *name;
161
162                    if (m->bits[k] & (1 << j)) {
163                        name = pcm_get_format_name(j + k*bitcount);
164                        if (name) {
165                            if (count++ == 0) {
166                                printf(" Format Name:\t");
167                            } else {
168                                printf (", ");
169                            }
170                            printf("%s", name);
171                        }
172                    }
173                }
174            }
175            if (count) {
176                printf("\n");
177            }
178        }
179        m = pcm_params_get_mask(params, PCM_PARAM_SUBFORMAT);
180        if (m) { /* bitmask, should be 1: SNDRV_PCM_SUBFORMAT_STD */
181            printf("   Subformat:\t%#08x\n", m->bits[0]);
182        }
183        min = pcm_params_get_min(params, PCM_PARAM_RATE);
184        max = pcm_params_get_max(params, PCM_PARAM_RATE);
185        printf("        Rate:\tmin=%uHz\tmax=%uHz\n", min, max);
186        min = pcm_params_get_min(params, PCM_PARAM_CHANNELS);
187        max = pcm_params_get_max(params, PCM_PARAM_CHANNELS);
188        printf("    Channels:\tmin=%u\t\tmax=%u\n", min, max);
189        min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS);
190        max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS);
191        printf(" Sample bits:\tmin=%u\t\tmax=%u\n", min, max);
192        min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE);
193        max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE);
194        printf(" Period size:\tmin=%u\t\tmax=%u\n", min, max);
195        min = pcm_params_get_min(params, PCM_PARAM_PERIODS);
196        max = pcm_params_get_max(params, PCM_PARAM_PERIODS);
197        printf("Period count:\tmin=%u\t\tmax=%u\n", min, max);
198
199        pcm_params_free(params);
200    }
201
202    return 0;
203}
204