blob: 4235bd8cef2b57fee2cf7dbe89a02edee69f7e1b [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 Zhao4bd18762022-09-30 16:39:52 -0700165#define A_ADJ_THREDHOLD_MB (900 * 3) //30ms
Song Zhao52f55192021-05-06 10:52:21 -0700166#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800167#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhao76005282022-03-08 16:49:41 -0800168#define LIVE_MODE(m) ((m) == AV_SYNC_MODE_PCR_MASTER || (m) == AV_SYNC_MODE_IPTV)
Song Zhao7e24b182022-04-01 08:46:40 -0700169#define V_DISC_MODE(mode) (LIVE_MODE(mode) || (mode) == AV_SYNC_MODE_VMASTER)
Song Zhaod62bb392021-04-23 12:25:49 -0700170
Song Zhao065800e2021-05-26 15:56:06 -0700171#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
Song Zhaod62bb392021-04-23 12:25:49 -0700172#define OUTLIER_MAX_CNT 8
Song Zhaoa2985cb2021-06-24 12:01:47 -0700173#define VALID_TS(x) ((x) != -1)
yongchun.li428390d2022-02-17 17:15:40 -0800174#define UNDERFLOW_CHECK_THRESH_MS (100)
Song Zhaoc03ba122020-12-23 21:54:02 -0800175
yongchun.li0ee6e372021-08-20 04:26:04 -0700176static uint64_t time_diff (struct timespec *b, struct timespec *a);
Song Zhaoc03ba122020-12-23 21:54:02 -0800177static bool frame_expire(struct av_sync_session* avsync,
178 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800179 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800180 struct vframe * frame,
181 struct vframe * next_frame,
182 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700183static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800184 int cur_period,
185 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800186static void * poll_thread(void * arg);
187static void trigger_audio_start_cb(struct av_sync_session *avsync,
188 avs_ascb_reason reason);
Song Zhao95bd0922021-09-21 14:07:46 -0700189static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync);
190static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame);
fei.deng55389b62022-08-18 23:46:50 +0800191
Song Zhao2f6744b2021-11-03 21:23:50 -0700192pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER;
Song Zhaoc03ba122020-12-23 21:54:02 -0800193
Song Zhaoea5a0412021-01-18 16:40:08 -0800194int av_sync_open_session(int *session_id)
195{
Song Zhao2f6744b2021-11-03 21:23:50 -0700196 int fd = -1;
Song Zhaoea5a0412021-01-18 16:40:08 -0800197 int id, rc;
198
Song Zhao2f6744b2021-11-03 21:23:50 -0700199 pthread_mutex_lock(&glock);
200 fd = msync_create_session();
Song Zhaoea5a0412021-01-18 16:40:08 -0800201 if (fd < 0) {
202 log_error("fail");
Song Zhao2f6744b2021-11-03 21:23:50 -0700203 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800204 }
205 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
206 if (rc) {
207 log_error("new session errno:%d", errno);
Song Zhao2f6744b2021-11-03 21:23:50 -0700208 msync_destory_session(fd);
209 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800210 }
211 *session_id = id;
Song Zhao2f6744b2021-11-03 21:23:50 -0700212 log_debug("new avsession id %d fd %d", id, fd);
213exit:
214 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800215 return fd;
216}
217
218void av_sync_close_session(int session)
219{
Song Zhao2f6744b2021-11-03 21:23:50 -0700220 log_debug("session closed fd %d", session);
221 pthread_mutex_lock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800222 msync_destory_session(session);
Song Zhao2f6744b2021-11-03 21:23:50 -0700223 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800224}
225
226static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800227 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800228 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800229 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800230 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800231{
232 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800233 char dev_name[20];
Song Zhao2f6744b2021-11-03 21:23:50 -0700234 int retry = 10;
Song Zhaoc03ba122020-12-23 21:54:02 -0800235
fei.deng55389b62022-08-18 23:46:50 +0800236 /* debug log level */
237 {
238 const char *env= getenv( "AML_AVSYNC_DEBUG_LEVEL");
239 if ( env ) {
240 log_set_level(atoi(env));
241 }
242 }
243
Song Zhao95bd0922021-09-21 14:07:46 -0700244 log_info("[%d] mode %d type %d", session_id, mode, type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800245 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
246 if (!avsync) {
247 log_error("OOM");
248 return NULL;
249 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800250
Song Zhao95bd0922021-09-21 14:07:46 -0700251 if (type == AV_SYNC_TYPE_VIDEO &&
252 mode == AV_SYNC_MODE_VIDEO_MONO) {
253 if (session_id < AV_SYNC_SESSION_V_MONO) {
254 log_error("wrong session id %d", session_id);
255 goto err;
256 }
257 avsync->type = type;
258 avsync->mode = mode;
259 avsync->fd = -1;
260 avsync->session_id = session_id;
261 log_info("[%d]init", avsync->session_id);
262 return avsync;
263 }
264
Song Zhaoea5a0412021-01-18 16:40:08 -0800265 if (type == AV_SYNC_TYPE_VIDEO) {
266 avsync->pattern_detector = create_pattern_detector();
267 if (!avsync->pattern_detector) {
268 log_error("pd create fail");
269 goto err;
270 }
271
272 if (!start_thres)
273 avsync->start_thres = DEFAULT_START_THRESHOLD;
274 else {
275 if (start_thres > 5) {
276 log_error("start_thres too big: %d", start_thres);
277 goto err2;
278 }
279 avsync->start_thres = start_thres;
280 }
281 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800282 avsync->phase_adjusted = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800283 avsync->first_frame_toggled = false;
Song Zhaofd007632022-09-30 16:21:30 -0700284
285 avsync->frame_q = create_q(MAX_FRAME_NUM);
286 if (!avsync->frame_q) {
287 log_error("[%d]create queue fail", avsync->session_id);
288 goto err2;
289 }
Song Zhaofd007632022-09-30 16:21:30 -0700290 {
291 int ret;
292
293 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
294 if (ret) {
295 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
296 goto err2;
297 }
298 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800299 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800300
301 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800302 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800303 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800304 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800305 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800306 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800307 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800308 avsync->speed = 1.0f;
309 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhao409739b2021-05-12 22:21:40 -0700310 avsync->vsync_interval = -1;
311 avsync->last_disc_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700312 avsync->last_log_syst = -1;
313 avsync->last_pts = -1;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700314 avsync->last_q_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700315 avsync->last_wall = -1;
316 avsync->fps_interval = -1;
317 avsync->last_r_syst = -1;
bo.xiao5821fc72021-07-11 22:47:00 -0400318 avsync->timeout = -1;
319
Song Zhaof46932e2021-05-21 01:51:45 -0700320 if (msync_session_get_disc_thres(session_id,
321 &avsync->disc_thres_min, &avsync->disc_thres_max)) {
hanghang.luo02efd312022-08-26 09:49:53 +0800322 log_error("dev_name:%s; errno:%d; fail to get disc thres", dev_name, errno);
Song Zhaof46932e2021-05-21 01:51:45 -0700323 avsync->disc_thres_min = AV_DISC_THRES_MIN;
324 avsync->disc_thres_max = AV_DISC_THRES_MAX;
325 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800326
327 pthread_mutex_init(&avsync->lock, NULL);
Song Zhao9c09f772022-01-07 14:26:50 -0800328 log_info("[%d] start_thres %d disc_thres %u/%u", session_id,
Song Zhao95bd0922021-09-21 14:07:46 -0700329 start_thres, avsync->disc_thres_min, avsync->disc_thres_max);
Song Zhaoea5a0412021-01-18 16:40:08 -0800330
331 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
Song Zhao2f6744b2021-11-03 21:23:50 -0700332 while (retry) {
333 /* wait for sysfs to update */
334 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
335 if (avsync->fd > 0)
336 break;
337
338 retry--;
339 if (!retry) {
340 log_error("open %s errno %d", dev_name, errno);
341 goto err2;
342 }
343 usleep(20000);
Song Zhaoea5a0412021-01-18 16:40:08 -0800344 }
345
wei.dubcc2ed22021-05-19 07:16:10 -0400346 if (avsync->type == AV_SYNC_TYPE_PCR) {
347 if (pcr_monitor_init(&avsync->pcr_monitor)) {
348 log_error("pcr monitor init");
Song Zhao9cd27a52021-07-26 15:27:38 +0000349 goto err3;
wei.dubcc2ed22021-05-19 07:16:10 -0400350 }
351 }
352
Song Zhaoea5a0412021-01-18 16:40:08 -0800353 if (!attach) {
354 msync_session_set_mode(avsync->fd, mode);
355 avsync->mode = mode;
Song Zhao7e24b182022-04-01 08:46:40 -0700356 if (avsync->mode == AV_SYNC_MODE_VMASTER)
357 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -0800358 } else {
359 avsync->attached = true;
360 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
361 log_error("get mode");
Song Zhao9cd27a52021-07-26 15:27:38 +0000362 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800363 }
364 avsync->backup_mode = avsync->mode;
bo.xiao5821fc72021-07-11 22:47:00 -0400365 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800366 log_error("get policy");
Song Zhao9cd27a52021-07-26 15:27:38 +0000367 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800368 }
Song Zhao9fef59c2022-08-17 12:43:10 -0700369 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700370 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -0700371 log_error("get state");
Song Zhao9cd27a52021-07-26 15:27:38 +0000372 goto err4;
yongchun.li107a6162021-05-05 02:38:57 -0700373 }
374 if (avsync->in_audio_switch) {
375 log_info("audio_switch_state reseted the audio");
376 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
377 }
378
Song Zhaoea5a0412021-01-18 16:40:08 -0800379 log_info("[%d]retrieve sync mode %d policy %d",
380 session_id, avsync->mode, avsync->start_policy);
381 }
382
Song Zhaoc03ba122020-12-23 21:54:02 -0800383 return avsync;
Song Zhao9cd27a52021-07-26 15:27:38 +0000384err4:
wei.dubcc2ed22021-05-19 07:16:10 -0400385 if (avsync->pcr_monitor)
386 pcr_monitor_destroy(avsync->pcr_monitor);
Song Zhao9cd27a52021-07-26 15:27:38 +0000387err3:
Song Zhaofd007632022-09-30 16:21:30 -0700388 if (avsync->fd)
389 close(avsync->fd);
Song Zhaoea5a0412021-01-18 16:40:08 -0800390err2:
Song Zhaofd007632022-09-30 16:21:30 -0700391 avsync->quit_poll = true;
392 if (avsync->poll_thread) {
393 pthread_join(avsync->poll_thread, NULL);
394 avsync->poll_thread = 0;
395 }
396 if (avsync->frame_q)
397 destroy_q(avsync->frame_q);
398 if (avsync->pattern_detector)
399 destroy_pattern_detector(avsync->pattern_detector);
Song Zhaoea5a0412021-01-18 16:40:08 -0800400err:
401 free(avsync);
402 return NULL;
403}
404
405void* av_sync_create(int session_id,
406 enum sync_mode mode,
407 enum sync_type type,
408 int start_thres)
409{
410 return create_internal(session_id, mode,
411 type, start_thres, false);
412}
413
414void* av_sync_attach(int session_id, enum sync_type type)
415{
Song Zhao95bd0922021-09-21 14:07:46 -0700416 if (type == AV_SYNC_TYPE_VIDEO)
417 return NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800418 return create_internal(session_id, AV_SYNC_MODE_MAX,
419 type, 0, true);
420}
421
422int av_sync_video_config(void *sync, struct video_config* config)
423{
424 struct av_sync_session *avsync = (struct av_sync_session *)sync;
425
426 if (!avsync || !config)
427 return -1;
428
429 if (config->delay != 1 && config->delay != 2) {
430 log_error("invalid delay: %d\n", config->delay);
431 return -1;
432 }
433
434 avsync->delay = config->delay;
Song Zhao6dce2672022-01-13 11:32:44 -0800435 avsync->extra_delay = config->extra_delay * 90;
Song Zhaoea5a0412021-01-18 16:40:08 -0800436
Song Zhao6dce2672022-01-13 11:32:44 -0800437 log_info("[%d] vsync delay: %d extra_delay: %d ms",
438 avsync->session_id, config->delay, config->extra_delay);
Song Zhaoea5a0412021-01-18 16:40:08 -0800439 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800440}
441
442static int internal_stop(struct av_sync_session *avsync)
443{
444 int ret = 0;
445 struct vframe *frame;
446
447 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800448 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
449 frame->free(frame);
450 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800451 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800452 pthread_mutex_unlock(&avsync->lock);
453 return ret;
454}
455
456/* destroy and detach from kernel session */
457void av_sync_destroy(void *sync)
458{
459 struct av_sync_session *avsync = (struct av_sync_session *)sync;
460
461 if (!avsync)
462 return;
463
Song Zhao95bd0922021-09-21 14:07:46 -0700464 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
465 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
466 log_info("[%d]done", avsync->session_id);
467 internal_stop(avsync);
468 destroy_q(avsync->frame_q);
469 free(avsync);
470 return;
471 }
Song Zhaob5458b32021-11-12 15:58:47 -0800472 log_info("[%d]begin type %d", avsync->session_id, avsync->type);
Song Zhao6be9ac22022-09-30 16:44:50 -0700473 if (avsync->type == AV_SYNC_TYPE_VIDEO)
474 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800475
Song Zhao6be9ac22022-09-30 16:44:50 -0700476 avsync->quit_poll = true;
477 if (avsync->poll_thread) {
478 pthread_join(avsync->poll_thread, NULL);
479 avsync->poll_thread = 0;
Song Zhaoaf368d52021-02-17 17:53:45 -0800480 }
Song Zhao6be9ac22022-09-30 16:44:50 -0700481 if (avsync->type == AV_SYNC_TYPE_AUDIO)
482 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoc03ba122020-12-23 21:54:02 -0800483
Song Zhaoea5a0412021-01-18 16:40:08 -0800484 if (avsync->session_started) {
485 if (avsync->type == AV_SYNC_TYPE_VIDEO)
486 msync_session_set_video_stop(avsync->fd);
487 else
488 msync_session_set_audio_stop(avsync->fd);
489 }
wei.dubcc2ed22021-05-19 07:16:10 -0400490
491 if(avsync->pcr_monitor)
492 pcr_monitor_destroy(avsync->pcr_monitor);
493
Song Zhaoea5a0412021-01-18 16:40:08 -0800494 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800495 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800496 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
497 destroy_q(avsync->frame_q);
498 destroy_pattern_detector(avsync->pattern_detector);
499 }
Song Zhaob5458b32021-11-12 15:58:47 -0800500 log_info("[%d]done type %d", avsync->session_id, avsync->type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800501 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800502}
503
bo.xiao5821fc72021-07-11 22:47:00 -0400504int avs_sync_set_start_policy(void *sync, struct start_policy* st_policy)
Song Zhaoea5a0412021-01-18 16:40:08 -0800505{
506 struct av_sync_session *avsync = (struct av_sync_session *)sync;
507
508 if (!avsync || !avsync->fd)
509 return -1;
510
Song Zhao47961d72022-08-29 14:04:44 -0700511 log_info("[%d]policy %u --> %u, timeout %d --> %d", avsync->session_id,
512 avsync->start_policy, st_policy->policy, avsync->timeout, st_policy->timeout);
Song Zhao76005282022-03-08 16:49:41 -0800513 if (LIVE_MODE(avsync->mode) &&
514 st_policy->policy != AV_SYNC_START_ASAP) {
515 log_error("policy %d not supported in live mode", st_policy->policy);
516 return -1;
517 }
518
bo.xiao5821fc72021-07-11 22:47:00 -0400519 avsync->start_policy = st_policy->policy;
520 avsync->timeout = st_policy->timeout;
Song Zhao76005282022-03-08 16:49:41 -0800521
Song Zhaoea5a0412021-01-18 16:40:08 -0800522 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400523 if (st_policy->policy != AV_SYNC_START_NONE &&
524 st_policy->policy != AV_SYNC_START_V_PEEK)
525 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800526
527 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800528}
529
530int av_sync_pause(void *sync, bool pause)
531{
532 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700533 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800534 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800535
Song Zhaob5458b32021-11-12 15:58:47 -0800536 if (!avsync) {
537 log_error("invalid handle");
Song Zhaoc03ba122020-12-23 21:54:02 -0800538 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800539 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800540
fei.deng55389b62022-08-18 23:46:50 +0800541 if (avsync->type == AV_SYNC_TYPE_VIDEO && avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
542 log_warn("ignore pause in video mono mode");
543 return -1;
544 }
545
Song Zhaob5458b32021-11-12 15:58:47 -0800546 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
547 log_warn("ignore pause in pcr master mode");
Song Zhaoea5a0412021-01-18 16:40:08 -0800548 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800549 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800550
Song Zhao9fef59c2022-08-17 12:43:10 -0700551 rc = msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -0700552 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700553 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700554
yongchun.li5f52fb02021-06-04 18:13:05 -0700555 /* ignore only when video try to pause when audio is acive, on which
556 the control of the STC will be relays.
557 When resume,it can do always as it is possible that video just
558 paused earlier without audio yet,then audio added later before resume.
559 We shall not igore that otherwise it could cause video freeze. */
560 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
561 avsync->type == AV_SYNC_TYPE_VIDEO &&
562 a_active &&
563 !avsync->in_audio_switch) {
564 if (!pause) {
565 log_info("[%d] clear video pause when audio active",
566 avsync->session_id);
567 avsync->paused = pause;
568 } else {
569 log_info("[%d] ignore the pause from video when audio active",
570 avsync->session_id);
571 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800572 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700573 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800574
yongchun.li107a6162021-05-05 02:38:57 -0700575 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
576 log_info("[%d] ignore the pause from audio", avsync->session_id);
577 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
578 return 0;
579 }
580
Song Zhaoea5a0412021-01-18 16:40:08 -0800581 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800582 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800583 log_info("[%d]paused:%d type:%d rc %d",
584 avsync->session_id, pause, avsync->type, rc);
yongchun.li428390d2022-02-17 17:15:40 -0800585 if (!avsync->paused && avsync->first_frame_toggled) {
586 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
587 log_info("[%d] resume update new frame time", avsync->session_id);
588 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800589 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800590}
591
592int av_sync_push_frame(void *sync , struct vframe *frame)
593{
594 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700595 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800596 struct av_sync_session *avsync = (struct av_sync_session *)sync;
597
598 if (!avsync)
599 return -1;
600
Song Zhao95bd0922021-09-21 14:07:46 -0700601 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
fei.deng55389b62022-08-18 23:46:50 +0800602 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
Song Zhao95bd0922021-09-21 14:07:46 -0700603 return video_mono_push_frame(avsync, frame);
fei.deng55389b62022-08-18 23:46:50 +0800604 }
Song Zhao95bd0922021-09-21 14:07:46 -0700605
Song Zhaofd007632022-09-30 16:21:30 -0700606 if (avsync->state == AV_SYNC_STAT_INIT && !queue_size(avsync->frame_q)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800607 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400608 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800609 log_error("[%d]get policy", avsync->session_id);
610 return -1;
611 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800612 }
613
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700614 if (avsync->last_q_pts != -1) {
Song Zhao7e24b182022-04-01 08:46:40 -0700615 if (frame->pts != -1 && avsync->mode == AV_SYNC_MODE_VMASTER) {
616 /* Sometimes app will fake PTS for trickplay, video PTS gap
617 * is really big depending on the speed. Have to adjust the
618 * threshold dynamically.
619 */
620 int gap = (int)(frame->pts - avsync->last_q_pts);
621 if (gap > avsync->disc_thres_min) {
622 avsync->disc_thres_min = gap * 6;
623 avsync->disc_thres_max = gap * 20;
624 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
625 msync_session_set_disc_thres(avsync->session_id,
626 avsync->disc_thres_min, avsync->disc_thres_max);
627 log_info("[%d] update disc_thres to %d/%d",avsync->session_id,
628 avsync->disc_thres_min, avsync->disc_thres_max);
629 }
630 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700631 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
632 /* TODO: wrong, should remove from back of queue */
Song Zhaoc03ba122020-12-23 21:54:02 -0800633 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700634 if (prev) {
635 prev->free(prev);
636 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
637 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700638 } else if (avsync->fps_cnt < 100) {
639 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700640
641 if (interval > 0 && interval <= 4500) {
642 if (avsync->fps_interval_acc == -1) {
643 avsync->fps_interval_acc = interval;
644 avsync->fps_cnt = 1;
645 } else {
646 avsync->fps_interval_acc += interval;
647 avsync->fps_cnt++;
648 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
649 if (avsync->fps_cnt == 100)
650 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
651 }
652 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800653 }
654 }
655
Song Zhao065800e2021-05-26 15:56:06 -0700656 if (frame->duration == -1)
657 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800658 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700659 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800660 ret = queue_item(avsync->frame_q, frame);
661 if (avsync->state == AV_SYNC_STAT_INIT &&
662 queue_size(avsync->frame_q) >= avsync->start_thres) {
663 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaofd007632022-09-30 16:21:30 -0700664 log_debug("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800665 }
666
667 if (ret)
Song Zhaoe1b65602022-01-06 08:03:46 -0800668 log_error("queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400669 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800670 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800671}
672
673struct vframe *av_sync_pop_frame(void *sync)
674{
Song Zhaoea5a0412021-01-18 16:40:08 -0800675 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800676 struct av_sync_session *avsync = (struct av_sync_session *)sync;
677 int toggle_cnt = 0;
hanghang.luo02efd312022-08-26 09:49:53 +0800678 uint32_t systime = 0;
Song Zhao468fd652021-01-15 22:13:04 -0800679 bool pause_pts_reached = false;
hanghang.luo02efd312022-08-26 09:49:53 +0800680 uint32_t interval = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800681
Song Zhao95bd0922021-09-21 14:07:46 -0700682 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
683 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
684 return video_mono_pop_frame(avsync);
685
Song Zhaoc03ba122020-12-23 21:54:02 -0800686 pthread_mutex_lock(&avsync->lock);
687 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhao2f6744b2021-11-03 21:23:50 -0700688 log_debug("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800689 goto exit;
690 }
691
Song Zhaoea5a0412021-01-18 16:40:08 -0800692 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700693 uint32_t pts;
694
Song Zhaoc03ba122020-12-23 21:54:02 -0800695 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800696 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800697 goto exit;
698 }
Song Zhao35a82df2021-04-15 10:58:49 -0700699 msync_session_get_wall(avsync->fd, &systime, &interval);
700 pts = frame->pts - avsync->delay * interval;
701 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800702 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700703 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800704 }
705
Song Zhaoea5a0412021-01-18 16:40:08 -0800706 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700707 !avsync->first_frame_toggled &&
708 !msync_clock_started(avsync->fd)) {
709 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800710 log_trace("[%d]clock not started", avsync->session_id);
711 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800712 }
713
Song Zhaoea5a0412021-01-18 16:40:08 -0800714 enter_last_frame = avsync->last_frame;
715 msync_session_get_wall(avsync->fd, &systime, &interval);
716
717 /* handle refresh rate change */
718 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
719 avsync->vsync_interval != interval) {
720 log_info("[%d]vsync interval update %d --> %u",
721 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700722 if (avsync->fps_interval == -1)
723 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800724 avsync->vsync_interval = interval;
725 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800726 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700727 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800728 reset_pattern(avsync->pattern_detector);
729 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800730 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
731 struct vframe *next_frame = NULL;
732
733 peek_item(avsync->frame_q, (void **)&next_frame, 1);
734 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700735 log_debug("[%d]cur_f %u next_f %u size %d",
736 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800737 if (frame_expire(avsync, systime, interval,
738 frame, next_frame, toggle_cnt)) {
739 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800740 toggle_cnt++;
741
Song Zhao35a82df2021-04-15 10:58:49 -0700742 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800743 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700744 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700745 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700746 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
747 if (next_frame)
748 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
749 }
Song Zhao35a82df2021-04-15 10:58:49 -0700750
Song Zhaoc03ba122020-12-23 21:54:02 -0800751 if (avsync->last_frame)
752 avsync->last_holding_peroid = avsync->last_frame->hold_period;
753
754 dqueue_item(avsync->frame_q, (void **)&frame);
755 if (avsync->last_frame) {
756 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800757 if (toggle_cnt > 1) {
Song Zhaofd007632022-09-30 16:21:30 -0700758 log_info("[%d]free %u cur %u system/d %u/%u queue size %d", avsync->session_id,
759 avsync->last_frame->pts, frame->pts,
760 systime, systime - avsync->last_poptime,
761 queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800762 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800763 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800764 } else {
765 avsync->first_frame_toggled = true;
Song Zhaofd007632022-09-30 16:21:30 -0700766 log_info("[%d]first frame %u queue size %d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800767 }
768 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800769 avsync->last_pts = frame->pts;
yongchun.li428390d2022-02-17 17:15:40 -0800770 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
Song Zhaoc03ba122020-12-23 21:54:02 -0800771 } else
772 break;
773 }
774
775 /* pause pts */
776 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800777 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800778 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800779 else
Song Zhao468fd652021-01-15 22:13:04 -0800780 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
781 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
782 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
783 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
784 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800785
Song Zhao468fd652021-01-15 22:13:04 -0800786 if (pause_pts_reached) {
Song Zhao468fd652021-01-15 22:13:04 -0800787 /* stay in paused until av_sync_pause(false) */
Song Zhaoa1742282022-09-30 16:17:26 -0700788 uint32_t local_pts = avsync->pause_pts;
Song Zhao468fd652021-01-15 22:13:04 -0800789 avsync->paused = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800790 log_info ("[%d]reach pause pts: %u",
Song Zhaob5458b32021-11-12 15:58:47 -0800791 avsync->session_id, avsync->pause_pts);
Song Zhaoad7c8232021-12-14 11:46:48 -0800792 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoa1742282022-09-30 16:17:26 -0700793 if (avsync->pause_pts_cb)
794 avsync->pause_pts_cb(local_pts,
795 avsync->pause_cb_priv);
796 log_info ("[%d] reach pause pts: %u handle done",
797 avsync->session_id, local_pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800798 }
799
800exit:
801 pthread_mutex_unlock(&avsync->lock);
yongchun.li428390d2022-02-17 17:15:40 -0800802
803 /* underflow check */
804 if (avsync->session_started && avsync->first_frame_toggled &&
805 (avsync->paused == false) && (avsync->state >= AV_SYNC_STAT_RUNNING) &&
806 avsync->underflow_cb && peek_item(avsync->frame_q, (void **)&frame, 0))
807 {/* empty queue in normal play */
808 struct timespec now;
809 int diff_ms;
810 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
811 diff_ms = time_diff(&now, &avsync->frame_last_update_time)/1000;
812 if(diff_ms >= (avsync->underflow_cfg.time_thresh
813 + avsync->vsync_interval*avsync->last_holding_peroid/90)) {
814 log_info ("[%d]underflow detected: %u", avsync->session_id, avsync->last_pts);
815 avsync->underflow_cb (avsync->last_pts,
816 avsync->underflow_cb_priv);
817 /* update time to control the underflow check call backs */
818 avsync->frame_last_update_time = now;
819 }
820 }
821
Song Zhaoc03ba122020-12-23 21:54:02 -0800822 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800823 if (enter_last_frame != avsync->last_frame)
824 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
bo.xiao1f94b352021-08-02 03:53:47 -0400825 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 -0700826 /* don't update vpts for out_lier */
827 if (avsync->last_frame->duration != -1)
828 msync_session_update_vpts(avsync->fd, systime,
829 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800830 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800831 if (enter_last_frame != avsync->last_frame)
832 log_debug("[%d]pop (nil)", avsync->session_id);
833
Song Zhao35a82df2021-04-15 10:58:49 -0700834 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800835 if (avsync->last_frame)
836 avsync->last_frame->hold_period++;
837 return avsync->last_frame;
838}
839
Song Zhaoc03ba122020-12-23 21:54:02 -0800840static inline uint32_t abs_diff(uint32_t a, uint32_t b)
841{
Song Zhaoea5a0412021-01-18 16:40:08 -0800842 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800843}
844
yongchun.li0ee6e372021-08-20 04:26:04 -0700845static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800846{
hanghang.luo02efd312022-08-26 09:49:53 +0800847 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 -0800848}
849
Song Zhaoc03ba122020-12-23 21:54:02 -0800850static bool frame_expire(struct av_sync_session* avsync,
851 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800852 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800853 struct vframe * frame,
854 struct vframe * next_frame,
855 int toggle_cnt)
856{
Song Zhao6dce2672022-01-13 11:32:44 -0800857 uint32_t fpts = frame->pts + avsync->extra_delay;
858 uint32_t nfpts = -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800859 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800860 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800861
862 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
863 return false;
864
865 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
866 return true;
867
Song Zhaoad7c8232021-12-14 11:46:48 -0800868 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS &&
869 avsync->pause_pts == frame->pts)
870 return true;
871
Song Zhao08fa16b2021-12-08 14:30:17 -0800872 if (systime == AV_SYNC_INVALID_PTS &&
873 avsync->mode == AV_SYNC_MODE_AMASTER)
874 return false;
875
Song Zhao6dce2672022-01-13 11:32:44 -0800876 if (next_frame)
877 nfpts = next_frame->pts + avsync->extra_delay;
878
Song Zhao7e24b182022-04-01 08:46:40 -0700879 if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
fei.deng63e43e12021-09-23 19:44:01 +0800880 /* We need to ensure that the video outputs smoothly,
881 so output video frame by frame hold_period */
882 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
883 avsync->last_frame &&
884 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
885 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
886 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700887 return true;
888 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700889 }
890
Song Zhaoc03ba122020-12-23 21:54:02 -0800891 if (!fpts) {
892 if (avsync->last_frame) {
893 /* try to accumulate duration as PTS */
894 fpts = avsync->vpts + avsync->last_frame->duration;
895 } else {
896 fpts = avsync->vpts;
897 }
898 }
899 systime += pts_correction;
900
901 /* phase adjustment */
902 if (avsync->phase_set)
903 systime += avsync->phase;
904
yongchun.lia50b1e92021-08-07 01:11:54 +0000905 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800906 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000907 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700908 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800909 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800910 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800911 return false;
912
Song Zhaoa2985cb2021-06-24 12:01:47 -0700913 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
914 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700915 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800916
yongchun.li0ee6e372021-08-20 04:26:04 -0700917 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700918 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800919 avsync->last_pts = fpts;
920 if (time_diff(&now, &avsync->sync_lost_print_time) >=
921 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700922 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800923 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800924 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700925 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800926 } else
927 avsync->sync_lost_cnt++;
928 }
Song Zhaod62bb392021-04-23 12:25:49 -0700929
930 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
931 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700932 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700933 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700934 /* outlier by stream error */
935 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700936 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700937 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
938 log_info("render outlier %u", fpts);
939 return true;
940 }
941 }
942
943 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800944 avsync->state = AV_SYNC_STAT_SYNC_LOST;
945 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800946 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700947 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800948 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700949
Song Zhao7e24b182022-04-01 08:46:40 -0700950 if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700951 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700952 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700953 msync_session_set_video_dis(avsync->fd, fpts);
954 avsync->last_disc_pts = fpts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700955 }
956
957 if ((int)(systime - fpts) > 0) {
958 if ((int)(systime - fpts) < avsync->disc_thres_max) {
959 /* catch up PCR */
Song Zhaof46932e2021-05-21 01:51:45 -0700960 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700961 } else {
962 /* render according to FPS */
963 if (!VALID_TS(avsync->last_r_syst) ||
964 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
965 avsync->last_r_syst = systime;
966 return true;
967 }
968 return false;
969 }
970 } else if (LIVE_MODE(avsync->mode)) {
971 /* hold if the gap is small */
972 if ((int)(fpts - systime) < avsync->disc_thres_max) {
973 return false;
974 } else {
975 /* render according to FPS */
976 if (!VALID_TS(avsync->last_r_syst) ||
977 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
978 avsync->last_r_syst = systime;
979 return true;
980 }
981 return false;
982 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800983 }
984 }
985
Song Zhao52f55192021-05-06 10:52:21 -0700986 /* In some cases, keeping pattern will enlarge the gap */
987 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
988 avsync->first_frame_toggled) {
989 reset_pattern(avsync->pattern_detector);
Song Zhaofd007632022-09-30 16:21:30 -0700990 log_info("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700991 systime, fpts);
992 }
993
Song Zhaoc03ba122020-12-23 21:54:02 -0800994 expire = (int)(systime - fpts) >= 0;
995
996 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -0800997 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800998 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -0800999 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001000 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001001 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001002 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -08001003 }
Song Zhao6dce2672022-01-13 11:32:44 -08001004 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -08001005 && avsync->first_frame_toggled) {
1006 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -08001007 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001008 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -08001009 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001010 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001011 }
1012 }
1013
Song Zhaoa58c3e92021-03-09 18:52:55 -08001014 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -08001015 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -08001016 (avsync->last_frame?avsync->last_frame->hold_period:0),
1017 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -08001018 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -08001019
1020 if (expire) {
1021 avsync->vpts = fpts;
1022 /* phase adjustment */
1023 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +00001024 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -08001025 if ((int)(systime - fpts) >= 0 &&
1026 (int)(fpts + interval - systime) > 0) {
1027 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -08001028 avsync->phase_set = true;
Song Zhaofd007632022-09-30 16:21:30 -07001029 log_debug("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -08001030 }
Song Zhao1561e542022-01-12 10:37:55 -08001031 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -08001032 if ((int)(systime - fpts) >= 0 &&
1033 (int)(fpts + interval - systime) > 0) {
1034 int vsync_pts_delta = (int)(systime - fpts);
1035
1036 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1037 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001038 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001039 log_info("[%d] too aligned adjust phase to %d",
1040 avsync->session_id, (int)avsync->phase);
1041 }
1042 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001043 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001044 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaofd007632022-09-30 16:21:30 -07001045 log_info("[%d]sync setup on frame %u", avsync->session_id, fpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001046 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001047 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001048 }
1049 return expire;
1050}
1051
Song Zhao35a82df2021-04-15 10:58:49 -07001052static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001053{
Song Zhao35a82df2021-04-15 10:58:49 -07001054 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001055 log_trace("[%d]cur_period: %d last_period: %d",
1056 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -07001057 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
1058 ret = true;
1059 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
1060 ret = true;
1061 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
1062 ret = true;
1063 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
1064 ret = true;
1065
1066 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -08001067}
1068
1069int av_sync_set_speed(void *sync, float speed)
1070{
1071 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1072
1073 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001074 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001075 return -1;
1076 }
1077
Song Zhao76005282022-03-08 16:49:41 -08001078 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001079 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001080 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001081 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001082
Song Zhaoea5a0412021-01-18 16:40:08 -08001083 avsync->speed = speed;
1084
1085 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
1086 if (speed == 1.0) {
1087 avsync->mode = avsync->backup_mode;
1088 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1089 } else {
1090 avsync->backup_mode = avsync->mode;
1091 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1092 log_info("[%d]audio to freerun mode", avsync->session_id);
1093 }
1094 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001095
Song Zhaoea5a0412021-01-18 16:40:08 -08001096 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1097 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001098}
1099
1100int av_sync_change_mode(void *sync, enum sync_mode mode)
1101{
1102 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1103
1104 if (!avsync)
1105 return -1;
1106
Song Zhaoea5a0412021-01-18 16:40:08 -08001107 if (msync_session_set_mode(avsync->fd, mode)) {
1108 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001109 return -1;
1110 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001111 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001112 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001113 return 0;
1114}
1115
Song Zhao01031bb2021-05-13 21:23:20 -07001116int av_sync_get_mode(void *sync, enum sync_mode *mode)
1117{
1118 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1119
1120 if (!avsync || !mode)
1121 return -1;
1122
1123 *mode = avsync->mode;
1124 return 0;
1125}
1126
Song Zhaoc03ba122020-12-23 21:54:02 -08001127int av_sync_set_pause_pts(void *sync, pts90K pts)
1128{
1129 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1130
1131 if (!avsync)
1132 return -1;
1133
1134 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001135 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001136 return 0;
1137}
1138
1139int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1140{
1141 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1142
1143 if (!avsync)
1144 return -1;
1145
1146 avsync->pause_pts_cb = cb;
1147 avsync->pause_cb_priv = priv;
1148 return 0;
1149}
Song Zhaoea5a0412021-01-18 16:40:08 -08001150
yongchun.li428390d2022-02-17 17:15:40 -08001151int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1152{
1153 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1154
1155 if (!avsync)
1156 return -1;
1157
1158 avsync->underflow_cb = cb;
1159 avsync->underflow_cb_priv = priv;
1160
1161 if (cfg)
1162 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1163 else
1164 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1165
1166 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1167 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1168 avsync->underflow_cfg.time_thresh);
1169 return 0;
1170}
Song Zhaoea5a0412021-01-18 16:40:08 -08001171static void trigger_audio_start_cb(struct av_sync_session *avsync,
1172 avs_ascb_reason reason)
1173{
1174 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001175 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001176 pthread_mutex_lock(&avsync->lock);
1177 if (avsync->audio_start) {
1178 avsync->audio_start(avsync->audio_start_priv, reason);
1179 avsync->session_started = true;
1180 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001181 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001182 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1183 }
1184 pthread_mutex_unlock(&avsync->lock);
1185 }
1186}
1187
1188avs_start_ret av_sync_audio_start(
1189 void *sync,
1190 pts90K pts,
1191 pts90K delay,
1192 audio_start_cb cb,
1193 void *priv)
1194{
1195 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1196 uint32_t start_mode;
yongchun.li59e873d2021-07-07 11:42:38 -07001197 uint32_t systime;
Song Zhaoea5a0412021-01-18 16:40:08 -08001198 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1199 bool create_poll_t = false;
1200
1201 if (!avsync)
1202 return ret;
1203
yongchun.li59e873d2021-07-07 11:42:38 -07001204 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1205 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001206
yongchun.li59e873d2021-07-07 11:42:38 -07001207 if (avsync->in_audio_switch &&
1208 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1209 {
1210 start_mode = AVS_START_SYNC;
1211 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1212 } else {
1213 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1214 log_error("[%d]fail to set audio start", avsync->session_id);
1215 }
1216 if (avsync->in_audio_switch &&
1217 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1218 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
1219 msync_session_get_wall(avsync->fd, &systime, NULL);
Song Zhao4bd18762022-09-30 16:39:52 -07001220 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB
1221 && start_mode == AVS_START_SYNC) {
yongchun.li59e873d2021-07-07 11:42:38 -07001222 log_info("%d audio_switch audio need drop first.ahead %d ms",
1223 avsync->session_id, (int)(systime - pts)/90);
1224 ret = AV_SYNC_ASTART_AGAIN;
1225 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1226 goto exit;
1227 }
1228 else {
1229 int diff = (int)(pts - systime);
1230 log_info("%d audio_switch_state to start mode %d diff %d ms",
1231 avsync->session_id, start_mode, diff/90);
yongchun.li59e873d2021-07-07 11:42:38 -07001232 if (diff < A_ADJ_THREDHOLD_LB) {
1233 log_info("%d orig mode %d already close enough direct start",
1234 avsync->session_id, start_mode);
1235 start_mode = AVS_START_SYNC;
Song Zhao4bd18762022-09-30 16:39:52 -07001236 } else if (start_mode != AVS_START_ASYNC) {
1237 log_info("%d drop too far mode %d need to try ASYNC",
1238 avsync->session_id, start_mode);
1239 msync_session_set_audio_stop(avsync->fd);
1240 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1241 log_error("[%d]fail to set audio start", avsync->session_id);
1242 log_info("%d New start mode %d",
1243 avsync->session_id, start_mode);
yongchun.li59e873d2021-07-07 11:42:38 -07001244 }
Song Zhao4bd18762022-09-30 16:39:52 -07001245 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
yongchun.li59e873d2021-07-07 11:42:38 -07001246 }
yongchun.li107a6162021-05-05 02:38:57 -07001247 }
1248
Song Zhaoea5a0412021-01-18 16:40:08 -08001249 if (start_mode == AVS_START_SYNC) {
1250 ret = AV_SYNC_ASTART_SYNC;
1251 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001252 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001253 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001254 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001255 avsync->state = AV_SYNC_STAT_RUNNING;
1256 } else if (start_mode == AVS_START_AGAIN) {
1257 ret = AV_SYNC_ASTART_AGAIN;
1258 }
1259
1260 if (ret == AV_SYNC_ASTART_AGAIN)
1261 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001262
Song Zhao76005282022-03-08 16:49:41 -08001263 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1264 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001265 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001266
1267 if (start_mode == AVS_START_ASYNC) {
1268 if (!cb) {
1269 log_error("[%d]invalid cb", avsync->session_id);
1270 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001271 }
Song Zhao76005282022-03-08 16:49:41 -08001272 avsync->audio_start = cb;
1273 avsync->audio_start_priv = priv;
1274 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001275
Song Zhaod62bb392021-04-23 12:25:49 -07001276 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001277 int ret;
1278
1279 log_info("[%d]start poll thread", avsync->session_id);
1280 avsync->quit_poll = false;
1281 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1282 if (ret) {
1283 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1284 return AV_SYNC_ASTART_ERR;
1285 }
1286 }
Song Zhaod62bb392021-04-23 12:25:49 -07001287 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001288 msync_session_get_wall(avsync->fd, &systime, NULL);
1289 log_info("[%d]return %u w %u pts %u d %u",
1290 avsync->session_id, ret, systime, pts, delay);
1291 }
1292exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001293 log_info("[%d]return %u", avsync->session_id, ret);
1294 return ret;
1295}
1296
1297int av_sync_audio_render(
1298 void *sync,
1299 pts90K pts,
1300 struct audio_policy *policy)
1301{
1302 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001303 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001304 uint32_t systime;
1305 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1306 avs_audio_action action = AA_SYNC_AA_MAX;
1307
1308 if (!avsync || !policy)
1309 return -1;
1310
yongchun.li107a6162021-05-05 02:38:57 -07001311 msync_session_get_wall(avsync->fd, &systime, NULL);
1312
1313 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1314 pts, systime, avsync->mode, (int)(pts-systime)/90);
1315
1316 if (avsync->in_audio_switch
1317 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
Song Zhao4bd18762022-09-30 16:39:52 -07001318 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_MB) {
yongchun.li107a6162021-05-05 02:38:57 -07001319 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1320 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1321 action = AV_SYNC_AA_RENDER;
1322 } else if ((int)(systime - pts) > 0) {
1323 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1324 (int)(systime - pts)/90, systime, pts);
1325 action = AV_SYNC_AA_DROP;
1326 } else {
1327 action = AV_SYNC_AA_INSERT;
1328 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1329 (int)(pts - systime)/90, systime, pts);
1330 }
1331 goto done;
1332 }
1333
Song Zhaoea5a0412021-01-18 16:40:08 -08001334 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1335 avsync->mode == AV_SYNC_MODE_AMASTER) {
1336 action = AV_SYNC_AA_RENDER;
1337 goto done;
1338 }
1339
Song Zhaod62bb392021-04-23 12:25:49 -07001340 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001341 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001342 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1343 action = AV_SYNC_AA_DROP;
1344 goto done;
1345 }
1346
Song Zhao7daf3a12021-05-10 22:22:25 -07001347 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1348 avsync->mode == AV_SYNC_MODE_AMASTER) {
1349 action = AV_SYNC_AA_RENDER;
1350 goto done;
1351 }
1352
Song Zhaod62bb392021-04-23 12:25:49 -07001353 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1354 LIVE_MODE(avsync->mode) &&
1355 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1356 /* outlier by stream error */
1357 avsync->outlier_cnt++;
1358 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1359 /* treat as disc, just drop current frame */
1360 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1361 avsync->outlier_cnt = 0;
1362 action = AV_SYNC_AA_DROP;
1363 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001364 goto done;
1365 }
1366 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1367 pts = systime;
1368 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001369 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001370 goto done;
1371 }
1372
1373 avsync->outlier_cnt = 0;
1374 /* low bound from sync_lost to sync_setup */
1375 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1376 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1377 action = AV_SYNC_AA_RENDER;
1378 goto done;
1379 }
1380
1381 /* high bound of sync_setup */
1382 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1383 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1384 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001385 action = AV_SYNC_AA_RENDER;
1386 goto done;
1387 }
1388
1389 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001390 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001391 action = AV_SYNC_AA_DROP;
1392 goto done;
1393 }
1394
1395 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001396 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001397 action = AV_SYNC_AA_INSERT;
1398 goto done;
1399 }
1400
1401done:
1402 policy->action = action;
1403 policy->delta = (int)(systime - pts);
1404 if (action == AV_SYNC_AA_RENDER) {
1405 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001406 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001407 if (!out_lier)
1408 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001409 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001410 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001411 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1412 msync_session_update_apts(avsync->fd, systime, pts, 0);
1413 log_info("[%d] audio switch done sys %u pts %u",
1414 avsync->session_id, systime, pts);
1415 msync_session_set_audio_switch(avsync->fd, false);
1416 avsync->in_audio_switch = false;
1417 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1418 } else {
1419 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1420 avsync->session_id, action, systime, pts, systime - pts);
1421 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001422 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001423 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001424 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001425 avsync->last_disc_pts != pts &&
1426 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001427 log_info ("[%d]audio disc %u --> %u",
1428 avsync->session_id, systime, pts);
1429 msync_session_set_audio_dis(avsync->fd, pts);
1430 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001431 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001432 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001433
1434 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001435 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001436 if (!avsync->audio_drop_cnt)
1437 avsync->audio_drop_start = now;
1438 avsync->audio_drop_cnt++;
1439 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1440 log_info ("[%d]audio keep dropping sys %u vs a %u",
1441 avsync->session_id, systime, pts);
1442 msync_session_set_audio_dis(avsync->fd, pts);
1443 }
Song Zhao409739b2021-05-12 22:21:40 -07001444 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001445 if (action != AV_SYNC_AA_DROP)
1446 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001447 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001448 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001449 }
1450
1451 return ret;
1452}
1453
1454int av_sync_get_clock(void *sync, pts90K *pts)
1455{
1456 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1457
1458 if (!avsync || !pts)
1459 return -1;
1460 return msync_session_get_wall(avsync->fd, pts, NULL);
1461}
1462
1463static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001464 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001465 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001466{
Song Zhao76005282022-03-08 16:49:41 -08001467 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1468 avsync->session_id, avsync->active_mode, avsync->mode,
1469 v_active, a_active, v_timeout, stat);
1470
1471 /* iptv delayed start */
1472 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1473 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1474
Song Zhaoea5a0412021-01-18 16:40:08 -08001475 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1476 float speed;
Song Zhao7e8c68f2022-07-12 16:24:30 -07001477 if (a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001478 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001479 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhao6183ca92022-07-29 09:57:03 -07001480 } else if (!a_active && !avsync->session_started) {
1481 /* quit waiting ASAP */
1482 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoea5a0412021-01-18 16:40:08 -08001483 }
1484
1485 if (!msync_session_get_rate(avsync->fd, &speed)) {
1486 /* speed change is triggered by asink,
1487 * attached audio HAL will handle it
1488 */
1489 if (speed != avsync->speed)
1490 log_info("[%d]new rate %f", avsync->session_id, speed);
1491 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001492 if (avsync->mode != avsync->backup_mode) {
1493 avsync->mode = avsync->backup_mode;
1494 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1495 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001496 } else {
1497 avsync->backup_mode = avsync->mode;
1498 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1499 log_info("[%d]audio to freerun mode", avsync->session_id);
1500 }
1501 avsync->speed = speed;
1502 }
Song Zhaod62bb392021-04-23 12:25:49 -07001503 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1504 struct session_debug debug;
1505 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001506 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001507 avsync->backup_mode = avsync->mode;
1508 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001509 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001510 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001511 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001512 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001513 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001514 log_warn("[%d]audio back to mode %d",
1515 avsync->session_id, avsync->mode);
1516 }
1517 }
Song Zhao76005282022-03-08 16:49:41 -08001518 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1519 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001520 }
1521}
1522
1523static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001524 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001525 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001526{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001527 struct session_debug debug;
1528
Song Zhao76005282022-03-08 16:49:41 -08001529 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1530 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001531 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1532 if (debug.debug_freerun && !avsync->debug_freerun) {
1533 avsync->backup_mode = avsync->mode;
1534 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1535 avsync->debug_freerun = true;
1536 log_warn("[%d]video to freerun mode", avsync->session_id);
1537 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1538 avsync->mode = avsync->backup_mode;
1539 avsync->debug_freerun = false;
1540 log_warn("[%d]video back to mode %d",
1541 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001542 }
1543 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001544}
1545
1546static void * poll_thread(void * arg)
1547{
1548 int ret = 0;
1549 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1550 const int fd = avsync->fd;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001551 int poll_timeout = 10;
Song Zhaoea5a0412021-01-18 16:40:08 -08001552 struct pollfd pfd = {
1553 /* default blocking capture */
Song Zhao4bd18762022-09-30 16:39:52 -07001554 .events = POLLPRI,
Song Zhaoea5a0412021-01-18 16:40:08 -08001555 .fd = avsync->fd,
1556 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001557 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001558
Song Zhaoea5a0412021-01-18 16:40:08 -08001559 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001560
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001561 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001562 prctl (PR_SET_NAME, "avs_apoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001563 sflag = SRC_A;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001564 } else if (avsync->type == AV_SYNC_TYPE_VIDEO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001565 prctl (PR_SET_NAME, "avs_vpoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001566 sflag = SRC_V;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001567 poll_timeout = 100;
1568 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001569
Song Zhaoea5a0412021-01-18 16:40:08 -08001570 while (!avsync->quit_poll) {
1571 for (;;) {
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001572 ret = poll(&pfd, 1, poll_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001573 if (ret > 0)
1574 break;
1575 if (avsync->quit_poll)
1576 goto exit;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001577 if (errno == EINTR) {
1578 log_debug("[%d] poll interrupted", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001579 continue;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001580 }
Song Zhao4bd18762022-09-30 16:39:52 -07001581 if (errno == EAGAIN || errno == ENOMEM) {
1582 log_info("[%d] poll error %d", avsync->session_id, errno);
1583 continue;
1584 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001585 }
1586
1587 /* error handling */
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001588 if (pfd.revents & POLLERR) {
1589 usleep(poll_timeout * 1000);
1590 continue;
1591 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001592
Song Zhao4bd18762022-09-30 16:39:52 -07001593 if (pfd.revents & POLLNVAL) {
1594 log_warn("[%d] fd closed", avsync->session_id);
1595 goto exit;
1596 }
Song Zhaod62bb392021-04-23 12:25:49 -07001597 /* mode change. Non-exclusive wait so all the processes
1598 * shall be woken up
1599 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001600 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001601 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001602 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001603
Song Zhao9fef59c2022-08-17 12:43:10 -07001604 msync_session_get_stat(fd, true, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001605 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001606
1607 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001608 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001609 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001610 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001611 usleep(10000);
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001612 } else {
1613 log_debug("[%d] unexpected revents %x", avsync->session_id, pfd.revents);
1614 usleep(poll_timeout * 1000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001615 }
1616 }
1617exit:
1618 log_info("[%d]quit", avsync->session_id);
1619 return NULL;
1620}
1621
Song Zhao623e2f12021-09-03 15:54:04 -07001622#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1623/* return ppm between demod and PCR clock */
1624int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1625{
1626 int fd = -1, ppm = 0, nread;
1627 char buf[128];
1628 uint32_t reg_v, lock;
1629 float val;
1630
1631 fd = open(DEMOD_NODE, O_RDWR);
1632 if (fd < 0) {
1633 log_warn("node not found %s", DEMOD_NODE);
1634 /* do not retry */
1635 avsync->ppm_adjusted = true;
1636 return 0;
1637 }
1638 snprintf(buf, sizeof(buf), "%d", 5);
1639 write(fd, buf, 2);
1640
1641 lseek(fd, 0, SEEK_SET);
1642
hanghang.luo02efd312022-08-26 09:49:53 +08001643 nread = read(fd, buf, sizeof(buf)-1);
Song Zhao623e2f12021-09-03 15:54:04 -07001644 if (nread <= 0) {
1645 log_error("read error");
1646 goto err;
1647 }
1648 buf[nread] = 0;
1649 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1650 log_error("wrong format %s", buf);
1651 goto err;
1652 }
1653 if (lock != 0x1f) {
1654 log_info("demod not locked");
1655 goto err;
1656 }
1657 if (reg_v > ((2 << 20) - 1))
1658 reg_v -= (2 << 21);
1659 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1660 ppm = val;
1661 log_info("ppm from SFO %d", ppm);
1662 avsync->ppm_adjusted = true;
1663
1664err:
1665 if (fd >= 0)
1666 close(fd);
1667 return ppm;
1668}
1669
Song Zhaod62bb392021-04-23 12:25:49 -07001670int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001671{
1672 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001673 struct pcr_info pcr;
1674 enum pcr_monitor_status status;
1675 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001676 if (!avsync)
1677 return -1;
1678
1679 if (avsync->type != AV_SYNC_TYPE_PCR)
1680 return -2;
1681
Song Zhao623e2f12021-09-03 15:54:04 -07001682 /* initial estimation from Demod SFO HW */
1683 if (!avsync->ppm_adjusted) {
1684 ppm = dmod_get_sfo_dev(avsync);
1685 if (ppm != 0) {
1686 /* ppm > 0 means board clock is faster */
1687 msync_session_set_clock_dev(avsync->fd, -ppm);
1688 }
1689 }
wei.dubcc2ed22021-05-19 07:16:10 -04001690 pcr.monoclk = mono_clock / 1000;
1691 pcr.pts = (long long) pts * 1000 / 90;
1692 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1693
1694 status = pcr_monitor_get_status(avsync->pcr_monitor);
1695
1696 if (status >= DEVIATION_READY) {
1697 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1698 if (avsync->ppm != ppm) {
1699 avsync->ppm = ppm;
1700 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1701 if (msync_session_set_clock_dev(avsync->fd, ppm))
1702 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001703 else
1704 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001705 }
1706 }
1707
Song Zhaod62bb392021-04-23 12:25:49 -07001708 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001709}
1710
Song Zhaod62bb392021-04-23 12:25:49 -07001711int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001712{
1713 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1714
1715 if (!avsync)
1716 return -1;
1717
Song Zhaod62bb392021-04-23 12:25:49 -07001718 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001719}
1720
1721int av_sync_set_session_name(void *sync, const char *name)
1722{
1723 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1724
1725 if (!avsync)
1726 return -1;
1727
1728 return msync_session_set_name(avsync->fd, name);
1729}
yongchun.li107a6162021-05-05 02:38:57 -07001730
1731int av_sync_set_audio_switch(void *sync, bool start)
1732{
1733 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1734 bool v_active, a_active, v_timeout;
1735
1736 if (!avsync)
1737 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001738 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001739 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001740 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001741 log_error("[%d] can not get session state",
1742 avsync->session_id);
1743 return -1;
1744 }
1745 if (!v_active || !a_active) {
1746 log_error("[%d] no apply if not AV both active v %d a %d",
1747 avsync->session_id, v_active, a_active);
1748 return -1;
1749 }
1750 if (msync_session_set_audio_switch(avsync->fd, start)) {
1751 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1752 return -1;
1753 }
1754 avsync->in_audio_switch = start;
1755 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1756 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1757 return 0;
1758}
1759
1760int av_sync_get_audio_switch(void *sync, bool *start)
1761{
1762 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1763
1764 if (!avsync)
1765 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001766 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001767 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001768 log_error("[%d] can not audio seamless switch state",
1769 avsync->session_id);
1770 return -1;
1771 }
1772 if (start) *start = avsync->in_audio_switch;
1773 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001774}
Song Zhao8039f562021-05-18 18:11:25 -07001775
Song Zhao623e2f12021-09-03 15:54:04 -07001776enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001777{
1778 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1779
wei.dubcc2ed22021-05-19 07:16:10 -04001780 if (!avsync || !ppm)
1781 return CLK_RECOVERY_ERR;
1782 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001783 return CLK_RECOVERY_NOT_RUNNING;
1784
wei.dubcc2ed22021-05-19 07:16:10 -04001785 if (msync_session_get_clock_dev(avsync->fd, ppm))
1786 return CLK_RECOVERY_ERR;
1787
1788 if (*ppm == 0)
1789 return CLK_RECOVERY_ONGOING;
1790 else
1791 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001792}
Song Zhao95bd0922021-09-21 14:07:46 -07001793
1794static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1795{
1796 int ret;
1797
1798 if (!avsync->frame_q) {
1799 avsync->frame_q = create_q(MAX_FRAME_NUM);
1800 if (!avsync->frame_q) {
1801 log_error("[%d]create queue fail", avsync->session_id);
1802
1803 return -1;
1804 }
1805 }
1806
1807 ret = queue_item(avsync->frame_q, frame);
1808 if (ret)
hanghang.luo02efd312022-08-26 09:49:53 +08001809 log_error("queue fail:%d", ret);
Song Zhao95bd0922021-09-21 14:07:46 -07001810 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1811 return ret;
1812}
1813
1814int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1815{
1816 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1817
1818 if (!avsync)
1819 return -1;
1820 avsync->msys = msys;
1821 return 0;
1822}
1823
1824static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1825{
1826 struct vframe *frame = NULL, *enter_last_frame = NULL;
1827 uint64_t systime;
1828 int toggle_cnt = 0;
1829
1830 enter_last_frame = avsync->last_frame;
1831 systime = avsync->msys;
1832 log_debug("[%d]sys %llu", avsync->session_id, systime);
1833 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1834 if (systime >= frame->mts) {
1835 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1836 toggle_cnt++;
1837
1838 if (avsync->last_frame)
1839 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1840
1841 dqueue_item(avsync->frame_q, (void **)&frame);
1842 if (avsync->last_frame) {
1843 /* free frame that are not for display */
1844 if (toggle_cnt > 1) {
1845 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1846 avsync->last_frame->mts, frame->mts, systime);
1847 avsync->last_frame->free(avsync->last_frame);
1848 }
1849 } else {
1850 avsync->first_frame_toggled = true;
1851 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1852 }
1853 avsync->last_frame = frame;
1854 } else
1855 break;
1856 }
1857
1858 if (avsync->last_frame) {
1859 if (enter_last_frame != avsync->last_frame)
hanghang.luo02efd312022-08-26 09:49:53 +08001860 log_debug("[%d]pop %lu", avsync->session_id, avsync->last_frame->pts);
1861 log_trace("[%d]pop=%llu, system=%llu, diff %llu(ms), QNum=%d", avsync->session_id,
Song Zhao95bd0922021-09-21 14:07:46 -07001862 avsync->last_frame->mts,
1863 systime, (systime - avsync->last_frame->mts) / 1000000,
1864 queue_size(avsync->frame_q));
1865 } else
1866 if (enter_last_frame != avsync->last_frame)
1867 log_debug("[%d]pop (nil)", avsync->session_id);
1868
1869 if (avsync->last_frame)
1870 avsync->last_frame->hold_period++;
1871 return avsync->last_frame;
1872}
Song Zhao6183ca92022-07-29 09:57:03 -07001873
1874int avs_sync_stop_audio(void *sync)
1875{
1876 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1877
1878 if (!avsync)
1879 return -1;
1880
1881 return msync_session_stop_audio(avsync->fd);
1882}
bo.xiao05ba1ac2022-12-13 14:38:13 +08001883
1884int avs_sync_set_eos(void *sync)
1885{
1886 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1887
1888 if (!avsync)
1889 return -1;
1890
1891 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
1892 if (avsync->state == AV_SYNC_STAT_INIT) {
1893 avsync->state = AV_SYNC_STAT_RUNNING;
1894 log_debug("[%d]eos trigger state change: init --> running", avsync->session_id);
1895 }
1896 }
1897
1898 return 0;
1899}