blob: c9e53012c4ab5fd7bc0b488376b1352e04ebf327 [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) {
Song Zhao468fd652021-01-15 22:13:04 -0800780 /* stay in paused until av_sync_pause(false) */
Song Zhaoa1742282022-09-30 16:17:26 -0700781 uint32_t local_pts = avsync->pause_pts;
Song Zhao468fd652021-01-15 22:13:04 -0800782 avsync->paused = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800783 log_info ("[%d]reach pause pts: %u",
Song Zhaob5458b32021-11-12 15:58:47 -0800784 avsync->session_id, avsync->pause_pts);
Song Zhaoad7c8232021-12-14 11:46:48 -0800785 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoa1742282022-09-30 16:17:26 -0700786 if (avsync->pause_pts_cb)
787 avsync->pause_pts_cb(local_pts,
788 avsync->pause_cb_priv);
789 log_info ("[%d] reach pause pts: %u handle done",
790 avsync->session_id, local_pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800791 }
792
793exit:
794 pthread_mutex_unlock(&avsync->lock);
yongchun.li428390d2022-02-17 17:15:40 -0800795
796 /* underflow check */
797 if (avsync->session_started && avsync->first_frame_toggled &&
798 (avsync->paused == false) && (avsync->state >= AV_SYNC_STAT_RUNNING) &&
799 avsync->underflow_cb && peek_item(avsync->frame_q, (void **)&frame, 0))
800 {/* empty queue in normal play */
801 struct timespec now;
802 int diff_ms;
803 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
804 diff_ms = time_diff(&now, &avsync->frame_last_update_time)/1000;
805 if(diff_ms >= (avsync->underflow_cfg.time_thresh
806 + avsync->vsync_interval*avsync->last_holding_peroid/90)) {
807 log_info ("[%d]underflow detected: %u", avsync->session_id, avsync->last_pts);
808 avsync->underflow_cb (avsync->last_pts,
809 avsync->underflow_cb_priv);
810 /* update time to control the underflow check call backs */
811 avsync->frame_last_update_time = now;
812 }
813 }
814
Song Zhaoc03ba122020-12-23 21:54:02 -0800815 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800816 if (enter_last_frame != avsync->last_frame)
817 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
bo.xiao1f94b352021-08-02 03:53:47 -0400818 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 -0700819 /* don't update vpts for out_lier */
820 if (avsync->last_frame->duration != -1)
821 msync_session_update_vpts(avsync->fd, systime,
822 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800823 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800824 if (enter_last_frame != avsync->last_frame)
825 log_debug("[%d]pop (nil)", avsync->session_id);
826
Song Zhao35a82df2021-04-15 10:58:49 -0700827 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800828 if (avsync->last_frame)
829 avsync->last_frame->hold_period++;
830 return avsync->last_frame;
831}
832
Song Zhaoc03ba122020-12-23 21:54:02 -0800833static inline uint32_t abs_diff(uint32_t a, uint32_t b)
834{
Song Zhaoea5a0412021-01-18 16:40:08 -0800835 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800836}
837
yongchun.li0ee6e372021-08-20 04:26:04 -0700838static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800839{
hanghang.luo02efd312022-08-26 09:49:53 +0800840 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 -0800841}
842
Song Zhaoc03ba122020-12-23 21:54:02 -0800843static bool frame_expire(struct av_sync_session* avsync,
844 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800845 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800846 struct vframe * frame,
847 struct vframe * next_frame,
848 int toggle_cnt)
849{
Song Zhao6dce2672022-01-13 11:32:44 -0800850 uint32_t fpts = frame->pts + avsync->extra_delay;
851 uint32_t nfpts = -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800852 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800853 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800854
855 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
856 return false;
857
858 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
859 return true;
860
Song Zhaoad7c8232021-12-14 11:46:48 -0800861 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS &&
862 avsync->pause_pts == frame->pts)
863 return true;
864
Song Zhao08fa16b2021-12-08 14:30:17 -0800865 if (systime == AV_SYNC_INVALID_PTS &&
866 avsync->mode == AV_SYNC_MODE_AMASTER)
867 return false;
868
Song Zhao6dce2672022-01-13 11:32:44 -0800869 if (next_frame)
870 nfpts = next_frame->pts + avsync->extra_delay;
871
Song Zhao7e24b182022-04-01 08:46:40 -0700872 if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
fei.deng63e43e12021-09-23 19:44:01 +0800873 /* We need to ensure that the video outputs smoothly,
874 so output video frame by frame hold_period */
875 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
876 avsync->last_frame &&
877 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
878 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
879 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700880 return true;
881 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700882 }
883
Song Zhaoc03ba122020-12-23 21:54:02 -0800884 if (!fpts) {
885 if (avsync->last_frame) {
886 /* try to accumulate duration as PTS */
887 fpts = avsync->vpts + avsync->last_frame->duration;
888 } else {
889 fpts = avsync->vpts;
890 }
891 }
892 systime += pts_correction;
893
894 /* phase adjustment */
895 if (avsync->phase_set)
896 systime += avsync->phase;
897
yongchun.lia50b1e92021-08-07 01:11:54 +0000898 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800899 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000900 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700901 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800902 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800903 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800904 return false;
905
Song Zhaoa2985cb2021-06-24 12:01:47 -0700906 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
907 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700908 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800909
yongchun.li0ee6e372021-08-20 04:26:04 -0700910 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700911 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800912 avsync->last_pts = fpts;
913 if (time_diff(&now, &avsync->sync_lost_print_time) >=
914 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700915 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800916 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800917 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700918 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800919 } else
920 avsync->sync_lost_cnt++;
921 }
Song Zhaod62bb392021-04-23 12:25:49 -0700922
923 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
924 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700925 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700926 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700927 /* outlier by stream error */
928 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700929 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700930 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
931 log_info("render outlier %u", fpts);
932 return true;
933 }
934 }
935
936 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800937 avsync->state = AV_SYNC_STAT_SYNC_LOST;
938 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800939 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700940 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800941 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700942
Song Zhao7e24b182022-04-01 08:46:40 -0700943 if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700944 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700945 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700946 msync_session_set_video_dis(avsync->fd, fpts);
947 avsync->last_disc_pts = fpts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700948 }
949
950 if ((int)(systime - fpts) > 0) {
951 if ((int)(systime - fpts) < avsync->disc_thres_max) {
952 /* catch up PCR */
Song Zhaof46932e2021-05-21 01:51:45 -0700953 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700954 } else {
955 /* render according to FPS */
956 if (!VALID_TS(avsync->last_r_syst) ||
957 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
958 avsync->last_r_syst = systime;
959 return true;
960 }
961 return false;
962 }
963 } else if (LIVE_MODE(avsync->mode)) {
964 /* hold if the gap is small */
965 if ((int)(fpts - systime) < avsync->disc_thres_max) {
966 return false;
967 } else {
968 /* render according to FPS */
969 if (!VALID_TS(avsync->last_r_syst) ||
970 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
971 avsync->last_r_syst = systime;
972 return true;
973 }
974 return false;
975 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800976 }
977 }
978
Song Zhao52f55192021-05-06 10:52:21 -0700979 /* In some cases, keeping pattern will enlarge the gap */
980 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
981 avsync->first_frame_toggled) {
982 reset_pattern(avsync->pattern_detector);
Song Zhaof46932e2021-05-21 01:51:45 -0700983 log_warn("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700984 systime, fpts);
985 }
986
Song Zhaoc03ba122020-12-23 21:54:02 -0800987 expire = (int)(systime - fpts) >= 0;
988
989 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -0800990 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800991 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -0800992 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800993 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800994 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -0800995 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800996 }
Song Zhao6dce2672022-01-13 11:32:44 -0800997 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -0800998 && avsync->first_frame_toggled) {
999 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -08001000 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001001 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -08001002 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001003 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001004 }
1005 }
1006
Song Zhaoa58c3e92021-03-09 18:52:55 -08001007 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -08001008 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -08001009 (avsync->last_frame?avsync->last_frame->hold_period:0),
1010 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -08001011 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -08001012
1013 if (expire) {
1014 avsync->vpts = fpts;
1015 /* phase adjustment */
1016 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +00001017 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -08001018 if ((int)(systime - fpts) >= 0 &&
1019 (int)(fpts + interval - systime) > 0) {
1020 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -08001021 avsync->phase_set = true;
yongchun.lia50b1e92021-08-07 01:11:54 +00001022 log_info("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -08001023 }
Song Zhao1561e542022-01-12 10:37:55 -08001024 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -08001025 if ((int)(systime - fpts) >= 0 &&
1026 (int)(fpts + interval - systime) > 0) {
1027 int vsync_pts_delta = (int)(systime - fpts);
1028
1029 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1030 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001031 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001032 log_info("[%d] too aligned adjust phase to %d",
1033 avsync->session_id, (int)avsync->phase);
1034 }
1035 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001036 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001037 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -08001038 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -08001039 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001040 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001041 }
1042 return expire;
1043}
1044
Song Zhao35a82df2021-04-15 10:58:49 -07001045static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001046{
Song Zhao35a82df2021-04-15 10:58:49 -07001047 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001048 log_trace("[%d]cur_period: %d last_period: %d",
1049 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -07001050 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
1051 ret = true;
1052 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
1053 ret = true;
1054 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
1055 ret = true;
1056 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
1057 ret = true;
1058
1059 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -08001060}
1061
1062int av_sync_set_speed(void *sync, float speed)
1063{
1064 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1065
1066 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001067 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001068 return -1;
1069 }
1070
Song Zhao76005282022-03-08 16:49:41 -08001071 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001072 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001073 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001074 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001075
Song Zhaoea5a0412021-01-18 16:40:08 -08001076 avsync->speed = speed;
1077
1078 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
1079 if (speed == 1.0) {
1080 avsync->mode = avsync->backup_mode;
1081 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1082 } else {
1083 avsync->backup_mode = avsync->mode;
1084 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1085 log_info("[%d]audio to freerun mode", avsync->session_id);
1086 }
1087 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001088
Song Zhaoea5a0412021-01-18 16:40:08 -08001089 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1090 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001091}
1092
1093int av_sync_change_mode(void *sync, enum sync_mode mode)
1094{
1095 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1096
1097 if (!avsync)
1098 return -1;
1099
Song Zhaoea5a0412021-01-18 16:40:08 -08001100 if (msync_session_set_mode(avsync->fd, mode)) {
1101 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001102 return -1;
1103 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001104 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001105 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001106 return 0;
1107}
1108
Song Zhao01031bb2021-05-13 21:23:20 -07001109int av_sync_get_mode(void *sync, enum sync_mode *mode)
1110{
1111 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1112
1113 if (!avsync || !mode)
1114 return -1;
1115
1116 *mode = avsync->mode;
1117 return 0;
1118}
1119
Song Zhaoc03ba122020-12-23 21:54:02 -08001120int av_sync_set_pause_pts(void *sync, pts90K pts)
1121{
1122 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1123
1124 if (!avsync)
1125 return -1;
1126
1127 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001128 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001129 return 0;
1130}
1131
1132int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1133{
1134 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1135
1136 if (!avsync)
1137 return -1;
1138
1139 avsync->pause_pts_cb = cb;
1140 avsync->pause_cb_priv = priv;
1141 return 0;
1142}
Song Zhaoea5a0412021-01-18 16:40:08 -08001143
yongchun.li428390d2022-02-17 17:15:40 -08001144int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1145{
1146 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1147
1148 if (!avsync)
1149 return -1;
1150
1151 avsync->underflow_cb = cb;
1152 avsync->underflow_cb_priv = priv;
1153
1154 if (cfg)
1155 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1156 else
1157 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1158
1159 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1160 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1161 avsync->underflow_cfg.time_thresh);
1162 return 0;
1163}
Song Zhaoea5a0412021-01-18 16:40:08 -08001164static void trigger_audio_start_cb(struct av_sync_session *avsync,
1165 avs_ascb_reason reason)
1166{
1167 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001168 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001169 pthread_mutex_lock(&avsync->lock);
1170 if (avsync->audio_start) {
1171 avsync->audio_start(avsync->audio_start_priv, reason);
1172 avsync->session_started = true;
1173 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001174 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001175 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1176 }
1177 pthread_mutex_unlock(&avsync->lock);
1178 }
1179}
1180
1181avs_start_ret av_sync_audio_start(
1182 void *sync,
1183 pts90K pts,
1184 pts90K delay,
1185 audio_start_cb cb,
1186 void *priv)
1187{
1188 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1189 uint32_t start_mode;
yongchun.li59e873d2021-07-07 11:42:38 -07001190 uint32_t systime;
Song Zhaoea5a0412021-01-18 16:40:08 -08001191 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1192 bool create_poll_t = false;
1193
1194 if (!avsync)
1195 return ret;
1196
yongchun.li59e873d2021-07-07 11:42:38 -07001197 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1198 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001199
yongchun.li59e873d2021-07-07 11:42:38 -07001200 if (avsync->in_audio_switch &&
1201 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1202 {
1203 start_mode = AVS_START_SYNC;
1204 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1205 } else {
1206 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1207 log_error("[%d]fail to set audio start", avsync->session_id);
1208 }
1209 if (avsync->in_audio_switch &&
1210 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1211 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
1212 msync_session_get_wall(avsync->fd, &systime, NULL);
1213 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB &&
1214 start_mode == AVS_START_SYNC) {
1215 log_info("%d audio_switch audio need drop first.ahead %d ms",
1216 avsync->session_id, (int)(systime - pts)/90);
1217 ret = AV_SYNC_ASTART_AGAIN;
1218 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1219 goto exit;
1220 }
1221 else {
1222 int diff = (int)(pts - systime);
1223 log_info("%d audio_switch_state to start mode %d diff %d ms",
1224 avsync->session_id, start_mode, diff/90);
1225 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
1226 if (diff < A_ADJ_THREDHOLD_LB) {
1227 log_info("%d orig mode %d already close enough direct start",
1228 avsync->session_id, start_mode);
1229 start_mode = AVS_START_SYNC;
1230 }
1231 }
yongchun.li107a6162021-05-05 02:38:57 -07001232 }
1233
Song Zhaoea5a0412021-01-18 16:40:08 -08001234 if (start_mode == AVS_START_SYNC) {
1235 ret = AV_SYNC_ASTART_SYNC;
1236 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001237 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001238 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001239 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001240 avsync->state = AV_SYNC_STAT_RUNNING;
1241 } else if (start_mode == AVS_START_AGAIN) {
1242 ret = AV_SYNC_ASTART_AGAIN;
1243 }
1244
1245 if (ret == AV_SYNC_ASTART_AGAIN)
1246 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001247
Song Zhao76005282022-03-08 16:49:41 -08001248 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1249 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001250 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001251
1252 if (start_mode == AVS_START_ASYNC) {
1253 if (!cb) {
1254 log_error("[%d]invalid cb", avsync->session_id);
1255 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001256 }
Song Zhao76005282022-03-08 16:49:41 -08001257 avsync->audio_start = cb;
1258 avsync->audio_start_priv = priv;
1259 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001260
Song Zhaod62bb392021-04-23 12:25:49 -07001261 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001262 int ret;
1263
1264 log_info("[%d]start poll thread", avsync->session_id);
1265 avsync->quit_poll = false;
1266 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1267 if (ret) {
1268 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1269 return AV_SYNC_ASTART_ERR;
1270 }
1271 }
Song Zhaod62bb392021-04-23 12:25:49 -07001272 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001273 msync_session_get_wall(avsync->fd, &systime, NULL);
1274 log_info("[%d]return %u w %u pts %u d %u",
1275 avsync->session_id, ret, systime, pts, delay);
1276 }
1277exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001278 log_info("[%d]return %u", avsync->session_id, ret);
1279 return ret;
1280}
1281
1282int av_sync_audio_render(
1283 void *sync,
1284 pts90K pts,
1285 struct audio_policy *policy)
1286{
1287 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001288 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001289 uint32_t systime;
1290 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1291 avs_audio_action action = AA_SYNC_AA_MAX;
1292
1293 if (!avsync || !policy)
1294 return -1;
1295
yongchun.li107a6162021-05-05 02:38:57 -07001296 msync_session_get_wall(avsync->fd, &systime, NULL);
1297
1298 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1299 pts, systime, avsync->mode, (int)(pts-systime)/90);
1300
1301 if (avsync->in_audio_switch
1302 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
1303 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
1304 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1305 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1306 action = AV_SYNC_AA_RENDER;
1307 } else if ((int)(systime - pts) > 0) {
1308 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1309 (int)(systime - pts)/90, systime, pts);
1310 action = AV_SYNC_AA_DROP;
1311 } else {
1312 action = AV_SYNC_AA_INSERT;
1313 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1314 (int)(pts - systime)/90, systime, pts);
1315 }
1316 goto done;
1317 }
1318
Song Zhaoea5a0412021-01-18 16:40:08 -08001319 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1320 avsync->mode == AV_SYNC_MODE_AMASTER) {
1321 action = AV_SYNC_AA_RENDER;
1322 goto done;
1323 }
1324
Song Zhaod62bb392021-04-23 12:25:49 -07001325 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001326 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001327 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1328 action = AV_SYNC_AA_DROP;
1329 goto done;
1330 }
1331
Song Zhao7daf3a12021-05-10 22:22:25 -07001332 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1333 avsync->mode == AV_SYNC_MODE_AMASTER) {
1334 action = AV_SYNC_AA_RENDER;
1335 goto done;
1336 }
1337
Song Zhaod62bb392021-04-23 12:25:49 -07001338 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1339 LIVE_MODE(avsync->mode) &&
1340 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1341 /* outlier by stream error */
1342 avsync->outlier_cnt++;
1343 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1344 /* treat as disc, just drop current frame */
1345 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1346 avsync->outlier_cnt = 0;
1347 action = AV_SYNC_AA_DROP;
1348 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001349 goto done;
1350 }
1351 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1352 pts = systime;
1353 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001354 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001355 goto done;
1356 }
1357
1358 avsync->outlier_cnt = 0;
1359 /* low bound from sync_lost to sync_setup */
1360 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1361 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1362 action = AV_SYNC_AA_RENDER;
1363 goto done;
1364 }
1365
1366 /* high bound of sync_setup */
1367 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1368 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1369 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001370 action = AV_SYNC_AA_RENDER;
1371 goto done;
1372 }
1373
1374 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001375 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001376 action = AV_SYNC_AA_DROP;
1377 goto done;
1378 }
1379
1380 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001381 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001382 action = AV_SYNC_AA_INSERT;
1383 goto done;
1384 }
1385
1386done:
1387 policy->action = action;
1388 policy->delta = (int)(systime - pts);
1389 if (action == AV_SYNC_AA_RENDER) {
1390 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001391 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001392 if (!out_lier)
1393 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001394 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001395 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001396 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1397 msync_session_update_apts(avsync->fd, systime, pts, 0);
1398 log_info("[%d] audio switch done sys %u pts %u",
1399 avsync->session_id, systime, pts);
1400 msync_session_set_audio_switch(avsync->fd, false);
1401 avsync->in_audio_switch = false;
1402 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1403 } else {
1404 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1405 avsync->session_id, action, systime, pts, systime - pts);
1406 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001407 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001408 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001409 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001410 avsync->last_disc_pts != pts &&
1411 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001412 log_info ("[%d]audio disc %u --> %u",
1413 avsync->session_id, systime, pts);
1414 msync_session_set_audio_dis(avsync->fd, pts);
1415 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001416 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001417 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001418
1419 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001420 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001421 if (!avsync->audio_drop_cnt)
1422 avsync->audio_drop_start = now;
1423 avsync->audio_drop_cnt++;
1424 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1425 log_info ("[%d]audio keep dropping sys %u vs a %u",
1426 avsync->session_id, systime, pts);
1427 msync_session_set_audio_dis(avsync->fd, pts);
1428 }
Song Zhao409739b2021-05-12 22:21:40 -07001429 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001430 if (action != AV_SYNC_AA_DROP)
1431 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001432 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001433 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001434 }
1435
1436 return ret;
1437}
1438
1439int av_sync_get_clock(void *sync, pts90K *pts)
1440{
1441 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1442
1443 if (!avsync || !pts)
1444 return -1;
1445 return msync_session_get_wall(avsync->fd, pts, NULL);
1446}
1447
1448static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001449 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001450 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001451{
Song Zhao76005282022-03-08 16:49:41 -08001452 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1453 avsync->session_id, avsync->active_mode, avsync->mode,
1454 v_active, a_active, v_timeout, stat);
1455
1456 /* iptv delayed start */
1457 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1458 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1459
Song Zhaoea5a0412021-01-18 16:40:08 -08001460 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1461 float speed;
Song Zhao7e8c68f2022-07-12 16:24:30 -07001462 if (a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001463 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001464 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhao6183ca92022-07-29 09:57:03 -07001465 } else if (!a_active && !avsync->session_started) {
1466 /* quit waiting ASAP */
1467 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoea5a0412021-01-18 16:40:08 -08001468 }
1469
1470 if (!msync_session_get_rate(avsync->fd, &speed)) {
1471 /* speed change is triggered by asink,
1472 * attached audio HAL will handle it
1473 */
1474 if (speed != avsync->speed)
1475 log_info("[%d]new rate %f", avsync->session_id, speed);
1476 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001477 if (avsync->mode != avsync->backup_mode) {
1478 avsync->mode = avsync->backup_mode;
1479 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1480 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001481 } else {
1482 avsync->backup_mode = avsync->mode;
1483 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1484 log_info("[%d]audio to freerun mode", avsync->session_id);
1485 }
1486 avsync->speed = speed;
1487 }
Song Zhaod62bb392021-04-23 12:25:49 -07001488 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1489 struct session_debug debug;
1490 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001491 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001492 avsync->backup_mode = avsync->mode;
1493 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001494 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001495 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001496 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001497 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001498 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001499 log_warn("[%d]audio back to mode %d",
1500 avsync->session_id, avsync->mode);
1501 }
1502 }
Song Zhao76005282022-03-08 16:49:41 -08001503 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1504 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001505 }
1506}
1507
1508static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001509 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001510 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001511{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001512 struct session_debug debug;
1513
Song Zhao76005282022-03-08 16:49:41 -08001514 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1515 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001516 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1517 if (debug.debug_freerun && !avsync->debug_freerun) {
1518 avsync->backup_mode = avsync->mode;
1519 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1520 avsync->debug_freerun = true;
1521 log_warn("[%d]video to freerun mode", avsync->session_id);
1522 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1523 avsync->mode = avsync->backup_mode;
1524 avsync->debug_freerun = false;
1525 log_warn("[%d]video back to mode %d",
1526 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001527 }
1528 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001529}
1530
1531static void * poll_thread(void * arg)
1532{
1533 int ret = 0;
1534 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1535 const int fd = avsync->fd;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001536 int poll_timeout = 10;
Song Zhaoea5a0412021-01-18 16:40:08 -08001537 struct pollfd pfd = {
1538 /* default blocking capture */
1539 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1540 .fd = avsync->fd,
1541 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001542 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001543
1544 prctl (PR_SET_NAME, "avs_poll");
1545 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001546
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001547 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001548 sflag = SRC_A;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001549 } else if (avsync->type == AV_SYNC_TYPE_VIDEO) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001550 sflag = SRC_V;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001551 poll_timeout = 100;
1552 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001553
Song Zhaoea5a0412021-01-18 16:40:08 -08001554 while (!avsync->quit_poll) {
1555 for (;;) {
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001556 ret = poll(&pfd, 1, poll_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001557 if (ret > 0)
1558 break;
1559 if (avsync->quit_poll)
1560 goto exit;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001561 if (errno == EINTR) {
1562 log_debug("[%d] poll interrupted", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001563 continue;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001564 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001565 }
1566
1567 /* error handling */
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001568 if (pfd.revents & POLLERR) {
1569 usleep(poll_timeout * 1000);
1570 continue;
1571 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001572
Song Zhaod62bb392021-04-23 12:25:49 -07001573 /* mode change. Non-exclusive wait so all the processes
1574 * shall be woken up
1575 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001576 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001577 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001578 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001579
Song Zhao9fef59c2022-08-17 12:43:10 -07001580 msync_session_get_stat(fd, true, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001581 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001582
1583 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001584 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001585 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001586 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001587 usleep(10000);
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001588 } else {
1589 log_debug("[%d] unexpected revents %x", avsync->session_id, pfd.revents);
1590 usleep(poll_timeout * 1000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001591 }
1592 }
1593exit:
1594 log_info("[%d]quit", avsync->session_id);
1595 return NULL;
1596}
1597
Song Zhao623e2f12021-09-03 15:54:04 -07001598#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1599/* return ppm between demod and PCR clock */
1600int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1601{
1602 int fd = -1, ppm = 0, nread;
1603 char buf[128];
1604 uint32_t reg_v, lock;
1605 float val;
1606
1607 fd = open(DEMOD_NODE, O_RDWR);
1608 if (fd < 0) {
1609 log_warn("node not found %s", DEMOD_NODE);
1610 /* do not retry */
1611 avsync->ppm_adjusted = true;
1612 return 0;
1613 }
1614 snprintf(buf, sizeof(buf), "%d", 5);
1615 write(fd, buf, 2);
1616
1617 lseek(fd, 0, SEEK_SET);
1618
hanghang.luo02efd312022-08-26 09:49:53 +08001619 nread = read(fd, buf, sizeof(buf)-1);
Song Zhao623e2f12021-09-03 15:54:04 -07001620 if (nread <= 0) {
1621 log_error("read error");
1622 goto err;
1623 }
1624 buf[nread] = 0;
1625 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1626 log_error("wrong format %s", buf);
1627 goto err;
1628 }
1629 if (lock != 0x1f) {
1630 log_info("demod not locked");
1631 goto err;
1632 }
1633 if (reg_v > ((2 << 20) - 1))
1634 reg_v -= (2 << 21);
1635 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1636 ppm = val;
1637 log_info("ppm from SFO %d", ppm);
1638 avsync->ppm_adjusted = true;
1639
1640err:
1641 if (fd >= 0)
1642 close(fd);
1643 return ppm;
1644}
1645
Song Zhaod62bb392021-04-23 12:25:49 -07001646int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001647{
1648 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001649 struct pcr_info pcr;
1650 enum pcr_monitor_status status;
1651 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001652 if (!avsync)
1653 return -1;
1654
1655 if (avsync->type != AV_SYNC_TYPE_PCR)
1656 return -2;
1657
Song Zhao623e2f12021-09-03 15:54:04 -07001658 /* initial estimation from Demod SFO HW */
1659 if (!avsync->ppm_adjusted) {
1660 ppm = dmod_get_sfo_dev(avsync);
1661 if (ppm != 0) {
1662 /* ppm > 0 means board clock is faster */
1663 msync_session_set_clock_dev(avsync->fd, -ppm);
1664 }
1665 }
wei.dubcc2ed22021-05-19 07:16:10 -04001666 pcr.monoclk = mono_clock / 1000;
1667 pcr.pts = (long long) pts * 1000 / 90;
1668 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1669
1670 status = pcr_monitor_get_status(avsync->pcr_monitor);
1671
1672 if (status >= DEVIATION_READY) {
1673 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1674 if (avsync->ppm != ppm) {
1675 avsync->ppm = ppm;
1676 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1677 if (msync_session_set_clock_dev(avsync->fd, ppm))
1678 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001679 else
1680 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001681 }
1682 }
1683
Song Zhaod62bb392021-04-23 12:25:49 -07001684 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001685}
1686
Song Zhaod62bb392021-04-23 12:25:49 -07001687int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001688{
1689 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1690
1691 if (!avsync)
1692 return -1;
1693
Song Zhaod62bb392021-04-23 12:25:49 -07001694 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001695}
1696
1697int av_sync_set_session_name(void *sync, const char *name)
1698{
1699 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1700
1701 if (!avsync)
1702 return -1;
1703
1704 return msync_session_set_name(avsync->fd, name);
1705}
yongchun.li107a6162021-05-05 02:38:57 -07001706
1707int av_sync_set_audio_switch(void *sync, bool start)
1708{
1709 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1710 bool v_active, a_active, v_timeout;
1711
1712 if (!avsync)
1713 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001714 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001715 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001716 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001717 log_error("[%d] can not get session state",
1718 avsync->session_id);
1719 return -1;
1720 }
1721 if (!v_active || !a_active) {
1722 log_error("[%d] no apply if not AV both active v %d a %d",
1723 avsync->session_id, v_active, a_active);
1724 return -1;
1725 }
1726 if (msync_session_set_audio_switch(avsync->fd, start)) {
1727 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1728 return -1;
1729 }
1730 avsync->in_audio_switch = start;
1731 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1732 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1733 return 0;
1734}
1735
1736int av_sync_get_audio_switch(void *sync, bool *start)
1737{
1738 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1739
1740 if (!avsync)
1741 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001742 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001743 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001744 log_error("[%d] can not audio seamless switch state",
1745 avsync->session_id);
1746 return -1;
1747 }
1748 if (start) *start = avsync->in_audio_switch;
1749 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001750}
Song Zhao8039f562021-05-18 18:11:25 -07001751
Song Zhao623e2f12021-09-03 15:54:04 -07001752enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001753{
1754 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1755
wei.dubcc2ed22021-05-19 07:16:10 -04001756 if (!avsync || !ppm)
1757 return CLK_RECOVERY_ERR;
1758 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001759 return CLK_RECOVERY_NOT_RUNNING;
1760
wei.dubcc2ed22021-05-19 07:16:10 -04001761 if (msync_session_get_clock_dev(avsync->fd, ppm))
1762 return CLK_RECOVERY_ERR;
1763
1764 if (*ppm == 0)
1765 return CLK_RECOVERY_ONGOING;
1766 else
1767 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001768}
Song Zhao95bd0922021-09-21 14:07:46 -07001769
1770static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1771{
1772 int ret;
1773
1774 if (!avsync->frame_q) {
1775 avsync->frame_q = create_q(MAX_FRAME_NUM);
1776 if (!avsync->frame_q) {
1777 log_error("[%d]create queue fail", avsync->session_id);
1778
1779 return -1;
1780 }
1781 }
1782
1783 ret = queue_item(avsync->frame_q, frame);
1784 if (ret)
hanghang.luo02efd312022-08-26 09:49:53 +08001785 log_error("queue fail:%d", ret);
Song Zhao95bd0922021-09-21 14:07:46 -07001786 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1787 return ret;
1788}
1789
1790int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1791{
1792 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1793
1794 if (!avsync)
1795 return -1;
1796 avsync->msys = msys;
1797 return 0;
1798}
1799
1800static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1801{
1802 struct vframe *frame = NULL, *enter_last_frame = NULL;
1803 uint64_t systime;
1804 int toggle_cnt = 0;
1805
1806 enter_last_frame = avsync->last_frame;
1807 systime = avsync->msys;
1808 log_debug("[%d]sys %llu", avsync->session_id, systime);
1809 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1810 if (systime >= frame->mts) {
1811 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1812 toggle_cnt++;
1813
1814 if (avsync->last_frame)
1815 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1816
1817 dqueue_item(avsync->frame_q, (void **)&frame);
1818 if (avsync->last_frame) {
1819 /* free frame that are not for display */
1820 if (toggle_cnt > 1) {
1821 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1822 avsync->last_frame->mts, frame->mts, systime);
1823 avsync->last_frame->free(avsync->last_frame);
1824 }
1825 } else {
1826 avsync->first_frame_toggled = true;
1827 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1828 }
1829 avsync->last_frame = frame;
1830 } else
1831 break;
1832 }
1833
1834 if (avsync->last_frame) {
1835 if (enter_last_frame != avsync->last_frame)
hanghang.luo02efd312022-08-26 09:49:53 +08001836 log_debug("[%d]pop %lu", avsync->session_id, avsync->last_frame->pts);
1837 log_trace("[%d]pop=%llu, system=%llu, diff %llu(ms), QNum=%d", avsync->session_id,
Song Zhao95bd0922021-09-21 14:07:46 -07001838 avsync->last_frame->mts,
1839 systime, (systime - avsync->last_frame->mts) / 1000000,
1840 queue_size(avsync->frame_q));
1841 } else
1842 if (enter_last_frame != avsync->last_frame)
1843 log_debug("[%d]pop (nil)", avsync->session_id);
1844
1845 if (avsync->last_frame)
1846 avsync->last_frame->hold_period++;
1847 return avsync->last_frame;
1848}
Song Zhao6183ca92022-07-29 09:57:03 -07001849
1850int avs_sync_stop_audio(void *sync)
1851{
1852 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1853
1854 if (!avsync)
1855 return -1;
1856
1857 return msync_session_stop_audio(avsync->fd);
1858}