blob: 3a078efbc6fb1930cf2535d3e0c2f64941ac7cf2
1 | #include <stdio.h> |
2 | #include <stdlib.h> |
3 | #include <string.h> |
4 | #include <fcntl.h> |
5 | #include <pthread.h> |
6 | #include <sys/ioctl.h> |
7 | #include <dlfcn.h> |
8 | #include <sys/mman.h> |
9 | #include <android/log.h> |
10 | #include <cutils/properties.h> |
11 | #include <unistd.h> |
12 | #include "../../amadec/adec-armdec-mgt.h" |
13 | |
14 | #define LOG_TAG "LPCMDEC" |
15 | #define printk(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) |
16 | #define audio_codec_print(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) |
17 | |
18 | |
19 | #define ASTREAM_DEV "/dev/uio0" |
20 | #define ASTREAM_ADDR "/sys/class/astream/astream-dev/uio0/maps/map0/addr" |
21 | #define ASTREAM_SIZE "/sys/class/astream/astream-dev/uio0/maps/map0/size" |
22 | #define ASTREAM_OFFSET "/sys/class/astream/astream-dev/uio0/maps/map0/offset" |
23 | |
24 | |
25 | |
26 | #define AIU_AIFIFO_CTRL 0x1580 |
27 | #define AIU_AIFIFO_STATUS 0x1581 |
28 | #define AIU_AIFIFO_GBIT 0x1582 |
29 | #define AIU_AIFIFO_CLB 0x1583 |
30 | #define AIU_MEM_AIFIFO_START_PTR 0x1584 |
31 | #define AIU_MEM_AIFIFO_CURR_PTR 0x1585 |
32 | #define AIU_MEM_AIFIFO_END_PTR 0x1586 |
33 | #define AIU_MEM_AIFIFO_BYTES_AVAIL 0x1587 |
34 | #define AIU_MEM_AIFIFO_CONTROL 0x1588 |
35 | #define AIU_MEM_AIFIFO_MAN_WP 0x1589 |
36 | #define AIU_MEM_AIFIFO_MAN_RP 0x158a |
37 | #define AIU_MEM_AIFIFO_LEVEL 0x158b |
38 | #define AIU_MEM_AIFIFO_BUF_CNTL 0x158c |
39 | #define AIU_MEM_AIFIFO_BUF_WRAP_COUNT 0x158d |
40 | #define AIU_MEM_AIFIFO2_BUF_WRAP_COUNT 0x158e |
41 | #define AIU_MEM_AIFIFO_MEM_CTL 0x158f |
42 | |
43 | volatile unsigned* reg_base = 0; |
44 | #define READ_MPEG_REG(reg) reg_base[reg-AIU_AIFIFO_CTRL] |
45 | #define WRITE_MPEG_REG(reg, val) reg_base[reg-AIU_AIFIFO_CTRL]=val |
46 | #define AIFIFO_READY (((READ_MPEG_REG(AIU_MEM_AIFIFO_CONTROL)&(1<<9)))) |
47 | #define min(x,y) ((x<y)?(x):(y)) |
48 | static int fd_uio = -1; |
49 | static volatile int exit_flag = 0; |
50 | static char *memmap = MAP_FAILED; |
51 | static int phys_size; |
52 | static unsigned enable_debug_print = 0; |
53 | |
54 | static unsigned long amsysfs_get_sysfs_ulong(const char *path) |
55 | { |
56 | int fd; |
57 | char bcmd[24] = ""; |
58 | unsigned long num = 0; |
59 | if ((fd = open(path, O_RDONLY)) >= 0) { |
60 | read(fd, bcmd, sizeof(bcmd)); |
61 | num = strtoul(bcmd, NULL, 0); |
62 | close(fd); |
63 | } else { |
64 | audio_codec_print("unable to open file %s", path); |
65 | } |
66 | return num; |
67 | } |
68 | static unsigned long get_num_infile(char *file) |
69 | { |
70 | return amsysfs_get_sysfs_ulong(file); |
71 | } |
72 | |
73 | static int uio_init() |
74 | { |
75 | int pagesize = getpagesize(); |
76 | int phys_start; |
77 | int phys_offset; |
78 | |
79 | |
80 | fd_uio = open(ASTREAM_DEV, O_RDWR); |
81 | if (fd_uio < 0) { |
82 | audio_codec_print("error open UIO 0\n"); |
83 | return -1; |
84 | } |
85 | phys_start = get_num_infile(ASTREAM_ADDR); |
86 | phys_size = get_num_infile(ASTREAM_SIZE); |
87 | phys_offset = get_num_infile(ASTREAM_OFFSET); |
88 | |
89 | audio_codec_print("add=%08x, size=%08x, offset=%08x\n", phys_start, phys_size, phys_offset); |
90 | |
91 | phys_size = (phys_size + pagesize - 1) & (~(pagesize - 1)); |
92 | memmap = mmap(NULL, phys_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_uio, 0 * pagesize); |
93 | |
94 | audio_codec_print("memmap = %x , pagesize = %x\n", memmap, pagesize); |
95 | if (memmap == MAP_FAILED) { |
96 | audio_codec_print("map /dev/uio0 failed\n"); |
97 | return -1; |
98 | } |
99 | if (phys_offset == 0) |
100 | phys_offset = (AIU_AIFIFO_CTRL*4)&(pagesize-1); |
101 | reg_base = memmap + phys_offset; |
102 | return 0; |
103 | } |
104 | |
105 | #define EXTRA_DATA_SIZE 128 |
106 | |
107 | static inline void waiting_bits(int bits) |
108 | { |
109 | int bytes; |
110 | bytes = READ_MPEG_REG(AIU_MEM_AIFIFO_BYTES_AVAIL); |
111 | while (bytes * 8 < bits && !exit_flag) { |
112 | printk("waiting_bits \n"); |
113 | usleep(1000); |
114 | bytes = READ_MPEG_REG(AIU_MEM_AIFIFO_BYTES_AVAIL); |
115 | } |
116 | } |
117 | static unsigned stream_in_offset = 0; |
118 | |
119 | int read_buffer(unsigned char *buffer, int size) |
120 | { |
121 | int bytes; |
122 | int len; |
123 | unsigned char *p = buffer; |
124 | int tmp; |
125 | int space; |
126 | int i; |
127 | int wait_times = 0, fifo_ready_wait = 0; |
128 | |
129 | int iii; |
130 | |
131 | iii = READ_MPEG_REG(AIU_MEM_AIFIFO_LEVEL) - EXTRA_DATA_SIZE; |
132 | while (size > iii && (!exit_flag)) { |
133 | iii = READ_MPEG_REG(AIU_MEM_AIFIFO_LEVEL) - EXTRA_DATA_SIZE; |
134 | |
135 | } |
136 | if (exit_flag) { |
137 | printk("exit flag set.exit dec\n"); |
138 | return 0; |
139 | } |
140 | //if(( size >= iii)) |
141 | // return 0; |
142 | |
143 | // adec_print("read_buffer start while iii= %d!!\n", iii); |
144 | for (len = 0; len < size;) { |
145 | space = (size - len); |
146 | bytes = READ_MPEG_REG(AIU_MEM_AIFIFO_BYTES_AVAIL); |
147 | //printk("read_buffer start AIU_MEM_AIFIFO_BYTES_AVAIL bytes= %d!!,exit %d \n", bytes,exit_flag); |
148 | if (exit_flag) { |
149 | printk("exit 1 \n"); |
150 | return 0; |
151 | } |
152 | wait_times = 0; |
153 | while (bytes == 0) { |
154 | waiting_bits((space > 128) ? 128 * 8 : (space * 8)); /*wait 32 bytes,if the space is less than 32 bytes,wait the space bits*/ |
155 | bytes = READ_MPEG_REG(AIU_MEM_AIFIFO_BYTES_AVAIL); |
156 | |
157 | // audio_codec_print("read_buffer while AIU_MEM_AIFIFO_BYTES_AVAIL = %d!!\n", bytes); |
158 | wait_times++; |
159 | if (wait_times > 10 || exit_flag) { |
160 | audio_codec_print("goto out!!\n"); |
161 | goto out; |
162 | } |
163 | } |
164 | bytes = min(space, bytes); |
165 | |
166 | //adec_print("read_buffer while bytes = %d!!\n", bytes); |
167 | for (i = 0; i < bytes; i++) { |
168 | if (exit_flag) { |
169 | printk("exit 2 \n"); |
170 | |
171 | return 0; |
172 | } |
173 | while (!AIFIFO_READY) { |
174 | fifo_ready_wait++; |
175 | usleep(1000); |
176 | printk("fifo not ready \n"); |
177 | if (fifo_ready_wait > 100) { |
178 | audio_codec_print("FATAL err,AIFIFO is not ready,check!!\n"); |
179 | return 0; |
180 | } |
181 | } |
182 | WRITE_MPEG_REG(AIU_AIFIFO_GBIT, 8); |
183 | tmp = READ_MPEG_REG(AIU_AIFIFO_GBIT); |
184 | //adec_print("read_buffer while tmp = %d!!\n", tmp); |
185 | |
186 | *p++ = tmp & 0xff; |
187 | fifo_ready_wait = 0; |
188 | |
189 | } |
190 | len += bytes; |
191 | } |
192 | out: |
193 | stream_in_offset += len; |
194 | return len; |
195 | } |
196 | int get_audiobuf_level() |
197 | { |
198 | int level = 0; |
199 | level = READ_MPEG_REG(AIU_MEM_AIFIFO_LEVEL) - EXTRA_DATA_SIZE; |
200 | if (level < 0) { |
201 | level = 0; |
202 | } |
203 | return level; |
204 | } |
205 | |
206 | |
207 | |
208 | #define pcm_buffer_size (1024*6) |
209 | #define bluray_pcm_size (1024*17) |
210 | |
211 | |
212 | static short table[256]; |
213 | static unsigned char pcm_buffer[bluray_pcm_size]; |
214 | |
215 | #define LOCAL inline |
216 | |
217 | #define SIGN_BIT (0x80) |
218 | #define QUANT_MASK (0xf) |
219 | #define NSEGS (8) |
220 | #define SEG_SHIFT (4) |
221 | #define SEG_MASK (0x70) |
222 | |
223 | #define BIAS (0x84) |
224 | |
225 | static int pcm_channels = 0; |
226 | static int pcm_samplerate = 0; |
227 | static int pcm_datewidth = 16; |
228 | static int pcm_bluray_header = 0; |
229 | static int pcm_bluray_size = 0; |
230 | |
231 | static struct audio_info *pcm_info; |
232 | |
233 | |
234 | #define Emphasis_Off 0 |
235 | #define Emphasis_On 1 |
236 | #define Quantization_Word_16bit 0 |
237 | #define Quantization_Word_Reserved 0xff |
238 | #define Audio_Sampling_44_1 1 |
239 | #define Audio_Sampling_48 2 |
240 | #define Audio_Sampling_Reserved 0xff |
241 | #define Audio_channel_Dual_Mono 0 |
242 | #define Audio_channel_Stero 1 |
243 | #define Audio_channel_Reserved 0xff |
244 | #define FramesPerAU 80 //according to spec of wifi display |
245 | #define Wifi_Display_Private_Header_Size 4 |
246 | |
247 | static int lpcm_header_parsed = 0; |
248 | static int parse_wifi_display_pcm_header(char *header, int *bps) |
249 | { |
250 | char number_of_frame_header, audio_emphasis, quant, sample, channel; |
251 | int frame_size = -1; |
252 | |
253 | //check sub id |
254 | if (header[0] == 0xa0) { |
255 | number_of_frame_header = header[1]; |
256 | audio_emphasis = header[2] & 1; |
257 | quant = header[3] >> 6; |
258 | sample = (header[3] >> 3) & 7; |
259 | channel = header[3] & 7; |
260 | |
261 | if (quant == Quantization_Word_16bit) { |
262 | *bps = 16; |
263 | } else { |
264 | printk("using reserved bps %d\n", *bps); |
265 | } |
266 | |
267 | if (sample == Audio_Sampling_44_1) { |
268 | pcm_samplerate = 44100; |
269 | } else if (sample == Audio_Sampling_48) { |
270 | pcm_samplerate = 48000; |
271 | } else { |
272 | printk("using reserved sample_rate %d\n", pcm_samplerate); |
273 | } |
274 | |
275 | if (channel == Audio_channel_Dual_Mono) { |
276 | pcm_channels = 1; //note: this is not sure |
277 | } else if (channel == Audio_channel_Stero) { |
278 | pcm_channels = 2; |
279 | } else { |
280 | printk("using reserved channel %d\n", pcm_channels); |
281 | } |
282 | |
283 | |
284 | frame_size = FramesPerAU * (*bps >> 3) * pcm_channels * number_of_frame_header; |
285 | |
286 | } else { |
287 | printk("unknown sub id\n"); |
288 | } |
289 | |
290 | return frame_size; |
291 | } |
292 | |
293 | int frame_size_check_flag = 0; |
294 | int frame_size_check = 0; |
295 | int jump_read_head_flag = 0; |
296 | int audio_dec_init(audio_decoder_operations_t *adp) |
297 | { |
298 | //printk("\n\n[%s]WFD LPCMDEC BuildDate--%s BuildTime--%s", __FUNCTION__, __DATE__, __TIME__); |
299 | char value[PROPERTY_VALUE_MAX]; |
300 | if (property_get("media.wfd.debug_dec", value, NULL) > 0) { |
301 | enable_debug_print = atoi(value); |
302 | } |
303 | stream_in_offset = 0; |
304 | exit_flag = 0; |
305 | int err; |
306 | err = uio_init(); |
307 | if (err) { |
308 | return -1; |
309 | } |
310 | printk("LPCM--- audio_dec_init done \n"); |
311 | return 0; |
312 | } |
313 | |
314 | |
315 | |
316 | |
317 | int audio_dec_decode(audio_decoder_operations_t *adec_ops, char *buf, int *outlen, char *inbuf, int inlen) |
318 | { |
319 | short *sample; |
320 | unsigned char *src; |
321 | int size, n, i, j, bps, wifi_display_drop_header = 0; |
322 | int sample_size; |
323 | unsigned int header; |
324 | int16_t *dst_int16_t; |
325 | int32_t *dst_int32_t; |
326 | int64_t *dst_int64_t; |
327 | uint16_t *dst_uint16_t; |
328 | uint32_t *dst_uint32_t; |
329 | int frame_size; |
330 | int skip_bytes = 0; |
331 | sample = (short *)buf; |
332 | src = pcm_buffer; |
333 | *outlen = 0; |
334 | |
335 | //check audio info for wifi display LPCM |
336 | size = read_buffer(pcm_buffer, Wifi_Display_Private_Header_Size); |
337 | resync: |
338 | /* |
339 | while (get_audiobuf_level()*1000 /(4*48000) > 300) { |
340 | printk("skip byte buffer level %d \n",get_audiobuf_level()); |
341 | read_buffer(pcm_buffer,1024); |
342 | } |
343 | */ |
344 | if (exit_flag == 1) { |
345 | printk("exit flag set.exit dec1\n"); |
346 | return 0; |
347 | } |
348 | if (enable_debug_print) { |
349 | printk("wifi display: pcm read size%d %x-%x-%x-%x\n", size, pcm_buffer[0], pcm_buffer[1], pcm_buffer[2], pcm_buffer[3]); |
350 | } |
351 | |
352 | if (pcm_buffer[0] == 0xa0) { |
353 | frame_size = parse_wifi_display_pcm_header(pcm_buffer, &bps); |
354 | if (frame_size > 1920) { |
355 | printk("frame size error ??? %d \n", frame_size); |
356 | goto skipbyte; |
357 | } |
358 | size = read_buffer(pcm_buffer, frame_size); |
359 | |
360 | } else { |
361 | skipbyte: |
362 | pcm_buffer[0] = pcm_buffer[1]; |
363 | pcm_buffer[1] = pcm_buffer[2]; |
364 | pcm_buffer[2] = pcm_buffer[3]; |
365 | read_buffer(&pcm_buffer[3], 1); |
366 | skip_bytes++; |
367 | goto resync; |
368 | frame_size = Wifi_Display_Private_Header_Size; //transimit error or something? |
369 | } |
370 | if (enable_debug_print) { |
371 | printk("wifi display: pcm read size%d %x-%x-%x-%x,skip bytes %d \n", size, pcm_buffer[0], pcm_buffer[1], pcm_buffer[2], pcm_buffer[3], skip_bytes); |
372 | } |
373 | |
374 | if (bps == 16) { |
375 | if (pcm_channels == 1) { |
376 | for (i = 0, j = 0; i < frame_size;) { |
377 | sample[j + 1] = sample[j] = (pcm_buffer[i] << 8) | pcm_buffer[i + 1]; |
378 | i += 2; |
379 | j += 2; |
380 | } |
381 | } else if (pcm_channels == 2) { |
382 | for (i = 0, j = 0; i < frame_size;) { |
383 | sample[j++] = (pcm_buffer[i] << 8) | pcm_buffer[i + 1]; |
384 | i += 2; |
385 | sample[j++] = (pcm_buffer[i] << 8) | pcm_buffer[i + 1]; |
386 | i += 2; |
387 | } |
388 | } |
389 | *outlen = frame_size; |
390 | |
391 | |
392 | /* |
393 | before output the audio frame,check the audio buffer level to see if we need drop pcm |
394 | |
395 | */ |
396 | unsigned audio_latency = get_audiobuf_level() * 1000 / (48000 * 4); |
397 | // printk("audio latency %d \n",audio_latency); |
398 | memcpy(inbuf, &audio_latency, sizeof(audio_latency)); |
399 | if (enable_debug_print) { |
400 | printk("sample rate %d, ch %d \n", pcm_samplerate, pcm_channels); |
401 | } |
402 | if (pcm_samplerate > 0 && pcm_channels > 0) { |
403 | adec_ops->channels = pcm_channels; |
404 | adec_ops->samplerate = pcm_samplerate; |
405 | } |
406 | return stream_in_offset; |
407 | } else { |
408 | printk("wifi display:unimplemented bps %d\n", bps); |
409 | } |
410 | |
411 | |
412 | return stream_in_offset; |
413 | } |
414 | |
415 | int audio_dec_release(audio_decoder_operations_t *adec_ops) |
416 | { |
417 | if (fd_uio >= 0) { |
418 | close(fd_uio); |
419 | } |
420 | fd_uio = -1; |
421 | if (memmap != NULL && memmap != MAP_FAILED) { |
422 | munmap(memmap, phys_size); |
423 | } |
424 | printk("audio_dec_release done \n"); |
425 | return 0; |
426 | } |
427 | |
428 | |
429 | int audio_dec_getinfo(audio_decoder_operations_t *adec_ops) |
430 | { |
431 | return 0; |
432 | } |
433 | void audio_set_exit_flag() |
434 | { |
435 | exit_flag = 1; |
436 | printk("adec decode exit flag set \n"); |
437 | } |
438 |