blob: 6eb4bd63c83ce71e9ae977bba0ceca198a86dcd3
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_utils" |
20 | #define LOG_NDEBUG 0 |
21 | |
22 | #include <errno.h> |
23 | #include <pthread.h> |
24 | #include <stdint.h> |
25 | #include <sys/time.h> |
26 | #include <stdlib.h> |
27 | #include <sys/stat.h> |
28 | #include <fcntl.h> |
29 | #include <time.h> |
30 | #include <utils/Timers.h> |
31 | #include <cutils/log.h> |
32 | #include <cutils/str_parms.h> |
33 | #include <cutils/properties.h> |
34 | #include <linux/ioctl.h> |
35 | #include <hardware/hardware.h> |
36 | #include <system/audio.h> |
37 | #include <hardware/audio.h> |
38 | #include <sound/asound.h> |
39 | #include <tinyalsa/asoundlib.h> |
40 | |
41 | #include "audio_hw_utils.h" |
42 | |
43 | #include "audio_hwsync.h" |
44 | #include "audio_hw.h" |
45 | #include <audio_utils/primitives.h> |
46 | |
47 | #ifdef LOG_NDEBUG_FUNCTION |
48 | #define LOGFUNC(...) ((void)0) |
49 | #else |
50 | #define LOGFUNC(...) (ALOGD(__VA_ARGS__)) |
51 | #endif |
52 | int get_sysfs_uint(const char *path, uint *value) |
53 | { |
54 | int fd; |
55 | char valstr[64]; |
56 | uint val = 0; |
57 | fd = open(path, O_RDONLY); |
58 | if (fd >= 0) { |
59 | memset(valstr, 0, 64); |
60 | read(fd, valstr, 64 - 1); |
61 | valstr[strlen(valstr)] = '\0'; |
62 | close(fd); |
63 | } else { |
64 | ALOGE("unable to open file %s\n", path); |
65 | return -1; |
66 | } |
67 | if (sscanf(valstr, "0x%x", &val) < 1) { |
68 | ALOGE("unable to get pts from: %s", valstr); |
69 | return -1; |
70 | } |
71 | *value = val; |
72 | return 0; |
73 | } |
74 | |
75 | int sysfs_set_sysfs_str(const char *path, const char *val) |
76 | { |
77 | int fd; |
78 | int bytes; |
79 | fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644); |
80 | if (fd >= 0) { |
81 | bytes = write(fd, val, strlen(val)); |
82 | close(fd); |
83 | return 0; |
84 | } else { |
85 | ALOGE("unable to open file %s,err: %s", path, strerror(errno)); |
86 | } |
87 | return -1; |
88 | } |
89 | |
90 | int get_sysfs_int (const char *path) |
91 | { |
92 | int val = 0; |
93 | int fd = open (path, O_RDONLY); |
94 | if (fd >= 0) |
95 | { |
96 | char bcmd[16]; |
97 | read (fd, bcmd, sizeof (bcmd)); |
98 | val = strtol (bcmd, NULL, 10); |
99 | close (fd); |
100 | } |
101 | else |
102 | { |
103 | LOGFUNC ("[%s]open %s node failed! return 0\n", path, __FUNCTION__); |
104 | } |
105 | return val; |
106 | } |
107 | int mystrstr(char *mystr,char *substr) { |
108 | int i=0; |
109 | int j=0; |
110 | int score = 0; |
111 | int substrlen = strlen(substr); |
112 | int ok = 0; |
113 | for (i =0;i < 1024 - substrlen;i++) { |
114 | for (j = 0;j < substrlen;j++) { |
115 | score += (substr[j] == mystr[i+j])?1:0; |
116 | } |
117 | if (score == substrlen) { |
118 | ok = 1; |
119 | break; |
120 | } |
121 | score = 0; |
122 | } |
123 | return ok; |
124 | } |
125 | void set_codec_type(int type) |
126 | { |
127 | char buf[16]; |
128 | int fd = open ("/sys/class/audiodsp/digital_codec", O_WRONLY); |
129 | |
130 | if (fd >= 0) { |
131 | memset(buf, 0, sizeof(buf)); |
132 | snprintf(buf, sizeof(buf), "%d", type); |
133 | |
134 | write(fd, buf, sizeof(buf)); |
135 | close(fd); |
136 | } |
137 | } |
138 | unsigned char codec_type_is_raw_data(int type) |
139 | { |
140 | switch (type) { |
141 | case TYPE_AC3: |
142 | case TYPE_EAC3: |
143 | case TYPE_TRUE_HD: |
144 | case TYPE_DTS: |
145 | case TYPE_DTS_HD: |
146 | case TYPE_DTS_HD_MA: |
147 | return 1; |
148 | default: |
149 | return 0; |
150 | } |
151 | } |
152 | |
153 | int get_codec_type(int format) |
154 | { |
155 | switch (format) { |
156 | case AUDIO_FORMAT_AC3: |
157 | return TYPE_AC3; |
158 | case AUDIO_FORMAT_E_AC3: |
159 | return TYPE_EAC3; |
160 | case AUDIO_FORMAT_DTS: |
161 | return TYPE_DTS; |
162 | case AUDIO_FORMAT_DTS_HD: |
163 | return TYPE_DTS_HD_MA; |
164 | case AUDIO_FORMAT_DOLBY_TRUEHD: |
165 | return TYPE_TRUE_HD; |
166 | case AUDIO_FORMAT_PCM: |
167 | return TYPE_PCM; |
168 | default: |
169 | return TYPE_PCM; |
170 | } |
171 | } |
172 | int getprop_bool (const char *path) |
173 | { |
174 | char buf[PROPERTY_VALUE_MAX]; |
175 | int ret = -1; |
176 | |
177 | ret = property_get (path, buf, NULL); |
178 | if (ret > 0) |
179 | { |
180 | if (strcasecmp (buf, "true") == 0 || strcmp (buf, "1") == 0) |
181 | return 1; |
182 | } |
183 | return 0; |
184 | } |
185 | |
186 | /* |
187 | convert audio formats to supported audio format |
188 | 8 ch goes to 32 bit |
189 | 2 ch can be 16 bit or 32 bit |
190 | @return input buffer used by alsa drivers to do the data write |
191 | */ |
192 | void *convert_audio_sample_for_output(int input_frames, int input_format, int input_ch, void *input_buf, int *out_size) |
193 | { |
194 | float lvol = 1.0; |
195 | int *out_buf = NULL; |
196 | short *p16 = (short*)input_buf; |
197 | int *p32 = (int*)input_buf; |
198 | int max_ch = input_ch; |
199 | int i; |
200 | //ALOGV("intput frame %d,input ch %d,buf ptr %p,vol %f\n", input_frames, input_ch, input_buf, lvol); |
201 | ALOG_ASSERT(input_buf); |
202 | if (input_ch > 2) |
203 | max_ch = 8; |
204 | //our HW need round the frames to 8 channels |
205 | out_buf = malloc(sizeof(int) * max_ch * input_frames); |
206 | if (out_buf == NULL) { |
207 | ALOGE("malloc buffer failed\n"); |
208 | return NULL; |
209 | } |
210 | switch (input_format) { |
211 | case AUDIO_FORMAT_PCM_16_BIT: |
212 | break; |
213 | case AUDIO_FORMAT_PCM_32_BIT: |
214 | break; |
215 | case AUDIO_FORMAT_PCM_8_24_BIT: |
216 | for (i = 0; i < input_frames * input_ch; i++) { |
217 | p32[i] = p32[i] << 8; |
218 | } |
219 | break; |
220 | case AUDIO_FORMAT_PCM_FLOAT: |
221 | memcpy_to_i16_from_float(out_buf, input_buf, input_frames * input_ch); |
222 | memcpy(input_buf, out_buf, sizeof(short)*input_frames * input_ch); |
223 | break; |
224 | } |
225 | //current all the data are in the input buffer |
226 | if (input_ch == 8) { |
227 | short *p16_temp; |
228 | int i, NumSamps; |
229 | int *p32_temp = out_buf; |
230 | float m_vol = lvol; |
231 | NumSamps = input_frames * input_ch; |
232 | //here to swap the channnl data here |
233 | //actual now:L,missing,R,RS,RRS,,LS,LRS,missing |
234 | //expect L,C,R,RS,RRS,LRS,LS,LFE (LFE comes from to center) |
235 | //actual audio data layout L,R,C,none/LFE,LRS,RRS,LS,RS |
236 | if (input_format == AUDIO_FORMAT_PCM_16_BIT) { |
237 | p16_temp = (short*)out_buf; |
238 | for (i = 0; i < NumSamps; i = i + 8) { |
239 | p16_temp[0 + i]/*L*/ = m_vol * p16[0 + i]; |
240 | p16_temp[1 + i]/*R*/ = m_vol * p16[1 + i]; |
241 | p16_temp[2 + i] /*LFE*/ = m_vol * p16[3 + i]; |
242 | p16_temp[3 + i] /*C*/ = m_vol * p16[2 + i]; |
243 | p16_temp[4 + i] /*LS*/ = m_vol * p16[6 + i]; |
244 | p16_temp[5 + i] /*RS*/ = m_vol * p16[7 + i]; |
245 | p16_temp[6 + i] /*LRS*/ = m_vol * p16[4 + i]; |
246 | p16_temp[7 + i]/*RRS*/ = m_vol * p16[5 + i]; |
247 | } |
248 | memcpy(p16, p16_temp, NumSamps * sizeof(short)); |
249 | for (i = 0; i < NumSamps; i++) { //suppose 16bit/8ch PCM |
250 | p32_temp[i] = p16[i] << 16; |
251 | } |
252 | } else { |
253 | p32_temp = out_buf; |
254 | for (i = 0; i < NumSamps; i = i + 8) { |
255 | p32_temp[0 + i]/*L*/ = m_vol * p32[0 + i]; |
256 | p32_temp[1 + i]/*R*/ = m_vol * p32[1 + i]; |
257 | p32_temp[2 + i] /*LFE*/ = m_vol * p32[3 + i]; |
258 | p32_temp[3 + i] /*C*/ = m_vol * p32[2 + i]; |
259 | p32_temp[4 + i] /*LS*/ = m_vol * p32[6 + i]; |
260 | p32_temp[5 + i] /*RS*/ = m_vol * p32[7 + i]; |
261 | p32_temp[6 + i] /*LRS*/ = m_vol * p32[4 + i]; |
262 | p32_temp[7 + i]/*RRS*/ = m_vol * p32[5 + i]; |
263 | } |
264 | |
265 | } |
266 | *out_size = NumSamps * sizeof(int); |
267 | |
268 | } else if (input_ch == 6) { |
269 | int j, NumSamps, real_samples; |
270 | short *p16_temp; |
271 | int *p32_temp = out_buf; |
272 | float m_vol = lvol; |
273 | NumSamps = input_frames * input_ch; |
274 | real_samples = NumSamps; |
275 | NumSamps = real_samples * 8 / 6; |
276 | //ALOGI("6ch to 8 ch real %d, to %d\n",real_samples,NumSamps); |
277 | if (input_format == AUDIO_FORMAT_PCM_16_BIT) { |
278 | p16_temp = (short*)out_buf; |
279 | for (i = 0; i < real_samples; i = i + 6) { |
280 | p16_temp[0 + i]/*L*/ = m_vol * p16[0 + i]; |
281 | p16_temp[1 + i]/*R*/ = m_vol * p16[1 + i]; |
282 | p16_temp[2 + i] /*LFE*/ = m_vol * p16[3 + i]; |
283 | p16_temp[3 + i] /*C*/ = m_vol * p16[2 + i]; |
284 | p16_temp[4 + i] /*LS*/ = m_vol * p16[4 + i]; |
285 | p16_temp[5 + i] /*RS*/ = m_vol * p16[5 + i]; |
286 | } |
287 | memcpy(p16, p16_temp, real_samples * sizeof(short)); |
288 | memset(p32_temp, 0, NumSamps * sizeof(int)); |
289 | for (i = 0, j = 0; j < NumSamps; i = i + 6, j = j + 8) { //suppose 16bit/8ch PCM |
290 | p32_temp[j + 0] = p16[i] << 16; |
291 | p32_temp[j + 1] = p16[i + 1] << 16; |
292 | p32_temp[j + 2] = p16[i + 2] << 16; |
293 | p32_temp[j + 3] = p16[i + 3] << 16; |
294 | p32_temp[j + 4] = p16[i + 4] << 16; |
295 | p32_temp[j + 5] = p16[i + 5] << 16; |
296 | } |
297 | } else { |
298 | p32_temp = out_buf; |
299 | memset(p32_temp, 0, NumSamps * sizeof(int)); |
300 | for (i = 0, j = 0; j < NumSamps; i = i + 6, j = j + 8) { //suppose 16bit/8ch PCM |
301 | p32_temp[j + 0] = m_vol * p32[i + 0]; |
302 | p32_temp[j + 1] = m_vol * p32[i + 1] ; |
303 | p32_temp[j + 2] = m_vol * p32[i + 2] ; |
304 | p32_temp[j + 3] = m_vol * p32[i + 3] ; |
305 | p32_temp[j + 4] = m_vol * p32[i + 4] ; |
306 | p32_temp[j + 5] = m_vol * p32[i + 5] ; |
307 | } |
308 | } |
309 | *out_size = NumSamps * sizeof(int); |
310 | } else { |
311 | //2ch with 24 bit/32/float audio |
312 | int *p32_temp = out_buf; |
313 | short *p16_temp = (short*)out_buf; |
314 | for (i = 0; i < input_frames; i++) { |
315 | p16_temp[2 * i + 0] = lvol * p16[2 * i + 0]; |
316 | p16_temp[2 * i + 1] = lvol * p16[2 * i + 1]; |
317 | } |
318 | *out_size = sizeof(short) * input_frames * input_ch; |
319 | } |
320 | return out_buf; |
321 | |
322 | } |
323 | |
324 |