blob: 388e5161e28575aefef310be675af9925b9686fe
1 | /** |
2 | * \file alsa-out.c |
3 | * \brief Functions of Auduo output control for Linux Platform |
4 | * \version 1.0.0 |
5 | * \date 2011-03-08 |
6 | */ |
7 | /* Copyright (C) 2007-2011, Amlogic Inc. |
8 | * All right reserved |
9 | * |
10 | */ |
11 | #include <stdio.h> |
12 | #include <stdlib.h> |
13 | #include <fcntl.h> |
14 | #include <sys/ioctl.h> |
15 | #include <unistd.h> |
16 | #include <linux/soundcard.h> |
17 | //#include <config.h> |
18 | #include <asoundlib.h> |
19 | |
20 | #include <audio-dec.h> |
21 | #include <adec-pts-mgt.h> |
22 | #include <log-print.h> |
23 | #include <alsa-out.h> |
24 | #include <amthreadpool.h> |
25 | #include <cutils/properties.h> |
26 | |
27 | |
28 | #define USE_INTERPOLATION |
29 | |
30 | static snd_pcm_sframes_t (*readi_func)(snd_pcm_t *handle, void *buffer, snd_pcm_uframes_t size); |
31 | static snd_pcm_sframes_t (*writei_func)(snd_pcm_t *handle, const void *buffer, snd_pcm_uframes_t size); |
32 | static snd_pcm_sframes_t (*readn_func)(snd_pcm_t *handle, void **bufs, snd_pcm_uframes_t size); |
33 | static snd_pcm_sframes_t (*writen_func)(snd_pcm_t *handle, void **bufs, snd_pcm_uframes_t size); |
34 | |
35 | static float alsa_default_vol = 1.0; |
36 | static int hdmi_out = 0; |
37 | static int fragcount = 16; |
38 | static snd_pcm_uframes_t chunk_size = 1024; |
39 | static char output_buffer[64 * 1024]; |
40 | static unsigned char decode_buffer[OUTPUT_BUFFER_SIZE + 64]; |
41 | #define PERIOD_SIZE 1024 |
42 | #define PERIOD_NUM 4 |
43 | |
44 | #ifdef USE_INTERPOLATION |
45 | static int pass1_history[8][8]; |
46 | #pragma align_to(64,pass1_history) |
47 | static int pass2_history[8][8]; |
48 | #pragma align_to(64,pass2_history) |
49 | static short pass1_interpolation_output[0x4000]; |
50 | #pragma align_to(64,pass1_interpolation_output) |
51 | static short interpolation_output[0x8000]; |
52 | #pragma align_to(64,interpolation_output) |
53 | static int tv_mode = 0; |
54 | static int getprop_bool(const char * path) |
55 | { |
56 | char buf[PROPERTY_VALUE_MAX]; |
57 | int ret = -1; |
58 | ret = property_get(path, buf, NULL); |
59 | if (ret > 0) { |
60 | if (strcasecmp(buf,"true") == 0 || strcmp(buf,"1") == 0) |
61 | return 1; |
62 | } |
63 | return 0; |
64 | } |
65 | static inline short CLIPTOSHORT(int x) |
66 | { |
67 | short res; |
68 | #if 0 |
69 | __asm__ __volatile__( |
70 | "min r0, %1, 0x7fff\r\n" |
71 | "max r0, r0, -0x8000\r\n" |
72 | "mov %0, r0\r\n" |
73 | :"=r"(res) |
74 | :"r"(x) |
75 | :"r0" |
76 | ); |
77 | #else |
78 | if (x > 0x7fff) { |
79 | res = 0x7fff; |
80 | } else if (x < -0x8000) { |
81 | res = -0x8000; |
82 | } else { |
83 | res = x; |
84 | } |
85 | #endif |
86 | return res; |
87 | } |
88 | |
89 | static int set_sysfs_type(const char *path, const char *type) |
90 | { |
91 | int ret = -1; |
92 | int fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644); |
93 | if (fd >= 0) { |
94 | char set_type[10] = {0}; |
95 | int length = snprintf(set_type, sizeof(set_type), "%s", type); |
96 | if (length > 0) |
97 | ret = write(fd, set_type, length); |
98 | adec_print("%s , %s\n", path, set_type); |
99 | close(fd); |
100 | }else{ |
101 | adec_print("open hdmi-tx node:%s failed!\n", path); |
102 | } |
103 | return ret; |
104 | } |
105 | |
106 | |
107 | static void pcm_interpolation(int interpolation, unsigned num_channel, unsigned num_sample, short *samples) |
108 | { |
109 | int i, k, l, ch; |
110 | int *s; |
111 | short *d; |
112 | for (ch = 0; ch < num_channel; ch++) { |
113 | s = pass1_history[ch]; |
114 | if (interpolation < 2) { |
115 | d = interpolation_output; |
116 | } else { |
117 | d = pass1_interpolation_output; |
118 | } |
119 | for (i = 0, k = l = ch; i < num_sample; i++, k += num_channel) { |
120 | s[0] = s[1]; |
121 | s[1] = s[2]; |
122 | s[2] = s[3]; |
123 | s[3] = s[4]; |
124 | s[4] = s[5]; |
125 | s[5] = samples[k]; |
126 | d[l] = s[2]; |
127 | l += num_channel; |
128 | d[l] = CLIPTOSHORT((150 * (s[2] + s[3]) - 25 * (s[1] + s[4]) + 3 * (s[0] + s[5]) + 128) >> 8); |
129 | l += num_channel; |
130 | } |
131 | if (interpolation >= 2) { |
132 | s = pass2_history[ch]; |
133 | d = interpolation_output; |
134 | for (i = 0, k = l = ch; i < num_sample * 2; i++, k += num_channel) { |
135 | s[0] = s[1]; |
136 | s[1] = s[2]; |
137 | s[2] = s[3]; |
138 | s[3] = s[4]; |
139 | s[4] = s[5]; |
140 | s[5] = pass1_interpolation_output[k]; |
141 | d[l] = s[2]; |
142 | l += num_channel; |
143 | d[l] = CLIPTOSHORT((150 * (s[2] + s[3]) - 25 * (s[1] + s[4]) + 3 * (s[0] + s[5]) + 128) >> 8); |
144 | l += num_channel; |
145 | } |
146 | } |
147 | } |
148 | } |
149 | #endif |
150 | |
151 | |
152 | static int set_params(alsa_param_t *alsa_params) |
153 | { |
154 | snd_pcm_hw_params_t *hwparams; |
155 | snd_pcm_sw_params_t *swparams; |
156 | // snd_pcm_uframes_t buffer_size; |
157 | // snd_pcm_uframes_t boundary; |
158 | // unsigned int period_time = 0; |
159 | // unsigned int buffer_time = 0; |
160 | snd_pcm_uframes_t bufsize; |
161 | int err; |
162 | unsigned int rate; |
163 | snd_pcm_uframes_t start_threshold, stop_threshold; |
164 | snd_pcm_hw_params_alloca(&hwparams); |
165 | snd_pcm_sw_params_alloca(&swparams); |
166 | |
167 | err = snd_pcm_hw_params_any(alsa_params->handle, hwparams); |
168 | if (err < 0) { |
169 | adec_print("Broken configuration for this PCM: no configurations available"); |
170 | return err; |
171 | } |
172 | |
173 | err = snd_pcm_hw_params_set_access(alsa_params->handle, hwparams, |
174 | SND_PCM_ACCESS_RW_INTERLEAVED); |
175 | if (err < 0) { |
176 | adec_print("Access type not available"); |
177 | return err; |
178 | } |
179 | if (tv_mode) { |
180 | alsa_params->format = SND_PCM_FORMAT_S32_LE; |
181 | } |
182 | err = snd_pcm_hw_params_set_format(alsa_params->handle,hwparams,alsa_params->format); |
183 | if (err < 0) { |
184 | adec_print("Sample format non available"); |
185 | return err; |
186 | } |
187 | alsa_params->format = SND_PCM_FORMAT_S16_LE; |
188 | if (tv_mode) { |
189 | alsa_params->channelcount = 8; |
190 | } |
191 | err = snd_pcm_hw_params_set_channels(alsa_params->handle, hwparams, alsa_params->channelcount); |
192 | alsa_params->channelcount = 2; |
193 | if (err < 0) { |
194 | adec_print("Channels count non available"); |
195 | return err; |
196 | } |
197 | |
198 | rate = alsa_params->rate; |
199 | err = snd_pcm_hw_params_set_rate_near(alsa_params->handle, hwparams, &alsa_params->rate, 0); |
200 | assert(err >= 0); |
201 | #if 0 |
202 | err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &buffer_time, 0); |
203 | assert(err >= 0); |
204 | if (buffer_time > 500000) { |
205 | buffer_time = 500000; |
206 | } |
207 | |
208 | period_time = buffer_time / 4; |
209 | |
210 | err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, |
211 | &period_time, 0); |
212 | assert(err >= 0); |
213 | |
214 | err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, |
215 | &buffer_time, 0); |
216 | assert(err >= 0); |
217 | |
218 | #endif |
219 | alsa_params->bits_per_sample = snd_pcm_format_physical_width(alsa_params->format); |
220 | //bits_per_frame = bits_per_sample * hwparams.realchanl; |
221 | alsa_params->bits_per_frame = alsa_params->bits_per_sample * alsa_params->channelcount; |
222 | adec_print("bits_per_sample %d,bits_per_frame %d\n",alsa_params->bits_per_sample,alsa_params->bits_per_frame); |
223 | bufsize = PERIOD_NUM * PERIOD_SIZE; |
224 | |
225 | if (tv_mode) { |
226 | set_sysfs_type("/sys/class/amhdmitx/amhdmitx0/aud_output_chs", "2:1"); |
227 | } |
228 | |
229 | err = snd_pcm_hw_params_set_buffer_size_near(alsa_params->handle, hwparams, &bufsize); |
230 | if (err < 0) { |
231 | adec_print("Unable to set buffer size \n"); |
232 | return err; |
233 | } |
234 | err = snd_pcm_hw_params_set_period_size_near(alsa_params->handle, hwparams, &chunk_size, NULL); |
235 | if (err < 0) { |
236 | adec_print("Unable to set period size \n"); |
237 | return err; |
238 | } |
239 | |
240 | //err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &fragcount, NULL); |
241 | //if (err < 0) { |
242 | // adec_print("Unable to set periods \n"); |
243 | // return err; |
244 | //} |
245 | |
246 | err = snd_pcm_hw_params(alsa_params->handle, hwparams); |
247 | if (err < 0) { |
248 | adec_print("Unable to install hw params:"); |
249 | return err; |
250 | } |
251 | |
252 | err = snd_pcm_hw_params_get_buffer_size(hwparams, &bufsize); |
253 | if (err < 0) { |
254 | adec_print("Unable to get buffersize \n"); |
255 | return err; |
256 | } |
257 | alsa_params->buffer_size = bufsize * alsa_params->bits_per_frame / 8; |
258 | |
259 | #if 1 |
260 | err = snd_pcm_sw_params_current(alsa_params->handle, swparams); |
261 | if (err < 0) { |
262 | adec_print("??Unable to get sw-parameters\n"); |
263 | return err; |
264 | } |
265 | |
266 | //err = snd_pcm_sw_params_get_boundary(swparams, &boundary); |
267 | //if (err < 0){ |
268 | // adec_print("Unable to get boundary\n"); |
269 | // return err; |
270 | //} |
271 | |
272 | //err = snd_pcm_sw_params_set_start_threshold(handle, swparams, bufsize); |
273 | //if (err < 0) { |
274 | // adec_print("Unable to set start threshold \n"); |
275 | // return err; |
276 | //} |
277 | |
278 | //err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, buffer_size); |
279 | //if (err < 0) { |
280 | // adec_print("Unable to set stop threshold \n"); |
281 | // return err; |
282 | //} |
283 | |
284 | // err = snd_pcm_sw_params_set_silence_size(handle, swparams, buffer_size); |
285 | // if (err < 0) { |
286 | // adec_print("Unable to set silence size \n"); |
287 | // return err; |
288 | // } |
289 | |
290 | err = snd_pcm_sw_params(alsa_params->handle, swparams); |
291 | if (err < 0) { |
292 | adec_print("Unable to get sw-parameters\n"); |
293 | return err; |
294 | } |
295 | |
296 | //snd_pcm_sw_params_free(swparams); |
297 | #endif |
298 | |
299 | |
300 | //chunk_bytes = chunk_size * bits_per_frame / 8; |
301 | |
302 | return 0; |
303 | } |
304 | |
305 | static int alsa_get_hdmi_state() |
306 | { |
307 | return 0; |
308 | #if 0 |
309 | int fd = -1, err = 0, state = 0; |
310 | unsigned fileSize = 32; |
311 | char *read_buf = NULL; |
312 | static const char *const HDMI_STATE_PATH = "/sys/class/switch/hdmi/state"; |
313 | |
314 | fd = open(HDMI_STATE_PATH, O_RDONLY); |
315 | if (fd < 0) { |
316 | adec_print("ERROR: failed to open config file %s error: %d\n", HDMI_STATE_PATH, errno); |
317 | close(fd); |
318 | return -EINVAL; |
319 | } |
320 | |
321 | read_buf = (char *)malloc(fileSize); |
322 | if (!read_buf) { |
323 | adec_print("Failed to malloc read_buf"); |
324 | goto OUT; |
325 | } |
326 | memset(read_buf, 0x0, fileSize); |
327 | err = read(fd, read_buf, fileSize); |
328 | if (fd < 0) { |
329 | adec_print("ERROR: failed to read config file %s error: %d\n", HDMI_STATE_PATH, errno); |
330 | goto OUT; |
331 | } |
332 | |
333 | if (*read_buf == '1') { |
334 | state = 1; |
335 | } |
336 | |
337 | OUT: |
338 | free(read_buf); |
339 | close(fd); |
340 | return state; |
341 | #endif |
342 | } |
343 | |
344 | static int alsa_get_aml_card() |
345 | { |
346 | int card = -1, err = 0; |
347 | int fd = -1; |
348 | unsigned fileSize = 512; |
349 | char *read_buf = NULL, *pd = NULL; |
350 | static const char *const SOUND_CARDS_PATH = "/proc/asound/cards"; |
351 | fd = open(SOUND_CARDS_PATH, O_RDONLY); |
352 | if (fd < 0) { |
353 | adec_print("ERROR: failed to open config file %s error: %d\n", SOUND_CARDS_PATH, errno); |
354 | close(fd); |
355 | return -EINVAL; |
356 | } |
357 | |
358 | read_buf = (char *)malloc(fileSize); |
359 | if (!read_buf) { |
360 | adec_print("Failed to malloc read_buf"); |
361 | close(fd); |
362 | return -ENOMEM; |
363 | } |
364 | memset(read_buf, 0x0, fileSize); |
365 | err = read(fd, read_buf, fileSize); |
366 | if (fd < 0) { |
367 | adec_print("ERROR: failed to read config file %s error: %d\n", SOUND_CARDS_PATH, errno); |
368 | free(read_buf); |
369 | close(fd); |
370 | return -EINVAL; |
371 | } |
372 | pd = strstr(read_buf, "AML"); |
373 | card = *(pd - 3) - '0'; |
374 | |
375 | OUT: |
376 | free(read_buf); |
377 | close(fd); |
378 | return card; |
379 | } |
380 | |
381 | static int alsa_get_spdif_port() |
382 | { |
383 | /* for pcm output,i2s/958 share the same data from i2s,so always use device 0 as i2s output */ |
384 | return 0; |
385 | int port = -1, err = 0; |
386 | int fd = -1; |
387 | unsigned fileSize = 512; |
388 | char *read_buf = NULL, *pd = NULL; |
389 | static const char *const SOUND_PCM_PATH = "/proc/asound/pcm"; |
390 | fd = open(SOUND_PCM_PATH, O_RDONLY); |
391 | if (fd < 0) { |
392 | adec_print("ERROR: failed to open config file %s error: %d\n", SOUND_PCM_PATH, errno); |
393 | close(fd); |
394 | return -EINVAL; |
395 | } |
396 | |
397 | read_buf = (char *)malloc(fileSize); |
398 | if (!read_buf) { |
399 | adec_print("Failed to malloc read_buf"); |
400 | close(fd); |
401 | return -ENOMEM; |
402 | } |
403 | memset(read_buf, 0x0, fileSize); |
404 | err = read(fd, read_buf, fileSize); |
405 | if (fd < 0) { |
406 | adec_print("ERROR: failed to read config file %s error: %d\n", SOUND_PCM_PATH, errno); |
407 | free(read_buf); |
408 | close(fd); |
409 | return -EINVAL; |
410 | } |
411 | pd = strstr(read_buf, "SPDIF"); |
412 | if (!pd) { |
413 | goto OUT; |
414 | } |
415 | adec_print("%s \n", pd); |
416 | |
417 | port = *(pd - 3) - '0'; |
418 | adec_print("%s \n", (pd - 3)); |
419 | |
420 | OUT: |
421 | free(read_buf); |
422 | close(fd); |
423 | return port; |
424 | } |
425 | |
426 | static size_t pcm_write(alsa_param_t * alsa_param, u_char * data, size_t count) |
427 | { |
428 | snd_pcm_sframes_t r; |
429 | size_t result = 0; |
430 | int i; |
431 | short *sample = (short*)data; |
432 | /* |
433 | if (count < chunk_size) { |
434 | snd_pcm_format_set_silence(hwparams.format, data + count * bits_per_frame / 8, (chunk_size - count) * hwparams.channels); |
435 | count = chunk_size; |
436 | } |
437 | */ |
438 | /* volume control for bootplayer */ |
439 | if (alsa_default_vol != 1.0) { |
440 | for (i = 0;i < count*2;i++) { |
441 | sample[i] = (short)(alsa_default_vol*(float)sample[i]); |
442 | } |
443 | } |
444 | // dump pcm data here |
445 | #if 0 |
446 | FILE *fp1=fopen("/data/audio_out.pcm","a+"); |
447 | if (fp1) { |
448 | int flen=fwrite((char *)data,1,count*2*2,fp1); |
449 | adec_print("flen = %d---outlen=%d ", flen, count*2*2); |
450 | fclose(fp1); |
451 | }else{ |
452 | adec_print("could not open file:audio_out.pcm"); |
453 | } |
454 | #endif |
455 | int *tmp_buffer = NULL; |
456 | int bits_per_frame = alsa_param->bits_per_frame; |
457 | if (tv_mode) { |
458 | tmp_buffer = (int*)malloc(count*8*4); |
459 | if (tmp_buffer == NULL) { |
460 | adec_print("malloc tmp_buffer failed\n"); |
461 | return -1; |
462 | } |
463 | int i; |
464 | int out_frames = count; |
465 | short *in_buffer = (short*)data; |
466 | for (i = 0; i < out_frames; i ++) { |
467 | tmp_buffer[8*i] = ((int)(in_buffer[2*i])) << 16; |
468 | tmp_buffer[8*i + 1] = ((int)(in_buffer[2*i + 1])) << 16; |
469 | tmp_buffer[8*i + 2] = ((int)(in_buffer[2*i])) << 16; |
470 | tmp_buffer[8*i + 3] = ((int)(in_buffer[2*i + 1])) << 16; |
471 | tmp_buffer[8*i + 4] = 0; |
472 | tmp_buffer[8*i + 5] = 0; |
473 | tmp_buffer[8*i + 6] = 0; |
474 | tmp_buffer[8*i + 7] = 0; |
475 | } |
476 | data = (char*)tmp_buffer; |
477 | bits_per_frame = bits_per_frame*8;//8ch,32bit |
478 | } |
479 | while (count > 0) { |
480 | r = writei_func(alsa_param->handle, data, count); |
481 | |
482 | if (r == -EINTR) { |
483 | r = 0; |
484 | } |
485 | if (r == -ESTRPIPE) { |
486 | while ((r = snd_pcm_resume(alsa_param->handle)) == -EAGAIN) { |
487 | amthreadpool_thread_usleep(1000); |
488 | } |
489 | } |
490 | |
491 | if (r < 0) { |
492 | printf("xun in\n"); |
493 | if ((r = snd_pcm_prepare(alsa_param->handle)) < 0) { |
494 | result = 0; |
495 | goto done; |
496 | } |
497 | } |
498 | |
499 | if (r > 0) { |
500 | result += r; |
501 | count -= r; |
502 | data += r * bits_per_frame / 8; |
503 | } |
504 | } |
505 | done: |
506 | if (tmp_buffer) { |
507 | free(tmp_buffer); |
508 | } |
509 | return result; |
510 | } |
511 | |
512 | static unsigned oversample_play(alsa_param_t * alsa_param, char * src, unsigned count) |
513 | { |
514 | int frames = 0; |
515 | int ret, i; |
516 | unsigned short * to, *from; |
517 | to = (unsigned short *)output_buffer; |
518 | from = (unsigned short *)src; |
519 | |
520 | if (alsa_param->realchanl == 2) { |
521 | if (alsa_param->oversample == -1) { |
522 | frames = count * 8 / alsa_param->bits_per_frame; |
523 | frames = frames & (~(32 - 1)); |
524 | for (i = 0; i < (frames * 2); i += 4) { // i for sample |
525 | *to++ = *from++; |
526 | *to ++ = *from++; |
527 | from += 2; |
528 | } |
529 | ret = pcm_write(alsa_param, output_buffer, frames / 2); |
530 | ret = ret * alsa_param->bits_per_frame / 8; |
531 | ret = ret * 2; |
532 | } else if (alsa_param->oversample == 1) { |
533 | frames = count * 8 / alsa_param->bits_per_frame; |
534 | frames = frames & (~(16 - 1)); |
535 | #ifdef USE_INTERPOLATION |
536 | pcm_interpolation(1, alsa_param->realchanl, frames, (short*)src); |
537 | memcpy(output_buffer, interpolation_output, (frames * alsa_param->bits_per_frame / 4)); |
538 | #else |
539 | short l, r; |
540 | for (i = 0; i < (frames * 2); i += 2) { |
541 | l = *from++; |
542 | r = *from++; |
543 | *to++ = l; |
544 | *to++ = r; |
545 | *to++ = l; |
546 | *to++ = r; |
547 | } |
548 | #endif |
549 | ret = pcm_write(alsa_param, output_buffer, frames * 2); |
550 | ret = ret * alsa_param->bits_per_frame / 8; |
551 | ret = ret / 2; |
552 | } else if (alsa_param->oversample == 2) { |
553 | frames = count * 8 / alsa_param->bits_per_frame; |
554 | frames = frames & (~(8 - 1)); |
555 | #ifdef USE_INTERPOLATION |
556 | pcm_interpolation(2, alsa_param->realchanl, frames, (short*)src); |
557 | memcpy(output_buffer, interpolation_output, (frames * alsa_param->bits_per_frame / 2)); |
558 | #else |
559 | short l, r; |
560 | for (i = 0; i < (frames * 2); i += 2) { |
561 | l = *from++; |
562 | r = *from++; |
563 | *to++ = l; |
564 | *to++ = r; |
565 | *to++ = l; |
566 | *to++ = r; |
567 | *to++ = l; |
568 | *to++ = r; |
569 | *to++ = l; |
570 | *to++ = r; |
571 | } |
572 | #endif |
573 | ret = pcm_write(alsa_param, output_buffer, frames * 4); |
574 | ret = ret * alsa_param->bits_per_frame / 8; |
575 | ret = ret / 4; |
576 | } |
577 | } else if (alsa_param->realchanl == 1) { |
578 | if (alsa_param->oversample == -1) { |
579 | frames = count * 8 / alsa_param->bits_per_frame; |
580 | frames = frames & (~(32 - 1)); |
581 | for (i = 0; i < (frames * 2); i += 2) { |
582 | *to++ = *from; |
583 | *to++ = *from++; |
584 | from++; |
585 | } |
586 | ret = pcm_write(alsa_param, output_buffer, frames); |
587 | ret = ret * alsa_param->bits_per_frame / 8; |
588 | } else if (alsa_param->oversample == 0) { |
589 | frames = count * 8 / (alsa_param->bits_per_frame >> 1); |
590 | frames = frames & (~(16 - 1)); |
591 | for (i = 0; i < (frames); i++) { |
592 | *to++ = *from; |
593 | *to++ = *from++; |
594 | } |
595 | ret = pcm_write(alsa_param, output_buffer, frames); |
596 | ret = ret * (alsa_param->bits_per_frame) / 8; |
597 | ret = ret / 2; |
598 | } else if (alsa_param->oversample == 1) { |
599 | frames = count * 8 / (alsa_param->bits_per_frame >> 1); |
600 | frames = frames & (~(8 - 1)); |
601 | #ifdef USE_INTERPOLATION |
602 | pcm_interpolation(1, alsa_param->realchanl, frames, (short*)src); |
603 | from = (unsigned short*)interpolation_output; |
604 | for (i = 0; i < (frames * 2); i++) { |
605 | *to++ = *from; |
606 | *to++ = *from++; |
607 | } |
608 | #else |
609 | for (i = 0; i < (frames); i++) { |
610 | *to++ = *from; |
611 | *to++ = *from; |
612 | *to++ = *from; |
613 | *to++ = *from++; |
614 | } |
615 | #endif |
616 | ret = pcm_write(alsa_param, output_buffer, frames * 2); |
617 | ret = ret * (alsa_param->bits_per_frame) / 8; |
618 | ret = ret / 4; |
619 | } else if (alsa_param->oversample == 2) { |
620 | frames = count * 8 / (alsa_param->bits_per_frame >> 1); |
621 | frames = frames & (~(8 - 1)); |
622 | #ifdef USE_INTERPOLATION |
623 | pcm_interpolation(2, alsa_param->realchanl, frames, (short*)src); |
624 | from = (unsigned short*)interpolation_output; |
625 | for (i = 0; i < (frames * 4); i++) { |
626 | *to++ = *from; |
627 | *to++ = *from++; |
628 | } |
629 | #else |
630 | for (i = 0; i < (frames); i++) { |
631 | *to++ = *from; |
632 | *to++ = *from; |
633 | *to++ = *from; |
634 | *to++ = *from; |
635 | *to++ = *from; |
636 | *to++ = *from; |
637 | *to++ = *from; |
638 | *to++ = *from++; |
639 | } |
640 | #endif |
641 | ret = pcm_write(alsa_param, output_buffer, frames * 4); |
642 | ret = ret * (alsa_param->bits_per_frame) / 8; |
643 | ret = ret / 8; |
644 | } |
645 | } |
646 | |
647 | return ret; |
648 | } |
649 | |
650 | static int alsa_play(alsa_param_t * alsa_param, char * data, unsigned len) |
651 | { |
652 | size_t l = 0, r; |
653 | |
654 | if (!alsa_param->flag) { |
655 | l = len * 8 / alsa_param->bits_per_frame; |
656 | l = l & (~(32 - 1)); /*driver only support 32 frames each time */ |
657 | r = pcm_write(alsa_param, data, l); |
658 | r = r * alsa_param->bits_per_frame / 8; |
659 | } else { |
660 | r = oversample_play(alsa_param, data, len); |
661 | } |
662 | |
663 | return r ; |
664 | } |
665 | |
666 | static int alsa_swtich_port(alsa_param_t *alsa_params, int card, int port) |
667 | { |
668 | char dev[10] = {0}; |
669 | adec_print("card = %d, port = %d\n", card, port); |
670 | sprintf(dev, "hw:%d,%d", (card >= 0) ? card : 0, (port >= 0) ? port : 0); |
671 | pthread_mutex_lock(&alsa_params->playback_mutex); |
672 | snd_pcm_drop(alsa_params->handle); |
673 | snd_pcm_close(alsa_params->handle); |
674 | alsa_params->handle = NULL; |
675 | int err = snd_pcm_open(&alsa_params->handle, dev, SND_PCM_STREAM_PLAYBACK, 0); |
676 | |
677 | if (err < 0) { |
678 | adec_print("audio open error: %s", snd_strerror(err)); |
679 | pthread_mutex_unlock(&alsa_params->playback_mutex); |
680 | return -1; |
681 | } |
682 | |
683 | set_params(alsa_params); |
684 | pthread_mutex_unlock(&alsa_params->playback_mutex); |
685 | |
686 | return 0; |
687 | } |
688 | |
689 | static void *alsa_playback_loop(void *args) |
690 | { |
691 | int len = 0; |
692 | int len2 = 0; |
693 | int offset = 0; |
694 | aml_audio_dec_t *audec; |
695 | alsa_param_t *alsa_params; |
696 | unsigned char *buffer = (unsigned char *)(((unsigned long)decode_buffer + 32) & (~0x1f)); |
697 | |
698 | char value[PROPERTY_VALUE_MAX]={0}; |
699 | audec = (aml_audio_dec_t *)args; |
700 | alsa_params = (alsa_param_t *)audec->aout_ops.private_data; |
701 | |
702 | // bootplayer default volume configuration |
703 | if (property_get("media.amplayer.boot_vol",value,NULL) > 0) { |
704 | alsa_default_vol = atof(value); |
705 | if (alsa_default_vol < 0.0 || alsa_default_vol > 1.0 ) { |
706 | adec_print("wrong alsa default volume %f, set to 1.0 \n",alsa_default_vol); |
707 | alsa_default_vol = 1.0; |
708 | } |
709 | } |
710 | adec_print("alsa default volume %f \n",alsa_default_vol); |
711 | /* pthread_mutex_init(&alsa_params->playback_mutex, NULL); |
712 | pthread_cond_init(&alsa_params->playback_cond, NULL);*/ |
713 | |
714 | while (!alsa_params->wait_flag && alsa_params->stop_flag == 0) { |
715 | amthreadpool_thread_usleep(10000); |
716 | } |
717 | |
718 | adec_print("alsa playback loop start to run !\n"); |
719 | |
720 | while (!alsa_params->stop_flag) { |
721 | #if 0 |
722 | if (hdmi_out == 0) { |
723 | adec_print("===dynmiac get hdmi plugin state===\n"); |
724 | if (alsa_get_hdmi_state() == 1) { |
725 | if (alsa_swtich_port(alsa_params, alsa_get_aml_card(), alsa_get_spdif_port()) == -1) { |
726 | adec_print("switch to hdmi port failed.\n"); |
727 | goto exit; |
728 | } |
729 | |
730 | hdmi_out = 1; |
731 | adec_print("[%s,%d]get hdmi device, use hdmi device \n", __FUNCTION__, __LINE__); |
732 | } |
733 | } else if (alsa_get_hdmi_state() == 0) { |
734 | if (alsa_swtich_port(alsa_params, alsa_get_aml_card(), 0) == -1) { |
735 | adec_print("switch to default port failed.\n"); |
736 | goto exit; |
737 | } |
738 | |
739 | hdmi_out = 0; |
740 | adec_print("[%s,%d]get default device, use default device \n", __FUNCTION__, __LINE__); |
741 | } |
742 | #endif |
743 | while ((len < (128 * 2)) && (!alsa_params->stop_flag)) { |
744 | if (offset > 0) { |
745 | memcpy(buffer, buffer + offset, len); |
746 | } |
747 | len2 = audec->adsp_ops.dsp_read(&audec->adsp_ops, (buffer + len), (OUTPUT_BUFFER_SIZE - len)); |
748 | len = len + len2; |
749 | offset = 0; |
750 | } |
751 | audec->pcm_bytes_readed += len; |
752 | while (alsa_params->pause_flag) { |
753 | amthreadpool_thread_usleep(10000); |
754 | } |
755 | if (alsa_params->stop_flag) { |
756 | goto exit; |
757 | } |
758 | adec_refresh_pts(audec); |
759 | |
760 | len2 = alsa_play(alsa_params, (buffer + offset), len); |
761 | if (len2 >= 0) { |
762 | len -= len2; |
763 | offset += len2; |
764 | } else { |
765 | len = 0; |
766 | offset = 0; |
767 | } |
768 | } |
769 | exit: |
770 | adec_print("Exit alsa playback loop !\n"); |
771 | pthread_exit(NULL); |
772 | return NULL; |
773 | } |
774 | |
775 | /** |
776 | * \brief output initialization |
777 | * \param audec pointer to audec |
778 | * \return 0 on success otherwise negative error code |
779 | */ |
780 | int alsa_init(struct aml_audio_dec* audec) |
781 | { |
782 | adec_print("alsa out init"); |
783 | char sound_card_dev[10] = {0}; |
784 | int sound_card_id = 0; |
785 | int sound_dev_id = 0; |
786 | int err; |
787 | pthread_t tid; |
788 | alsa_param_t *alsa_param; |
789 | audio_out_operations_t *out_ops = &audec->aout_ops; |
790 | tv_mode = getprop_bool("ro.platform.has.tvuimode"); |
791 | alsa_param = (alsa_param_t *)malloc(sizeof(alsa_param_t)); |
792 | if (!alsa_param) { |
793 | adec_print("alloc alsa_param failed, not enough memory!"); |
794 | return -1; |
795 | } |
796 | memset(alsa_param, 0, sizeof(alsa_param_t)); |
797 | |
798 | if (audec->samplerate >= (88200 + 96000) / 2) { |
799 | alsa_param->flag = 1; |
800 | alsa_param->oversample = -1; |
801 | alsa_param->rate = 48000; |
802 | } else if (audec->samplerate >= (64000 + 88200) / 2) { |
803 | alsa_param->flag = 1; |
804 | alsa_param->oversample = -1; |
805 | alsa_param->rate = 44100; |
806 | } else if (audec->samplerate >= (48000 + 64000) / 2) { |
807 | alsa_param->flag = 1; |
808 | alsa_param->oversample = -1; |
809 | alsa_param->rate = 32000; |
810 | } else if (audec->samplerate >= (44100 + 48000) / 2) { |
811 | alsa_param->oversample = 0; |
812 | alsa_param->rate = 48000; |
813 | if (audec->channels == 1) { |
814 | alsa_param->flag = 1; |
815 | } else if (audec->channels == 2) { |
816 | alsa_param->flag = 0; |
817 | } |
818 | } else if (audec->samplerate >= (32000 + 44100) / 2) { |
819 | alsa_param->oversample = 0; |
820 | alsa_param->rate = 44100; |
821 | if (audec->channels == 1) { |
822 | alsa_param->flag = 1; |
823 | } else if (audec->channels == 2) { |
824 | alsa_param->flag = 0; |
825 | } |
826 | } else if (audec->samplerate >= (24000 + 32000) / 2) { |
827 | alsa_param->oversample = 0; |
828 | alsa_param->rate = 32000; |
829 | if (audec->channels == 1) { |
830 | alsa_param->flag = 1; |
831 | } else if (audec->channels == 2) { |
832 | alsa_param->flag = 0; |
833 | } |
834 | } else if (audec->samplerate >= (22050 + 24000) / 2) { |
835 | alsa_param->flag = 1; |
836 | alsa_param->oversample = 1; |
837 | alsa_param->rate = 48000; |
838 | } else if (audec->samplerate >= (16000 + 22050) / 2) { |
839 | alsa_param->flag = 1; |
840 | alsa_param->oversample = 1; |
841 | alsa_param->rate = 44100; |
842 | } else if (audec->samplerate >= (12000 + 16000) / 2) { |
843 | alsa_param->flag = 1; |
844 | alsa_param->oversample = 1; |
845 | alsa_param->rate = 32000; |
846 | } else if (audec->samplerate >= (11025 + 12000) / 2) { |
847 | alsa_param->flag = 1; |
848 | alsa_param->oversample = 2; |
849 | alsa_param->rate = 48000; |
850 | } else if (audec->samplerate >= (8000 + 11025) / 2) { |
851 | alsa_param->flag = 1; |
852 | alsa_param->oversample = 2; |
853 | alsa_param->rate = 44100; |
854 | } else { |
855 | alsa_param->flag = 1; |
856 | alsa_param->oversample = 2; |
857 | alsa_param->rate = 32000; |
858 | } |
859 | |
860 | alsa_param->channelcount = 2; |
861 | alsa_param->realchanl = audec->channels; |
862 | //alsa_param->rate = audec->samplerate; |
863 | alsa_param->format = SND_PCM_FORMAT_S16_LE; |
864 | alsa_param->wait_flag = 0; |
865 | |
866 | #ifdef USE_INTERPOLATION |
867 | memset(pass1_history, 0, 64 * sizeof(int)); |
868 | memset(pass2_history, 0, 64 * sizeof(int)); |
869 | #endif |
870 | |
871 | sound_card_id = alsa_get_aml_card(); |
872 | if (sound_card_id < 0) { |
873 | sound_card_id = 0; |
874 | adec_print("get aml card fail, use default \n"); |
875 | } |
876 | #if 0 |
877 | if (alsa_get_hdmi_state() == 1) { |
878 | sound_dev_id = alsa_get_spdif_port(); |
879 | if (sound_dev_id < 0) { |
880 | sound_dev_id = 0; |
881 | adec_print("get aml card device fail, use default \n"); |
882 | } else { |
883 | hdmi_out = 1; |
884 | } |
885 | adec_print("get hdmi device, use hdmi device \n"); |
886 | } |
887 | #endif |
888 | sprintf(sound_card_dev, "hw:%d,%d", sound_card_id, sound_dev_id); |
889 | err = snd_pcm_open(&alsa_param->handle, sound_card_dev, SND_PCM_STREAM_PLAYBACK, 0); |
890 | if (err < 0) { |
891 | adec_print("audio open error: %s", snd_strerror(err)); |
892 | return -1; |
893 | } |
894 | readi_func = snd_pcm_readi; |
895 | writei_func = snd_pcm_writei; |
896 | readn_func = snd_pcm_readn; |
897 | writen_func = snd_pcm_writen; |
898 | |
899 | set_params(alsa_param); |
900 | |
901 | out_ops->private_data = (void *)alsa_param; |
902 | |
903 | /*TODO: create play thread */ |
904 | pthread_mutex_init(&alsa_param->playback_mutex, NULL); |
905 | pthread_cond_init(&alsa_param->playback_cond, NULL); |
906 | err = amthreadpool_pthread_create(&tid, NULL, (void *)alsa_playback_loop, (void *)audec); |
907 | if (err != 0) { |
908 | adec_print("alsa_playback_loop thread create failed!"); |
909 | snd_pcm_close(alsa_param->handle); |
910 | return -1; |
911 | } |
912 | pthread_setname_np(tid, "ALSAOUTLOOP"); |
913 | |
914 | adec_print("Create alsa playback loop thread success ! tid = %d\n", tid); |
915 | |
916 | alsa_param->playback_tid = tid; |
917 | |
918 | return 0; |
919 | } |
920 | |
921 | /** |
922 | * \brief start output |
923 | * \param audec pointer to audec |
924 | * \return 0 on success otherwise negative error code |
925 | * |
926 | * Call alsa_start(), then the callback will start being called. |
927 | */ |
928 | int alsa_start(struct aml_audio_dec* audec) |
929 | { |
930 | adec_print("alsa out start!\n"); |
931 | |
932 | audio_out_operations_t *out_ops = &audec->aout_ops; |
933 | alsa_param_t *alsa_param = (alsa_param_t *)out_ops->private_data; |
934 | |
935 | pthread_mutex_lock(&alsa_param->playback_mutex); |
936 | adec_print("yvonne pthread_cond_signalalsa_param->wait_flag=1\n"); |
937 | alsa_param->wait_flag = 1; //yvonneadded |
938 | pthread_cond_signal(&alsa_param->playback_cond); |
939 | pthread_mutex_unlock(&alsa_param->playback_mutex); |
940 | adec_print("exit alsa out start!\n"); |
941 | |
942 | return 0; |
943 | } |
944 | |
945 | /** |
946 | * \brief pause output |
947 | * \param audec pointer to audec |
948 | * \return 0 on success otherwise negative error code |
949 | */ |
950 | int alsa_pause(struct aml_audio_dec* audec) |
951 | { |
952 | adec_print("alsa out pause\n"); |
953 | |
954 | int res; |
955 | alsa_param_t *alsa_params; |
956 | |
957 | alsa_params = (alsa_param_t *)audec->aout_ops.private_data; |
958 | pthread_mutex_lock(&alsa_params->playback_mutex); |
959 | |
960 | alsa_params->pause_flag = 1; |
961 | while ((res = snd_pcm_pause(alsa_params->handle, 1)) == -EAGAIN) { |
962 | sleep(1); |
963 | } |
964 | pthread_mutex_unlock(&alsa_params->playback_mutex); |
965 | adec_print("exit alsa out pause\n"); |
966 | |
967 | return res; |
968 | } |
969 | |
970 | /** |
971 | * \brief resume output |
972 | * \param audec pointer to audec |
973 | * \return 0 on success otherwise negative error code |
974 | */ |
975 | int alsa_resume(struct aml_audio_dec* audec) |
976 | { |
977 | adec_print("alsa out rsume\n"); |
978 | |
979 | int res; |
980 | alsa_param_t *alsa_params; |
981 | |
982 | alsa_params = (alsa_param_t *)audec->aout_ops.private_data; |
983 | pthread_mutex_lock(&alsa_params->playback_mutex); |
984 | |
985 | alsa_params->pause_flag = 0; |
986 | while ((res = snd_pcm_pause(alsa_params->handle, 0)) == -EAGAIN) { |
987 | sleep(1); |
988 | } |
989 | pthread_mutex_unlock(&alsa_params->playback_mutex); |
990 | |
991 | return res; |
992 | } |
993 | |
994 | /** |
995 | * \brief stop output |
996 | * \param audec pointer to audec |
997 | * \return 0 on success otherwise negative error code |
998 | */ |
999 | int alsa_stop(struct aml_audio_dec* audec) |
1000 | { |
1001 | adec_print("enter alsa out stop\n"); |
1002 | |
1003 | alsa_param_t *alsa_params; |
1004 | |
1005 | alsa_params = (alsa_param_t *)audec->aout_ops.private_data; |
1006 | pthread_mutex_lock(&alsa_params->playback_mutex); |
1007 | alsa_params->pause_flag = 0; |
1008 | alsa_params->stop_flag = 1; |
1009 | //alsa_params->wait_flag = 0; |
1010 | pthread_cond_signal(&alsa_params->playback_cond); |
1011 | amthreadpool_pthread_join(alsa_params->playback_tid, NULL); |
1012 | pthread_cond_destroy(&alsa_params->playback_cond); |
1013 | |
1014 | |
1015 | snd_pcm_drop(alsa_params->handle); |
1016 | snd_pcm_close(alsa_params->handle); |
1017 | pthread_mutex_unlock(&alsa_params->playback_mutex); |
1018 | pthread_mutex_destroy(&alsa_params->playback_mutex); |
1019 | |
1020 | free(alsa_params); |
1021 | audec->aout_ops.private_data = NULL; |
1022 | adec_print("exit alsa out stop\n"); |
1023 | |
1024 | return 0; |
1025 | } |
1026 | |
1027 | static int alsa_get_space(alsa_param_t * alsa_param) |
1028 | { |
1029 | snd_pcm_status_t *status; |
1030 | int ret; |
1031 | int bits_per_sample = alsa_param->bits_per_sample; |
1032 | snd_pcm_status_alloca(&status); |
1033 | if ((ret = snd_pcm_status(alsa_param->handle, status)) < 0) { |
1034 | adec_print("Cannot get pcm status \n"); |
1035 | return 0; |
1036 | } |
1037 | ret = snd_pcm_status_get_avail(status) * alsa_param->bits_per_sample / 8; |
1038 | if (ret > alsa_param->buffer_size) { |
1039 | ret = alsa_param->buffer_size; |
1040 | } |
1041 | return ret; |
1042 | } |
1043 | |
1044 | /** |
1045 | * \brief get output latency in ms |
1046 | * \param audec pointer to audec |
1047 | * \return output latency |
1048 | */ |
1049 | unsigned long alsa_latency(struct aml_audio_dec* audec) |
1050 | { |
1051 | int buffered_data; |
1052 | int sample_num; |
1053 | alsa_param_t *alsa_param = (alsa_param_t *)audec->aout_ops.private_data; |
1054 | int bits_per_sample = alsa_param->bits_per_sample; |
1055 | if (tv_mode) { |
1056 | bits_per_sample = bits_per_sample*4; |
1057 | } |
1058 | buffered_data = alsa_param->buffer_size - alsa_get_space(alsa_param); |
1059 | sample_num = buffered_data / (alsa_param->channelcount * (bits_per_sample / 8)); /*16/2*/ |
1060 | return ((sample_num * 1000) / alsa_param->rate); |
1061 | } |
1062 | |
1063 | static int alsa_mute(struct aml_audio_dec* audec, adec_bool_t en) |
1064 | { |
1065 | return 0; |
1066 | } |
1067 | /** |
1068 | * \brief get output handle |
1069 | * \param audec pointer to audec |
1070 | */ |
1071 | void get_output_func(struct aml_audio_dec* audec) |
1072 | { |
1073 | audio_out_operations_t *out_ops = &audec->aout_ops; |
1074 | |
1075 | out_ops->init = alsa_init; |
1076 | out_ops->start = alsa_start; |
1077 | out_ops->pause = alsa_pause; |
1078 | out_ops->resume = alsa_resume; |
1079 | out_ops->mute = alsa_mute; |
1080 | out_ops->stop = alsa_stop; |
1081 | out_ops->latency = alsa_latency; |
1082 | } |
1083 |