summaryrefslogtreecommitdiff
path: root/audio_codec/liblpcm/lpcm_decode.c (plain)
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
43volatile 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))
48static int fd_uio = -1;
49static volatile int exit_flag = 0;
50static char *memmap = MAP_FAILED;
51static int phys_size;
52static unsigned enable_debug_print = 0;
53
54static 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}
68static unsigned long get_num_infile(char *file)
69{
70 return amsysfs_get_sysfs_ulong(file);
71}
72
73static 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
107static 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}
117static unsigned stream_in_offset = 0;
118
119int 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 }
192out:
193 stream_in_offset += len;
194 return len;
195}
196int 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
212static short table[256];
213static 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
225static int pcm_channels = 0;
226static int pcm_samplerate = 0;
227static int pcm_datewidth = 16;
228static int pcm_bluray_header = 0;
229static int pcm_bluray_size = 0;
230
231static 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
247static int lpcm_header_parsed = 0;
248static 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
293int frame_size_check_flag = 0;
294int frame_size_check = 0;
295int jump_read_head_flag = 0;
296int 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
317int 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);
337resync:
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 {
361skipbyte:
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
415int 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
429int audio_dec_getinfo(audio_decoder_operations_t *adec_ops)
430{
431 return 0;
432}
433void audio_set_exit_flag()
434{
435 exit_flag = 1;
436 printk("adec decode exit flag set \n");
437}
438