avsynclib: support vmaster trickplay with makeup PTS from App [1/1]

PD#TV-52104

Problem:
Support video PTS big gap during trickplay

Solution:
When big video PTS gap is detected, increase the wall clock adjust
threshold

Verify:
TM2 + LLama + Linear channel

Change-Id: I20362c7b5e49eeefd1cc0395a92ac36535906c81
diff --git a/src/avsync.c b/src/avsync.c
index 91a0232..e3fd905 100644
--- a/src/avsync.c
+++ b/src/avsync.c
@@ -164,6 +164,7 @@
 #define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
 #define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
 #define LIVE_MODE(m) ((m) == AV_SYNC_MODE_PCR_MASTER || (m) == AV_SYNC_MODE_IPTV)
+#define V_DISC_MODE(mode) (LIVE_MODE(mode) || (mode) == AV_SYNC_MODE_VMASTER)
 
 #define STREAM_DISC_THRES (TIME_UNIT90K / 10)
 #define OUTLIER_MAX_CNT 8
@@ -326,6 +327,8 @@
     if (!attach) {
         msync_session_set_mode(avsync->fd, mode);
         avsync->mode = mode;
+        if (avsync->mode == AV_SYNC_MODE_VMASTER)
+            msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
     } else {
         avsync->attached = true;
         if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
@@ -595,6 +598,22 @@
     }
 
     if (avsync->last_q_pts != -1) {
+        if (frame->pts != -1 && avsync->mode == AV_SYNC_MODE_VMASTER) {
+            /* Sometimes app will fake PTS for trickplay, video PTS gap
+             * is really big depending on the speed. Have to adjust the
+             * threshold dynamically.
+             */
+            int gap = (int)(frame->pts - avsync->last_q_pts);
+            if (gap > avsync->disc_thres_min) {
+                avsync->disc_thres_min = gap * 6;
+                avsync->disc_thres_max = gap * 20;
+                msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
+                msync_session_set_disc_thres(avsync->session_id,
+                        avsync->disc_thres_min, avsync->disc_thres_max);
+                log_info("[%d] update disc_thres to %d/%d",avsync->session_id,
+                        avsync->disc_thres_min, avsync->disc_thres_max);
+            }
+        }
         if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
             /* TODO: wrong, should remove from back of queue */
             dqueue_item(avsync->frame_q, (void **)&prev);
@@ -839,8 +858,7 @@
     if (next_frame)
         nfpts = next_frame->pts + avsync->extra_delay;
 
-    if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
-            avsync->mode == AV_SYNC_MODE_VMASTER) {
+    if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
         /* We need to ensure that the video outputs smoothly,
         so output video frame by frame hold_period */
         if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
@@ -911,7 +929,7 @@
         avsync->phase = 0;
         reset_pattern(avsync->pattern_detector);
 
-        if (LIVE_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
+        if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
             log_info ("[%d]video disc %u --> %u",
                 avsync->session_id, systime, fpts);
             msync_session_set_video_dis(avsync->fd, fpts);
diff --git a/src/msync_util.c b/src/msync_util.c
index 8a9c5c8..4c77db4 100644
--- a/src/msync_util.c
+++ b/src/msync_util.c
@@ -415,6 +415,16 @@
     return rc;
 }
 
+int msync_session_set_wall_adj_thres(int fd, int32_t thres)
+{
+    int rc;
+
+    rc = ioctl(fd, AMSYNCS_IOC_SET_WALL_ADJ_THRES, &thres);
+    if (rc)
+        log_error("session[%d] set wall adj thres errno:%d", fd, errno);
+    return rc;
+}
+
 static int get_sysfs_uint32(const char *path, uint32_t *value)
 {
     int fd;
@@ -425,7 +435,7 @@
     if (fd >= 0) {
         memset(valstr, 0, 64);
         read(fd, valstr, 64 - 1);
-        valstr[strlen(valstr)] = '\0';
+        valstr[strnlen(valstr, sizeof(valstr))] = '\0';
         close(fd);
     } else {
         log_error("unable to open file %s\n", path);
@@ -457,3 +467,41 @@
 
     return 0;
 }
+
+static int set_sysfs_uint32(const char *path, uint32_t value)
+{
+    int fd, ret = 0;
+    char valstr[64];
+
+    fd = open(path, O_RDWR);
+    snprintf(valstr, sizeof(valstr), "%d", value);
+    if (fd >= 0) {
+        ret = write(fd, valstr, strnlen(valstr, sizeof(valstr)));
+        if (ret >= 0)
+            ret = 0;
+        close(fd);
+    } else {
+        log_error("unable to open file %s\n", path);
+        return -1;
+    }
+    return ret;
+}
+
+int msync_session_set_disc_thres(int session_id, uint32_t min, uint32_t max)
+{
+    char name[64];
+
+    if (snprintf(name, sizeof(name),
+            "/sys/class/avsync_session%d/disc_thres_min", session_id) < 0)
+        return -1;
+    if (set_sysfs_uint32(name, min))
+        return -1;
+
+    if (snprintf(name, sizeof(name),
+            "/sys/class/avsync_session%d/disc_thres_max", session_id) < 0)
+        return -1;
+    if (set_sysfs_uint32(name, max))
+        return -1;
+
+    return 0;
+}
diff --git a/src/msync_util.h b/src/msync_util.h
index c9bf085..1c8544d 100644
--- a/src/msync_util.h
+++ b/src/msync_util.h
@@ -60,5 +60,7 @@
 int msync_session_set_audio_switch(int fd, bool start);
 int msync_session_get_clock_dev(int fd, int32_t *ppm);
 int msync_session_set_clock_dev(int fd, int32_t ppm);
+int msync_session_set_wall_adj_thres(int fd, int32_t thres);
 int msync_session_get_disc_thres(int session_id, uint32_t *min, uint32_t *max);
+int msync_session_set_disc_thres(int session_id, uint32_t min, uint32_t max);
 #endif