blob: 8fd6b2da5c71cc2ef117794c8bf0b17b1e513431 [file] [log] [blame]
Song Zhaoc03ba122020-12-23 21:54:02 -08001/*
2 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
3 *
4 * This source code is subject to the terms and conditions defined in the
5 * file 'LICENSE' which is part of this source code package.
6 *
7 * Description:
8 */
Song Zhaoea5a0412021-01-18 16:40:08 -08009#include <errno.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080010#include <pthread.h>
11#include <stdbool.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <sys/time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080015#include <poll.h>
16#include <fcntl.h>
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <sys/prctl.h>
20#include <sys/ioctl.h>
Song Zhaoa2985cb2021-06-24 12:01:47 -070021#include <time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080022#include <unistd.h>
23//#include <linux/amlogic/msync.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080024#include "aml_avsync.h"
Song Zhao4f632952021-12-16 09:00:18 -080025#include "aml_queue.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080026#include "pattern.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080027#include "aml_avsync_log.h"
Song Zhaoea5a0412021-01-18 16:40:08 -080028#include "msync_util.h"
29#include "msync.h"
30#include <pthread.h>
wei.dubcc2ed22021-05-19 07:16:10 -040031#include "pcr_monitor.h"
fei.deng66b4e812022-04-14 12:23:01 +080032#include "aml_version.h"
Song Zhao2f6744b2021-11-03 21:23:50 -070033
Song Zhaoc03ba122020-12-23 21:54:02 -080034enum sync_state {
35 AV_SYNC_STAT_INIT = 0,
36 AV_SYNC_STAT_RUNNING = 1,
37 AV_SYNC_STAT_SYNC_SETUP = 2,
38 AV_SYNC_STAT_SYNC_LOST = 3,
39};
40
yongchun.li107a6162021-05-05 02:38:57 -070041enum audio_switch_state_ {
42 AUDIO_SWITCH_STAT_INIT = 0,
43 AUDIO_SWITCH_STAT_RESET = 1,
44 AUDIO_SWITCH_STAT_START = 2,
45 AUDIO_SWITCH_STAT_FINISH = 3,
yongchun.li59e873d2021-07-07 11:42:38 -070046 AUDIO_SWITCH_STAT_AGAIN = 4,
yongchun.li107a6162021-05-05 02:38:57 -070047};
48
Song Zhaoea5a0412021-01-18 16:40:08 -080049#define SESSION_DEV "avsync_s"
50
Song Zhaoc03ba122020-12-23 21:54:02 -080051struct av_sync_session {
52 /* session id attached */
53 int session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -080054 int fd;
55 bool attached;
56 enum sync_mode mode;
57 /* for audio trickplay */
58 enum sync_mode backup_mode;
59 enum sync_type type;
60 uint32_t start_policy;
bo.xiao5821fc72021-07-11 22:47:00 -040061 int timeout;
Song Zhaoc03ba122020-12-23 21:54:02 -080062
Song Zhaoea5a0412021-01-18 16:40:08 -080063 /* playback time, will stop increasing during pause */
64 pts90K vpts;
65 pts90K apts;
66
67 /* phase adjustment of stream time for rate control (Video ONLY) */
Song Zhaoc03ba122020-12-23 21:54:02 -080068 pts90K phase;
69 bool phase_set;
Song Zhao1561e542022-01-12 10:37:55 -080070 bool phase_adjusted;
Song Zhaoc03ba122020-12-23 21:54:02 -080071
72 /* pts of last rendered frame */
Song Zhaoea5a0412021-01-18 16:40:08 -080073 pts90K last_wall;
Song Zhaoc03ba122020-12-23 21:54:02 -080074 pts90K last_pts;
75 struct vframe *last_frame;
76
Song Zhaoe0bf6ad2021-07-09 11:28:42 -070077 /* pts of last pushed frame */
78 pts90K last_q_pts;
79
Song Zhaoc03ba122020-12-23 21:54:02 -080080 bool first_frame_toggled;
Song Zhaoc03ba122020-12-23 21:54:02 -080081 bool paused;
Song Zhaoea5a0412021-01-18 16:40:08 -080082 enum sync_state state;
Song Zhaoc03ba122020-12-23 21:54:02 -080083 void *pattern_detector;
84 void *frame_q;
Song Zhaoc03ba122020-12-23 21:54:02 -080085
Song Zhaoea5a0412021-01-18 16:40:08 -080086 /* start control */
87 int start_thres;
88 audio_start_cb audio_start;
89 void *audio_start_priv;
90
91 /* render property */
Song Zhaoc03ba122020-12-23 21:54:02 -080092 int delay;
Song Zhao6dce2672022-01-13 11:32:44 -080093 int extra_delay;
Song Zhaoc03ba122020-12-23 21:54:02 -080094 pts90K vsync_interval;
95
96 /* state lock */
97 pthread_mutex_t lock;
98 /* pattern */
99 int last_holding_peroid;
Song Zhaoea5a0412021-01-18 16:40:08 -0800100 bool session_started;
Song Zhaoc03ba122020-12-23 21:54:02 -0800101
102 float speed;
103
Song Zhaoc03ba122020-12-23 21:54:02 -0800104 /* pause pts */
105 pts90K pause_pts;
106 pause_pts_done pause_pts_cb;
107 void *pause_cb_priv;
yongchun.li428390d2022-02-17 17:15:40 -0800108 /* underflow */
109 underflow_detected underflow_cb;
110 void *underflow_cb_priv;
111 struct underflow_config underflow_cfg;
112 struct timespec frame_last_update_time;
Song Zhao5d2b4772021-01-18 16:40:08 -0800113
114 /* log control */
Song Zhaoa2985cb2021-06-24 12:01:47 -0700115 uint32_t last_log_syst;
Song Zhao5d2b4772021-01-18 16:40:08 -0800116 uint32_t sync_lost_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700117 struct timespec sync_lost_print_time;
Song Zhaoea5a0412021-01-18 16:40:08 -0800118
119 pthread_t poll_thread;
120 /* pcr master, IPTV only */
121 bool quit_poll;
122 enum sync_mode active_mode;
Song Zhaof46932e2021-05-21 01:51:45 -0700123 uint32_t disc_thres_min;
124 uint32_t disc_thres_max;
Song Zhao35a82df2021-04-15 10:58:49 -0700125
126 /* error detection */
127 uint32_t last_poptime;
Song Zhaod62bb392021-04-23 12:25:49 -0700128 uint32_t outlier_cnt;
Song Zhao409739b2021-05-12 22:21:40 -0700129 pts90K last_disc_pts;
130
yongchun.li107a6162021-05-05 02:38:57 -0700131 // indicate set audio switch
132 bool in_audio_switch;
133 enum audio_switch_state_ audio_switch_state;
wei.dubcc2ed22021-05-19 07:16:10 -0400134
135 //pcr monitor handle
136 void *pcr_monitor;
137 int ppm;
Song Zhao623e2f12021-09-03 15:54:04 -0700138 bool ppm_adjusted;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700139
140 //video FPS detection
141 pts90K last_fpts;
142 int fps_interval;
143 int fps_interval_acc;
144 int fps_cnt;
145
146 //video freerun with rate control
147 uint32_t last_r_syst;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700148 bool debug_freerun;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700149
150 //Audio dropping detection
151 uint32_t audio_drop_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700152 struct timespec audio_drop_start;
Song Zhao95bd0922021-09-21 14:07:46 -0700153
154 /*system mono time for current vsync interrupt */
155 uint64_t msys;
Song Zhaoc03ba122020-12-23 21:54:02 -0800156};
157
158#define MAX_FRAME_NUM 32
159#define DEFAULT_START_THRESHOLD 2
160#define TIME_UNIT90K (90000)
Song Zhaoa73fcf32023-01-13 08:12:26 -0800161#define DEFAULT_WALL_ADJ_THRES (TIME_UNIT90K / 10) //100ms
Song Zhaof46932e2021-05-21 01:51:45 -0700162#define AV_DISC_THRES_MIN (TIME_UNIT90K / 3)
163#define AV_DISC_THRES_MAX (TIME_UNIT90K * 10)
Song Zhao7daf3a12021-05-10 22:22:25 -0700164#define A_ADJ_THREDHOLD_HB (900 * 6) //60ms
165#define A_ADJ_THREDHOLD_LB (900 * 2) //20ms
Song Zhao4bd18762022-09-30 16:39:52 -0700166#define A_ADJ_THREDHOLD_MB (900 * 3) //30ms
Song Zhao52f55192021-05-06 10:52:21 -0700167#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800168#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhao76005282022-03-08 16:49:41 -0800169#define LIVE_MODE(m) ((m) == AV_SYNC_MODE_PCR_MASTER || (m) == AV_SYNC_MODE_IPTV)
Song Zhao7e24b182022-04-01 08:46:40 -0700170#define V_DISC_MODE(mode) (LIVE_MODE(mode) || (mode) == AV_SYNC_MODE_VMASTER)
Song Zhaod62bb392021-04-23 12:25:49 -0700171
Song Zhao065800e2021-05-26 15:56:06 -0700172#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
Song Zhaod62bb392021-04-23 12:25:49 -0700173#define OUTLIER_MAX_CNT 8
Song Zhaoa2985cb2021-06-24 12:01:47 -0700174#define VALID_TS(x) ((x) != -1)
yongchun.li428390d2022-02-17 17:15:40 -0800175#define UNDERFLOW_CHECK_THRESH_MS (100)
Song Zhaoc03ba122020-12-23 21:54:02 -0800176
yongchun.li0ee6e372021-08-20 04:26:04 -0700177static uint64_t time_diff (struct timespec *b, struct timespec *a);
Song Zhaoc03ba122020-12-23 21:54:02 -0800178static bool frame_expire(struct av_sync_session* avsync,
179 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800180 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800181 struct vframe * frame,
182 struct vframe * next_frame,
183 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700184static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800185 int cur_period,
186 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800187static void * poll_thread(void * arg);
188static void trigger_audio_start_cb(struct av_sync_session *avsync,
189 avs_ascb_reason reason);
Song Zhao95bd0922021-09-21 14:07:46 -0700190static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync);
191static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame);
fei.deng55389b62022-08-18 23:46:50 +0800192
Song Zhao2f6744b2021-11-03 21:23:50 -0700193pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER;
Song Zhaoc03ba122020-12-23 21:54:02 -0800194
Song Zhaoea5a0412021-01-18 16:40:08 -0800195int av_sync_open_session(int *session_id)
196{
Song Zhao2f6744b2021-11-03 21:23:50 -0700197 int fd = -1;
Song Zhaoea5a0412021-01-18 16:40:08 -0800198 int id, rc;
199
Song Zhao2f6744b2021-11-03 21:23:50 -0700200 pthread_mutex_lock(&glock);
201 fd = msync_create_session();
Song Zhaoea5a0412021-01-18 16:40:08 -0800202 if (fd < 0) {
203 log_error("fail");
Song Zhao2f6744b2021-11-03 21:23:50 -0700204 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800205 }
206 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
207 if (rc) {
208 log_error("new session errno:%d", errno);
Song Zhao2f6744b2021-11-03 21:23:50 -0700209 msync_destory_session(fd);
210 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800211 }
212 *session_id = id;
Song Zhao2f6744b2021-11-03 21:23:50 -0700213 log_debug("new avsession id %d fd %d", id, fd);
214exit:
215 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800216 return fd;
217}
218
219void av_sync_close_session(int session)
220{
Song Zhao2f6744b2021-11-03 21:23:50 -0700221 log_debug("session closed fd %d", session);
222 pthread_mutex_lock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800223 msync_destory_session(session);
Song Zhao2f6744b2021-11-03 21:23:50 -0700224 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800225}
226
227static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800228 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800229 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800230 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800231 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800232{
233 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800234 char dev_name[20];
Song Zhao2f6744b2021-11-03 21:23:50 -0700235 int retry = 10;
Song Zhaoc03ba122020-12-23 21:54:02 -0800236
fei.deng55389b62022-08-18 23:46:50 +0800237 /* debug log level */
238 {
239 const char *env= getenv( "AML_AVSYNC_DEBUG_LEVEL");
240 if ( env ) {
241 log_set_level(atoi(env));
242 }
243 }
244
Song Zhao95bd0922021-09-21 14:07:46 -0700245 log_info("[%d] mode %d type %d", session_id, mode, type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800246 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
247 if (!avsync) {
248 log_error("OOM");
249 return NULL;
250 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800251
Song Zhao95bd0922021-09-21 14:07:46 -0700252 if (type == AV_SYNC_TYPE_VIDEO &&
253 mode == AV_SYNC_MODE_VIDEO_MONO) {
254 if (session_id < AV_SYNC_SESSION_V_MONO) {
255 log_error("wrong session id %d", session_id);
256 goto err;
257 }
258 avsync->type = type;
259 avsync->mode = mode;
260 avsync->fd = -1;
261 avsync->session_id = session_id;
262 log_info("[%d]init", avsync->session_id);
263 return avsync;
264 }
265
Song Zhaoea5a0412021-01-18 16:40:08 -0800266 if (type == AV_SYNC_TYPE_VIDEO) {
267 avsync->pattern_detector = create_pattern_detector();
268 if (!avsync->pattern_detector) {
269 log_error("pd create fail");
270 goto err;
271 }
272
273 if (!start_thres)
274 avsync->start_thres = DEFAULT_START_THRESHOLD;
275 else {
276 if (start_thres > 5) {
277 log_error("start_thres too big: %d", start_thres);
278 goto err2;
279 }
280 avsync->start_thres = start_thres;
281 }
282 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800283 avsync->phase_adjusted = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800284 avsync->first_frame_toggled = false;
Song Zhaofd007632022-09-30 16:21:30 -0700285
286 avsync->frame_q = create_q(MAX_FRAME_NUM);
287 if (!avsync->frame_q) {
288 log_error("[%d]create queue fail", avsync->session_id);
289 goto err2;
290 }
Song Zhaofd007632022-09-30 16:21:30 -0700291 {
292 int ret;
293
294 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
295 if (ret) {
296 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
297 goto err2;
298 }
299 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800300 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800301
302 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800303 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800304 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800305 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800306 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800307 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800308 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800309 avsync->speed = 1.0f;
310 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhao409739b2021-05-12 22:21:40 -0700311 avsync->vsync_interval = -1;
312 avsync->last_disc_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700313 avsync->last_log_syst = -1;
314 avsync->last_pts = -1;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700315 avsync->last_q_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700316 avsync->last_wall = -1;
317 avsync->fps_interval = -1;
318 avsync->last_r_syst = -1;
bo.xiao5821fc72021-07-11 22:47:00 -0400319 avsync->timeout = -1;
320
Song Zhaof46932e2021-05-21 01:51:45 -0700321 if (msync_session_get_disc_thres(session_id,
322 &avsync->disc_thres_min, &avsync->disc_thres_max)) {
hanghang.luo02efd312022-08-26 09:49:53 +0800323 log_error("dev_name:%s; errno:%d; fail to get disc thres", dev_name, errno);
Song Zhaof46932e2021-05-21 01:51:45 -0700324 avsync->disc_thres_min = AV_DISC_THRES_MIN;
325 avsync->disc_thres_max = AV_DISC_THRES_MAX;
326 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800327
328 pthread_mutex_init(&avsync->lock, NULL);
Song Zhao9c09f772022-01-07 14:26:50 -0800329 log_info("[%d] start_thres %d disc_thres %u/%u", session_id,
Song Zhao95bd0922021-09-21 14:07:46 -0700330 start_thres, avsync->disc_thres_min, avsync->disc_thres_max);
Song Zhaoea5a0412021-01-18 16:40:08 -0800331
332 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
Song Zhao2f6744b2021-11-03 21:23:50 -0700333 while (retry) {
334 /* wait for sysfs to update */
335 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
336 if (avsync->fd > 0)
337 break;
338
339 retry--;
340 if (!retry) {
341 log_error("open %s errno %d", dev_name, errno);
342 goto err2;
343 }
344 usleep(20000);
Song Zhaoea5a0412021-01-18 16:40:08 -0800345 }
346
wei.dubcc2ed22021-05-19 07:16:10 -0400347 if (avsync->type == AV_SYNC_TYPE_PCR) {
348 if (pcr_monitor_init(&avsync->pcr_monitor)) {
349 log_error("pcr monitor init");
Song Zhao9cd27a52021-07-26 15:27:38 +0000350 goto err3;
wei.dubcc2ed22021-05-19 07:16:10 -0400351 }
352 }
353
Song Zhaoea5a0412021-01-18 16:40:08 -0800354 if (!attach) {
355 msync_session_set_mode(avsync->fd, mode);
356 avsync->mode = mode;
Song Zhao7e24b182022-04-01 08:46:40 -0700357 if (avsync->mode == AV_SYNC_MODE_VMASTER)
358 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -0800359 } else {
360 avsync->attached = true;
361 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
362 log_error("get mode");
Song Zhao9cd27a52021-07-26 15:27:38 +0000363 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800364 }
365 avsync->backup_mode = avsync->mode;
bo.xiao5821fc72021-07-11 22:47:00 -0400366 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800367 log_error("get policy");
Song Zhao9cd27a52021-07-26 15:27:38 +0000368 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800369 }
Song Zhao9fef59c2022-08-17 12:43:10 -0700370 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700371 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -0700372 log_error("get state");
Song Zhao9cd27a52021-07-26 15:27:38 +0000373 goto err4;
yongchun.li107a6162021-05-05 02:38:57 -0700374 }
375 if (avsync->in_audio_switch) {
376 log_info("audio_switch_state reseted the audio");
377 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
378 }
379
Song Zhaoea5a0412021-01-18 16:40:08 -0800380 log_info("[%d]retrieve sync mode %d policy %d",
381 session_id, avsync->mode, avsync->start_policy);
382 }
383
Song Zhaoc03ba122020-12-23 21:54:02 -0800384 return avsync;
Song Zhao9cd27a52021-07-26 15:27:38 +0000385err4:
wei.dubcc2ed22021-05-19 07:16:10 -0400386 if (avsync->pcr_monitor)
387 pcr_monitor_destroy(avsync->pcr_monitor);
Song Zhao9cd27a52021-07-26 15:27:38 +0000388err3:
Song Zhaofd007632022-09-30 16:21:30 -0700389 if (avsync->fd)
390 close(avsync->fd);
Song Zhaoea5a0412021-01-18 16:40:08 -0800391err2:
Song Zhaofd007632022-09-30 16:21:30 -0700392 avsync->quit_poll = true;
393 if (avsync->poll_thread) {
394 pthread_join(avsync->poll_thread, NULL);
395 avsync->poll_thread = 0;
396 }
397 if (avsync->frame_q)
398 destroy_q(avsync->frame_q);
399 if (avsync->pattern_detector)
400 destroy_pattern_detector(avsync->pattern_detector);
Song Zhaoea5a0412021-01-18 16:40:08 -0800401err:
402 free(avsync);
403 return NULL;
404}
405
406void* av_sync_create(int session_id,
407 enum sync_mode mode,
408 enum sync_type type,
409 int start_thres)
410{
411 return create_internal(session_id, mode,
412 type, start_thres, false);
413}
414
415void* av_sync_attach(int session_id, enum sync_type type)
416{
Song Zhao95bd0922021-09-21 14:07:46 -0700417 if (type == AV_SYNC_TYPE_VIDEO)
418 return NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800419 return create_internal(session_id, AV_SYNC_MODE_MAX,
420 type, 0, true);
421}
422
423int av_sync_video_config(void *sync, struct video_config* config)
424{
425 struct av_sync_session *avsync = (struct av_sync_session *)sync;
426
427 if (!avsync || !config)
428 return -1;
429
430 if (config->delay != 1 && config->delay != 2) {
431 log_error("invalid delay: %d\n", config->delay);
432 return -1;
433 }
434
435 avsync->delay = config->delay;
Song Zhao6dce2672022-01-13 11:32:44 -0800436 avsync->extra_delay = config->extra_delay * 90;
Song Zhaoea5a0412021-01-18 16:40:08 -0800437
Song Zhao6dce2672022-01-13 11:32:44 -0800438 log_info("[%d] vsync delay: %d extra_delay: %d ms",
439 avsync->session_id, config->delay, config->extra_delay);
Song Zhaoea5a0412021-01-18 16:40:08 -0800440 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800441}
442
443static int internal_stop(struct av_sync_session *avsync)
444{
445 int ret = 0;
446 struct vframe *frame;
447
448 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800449 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
450 frame->free(frame);
451 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800452 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800453 pthread_mutex_unlock(&avsync->lock);
454 return ret;
455}
456
457/* destroy and detach from kernel session */
458void av_sync_destroy(void *sync)
459{
460 struct av_sync_session *avsync = (struct av_sync_session *)sync;
461
462 if (!avsync)
463 return;
464
Song Zhao95bd0922021-09-21 14:07:46 -0700465 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
466 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
467 log_info("[%d]done", avsync->session_id);
468 internal_stop(avsync);
469 destroy_q(avsync->frame_q);
470 free(avsync);
471 return;
472 }
Song Zhaob5458b32021-11-12 15:58:47 -0800473 log_info("[%d]begin type %d", avsync->session_id, avsync->type);
Song Zhao6be9ac22022-09-30 16:44:50 -0700474 if (avsync->type == AV_SYNC_TYPE_VIDEO)
475 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800476
Song Zhao6be9ac22022-09-30 16:44:50 -0700477 avsync->quit_poll = true;
478 if (avsync->poll_thread) {
479 pthread_join(avsync->poll_thread, NULL);
480 avsync->poll_thread = 0;
Song Zhaoaf368d52021-02-17 17:53:45 -0800481 }
Song Zhao6be9ac22022-09-30 16:44:50 -0700482 if (avsync->type == AV_SYNC_TYPE_AUDIO)
483 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoc03ba122020-12-23 21:54:02 -0800484
Song Zhaoea5a0412021-01-18 16:40:08 -0800485 if (avsync->session_started) {
486 if (avsync->type == AV_SYNC_TYPE_VIDEO)
487 msync_session_set_video_stop(avsync->fd);
488 else
489 msync_session_set_audio_stop(avsync->fd);
490 }
wei.dubcc2ed22021-05-19 07:16:10 -0400491
492 if(avsync->pcr_monitor)
493 pcr_monitor_destroy(avsync->pcr_monitor);
494
Song Zhaoea5a0412021-01-18 16:40:08 -0800495 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800496 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800497 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
498 destroy_q(avsync->frame_q);
499 destroy_pattern_detector(avsync->pattern_detector);
500 }
Song Zhaob5458b32021-11-12 15:58:47 -0800501 log_info("[%d]done type %d", avsync->session_id, avsync->type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800502 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800503}
504
bo.xiao5821fc72021-07-11 22:47:00 -0400505int avs_sync_set_start_policy(void *sync, struct start_policy* st_policy)
Song Zhaoea5a0412021-01-18 16:40:08 -0800506{
507 struct av_sync_session *avsync = (struct av_sync_session *)sync;
508
509 if (!avsync || !avsync->fd)
510 return -1;
511
Song Zhao47961d72022-08-29 14:04:44 -0700512 log_info("[%d]policy %u --> %u, timeout %d --> %d", avsync->session_id,
513 avsync->start_policy, st_policy->policy, avsync->timeout, st_policy->timeout);
Song Zhaof4e3c862022-09-01 14:00:11 -0700514 if (avsync->mode == AV_SYNC_MODE_IPTV &&
Song Zhao76005282022-03-08 16:49:41 -0800515 st_policy->policy != AV_SYNC_START_ASAP) {
516 log_error("policy %d not supported in live mode", st_policy->policy);
517 return -1;
518 }
519
Song Zhaof4e3c862022-09-01 14:00:11 -0700520 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
521 msync_session_set_start_thres(avsync->fd, st_policy->timeout);
522
bo.xiao5821fc72021-07-11 22:47:00 -0400523 avsync->start_policy = st_policy->policy;
524 avsync->timeout = st_policy->timeout;
Song Zhao76005282022-03-08 16:49:41 -0800525
Song Zhaoea5a0412021-01-18 16:40:08 -0800526 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400527 if (st_policy->policy != AV_SYNC_START_NONE &&
528 st_policy->policy != AV_SYNC_START_V_PEEK)
529 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800530
531 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800532}
533
534int av_sync_pause(void *sync, bool pause)
535{
536 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700537 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800538 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800539
Song Zhaob5458b32021-11-12 15:58:47 -0800540 if (!avsync) {
541 log_error("invalid handle");
Song Zhaoc03ba122020-12-23 21:54:02 -0800542 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800543 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800544
fei.deng55389b62022-08-18 23:46:50 +0800545 if (avsync->type == AV_SYNC_TYPE_VIDEO && avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
546 log_warn("ignore pause in video mono mode");
547 return -1;
548 }
549
Song Zhaob5458b32021-11-12 15:58:47 -0800550 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
551 log_warn("ignore pause in pcr master mode");
Song Zhaoea5a0412021-01-18 16:40:08 -0800552 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800553 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800554
Song Zhao9fef59c2022-08-17 12:43:10 -0700555 rc = msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -0700556 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700557 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700558
yongchun.li5f52fb02021-06-04 18:13:05 -0700559 /* ignore only when video try to pause when audio is acive, on which
560 the control of the STC will be relays.
561 When resume,it can do always as it is possible that video just
562 paused earlier without audio yet,then audio added later before resume.
563 We shall not igore that otherwise it could cause video freeze. */
564 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
565 avsync->type == AV_SYNC_TYPE_VIDEO &&
566 a_active &&
567 !avsync->in_audio_switch) {
568 if (!pause) {
569 log_info("[%d] clear video pause when audio active",
570 avsync->session_id);
571 avsync->paused = pause;
572 } else {
573 log_info("[%d] ignore the pause from video when audio active",
574 avsync->session_id);
575 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800576 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700577 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800578
yongchun.li107a6162021-05-05 02:38:57 -0700579 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
580 log_info("[%d] ignore the pause from audio", avsync->session_id);
581 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
582 return 0;
583 }
584
Song Zhaoea5a0412021-01-18 16:40:08 -0800585 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800586 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800587 log_info("[%d]paused:%d type:%d rc %d",
588 avsync->session_id, pause, avsync->type, rc);
yongchun.li428390d2022-02-17 17:15:40 -0800589 if (!avsync->paused && avsync->first_frame_toggled) {
590 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
591 log_info("[%d] resume update new frame time", avsync->session_id);
592 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800593 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800594}
595
596int av_sync_push_frame(void *sync , struct vframe *frame)
597{
598 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700599 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800600 struct av_sync_session *avsync = (struct av_sync_session *)sync;
601
602 if (!avsync)
603 return -1;
604
Song Zhao95bd0922021-09-21 14:07:46 -0700605 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
fei.deng55389b62022-08-18 23:46:50 +0800606 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
Song Zhao95bd0922021-09-21 14:07:46 -0700607 return video_mono_push_frame(avsync, frame);
fei.deng55389b62022-08-18 23:46:50 +0800608 }
Song Zhao95bd0922021-09-21 14:07:46 -0700609
Song Zhaofd007632022-09-30 16:21:30 -0700610 if (avsync->state == AV_SYNC_STAT_INIT && !queue_size(avsync->frame_q)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800611 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400612 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800613 log_error("[%d]get policy", avsync->session_id);
614 return -1;
615 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800616 }
617
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700618 if (avsync->last_q_pts != -1) {
Song Zhao7e24b182022-04-01 08:46:40 -0700619 if (frame->pts != -1 && avsync->mode == AV_SYNC_MODE_VMASTER) {
620 /* Sometimes app will fake PTS for trickplay, video PTS gap
621 * is really big depending on the speed. Have to adjust the
622 * threshold dynamically.
623 */
624 int gap = (int)(frame->pts - avsync->last_q_pts);
625 if (gap > avsync->disc_thres_min) {
626 avsync->disc_thres_min = gap * 6;
627 avsync->disc_thres_max = gap * 20;
628 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
629 msync_session_set_disc_thres(avsync->session_id,
630 avsync->disc_thres_min, avsync->disc_thres_max);
631 log_info("[%d] update disc_thres to %d/%d",avsync->session_id,
632 avsync->disc_thres_min, avsync->disc_thres_max);
633 }
634 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700635 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
636 /* TODO: wrong, should remove from back of queue */
Song Zhaoc03ba122020-12-23 21:54:02 -0800637 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700638 if (prev) {
639 prev->free(prev);
640 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
641 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700642 } else if (avsync->fps_cnt < 100) {
643 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700644
645 if (interval > 0 && interval <= 4500) {
646 if (avsync->fps_interval_acc == -1) {
647 avsync->fps_interval_acc = interval;
648 avsync->fps_cnt = 1;
649 } else {
650 avsync->fps_interval_acc += interval;
651 avsync->fps_cnt++;
652 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
653 if (avsync->fps_cnt == 100)
654 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
655 }
656 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800657 }
658 }
659
Song Zhao065800e2021-05-26 15:56:06 -0700660 if (frame->duration == -1)
661 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800662 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700663 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800664 ret = queue_item(avsync->frame_q, frame);
665 if (avsync->state == AV_SYNC_STAT_INIT &&
666 queue_size(avsync->frame_q) >= avsync->start_thres) {
667 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaofd007632022-09-30 16:21:30 -0700668 log_debug("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800669 }
670
671 if (ret)
Song Zhaoe1b65602022-01-06 08:03:46 -0800672 log_error("queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400673 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800674 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800675}
676
677struct vframe *av_sync_pop_frame(void *sync)
678{
Song Zhaoea5a0412021-01-18 16:40:08 -0800679 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800680 struct av_sync_session *avsync = (struct av_sync_session *)sync;
681 int toggle_cnt = 0;
hanghang.luo02efd312022-08-26 09:49:53 +0800682 uint32_t systime = 0;
Song Zhao468fd652021-01-15 22:13:04 -0800683 bool pause_pts_reached = false;
hanghang.luo02efd312022-08-26 09:49:53 +0800684 uint32_t interval = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800685
Song Zhao95bd0922021-09-21 14:07:46 -0700686 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
687 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
688 return video_mono_pop_frame(avsync);
689
Song Zhaoc03ba122020-12-23 21:54:02 -0800690 pthread_mutex_lock(&avsync->lock);
691 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhao2f6744b2021-11-03 21:23:50 -0700692 log_debug("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800693 goto exit;
694 }
695
Song Zhaoea5a0412021-01-18 16:40:08 -0800696 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700697 uint32_t pts;
698
Song Zhaoc03ba122020-12-23 21:54:02 -0800699 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800700 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800701 goto exit;
702 }
Song Zhao35a82df2021-04-15 10:58:49 -0700703 msync_session_get_wall(avsync->fd, &systime, &interval);
704 pts = frame->pts - avsync->delay * interval;
705 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800706 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700707 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800708 }
709
Song Zhaoea5a0412021-01-18 16:40:08 -0800710 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700711 !avsync->first_frame_toggled &&
712 !msync_clock_started(avsync->fd)) {
713 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800714 log_trace("[%d]clock not started", avsync->session_id);
715 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800716 }
717
Song Zhaoea5a0412021-01-18 16:40:08 -0800718 enter_last_frame = avsync->last_frame;
719 msync_session_get_wall(avsync->fd, &systime, &interval);
720
721 /* handle refresh rate change */
722 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
723 avsync->vsync_interval != interval) {
724 log_info("[%d]vsync interval update %d --> %u",
725 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700726 if (avsync->fps_interval == -1)
727 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800728 avsync->vsync_interval = interval;
729 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800730 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700731 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800732 reset_pattern(avsync->pattern_detector);
733 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800734 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
735 struct vframe *next_frame = NULL;
736
737 peek_item(avsync->frame_q, (void **)&next_frame, 1);
738 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700739 log_debug("[%d]cur_f %u next_f %u size %d",
740 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800741 if (frame_expire(avsync, systime, interval,
742 frame, next_frame, toggle_cnt)) {
743 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800744 toggle_cnt++;
745
Song Zhao35a82df2021-04-15 10:58:49 -0700746 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800747 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700748 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700749 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700750 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
751 if (next_frame)
752 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
753 }
Song Zhao35a82df2021-04-15 10:58:49 -0700754
Song Zhaoc03ba122020-12-23 21:54:02 -0800755 if (avsync->last_frame)
756 avsync->last_holding_peroid = avsync->last_frame->hold_period;
757
758 dqueue_item(avsync->frame_q, (void **)&frame);
759 if (avsync->last_frame) {
760 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800761 if (toggle_cnt > 1) {
Song Zhaofd007632022-09-30 16:21:30 -0700762 log_info("[%d]free %u cur %u system/d %u/%u queue size %d", avsync->session_id,
763 avsync->last_frame->pts, frame->pts,
764 systime, systime - avsync->last_poptime,
765 queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800766 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800767 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800768 } else {
769 avsync->first_frame_toggled = true;
Song Zhaofd007632022-09-30 16:21:30 -0700770 log_info("[%d]first frame %u queue size %d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800771 }
772 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800773 avsync->last_pts = frame->pts;
yongchun.li428390d2022-02-17 17:15:40 -0800774 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
Song Zhaoc03ba122020-12-23 21:54:02 -0800775 } else
776 break;
777 }
778
779 /* pause pts */
780 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800781 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800782 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800783 else
Song Zhao468fd652021-01-15 22:13:04 -0800784 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
785 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
786 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
787 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
788 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800789
Song Zhao468fd652021-01-15 22:13:04 -0800790 if (pause_pts_reached) {
Song Zhao468fd652021-01-15 22:13:04 -0800791 /* stay in paused until av_sync_pause(false) */
Song Zhaoa1742282022-09-30 16:17:26 -0700792 uint32_t local_pts = avsync->pause_pts;
Song Zhao468fd652021-01-15 22:13:04 -0800793 avsync->paused = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800794 log_info ("[%d]reach pause pts: %u",
Song Zhaob5458b32021-11-12 15:58:47 -0800795 avsync->session_id, avsync->pause_pts);
Song Zhaoad7c8232021-12-14 11:46:48 -0800796 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoa1742282022-09-30 16:17:26 -0700797 if (avsync->pause_pts_cb)
798 avsync->pause_pts_cb(local_pts,
799 avsync->pause_cb_priv);
800 log_info ("[%d] reach pause pts: %u handle done",
801 avsync->session_id, local_pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800802 }
803
804exit:
805 pthread_mutex_unlock(&avsync->lock);
yongchun.li428390d2022-02-17 17:15:40 -0800806
807 /* underflow check */
808 if (avsync->session_started && avsync->first_frame_toggled &&
809 (avsync->paused == false) && (avsync->state >= AV_SYNC_STAT_RUNNING) &&
810 avsync->underflow_cb && peek_item(avsync->frame_q, (void **)&frame, 0))
811 {/* empty queue in normal play */
812 struct timespec now;
813 int diff_ms;
814 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
815 diff_ms = time_diff(&now, &avsync->frame_last_update_time)/1000;
816 if(diff_ms >= (avsync->underflow_cfg.time_thresh
817 + avsync->vsync_interval*avsync->last_holding_peroid/90)) {
818 log_info ("[%d]underflow detected: %u", avsync->session_id, avsync->last_pts);
819 avsync->underflow_cb (avsync->last_pts,
820 avsync->underflow_cb_priv);
821 /* update time to control the underflow check call backs */
822 avsync->frame_last_update_time = now;
823 }
824 }
825
Song Zhaoc03ba122020-12-23 21:54:02 -0800826 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800827 if (enter_last_frame != avsync->last_frame)
828 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
bo.xiao1f94b352021-08-02 03:53:47 -0400829 log_trace("[%d]pop=%u, stc=%u, QNum=%d", avsync->session_id, avsync->last_frame->pts, systime, queue_size(avsync->frame_q));
Song Zhao065800e2021-05-26 15:56:06 -0700830 /* don't update vpts for out_lier */
831 if (avsync->last_frame->duration != -1)
832 msync_session_update_vpts(avsync->fd, systime,
833 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800834 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800835 if (enter_last_frame != avsync->last_frame)
836 log_debug("[%d]pop (nil)", avsync->session_id);
837
Song Zhao35a82df2021-04-15 10:58:49 -0700838 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800839 if (avsync->last_frame)
840 avsync->last_frame->hold_period++;
841 return avsync->last_frame;
842}
843
Song Zhaoc03ba122020-12-23 21:54:02 -0800844static inline uint32_t abs_diff(uint32_t a, uint32_t b)
845{
Song Zhaoea5a0412021-01-18 16:40:08 -0800846 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800847}
848
yongchun.li0ee6e372021-08-20 04:26:04 -0700849static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800850{
hanghang.luo02efd312022-08-26 09:49:53 +0800851 return (uint64_t)(b->tv_sec - a->tv_sec)*1000000 + (b->tv_nsec/1000 - a->tv_nsec/1000);
Song Zhaoc03ba122020-12-23 21:54:02 -0800852}
853
Song Zhaoc03ba122020-12-23 21:54:02 -0800854static bool frame_expire(struct av_sync_session* avsync,
855 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800856 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800857 struct vframe * frame,
858 struct vframe * next_frame,
859 int toggle_cnt)
860{
Song Zhao6dce2672022-01-13 11:32:44 -0800861 uint32_t fpts = frame->pts + avsync->extra_delay;
862 uint32_t nfpts = -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800863 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800864 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800865
866 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
867 return false;
868
869 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
870 return true;
871
Song Zhaoad7c8232021-12-14 11:46:48 -0800872 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS &&
873 avsync->pause_pts == frame->pts)
874 return true;
875
Song Zhao08fa16b2021-12-08 14:30:17 -0800876 if (systime == AV_SYNC_INVALID_PTS &&
877 avsync->mode == AV_SYNC_MODE_AMASTER)
878 return false;
879
Song Zhao6dce2672022-01-13 11:32:44 -0800880 if (next_frame)
881 nfpts = next_frame->pts + avsync->extra_delay;
882
Song Zhao7e24b182022-04-01 08:46:40 -0700883 if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
fei.deng63e43e12021-09-23 19:44:01 +0800884 /* We need to ensure that the video outputs smoothly,
885 so output video frame by frame hold_period */
886 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
887 avsync->last_frame &&
888 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
889 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
890 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700891 return true;
892 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700893 }
894
Song Zhaoc03ba122020-12-23 21:54:02 -0800895 if (!fpts) {
896 if (avsync->last_frame) {
897 /* try to accumulate duration as PTS */
898 fpts = avsync->vpts + avsync->last_frame->duration;
899 } else {
900 fpts = avsync->vpts;
901 }
902 }
903 systime += pts_correction;
904
905 /* phase adjustment */
906 if (avsync->phase_set)
907 systime += avsync->phase;
908
yongchun.lia50b1e92021-08-07 01:11:54 +0000909 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800910 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000911 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700912 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800913 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800914 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800915 return false;
916
Song Zhaoa2985cb2021-06-24 12:01:47 -0700917 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
918 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700919 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800920
yongchun.li0ee6e372021-08-20 04:26:04 -0700921 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700922 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800923 avsync->last_pts = fpts;
924 if (time_diff(&now, &avsync->sync_lost_print_time) >=
925 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700926 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800927 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800928 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700929 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800930 } else
931 avsync->sync_lost_cnt++;
932 }
Song Zhaod62bb392021-04-23 12:25:49 -0700933
934 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
935 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700936 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700937 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700938 /* outlier by stream error */
939 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700940 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700941 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
942 log_info("render outlier %u", fpts);
943 return true;
944 }
945 }
946
947 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800948 avsync->state = AV_SYNC_STAT_SYNC_LOST;
949 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800950 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700951 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800952 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700953
Song Zhao7e24b182022-04-01 08:46:40 -0700954 if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700955 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700956 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700957 msync_session_set_video_dis(avsync->fd, fpts);
958 avsync->last_disc_pts = fpts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700959 }
960
961 if ((int)(systime - fpts) > 0) {
962 if ((int)(systime - fpts) < avsync->disc_thres_max) {
963 /* catch up PCR */
Song Zhaof46932e2021-05-21 01:51:45 -0700964 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700965 } else {
966 /* render according to FPS */
967 if (!VALID_TS(avsync->last_r_syst) ||
968 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
969 avsync->last_r_syst = systime;
970 return true;
971 }
972 return false;
973 }
974 } else if (LIVE_MODE(avsync->mode)) {
975 /* hold if the gap is small */
976 if ((int)(fpts - systime) < avsync->disc_thres_max) {
977 return false;
978 } else {
979 /* render according to FPS */
980 if (!VALID_TS(avsync->last_r_syst) ||
981 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
982 avsync->last_r_syst = systime;
983 return true;
984 }
985 return false;
986 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800987 }
988 }
989
Song Zhao52f55192021-05-06 10:52:21 -0700990 /* In some cases, keeping pattern will enlarge the gap */
991 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
992 avsync->first_frame_toggled) {
993 reset_pattern(avsync->pattern_detector);
Song Zhaofd007632022-09-30 16:21:30 -0700994 log_info("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700995 systime, fpts);
996 }
997
Song Zhaoc03ba122020-12-23 21:54:02 -0800998 expire = (int)(systime - fpts) >= 0;
999
1000 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -08001001 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001002 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -08001003 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001004 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001005 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001006 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -08001007 }
Song Zhao6dce2672022-01-13 11:32:44 -08001008 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -08001009 && avsync->first_frame_toggled) {
1010 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -08001011 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001012 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -08001013 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001014 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001015 }
1016 }
1017
Song Zhaoa58c3e92021-03-09 18:52:55 -08001018 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -08001019 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -08001020 (avsync->last_frame?avsync->last_frame->hold_period:0),
1021 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -08001022 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -08001023
1024 if (expire) {
1025 avsync->vpts = fpts;
1026 /* phase adjustment */
1027 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +00001028 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -08001029 if ((int)(systime - fpts) >= 0 &&
1030 (int)(fpts + interval - systime) > 0) {
1031 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -08001032 avsync->phase_set = true;
Song Zhaofd007632022-09-30 16:21:30 -07001033 log_debug("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -08001034 }
Song Zhao1561e542022-01-12 10:37:55 -08001035 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -08001036 if ((int)(systime - fpts) >= 0 &&
1037 (int)(fpts + interval - systime) > 0) {
1038 int vsync_pts_delta = (int)(systime - fpts);
1039
1040 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1041 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001042 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001043 log_info("[%d] too aligned adjust phase to %d",
1044 avsync->session_id, (int)avsync->phase);
1045 }
1046 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001047 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001048 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaofd007632022-09-30 16:21:30 -07001049 log_info("[%d]sync setup on frame %u", avsync->session_id, fpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001050 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001051 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001052 }
1053 return expire;
1054}
1055
Song Zhao35a82df2021-04-15 10:58:49 -07001056static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001057{
Song Zhao35a82df2021-04-15 10:58:49 -07001058 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001059 log_trace("[%d]cur_period: %d last_period: %d",
1060 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -07001061 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
1062 ret = true;
1063 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
1064 ret = true;
1065 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
1066 ret = true;
1067 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
1068 ret = true;
1069
1070 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -08001071}
1072
1073int av_sync_set_speed(void *sync, float speed)
1074{
1075 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1076
1077 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001078 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001079 return -1;
1080 }
1081
Song Zhao76005282022-03-08 16:49:41 -08001082 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001083 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001084 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001085 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001086
Song Zhaoea5a0412021-01-18 16:40:08 -08001087 avsync->speed = speed;
1088
1089 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhaoa73fcf32023-01-13 08:12:26 -08001090 if (speed == 1.0)
1091 msync_session_set_wall_adj_thres(avsync->fd, DEFAULT_WALL_ADJ_THRES);
1092 else
1093 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
1094 log_info("[%d]adjust wall adj threshold to %d", avsync->session_id,
1095 (speed == 1.0) ? DEFAULT_WALL_ADJ_THRES : avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -08001096 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001097
Song Zhaoea5a0412021-01-18 16:40:08 -08001098 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1099 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001100}
1101
1102int av_sync_change_mode(void *sync, enum sync_mode mode)
1103{
1104 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1105
1106 if (!avsync)
1107 return -1;
1108
Song Zhaoea5a0412021-01-18 16:40:08 -08001109 if (msync_session_set_mode(avsync->fd, mode)) {
1110 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001111 return -1;
1112 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001113 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001114 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001115 return 0;
1116}
1117
Song Zhao01031bb2021-05-13 21:23:20 -07001118int av_sync_get_mode(void *sync, enum sync_mode *mode)
1119{
1120 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1121
1122 if (!avsync || !mode)
1123 return -1;
1124
1125 *mode = avsync->mode;
1126 return 0;
1127}
1128
Song Zhaoc03ba122020-12-23 21:54:02 -08001129int av_sync_set_pause_pts(void *sync, pts90K pts)
1130{
1131 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1132
1133 if (!avsync)
1134 return -1;
1135
1136 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001137 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001138 return 0;
1139}
1140
1141int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1142{
1143 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1144
1145 if (!avsync)
1146 return -1;
1147
1148 avsync->pause_pts_cb = cb;
1149 avsync->pause_cb_priv = priv;
1150 return 0;
1151}
Song Zhaoea5a0412021-01-18 16:40:08 -08001152
yongchun.li428390d2022-02-17 17:15:40 -08001153int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1154{
1155 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1156
1157 if (!avsync)
1158 return -1;
1159
1160 avsync->underflow_cb = cb;
1161 avsync->underflow_cb_priv = priv;
1162
1163 if (cfg)
1164 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1165 else
1166 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1167
1168 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1169 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1170 avsync->underflow_cfg.time_thresh);
1171 return 0;
1172}
Song Zhaoea5a0412021-01-18 16:40:08 -08001173static void trigger_audio_start_cb(struct av_sync_session *avsync,
1174 avs_ascb_reason reason)
1175{
1176 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001177 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001178 pthread_mutex_lock(&avsync->lock);
1179 if (avsync->audio_start) {
1180 avsync->audio_start(avsync->audio_start_priv, reason);
1181 avsync->session_started = true;
1182 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001183 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001184 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1185 }
1186 pthread_mutex_unlock(&avsync->lock);
1187 }
1188}
1189
1190avs_start_ret av_sync_audio_start(
1191 void *sync,
1192 pts90K pts,
1193 pts90K delay,
1194 audio_start_cb cb,
1195 void *priv)
1196{
1197 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1198 uint32_t start_mode;
yongchun.li06965172022-12-14 19:50:31 -08001199 uint32_t systime = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001200 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1201 bool create_poll_t = false;
1202
1203 if (!avsync)
1204 return ret;
1205
yongchun.li59e873d2021-07-07 11:42:38 -07001206 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1207 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001208
yongchun.li06965172022-12-14 19:50:31 -08001209 if (avsync->in_audio_switch) {
1210 msync_session_get_wall(avsync->fd, &systime, NULL);
1211 if (systime == AV_SYNC_INVALID_PTS) {
1212 log_info("%d Invalid systime could be paused pts %d ms switch_state %d again",
1213 avsync->session_id, (int) pts/90, avsync->audio_switch_state);
1214 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
1215 ret = AV_SYNC_ASTART_AGAIN;
1216 goto exit;
1217 }
1218 }
1219
yongchun.li59e873d2021-07-07 11:42:38 -07001220 if (avsync->in_audio_switch &&
1221 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1222 {
1223 start_mode = AVS_START_SYNC;
1224 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1225 } else {
1226 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1227 log_error("[%d]fail to set audio start", avsync->session_id);
1228 }
1229 if (avsync->in_audio_switch &&
1230 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1231 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
Song Zhao4bd18762022-09-30 16:39:52 -07001232 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB
1233 && start_mode == AVS_START_SYNC) {
yongchun.li59e873d2021-07-07 11:42:38 -07001234 log_info("%d audio_switch audio need drop first.ahead %d ms",
1235 avsync->session_id, (int)(systime - pts)/90);
1236 ret = AV_SYNC_ASTART_AGAIN;
1237 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1238 goto exit;
1239 }
1240 else {
1241 int diff = (int)(pts - systime);
1242 log_info("%d audio_switch_state to start mode %d diff %d ms",
1243 avsync->session_id, start_mode, diff/90);
yongchun.li59e873d2021-07-07 11:42:38 -07001244 if (diff < A_ADJ_THREDHOLD_LB) {
1245 log_info("%d orig mode %d already close enough direct start",
1246 avsync->session_id, start_mode);
1247 start_mode = AVS_START_SYNC;
Song Zhao4bd18762022-09-30 16:39:52 -07001248 } else if (start_mode != AVS_START_ASYNC) {
1249 log_info("%d drop too far mode %d need to try ASYNC",
1250 avsync->session_id, start_mode);
1251 msync_session_set_audio_stop(avsync->fd);
1252 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1253 log_error("[%d]fail to set audio start", avsync->session_id);
1254 log_info("%d New start mode %d",
1255 avsync->session_id, start_mode);
yongchun.li59e873d2021-07-07 11:42:38 -07001256 }
Song Zhao4bd18762022-09-30 16:39:52 -07001257 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
yongchun.li59e873d2021-07-07 11:42:38 -07001258 }
yongchun.li107a6162021-05-05 02:38:57 -07001259 }
1260
Song Zhaoea5a0412021-01-18 16:40:08 -08001261 if (start_mode == AVS_START_SYNC) {
1262 ret = AV_SYNC_ASTART_SYNC;
1263 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001264 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001265 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001266 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001267 avsync->state = AV_SYNC_STAT_RUNNING;
1268 } else if (start_mode == AVS_START_AGAIN) {
1269 ret = AV_SYNC_ASTART_AGAIN;
1270 }
1271
1272 if (ret == AV_SYNC_ASTART_AGAIN)
1273 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001274
Song Zhao76005282022-03-08 16:49:41 -08001275 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1276 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001277 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001278
1279 if (start_mode == AVS_START_ASYNC) {
1280 if (!cb) {
1281 log_error("[%d]invalid cb", avsync->session_id);
1282 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001283 }
Song Zhao76005282022-03-08 16:49:41 -08001284 avsync->audio_start = cb;
1285 avsync->audio_start_priv = priv;
1286 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001287
Song Zhaod62bb392021-04-23 12:25:49 -07001288 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001289 int ret;
1290
1291 log_info("[%d]start poll thread", avsync->session_id);
1292 avsync->quit_poll = false;
1293 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1294 if (ret) {
1295 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1296 return AV_SYNC_ASTART_ERR;
1297 }
1298 }
Song Zhaod62bb392021-04-23 12:25:49 -07001299 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001300 msync_session_get_wall(avsync->fd, &systime, NULL);
1301 log_info("[%d]return %u w %u pts %u d %u",
1302 avsync->session_id, ret, systime, pts, delay);
1303 }
1304exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001305 log_info("[%d]return %u", avsync->session_id, ret);
1306 return ret;
1307}
1308
1309int av_sync_audio_render(
1310 void *sync,
1311 pts90K pts,
1312 struct audio_policy *policy)
1313{
1314 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001315 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001316 uint32_t systime;
1317 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1318 avs_audio_action action = AA_SYNC_AA_MAX;
1319
1320 if (!avsync || !policy)
1321 return -1;
1322
yongchun.li107a6162021-05-05 02:38:57 -07001323 msync_session_get_wall(avsync->fd, &systime, NULL);
1324
1325 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1326 pts, systime, avsync->mode, (int)(pts-systime)/90);
1327
1328 if (avsync->in_audio_switch
1329 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
Song Zhao4bd18762022-09-30 16:39:52 -07001330 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_MB) {
yongchun.li107a6162021-05-05 02:38:57 -07001331 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1332 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1333 action = AV_SYNC_AA_RENDER;
1334 } else if ((int)(systime - pts) > 0) {
1335 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1336 (int)(systime - pts)/90, systime, pts);
1337 action = AV_SYNC_AA_DROP;
1338 } else {
1339 action = AV_SYNC_AA_INSERT;
1340 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1341 (int)(pts - systime)/90, systime, pts);
1342 }
1343 goto done;
1344 }
1345
Song Zhaoea5a0412021-01-18 16:40:08 -08001346 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1347 avsync->mode == AV_SYNC_MODE_AMASTER) {
1348 action = AV_SYNC_AA_RENDER;
1349 goto done;
1350 }
1351
Song Zhaod62bb392021-04-23 12:25:49 -07001352 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001353 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001354 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1355 action = AV_SYNC_AA_DROP;
1356 goto done;
1357 }
1358
Song Zhao7daf3a12021-05-10 22:22:25 -07001359 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1360 avsync->mode == AV_SYNC_MODE_AMASTER) {
1361 action = AV_SYNC_AA_RENDER;
1362 goto done;
1363 }
1364
Song Zhaod62bb392021-04-23 12:25:49 -07001365 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1366 LIVE_MODE(avsync->mode) &&
1367 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1368 /* outlier by stream error */
1369 avsync->outlier_cnt++;
1370 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1371 /* treat as disc, just drop current frame */
1372 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1373 avsync->outlier_cnt = 0;
1374 action = AV_SYNC_AA_DROP;
1375 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001376 goto done;
1377 }
1378 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1379 pts = systime;
1380 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001381 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001382 goto done;
1383 }
1384
1385 avsync->outlier_cnt = 0;
1386 /* low bound from sync_lost to sync_setup */
1387 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1388 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1389 action = AV_SYNC_AA_RENDER;
1390 goto done;
1391 }
1392
1393 /* high bound of sync_setup */
1394 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1395 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1396 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001397 action = AV_SYNC_AA_RENDER;
1398 goto done;
1399 }
1400
1401 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001402 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001403 action = AV_SYNC_AA_DROP;
1404 goto done;
1405 }
1406
1407 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001408 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001409 action = AV_SYNC_AA_INSERT;
1410 goto done;
1411 }
1412
1413done:
1414 policy->action = action;
1415 policy->delta = (int)(systime - pts);
1416 if (action == AV_SYNC_AA_RENDER) {
1417 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001418 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001419 if (!out_lier)
1420 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001421 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001422 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001423 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1424 msync_session_update_apts(avsync->fd, systime, pts, 0);
1425 log_info("[%d] audio switch done sys %u pts %u",
1426 avsync->session_id, systime, pts);
1427 msync_session_set_audio_switch(avsync->fd, false);
1428 avsync->in_audio_switch = false;
1429 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1430 } else {
1431 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1432 avsync->session_id, action, systime, pts, systime - pts);
1433 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001434 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001435 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001436 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001437 avsync->last_disc_pts != pts &&
1438 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001439 log_info ("[%d]audio disc %u --> %u",
1440 avsync->session_id, systime, pts);
1441 msync_session_set_audio_dis(avsync->fd, pts);
1442 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001443 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001444 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001445
1446 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001447 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001448 if (!avsync->audio_drop_cnt)
1449 avsync->audio_drop_start = now;
1450 avsync->audio_drop_cnt++;
1451 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1452 log_info ("[%d]audio keep dropping sys %u vs a %u",
1453 avsync->session_id, systime, pts);
1454 msync_session_set_audio_dis(avsync->fd, pts);
1455 }
Song Zhao409739b2021-05-12 22:21:40 -07001456 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001457 if (action != AV_SYNC_AA_DROP)
1458 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001459 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001460 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001461 }
1462
1463 return ret;
1464}
1465
1466int av_sync_get_clock(void *sync, pts90K *pts)
1467{
1468 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1469
1470 if (!avsync || !pts)
1471 return -1;
1472 return msync_session_get_wall(avsync->fd, pts, NULL);
1473}
1474
1475static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001476 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001477 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001478{
Song Zhao76005282022-03-08 16:49:41 -08001479 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1480 avsync->session_id, avsync->active_mode, avsync->mode,
1481 v_active, a_active, v_timeout, stat);
1482
1483 /* iptv delayed start */
1484 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1485 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1486
Song Zhaoea5a0412021-01-18 16:40:08 -08001487 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1488 float speed;
Song Zhao7e8c68f2022-07-12 16:24:30 -07001489 if (a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001490 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001491 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhao6183ca92022-07-29 09:57:03 -07001492 } else if (!a_active && !avsync->session_started) {
1493 /* quit waiting ASAP */
1494 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoea5a0412021-01-18 16:40:08 -08001495 }
1496
1497 if (!msync_session_get_rate(avsync->fd, &speed)) {
1498 /* speed change is triggered by asink,
1499 * attached audio HAL will handle it
1500 */
1501 if (speed != avsync->speed)
1502 log_info("[%d]new rate %f", avsync->session_id, speed);
Song Zhaoa73fcf32023-01-13 08:12:26 -08001503#if 0 //don't use freerun for trick mode. Or A/V gap will keep increasing
Song Zhaoea5a0412021-01-18 16:40:08 -08001504 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001505 if (avsync->mode != avsync->backup_mode) {
1506 avsync->mode = avsync->backup_mode;
1507 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1508 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001509 } else {
1510 avsync->backup_mode = avsync->mode;
1511 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1512 log_info("[%d]audio to freerun mode", avsync->session_id);
1513 }
Song Zhaoa73fcf32023-01-13 08:12:26 -08001514#endif
Song Zhaoea5a0412021-01-18 16:40:08 -08001515 avsync->speed = speed;
1516 }
Song Zhaod62bb392021-04-23 12:25:49 -07001517 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1518 struct session_debug debug;
1519 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001520 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001521 avsync->backup_mode = avsync->mode;
1522 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001523 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001524 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001525 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001526 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001527 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001528 log_warn("[%d]audio back to mode %d",
1529 avsync->session_id, avsync->mode);
1530 }
1531 }
Song Zhao76005282022-03-08 16:49:41 -08001532 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1533 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001534 }
1535}
1536
1537static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001538 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001539 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001540{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001541 struct session_debug debug;
1542
Song Zhao76005282022-03-08 16:49:41 -08001543 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1544 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001545 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1546 if (debug.debug_freerun && !avsync->debug_freerun) {
1547 avsync->backup_mode = avsync->mode;
1548 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1549 avsync->debug_freerun = true;
1550 log_warn("[%d]video to freerun mode", avsync->session_id);
1551 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1552 avsync->mode = avsync->backup_mode;
1553 avsync->debug_freerun = false;
1554 log_warn("[%d]video back to mode %d",
1555 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001556 }
1557 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001558}
1559
1560static void * poll_thread(void * arg)
1561{
1562 int ret = 0;
1563 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1564 const int fd = avsync->fd;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001565 int poll_timeout = 10;
Song Zhaoea5a0412021-01-18 16:40:08 -08001566 struct pollfd pfd = {
1567 /* default blocking capture */
Song Zhao4bd18762022-09-30 16:39:52 -07001568 .events = POLLPRI,
Song Zhaoea5a0412021-01-18 16:40:08 -08001569 .fd = avsync->fd,
1570 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001571 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001572
Song Zhaoea5a0412021-01-18 16:40:08 -08001573 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001574
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001575 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001576 prctl (PR_SET_NAME, "avs_apoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001577 sflag = SRC_A;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001578 } else if (avsync->type == AV_SYNC_TYPE_VIDEO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001579 prctl (PR_SET_NAME, "avs_vpoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001580 sflag = SRC_V;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001581 poll_timeout = 100;
1582 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001583
Song Zhaoea5a0412021-01-18 16:40:08 -08001584 while (!avsync->quit_poll) {
1585 for (;;) {
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001586 ret = poll(&pfd, 1, poll_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001587 if (ret > 0)
1588 break;
1589 if (avsync->quit_poll)
1590 goto exit;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001591 if (errno == EINTR) {
1592 log_debug("[%d] poll interrupted", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001593 continue;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001594 }
Song Zhao4bd18762022-09-30 16:39:52 -07001595 if (errno == EAGAIN || errno == ENOMEM) {
1596 log_info("[%d] poll error %d", avsync->session_id, errno);
1597 continue;
1598 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001599 }
1600
1601 /* error handling */
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001602 if (pfd.revents & POLLERR) {
1603 usleep(poll_timeout * 1000);
1604 continue;
1605 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001606
Song Zhao4bd18762022-09-30 16:39:52 -07001607 if (pfd.revents & POLLNVAL) {
1608 log_warn("[%d] fd closed", avsync->session_id);
1609 goto exit;
1610 }
Song Zhaod62bb392021-04-23 12:25:49 -07001611 /* mode change. Non-exclusive wait so all the processes
1612 * shall be woken up
1613 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001614 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001615 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001616 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001617
Song Zhao9fef59c2022-08-17 12:43:10 -07001618 msync_session_get_stat(fd, true, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001619 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001620
1621 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001622 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001623 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001624 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001625 usleep(10000);
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001626 } else {
1627 log_debug("[%d] unexpected revents %x", avsync->session_id, pfd.revents);
1628 usleep(poll_timeout * 1000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001629 }
1630 }
1631exit:
1632 log_info("[%d]quit", avsync->session_id);
1633 return NULL;
1634}
1635
Song Zhao623e2f12021-09-03 15:54:04 -07001636#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1637/* return ppm between demod and PCR clock */
1638int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1639{
1640 int fd = -1, ppm = 0, nread;
1641 char buf[128];
1642 uint32_t reg_v, lock;
1643 float val;
1644
1645 fd = open(DEMOD_NODE, O_RDWR);
1646 if (fd < 0) {
1647 log_warn("node not found %s", DEMOD_NODE);
1648 /* do not retry */
1649 avsync->ppm_adjusted = true;
1650 return 0;
1651 }
1652 snprintf(buf, sizeof(buf), "%d", 5);
1653 write(fd, buf, 2);
1654
1655 lseek(fd, 0, SEEK_SET);
1656
hanghang.luo02efd312022-08-26 09:49:53 +08001657 nread = read(fd, buf, sizeof(buf)-1);
Song Zhao623e2f12021-09-03 15:54:04 -07001658 if (nread <= 0) {
1659 log_error("read error");
1660 goto err;
1661 }
1662 buf[nread] = 0;
1663 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1664 log_error("wrong format %s", buf);
1665 goto err;
1666 }
1667 if (lock != 0x1f) {
1668 log_info("demod not locked");
1669 goto err;
1670 }
1671 if (reg_v > ((2 << 20) - 1))
1672 reg_v -= (2 << 21);
1673 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1674 ppm = val;
1675 log_info("ppm from SFO %d", ppm);
1676 avsync->ppm_adjusted = true;
1677
1678err:
1679 if (fd >= 0)
1680 close(fd);
1681 return ppm;
1682}
1683
Song Zhaod62bb392021-04-23 12:25:49 -07001684int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001685{
1686 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001687 struct pcr_info pcr;
1688 enum pcr_monitor_status status;
1689 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001690 if (!avsync)
1691 return -1;
1692
1693 if (avsync->type != AV_SYNC_TYPE_PCR)
1694 return -2;
1695
Song Zhao623e2f12021-09-03 15:54:04 -07001696 /* initial estimation from Demod SFO HW */
1697 if (!avsync->ppm_adjusted) {
1698 ppm = dmod_get_sfo_dev(avsync);
1699 if (ppm != 0) {
1700 /* ppm > 0 means board clock is faster */
1701 msync_session_set_clock_dev(avsync->fd, -ppm);
1702 }
1703 }
wei.dubcc2ed22021-05-19 07:16:10 -04001704 pcr.monoclk = mono_clock / 1000;
1705 pcr.pts = (long long) pts * 1000 / 90;
1706 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1707
1708 status = pcr_monitor_get_status(avsync->pcr_monitor);
1709
1710 if (status >= DEVIATION_READY) {
1711 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1712 if (avsync->ppm != ppm) {
1713 avsync->ppm = ppm;
1714 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1715 if (msync_session_set_clock_dev(avsync->fd, ppm))
1716 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001717 else
1718 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001719 }
1720 }
1721
Song Zhaod62bb392021-04-23 12:25:49 -07001722 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001723}
1724
Song Zhaod62bb392021-04-23 12:25:49 -07001725int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001726{
1727 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1728
1729 if (!avsync)
1730 return -1;
1731
Song Zhaod62bb392021-04-23 12:25:49 -07001732 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001733}
1734
1735int av_sync_set_session_name(void *sync, const char *name)
1736{
1737 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1738
1739 if (!avsync)
1740 return -1;
1741
1742 return msync_session_set_name(avsync->fd, name);
1743}
yongchun.li107a6162021-05-05 02:38:57 -07001744
1745int av_sync_set_audio_switch(void *sync, bool start)
1746{
1747 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1748 bool v_active, a_active, v_timeout;
1749
1750 if (!avsync)
1751 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001752 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001753 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001754 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001755 log_error("[%d] can not get session state",
1756 avsync->session_id);
1757 return -1;
1758 }
1759 if (!v_active || !a_active) {
1760 log_error("[%d] no apply if not AV both active v %d a %d",
1761 avsync->session_id, v_active, a_active);
1762 return -1;
1763 }
1764 if (msync_session_set_audio_switch(avsync->fd, start)) {
1765 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1766 return -1;
1767 }
1768 avsync->in_audio_switch = start;
1769 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1770 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1771 return 0;
1772}
1773
1774int av_sync_get_audio_switch(void *sync, bool *start)
1775{
1776 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1777
1778 if (!avsync)
1779 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001780 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001781 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001782 log_error("[%d] can not audio seamless switch state",
1783 avsync->session_id);
1784 return -1;
1785 }
1786 if (start) *start = avsync->in_audio_switch;
1787 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001788}
Song Zhao8039f562021-05-18 18:11:25 -07001789
Song Zhao623e2f12021-09-03 15:54:04 -07001790enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001791{
1792 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1793
wei.dubcc2ed22021-05-19 07:16:10 -04001794 if (!avsync || !ppm)
1795 return CLK_RECOVERY_ERR;
1796 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001797 return CLK_RECOVERY_NOT_RUNNING;
1798
wei.dubcc2ed22021-05-19 07:16:10 -04001799 if (msync_session_get_clock_dev(avsync->fd, ppm))
1800 return CLK_RECOVERY_ERR;
1801
1802 if (*ppm == 0)
1803 return CLK_RECOVERY_ONGOING;
1804 else
1805 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001806}
Song Zhao95bd0922021-09-21 14:07:46 -07001807
1808static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1809{
1810 int ret;
1811
1812 if (!avsync->frame_q) {
1813 avsync->frame_q = create_q(MAX_FRAME_NUM);
1814 if (!avsync->frame_q) {
1815 log_error("[%d]create queue fail", avsync->session_id);
1816
1817 return -1;
1818 }
1819 }
1820
1821 ret = queue_item(avsync->frame_q, frame);
1822 if (ret)
hanghang.luo02efd312022-08-26 09:49:53 +08001823 log_error("queue fail:%d", ret);
Song Zhao95bd0922021-09-21 14:07:46 -07001824 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1825 return ret;
1826}
1827
1828int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1829{
1830 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1831
1832 if (!avsync)
1833 return -1;
1834 avsync->msys = msys;
1835 return 0;
1836}
1837
1838static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1839{
1840 struct vframe *frame = NULL, *enter_last_frame = NULL;
1841 uint64_t systime;
1842 int toggle_cnt = 0;
1843
1844 enter_last_frame = avsync->last_frame;
1845 systime = avsync->msys;
1846 log_debug("[%d]sys %llu", avsync->session_id, systime);
1847 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1848 if (systime >= frame->mts) {
1849 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1850 toggle_cnt++;
1851
1852 if (avsync->last_frame)
1853 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1854
1855 dqueue_item(avsync->frame_q, (void **)&frame);
1856 if (avsync->last_frame) {
1857 /* free frame that are not for display */
1858 if (toggle_cnt > 1) {
1859 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1860 avsync->last_frame->mts, frame->mts, systime);
1861 avsync->last_frame->free(avsync->last_frame);
1862 }
1863 } else {
1864 avsync->first_frame_toggled = true;
1865 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1866 }
1867 avsync->last_frame = frame;
1868 } else
1869 break;
1870 }
1871
1872 if (avsync->last_frame) {
1873 if (enter_last_frame != avsync->last_frame)
hanghang.luo02efd312022-08-26 09:49:53 +08001874 log_debug("[%d]pop %lu", avsync->session_id, avsync->last_frame->pts);
1875 log_trace("[%d]pop=%llu, system=%llu, diff %llu(ms), QNum=%d", avsync->session_id,
Song Zhao95bd0922021-09-21 14:07:46 -07001876 avsync->last_frame->mts,
1877 systime, (systime - avsync->last_frame->mts) / 1000000,
1878 queue_size(avsync->frame_q));
1879 } else
1880 if (enter_last_frame != avsync->last_frame)
1881 log_debug("[%d]pop (nil)", avsync->session_id);
1882
1883 if (avsync->last_frame)
1884 avsync->last_frame->hold_period++;
1885 return avsync->last_frame;
1886}
Song Zhao6183ca92022-07-29 09:57:03 -07001887
1888int avs_sync_stop_audio(void *sync)
1889{
1890 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1891
1892 if (!avsync)
1893 return -1;
1894
1895 return msync_session_stop_audio(avsync->fd);
1896}
bo.xiao05ba1ac2022-12-13 14:38:13 +08001897
1898int avs_sync_set_eos(void *sync)
1899{
1900 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1901
1902 if (!avsync)
1903 return -1;
1904
1905 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
1906 if (avsync->state == AV_SYNC_STAT_INIT) {
1907 avsync->state = AV_SYNC_STAT_RUNNING;
1908 log_debug("[%d]eos trigger state change: init --> running", avsync->session_id);
1909 }
1910 }
1911
1912 return 0;
1913}