blob: c1faf4da0166040ce7926b3945d974fc6477982c
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 | |
9 | #include <adec-pts-mgt.h> |
10 | #include <adec_write.h> |
11 | #include <adec_omx_brige.h> |
12 | #include <Amsysfsutils.h> |
13 | #include <audio-dec.h> |
14 | #include <cutils/properties.h> |
15 | #include <amthreadpool.h> |
16 | #include "audiodsp_update_format.h" |
17 | |
18 | typedef struct { |
19 | int codec_id; |
20 | char name[64]; |
21 | } audio_lib_t; |
22 | |
23 | typedef int (*fn_pcm_output_init)(int sr, int ch); |
24 | typedef int (*fn_pcm_output_write)(char *buf, unsigned size); |
25 | typedef int (*fn_pcm_output_uninit)(); |
26 | typedef int (*fn_pcm_output_latency)(); |
27 | |
28 | |
29 | typedef void (*fn_audio_set_exit_flag)(); |
30 | |
31 | |
32 | static audio_lib_t wfd_audio_lib_list[] = { |
33 | {ACODEC_FMT_WIFIDISPLAY, "libpcm_wfd.so"}, |
34 | {ACODEC_FMT_AAC, "libaac_helix.so"}, |
35 | 0 |
36 | } ; |
37 | static audio_decoder_operations_t WFDAudioDecoder = { |
38 | "WFDDecoder", |
39 | AUDIO_ARM_DECODER, |
40 | 0, |
41 | }; |
42 | |
43 | static fn_pcm_output_init wfd_out_init = NULL; |
44 | static fn_pcm_output_write wfd_out_write = NULL; |
45 | static fn_pcm_output_uninit wfd_out_uninit = NULL; |
46 | static fn_pcm_output_latency wfd_out_latency = NULL; |
47 | |
48 | |
49 | static fn_audio_set_exit_flag wfd_adec_exit = NULL; |
50 | static void *dec_mLibHandle = NULL; |
51 | static void *out_mLibHandle = NULL; |
52 | static void *audio_wfd_decode_loop(void *args); |
53 | static void stop_wfd_decode_thread(aml_audio_dec_t *audec); |
54 | static int wfd_register_audio_lib(aml_audio_dec_t *audec) |
55 | { |
56 | int i; |
57 | int num; |
58 | audio_lib_t *f; |
59 | adec_print("wfd audec->format %d,audec->codec_id %x", audec->format, audec->codec_id); |
60 | num = ARRAY_SIZE(wfd_audio_lib_list); |
61 | audio_decoder_operations_t *adec_ops = audec->adec_ops; |
62 | for (i = 0; i < num; i++) { |
63 | f = &wfd_audio_lib_list[i]; |
64 | if (f->codec_id == audec->format) { |
65 | dec_mLibHandle = dlopen(wfd_audio_lib_list[i].name, RTLD_NOW); |
66 | if (dec_mLibHandle) { |
67 | adec_ops->init = dlsym(dec_mLibHandle, "audio_dec_init"); |
68 | adec_ops->decode = dlsym(dec_mLibHandle, "audio_dec_decode"); |
69 | adec_ops->release = dlsym(dec_mLibHandle, "audio_dec_release"); |
70 | adec_ops->getinfo = dlsym(dec_mLibHandle, "audio_dec_getinfo"); |
71 | wfd_adec_exit = dlsym(dec_mLibHandle, "audio_set_exit_flag"); |
72 | if (!adec_ops->init || !adec_ops->decode || !adec_ops->release || !adec_ops->getinfo || !wfd_adec_exit) { |
73 | adec_print("in %s,decode func not implemented %p %p %p %p \n", wfd_audio_lib_list[i].name, \ |
74 | adec_ops->init, adec_ops->decode, adec_ops->release, adec_ops->getinfo); |
75 | goto error; |
76 | } |
77 | } else { |
78 | adec_print("wfd cant find decoder lib\n"); |
79 | goto error; |
80 | } |
81 | return 0; |
82 | } |
83 | } |
84 | error: |
85 | if (dec_mLibHandle) { |
86 | dlclose(dec_mLibHandle); |
87 | } |
88 | dec_mLibHandle = NULL; |
89 | return -1; |
90 | } |
91 | static int wfd_register_output_lib(aml_audio_dec_t *audec) |
92 | { |
93 | out_mLibHandle = dlopen("libamadec_wfd_out.so", RTLD_NOW); |
94 | if (out_mLibHandle) { |
95 | wfd_out_init = dlsym(out_mLibHandle, "pcm_output_init"); |
96 | wfd_out_write = dlsym(out_mLibHandle, "pcm_output_write"); |
97 | wfd_out_uninit = dlsym(out_mLibHandle, "pcm_output_uninit"); |
98 | wfd_out_latency = dlsym(out_mLibHandle, "pcm_output_latency"); |
99 | |
100 | if (!wfd_out_init || !wfd_out_write || !wfd_out_uninit || !wfd_out_latency) { |
101 | adec_print("wfd load output lib api failed\n"); |
102 | goto error; |
103 | } |
104 | } else { |
105 | goto error; |
106 | } |
107 | return 0; |
108 | error: |
109 | if (out_mLibHandle) { |
110 | dlclose(out_mLibHandle); |
111 | } |
112 | out_mLibHandle = NULL; |
113 | return -1; |
114 | |
115 | |
116 | } |
117 | static void wfd_unregister_lib() |
118 | { |
119 | if (out_mLibHandle) { |
120 | dlclose(out_mLibHandle); |
121 | } |
122 | out_mLibHandle = NULL; |
123 | if (dec_mLibHandle) { |
124 | dlclose(dec_mLibHandle); |
125 | } |
126 | dec_mLibHandle = NULL; |
127 | } |
128 | extern int read_buffer(unsigned char *buffer, int size); |
129 | |
130 | |
131 | static int wfd_dec_pcm_read(dsp_operations_t *dsp_ops, char *buffer, int len) |
132 | { |
133 | return 0; |
134 | } |
135 | static unsigned long wfd_dec_get_pts(dsp_operations_t *dsp_ops) |
136 | { |
137 | unsigned long val, offset; |
138 | unsigned long pts; |
139 | int data_width, channels, samplerate; |
140 | unsigned long long frame_nums ; |
141 | unsigned long delay_pts; |
142 | samplerate = 48000; |
143 | aml_audio_dec_t *audec = (aml_audio_dec_t *)dsp_ops->audec; |
144 | offset = audec->decode_offset; |
145 | |
146 | if (dsp_ops->dsp_file_fd >= 0) { |
147 | ioctl(dsp_ops->dsp_file_fd, AMSTREAM_IOC_APTS_LOOKUP, &offset); |
148 | } else { |
149 | adec_print("====abuf have not open!\n", val); |
150 | } |
151 | pts = offset; |
152 | if (pts == 0) { |
153 | if (audec->last_valid_pts) { |
154 | pts = audec->last_valid_pts; |
155 | } |
156 | frame_nums = (audec->out_len_after_last_valid_pts * 8 / (16 * 2)); |
157 | adec_print("decode_offset:%d out_pcm:%d pts:%d \n", audec->decode_offset, audec->out_len_after_last_valid_pts, pts); |
158 | pts += (frame_nums * 90000 / samplerate); |
159 | return pts; |
160 | } |
161 | audec->last_valid_pts = pts; |
162 | audec->out_len_after_last_valid_pts = 0; |
163 | return pts; |
164 | } |
165 | |
166 | static unsigned long wfd_dec_get_pcrscr(dsp_operations_t *dsp_ops) |
167 | { |
168 | unsigned long val; |
169 | if (dsp_ops->dsp_file_fd < 0) { |
170 | adec_print("read error!! audiodsp have not opened\n"); |
171 | return -1; |
172 | } |
173 | ioctl(dsp_ops->dsp_file_fd, AMSTREAM_IOC_PCRSCR, &val); |
174 | return val; |
175 | } |
176 | unsigned long wfd_dec_set_pts(dsp_operations_t *dsp_ops, unsigned long apts) |
177 | { |
178 | if (dsp_ops->dsp_file_fd < 0) { |
179 | adec_print("armdec_set_apts err!\n"); |
180 | return -1; |
181 | } |
182 | ioctl(dsp_ops->dsp_file_fd, AMSTREAM_IOC_SET_APTS, &apts); |
183 | return 0; |
184 | } |
185 | static int wfd_dec_set_skip_bytes(dsp_operations_t* dsp_ops, unsigned int bytes) |
186 | { |
187 | return 0; |
188 | } |
189 | static int set_sysfs_int(const char *path, int val) |
190 | { |
191 | return amsysfs_set_sysfs_int(path, val); |
192 | } |
193 | |
194 | |
195 | static int wfd_audio_codec_release(aml_audio_dec_t *audec) |
196 | { |
197 | if (wfd_adec_exit) { |
198 | wfd_adec_exit(); |
199 | } |
200 | stop_wfd_decode_thread(audec); |
201 | if (wfd_out_uninit) { |
202 | wfd_out_uninit(); |
203 | } |
204 | audec->adec_ops->release(audec->adec_ops); |
205 | wfd_unregister_lib(); |
206 | adec_print("wfd audio_codec_release done\n"); |
207 | return 0; |
208 | } |
209 | |
210 | |
211 | static int get_first_apts_flag(dsp_operations_t *dsp_ops) |
212 | { |
213 | int val; |
214 | if (dsp_ops->dsp_file_fd < 0) { |
215 | adec_print("[%s %d]read error!! audiodsp have not opened\n", __FUNCTION__, __LINE__); |
216 | return -1; |
217 | } |
218 | ioctl(dsp_ops->dsp_file_fd, GET_FIRST_APTS_FLAG, &val); |
219 | return val; |
220 | } |
221 | |
222 | |
223 | /** |
224 | * \brief start audio dec when receive START command. |
225 | * \param audec pointer to audec |
226 | */ |
227 | static void start_adec(aml_audio_dec_t *audec) |
228 | { |
229 | int ret; |
230 | audio_out_operations_t *aout_ops = &audec->aout_ops; |
231 | dsp_operations_t *dsp_ops = &audec->adsp_ops; |
232 | unsigned long vpts, apts; |
233 | int times = 0; |
234 | char buf[32]; |
235 | apts = vpts = 0; |
236 | audec->no_first_apts = 0; |
237 | |
238 | if (audec->state == INITTED) { |
239 | audec->state = ACTIVE; |
240 | //get info from the audiodsp == can get from amstreamer |
241 | while ((!get_first_apts_flag(dsp_ops)) && (!audec->need_stop) && (!audec->no_first_apts)) { |
242 | adec_print("wait first pts checkin complete !"); |
243 | times++; |
244 | if (times >= 5) { |
245 | amsysfs_get_sysfs_str(TSYNC_VPTS, buf, sizeof(buf));// read vpts |
246 | if (sscanf(buf, "0x%lx", &vpts) < 1) { |
247 | adec_print("unable to get vpts from: %s", buf); |
248 | return; |
249 | } |
250 | // save vpts to apts |
251 | adec_print("## can't get first apts, save vpts to apts,vpts=%lx, \n", vpts); |
252 | sprintf(buf, "0x%lx", vpts); |
253 | amsysfs_set_sysfs_str(TSYNC_APTS, buf); |
254 | audec->no_first_apts = 1; |
255 | } |
256 | amthreadpool_thread_usleep(100000); |
257 | } |
258 | |
259 | /*start the the pts scr,...*/ |
260 | ret = adec_pts_start(audec); |
261 | if (audec->auto_mute) { |
262 | avsync_en(0); |
263 | adec_pts_pause(); |
264 | while ((!audec->need_stop) && track_switch_pts(audec)) { |
265 | amthreadpool_thread_usleep(1000); |
266 | } |
267 | avsync_en(1); |
268 | adec_pts_resume(); |
269 | audec->auto_mute = 0; |
270 | } |
271 | #ifdef OUT_USE_AUDIOTRACK |
272 | aout_ops->start(audec); |
273 | #endif |
274 | } |
275 | } |
276 | |
277 | /** |
278 | * \brief pause audio dec when receive PAUSE command. |
279 | * \param audec pointer to audec |
280 | */ |
281 | static void pause_adec(aml_audio_dec_t *audec) |
282 | { |
283 | audio_out_operations_t *aout_ops = &audec->aout_ops; |
284 | if (audec->state == ACTIVE) { |
285 | audec->state = PAUSED; |
286 | adec_pts_pause(); |
287 | #ifdef OUT_USE_AUDIOTRACK |
288 | aout_ops->pause(audec); |
289 | #endif |
290 | } |
291 | } |
292 | |
293 | /** |
294 | * \brief resume audio dec when receive RESUME command. |
295 | * \param audec pointer to audec |
296 | */ |
297 | static void resume_adec(aml_audio_dec_t *audec) |
298 | { |
299 | audio_out_operations_t *aout_ops = &audec->aout_ops; |
300 | if (audec->state == PAUSED) { |
301 | audec->state = ACTIVE; |
302 | #ifdef OUT_USE_AUDIOTRACK |
303 | aout_ops->resume(audec); |
304 | #endif |
305 | adec_pts_resume(); |
306 | } |
307 | } |
308 | |
309 | /** |
310 | * \brief stop audio dec when receive STOP command. |
311 | * \param audec pointer to audec |
312 | */ |
313 | static void stop_adec(aml_audio_dec_t *audec) |
314 | { |
315 | audio_out_operations_t *aout_ops = &audec->aout_ops; |
316 | adec_print("[%s %d]audec->state/%d\n", __FUNCTION__, __LINE__, audec->state); |
317 | if (audec->state > INITING) { |
318 | audec->state = STOPPED; |
319 | #ifdef OUT_USE_AUDIOTRACK |
320 | aout_ops->mute(audec, 1); //mute output, some repeat sound in audioflinger after stop |
321 | aout_ops->stop(audec); |
322 | #endif |
323 | wfd_audio_codec_release(audec); |
324 | } |
325 | } |
326 | |
327 | /** |
328 | * \brief release audio dec when receive RELEASE command. |
329 | * \param audec pointer to audec |
330 | */ |
331 | static void release_adec(aml_audio_dec_t *audec) |
332 | { |
333 | audec->state = TERMINATED; |
334 | } |
335 | |
336 | /** |
337 | * \brief mute audio dec when receive MUTE command. |
338 | * \param audec pointer to audec |
339 | * \param en 1 = mute, 0 = unmute |
340 | */ |
341 | static void mute_adec(aml_audio_dec_t *audec, int en) |
342 | { |
343 | #ifdef OUT_USE_AUDIOTRACK |
344 | audio_out_operations_t *aout_ops = &audec->aout_ops; |
345 | if (aout_ops->mute) { |
346 | adec_print("%s the output !\n", (en ? "mute" : "unmute")); |
347 | aout_ops->mute(audec, en); |
348 | audec->muted = en; |
349 | } |
350 | #endif |
351 | } |
352 | |
353 | /** |
354 | * \brief set volume to audio dec when receive SET_VOL command. |
355 | * \param audec pointer to audec |
356 | * \param vol volume value |
357 | */ |
358 | static void adec_set_volume(aml_audio_dec_t *audec, float vol) |
359 | { |
360 | #ifdef OUT_USE_AUDIOTRACK |
361 | audio_out_operations_t *aout_ops = &audec->aout_ops; |
362 | if (aout_ops->set_volume) { |
363 | adec_print("set audio volume! vol = %f\n", vol); |
364 | aout_ops->set_volume(audec, vol); |
365 | } |
366 | #endif |
367 | } |
368 | |
369 | /** |
370 | * \brief set volume to audio dec when receive SET_LRVOL command. |
371 | * \param audec pointer to audec |
372 | * \param lvol left channel volume value |
373 | * \param rvol right channel volume value |
374 | */ |
375 | static void adec_set_lrvolume(aml_audio_dec_t *audec, float lvol, float rvol) |
376 | { |
377 | #ifdef OUT_USE_AUDIOTRACK |
378 | audio_out_operations_t *aout_ops = &audec->aout_ops; |
379 | if (aout_ops->set_lrvolume) { |
380 | adec_print("set audio volume! left vol = %f,right vol:%f\n", lvol, rvol); |
381 | aout_ops->set_lrvolume(audec, lvol, rvol); |
382 | } |
383 | #endif |
384 | } |
385 | static void adec_flag_check(aml_audio_dec_t *audec) |
386 | { |
387 | audio_out_operations_t *aout_ops = &audec->aout_ops; |
388 | if (audec->auto_mute && (audec->state > INITTED)) { |
389 | aout_ops->pause(audec); |
390 | amthreadpool_thread_usleep(10000); |
391 | while ((!audec->need_stop) && track_switch_pts(audec)) { |
392 | amthreadpool_thread_usleep(1000); |
393 | } |
394 | #ifdef OUT_USE_AUDIOTRACK |
395 | aout_ops->resume(audec); |
396 | #endif |
397 | audec->auto_mute = 0; |
398 | } |
399 | } |
400 | |
401 | |
402 | static void start_wfd_decode_thread(aml_audio_dec_t *audec) |
403 | { |
404 | int ret = -1; |
405 | if (audec->state != INITTED) { |
406 | adec_print("decode not inited quit \n"); |
407 | return; |
408 | } |
409 | pthread_t tid; |
410 | ret = amthreadpool_pthread_create(&tid, NULL, (void *)audio_wfd_decode_loop, (void *)audec); |
411 | if (ret != 0) { |
412 | adec_print("[%s]Create ffmpeg decode thread failed!\n", __FUNCTION__); |
413 | return; |
414 | } |
415 | audec->sn_threadid = tid; |
416 | pthread_setname_np(tid, "AmadecDecodeWFD"); |
417 | adec_print("[%s]Create WFD audio decode thread success! tid = %d\n", __FUNCTION__, tid); |
418 | } |
419 | static void stop_wfd_decode_thread(aml_audio_dec_t *audec) |
420 | { |
421 | adec_print("enter stop_wfd_decode_thread \n"); |
422 | audec->exit_decode_thread = 1; |
423 | int ret = amthreadpool_pthread_join(audec->sn_threadid, NULL); |
424 | adec_print("[%s]wfd decode thread exit success\n", __FUNCTION__); |
425 | audec->exit_decode_thread = 0; |
426 | audec->sn_threadid = -1; |
427 | |
428 | } |
429 | |
430 | static int wfd_audio_codec_init(aml_audio_dec_t *audec) |
431 | { |
432 | int ret = 0; |
433 | audec->exit_decode_thread = 0; |
434 | audec->fd_uio = -1; |
435 | audec->sn_threadid = -1; |
436 | audec->adsp_ops.dsp_on = 1; |
437 | //TODO : get the actual sample rate /channel num |
438 | audec->data_width = AV_SAMPLE_FMT_S16; |
439 | audec->channels = 2; |
440 | audec->samplerate = 48000; |
441 | |
442 | audec->adsp_ops.dsp_read = wfd_dec_pcm_read; |
443 | audec->adsp_ops.get_cur_pts = wfd_dec_get_pts; |
444 | audec->adsp_ops.get_cur_pcrscr = wfd_dec_get_pcrscr; |
445 | audec->adsp_ops.set_cur_apts = wfd_dec_set_pts; |
446 | audec->adsp_ops.set_skip_bytes = wfd_dec_set_skip_bytes; |
447 | audec->adsp_ops.dsp_read_raw = NULL; |
448 | while (0 != set_sysfs_int(DECODE_ERR_PATH, DECODE_NONE_ERR)) { |
449 | adec_print("[%s %d]set codec fatal failed ! \n", __FUNCTION__, __LINE__); |
450 | amthreadpool_thread_usleep(100000); |
451 | } |
452 | /* |
453 | //enable uio interface |
454 | ret = uio_init(audec); |
455 | if (ret < 0) { |
456 | adec_print("wfd uio init error! \n"); |
457 | return -1; |
458 | } |
459 | */ |
460 | // register decoder lib |
461 | memset(&WFDAudioDecoder, 0, sizeof(audio_decoder_operations_t)); |
462 | audec->adec_ops = &WFDAudioDecoder; |
463 | audec->adec_ops->priv_data = audec; |
464 | if (wfd_register_audio_lib(audec)) { |
465 | adec_print("wfd register decoder failed \n"); |
466 | return -1; |
467 | } |
468 | if (wfd_register_output_lib(audec)) { |
469 | adec_print("wfd register output failed \n"); |
470 | return -1; |
471 | } |
472 | // output init,not init here as we should get the sr/ch info when decode one frame |
473 | #if 0 |
474 | if (wfd_out_init()) { |
475 | adec_print("wfd init pcm output device failed\n"); |
476 | return -1; |
477 | } |
478 | #endif |
479 | ret = audec->adec_ops->init(audec->adec_ops); |
480 | if (ret) { |
481 | adec_print("wfd audio decoder init failed \n"); |
482 | goto error1; |
483 | } |
484 | |
485 | |
486 | adec_print("wfd audio_codec_init ok \n"); |
487 | return 0; |
488 | error1: |
489 | wfd_out_uninit(); |
490 | return -1; |
491 | |
492 | } |
493 | #define RESAMPLE_FRAMES 128 |
494 | static short date_temp[1024 * 4 * 2]; |
495 | |
496 | static void audio_resample_api(char* buffer, unsigned int *size, int Chnum, int enable, int delta) |
497 | { |
498 | short *pbuf; |
499 | int resample_enable; |
500 | int resample_type; |
501 | int resample_delta; |
502 | int frame_read; |
503 | int num_sample = 0; |
504 | int i, j, k, h; |
505 | int request = *size; |
506 | int dsp_read = 0; |
507 | static int last_resample_enable = 0; |
508 | pbuf = (short*)date_temp; |
509 | unsigned index = 0; |
510 | float mPhaseFraction; |
511 | float phaseIncrement ; |
512 | float mPhaseFraction1; |
513 | unsigned in_sr; |
514 | unsigned out_sr; |
515 | short *input; |
516 | short *output; |
517 | unsigned frames = 0; |
518 | in_sr = (RESAMPLE_FRAMES - 1); |
519 | out_sr = (RESAMPLE_FRAMES - delta - 1); |
520 | phaseIncrement = (float)in_sr / out_sr; |
521 | resample_enable = enable; |
522 | resample_delta = delta; |
523 | |
524 | if (last_resample_enable != resample_enable) { |
525 | adec_print("resample changed: %s\n", resample_enable ? "Enabled" : "Disabled"); |
526 | last_resample_enable = resample_enable; |
527 | } |
528 | |
529 | if (resample_enable && resample_delta && *size >= RESAMPLE_FRAMES * sizeof(short)*Chnum) { |
530 | //adec_print("resample start ... %d, step=%d\n", *size, resample_delta); |
531 | if (resample_delta < 0) { |
532 | // *size = *size*RESAMPLE_FRAMES/(RESAMPLE_FRAMES-resample_delta); |
533 | } |
534 | memcpy(pbuf, buffer, *size); |
535 | frame_read = *size / (sizeof(short) * Chnum); //dsp_pcm_read(audec, pbuf, *size); // return mono sample number |
536 | dsp_read += frame_read; |
537 | k = 0; |
538 | while (frame_read >= RESAMPLE_FRAMES) { |
539 | mPhaseFraction = 0; |
540 | mPhaseFraction1 = 0; |
541 | index = 0; |
542 | input = (short*)pbuf + frames * Chnum; |
543 | output = (short*)buffer + k * Chnum; |
544 | for (j = 0; j < RESAMPLE_FRAMES - resample_delta; j++) { |
545 | output[2 * j] = input[index * 2] + (short)((input[(index + 1) * 2] - input[index * 2]) * mPhaseFraction1); |
546 | output[2 * j + 1] = input[index * 2 + 1] + (short)((input[(index + 1) * 2 + 1] - input[index * 2 + 1]) * mPhaseFraction1); |
547 | mPhaseFraction += phaseIncrement; |
548 | index = mPhaseFraction; |
549 | mPhaseFraction1 = mPhaseFraction - index; |
550 | k++; |
551 | } |
552 | frames += RESAMPLE_FRAMES; |
553 | frame_read -= RESAMPLE_FRAMES; |
554 | } |
555 | if (frame_read > 0) { |
556 | memcpy((short*)buffer + k * Chnum, (short*)pbuf + frames * Chnum, frame_read * sizeof(short)* Chnum); |
557 | k += frame_read; |
558 | } |
559 | |
560 | |
561 | num_sample = k * sizeof(short) * Chnum; |
562 | *size = k * sizeof(short) * Chnum; |
563 | } |
564 | // adec_print("resample size from %d to %d, original %d\n", request, *size, dsp_read); |
565 | } |
566 | |
567 | static int skip_thred = 400; |
568 | static int up_thred = 100; |
569 | static int dn_thred = 200; |
570 | static int dn_resample_delta = 2; |
571 | static int up_resample_delta = -4; |
572 | static void set_wfd_pcm_thredhold() |
573 | { |
574 | |
575 | char value[PROPERTY_VALUE_MAX]; |
576 | if (property_get("media.wfd.skip", value, NULL) > 0) { |
577 | skip_thred = atoi(value); |
578 | } |
579 | if (property_get("media.wfd.up", value, NULL) > 0) { |
580 | up_thred = atoi(value); |
581 | } |
582 | if (property_get("media.wfd.dn", value, NULL) > 0) { |
583 | dn_thred = atoi(value); |
584 | } |
585 | if (property_get("media.wfd.dn_delta", value, NULL) > 0) { |
586 | dn_resample_delta = atoi(value); |
587 | } |
588 | if (property_get("media.wfd.up_delta", value, NULL) > 0) { |
589 | up_resample_delta = atoi(value); |
590 | } |
591 | } |
592 | void *audio_wfd_decode_loop(void *args) |
593 | { |
594 | int ret; |
595 | aml_audio_dec_t *audec; |
596 | audio_out_operations_t *aout_ops; |
597 | audio_decoder_operations_t *adec_ops; |
598 | short outbuf[2048]; |
599 | int outlen = 0; |
600 | int write_size = 0; |
601 | int in_latency = 0; |
602 | int out_latency = 0; |
603 | int total_latency = 0; |
604 | int out_init_flag = 0; |
605 | char value[PROPERTY_VALUE_MAX]; |
606 | unsigned char debug_latency = 0; |
607 | adec_print("audio_wfd_decode_loop start!\n"); |
608 | audec = (aml_audio_dec_t *)args; |
609 | aout_ops = &audec->aout_ops; |
610 | adec_ops = audec->adec_ops; |
611 | if (property_get("media.wfd.debug_latency", value, NULL) > 0) { |
612 | debug_latency = atoi(value); |
613 | } |
614 | while (!audec->exit_decode_thread) { |
615 | outlen = 0; |
616 | // adec_refresh_pts(audec); |
617 | set_wfd_pcm_thredhold(); |
618 | audec->decode_offset = adec_ops->decode(adec_ops, outbuf, &outlen, (char*)&in_latency, 0); |
619 | |
620 | if (outlen > 0) { |
621 | if (!out_init_flag) { |
622 | if (wfd_out_init(adec_ops->samplerate, adec_ops->channels)) { |
623 | adec_print("wfd init pcm output device failed\n"); |
624 | continue; |
625 | } |
626 | out_init_flag = 1; |
627 | } |
628 | out_latency = wfd_out_latency(); |
629 | if (out_latency < 0) { |
630 | out_latency = 0; |
631 | } |
632 | total_latency = in_latency + out_latency; |
633 | audec->out_len_after_last_valid_pts += outlen; |
634 | if (debug_latency) { |
635 | adec_print("latency in %d ms,out %d ms.total %d ms\n", in_latency, out_latency, total_latency); |
636 | if (total_latency < 150) { |
637 | if (property_get("sys.pkginfo", value, NULL) > 0) { |
638 | adec_print("latency pkg info %s \n", value); |
639 | } |
640 | } |
641 | } |
642 | if (total_latency > skip_thred) { |
643 | if (debug_latency) { |
644 | adec_print(" total latency %d ms ,skip bytes %d \n", total_latency, outlen); |
645 | } |
646 | outlen = 0; |
647 | } else if (total_latency > dn_thred) { |
648 | audio_resample_api(outbuf, &outlen, 2, 1, dn_resample_delta); |
649 | } else if (total_latency < up_thred) { |
650 | audio_resample_api(outbuf, &outlen, 2, 1, up_resample_delta); |
651 | } |
652 | if (debug_latency) { |
653 | adec_print("wfd dec out %d byts pcm \n", outlen); |
654 | } |
655 | write_size = wfd_out_write(outbuf, outlen); |
656 | } |
657 | //TODO decode function |
658 | } |
659 | adec_print("exit audio_wfd_decode_loop Thread finished!\n"); |
660 | pthread_exit(NULL); |
661 | error: |
662 | pthread_exit(NULL); |
663 | return NULL; |
664 | } |
665 | |
666 | |
667 | /* |
668 | WFD audio decoder control thread |
669 | */ |
670 | void *adec_wfddec_msg_loop(void *args) |
671 | { |
672 | int ret; |
673 | aml_audio_dec_t *audec; |
674 | audio_out_operations_t *aout_ops; |
675 | adec_cmd_t *msg = NULL; |
676 | audec = (aml_audio_dec_t *)args; |
677 | aout_ops = &audec->aout_ops; |
678 | adec_print("adec_wfddec_loop in \n"); |
679 | while (!audec->need_stop) { |
680 | audec->state = INITING; |
681 | ret = wfd_audio_codec_init(audec); |
682 | if (ret == 0) { |
683 | { |
684 | #ifdef OUT_USE_AUDIOTRACK |
685 | ret = aout_ops->init(audec); |
686 | if (ret) { |
687 | adec_print("WFD Audio out device init failed!\n"); |
688 | wfd_audio_codec_release(audec); |
689 | continue; |
690 | } |
691 | #endif |
692 | audec->state = INITTED; |
693 | start_wfd_decode_thread(audec); |
694 | start_adec(audec); |
695 | } |
696 | break; |
697 | } |
698 | |
699 | if (!audec->need_stop) { |
700 | amthreadpool_thread_usleep(100000); |
701 | } |
702 | } |
703 | |
704 | do { |
705 | |
706 | adec_reset_track(audec); |
707 | adec_flag_check(audec); |
708 | msg = adec_get_message(audec); |
709 | if (!msg) { |
710 | amthreadpool_thread_usleep(100000); |
711 | continue; |
712 | } |
713 | |
714 | switch (msg->ctrl_cmd) { |
715 | case CMD_START: |
716 | |
717 | adec_print("Receive START Command!\n"); |
718 | start_wfd_decode_thread(audec); |
719 | start_adec(audec); |
720 | break; |
721 | |
722 | case CMD_PAUSE: |
723 | |
724 | adec_print("Receive PAUSE Command!"); |
725 | pause_adec(audec); |
726 | break; |
727 | |
728 | case CMD_RESUME: |
729 | |
730 | adec_print("Receive RESUME Command!"); |
731 | resume_adec(audec); |
732 | break; |
733 | |
734 | case CMD_STOP: |
735 | |
736 | adec_print("Receive STOP Command!"); |
737 | stop_adec(audec); |
738 | break; |
739 | |
740 | case CMD_MUTE: |
741 | |
742 | adec_print("Receive Mute Command!"); |
743 | if (msg->has_arg) { |
744 | mute_adec(audec, msg->value.en); |
745 | } |
746 | break; |
747 | |
748 | case CMD_SET_VOL: |
749 | |
750 | adec_print("Receive Set Vol Command!"); |
751 | if (msg->has_arg) { |
752 | adec_set_volume(audec, msg->value.volume); |
753 | } |
754 | break; |
755 | case CMD_SET_LRVOL: |
756 | |
757 | adec_print("Receive Set LRVol Command!"); |
758 | if (msg->has_arg) { |
759 | adec_set_lrvolume(audec, msg->value.volume, msg->value_ext.volume); |
760 | } |
761 | break; |
762 | #if 0 |
763 | case CMD_CHANL_SWAP: |
764 | |
765 | adec_print("Receive Channels Swap Command!"); |
766 | audio_hardware_ctrl(HW_CHANNELS_SWAP); |
767 | break; |
768 | |
769 | case CMD_LEFT_MONO: |
770 | |
771 | adec_print("Receive Left Mono Command!"); |
772 | audio_hardware_ctrl(HW_LEFT_CHANNEL_MONO); |
773 | break; |
774 | |
775 | case CMD_RIGHT_MONO: |
776 | |
777 | adec_print("Receive Right Mono Command!"); |
778 | audio_hardware_ctrl(HW_RIGHT_CHANNEL_MONO); |
779 | break; |
780 | |
781 | case CMD_STEREO: |
782 | |
783 | adec_print("Receive Stereo Command!"); |
784 | audio_hardware_ctrl(HW_STEREO_MODE); |
785 | break; |
786 | #endif |
787 | case CMD_RELEASE: |
788 | |
789 | adec_print("Receive RELEASE Command!"); |
790 | release_adec(audec); |
791 | break; |
792 | |
793 | default: |
794 | adec_print("Unknow Command!"); |
795 | break; |
796 | |
797 | } |
798 | |
799 | if (msg) { |
800 | adec_message_free(msg); |
801 | msg = NULL; |
802 | } |
803 | } while (audec->state != TERMINATED); |
804 | |
805 | adec_print("Exit adec_wfddec_msg_loop!"); |
806 | pthread_exit(NULL); |
807 | return NULL; |
808 | } |
809 | |
810 | |
811 | |
812 |