avsync-lib: support PCR master mode [2/4]
Change-Id: I7203cfa73f7e6a202218514b6272aeed1eee8841
diff --git a/src/aml_avsync.h b/src/aml_avsync.h
index 12bfa82..4c595aa 100644
--- a/src/aml_avsync.h
+++ b/src/aml_avsync.h
@@ -62,6 +62,7 @@
typedef enum {
AV_SYNC_ASTART_SYNC = 0,
AV_SYNC_ASTART_ASYNC,
+ AV_SYNC_ASTART_AGAIN,
AV_SYNC_ASTART_ERR
} avs_start_ret;
@@ -80,6 +81,7 @@
/* delta between apts and ideal render position
* positive means apts is behind wall clock
* negative means apts is ahead of wall clock
+ * 0 is only valid for AV_SYNC_AA_DROP, drop current chunk
*/
int delta;
};
@@ -216,7 +218,7 @@
struct vframe *av_sync_pop_frame(void *sync);
/* Audio start control. Audio render need to check return value and
- * do sync or async start.
+ * do sync or async start. NOT thread safe.
* Params:
* @sync: AV sync module handle
* @pts: first audio pts
@@ -226,6 +228,7 @@
* Return:
* AV_SYNC_ASTART_SYNC, audio can start render ASAP. No need to wait for callback.
* AV_SYNC_ASTART_ASYNC, audio need to block until callback is triggered.
+ * AV_SYNC_ASTART_AGAIN, discard current audio chunk and call this API again.
* AV_SYNC_ASTART_ERR, something bad happens
*/
avs_start_ret av_sync_audio_start(
@@ -236,6 +239,7 @@
void *priv);
/* Audio render policy. Indicate render action and the difference from ideal position
+ * NOT thread safe.
* Params:
* @sync: AV sync module handle
* @pts: curent audio pts (considering delay)
@@ -303,12 +307,22 @@
* Params:
* @sync: AV sync module handle
* @pts: PCR clock
+ * @mono_clock: system monotonic clock receiving the pts
* Return:
* 0 for OK, or error code
*/
-int av_sync_set_pcr_clock(void *sync, pts90K pts);
+int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock);
-int av_sync_get_pcr_clock(void *sync, pts90K *pts);
+/* Get PCR clock pair.
+ * Use for clock recovery
+ * Params:
+ * @sync: AV sync module handle
+ * @pts: PCR clock pointer
+ * @mono_clock: system monotonic clock pointer receiving the pts
+ * Return:
+ * 0 for OK, or error code
+ */
+int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t *mono_clock);
/* get wall clock
* Params:
diff --git a/src/avsync.c b/src/avsync.c
index 52adfa5..e30dc51 100644
--- a/src/avsync.c
+++ b/src/avsync.c
@@ -85,14 +85,6 @@
float speed;
-#if 0
- /*pip sync, remove after multi instance is supported*/
- struct timeval base_sys_time;
- struct timeval pause_start;
- uint64_t pause_duration;
- pts90K first_pts;
-#endif
-
/* pause pts */
pts90K pause_pts;
pause_pts_done pause_pts_cb;
@@ -110,14 +102,20 @@
/* error detection */
uint32_t last_poptime;
+ uint32_t outlier_cnt;
};
#define MAX_FRAME_NUM 32
#define DEFAULT_START_THRESHOLD 2
#define TIME_UNIT90K (90000)
-#define AV_DISCONTINUE_THREDHOLD_MIN (TIME_UNIT90K / 3)
-#define A_ADJ_THREDHOLD (TIME_UNIT90K/10)
+#define AV_DISC_THRES_MIN (TIME_UNIT90K * 3)
+#define A_ADJ_THREDHOLD_HB (TIME_UNIT90K/10)
+#define A_ADJ_THREDHOLD_LB (TIME_UNIT90K/40)
#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
+#define LIVE_MODE(mode) ((mode) == AV_SYNC_MODE_PCR_MASTER || (mode) == AV_SYNC_MODE_IPTV)
+
+#define STREAM_DISC_THRES (TIME_UNIT90K * 10)
+#define OUTLIER_MAX_CNT 8
static uint64_t time_diff (struct timeval *b, struct timeval *a);
static bool frame_expire(struct av_sync_session* avsync,
@@ -400,7 +398,7 @@
}
if (!peek_item(avsync->frame_q, (void **)&prev, 0)) {
- if (prev->pts == frame->pts) {
+ if (prev->pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
dqueue_item(avsync->frame_q, (void **)&prev);
prev->free(prev);
log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
@@ -433,7 +431,7 @@
pthread_mutex_lock(&avsync->lock);
if (avsync->state == AV_SYNC_STAT_INIT) {
- log_trace("[%d]in state INIT", avsync->session_id);
+ log_info("[%d]in state INIT", avsync->session_id);
goto exit;
}
@@ -569,6 +567,9 @@
bool expire = false;
uint32_t pts_correction = avsync->delay * interval;
+ if (avsync->mode == AV_SYNC_MODE_FREE_RUN)
+ return true;
+
if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
return false;
@@ -592,7 +593,7 @@
log_trace("[%d]systime:%u phase:%u correct:%u fpts:%u",
avsync->session_id, systime,
avsync->phase_set?avsync->phase:0, pts_correction, fpts);
- if (abs_diff(systime, fpts) > AV_DISCONTINUE_THREDHOLD_MIN &&
+ if (abs_diff(systime, fpts) > AV_DISC_THRES_MIN &&
avsync->first_frame_toggled) {
/* ignore discontinity under pause */
if (avsync->paused)
@@ -613,25 +614,36 @@
} else
avsync->sync_lost_cnt++;
}
+
+ if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
+ LIVE_MODE(avsync->mode) &&
+ abs_diff(systime, fpts) > STREAM_DISC_THRES) {
+ /* outlier by stream error */
+ avsync->outlier_cnt++;
+ if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
+ log_info("render outlier %u", fpts);
+ return true;
+ }
+ }
+
+ avsync->outlier_cnt = 0;
avsync->state = AV_SYNC_STAT_SYNC_LOST;
avsync->phase_set = false;
reset_pattern(avsync->pattern_detector);
if ((int)(systime - fpts) > 0) {
- if (frame->pts && avsync->mode == AV_SYNC_MODE_VMASTER) {
+ if (LIVE_MODE(avsync->mode)) {
log_info ("[%d]video disc %u --> %u",
avsync->session_id, systime, fpts);
msync_session_set_video_dis(avsync->fd, frame->pts);
}
- /*catch up PCR */
+ /* catch up PCR */
return true;
- } else if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
- avsync->mode == AV_SYNC_MODE_IPTV) {
+ } else if (LIVE_MODE(avsync->mode)) {
/* vpts wrapping */
- if (frame->pts)
- msync_session_set_video_dis(avsync->fd, frame->pts);
- else
- msync_session_set_video_dis(avsync->fd, fpts);
- return true;
+ log_info ("[%d]video disc %u --> %u",
+ avsync->session_id, systime, fpts);
+ msync_session_set_video_dis(avsync->fd, frame->pts);
+ return false;
}
}
@@ -818,13 +830,19 @@
if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
log_error("[%d]fail to set audio start", avsync->session_id);
- avsync->state = AV_SYNC_STAT_RUNNING;
if (start_mode == AVS_START_SYNC) {
ret = AV_SYNC_ASTART_SYNC;
avsync->session_started = true;
avsync->state = AV_SYNC_STAT_SYNC_SETUP;
- } else if (start_mode == AVS_START_ASYNC)
+ } else if (start_mode == AVS_START_ASYNC) {
ret = AV_SYNC_ASTART_ASYNC;
+ avsync->state = AV_SYNC_STAT_RUNNING;
+ } else if (start_mode == AVS_START_AGAIN) {
+ ret = AV_SYNC_ASTART_AGAIN;
+ }
+
+ if (ret == AV_SYNC_ASTART_AGAIN)
+ goto exit;
if (avsync->mode == AV_SYNC_MODE_AMASTER) {
create_poll_t = true;
@@ -836,10 +854,10 @@
avsync->audio_start = cb;
avsync->audio_start_priv = priv;
}
- } else if (avsync->mode == AV_SYNC_MODE_PCR_MASTER || start_mode == AV_SYNC_MODE_IPTV)
+ } else if (LIVE_MODE(avsync->mode))
create_poll_t = true;
- if (create_poll_t) {
+ if (create_poll_t && !avsync->poll_thread) {
int ret;
log_info("[%d]start poll thread", avsync->session_id);
@@ -850,7 +868,13 @@
return AV_SYNC_ASTART_ERR;
}
}
-
+ if (LIVE_MODE(avsync->mode)) {
+ uint32_t systime;
+ msync_session_get_wall(avsync->fd, &systime, NULL);
+ log_info("[%d]return %u w %u pts %u d %u",
+ avsync->session_id, ret, systime, pts, delay);
+ }
+exit:
log_info("[%d]return %u", avsync->session_id, ret);
return ret;
}
@@ -874,18 +898,59 @@
goto done;
}
+ /* stopping procedure, unblock audio rendering */
+ if (avsync->mode == AV_SYNC_MODE_PCR_MASTER &&
+ avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
+ action = AV_SYNC_AA_DROP;
+ goto done;
+ }
+
msync_session_get_wall(avsync->fd, &systime, NULL);
- if (abs_diff(systime, pts) < A_ADJ_THREDHOLD) {
+
+ if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
+ LIVE_MODE(avsync->mode) &&
+ abs_diff(systime, pts) > STREAM_DISC_THRES) {
+ /* outlier by stream error */
+ avsync->outlier_cnt++;
+ if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
+ /* treat as disc, just drop current frame */
+ avsync->state = AV_SYNC_STAT_SYNC_LOST;
+ avsync->outlier_cnt = 0;
+ action = AV_SYNC_AA_DROP;
+ systime = pts;
+ msync_session_set_audio_dis(avsync->fd, pts);
+ goto done;
+ }
+ log_info("[%d]ignore outlier %u", avsync->session_id, pts);
+ pts = systime;
+ action = AV_SYNC_AA_RENDER;
+ goto done;
+ }
+
+ avsync->outlier_cnt = 0;
+ /* low bound from sync_lost to sync_setup */
+ if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
+ avsync->state = AV_SYNC_STAT_SYNC_SETUP;
+ action = AV_SYNC_AA_RENDER;
+ goto done;
+ }
+
+ /* high bound of sync_setup */
+ if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
+ avsync->state != AV_SYNC_STAT_SYNC_LOST) {
+ avsync->state = AV_SYNC_STAT_SYNC_SETUP;
action = AV_SYNC_AA_RENDER;
goto done;
}
if ((int)(systime - pts) > 0) {
+ avsync->state = AV_SYNC_STAT_SYNC_LOST;
action = AV_SYNC_AA_DROP;
goto done;
}
if ((int)(systime - pts) < 0) {
+ avsync->state = AV_SYNC_STAT_SYNC_LOST;
action = AV_SYNC_AA_INSERT;
goto done;
}
@@ -896,8 +961,11 @@
if (action == AV_SYNC_AA_RENDER) {
avsync->apts = pts;
msync_session_update_apts(avsync->fd, systime, pts, 0);
+ log_debug("[%d]return %d sys %u - pts %u = %d",
+ avsync->session_id, action, systime, pts, systime - pts);
} else {
- log_info("[%d]return %d sys %u pts %u", avsync->session_id, action, systime, pts);
+ log_info("[%d]return %d sys %u - pts %u = %d",
+ avsync->session_id, action, systime, pts, systime - pts);
}
return ret;
@@ -943,6 +1011,19 @@
}
avsync->speed = speed;
}
+ } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
+ struct session_debug debug;
+ if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
+ if (debug.debug_freerun) {
+ avsync->backup_mode = avsync->mode;
+ avsync->mode = AV_SYNC_MODE_FREE_RUN;
+ log_warn("[%d]audio to freerun mode", avsync->session_id);
+ } else {
+ avsync->mode = avsync->backup_mode;
+ log_warn("[%d]audio back to mode %d",
+ avsync->session_id, avsync->mode);
+ }
+ }
}
}
@@ -951,6 +1032,19 @@
{
log_info("[%d]amode mode %d %d v/a %d/%d", avsync->session_id,
avsync->active_mode, avsync->mode, v_active, a_active);
+ if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
+ struct session_debug debug;
+ if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
+ if (debug.debug_freerun) {
+ avsync->backup_mode = avsync->mode;
+ avsync->mode = AV_SYNC_MODE_FREE_RUN;
+ log_warn("[%d]video to freerun mode", avsync->session_id);
+ } else
+ avsync->mode = avsync->backup_mode;
+ log_warn("[%d]video back to mode %d",
+ avsync->session_id, avsync->mode);
+ }
+ }
}
static void * poll_thread(void * arg)
@@ -981,7 +1075,9 @@
if (pfd.revents & POLLERR)
log_error("[%d]POLLERR received", avsync->session_id);
- /* mode change */
+ /* mode change. Non-exclusive wait so all the processes
+ * shall be woken up
+ */
if (pfd.revents & POLLPRI) {
bool v_active, a_active, v_timeout;
@@ -999,7 +1095,7 @@
return NULL;
}
-int av_sync_set_pcr_clock(void *sync, pts90K pts)
+int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
{
struct av_sync_session *avsync = (struct av_sync_session *)sync;
@@ -1009,10 +1105,10 @@
if (avsync->type != AV_SYNC_TYPE_PCR)
return -2;
- return msync_session_set_pcr(avsync->fd, pts);
+ return msync_session_set_pcr(avsync->fd, pts, mono_clock);
}
-int av_sync_get_pcr_clock(void *sync, pts90K *pts)
+int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
{
struct av_sync_session *avsync = (struct av_sync_session *)sync;
@@ -1022,7 +1118,7 @@
if (avsync->type != AV_SYNC_TYPE_PCR)
return -2;
- return msync_session_get_pcr(avsync->fd, pts);
+ return msync_session_get_pcr(avsync->fd, pts, mono_clock);
}
int av_sync_set_session_name(void *sync, const char *name)
diff --git a/src/msync.h b/src/msync.h
index 8487d5f..f7bcd68 100644
--- a/src/msync.h
+++ b/src/msync.h
@@ -25,6 +25,11 @@
uint32_t delay;
};
+struct pcr_pair {
+ uint32_t pts;
+ uint64_t mono_clock;
+};
+
struct pts_wall {
uint32_t wall_clock;
uint32_t interval;
@@ -61,6 +66,7 @@
enum avs_astart_mode {
AVS_START_SYNC = 0,
AVS_START_ASYNC,
+ AVS_START_AGAIN,
AVS_START_MAX
};
@@ -79,6 +85,12 @@
uint32_t value;
};
+struct session_debug {
+ uint32_t debug_freerun;
+ uint32_t pcr_init_flag;
+ uint32_t pcr_init_mode;
+};
+
#define AVS_INVALID_PTS 0xFFFFFFFFUL
#define AMSYNC_START_V_FIRST 0x1
@@ -104,8 +116,8 @@
#define AMSYNCS_IOC_SEND_EVENT _IOWR((_A_M_SS), 0x08, struct session_event)
//For PCR/IPTV mode only
#define AMSYNCS_IOC_GET_SYNC_STAT _IOWR((_A_M_SS), 0x09, struct session_sync_stat)
-#define AMSYNCS_IOC_SET_PCR _IOW((_A_M_SS), 0x0a, unsigned int)
-#define AMSYNCS_IOC_GET_PCR _IOWR((_A_M_SS), 0x0b, unsigned int)
+#define AMSYNCS_IOC_SET_PCR _IOW((_A_M_SS), 0x0a, struct pcr_pair)
+#define AMSYNCS_IOC_GET_PCR _IOWR((_A_M_SS), 0x0b, struct pcr_pair)
#define AMSYNCS_IOC_GET_WALL _IOR((_A_M_SS), 0x0c, struct pts_wall)
#define AMSYNCS_IOC_SET_RATE _IOW((_A_M_SS), 0x0d, unsigned int)
#define AMSYNCS_IOC_GET_RATE _IOR((_A_M_SS), 0x0e, unsigned int)
@@ -115,4 +127,7 @@
#define AMSYNCS_IOC_GET_CLOCK_START _IOR((_A_M_SS), 0x12, unsigned int)
#define AMSYNCS_IOC_AUDIO_START _IOW((_A_M_SS), 0x13, struct audio_start)
+//For debuging
+#define AMSYNCS_IOC_GET_DEBUG_MODE _IOR((_A_M_SS), 0x100, struct session_debug)
+
#endif
diff --git a/src/msync_util.c b/src/msync_util.c
index 4eaa41d..7ead777 100644
--- a/src/msync_util.c
+++ b/src/msync_util.c
@@ -332,11 +332,13 @@
return start != 0;
}
-int msync_session_set_pcr(int fd, pts90K pts)
+int msync_session_set_pcr(int fd, pts90K pts, uint64_t mono_clock)
{
int rc;
- uint32_t pcr = pts;
+ struct pcr_pair pcr;
+ pcr.pts = pts;
+ pcr.mono_clock = mono_clock;
rc = ioctl(fd, AMSYNCS_IOC_SET_PCR, &pcr);
if (rc)
log_error("session[%d] set pcr %u errno:%d", fd, pcr, errno);
@@ -344,16 +346,29 @@
return rc;
}
-int msync_session_get_pcr(int fd, pts90K *pts)
+int msync_session_get_pcr(int fd, pts90K *pts, uint64_t *mono_clock)
{
int rc;
- uint32_t pcr;
+ struct pcr_pair pcr;
rc = ioctl(fd, AMSYNCS_IOC_GET_PCR, &pcr);
if (rc)
log_error("session[%d] set pcr %u errno:%d", fd, pcr, errno);
- else
- *pts = pcr;
+ else {
+ *pts = pcr.pts;
+ *mono_clock = pcr.mono_clock;
+ }
+
+ return rc;
+}
+
+int msync_session_get_debug_mode(int fd, struct session_debug *debug)
+{
+ int rc;
+
+ rc = ioctl(fd, AMSYNCS_IOC_GET_DEBUG_MODE, debug);
+ if (rc)
+ log_error("session[%d] set debug mode errno:%d", fd, errno);
return rc;
}
diff --git a/src/msync_util.h b/src/msync_util.h
index 89be112..67dbfb3 100644
--- a/src/msync_util.h
+++ b/src/msync_util.h
@@ -16,6 +16,7 @@
#include <stdbool.h>
#include <stdint.h>
#include "aml_avsync.h"
+#include "msync.h"
int msync_create_session();
void msync_destory_session(int id);
@@ -41,7 +42,8 @@
int msync_session_get_stat (int fd, enum sync_mode *mode,
bool *v_active, bool *a_active, bool *v_timeout);
bool msync_clock_started(int fd);
-int msync_session_set_pcr(int fd, pts90K pts);
-int msync_session_get_pcr(int fd, pts90K *pts);
+int msync_session_set_pcr(int fd, pts90K pts, uint64_t mono_clock);
+int msync_session_get_pcr(int fd, pts90K *pts, uint64_t *mono_clock);
+int msync_session_get_debug_mode(int fd, struct session_debug *debug);
#endif