blob: 12f49725d9ecce83867daa0f4a8861b4cdf8b7a3
1 | #define LOG_TAG "audio_hwsync" |
2 | #include <errno.h> |
3 | #include <pthread.h> |
4 | #include <stdint.h> |
5 | #include <sys/time.h> |
6 | #include <stdlib.h> |
7 | #include <sys/stat.h> |
8 | #include <fcntl.h> |
9 | #include <time.h> |
10 | #include <utils/Timers.h> |
11 | #include <cutils/log.h> |
12 | #include <cutils/str_parms.h> |
13 | #include <cutils/properties.h> |
14 | #include <linux/ioctl.h> |
15 | #include <hardware/hardware.h> |
16 | #include <system/audio.h> |
17 | #include <hardware/audio.h> |
18 | #include <sound/asound.h> |
19 | #include <tinyalsa/asoundlib.h> |
20 | |
21 | #include "audio_hwsync.h" |
22 | #include "audio_hw_utils.h" |
23 | #include "audio_hw.h" |
24 | //#include "hdmi_audio_hw.h" |
25 | static uint32_t aml_hwsync_out_get_latency(const struct audio_stream_out *stream) |
26 | { |
27 | struct aml_stream_out *out = (struct aml_stream_out *)stream; |
28 | uint32_t whole_latency; |
29 | uint32_t ret; |
30 | snd_pcm_sframes_t frames = 0; |
31 | whole_latency = (out->config.period_size * out->config.period_count * 1000) / out->config.rate; |
32 | if (!out->pcm || !pcm_is_ready(out->pcm)) { |
33 | return whole_latency; |
34 | } |
35 | ret = pcm_ioctl(out->pcm, SNDRV_PCM_IOCTL_DELAY, &frames); |
36 | if (ret < 0) { |
37 | return whole_latency; |
38 | } |
39 | if (out->hal_format == AUDIO_FORMAT_E_AC3) { |
40 | frames /= 4; |
41 | } |
42 | return (uint32_t)((frames * 1000) / out->config.rate); |
43 | } |
44 | |
45 | void aml_audio_hwsync_clear_status(struct aml_stream_out *out) |
46 | { |
47 | struct aml_audio_device *adev = out->dev; |
48 | audio_hwsync_t *p_hwsync = &adev->hwsync; |
49 | p_hwsync->first_apts_flag = 0; |
50 | p_hwsync->hw_sync_state = HW_SYNC_STATE_HEADER; |
51 | p_hwsync->hw_sync_header_cnt = 0; |
52 | return; |
53 | } |
54 | //return bytes cost from input, |
55 | int aml_audio_hwsync_find_frame(struct aml_stream_out *out, const void *in_buffer, size_t in_bytes, uint64_t *cur_pts, int *outsize) |
56 | { |
57 | int remain = in_bytes; |
58 | uint8_t *p = in_buffer; |
59 | struct aml_audio_device *adev = out->dev; |
60 | audio_hwsync_t *p_hwsync = &adev->hwsync; |
61 | int time_diff = 0; |
62 | //ALOGI(" --- out_write %d, cache cnt = %d, body = %d, hw_sync_state = %d", out_frames * frame_size, out->body_align_cnt, out->hw_sync_body_cnt, out->hw_sync_state); |
63 | while (remain > 0) { |
64 | //if (p_hwsync->hw_sync_state == HW_SYNC_STATE_RESYNC) { |
65 | //} |
66 | if (p_hwsync->hw_sync_state == HW_SYNC_STATE_HEADER) { |
67 | //ALOGI("Add to header buffer [%d], 0x%x", out->hw_sync_header_cnt, *p); |
68 | p_hwsync->hw_sync_header[p_hwsync->hw_sync_header_cnt++] = *p++; |
69 | remain--; |
70 | if (p_hwsync->hw_sync_header_cnt == 16) { |
71 | uint64_t pts; |
72 | if (!hwsync_header_valid(&p_hwsync->hw_sync_header[0])) { |
73 | //ALOGE("!!!!!!hwsync header out of sync! Resync.should not happen????"); |
74 | p_hwsync->hw_sync_state = HW_SYNC_STATE_HEADER; |
75 | memcpy(p_hwsync->hw_sync_header, p_hwsync->hw_sync_header + 1, 15); |
76 | p_hwsync->hw_sync_header_cnt--; |
77 | continue; |
78 | } |
79 | if ((in_bytes-remain) > 16) |
80 | ALOGI("got the frame sync header cost %d\n",in_bytes-remain); |
81 | p_hwsync->hw_sync_state = HW_SYNC_STATE_BODY; |
82 | p_hwsync->hw_sync_body_cnt = hwsync_header_get_size(&p_hwsync->hw_sync_header[0]); |
83 | p_hwsync->hw_sync_frame_size = p_hwsync->hw_sync_body_cnt; |
84 | p_hwsync->body_align_cnt = 0; |
85 | pts = hwsync_header_get_pts(&p_hwsync->hw_sync_header[0]); |
86 | //memcpy(write_buf+write_pos,&p_hwsync->hw_sync_header[0],16); |
87 | //write_pos += 16; |
88 | pts = pts * 90 / 1000000; |
89 | time_diff = (abs(pts - p_hwsync->last_apts_from_header)) / 90; |
90 | ALOGV("pts %llx,frame len %d\n", pts, p_hwsync->hw_sync_body_cnt); |
91 | ALOGV("last pts %llx,diff %d ms\n", p_hwsync->last_apts_from_header, time_diff); |
92 | |
93 | if (time_diff > 32) { |
94 | ALOGI("pts time gap %d ms,last %llx,cur %llx\n", time_diff, |
95 | p_hwsync->last_apts_from_header, pts); |
96 | } |
97 | p_hwsync->last_apts_from_header = pts; |
98 | *cur_pts = pts; |
99 | //ALOGI("get header body_cnt = %d, pts = %lld", out->hw_sync_body_cnt, pts); |
100 | } |
101 | continue; |
102 | } else if (p_hwsync->hw_sync_state == HW_SYNC_STATE_BODY) { |
103 | int m = (p_hwsync->hw_sync_body_cnt < remain) ? p_hwsync->hw_sync_body_cnt : remain; |
104 | //ALOGI("m = %d", m); |
105 | // process m bytes body with an empty fragment for alignment |
106 | if (m > 0) { |
107 | //ret = pcm_write(out->pcm, p, m - align); |
108 | memcpy(p_hwsync->hw_sync_body_buf + p_hwsync->hw_sync_frame_size - p_hwsync->hw_sync_body_cnt, p, m); |
109 | p += m; |
110 | remain -= m; |
111 | //ALOGI("pcm_write %d, remain %d", m - align, remain); |
112 | p_hwsync->hw_sync_body_cnt -= m; |
113 | if (p_hwsync->hw_sync_body_cnt == 0) { |
114 | p_hwsync->hw_sync_state = HW_SYNC_STATE_HEADER; |
115 | p_hwsync->hw_sync_header_cnt = 0; |
116 | *outsize = p_hwsync->hw_sync_frame_size; |
117 | ALOGV("we found the frame total body,yeah\n"); |
118 | break;//continue; |
119 | } |
120 | } |
121 | } |
122 | } |
123 | return in_bytes - remain; |
124 | } |
125 |