1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "alsa_format"
18 /*#define LOG_NDEBUG 0*/
19 
20 #include "include/alsa_format.h"
21 
22 #include <tinyalsa/asoundlib.h>
23 
24 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
25 
26 /*
27  * Maps from bit position in pcm_mask to PCM_ format constants.
28  */
29 int8_t const pcm_format_value_map[50] = {
30     PCM_FORMAT_S8,          /* 00 - SNDRV_PCM_FORMAT_S8 */
31     PCM_FORMAT_INVALID,     /* 01 - SNDRV_PCM_FORMAT_U8 */
32     PCM_FORMAT_S16_LE,      /* 02 - SNDRV_PCM_FORMAT_S16_LE */
33     PCM_FORMAT_INVALID,     /* 03 - SNDRV_PCM_FORMAT_S16_BE */
34     PCM_FORMAT_INVALID,     /* 04 - SNDRV_PCM_FORMAT_U16_LE */
35     PCM_FORMAT_INVALID,     /* 05 - SNDRV_PCM_FORMAT_U16_BE */
36     PCM_FORMAT_S24_LE,      /* 06 - SNDRV_PCM_FORMAT_S24_LE */
37     PCM_FORMAT_INVALID,     /* 07 - SNDRV_PCM_FORMAT_S24_BE */
38     PCM_FORMAT_INVALID,     /* 08 - SNDRV_PCM_FORMAT_U24_LE */
39     PCM_FORMAT_INVALID,     /* 09 - SNDRV_PCM_FORMAT_U24_BE */
40     PCM_FORMAT_S32_LE,      /* 10 - SNDRV_PCM_FORMAT_S32_LE */
41     PCM_FORMAT_INVALID,     /* 11 - SNDRV_PCM_FORMAT_S32_BE */
42     PCM_FORMAT_INVALID,     /* 12 - SNDRV_PCM_FORMAT_U32_LE */
43     PCM_FORMAT_INVALID,     /* 13 - SNDRV_PCM_FORMAT_U32_BE */
44     PCM_FORMAT_INVALID,     /* 14 - SNDRV_PCM_FORMAT_FLOAT_LE */
45     PCM_FORMAT_INVALID,     /* 15 - SNDRV_PCM_FORMAT_FLOAT_BE */
46     PCM_FORMAT_INVALID,     /* 16 - SNDRV_PCM_FORMAT_FLOAT64_LE */
47     PCM_FORMAT_INVALID,     /* 17 - SNDRV_PCM_FORMAT_FLOAT64_BE */
48     PCM_FORMAT_INVALID,     /* 18 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE */
49     PCM_FORMAT_INVALID,     /* 19 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE */
50     PCM_FORMAT_INVALID,     /* 20 - SNDRV_PCM_FORMAT_MU_LAW */
51     PCM_FORMAT_INVALID,     /* 21 - SNDRV_PCM_FORMAT_A_LAW */
52     PCM_FORMAT_INVALID,     /* 22 - SNDRV_PCM_FORMAT_IMA_ADPCM */
53     PCM_FORMAT_INVALID,     /* 23 - SNDRV_PCM_FORMAT_MPEG */
54     PCM_FORMAT_INVALID,     /* 24 - SNDRV_PCM_FORMAT_GSM */
55     PCM_FORMAT_INVALID,     /* 25 -> 30 (not assigned) */
56     PCM_FORMAT_INVALID,
57     PCM_FORMAT_INVALID,
58     PCM_FORMAT_INVALID,
59     PCM_FORMAT_INVALID,
60     PCM_FORMAT_INVALID,
61     PCM_FORMAT_INVALID,     /* 31 - SNDRV_PCM_FORMAT_SPECIAL */
62     PCM_FORMAT_S24_3LE,     /* 32 - SNDRV_PCM_FORMAT_S24_3LE */
63     PCM_FORMAT_INVALID,     /* 33 - SNDRV_PCM_FORMAT_S24_3BE */
64     PCM_FORMAT_INVALID,     /* 34 - SNDRV_PCM_FORMAT_U24_3LE */
65     PCM_FORMAT_INVALID,     /* 35 - SNDRV_PCM_FORMAT_U24_3BE */
66     PCM_FORMAT_INVALID,     /* 36 - SNDRV_PCM_FORMAT_S20_3LE */
67     PCM_FORMAT_INVALID,     /* 37 - SNDRV_PCM_FORMAT_S20_3BE */
68     PCM_FORMAT_INVALID,     /* 38 - SNDRV_PCM_FORMAT_U20_3LE */
69     PCM_FORMAT_INVALID,     /* 39 - SNDRV_PCM_FORMAT_U20_3BE */
70     PCM_FORMAT_INVALID,     /* 40 - SNDRV_PCM_FORMAT_S18_3LE */
71     PCM_FORMAT_INVALID,     /* 41 - SNDRV_PCM_FORMAT_S18_3BE */
72     PCM_FORMAT_INVALID,     /* 42 - SNDRV_PCM_FORMAT_U18_3LE */
73     PCM_FORMAT_INVALID,     /* 43 - SNDRV_PCM_FORMAT_U18_3BE */
74     PCM_FORMAT_INVALID,     /* 44 - SNDRV_PCM_FORMAT_G723_24 */
75     PCM_FORMAT_INVALID,     /* 45 - SNDRV_PCM_FORMAT_G723_24_1B */
76     PCM_FORMAT_INVALID,     /* 46 - SNDRV_PCM_FORMAT_G723_40 */
77     PCM_FORMAT_INVALID,     /* 47 - SNDRV_PCM_FORMAT_G723_40_1B */
78     PCM_FORMAT_INVALID,     /* 48 - SNDRV_PCM_FORMAT_DSD_U8 */
79     PCM_FORMAT_INVALID      /* 49 - SNDRV_PCM_FORMAT_DSD_U16_LE */
80 };
81 
82 /*
83  * Scans the provided format mask and returns the first non-8 bit sample
84  * format supported by the devices.
85  */
get_pcm_format_for_mask(const struct pcm_mask * mask)86 enum pcm_format get_pcm_format_for_mask(const struct pcm_mask* mask)
87 {
88     int num_slots = ARRAY_SIZE(mask->bits);
89     int bits_per_slot = sizeof(mask->bits[0]) * 8;
90 
91     int table_size = ARRAY_SIZE(pcm_format_value_map);
92 
93     int slot_index, bit_index, table_index;
94     table_index = 0;
95     for (slot_index = 0; slot_index < num_slots && table_index < table_size; slot_index++) {
96         unsigned bit_mask = 1;
97         for (bit_index = 0; bit_index < bits_per_slot && table_index < table_size; bit_index++) {
98             /* skip any 8-bit formats */
99             if (table_index >= 2 && (mask->bits[slot_index] & bit_mask) != 0) {
100                 /* just return the first one which will be at least 16-bit */
101                 return (int)pcm_format_value_map[table_index];
102             }
103             bit_mask <<= 1;
104             table_index++;
105         }
106     }
107 
108     return PCM_FORMAT_INVALID;
109 }
110