blob: 81bb83fecf9e9cc2eb5d1689743d86701dc5c50c
1 | /* |
2 | * Copyright (C) 2010 Amlogic Corporation. |
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 | |
18 | |
19 | #define LOG_TAG "audio_hw_profile" |
20 | #include <errno.h> |
21 | #include <pthread.h> |
22 | #include <stdint.h> |
23 | #include <sys/time.h> |
24 | #include <stdlib.h> |
25 | #include <sys/stat.h> |
26 | #include <fcntl.h> |
27 | #include <math.h> |
28 | #include <cutils/log.h> |
29 | #include <cutils/str_parms.h> |
30 | #include <cutils/properties.h> |
31 | #include <hardware/hardware.h> |
32 | #include <system/audio.h> |
33 | #include <hardware/audio.h> |
34 | |
35 | #include "audio_hw_utils.h" |
36 | |
37 | /* |
38 | type : 0 -> playback, 1 -> capture |
39 | */ |
40 | #define MAX_CARD_NUM 2 |
41 | int get_external_card(int type) |
42 | { |
43 | int card_num = 1; // start num, 0 is defualt sound card. |
44 | struct stat card_stat; |
45 | char fpath[256]; |
46 | int ret; |
47 | while (card_num <= MAX_CARD_NUM) { |
48 | snprintf(fpath, sizeof(fpath), "/proc/asound/card%d", card_num); |
49 | ret = stat(fpath, &card_stat); |
50 | if (ret < 0) { |
51 | ret = -1; |
52 | } else { |
53 | snprintf(fpath, sizeof(fpath), "/dev/snd/pcmC%uD0%c", card_num, |
54 | type ? 'c' : 'p'); |
55 | ret = stat(fpath, &card_stat); |
56 | if (ret == 0) { |
57 | return card_num; |
58 | } |
59 | } |
60 | card_num++; |
61 | } |
62 | return ret; |
63 | } |
64 | |
65 | int |
66 | get_aml_card() |
67 | { |
68 | int card = -1, err = 0; |
69 | int fd = -1; |
70 | unsigned fileSize = 512; |
71 | char *read_buf = NULL, *pd = NULL; |
72 | static const char *const SOUND_CARDS_PATH = "/proc/asound/cards"; |
73 | fd = open(SOUND_CARDS_PATH, O_RDONLY); |
74 | if (fd < 0) { |
75 | ALOGE("ERROR: failed to open config file %s error: %d\n", |
76 | SOUND_CARDS_PATH, errno); |
77 | close(fd); |
78 | return -EINVAL; |
79 | } |
80 | |
81 | read_buf = (char *) malloc(fileSize); |
82 | if (!read_buf) { |
83 | ALOGE("Failed to malloc read_buf"); |
84 | close(fd); |
85 | return -ENOMEM; |
86 | } |
87 | memset(read_buf, 0x0, fileSize); |
88 | err = read(fd, read_buf, fileSize); |
89 | if (fd < 0) { |
90 | ALOGE("ERROR: failed to read config file %s error: %d\n", |
91 | SOUND_CARDS_PATH, errno); |
92 | close(fd); |
93 | return -EINVAL; |
94 | } |
95 | pd = strstr(read_buf, "AML"); |
96 | card = *(pd - 3) - '0'; |
97 | OUT: |
98 | free(read_buf); |
99 | close(fd); |
100 | return card; |
101 | } |
102 | |
103 | int |
104 | get_spdif_port() |
105 | { |
106 | int port = -1, err = 0; |
107 | int fd = -1; |
108 | unsigned fileSize = 512; |
109 | char *read_buf = NULL, *pd = NULL; |
110 | static const char *const SOUND_PCM_PATH = "/proc/asound/pcm"; |
111 | fd = open(SOUND_PCM_PATH, O_RDONLY); |
112 | if (fd < 0) { |
113 | ALOGE("ERROR: failed to open config file %s error: %d\n", |
114 | SOUND_PCM_PATH, errno); |
115 | close(fd); |
116 | return -EINVAL; |
117 | } |
118 | read_buf = (char *) malloc(fileSize); |
119 | if (!read_buf) { |
120 | ALOGE("Failed to malloc read_buf"); |
121 | close(fd); |
122 | return -ENOMEM; |
123 | } |
124 | memset(read_buf, 0x0, fileSize); |
125 | err = read(fd, read_buf, fileSize); |
126 | if (fd < 0) { |
127 | ALOGE("ERROR: failed to read config file %s error: %d\n", |
128 | SOUND_PCM_PATH, errno); |
129 | close(fd); |
130 | return -EINVAL; |
131 | } |
132 | pd = strstr(read_buf, "SPDIF"); |
133 | port = *(pd - 3) - '0'; |
134 | OUT: |
135 | free(read_buf); |
136 | close(fd); |
137 | return port; |
138 | } |
139 | |
140 | |
141 | /* |
142 | CodingType MaxChannels SamplingFreq SampleSize |
143 | PCM, 2 ch, 32/44.1/48/88.2/96/176.4/192 kHz, 16/20/24 bit |
144 | PCM, 8 ch, 32/44.1/48/88.2/96/176.4/192 kHz, 16/20/24 bit |
145 | AC-3, 8 ch, 32/44.1/48 kHz, bit |
146 | DTS, 8 ch, 44.1/48 kHz, bit |
147 | OneBitAudio, 2 ch, 44.1 kHz, bit |
148 | Dobly_Digital+, 8 ch, 44.1/48 kHz, 16 bit |
149 | DTS-HD, 8 ch, 44.1/48/88.2/96/176.4/192 kHz, 16 bit |
150 | MAT, 8 ch, 32/44.1/48/88.2/96/176.4/192 kHz, 16 bit |
151 | */ |
152 | char* get_hdmi_sink_cap(const char *keys,audio_format_t format) |
153 | { |
154 | int i = 0; |
155 | char * infobuf = NULL; |
156 | int channel = 0; |
157 | int dgraw = 0; |
158 | int fd = -1; |
159 | int size = 0; |
160 | char *aud_cap = NULL; |
161 | infobuf = (char *)malloc(1024 * sizeof(char)); |
162 | if (infobuf == NULL) { |
163 | ALOGE("malloc buffer failed\n"); |
164 | goto fail; |
165 | } |
166 | aud_cap = (char*)malloc(1024); |
167 | if (aud_cap == NULL) { |
168 | ALOGE("malloc buffer failed\n"); |
169 | goto fail; |
170 | } |
171 | memset(aud_cap, 0, 1024); |
172 | memset(infobuf, 0, 1024); |
173 | fd = open("/sys/class/amhdmitx/amhdmitx0/aud_cap", O_RDONLY); |
174 | if (fd >= 0) { |
175 | int nread = read(fd, infobuf, 1024); |
176 | /* check the format cap */ |
177 | if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) { |
178 | size += sprintf(aud_cap, "sup_formats=%s", "AUDIO_FORMAT_PCM_16_BIT"); |
179 | if (mystrstr(infobuf, "Dobly_Digital+")) { |
180 | size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_E_AC3"); |
181 | } |
182 | if (mystrstr(infobuf, "AC-3")) { |
183 | size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_AC3"); |
184 | } |
185 | if (mystrstr(infobuf, "DTS-HD")) { |
186 | size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_DTS|AUDIO_FORMAT_DTS_HD"); |
187 | } else if (mystrstr(infobuf, "DTS")) { |
188 | size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_DTS"); |
189 | } |
190 | if (mystrstr(infobuf, "MAT")) { |
191 | size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_TRUEHD"); |
192 | } |
193 | } |
194 | /*check the channel cap */ |
195 | else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) { |
196 | /* take the 2ch suppported as default */ |
197 | size += sprintf(aud_cap, "sup_channels=%s", "AUDIO_CHANNEL_OUT_STEREO"); |
198 | if (mystrstr(infobuf, "PCM, 8 ch")) { |
199 | size += sprintf(aud_cap + size, "|%s", "AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_7POINT1"); |
200 | } else if (mystrstr(infobuf, "PCM, 6 ch")) { |
201 | size += sprintf(aud_cap + size, "|%s", "AUDIO_CHANNEL_OUT_5POINT1"); |
202 | } |
203 | } else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) { |
204 | /* take the 32/44.1/48 khz suppported as default */ |
205 | size += sprintf(aud_cap, "sup_sampling_rates=%s", "32000|44100|48000"); |
206 | if (mystrstr(infobuf, "88.2")) { |
207 | size += sprintf(aud_cap + size, "|%s", "88200"); |
208 | } |
209 | if (mystrstr(infobuf, "96")) { |
210 | size += sprintf(aud_cap + size, "|%s", "96000"); |
211 | } |
212 | if (mystrstr(infobuf, "176.4")) { |
213 | size += sprintf(aud_cap + size, "|%s", "176400"); |
214 | } |
215 | if (mystrstr(infobuf, "192") || (mystrstr(infobuf, "Dobly_Digital+") && |
216 | format == AUDIO_FORMAT_IEC61937)) { |
217 | size += sprintf(aud_cap + size, "|%s", "192000"); |
218 | } |
219 | } |
220 | } |
221 | if (infobuf) { |
222 | free(infobuf); |
223 | } |
224 | if (fd >= 0) { |
225 | close(fd); |
226 | } |
227 | return aud_cap; |
228 | fail: |
229 | if (aud_cap) { |
230 | free(aud_cap); |
231 | } |
232 | if (infobuf) { |
233 | free(infobuf); |
234 | } |
235 | return NULL; |
236 | } |
237 | char* get_hdmi_arc_cap(unsigned *ad, int maxsize, const char *keys) |
238 | { |
239 | int i = 0; |
240 | int channel = 0; |
241 | int dgraw = 0; |
242 | int fd = -1; |
243 | int size = 0; |
244 | int raw_support = 0; |
245 | int iec_added = 0; |
246 | char *aud_cap = NULL; |
247 | unsigned char format, ch, sr; |
248 | aud_cap = (char*)malloc(1024); |
249 | if (aud_cap == NULL) { |
250 | ALOGE("malloc buffer failed\n"); |
251 | goto fail; |
252 | } |
253 | memset(aud_cap, 0, 1024); |
254 | ALOGI("get_hdmi_arc_cap\n"); |
255 | /* check the format cap */ |
256 | if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) { |
257 | size += sprintf(aud_cap, "sup_formats=%s", "AUDIO_FORMAT_PCM_16_BIT"); |
258 | } |
259 | /*check the channel cap */ |
260 | else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) { |
261 | //ALOGI("check channels\n"); |
262 | /* take the 2ch suppported as default */ |
263 | size += sprintf(aud_cap, "sup_channels=%s", "AUDIO_CHANNEL_OUT_STEREO"); |
264 | } else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) { |
265 | /* take the 32/44.1/48 khz suppported as default */ |
266 | size += sprintf(aud_cap, "sup_sampling_rates=%s", "32000|44100|48000"); |
267 | //ALOGI("check sample rate\n"); |
268 | } |
269 | for (i = 0; i < maxsize; i++) { |
270 | if (ad[i] != 0) { |
271 | format = (ad[i] >> 19) & 0xf; |
272 | ch = (ad[i] >> 16) & 0x7; |
273 | sr = (ad[i] > 8) & 0xf; |
274 | ALOGI("ad %x,format %d,ch %d,sr %d\n", ad[i], format, ch, sr); |
275 | /* check the format cap */ |
276 | if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) { |
277 | //ALOGI("check format\n"); |
278 | if (format == 10) { |
279 | raw_support = 1; |
280 | size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_E_AC3"); |
281 | } |
282 | else if (format == 2) { |
283 | raw_support = 1; |
284 | size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_AC3"); |
285 | } |
286 | else if (format == 11) { |
287 | raw_support = 1; |
288 | size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_DTS|AUDIO_FORMAT_DTSHD"); |
289 | } else if (format == 7) { |
290 | raw_support = 1; |
291 | size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_DTS"); |
292 | } |
293 | else if (format == 12) { |
294 | raw_support = 1; |
295 | size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_TRUEHD"); |
296 | } |
297 | if (raw_support == 1 && iec_added == 0) { |
298 | size += sprintf(aud_cap + size, "|%s", "AUDIO_FORMAT_IEC61937"); |
299 | } |
300 | } |
301 | /*check the channel cap */ |
302 | else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) { |
303 | //ALOGI("check channels\n"); |
304 | if (/*format == 1 && */ch == 7) { |
305 | size += sprintf(aud_cap + size, "|%s", "AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_7POINT1"); |
306 | } else if (/*format == 1 && */ch == 5) { |
307 | size += sprintf(aud_cap + size, "|%s", "AUDIO_CHANNEL_OUT_5POINT1"); |
308 | } |
309 | } else if (strstr(keys, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) { |
310 | ALOGI("check sample rate\n"); |
311 | if (format == 1 && sr == 4) { |
312 | size += sprintf(aud_cap + size, "|%s", "88200"); |
313 | } |
314 | if (format == 1 && sr == 5) { |
315 | size += sprintf(aud_cap + size, "|%s", "96000"); |
316 | } |
317 | if (format == 1 && sr == 6) { |
318 | size += sprintf(aud_cap + size, "|%s", "176400"); |
319 | } |
320 | if (format == 1 && sr == 7) { |
321 | size += sprintf(aud_cap + size, "|%s", "192000"); |
322 | } |
323 | } |
324 | |
325 | } else { |
326 | format = 0; |
327 | ch = 0; |
328 | sr = 0; |
329 | } |
330 | } |
331 | return aud_cap; |
332 | fail: |
333 | if (aud_cap) { |
334 | free(aud_cap); |
335 | } |
336 | return NULL; |
337 | } |
338 | |
339 |