blob: 798e4a42a201ca02388b8b5cc17d01f33f987101 [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)) {
306 log_error("fail to get disc thres", dev_name, errno);
307 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 Zhao76005282022-03-08 16:49:41 -0800353 if (msync_session_get_stat(avsync->fd, &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
bo.xiao5821fc72021-07-11 22:47:00 -0400488 log_info("[%d]policy %u --> %u, timeout %d --> %d", avsync->start_policy, st_policy->policy, avsync->timeout, st_policy->timeout);
Song Zhao76005282022-03-08 16:49:41 -0800489 if (LIVE_MODE(avsync->mode) &&
490 st_policy->policy != AV_SYNC_START_ASAP) {
491 log_error("policy %d not supported in live mode", st_policy->policy);
492 return -1;
493 }
494
bo.xiao5821fc72021-07-11 22:47:00 -0400495 avsync->start_policy = st_policy->policy;
496 avsync->timeout = st_policy->timeout;
Song Zhao76005282022-03-08 16:49:41 -0800497
Song Zhaoea5a0412021-01-18 16:40:08 -0800498 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400499 if (st_policy->policy != AV_SYNC_START_NONE &&
500 st_policy->policy != AV_SYNC_START_V_PEEK)
501 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800502
503 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800504}
505
506int av_sync_pause(void *sync, bool pause)
507{
508 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700509 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800510 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800511
Song Zhaob5458b32021-11-12 15:58:47 -0800512 if (!avsync) {
513 log_error("invalid handle");
Song Zhaoc03ba122020-12-23 21:54:02 -0800514 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800515 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800516
fei.deng55389b62022-08-18 23:46:50 +0800517 if (avsync->type == AV_SYNC_TYPE_VIDEO && avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
518 log_warn("ignore pause in video mono mode");
519 return -1;
520 }
521
Song Zhaob5458b32021-11-12 15:58:47 -0800522 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
523 log_warn("ignore pause in pcr master mode");
Song Zhaoea5a0412021-01-18 16:40:08 -0800524 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800525 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800526
Song Zhao76005282022-03-08 16:49:41 -0800527 rc = msync_session_get_stat(avsync->fd, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -0700528 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700529 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700530
yongchun.li5f52fb02021-06-04 18:13:05 -0700531 /* ignore only when video try to pause when audio is acive, on which
532 the control of the STC will be relays.
533 When resume,it can do always as it is possible that video just
534 paused earlier without audio yet,then audio added later before resume.
535 We shall not igore that otherwise it could cause video freeze. */
536 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
537 avsync->type == AV_SYNC_TYPE_VIDEO &&
538 a_active &&
539 !avsync->in_audio_switch) {
540 if (!pause) {
541 log_info("[%d] clear video pause when audio active",
542 avsync->session_id);
543 avsync->paused = pause;
544 } else {
545 log_info("[%d] ignore the pause from video when audio active",
546 avsync->session_id);
547 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800548 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700549 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800550
yongchun.li107a6162021-05-05 02:38:57 -0700551 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
552 log_info("[%d] ignore the pause from audio", avsync->session_id);
553 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
554 return 0;
555 }
556
Song Zhaoea5a0412021-01-18 16:40:08 -0800557 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800558 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800559 log_info("[%d]paused:%d type:%d rc %d",
560 avsync->session_id, pause, avsync->type, rc);
yongchun.li428390d2022-02-17 17:15:40 -0800561 if (!avsync->paused && avsync->first_frame_toggled) {
562 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
563 log_info("[%d] resume update new frame time", avsync->session_id);
564 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800565 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800566}
567
568int av_sync_push_frame(void *sync , struct vframe *frame)
569{
570 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700571 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800572 struct av_sync_session *avsync = (struct av_sync_session *)sync;
573
574 if (!avsync)
575 return -1;
576
Song Zhao95bd0922021-09-21 14:07:46 -0700577 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
fei.deng55389b62022-08-18 23:46:50 +0800578 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
Song Zhao95bd0922021-09-21 14:07:46 -0700579 return video_mono_push_frame(avsync, frame);
fei.deng55389b62022-08-18 23:46:50 +0800580 }
Song Zhao95bd0922021-09-21 14:07:46 -0700581
Song Zhaoea5a0412021-01-18 16:40:08 -0800582 if (!avsync->frame_q) {
583 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400584 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800585 log_error("[%d]get policy", avsync->session_id);
586 return -1;
587 }
588
589 avsync->frame_q = create_q(MAX_FRAME_NUM);
590 if (!avsync->frame_q) {
591 log_error("[%d]create queue fail", avsync->session_id);
yongchun.li0ee6e372021-08-20 04:26:04 -0700592
Song Zhaoea5a0412021-01-18 16:40:08 -0800593 return -1;
594 }
595
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700596 {
Song Zhaoea5a0412021-01-18 16:40:08 -0800597 int ret;
598
599 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
600 if (ret) {
601 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
602 destroy_q(avsync->frame_q);
603 return -1;
604 }
605 }
606 }
607
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700608 if (avsync->last_q_pts != -1) {
Song Zhao7e24b182022-04-01 08:46:40 -0700609 if (frame->pts != -1 && avsync->mode == AV_SYNC_MODE_VMASTER) {
610 /* Sometimes app will fake PTS for trickplay, video PTS gap
611 * is really big depending on the speed. Have to adjust the
612 * threshold dynamically.
613 */
614 int gap = (int)(frame->pts - avsync->last_q_pts);
615 if (gap > avsync->disc_thres_min) {
616 avsync->disc_thres_min = gap * 6;
617 avsync->disc_thres_max = gap * 20;
618 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
619 msync_session_set_disc_thres(avsync->session_id,
620 avsync->disc_thres_min, avsync->disc_thres_max);
621 log_info("[%d] update disc_thres to %d/%d",avsync->session_id,
622 avsync->disc_thres_min, avsync->disc_thres_max);
623 }
624 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700625 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
626 /* TODO: wrong, should remove from back of queue */
Song Zhaoc03ba122020-12-23 21:54:02 -0800627 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700628 if (prev) {
629 prev->free(prev);
630 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
631 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700632 } else if (avsync->fps_cnt < 100) {
633 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700634
635 if (interval > 0 && interval <= 4500) {
636 if (avsync->fps_interval_acc == -1) {
637 avsync->fps_interval_acc = interval;
638 avsync->fps_cnt = 1;
639 } else {
640 avsync->fps_interval_acc += interval;
641 avsync->fps_cnt++;
642 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
643 if (avsync->fps_cnt == 100)
644 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
645 }
646 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800647 }
648 }
649
Song Zhao065800e2021-05-26 15:56:06 -0700650 if (frame->duration == -1)
651 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800652 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700653 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800654 ret = queue_item(avsync->frame_q, frame);
655 if (avsync->state == AV_SYNC_STAT_INIT &&
656 queue_size(avsync->frame_q) >= avsync->start_thres) {
657 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaoea5a0412021-01-18 16:40:08 -0800658 log_info("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800659 }
660
661 if (ret)
Song Zhaoe1b65602022-01-06 08:03:46 -0800662 log_error("queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400663 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800664 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800665}
666
667struct vframe *av_sync_pop_frame(void *sync)
668{
Song Zhaoea5a0412021-01-18 16:40:08 -0800669 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800670 struct av_sync_session *avsync = (struct av_sync_session *)sync;
671 int toggle_cnt = 0;
672 uint32_t systime;
Song Zhao468fd652021-01-15 22:13:04 -0800673 bool pause_pts_reached = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800674 uint32_t interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800675
Song Zhao95bd0922021-09-21 14:07:46 -0700676 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
677 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
678 return video_mono_pop_frame(avsync);
679
Song Zhaoc03ba122020-12-23 21:54:02 -0800680 pthread_mutex_lock(&avsync->lock);
681 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhao2f6744b2021-11-03 21:23:50 -0700682 log_debug("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800683 goto exit;
684 }
685
Song Zhaoea5a0412021-01-18 16:40:08 -0800686 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700687 uint32_t pts;
688
Song Zhaoc03ba122020-12-23 21:54:02 -0800689 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800690 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800691 goto exit;
692 }
Song Zhao35a82df2021-04-15 10:58:49 -0700693 msync_session_get_wall(avsync->fd, &systime, &interval);
694 pts = frame->pts - avsync->delay * interval;
695 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800696 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700697 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800698 }
699
Song Zhaoea5a0412021-01-18 16:40:08 -0800700 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700701 !avsync->first_frame_toggled &&
702 !msync_clock_started(avsync->fd)) {
703 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800704 log_trace("[%d]clock not started", avsync->session_id);
705 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800706 }
707
Song Zhaoea5a0412021-01-18 16:40:08 -0800708 enter_last_frame = avsync->last_frame;
709 msync_session_get_wall(avsync->fd, &systime, &interval);
710
711 /* handle refresh rate change */
712 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
713 avsync->vsync_interval != interval) {
714 log_info("[%d]vsync interval update %d --> %u",
715 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700716 if (avsync->fps_interval == -1)
717 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800718 avsync->vsync_interval = interval;
719 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800720 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700721 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800722 reset_pattern(avsync->pattern_detector);
723 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800724 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
725 struct vframe *next_frame = NULL;
726
727 peek_item(avsync->frame_q, (void **)&next_frame, 1);
728 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700729 log_debug("[%d]cur_f %u next_f %u size %d",
730 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800731 if (frame_expire(avsync, systime, interval,
732 frame, next_frame, toggle_cnt)) {
733 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800734 toggle_cnt++;
735
Song Zhao35a82df2021-04-15 10:58:49 -0700736 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800737 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700738 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700739 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700740 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
741 if (next_frame)
742 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
743 }
Song Zhao35a82df2021-04-15 10:58:49 -0700744
Song Zhaoc03ba122020-12-23 21:54:02 -0800745 if (avsync->last_frame)
746 avsync->last_holding_peroid = avsync->last_frame->hold_period;
747
748 dqueue_item(avsync->frame_q, (void **)&frame);
749 if (avsync->last_frame) {
750 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800751 if (toggle_cnt > 1) {
Song Zhao35a82df2021-04-15 10:58:49 -0700752 log_debug("[%d]free %u cur %u system/d %u/%u", avsync->session_id,
753 avsync->last_frame->pts, frame->pts, systime, systime - avsync->last_poptime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800754 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800755 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800756 } else {
757 avsync->first_frame_toggled = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800758 log_info("[%d]first frame %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800759 }
760 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800761 avsync->last_pts = frame->pts;
yongchun.li428390d2022-02-17 17:15:40 -0800762 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
Song Zhaoc03ba122020-12-23 21:54:02 -0800763 } else
764 break;
765 }
766
767 /* pause pts */
768 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800769 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800770 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800771 else
Song Zhao468fd652021-01-15 22:13:04 -0800772 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
773 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
774 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
775 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
776 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800777
Song Zhao468fd652021-01-15 22:13:04 -0800778 if (pause_pts_reached) {
779 if (avsync->pause_pts_cb)
780 avsync->pause_pts_cb(avsync->pause_pts,
Song Zhaoc03ba122020-12-23 21:54:02 -0800781 avsync->pause_cb_priv);
782
Song Zhao468fd652021-01-15 22:13:04 -0800783 /* stay in paused until av_sync_pause(false) */
784 avsync->paused = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800785 log_info ("[%d]reach pause pts: %u",
Song Zhaob5458b32021-11-12 15:58:47 -0800786 avsync->session_id, avsync->pause_pts);
Song Zhaoad7c8232021-12-14 11:46:48 -0800787 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoc03ba122020-12-23 21:54:02 -0800788 }
789
790exit:
791 pthread_mutex_unlock(&avsync->lock);
yongchun.li428390d2022-02-17 17:15:40 -0800792
793 /* underflow check */
794 if (avsync->session_started && avsync->first_frame_toggled &&
795 (avsync->paused == false) && (avsync->state >= AV_SYNC_STAT_RUNNING) &&
796 avsync->underflow_cb && peek_item(avsync->frame_q, (void **)&frame, 0))
797 {/* empty queue in normal play */
798 struct timespec now;
799 int diff_ms;
800 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
801 diff_ms = time_diff(&now, &avsync->frame_last_update_time)/1000;
802 if(diff_ms >= (avsync->underflow_cfg.time_thresh
803 + avsync->vsync_interval*avsync->last_holding_peroid/90)) {
804 log_info ("[%d]underflow detected: %u", avsync->session_id, avsync->last_pts);
805 avsync->underflow_cb (avsync->last_pts,
806 avsync->underflow_cb_priv);
807 /* update time to control the underflow check call backs */
808 avsync->frame_last_update_time = now;
809 }
810 }
811
Song Zhaoc03ba122020-12-23 21:54:02 -0800812 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800813 if (enter_last_frame != avsync->last_frame)
814 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
bo.xiao1f94b352021-08-02 03:53:47 -0400815 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 -0700816 /* don't update vpts for out_lier */
817 if (avsync->last_frame->duration != -1)
818 msync_session_update_vpts(avsync->fd, systime,
819 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800820 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800821 if (enter_last_frame != avsync->last_frame)
822 log_debug("[%d]pop (nil)", avsync->session_id);
823
Song Zhao35a82df2021-04-15 10:58:49 -0700824 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800825 if (avsync->last_frame)
826 avsync->last_frame->hold_period++;
827 return avsync->last_frame;
828}
829
Song Zhaoc03ba122020-12-23 21:54:02 -0800830static inline uint32_t abs_diff(uint32_t a, uint32_t b)
831{
Song Zhaoea5a0412021-01-18 16:40:08 -0800832 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800833}
834
yongchun.li0ee6e372021-08-20 04:26:04 -0700835static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800836{
yongchun.li0ee6e372021-08-20 04:26:04 -0700837 return (b->tv_sec - a->tv_sec)*1000000 + (b->tv_nsec/1000 - a->tv_nsec/1000);
Song Zhaoc03ba122020-12-23 21:54:02 -0800838}
839
Song Zhaoc03ba122020-12-23 21:54:02 -0800840static bool frame_expire(struct av_sync_session* avsync,
841 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800842 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800843 struct vframe * frame,
844 struct vframe * next_frame,
845 int toggle_cnt)
846{
Song Zhao6dce2672022-01-13 11:32:44 -0800847 uint32_t fpts = frame->pts + avsync->extra_delay;
848 uint32_t nfpts = -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800849 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800850 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800851
852 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
853 return false;
854
855 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
856 return true;
857
Song Zhaoad7c8232021-12-14 11:46:48 -0800858 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS &&
859 avsync->pause_pts == frame->pts)
860 return true;
861
Song Zhao08fa16b2021-12-08 14:30:17 -0800862 if (systime == AV_SYNC_INVALID_PTS &&
863 avsync->mode == AV_SYNC_MODE_AMASTER)
864 return false;
865
Song Zhao6dce2672022-01-13 11:32:44 -0800866 if (next_frame)
867 nfpts = next_frame->pts + avsync->extra_delay;
868
Song Zhao7e24b182022-04-01 08:46:40 -0700869 if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
fei.deng63e43e12021-09-23 19:44:01 +0800870 /* We need to ensure that the video outputs smoothly,
871 so output video frame by frame hold_period */
872 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
873 avsync->last_frame &&
874 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
875 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
876 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700877 return true;
878 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700879 }
880
Song Zhaoc03ba122020-12-23 21:54:02 -0800881 if (!fpts) {
882 if (avsync->last_frame) {
883 /* try to accumulate duration as PTS */
884 fpts = avsync->vpts + avsync->last_frame->duration;
885 } else {
886 fpts = avsync->vpts;
887 }
888 }
889 systime += pts_correction;
890
891 /* phase adjustment */
892 if (avsync->phase_set)
893 systime += avsync->phase;
894
yongchun.lia50b1e92021-08-07 01:11:54 +0000895 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800896 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000897 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700898 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800899 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800900 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800901 return false;
902
Song Zhaoa2985cb2021-06-24 12:01:47 -0700903 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
904 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700905 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800906
yongchun.li0ee6e372021-08-20 04:26:04 -0700907 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700908 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800909 avsync->last_pts = fpts;
910 if (time_diff(&now, &avsync->sync_lost_print_time) >=
911 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700912 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800913 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800914 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700915 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800916 } else
917 avsync->sync_lost_cnt++;
918 }
Song Zhaod62bb392021-04-23 12:25:49 -0700919
920 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
921 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700922 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700923 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700924 /* outlier by stream error */
925 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700926 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700927 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
928 log_info("render outlier %u", fpts);
929 return true;
930 }
931 }
932
933 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800934 avsync->state = AV_SYNC_STAT_SYNC_LOST;
935 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800936 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700937 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800938 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700939
Song Zhao7e24b182022-04-01 08:46:40 -0700940 if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700941 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700942 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700943 msync_session_set_video_dis(avsync->fd, fpts);
944 avsync->last_disc_pts = fpts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700945 }
946
947 if ((int)(systime - fpts) > 0) {
948 if ((int)(systime - fpts) < avsync->disc_thres_max) {
949 /* catch up PCR */
Song Zhaof46932e2021-05-21 01:51:45 -0700950 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700951 } else {
952 /* render according to FPS */
953 if (!VALID_TS(avsync->last_r_syst) ||
954 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
955 avsync->last_r_syst = systime;
956 return true;
957 }
958 return false;
959 }
960 } else if (LIVE_MODE(avsync->mode)) {
961 /* hold if the gap is small */
962 if ((int)(fpts - systime) < avsync->disc_thres_max) {
963 return false;
964 } else {
965 /* render according to FPS */
966 if (!VALID_TS(avsync->last_r_syst) ||
967 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
968 avsync->last_r_syst = systime;
969 return true;
970 }
971 return false;
972 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800973 }
974 }
975
Song Zhao52f55192021-05-06 10:52:21 -0700976 /* In some cases, keeping pattern will enlarge the gap */
977 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
978 avsync->first_frame_toggled) {
979 reset_pattern(avsync->pattern_detector);
Song Zhaof46932e2021-05-21 01:51:45 -0700980 log_warn("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700981 systime, fpts);
982 }
983
Song Zhaoc03ba122020-12-23 21:54:02 -0800984 expire = (int)(systime - fpts) >= 0;
985
986 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -0800987 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800988 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -0800989 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800990 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800991 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -0800992 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800993 }
Song Zhao6dce2672022-01-13 11:32:44 -0800994 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -0800995 && avsync->first_frame_toggled) {
996 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -0800997 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800998 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800999 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001000 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001001 }
1002 }
1003
Song Zhaoa58c3e92021-03-09 18:52:55 -08001004 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -08001005 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -08001006 (avsync->last_frame?avsync->last_frame->hold_period:0),
1007 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -08001008 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -08001009
1010 if (expire) {
1011 avsync->vpts = fpts;
1012 /* phase adjustment */
1013 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +00001014 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -08001015 if ((int)(systime - fpts) >= 0 &&
1016 (int)(fpts + interval - systime) > 0) {
1017 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -08001018 avsync->phase_set = true;
yongchun.lia50b1e92021-08-07 01:11:54 +00001019 log_info("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -08001020 }
Song Zhao1561e542022-01-12 10:37:55 -08001021 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -08001022 if ((int)(systime - fpts) >= 0 &&
1023 (int)(fpts + interval - systime) > 0) {
1024 int vsync_pts_delta = (int)(systime - fpts);
1025
1026 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1027 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001028 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001029 log_info("[%d] too aligned adjust phase to %d",
1030 avsync->session_id, (int)avsync->phase);
1031 }
1032 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001033 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001034 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -08001035 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -08001036 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001037 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001038 }
1039 return expire;
1040}
1041
Song Zhao35a82df2021-04-15 10:58:49 -07001042static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001043{
Song Zhao35a82df2021-04-15 10:58:49 -07001044 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001045 log_trace("[%d]cur_period: %d last_period: %d",
1046 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -07001047 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
1048 ret = true;
1049 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
1050 ret = true;
1051 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
1052 ret = true;
1053 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
1054 ret = true;
1055
1056 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -08001057}
1058
1059int av_sync_set_speed(void *sync, float speed)
1060{
1061 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1062
1063 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001064 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001065 return -1;
1066 }
1067
Song Zhao76005282022-03-08 16:49:41 -08001068 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001069 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001070 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001071 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001072
Song Zhaoea5a0412021-01-18 16:40:08 -08001073 avsync->speed = speed;
1074
1075 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
1076 if (speed == 1.0) {
1077 avsync->mode = avsync->backup_mode;
1078 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1079 } else {
1080 avsync->backup_mode = avsync->mode;
1081 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1082 log_info("[%d]audio to freerun mode", avsync->session_id);
1083 }
1084 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001085
Song Zhaoea5a0412021-01-18 16:40:08 -08001086 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1087 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001088}
1089
1090int av_sync_change_mode(void *sync, enum sync_mode mode)
1091{
1092 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1093
1094 if (!avsync)
1095 return -1;
1096
Song Zhaoea5a0412021-01-18 16:40:08 -08001097 if (msync_session_set_mode(avsync->fd, mode)) {
1098 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001099 return -1;
1100 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001101 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001102 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001103 return 0;
1104}
1105
Song Zhao01031bb2021-05-13 21:23:20 -07001106int av_sync_get_mode(void *sync, enum sync_mode *mode)
1107{
1108 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1109
1110 if (!avsync || !mode)
1111 return -1;
1112
1113 *mode = avsync->mode;
1114 return 0;
1115}
1116
Song Zhaoc03ba122020-12-23 21:54:02 -08001117int av_sync_set_pause_pts(void *sync, pts90K pts)
1118{
1119 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1120
1121 if (!avsync)
1122 return -1;
1123
1124 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001125 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001126 return 0;
1127}
1128
1129int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1130{
1131 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1132
1133 if (!avsync)
1134 return -1;
1135
1136 avsync->pause_pts_cb = cb;
1137 avsync->pause_cb_priv = priv;
1138 return 0;
1139}
Song Zhaoea5a0412021-01-18 16:40:08 -08001140
yongchun.li428390d2022-02-17 17:15:40 -08001141int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1142{
1143 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1144
1145 if (!avsync)
1146 return -1;
1147
1148 avsync->underflow_cb = cb;
1149 avsync->underflow_cb_priv = priv;
1150
1151 if (cfg)
1152 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1153 else
1154 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1155
1156 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1157 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1158 avsync->underflow_cfg.time_thresh);
1159 return 0;
1160}
Song Zhaoea5a0412021-01-18 16:40:08 -08001161static void trigger_audio_start_cb(struct av_sync_session *avsync,
1162 avs_ascb_reason reason)
1163{
1164 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001165 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001166 pthread_mutex_lock(&avsync->lock);
1167 if (avsync->audio_start) {
1168 avsync->audio_start(avsync->audio_start_priv, reason);
1169 avsync->session_started = true;
1170 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001171 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001172 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1173 }
1174 pthread_mutex_unlock(&avsync->lock);
1175 }
1176}
1177
1178avs_start_ret av_sync_audio_start(
1179 void *sync,
1180 pts90K pts,
1181 pts90K delay,
1182 audio_start_cb cb,
1183 void *priv)
1184{
1185 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1186 uint32_t start_mode;
yongchun.li59e873d2021-07-07 11:42:38 -07001187 uint32_t systime;
Song Zhaoea5a0412021-01-18 16:40:08 -08001188 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1189 bool create_poll_t = false;
1190
1191 if (!avsync)
1192 return ret;
1193
yongchun.li59e873d2021-07-07 11:42:38 -07001194 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1195 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001196
yongchun.li59e873d2021-07-07 11:42:38 -07001197 if (avsync->in_audio_switch &&
1198 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1199 {
1200 start_mode = AVS_START_SYNC;
1201 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1202 } else {
1203 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1204 log_error("[%d]fail to set audio start", avsync->session_id);
1205 }
1206 if (avsync->in_audio_switch &&
1207 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1208 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
1209 msync_session_get_wall(avsync->fd, &systime, NULL);
1210 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB &&
1211 start_mode == AVS_START_SYNC) {
1212 log_info("%d audio_switch audio need drop first.ahead %d ms",
1213 avsync->session_id, (int)(systime - pts)/90);
1214 ret = AV_SYNC_ASTART_AGAIN;
1215 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1216 goto exit;
1217 }
1218 else {
1219 int diff = (int)(pts - systime);
1220 log_info("%d audio_switch_state to start mode %d diff %d ms",
1221 avsync->session_id, start_mode, diff/90);
1222 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
1223 if (diff < A_ADJ_THREDHOLD_LB) {
1224 log_info("%d orig mode %d already close enough direct start",
1225 avsync->session_id, start_mode);
1226 start_mode = AVS_START_SYNC;
1227 }
1228 }
yongchun.li107a6162021-05-05 02:38:57 -07001229 }
1230
Song Zhaoea5a0412021-01-18 16:40:08 -08001231 if (start_mode == AVS_START_SYNC) {
1232 ret = AV_SYNC_ASTART_SYNC;
1233 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001234 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001235 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001236 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001237 avsync->state = AV_SYNC_STAT_RUNNING;
1238 } else if (start_mode == AVS_START_AGAIN) {
1239 ret = AV_SYNC_ASTART_AGAIN;
1240 }
1241
1242 if (ret == AV_SYNC_ASTART_AGAIN)
1243 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001244
Song Zhao76005282022-03-08 16:49:41 -08001245 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1246 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001247 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001248
1249 if (start_mode == AVS_START_ASYNC) {
1250 if (!cb) {
1251 log_error("[%d]invalid cb", avsync->session_id);
1252 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001253 }
Song Zhao76005282022-03-08 16:49:41 -08001254 avsync->audio_start = cb;
1255 avsync->audio_start_priv = priv;
1256 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001257
Song Zhaod62bb392021-04-23 12:25:49 -07001258 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001259 int ret;
1260
1261 log_info("[%d]start poll thread", avsync->session_id);
1262 avsync->quit_poll = false;
1263 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1264 if (ret) {
1265 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1266 return AV_SYNC_ASTART_ERR;
1267 }
1268 }
Song Zhaod62bb392021-04-23 12:25:49 -07001269 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001270 msync_session_get_wall(avsync->fd, &systime, NULL);
1271 log_info("[%d]return %u w %u pts %u d %u",
1272 avsync->session_id, ret, systime, pts, delay);
1273 }
1274exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001275 log_info("[%d]return %u", avsync->session_id, ret);
1276 return ret;
1277}
1278
1279int av_sync_audio_render(
1280 void *sync,
1281 pts90K pts,
1282 struct audio_policy *policy)
1283{
1284 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001285 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001286 uint32_t systime;
1287 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1288 avs_audio_action action = AA_SYNC_AA_MAX;
1289
1290 if (!avsync || !policy)
1291 return -1;
1292
yongchun.li107a6162021-05-05 02:38:57 -07001293 msync_session_get_wall(avsync->fd, &systime, NULL);
1294
1295 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1296 pts, systime, avsync->mode, (int)(pts-systime)/90);
1297
1298 if (avsync->in_audio_switch
1299 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
1300 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
1301 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1302 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1303 action = AV_SYNC_AA_RENDER;
1304 } else if ((int)(systime - pts) > 0) {
1305 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1306 (int)(systime - pts)/90, systime, pts);
1307 action = AV_SYNC_AA_DROP;
1308 } else {
1309 action = AV_SYNC_AA_INSERT;
1310 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1311 (int)(pts - systime)/90, systime, pts);
1312 }
1313 goto done;
1314 }
1315
Song Zhaoea5a0412021-01-18 16:40:08 -08001316 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1317 avsync->mode == AV_SYNC_MODE_AMASTER) {
1318 action = AV_SYNC_AA_RENDER;
1319 goto done;
1320 }
1321
Song Zhaod62bb392021-04-23 12:25:49 -07001322 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001323 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001324 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1325 action = AV_SYNC_AA_DROP;
1326 goto done;
1327 }
1328
Song Zhao7daf3a12021-05-10 22:22:25 -07001329 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1330 avsync->mode == AV_SYNC_MODE_AMASTER) {
1331 action = AV_SYNC_AA_RENDER;
1332 goto done;
1333 }
1334
Song Zhaod62bb392021-04-23 12:25:49 -07001335 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1336 LIVE_MODE(avsync->mode) &&
1337 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1338 /* outlier by stream error */
1339 avsync->outlier_cnt++;
1340 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1341 /* treat as disc, just drop current frame */
1342 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1343 avsync->outlier_cnt = 0;
1344 action = AV_SYNC_AA_DROP;
1345 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001346 goto done;
1347 }
1348 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1349 pts = systime;
1350 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001351 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001352 goto done;
1353 }
1354
1355 avsync->outlier_cnt = 0;
1356 /* low bound from sync_lost to sync_setup */
1357 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1358 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1359 action = AV_SYNC_AA_RENDER;
1360 goto done;
1361 }
1362
1363 /* high bound of sync_setup */
1364 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1365 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1366 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001367 action = AV_SYNC_AA_RENDER;
1368 goto done;
1369 }
1370
1371 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001372 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001373 action = AV_SYNC_AA_DROP;
1374 goto done;
1375 }
1376
1377 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001378 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001379 action = AV_SYNC_AA_INSERT;
1380 goto done;
1381 }
1382
1383done:
1384 policy->action = action;
1385 policy->delta = (int)(systime - pts);
1386 if (action == AV_SYNC_AA_RENDER) {
1387 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001388 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001389 if (!out_lier)
1390 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001391 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001392 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001393 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1394 msync_session_update_apts(avsync->fd, systime, pts, 0);
1395 log_info("[%d] audio switch done sys %u pts %u",
1396 avsync->session_id, systime, pts);
1397 msync_session_set_audio_switch(avsync->fd, false);
1398 avsync->in_audio_switch = false;
1399 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1400 } else {
1401 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1402 avsync->session_id, action, systime, pts, systime - pts);
1403 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001404 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001405 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001406 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001407 avsync->last_disc_pts != pts &&
1408 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001409 log_info ("[%d]audio disc %u --> %u",
1410 avsync->session_id, systime, pts);
1411 msync_session_set_audio_dis(avsync->fd, pts);
1412 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001413 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001414 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001415
1416 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001417 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001418 if (!avsync->audio_drop_cnt)
1419 avsync->audio_drop_start = now;
1420 avsync->audio_drop_cnt++;
1421 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1422 log_info ("[%d]audio keep dropping sys %u vs a %u",
1423 avsync->session_id, systime, pts);
1424 msync_session_set_audio_dis(avsync->fd, pts);
1425 }
Song Zhao409739b2021-05-12 22:21:40 -07001426 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001427 if (action != AV_SYNC_AA_DROP)
1428 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001429 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001430 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001431 }
1432
1433 return ret;
1434}
1435
1436int av_sync_get_clock(void *sync, pts90K *pts)
1437{
1438 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1439
1440 if (!avsync || !pts)
1441 return -1;
1442 return msync_session_get_wall(avsync->fd, pts, NULL);
1443}
1444
1445static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001446 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001447 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001448{
Song Zhao76005282022-03-08 16:49:41 -08001449 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1450 avsync->session_id, avsync->active_mode, avsync->mode,
1451 v_active, a_active, v_timeout, stat);
1452
1453 /* iptv delayed start */
1454 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1455 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1456
Song Zhaoea5a0412021-01-18 16:40:08 -08001457 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1458 float speed;
Song Zhao7e8c68f2022-07-12 16:24:30 -07001459 if (a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001460 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001461 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhao6183ca92022-07-29 09:57:03 -07001462 } else if (!a_active && !avsync->session_started) {
1463 /* quit waiting ASAP */
1464 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoea5a0412021-01-18 16:40:08 -08001465 }
1466
1467 if (!msync_session_get_rate(avsync->fd, &speed)) {
1468 /* speed change is triggered by asink,
1469 * attached audio HAL will handle it
1470 */
1471 if (speed != avsync->speed)
1472 log_info("[%d]new rate %f", avsync->session_id, speed);
1473 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001474 if (avsync->mode != avsync->backup_mode) {
1475 avsync->mode = avsync->backup_mode;
1476 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1477 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001478 } else {
1479 avsync->backup_mode = avsync->mode;
1480 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1481 log_info("[%d]audio to freerun mode", avsync->session_id);
1482 }
1483 avsync->speed = speed;
1484 }
Song Zhaod62bb392021-04-23 12:25:49 -07001485 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1486 struct session_debug debug;
1487 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001488 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001489 avsync->backup_mode = avsync->mode;
1490 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001491 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001492 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001493 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001494 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001495 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001496 log_warn("[%d]audio back to mode %d",
1497 avsync->session_id, avsync->mode);
1498 }
1499 }
Song Zhao76005282022-03-08 16:49:41 -08001500 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1501 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001502 }
1503}
1504
1505static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001506 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001507 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001508{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001509 struct session_debug debug;
1510
Song Zhao76005282022-03-08 16:49:41 -08001511 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1512 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001513 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1514 if (debug.debug_freerun && !avsync->debug_freerun) {
1515 avsync->backup_mode = avsync->mode;
1516 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1517 avsync->debug_freerun = true;
1518 log_warn("[%d]video to freerun mode", avsync->session_id);
1519 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1520 avsync->mode = avsync->backup_mode;
1521 avsync->debug_freerun = false;
1522 log_warn("[%d]video back to mode %d",
1523 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001524 }
1525 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001526}
1527
1528static void * poll_thread(void * arg)
1529{
1530 int ret = 0;
1531 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1532 const int fd = avsync->fd;
1533 struct pollfd pfd = {
1534 /* default blocking capture */
1535 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1536 .fd = avsync->fd,
1537 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001538 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001539
1540 prctl (PR_SET_NAME, "avs_poll");
1541 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001542
1543 if (avsync->type == AV_SYNC_TYPE_AUDIO)
1544 sflag = SRC_A;
1545 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
1546 sflag = SRC_V;
1547
Song Zhaoea5a0412021-01-18 16:40:08 -08001548 while (!avsync->quit_poll) {
1549 for (;;) {
1550 ret = poll(&pfd, 1, 10);
1551 if (ret > 0)
1552 break;
1553 if (avsync->quit_poll)
1554 goto exit;
1555 if (errno == EINTR)
1556 continue;
1557 }
1558
1559 /* error handling */
1560 if (pfd.revents & POLLERR)
1561 log_error("[%d]POLLERR received", avsync->session_id);
1562
Song Zhaod62bb392021-04-23 12:25:49 -07001563 /* mode change. Non-exclusive wait so all the processes
1564 * shall be woken up
1565 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001566 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001567 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001568 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001569
Song Zhao76005282022-03-08 16:49:41 -08001570 msync_session_get_stat(fd, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001571 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001572
1573 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001574 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001575 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001576 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001577 usleep(10000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001578 }
1579 }
1580exit:
1581 log_info("[%d]quit", avsync->session_id);
1582 return NULL;
1583}
1584
Song Zhao623e2f12021-09-03 15:54:04 -07001585#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1586/* return ppm between demod and PCR clock */
1587int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1588{
1589 int fd = -1, ppm = 0, nread;
1590 char buf[128];
1591 uint32_t reg_v, lock;
1592 float val;
1593
1594 fd = open(DEMOD_NODE, O_RDWR);
1595 if (fd < 0) {
1596 log_warn("node not found %s", DEMOD_NODE);
1597 /* do not retry */
1598 avsync->ppm_adjusted = true;
1599 return 0;
1600 }
1601 snprintf(buf, sizeof(buf), "%d", 5);
1602 write(fd, buf, 2);
1603
1604 lseek(fd, 0, SEEK_SET);
1605
1606 nread = read(fd, buf, sizeof(buf));
1607 if (nread <= 0) {
1608 log_error("read error");
1609 goto err;
1610 }
1611 buf[nread] = 0;
1612 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1613 log_error("wrong format %s", buf);
1614 goto err;
1615 }
1616 if (lock != 0x1f) {
1617 log_info("demod not locked");
1618 goto err;
1619 }
1620 if (reg_v > ((2 << 20) - 1))
1621 reg_v -= (2 << 21);
1622 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1623 ppm = val;
1624 log_info("ppm from SFO %d", ppm);
1625 avsync->ppm_adjusted = true;
1626
1627err:
1628 if (fd >= 0)
1629 close(fd);
1630 return ppm;
1631}
1632
Song Zhaod62bb392021-04-23 12:25:49 -07001633int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001634{
1635 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001636 struct pcr_info pcr;
1637 enum pcr_monitor_status status;
1638 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001639 if (!avsync)
1640 return -1;
1641
1642 if (avsync->type != AV_SYNC_TYPE_PCR)
1643 return -2;
1644
Song Zhao623e2f12021-09-03 15:54:04 -07001645 /* initial estimation from Demod SFO HW */
1646 if (!avsync->ppm_adjusted) {
1647 ppm = dmod_get_sfo_dev(avsync);
1648 if (ppm != 0) {
1649 /* ppm > 0 means board clock is faster */
1650 msync_session_set_clock_dev(avsync->fd, -ppm);
1651 }
1652 }
wei.dubcc2ed22021-05-19 07:16:10 -04001653 pcr.monoclk = mono_clock / 1000;
1654 pcr.pts = (long long) pts * 1000 / 90;
1655 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1656
1657 status = pcr_monitor_get_status(avsync->pcr_monitor);
1658
1659 if (status >= DEVIATION_READY) {
1660 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1661 if (avsync->ppm != ppm) {
1662 avsync->ppm = ppm;
1663 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1664 if (msync_session_set_clock_dev(avsync->fd, ppm))
1665 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001666 else
1667 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001668 }
1669 }
1670
Song Zhaod62bb392021-04-23 12:25:49 -07001671 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001672}
1673
Song Zhaod62bb392021-04-23 12:25:49 -07001674int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001675{
1676 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1677
1678 if (!avsync)
1679 return -1;
1680
Song Zhaod62bb392021-04-23 12:25:49 -07001681 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001682}
1683
1684int av_sync_set_session_name(void *sync, const char *name)
1685{
1686 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1687
1688 if (!avsync)
1689 return -1;
1690
1691 return msync_session_set_name(avsync->fd, name);
1692}
yongchun.li107a6162021-05-05 02:38:57 -07001693
1694int av_sync_set_audio_switch(void *sync, bool start)
1695{
1696 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1697 bool v_active, a_active, v_timeout;
1698
1699 if (!avsync)
1700 return -1;
Song Zhao76005282022-03-08 16:49:41 -08001701 if (msync_session_get_stat(avsync->fd, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001702 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001703 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001704 log_error("[%d] can not get session state",
1705 avsync->session_id);
1706 return -1;
1707 }
1708 if (!v_active || !a_active) {
1709 log_error("[%d] no apply if not AV both active v %d a %d",
1710 avsync->session_id, v_active, a_active);
1711 return -1;
1712 }
1713 if (msync_session_set_audio_switch(avsync->fd, start)) {
1714 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1715 return -1;
1716 }
1717 avsync->in_audio_switch = start;
1718 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1719 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1720 return 0;
1721}
1722
1723int av_sync_get_audio_switch(void *sync, bool *start)
1724{
1725 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1726
1727 if (!avsync)
1728 return -1;
Song Zhao76005282022-03-08 16:49:41 -08001729 if (msync_session_get_stat(avsync->fd, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001730 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001731 log_error("[%d] can not audio seamless switch state",
1732 avsync->session_id);
1733 return -1;
1734 }
1735 if (start) *start = avsync->in_audio_switch;
1736 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001737}
Song Zhao8039f562021-05-18 18:11:25 -07001738
Song Zhao623e2f12021-09-03 15:54:04 -07001739enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001740{
1741 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1742
wei.dubcc2ed22021-05-19 07:16:10 -04001743 if (!avsync || !ppm)
1744 return CLK_RECOVERY_ERR;
1745 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001746 return CLK_RECOVERY_NOT_RUNNING;
1747
wei.dubcc2ed22021-05-19 07:16:10 -04001748 if (msync_session_get_clock_dev(avsync->fd, ppm))
1749 return CLK_RECOVERY_ERR;
1750
1751 if (*ppm == 0)
1752 return CLK_RECOVERY_ONGOING;
1753 else
1754 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001755}
Song Zhao95bd0922021-09-21 14:07:46 -07001756
1757static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1758{
1759 int ret;
1760
1761 if (!avsync->frame_q) {
1762 avsync->frame_q = create_q(MAX_FRAME_NUM);
1763 if (!avsync->frame_q) {
1764 log_error("[%d]create queue fail", avsync->session_id);
1765
1766 return -1;
1767 }
1768 }
1769
1770 ret = queue_item(avsync->frame_q, frame);
1771 if (ret)
1772 log_error("%s queue fail:%d", ret);
1773 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1774 return ret;
1775}
1776
1777int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1778{
1779 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1780
1781 if (!avsync)
1782 return -1;
1783 avsync->msys = msys;
1784 return 0;
1785}
1786
1787static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1788{
1789 struct vframe *frame = NULL, *enter_last_frame = NULL;
1790 uint64_t systime;
1791 int toggle_cnt = 0;
1792
1793 enter_last_frame = avsync->last_frame;
1794 systime = avsync->msys;
1795 log_debug("[%d]sys %llu", avsync->session_id, systime);
1796 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1797 if (systime >= frame->mts) {
1798 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1799 toggle_cnt++;
1800
1801 if (avsync->last_frame)
1802 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1803
1804 dqueue_item(avsync->frame_q, (void **)&frame);
1805 if (avsync->last_frame) {
1806 /* free frame that are not for display */
1807 if (toggle_cnt > 1) {
1808 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1809 avsync->last_frame->mts, frame->mts, systime);
1810 avsync->last_frame->free(avsync->last_frame);
1811 }
1812 } else {
1813 avsync->first_frame_toggled = true;
1814 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1815 }
1816 avsync->last_frame = frame;
1817 } else
1818 break;
1819 }
1820
1821 if (avsync->last_frame) {
1822 if (enter_last_frame != avsync->last_frame)
1823 log_debug("[%d]pop %llu", avsync->session_id, avsync->last_frame->pts);
1824 log_trace("[%d]pop=%llu, system=%llu, diff %d(ms), QNum=%d", avsync->session_id,
1825 avsync->last_frame->mts,
1826 systime, (systime - avsync->last_frame->mts) / 1000000,
1827 queue_size(avsync->frame_q));
1828 } else
1829 if (enter_last_frame != avsync->last_frame)
1830 log_debug("[%d]pop (nil)", avsync->session_id);
1831
1832 if (avsync->last_frame)
1833 avsync->last_frame->hold_period++;
1834 return avsync->last_frame;
1835}
Song Zhao6183ca92022-07-29 09:57:03 -07001836
1837int avs_sync_stop_audio(void *sync)
1838{
1839 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1840
1841 if (!avsync)
1842 return -1;
1843
1844 return msync_session_stop_audio(avsync->fd);
1845}