avsync-lib: support underflow detection [3/3]
PD#TV-45115
Problem:
New feature requirment for vsink
Solution:
added underflow detection call back
Verify:
T5D + Roxton + NTS
Change-Id: I9fa3fe9e6b5a942221415b03fd29aff9d02236fa
Signed-off-by: yongchun.li <yongchun.li@amlogic.com>
diff --git a/src/aml_avsync.h b/src/aml_avsync.h
index c8eacea..2743768 100644
--- a/src/aml_avsync.h
+++ b/src/aml_avsync.h
@@ -60,6 +60,7 @@
struct vframe;
typedef void (*free_frame)(struct vframe * frame);
typedef void (*pause_pts_done)(uint32_t pts, void* priv);
+typedef void (*underflow_detected)(uint32_t pts, void* priv);
typedef enum {
/* good to render */
@@ -135,6 +136,9 @@
/*timeout in ms */
int timeout;
};
+struct underflow_config {
+ int time_thresh; /* underflow check time threshold in ms */
+};
/* Open a new session and create the ID
* Params:
@@ -423,4 +427,16 @@
* CLK_RECOVERY_ERR: error happens
*/
enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm);
+
+/* set underflow detect call back
+ * av sync will callback when a buffer underflow detected when normal play
+ * Params:
+ * @sync: AV sync module handle
+ * @cb: callback function
+ * @priv: callback function parameter
+ * @cfg: the configuration of the call back, NULL use default value.
+ * Return:
+ * 0 for OK, or error code
+ */
+int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg);
#endif
diff --git a/src/avsync.c b/src/avsync.c
index 8ee61b9..b265f9b 100644
--- a/src/avsync.c
+++ b/src/avsync.c
@@ -104,6 +104,11 @@
pts90K pause_pts;
pause_pts_done pause_pts_cb;
void *pause_cb_priv;
+ /* underflow */
+ underflow_detected underflow_cb;
+ void *underflow_cb_priv;
+ struct underflow_config underflow_cfg;
+ struct timespec frame_last_update_time;
/* log control */
uint32_t last_log_syst;
@@ -163,6 +168,7 @@
#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
#define OUTLIER_MAX_CNT 8
#define VALID_TS(x) ((x) != -1)
+#define UNDERFLOW_CHECK_THRESH_MS (100)
static uint64_t time_diff (struct timespec *b, struct timespec *a);
static bool frame_expire(struct av_sync_session* avsync,
@@ -535,7 +541,10 @@
avsync->paused = pause;
log_info("[%d]paused:%d type:%d rc %d",
avsync->session_id, pause, avsync->type, rc);
-
+ if (!avsync->paused && avsync->first_frame_toggled) {
+ clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
+ log_info("[%d] resume update new frame time", avsync->session_id);
+ }
return rc;
}
@@ -717,6 +726,7 @@
}
avsync->last_frame = frame;
avsync->last_pts = frame->pts;
+ clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
} else
break;
}
@@ -746,6 +756,26 @@
exit:
pthread_mutex_unlock(&avsync->lock);
+
+ /* underflow check */
+ if (avsync->session_started && avsync->first_frame_toggled &&
+ (avsync->paused == false) && (avsync->state >= AV_SYNC_STAT_RUNNING) &&
+ avsync->underflow_cb && peek_item(avsync->frame_q, (void **)&frame, 0))
+ {/* empty queue in normal play */
+ struct timespec now;
+ int diff_ms;
+ clock_gettime(CLOCK_MONOTONIC_RAW, &now);
+ diff_ms = time_diff(&now, &avsync->frame_last_update_time)/1000;
+ if(diff_ms >= (avsync->underflow_cfg.time_thresh
+ + avsync->vsync_interval*avsync->last_holding_peroid/90)) {
+ log_info ("[%d]underflow detected: %u", avsync->session_id, avsync->last_pts);
+ avsync->underflow_cb (avsync->last_pts,
+ avsync->underflow_cb_priv);
+ /* update time to control the underflow check call backs */
+ avsync->frame_last_update_time = now;
+ }
+ }
+
if (avsync->last_frame) {
if (enter_last_frame != avsync->last_frame)
log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
@@ -1083,6 +1113,26 @@
return 0;
}
+int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
+{
+ struct av_sync_session *avsync = (struct av_sync_session *)sync;
+
+ if (!avsync)
+ return -1;
+
+ avsync->underflow_cb = cb;
+ avsync->underflow_cb_priv = priv;
+
+ if (cfg)
+ avsync->underflow_cfg.time_thresh = cfg->time_thresh;
+ else
+ avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
+
+ log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
+ avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
+ avsync->underflow_cfg.time_thresh);
+ return 0;
+}
static void trigger_audio_start_cb(struct av_sync_session *avsync,
avs_ascb_reason reason)
{