blob: 5f210a030ba5653ae7828e03b97c7f19d5710a72 [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 Zhaof46932e2021-05-21 01:51:45 -0700161#define AV_DISC_THRES_MIN (TIME_UNIT90K / 3)
162#define AV_DISC_THRES_MAX (TIME_UNIT90K * 10)
Song Zhao7daf3a12021-05-10 22:22:25 -0700163#define A_ADJ_THREDHOLD_HB (900 * 6) //60ms
164#define A_ADJ_THREDHOLD_LB (900 * 2) //20ms
Song Zhao52f55192021-05-06 10:52:21 -0700165#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800166#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhao76005282022-03-08 16:49:41 -0800167#define LIVE_MODE(m) ((m) == AV_SYNC_MODE_PCR_MASTER || (m) == AV_SYNC_MODE_IPTV)
Song Zhao7e24b182022-04-01 08:46:40 -0700168#define V_DISC_MODE(mode) (LIVE_MODE(mode) || (mode) == AV_SYNC_MODE_VMASTER)
Song Zhaod62bb392021-04-23 12:25:49 -0700169
Song Zhao065800e2021-05-26 15:56:06 -0700170#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
Song Zhaod62bb392021-04-23 12:25:49 -0700171#define OUTLIER_MAX_CNT 8
Song Zhaoa2985cb2021-06-24 12:01:47 -0700172#define VALID_TS(x) ((x) != -1)
yongchun.li428390d2022-02-17 17:15:40 -0800173#define UNDERFLOW_CHECK_THRESH_MS (100)
Song Zhaoc03ba122020-12-23 21:54:02 -0800174
yongchun.li0ee6e372021-08-20 04:26:04 -0700175static uint64_t time_diff (struct timespec *b, struct timespec *a);
Song Zhaoc03ba122020-12-23 21:54:02 -0800176static bool frame_expire(struct av_sync_session* avsync,
177 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800178 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800179 struct vframe * frame,
180 struct vframe * next_frame,
181 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700182static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800183 int cur_period,
184 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800185static void * poll_thread(void * arg);
186static void trigger_audio_start_cb(struct av_sync_session *avsync,
187 avs_ascb_reason reason);
Song Zhao95bd0922021-09-21 14:07:46 -0700188static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync);
189static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame);
fei.deng55389b62022-08-18 23:46:50 +0800190
Song Zhao2f6744b2021-11-03 21:23:50 -0700191pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER;
Song Zhaoc03ba122020-12-23 21:54:02 -0800192
Song Zhaoea5a0412021-01-18 16:40:08 -0800193int av_sync_open_session(int *session_id)
194{
Song Zhao2f6744b2021-11-03 21:23:50 -0700195 int fd = -1;
Song Zhaoea5a0412021-01-18 16:40:08 -0800196 int id, rc;
197
Song Zhao2f6744b2021-11-03 21:23:50 -0700198 pthread_mutex_lock(&glock);
199 fd = msync_create_session();
Song Zhaoea5a0412021-01-18 16:40:08 -0800200 if (fd < 0) {
201 log_error("fail");
Song Zhao2f6744b2021-11-03 21:23:50 -0700202 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800203 }
204 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
205 if (rc) {
206 log_error("new session errno:%d", errno);
Song Zhao2f6744b2021-11-03 21:23:50 -0700207 msync_destory_session(fd);
208 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800209 }
210 *session_id = id;
Song Zhao2f6744b2021-11-03 21:23:50 -0700211 log_debug("new avsession id %d fd %d", id, fd);
212exit:
213 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800214 return fd;
215}
216
217void av_sync_close_session(int session)
218{
Song Zhao2f6744b2021-11-03 21:23:50 -0700219 log_debug("session closed fd %d", session);
220 pthread_mutex_lock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800221 msync_destory_session(session);
Song Zhao2f6744b2021-11-03 21:23:50 -0700222 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800223}
224
225static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800226 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800227 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800228 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800229 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800230{
231 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800232 char dev_name[20];
Song Zhao2f6744b2021-11-03 21:23:50 -0700233 int retry = 10;
Song Zhaoc03ba122020-12-23 21:54:02 -0800234
fei.deng55389b62022-08-18 23:46:50 +0800235 /* debug log level */
236 {
237 const char *env= getenv( "AML_AVSYNC_DEBUG_LEVEL");
238 if ( env ) {
239 log_set_level(atoi(env));
240 }
241 }
242
Song Zhao95bd0922021-09-21 14:07:46 -0700243 log_info("[%d] mode %d type %d", session_id, mode, type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800244 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
245 if (!avsync) {
246 log_error("OOM");
247 return NULL;
248 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800249
Song Zhao95bd0922021-09-21 14:07:46 -0700250 if (type == AV_SYNC_TYPE_VIDEO &&
251 mode == AV_SYNC_MODE_VIDEO_MONO) {
252 if (session_id < AV_SYNC_SESSION_V_MONO) {
253 log_error("wrong session id %d", session_id);
254 goto err;
255 }
256 avsync->type = type;
257 avsync->mode = mode;
258 avsync->fd = -1;
259 avsync->session_id = session_id;
260 log_info("[%d]init", avsync->session_id);
261 return avsync;
262 }
263
Song Zhaoea5a0412021-01-18 16:40:08 -0800264 if (type == AV_SYNC_TYPE_VIDEO) {
265 avsync->pattern_detector = create_pattern_detector();
266 if (!avsync->pattern_detector) {
267 log_error("pd create fail");
268 goto err;
269 }
270
271 if (!start_thres)
272 avsync->start_thres = DEFAULT_START_THRESHOLD;
273 else {
274 if (start_thres > 5) {
275 log_error("start_thres too big: %d", start_thres);
276 goto err2;
277 }
278 avsync->start_thres = start_thres;
279 }
280 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800281 avsync->phase_adjusted = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800282 avsync->first_frame_toggled = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800283 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800284
285 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800286 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800287 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800288 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800289 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800290 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800291 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800292 avsync->speed = 1.0f;
293 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhao409739b2021-05-12 22:21:40 -0700294 avsync->vsync_interval = -1;
295 avsync->last_disc_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700296 avsync->last_log_syst = -1;
297 avsync->last_pts = -1;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700298 avsync->last_q_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700299 avsync->last_wall = -1;
300 avsync->fps_interval = -1;
301 avsync->last_r_syst = -1;
bo.xiao5821fc72021-07-11 22:47:00 -0400302 avsync->timeout = -1;
303
Song Zhaof46932e2021-05-21 01:51:45 -0700304 if (msync_session_get_disc_thres(session_id,
305 &avsync->disc_thres_min, &avsync->disc_thres_max)) {
hanghang.luo02efd312022-08-26 09:49:53 +0800306 log_error("dev_name:%s; errno:%d; fail to get disc thres", dev_name, errno);
Song Zhaof46932e2021-05-21 01:51:45 -0700307 avsync->disc_thres_min = AV_DISC_THRES_MIN;
308 avsync->disc_thres_max = AV_DISC_THRES_MAX;
309 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800310
311 pthread_mutex_init(&avsync->lock, NULL);
Song Zhao9c09f772022-01-07 14:26:50 -0800312 log_info("[%d] start_thres %d disc_thres %u/%u", session_id,
Song Zhao95bd0922021-09-21 14:07:46 -0700313 start_thres, avsync->disc_thres_min, avsync->disc_thres_max);
Song Zhaoea5a0412021-01-18 16:40:08 -0800314
315 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
Song Zhao2f6744b2021-11-03 21:23:50 -0700316 while (retry) {
317 /* wait for sysfs to update */
318 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
319 if (avsync->fd > 0)
320 break;
321
322 retry--;
323 if (!retry) {
324 log_error("open %s errno %d", dev_name, errno);
325 goto err2;
326 }
327 usleep(20000);
Song Zhaoea5a0412021-01-18 16:40:08 -0800328 }
329
wei.dubcc2ed22021-05-19 07:16:10 -0400330 if (avsync->type == AV_SYNC_TYPE_PCR) {
331 if (pcr_monitor_init(&avsync->pcr_monitor)) {
332 log_error("pcr monitor init");
Song Zhao9cd27a52021-07-26 15:27:38 +0000333 goto err3;
wei.dubcc2ed22021-05-19 07:16:10 -0400334 }
335 }
336
Song Zhaoea5a0412021-01-18 16:40:08 -0800337 if (!attach) {
338 msync_session_set_mode(avsync->fd, mode);
339 avsync->mode = mode;
Song Zhao7e24b182022-04-01 08:46:40 -0700340 if (avsync->mode == AV_SYNC_MODE_VMASTER)
341 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -0800342 } else {
343 avsync->attached = true;
344 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
345 log_error("get mode");
Song Zhao9cd27a52021-07-26 15:27:38 +0000346 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800347 }
348 avsync->backup_mode = avsync->mode;
bo.xiao5821fc72021-07-11 22:47:00 -0400349 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800350 log_error("get policy");
Song Zhao9cd27a52021-07-26 15:27:38 +0000351 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800352 }
Song Zhao9fef59c2022-08-17 12:43:10 -0700353 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700354 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -0700355 log_error("get state");
Song Zhao9cd27a52021-07-26 15:27:38 +0000356 goto err4;
yongchun.li107a6162021-05-05 02:38:57 -0700357 }
358 if (avsync->in_audio_switch) {
359 log_info("audio_switch_state reseted the audio");
360 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
361 }
362
Song Zhaoea5a0412021-01-18 16:40:08 -0800363 log_info("[%d]retrieve sync mode %d policy %d",
364 session_id, avsync->mode, avsync->start_policy);
365 }
366
Song Zhaoc03ba122020-12-23 21:54:02 -0800367 return avsync;
Song Zhao9cd27a52021-07-26 15:27:38 +0000368err4:
wei.dubcc2ed22021-05-19 07:16:10 -0400369 if (avsync->pcr_monitor)
370 pcr_monitor_destroy(avsync->pcr_monitor);
Song Zhao9cd27a52021-07-26 15:27:38 +0000371err3:
372 close(avsync->fd);
Song Zhaoea5a0412021-01-18 16:40:08 -0800373err2:
374 destroy_pattern_detector(avsync->pattern_detector);
375err:
376 free(avsync);
377 return NULL;
378}
379
380void* av_sync_create(int session_id,
381 enum sync_mode mode,
382 enum sync_type type,
383 int start_thres)
384{
385 return create_internal(session_id, mode,
386 type, start_thres, false);
387}
388
389void* av_sync_attach(int session_id, enum sync_type type)
390{
Song Zhao95bd0922021-09-21 14:07:46 -0700391 if (type == AV_SYNC_TYPE_VIDEO)
392 return NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800393 return create_internal(session_id, AV_SYNC_MODE_MAX,
394 type, 0, true);
395}
396
397int av_sync_video_config(void *sync, struct video_config* config)
398{
399 struct av_sync_session *avsync = (struct av_sync_session *)sync;
400
401 if (!avsync || !config)
402 return -1;
403
404 if (config->delay != 1 && config->delay != 2) {
405 log_error("invalid delay: %d\n", config->delay);
406 return -1;
407 }
408
409 avsync->delay = config->delay;
Song Zhao6dce2672022-01-13 11:32:44 -0800410 avsync->extra_delay = config->extra_delay * 90;
Song Zhaoea5a0412021-01-18 16:40:08 -0800411
Song Zhao6dce2672022-01-13 11:32:44 -0800412 log_info("[%d] vsync delay: %d extra_delay: %d ms",
413 avsync->session_id, config->delay, config->extra_delay);
Song Zhaoea5a0412021-01-18 16:40:08 -0800414 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800415}
416
417static int internal_stop(struct av_sync_session *avsync)
418{
419 int ret = 0;
420 struct vframe *frame;
421
422 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800423 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
424 frame->free(frame);
425 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800426 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800427 pthread_mutex_unlock(&avsync->lock);
428 return ret;
429}
430
431/* destroy and detach from kernel session */
432void av_sync_destroy(void *sync)
433{
434 struct av_sync_session *avsync = (struct av_sync_session *)sync;
435
436 if (!avsync)
437 return;
438
Song Zhao95bd0922021-09-21 14:07:46 -0700439 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
440 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
441 log_info("[%d]done", avsync->session_id);
442 internal_stop(avsync);
443 destroy_q(avsync->frame_q);
444 free(avsync);
445 return;
446 }
Song Zhaob5458b32021-11-12 15:58:47 -0800447 log_info("[%d]begin type %d", avsync->session_id, avsync->type);
Song Zhaoea5a0412021-01-18 16:40:08 -0800448 if (avsync->state != AV_SYNC_STAT_INIT) {
449 if (avsync->type == AV_SYNC_TYPE_VIDEO)
450 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800451
Song Zhaoea5a0412021-01-18 16:40:08 -0800452 avsync->quit_poll = true;
453 if (avsync->poll_thread) {
454 pthread_join(avsync->poll_thread, NULL);
455 avsync->poll_thread = 0;
456 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700457 if (avsync->type == AV_SYNC_TYPE_AUDIO)
458 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoaf368d52021-02-17 17:53:45 -0800459 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800460
Song Zhaoea5a0412021-01-18 16:40:08 -0800461 if (avsync->session_started) {
462 if (avsync->type == AV_SYNC_TYPE_VIDEO)
463 msync_session_set_video_stop(avsync->fd);
464 else
465 msync_session_set_audio_stop(avsync->fd);
466 }
wei.dubcc2ed22021-05-19 07:16:10 -0400467
468 if(avsync->pcr_monitor)
469 pcr_monitor_destroy(avsync->pcr_monitor);
470
Song Zhaoea5a0412021-01-18 16:40:08 -0800471 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800472 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800473 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
474 destroy_q(avsync->frame_q);
475 destroy_pattern_detector(avsync->pattern_detector);
476 }
Song Zhaob5458b32021-11-12 15:58:47 -0800477 log_info("[%d]done type %d", avsync->session_id, avsync->type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800478 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800479}
480
bo.xiao5821fc72021-07-11 22:47:00 -0400481int avs_sync_set_start_policy(void *sync, struct start_policy* st_policy)
Song Zhaoea5a0412021-01-18 16:40:08 -0800482{
483 struct av_sync_session *avsync = (struct av_sync_session *)sync;
484
485 if (!avsync || !avsync->fd)
486 return -1;
487
Song Zhao47961d72022-08-29 14:04:44 -0700488 log_info("[%d]policy %u --> %u, timeout %d --> %d", avsync->session_id,
489 avsync->start_policy, st_policy->policy, avsync->timeout, st_policy->timeout);
Song Zhao76005282022-03-08 16:49:41 -0800490 if (LIVE_MODE(avsync->mode) &&
491 st_policy->policy != AV_SYNC_START_ASAP) {
492 log_error("policy %d not supported in live mode", st_policy->policy);
493 return -1;
494 }
495
bo.xiao5821fc72021-07-11 22:47:00 -0400496 avsync->start_policy = st_policy->policy;
497 avsync->timeout = st_policy->timeout;
Song Zhao76005282022-03-08 16:49:41 -0800498
Song Zhaoea5a0412021-01-18 16:40:08 -0800499 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400500 if (st_policy->policy != AV_SYNC_START_NONE &&
501 st_policy->policy != AV_SYNC_START_V_PEEK)
502 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800503
504 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800505}
506
507int av_sync_pause(void *sync, bool pause)
508{
509 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700510 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800511 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800512
Song Zhaob5458b32021-11-12 15:58:47 -0800513 if (!avsync) {
514 log_error("invalid handle");
Song Zhaoc03ba122020-12-23 21:54:02 -0800515 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800516 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800517
fei.deng55389b62022-08-18 23:46:50 +0800518 if (avsync->type == AV_SYNC_TYPE_VIDEO && avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
519 log_warn("ignore pause in video mono mode");
520 return -1;
521 }
522
Song Zhaob5458b32021-11-12 15:58:47 -0800523 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
524 log_warn("ignore pause in pcr master mode");
Song Zhaoea5a0412021-01-18 16:40:08 -0800525 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800526 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800527
Song Zhao9fef59c2022-08-17 12:43:10 -0700528 rc = msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -0700529 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700530 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700531
yongchun.li5f52fb02021-06-04 18:13:05 -0700532 /* ignore only when video try to pause when audio is acive, on which
533 the control of the STC will be relays.
534 When resume,it can do always as it is possible that video just
535 paused earlier without audio yet,then audio added later before resume.
536 We shall not igore that otherwise it could cause video freeze. */
537 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
538 avsync->type == AV_SYNC_TYPE_VIDEO &&
539 a_active &&
540 !avsync->in_audio_switch) {
541 if (!pause) {
542 log_info("[%d] clear video pause when audio active",
543 avsync->session_id);
544 avsync->paused = pause;
545 } else {
546 log_info("[%d] ignore the pause from video when audio active",
547 avsync->session_id);
548 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800549 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700550 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800551
yongchun.li107a6162021-05-05 02:38:57 -0700552 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
553 log_info("[%d] ignore the pause from audio", avsync->session_id);
554 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
555 return 0;
556 }
557
Song Zhaoea5a0412021-01-18 16:40:08 -0800558 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800559 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800560 log_info("[%d]paused:%d type:%d rc %d",
561 avsync->session_id, pause, avsync->type, rc);
yongchun.li428390d2022-02-17 17:15:40 -0800562 if (!avsync->paused && avsync->first_frame_toggled) {
563 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
564 log_info("[%d] resume update new frame time", avsync->session_id);
565 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800566 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800567}
568
569int av_sync_push_frame(void *sync , struct vframe *frame)
570{
571 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700572 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800573 struct av_sync_session *avsync = (struct av_sync_session *)sync;
574
575 if (!avsync)
576 return -1;
577
Song Zhao95bd0922021-09-21 14:07:46 -0700578 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
fei.deng55389b62022-08-18 23:46:50 +0800579 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
Song Zhao95bd0922021-09-21 14:07:46 -0700580 return video_mono_push_frame(avsync, frame);
fei.deng55389b62022-08-18 23:46:50 +0800581 }
Song Zhao95bd0922021-09-21 14:07:46 -0700582
Song Zhaoea5a0412021-01-18 16:40:08 -0800583 if (!avsync->frame_q) {
584 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400585 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800586 log_error("[%d]get policy", avsync->session_id);
587 return -1;
588 }
589
590 avsync->frame_q = create_q(MAX_FRAME_NUM);
591 if (!avsync->frame_q) {
592 log_error("[%d]create queue fail", avsync->session_id);
yongchun.li0ee6e372021-08-20 04:26:04 -0700593
Song Zhaoea5a0412021-01-18 16:40:08 -0800594 return -1;
595 }
596
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700597 {
Song Zhaoea5a0412021-01-18 16:40:08 -0800598 int ret;
599
600 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
601 if (ret) {
602 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
603 destroy_q(avsync->frame_q);
604 return -1;
605 }
606 }
607 }
608
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700609 if (avsync->last_q_pts != -1) {
Song Zhao7e24b182022-04-01 08:46:40 -0700610 if (frame->pts != -1 && avsync->mode == AV_SYNC_MODE_VMASTER) {
611 /* Sometimes app will fake PTS for trickplay, video PTS gap
612 * is really big depending on the speed. Have to adjust the
613 * threshold dynamically.
614 */
615 int gap = (int)(frame->pts - avsync->last_q_pts);
616 if (gap > avsync->disc_thres_min) {
617 avsync->disc_thres_min = gap * 6;
618 avsync->disc_thres_max = gap * 20;
619 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
620 msync_session_set_disc_thres(avsync->session_id,
621 avsync->disc_thres_min, avsync->disc_thres_max);
622 log_info("[%d] update disc_thres to %d/%d",avsync->session_id,
623 avsync->disc_thres_min, avsync->disc_thres_max);
624 }
625 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700626 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
627 /* TODO: wrong, should remove from back of queue */
Song Zhaoc03ba122020-12-23 21:54:02 -0800628 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700629 if (prev) {
630 prev->free(prev);
631 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
632 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700633 } else if (avsync->fps_cnt < 100) {
634 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700635
636 if (interval > 0 && interval <= 4500) {
637 if (avsync->fps_interval_acc == -1) {
638 avsync->fps_interval_acc = interval;
639 avsync->fps_cnt = 1;
640 } else {
641 avsync->fps_interval_acc += interval;
642 avsync->fps_cnt++;
643 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
644 if (avsync->fps_cnt == 100)
645 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
646 }
647 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800648 }
649 }
650
Song Zhao065800e2021-05-26 15:56:06 -0700651 if (frame->duration == -1)
652 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800653 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700654 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800655 ret = queue_item(avsync->frame_q, frame);
656 if (avsync->state == AV_SYNC_STAT_INIT &&
657 queue_size(avsync->frame_q) >= avsync->start_thres) {
658 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaoea5a0412021-01-18 16:40:08 -0800659 log_info("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800660 }
661
662 if (ret)
Song Zhaoe1b65602022-01-06 08:03:46 -0800663 log_error("queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400664 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800665 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800666}
667
668struct vframe *av_sync_pop_frame(void *sync)
669{
Song Zhaoea5a0412021-01-18 16:40:08 -0800670 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800671 struct av_sync_session *avsync = (struct av_sync_session *)sync;
672 int toggle_cnt = 0;
hanghang.luo02efd312022-08-26 09:49:53 +0800673 uint32_t systime = 0;
Song Zhao468fd652021-01-15 22:13:04 -0800674 bool pause_pts_reached = false;
hanghang.luo02efd312022-08-26 09:49:53 +0800675 uint32_t interval = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800676
Song Zhao95bd0922021-09-21 14:07:46 -0700677 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
678 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
679 return video_mono_pop_frame(avsync);
680
Song Zhaoc03ba122020-12-23 21:54:02 -0800681 pthread_mutex_lock(&avsync->lock);
682 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhao2f6744b2021-11-03 21:23:50 -0700683 log_debug("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800684 goto exit;
685 }
686
Song Zhaoea5a0412021-01-18 16:40:08 -0800687 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700688 uint32_t pts;
689
Song Zhaoc03ba122020-12-23 21:54:02 -0800690 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800691 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800692 goto exit;
693 }
Song Zhao35a82df2021-04-15 10:58:49 -0700694 msync_session_get_wall(avsync->fd, &systime, &interval);
695 pts = frame->pts - avsync->delay * interval;
696 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800697 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700698 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800699 }
700
Song Zhaoea5a0412021-01-18 16:40:08 -0800701 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700702 !avsync->first_frame_toggled &&
703 !msync_clock_started(avsync->fd)) {
704 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800705 log_trace("[%d]clock not started", avsync->session_id);
706 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800707 }
708
Song Zhaoea5a0412021-01-18 16:40:08 -0800709 enter_last_frame = avsync->last_frame;
710 msync_session_get_wall(avsync->fd, &systime, &interval);
711
712 /* handle refresh rate change */
713 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
714 avsync->vsync_interval != interval) {
715 log_info("[%d]vsync interval update %d --> %u",
716 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700717 if (avsync->fps_interval == -1)
718 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800719 avsync->vsync_interval = interval;
720 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800721 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700722 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800723 reset_pattern(avsync->pattern_detector);
724 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800725 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
726 struct vframe *next_frame = NULL;
727
728 peek_item(avsync->frame_q, (void **)&next_frame, 1);
729 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700730 log_debug("[%d]cur_f %u next_f %u size %d",
731 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800732 if (frame_expire(avsync, systime, interval,
733 frame, next_frame, toggle_cnt)) {
734 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800735 toggle_cnt++;
736
Song Zhao35a82df2021-04-15 10:58:49 -0700737 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800738 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700739 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700740 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700741 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
742 if (next_frame)
743 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
744 }
Song Zhao35a82df2021-04-15 10:58:49 -0700745
Song Zhaoc03ba122020-12-23 21:54:02 -0800746 if (avsync->last_frame)
747 avsync->last_holding_peroid = avsync->last_frame->hold_period;
748
749 dqueue_item(avsync->frame_q, (void **)&frame);
750 if (avsync->last_frame) {
751 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800752 if (toggle_cnt > 1) {
Song Zhao35a82df2021-04-15 10:58:49 -0700753 log_debug("[%d]free %u cur %u system/d %u/%u", avsync->session_id,
754 avsync->last_frame->pts, frame->pts, systime, systime - avsync->last_poptime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800755 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800756 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800757 } else {
758 avsync->first_frame_toggled = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800759 log_info("[%d]first frame %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800760 }
761 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800762 avsync->last_pts = frame->pts;
yongchun.li428390d2022-02-17 17:15:40 -0800763 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
Song Zhaoc03ba122020-12-23 21:54:02 -0800764 } else
765 break;
766 }
767
768 /* pause pts */
769 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800770 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800771 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800772 else
Song Zhao468fd652021-01-15 22:13:04 -0800773 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
774 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
775 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
776 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
777 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800778
Song Zhao468fd652021-01-15 22:13:04 -0800779 if (pause_pts_reached) {
780 if (avsync->pause_pts_cb)
781 avsync->pause_pts_cb(avsync->pause_pts,
Song Zhaoc03ba122020-12-23 21:54:02 -0800782 avsync->pause_cb_priv);
783
Song Zhao468fd652021-01-15 22:13:04 -0800784 /* stay in paused until av_sync_pause(false) */
785 avsync->paused = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800786 log_info ("[%d]reach pause pts: %u",
Song Zhaob5458b32021-11-12 15:58:47 -0800787 avsync->session_id, avsync->pause_pts);
Song Zhaoad7c8232021-12-14 11:46:48 -0800788 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoc03ba122020-12-23 21:54:02 -0800789 }
790
791exit:
792 pthread_mutex_unlock(&avsync->lock);
yongchun.li428390d2022-02-17 17:15:40 -0800793
794 /* underflow check */
795 if (avsync->session_started && avsync->first_frame_toggled &&
796 (avsync->paused == false) && (avsync->state >= AV_SYNC_STAT_RUNNING) &&
797 avsync->underflow_cb && peek_item(avsync->frame_q, (void **)&frame, 0))
798 {/* empty queue in normal play */
799 struct timespec now;
800 int diff_ms;
801 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
802 diff_ms = time_diff(&now, &avsync->frame_last_update_time)/1000;
803 if(diff_ms >= (avsync->underflow_cfg.time_thresh
804 + avsync->vsync_interval*avsync->last_holding_peroid/90)) {
805 log_info ("[%d]underflow detected: %u", avsync->session_id, avsync->last_pts);
806 avsync->underflow_cb (avsync->last_pts,
807 avsync->underflow_cb_priv);
808 /* update time to control the underflow check call backs */
809 avsync->frame_last_update_time = now;
810 }
811 }
812
Song Zhaoc03ba122020-12-23 21:54:02 -0800813 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800814 if (enter_last_frame != avsync->last_frame)
815 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
bo.xiao1f94b352021-08-02 03:53:47 -0400816 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 -0700817 /* don't update vpts for out_lier */
818 if (avsync->last_frame->duration != -1)
819 msync_session_update_vpts(avsync->fd, systime,
820 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800821 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800822 if (enter_last_frame != avsync->last_frame)
823 log_debug("[%d]pop (nil)", avsync->session_id);
824
Song Zhao35a82df2021-04-15 10:58:49 -0700825 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800826 if (avsync->last_frame)
827 avsync->last_frame->hold_period++;
828 return avsync->last_frame;
829}
830
Song Zhaoc03ba122020-12-23 21:54:02 -0800831static inline uint32_t abs_diff(uint32_t a, uint32_t b)
832{
Song Zhaoea5a0412021-01-18 16:40:08 -0800833 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800834}
835
yongchun.li0ee6e372021-08-20 04:26:04 -0700836static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800837{
hanghang.luo02efd312022-08-26 09:49:53 +0800838 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 -0800839}
840
Song Zhaoc03ba122020-12-23 21:54:02 -0800841static bool frame_expire(struct av_sync_session* avsync,
842 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800843 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800844 struct vframe * frame,
845 struct vframe * next_frame,
846 int toggle_cnt)
847{
Song Zhao6dce2672022-01-13 11:32:44 -0800848 uint32_t fpts = frame->pts + avsync->extra_delay;
849 uint32_t nfpts = -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800850 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800851 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800852
853 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
854 return false;
855
856 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
857 return true;
858
Song Zhaoad7c8232021-12-14 11:46:48 -0800859 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS &&
860 avsync->pause_pts == frame->pts)
861 return true;
862
Song Zhao08fa16b2021-12-08 14:30:17 -0800863 if (systime == AV_SYNC_INVALID_PTS &&
864 avsync->mode == AV_SYNC_MODE_AMASTER)
865 return false;
866
Song Zhao6dce2672022-01-13 11:32:44 -0800867 if (next_frame)
868 nfpts = next_frame->pts + avsync->extra_delay;
869
Song Zhao7e24b182022-04-01 08:46:40 -0700870 if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
fei.deng63e43e12021-09-23 19:44:01 +0800871 /* We need to ensure that the video outputs smoothly,
872 so output video frame by frame hold_period */
873 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
874 avsync->last_frame &&
875 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
876 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
877 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700878 return true;
879 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700880 }
881
Song Zhaoc03ba122020-12-23 21:54:02 -0800882 if (!fpts) {
883 if (avsync->last_frame) {
884 /* try to accumulate duration as PTS */
885 fpts = avsync->vpts + avsync->last_frame->duration;
886 } else {
887 fpts = avsync->vpts;
888 }
889 }
890 systime += pts_correction;
891
892 /* phase adjustment */
893 if (avsync->phase_set)
894 systime += avsync->phase;
895
yongchun.lia50b1e92021-08-07 01:11:54 +0000896 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800897 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000898 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700899 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800900 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800901 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800902 return false;
903
Song Zhaoa2985cb2021-06-24 12:01:47 -0700904 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
905 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700906 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800907
yongchun.li0ee6e372021-08-20 04:26:04 -0700908 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700909 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800910 avsync->last_pts = fpts;
911 if (time_diff(&now, &avsync->sync_lost_print_time) >=
912 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700913 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800914 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800915 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700916 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800917 } else
918 avsync->sync_lost_cnt++;
919 }
Song Zhaod62bb392021-04-23 12:25:49 -0700920
921 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
922 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700923 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700924 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700925 /* outlier by stream error */
926 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700927 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700928 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
929 log_info("render outlier %u", fpts);
930 return true;
931 }
932 }
933
934 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800935 avsync->state = AV_SYNC_STAT_SYNC_LOST;
936 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800937 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700938 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800939 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700940
Song Zhao7e24b182022-04-01 08:46:40 -0700941 if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700942 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700943 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700944 msync_session_set_video_dis(avsync->fd, fpts);
945 avsync->last_disc_pts = fpts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700946 }
947
948 if ((int)(systime - fpts) > 0) {
949 if ((int)(systime - fpts) < avsync->disc_thres_max) {
950 /* catch up PCR */
Song Zhaof46932e2021-05-21 01:51:45 -0700951 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700952 } else {
953 /* render according to FPS */
954 if (!VALID_TS(avsync->last_r_syst) ||
955 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
956 avsync->last_r_syst = systime;
957 return true;
958 }
959 return false;
960 }
961 } else if (LIVE_MODE(avsync->mode)) {
962 /* hold if the gap is small */
963 if ((int)(fpts - systime) < avsync->disc_thres_max) {
964 return false;
965 } 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 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800974 }
975 }
976
Song Zhao52f55192021-05-06 10:52:21 -0700977 /* In some cases, keeping pattern will enlarge the gap */
978 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
979 avsync->first_frame_toggled) {
980 reset_pattern(avsync->pattern_detector);
Song Zhaof46932e2021-05-21 01:51:45 -0700981 log_warn("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700982 systime, fpts);
983 }
984
Song Zhaoc03ba122020-12-23 21:54:02 -0800985 expire = (int)(systime - fpts) >= 0;
986
987 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -0800988 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800989 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -0800990 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800991 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800992 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -0800993 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800994 }
Song Zhao6dce2672022-01-13 11:32:44 -0800995 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -0800996 && avsync->first_frame_toggled) {
997 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -0800998 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800999 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -08001000 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001001 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001002 }
1003 }
1004
Song Zhaoa58c3e92021-03-09 18:52:55 -08001005 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -08001006 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -08001007 (avsync->last_frame?avsync->last_frame->hold_period:0),
1008 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -08001009 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -08001010
1011 if (expire) {
1012 avsync->vpts = fpts;
1013 /* phase adjustment */
1014 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +00001015 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -08001016 if ((int)(systime - fpts) >= 0 &&
1017 (int)(fpts + interval - systime) > 0) {
1018 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -08001019 avsync->phase_set = true;
yongchun.lia50b1e92021-08-07 01:11:54 +00001020 log_info("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -08001021 }
Song Zhao1561e542022-01-12 10:37:55 -08001022 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -08001023 if ((int)(systime - fpts) >= 0 &&
1024 (int)(fpts + interval - systime) > 0) {
1025 int vsync_pts_delta = (int)(systime - fpts);
1026
1027 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1028 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001029 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001030 log_info("[%d] too aligned adjust phase to %d",
1031 avsync->session_id, (int)avsync->phase);
1032 }
1033 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001034 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001035 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -08001036 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -08001037 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001038 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001039 }
1040 return expire;
1041}
1042
Song Zhao35a82df2021-04-15 10:58:49 -07001043static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001044{
Song Zhao35a82df2021-04-15 10:58:49 -07001045 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001046 log_trace("[%d]cur_period: %d last_period: %d",
1047 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -07001048 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
1049 ret = true;
1050 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
1051 ret = true;
1052 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
1053 ret = true;
1054 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
1055 ret = true;
1056
1057 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -08001058}
1059
1060int av_sync_set_speed(void *sync, float speed)
1061{
1062 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1063
1064 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001065 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001066 return -1;
1067 }
1068
Song Zhao76005282022-03-08 16:49:41 -08001069 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001070 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001071 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001072 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001073
Song Zhaoea5a0412021-01-18 16:40:08 -08001074 avsync->speed = speed;
1075
1076 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
1077 if (speed == 1.0) {
1078 avsync->mode = avsync->backup_mode;
1079 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1080 } else {
1081 avsync->backup_mode = avsync->mode;
1082 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1083 log_info("[%d]audio to freerun mode", avsync->session_id);
1084 }
1085 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001086
Song Zhaoea5a0412021-01-18 16:40:08 -08001087 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1088 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001089}
1090
1091int av_sync_change_mode(void *sync, enum sync_mode mode)
1092{
1093 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1094
1095 if (!avsync)
1096 return -1;
1097
Song Zhaoea5a0412021-01-18 16:40:08 -08001098 if (msync_session_set_mode(avsync->fd, mode)) {
1099 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001100 return -1;
1101 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001102 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001103 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001104 return 0;
1105}
1106
Song Zhao01031bb2021-05-13 21:23:20 -07001107int av_sync_get_mode(void *sync, enum sync_mode *mode)
1108{
1109 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1110
1111 if (!avsync || !mode)
1112 return -1;
1113
1114 *mode = avsync->mode;
1115 return 0;
1116}
1117
Song Zhaoc03ba122020-12-23 21:54:02 -08001118int av_sync_set_pause_pts(void *sync, pts90K pts)
1119{
1120 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1121
1122 if (!avsync)
1123 return -1;
1124
1125 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001126 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001127 return 0;
1128}
1129
1130int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1131{
1132 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1133
1134 if (!avsync)
1135 return -1;
1136
1137 avsync->pause_pts_cb = cb;
1138 avsync->pause_cb_priv = priv;
1139 return 0;
1140}
Song Zhaoea5a0412021-01-18 16:40:08 -08001141
yongchun.li428390d2022-02-17 17:15:40 -08001142int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1143{
1144 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1145
1146 if (!avsync)
1147 return -1;
1148
1149 avsync->underflow_cb = cb;
1150 avsync->underflow_cb_priv = priv;
1151
1152 if (cfg)
1153 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1154 else
1155 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1156
1157 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1158 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1159 avsync->underflow_cfg.time_thresh);
1160 return 0;
1161}
Song Zhaoea5a0412021-01-18 16:40:08 -08001162static void trigger_audio_start_cb(struct av_sync_session *avsync,
1163 avs_ascb_reason reason)
1164{
1165 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001166 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001167 pthread_mutex_lock(&avsync->lock);
1168 if (avsync->audio_start) {
1169 avsync->audio_start(avsync->audio_start_priv, reason);
1170 avsync->session_started = true;
1171 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001172 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001173 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1174 }
1175 pthread_mutex_unlock(&avsync->lock);
1176 }
1177}
1178
1179avs_start_ret av_sync_audio_start(
1180 void *sync,
1181 pts90K pts,
1182 pts90K delay,
1183 audio_start_cb cb,
1184 void *priv)
1185{
1186 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1187 uint32_t start_mode;
yongchun.li59e873d2021-07-07 11:42:38 -07001188 uint32_t systime;
Song Zhaoea5a0412021-01-18 16:40:08 -08001189 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1190 bool create_poll_t = false;
1191
1192 if (!avsync)
1193 return ret;
1194
yongchun.li59e873d2021-07-07 11:42:38 -07001195 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1196 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001197
yongchun.li59e873d2021-07-07 11:42:38 -07001198 if (avsync->in_audio_switch &&
1199 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1200 {
1201 start_mode = AVS_START_SYNC;
1202 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1203 } else {
1204 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1205 log_error("[%d]fail to set audio start", avsync->session_id);
1206 }
1207 if (avsync->in_audio_switch &&
1208 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1209 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
1210 msync_session_get_wall(avsync->fd, &systime, NULL);
1211 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB &&
1212 start_mode == AVS_START_SYNC) {
1213 log_info("%d audio_switch audio need drop first.ahead %d ms",
1214 avsync->session_id, (int)(systime - pts)/90);
1215 ret = AV_SYNC_ASTART_AGAIN;
1216 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1217 goto exit;
1218 }
1219 else {
1220 int diff = (int)(pts - systime);
1221 log_info("%d audio_switch_state to start mode %d diff %d ms",
1222 avsync->session_id, start_mode, diff/90);
1223 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
1224 if (diff < A_ADJ_THREDHOLD_LB) {
1225 log_info("%d orig mode %d already close enough direct start",
1226 avsync->session_id, start_mode);
1227 start_mode = AVS_START_SYNC;
1228 }
1229 }
yongchun.li107a6162021-05-05 02:38:57 -07001230 }
1231
Song Zhaoea5a0412021-01-18 16:40:08 -08001232 if (start_mode == AVS_START_SYNC) {
1233 ret = AV_SYNC_ASTART_SYNC;
1234 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001235 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001236 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001237 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001238 avsync->state = AV_SYNC_STAT_RUNNING;
1239 } else if (start_mode == AVS_START_AGAIN) {
1240 ret = AV_SYNC_ASTART_AGAIN;
1241 }
1242
1243 if (ret == AV_SYNC_ASTART_AGAIN)
1244 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001245
Song Zhao76005282022-03-08 16:49:41 -08001246 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1247 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001248 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001249
1250 if (start_mode == AVS_START_ASYNC) {
1251 if (!cb) {
1252 log_error("[%d]invalid cb", avsync->session_id);
1253 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001254 }
Song Zhao76005282022-03-08 16:49:41 -08001255 avsync->audio_start = cb;
1256 avsync->audio_start_priv = priv;
1257 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001258
Song Zhaod62bb392021-04-23 12:25:49 -07001259 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001260 int ret;
1261
1262 log_info("[%d]start poll thread", avsync->session_id);
1263 avsync->quit_poll = false;
1264 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1265 if (ret) {
1266 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1267 return AV_SYNC_ASTART_ERR;
1268 }
1269 }
Song Zhaod62bb392021-04-23 12:25:49 -07001270 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001271 msync_session_get_wall(avsync->fd, &systime, NULL);
1272 log_info("[%d]return %u w %u pts %u d %u",
1273 avsync->session_id, ret, systime, pts, delay);
1274 }
1275exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001276 log_info("[%d]return %u", avsync->session_id, ret);
1277 return ret;
1278}
1279
1280int av_sync_audio_render(
1281 void *sync,
1282 pts90K pts,
1283 struct audio_policy *policy)
1284{
1285 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001286 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001287 uint32_t systime;
1288 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1289 avs_audio_action action = AA_SYNC_AA_MAX;
1290
1291 if (!avsync || !policy)
1292 return -1;
1293
yongchun.li107a6162021-05-05 02:38:57 -07001294 msync_session_get_wall(avsync->fd, &systime, NULL);
1295
1296 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1297 pts, systime, avsync->mode, (int)(pts-systime)/90);
1298
1299 if (avsync->in_audio_switch
1300 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
1301 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
1302 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1303 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1304 action = AV_SYNC_AA_RENDER;
1305 } else if ((int)(systime - pts) > 0) {
1306 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1307 (int)(systime - pts)/90, systime, pts);
1308 action = AV_SYNC_AA_DROP;
1309 } else {
1310 action = AV_SYNC_AA_INSERT;
1311 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1312 (int)(pts - systime)/90, systime, pts);
1313 }
1314 goto done;
1315 }
1316
Song Zhaoea5a0412021-01-18 16:40:08 -08001317 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1318 avsync->mode == AV_SYNC_MODE_AMASTER) {
1319 action = AV_SYNC_AA_RENDER;
1320 goto done;
1321 }
1322
Song Zhaod62bb392021-04-23 12:25:49 -07001323 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001324 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001325 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1326 action = AV_SYNC_AA_DROP;
1327 goto done;
1328 }
1329
Song Zhao7daf3a12021-05-10 22:22:25 -07001330 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1331 avsync->mode == AV_SYNC_MODE_AMASTER) {
1332 action = AV_SYNC_AA_RENDER;
1333 goto done;
1334 }
1335
Song Zhaod62bb392021-04-23 12:25:49 -07001336 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1337 LIVE_MODE(avsync->mode) &&
1338 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1339 /* outlier by stream error */
1340 avsync->outlier_cnt++;
1341 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1342 /* treat as disc, just drop current frame */
1343 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1344 avsync->outlier_cnt = 0;
1345 action = AV_SYNC_AA_DROP;
1346 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001347 goto done;
1348 }
1349 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1350 pts = systime;
1351 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001352 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001353 goto done;
1354 }
1355
1356 avsync->outlier_cnt = 0;
1357 /* low bound from sync_lost to sync_setup */
1358 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1359 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1360 action = AV_SYNC_AA_RENDER;
1361 goto done;
1362 }
1363
1364 /* high bound of sync_setup */
1365 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1366 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1367 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001368 action = AV_SYNC_AA_RENDER;
1369 goto done;
1370 }
1371
1372 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001373 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001374 action = AV_SYNC_AA_DROP;
1375 goto done;
1376 }
1377
1378 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001379 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001380 action = AV_SYNC_AA_INSERT;
1381 goto done;
1382 }
1383
1384done:
1385 policy->action = action;
1386 policy->delta = (int)(systime - pts);
1387 if (action == AV_SYNC_AA_RENDER) {
1388 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001389 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001390 if (!out_lier)
1391 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001392 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001393 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001394 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1395 msync_session_update_apts(avsync->fd, systime, pts, 0);
1396 log_info("[%d] audio switch done sys %u pts %u",
1397 avsync->session_id, systime, pts);
1398 msync_session_set_audio_switch(avsync->fd, false);
1399 avsync->in_audio_switch = false;
1400 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1401 } else {
1402 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1403 avsync->session_id, action, systime, pts, systime - pts);
1404 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001405 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001406 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001407 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001408 avsync->last_disc_pts != pts &&
1409 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001410 log_info ("[%d]audio disc %u --> %u",
1411 avsync->session_id, systime, pts);
1412 msync_session_set_audio_dis(avsync->fd, pts);
1413 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001414 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001415 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001416
1417 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001418 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001419 if (!avsync->audio_drop_cnt)
1420 avsync->audio_drop_start = now;
1421 avsync->audio_drop_cnt++;
1422 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1423 log_info ("[%d]audio keep dropping sys %u vs a %u",
1424 avsync->session_id, systime, pts);
1425 msync_session_set_audio_dis(avsync->fd, pts);
1426 }
Song Zhao409739b2021-05-12 22:21:40 -07001427 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001428 if (action != AV_SYNC_AA_DROP)
1429 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001430 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001431 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001432 }
1433
1434 return ret;
1435}
1436
1437int av_sync_get_clock(void *sync, pts90K *pts)
1438{
1439 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1440
1441 if (!avsync || !pts)
1442 return -1;
1443 return msync_session_get_wall(avsync->fd, pts, NULL);
1444}
1445
1446static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001447 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001448 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001449{
Song Zhao76005282022-03-08 16:49:41 -08001450 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1451 avsync->session_id, avsync->active_mode, avsync->mode,
1452 v_active, a_active, v_timeout, stat);
1453
1454 /* iptv delayed start */
1455 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1456 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1457
Song Zhaoea5a0412021-01-18 16:40:08 -08001458 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1459 float speed;
Song Zhao7e8c68f2022-07-12 16:24:30 -07001460 if (a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001461 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001462 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhao6183ca92022-07-29 09:57:03 -07001463 } else if (!a_active && !avsync->session_started) {
1464 /* quit waiting ASAP */
1465 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoea5a0412021-01-18 16:40:08 -08001466 }
1467
1468 if (!msync_session_get_rate(avsync->fd, &speed)) {
1469 /* speed change is triggered by asink,
1470 * attached audio HAL will handle it
1471 */
1472 if (speed != avsync->speed)
1473 log_info("[%d]new rate %f", avsync->session_id, speed);
1474 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001475 if (avsync->mode != avsync->backup_mode) {
1476 avsync->mode = avsync->backup_mode;
1477 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1478 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001479 } else {
1480 avsync->backup_mode = avsync->mode;
1481 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1482 log_info("[%d]audio to freerun mode", avsync->session_id);
1483 }
1484 avsync->speed = speed;
1485 }
Song Zhaod62bb392021-04-23 12:25:49 -07001486 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1487 struct session_debug debug;
1488 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001489 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001490 avsync->backup_mode = avsync->mode;
1491 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001492 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001493 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001494 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001495 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001496 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001497 log_warn("[%d]audio back to mode %d",
1498 avsync->session_id, avsync->mode);
1499 }
1500 }
Song Zhao76005282022-03-08 16:49:41 -08001501 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1502 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001503 }
1504}
1505
1506static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001507 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001508 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001509{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001510 struct session_debug debug;
1511
Song Zhao76005282022-03-08 16:49:41 -08001512 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1513 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001514 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1515 if (debug.debug_freerun && !avsync->debug_freerun) {
1516 avsync->backup_mode = avsync->mode;
1517 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1518 avsync->debug_freerun = true;
1519 log_warn("[%d]video to freerun mode", avsync->session_id);
1520 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1521 avsync->mode = avsync->backup_mode;
1522 avsync->debug_freerun = false;
1523 log_warn("[%d]video back to mode %d",
1524 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001525 }
1526 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001527}
1528
1529static void * poll_thread(void * arg)
1530{
1531 int ret = 0;
1532 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1533 const int fd = avsync->fd;
1534 struct pollfd pfd = {
1535 /* default blocking capture */
1536 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1537 .fd = avsync->fd,
1538 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001539 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001540
1541 prctl (PR_SET_NAME, "avs_poll");
1542 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001543
1544 if (avsync->type == AV_SYNC_TYPE_AUDIO)
1545 sflag = SRC_A;
1546 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
1547 sflag = SRC_V;
1548
Song Zhaoea5a0412021-01-18 16:40:08 -08001549 while (!avsync->quit_poll) {
1550 for (;;) {
1551 ret = poll(&pfd, 1, 10);
1552 if (ret > 0)
1553 break;
1554 if (avsync->quit_poll)
1555 goto exit;
1556 if (errno == EINTR)
1557 continue;
1558 }
1559
1560 /* error handling */
1561 if (pfd.revents & POLLERR)
1562 log_error("[%d]POLLERR received", avsync->session_id);
1563
Song Zhaod62bb392021-04-23 12:25:49 -07001564 /* mode change. Non-exclusive wait so all the processes
1565 * shall be woken up
1566 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001567 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001568 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001569 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001570
Song Zhao9fef59c2022-08-17 12:43:10 -07001571 msync_session_get_stat(fd, true, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001572 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001573
1574 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001575 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001576 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001577 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001578 usleep(10000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001579 }
1580 }
1581exit:
1582 log_info("[%d]quit", avsync->session_id);
1583 return NULL;
1584}
1585
Song Zhao623e2f12021-09-03 15:54:04 -07001586#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1587/* return ppm between demod and PCR clock */
1588int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1589{
1590 int fd = -1, ppm = 0, nread;
1591 char buf[128];
1592 uint32_t reg_v, lock;
1593 float val;
1594
1595 fd = open(DEMOD_NODE, O_RDWR);
1596 if (fd < 0) {
1597 log_warn("node not found %s", DEMOD_NODE);
1598 /* do not retry */
1599 avsync->ppm_adjusted = true;
1600 return 0;
1601 }
1602 snprintf(buf, sizeof(buf), "%d", 5);
1603 write(fd, buf, 2);
1604
1605 lseek(fd, 0, SEEK_SET);
1606
hanghang.luo02efd312022-08-26 09:49:53 +08001607 nread = read(fd, buf, sizeof(buf)-1);
Song Zhao623e2f12021-09-03 15:54:04 -07001608 if (nread <= 0) {
1609 log_error("read error");
1610 goto err;
1611 }
1612 buf[nread] = 0;
1613 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1614 log_error("wrong format %s", buf);
1615 goto err;
1616 }
1617 if (lock != 0x1f) {
1618 log_info("demod not locked");
1619 goto err;
1620 }
1621 if (reg_v > ((2 << 20) - 1))
1622 reg_v -= (2 << 21);
1623 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1624 ppm = val;
1625 log_info("ppm from SFO %d", ppm);
1626 avsync->ppm_adjusted = true;
1627
1628err:
1629 if (fd >= 0)
1630 close(fd);
1631 return ppm;
1632}
1633
Song Zhaod62bb392021-04-23 12:25:49 -07001634int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001635{
1636 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001637 struct pcr_info pcr;
1638 enum pcr_monitor_status status;
1639 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001640 if (!avsync)
1641 return -1;
1642
1643 if (avsync->type != AV_SYNC_TYPE_PCR)
1644 return -2;
1645
Song Zhao623e2f12021-09-03 15:54:04 -07001646 /* initial estimation from Demod SFO HW */
1647 if (!avsync->ppm_adjusted) {
1648 ppm = dmod_get_sfo_dev(avsync);
1649 if (ppm != 0) {
1650 /* ppm > 0 means board clock is faster */
1651 msync_session_set_clock_dev(avsync->fd, -ppm);
1652 }
1653 }
wei.dubcc2ed22021-05-19 07:16:10 -04001654 pcr.monoclk = mono_clock / 1000;
1655 pcr.pts = (long long) pts * 1000 / 90;
1656 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1657
1658 status = pcr_monitor_get_status(avsync->pcr_monitor);
1659
1660 if (status >= DEVIATION_READY) {
1661 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1662 if (avsync->ppm != ppm) {
1663 avsync->ppm = ppm;
1664 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1665 if (msync_session_set_clock_dev(avsync->fd, ppm))
1666 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001667 else
1668 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001669 }
1670 }
1671
Song Zhaod62bb392021-04-23 12:25:49 -07001672 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001673}
1674
Song Zhaod62bb392021-04-23 12:25:49 -07001675int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001676{
1677 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1678
1679 if (!avsync)
1680 return -1;
1681
Song Zhaod62bb392021-04-23 12:25:49 -07001682 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001683}
1684
1685int av_sync_set_session_name(void *sync, const char *name)
1686{
1687 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1688
1689 if (!avsync)
1690 return -1;
1691
1692 return msync_session_set_name(avsync->fd, name);
1693}
yongchun.li107a6162021-05-05 02:38:57 -07001694
1695int av_sync_set_audio_switch(void *sync, bool start)
1696{
1697 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1698 bool v_active, a_active, v_timeout;
1699
1700 if (!avsync)
1701 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001702 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001703 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001704 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001705 log_error("[%d] can not get session state",
1706 avsync->session_id);
1707 return -1;
1708 }
1709 if (!v_active || !a_active) {
1710 log_error("[%d] no apply if not AV both active v %d a %d",
1711 avsync->session_id, v_active, a_active);
1712 return -1;
1713 }
1714 if (msync_session_set_audio_switch(avsync->fd, start)) {
1715 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1716 return -1;
1717 }
1718 avsync->in_audio_switch = start;
1719 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1720 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1721 return 0;
1722}
1723
1724int av_sync_get_audio_switch(void *sync, bool *start)
1725{
1726 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1727
1728 if (!avsync)
1729 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001730 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001731 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001732 log_error("[%d] can not audio seamless switch state",
1733 avsync->session_id);
1734 return -1;
1735 }
1736 if (start) *start = avsync->in_audio_switch;
1737 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001738}
Song Zhao8039f562021-05-18 18:11:25 -07001739
Song Zhao623e2f12021-09-03 15:54:04 -07001740enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001741{
1742 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1743
wei.dubcc2ed22021-05-19 07:16:10 -04001744 if (!avsync || !ppm)
1745 return CLK_RECOVERY_ERR;
1746 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001747 return CLK_RECOVERY_NOT_RUNNING;
1748
wei.dubcc2ed22021-05-19 07:16:10 -04001749 if (msync_session_get_clock_dev(avsync->fd, ppm))
1750 return CLK_RECOVERY_ERR;
1751
1752 if (*ppm == 0)
1753 return CLK_RECOVERY_ONGOING;
1754 else
1755 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001756}
Song Zhao95bd0922021-09-21 14:07:46 -07001757
1758static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1759{
1760 int ret;
1761
1762 if (!avsync->frame_q) {
1763 avsync->frame_q = create_q(MAX_FRAME_NUM);
1764 if (!avsync->frame_q) {
1765 log_error("[%d]create queue fail", avsync->session_id);
1766
1767 return -1;
1768 }
1769 }
1770
1771 ret = queue_item(avsync->frame_q, frame);
1772 if (ret)
hanghang.luo02efd312022-08-26 09:49:53 +08001773 log_error("queue fail:%d", ret);
Song Zhao95bd0922021-09-21 14:07:46 -07001774 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1775 return ret;
1776}
1777
1778int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1779{
1780 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1781
1782 if (!avsync)
1783 return -1;
1784 avsync->msys = msys;
1785 return 0;
1786}
1787
1788static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1789{
1790 struct vframe *frame = NULL, *enter_last_frame = NULL;
1791 uint64_t systime;
1792 int toggle_cnt = 0;
1793
1794 enter_last_frame = avsync->last_frame;
1795 systime = avsync->msys;
1796 log_debug("[%d]sys %llu", avsync->session_id, systime);
1797 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1798 if (systime >= frame->mts) {
1799 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1800 toggle_cnt++;
1801
1802 if (avsync->last_frame)
1803 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1804
1805 dqueue_item(avsync->frame_q, (void **)&frame);
1806 if (avsync->last_frame) {
1807 /* free frame that are not for display */
1808 if (toggle_cnt > 1) {
1809 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1810 avsync->last_frame->mts, frame->mts, systime);
1811 avsync->last_frame->free(avsync->last_frame);
1812 }
1813 } else {
1814 avsync->first_frame_toggled = true;
1815 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1816 }
1817 avsync->last_frame = frame;
1818 } else
1819 break;
1820 }
1821
1822 if (avsync->last_frame) {
1823 if (enter_last_frame != avsync->last_frame)
hanghang.luo02efd312022-08-26 09:49:53 +08001824 log_debug("[%d]pop %lu", avsync->session_id, avsync->last_frame->pts);
1825 log_trace("[%d]pop=%llu, system=%llu, diff %llu(ms), QNum=%d", avsync->session_id,
Song Zhao95bd0922021-09-21 14:07:46 -07001826 avsync->last_frame->mts,
1827 systime, (systime - avsync->last_frame->mts) / 1000000,
1828 queue_size(avsync->frame_q));
1829 } else
1830 if (enter_last_frame != avsync->last_frame)
1831 log_debug("[%d]pop (nil)", avsync->session_id);
1832
1833 if (avsync->last_frame)
1834 avsync->last_frame->hold_period++;
1835 return avsync->last_frame;
1836}
Song Zhao6183ca92022-07-29 09:57:03 -07001837
1838int avs_sync_stop_audio(void *sync)
1839{
1840 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1841
1842 if (!avsync)
1843 return -1;
1844
1845 return msync_session_stop_audio(avsync->fd);
1846}