blob: c6f8ce82603f823c6c1391943bd001b3c8155658 [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 Zhaof4e3c862022-09-01 14:00:11 -0700513 if (avsync->mode == AV_SYNC_MODE_IPTV &&
Song Zhao76005282022-03-08 16:49:41 -0800514 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
Song Zhaof4e3c862022-09-01 14:00:11 -0700519 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
520 msync_session_set_start_thres(avsync->fd, st_policy->timeout);
521
bo.xiao5821fc72021-07-11 22:47:00 -0400522 avsync->start_policy = st_policy->policy;
523 avsync->timeout = st_policy->timeout;
Song Zhao76005282022-03-08 16:49:41 -0800524
Song Zhaoea5a0412021-01-18 16:40:08 -0800525 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400526 if (st_policy->policy != AV_SYNC_START_NONE &&
527 st_policy->policy != AV_SYNC_START_V_PEEK)
528 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800529
530 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800531}
532
533int av_sync_pause(void *sync, bool pause)
534{
535 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700536 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800537 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800538
Song Zhaob5458b32021-11-12 15:58:47 -0800539 if (!avsync) {
540 log_error("invalid handle");
Song Zhaoc03ba122020-12-23 21:54:02 -0800541 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800542 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800543
fei.deng55389b62022-08-18 23:46:50 +0800544 if (avsync->type == AV_SYNC_TYPE_VIDEO && avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
545 log_warn("ignore pause in video mono mode");
546 return -1;
547 }
548
Song Zhaob5458b32021-11-12 15:58:47 -0800549 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
550 log_warn("ignore pause in pcr master mode");
Song Zhaoea5a0412021-01-18 16:40:08 -0800551 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800552 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800553
Song Zhao9fef59c2022-08-17 12:43:10 -0700554 rc = msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -0700555 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700556 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700557
yongchun.li5f52fb02021-06-04 18:13:05 -0700558 /* ignore only when video try to pause when audio is acive, on which
559 the control of the STC will be relays.
560 When resume,it can do always as it is possible that video just
561 paused earlier without audio yet,then audio added later before resume.
562 We shall not igore that otherwise it could cause video freeze. */
563 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
564 avsync->type == AV_SYNC_TYPE_VIDEO &&
565 a_active &&
566 !avsync->in_audio_switch) {
567 if (!pause) {
568 log_info("[%d] clear video pause when audio active",
569 avsync->session_id);
570 avsync->paused = pause;
571 } else {
572 log_info("[%d] ignore the pause from video when audio active",
573 avsync->session_id);
574 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800575 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700576 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800577
yongchun.li107a6162021-05-05 02:38:57 -0700578 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
579 log_info("[%d] ignore the pause from audio", avsync->session_id);
580 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
581 return 0;
582 }
583
Song Zhaoea5a0412021-01-18 16:40:08 -0800584 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800585 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800586 log_info("[%d]paused:%d type:%d rc %d",
587 avsync->session_id, pause, avsync->type, rc);
yongchun.li428390d2022-02-17 17:15:40 -0800588 if (!avsync->paused && avsync->first_frame_toggled) {
589 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
590 log_info("[%d] resume update new frame time", avsync->session_id);
591 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800592 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800593}
594
595int av_sync_push_frame(void *sync , struct vframe *frame)
596{
597 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700598 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800599 struct av_sync_session *avsync = (struct av_sync_session *)sync;
600
601 if (!avsync)
602 return -1;
603
Song Zhao95bd0922021-09-21 14:07:46 -0700604 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
fei.deng55389b62022-08-18 23:46:50 +0800605 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
Song Zhao95bd0922021-09-21 14:07:46 -0700606 return video_mono_push_frame(avsync, frame);
fei.deng55389b62022-08-18 23:46:50 +0800607 }
Song Zhao95bd0922021-09-21 14:07:46 -0700608
Song Zhaofd007632022-09-30 16:21:30 -0700609 if (avsync->state == AV_SYNC_STAT_INIT && !queue_size(avsync->frame_q)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800610 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400611 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800612 log_error("[%d]get policy", avsync->session_id);
613 return -1;
614 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800615 }
616
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700617 if (avsync->last_q_pts != -1) {
Song Zhao7e24b182022-04-01 08:46:40 -0700618 if (frame->pts != -1 && avsync->mode == AV_SYNC_MODE_VMASTER) {
619 /* Sometimes app will fake PTS for trickplay, video PTS gap
620 * is really big depending on the speed. Have to adjust the
621 * threshold dynamically.
622 */
623 int gap = (int)(frame->pts - avsync->last_q_pts);
624 if (gap > avsync->disc_thres_min) {
625 avsync->disc_thres_min = gap * 6;
626 avsync->disc_thres_max = gap * 20;
627 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
628 msync_session_set_disc_thres(avsync->session_id,
629 avsync->disc_thres_min, avsync->disc_thres_max);
630 log_info("[%d] update disc_thres to %d/%d",avsync->session_id,
631 avsync->disc_thres_min, avsync->disc_thres_max);
632 }
633 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700634 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
635 /* TODO: wrong, should remove from back of queue */
Song Zhaoc03ba122020-12-23 21:54:02 -0800636 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700637 if (prev) {
638 prev->free(prev);
639 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
640 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700641 } else if (avsync->fps_cnt < 100) {
642 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700643
644 if (interval > 0 && interval <= 4500) {
645 if (avsync->fps_interval_acc == -1) {
646 avsync->fps_interval_acc = interval;
647 avsync->fps_cnt = 1;
648 } else {
649 avsync->fps_interval_acc += interval;
650 avsync->fps_cnt++;
651 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
652 if (avsync->fps_cnt == 100)
653 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
654 }
655 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800656 }
657 }
658
Song Zhao065800e2021-05-26 15:56:06 -0700659 if (frame->duration == -1)
660 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800661 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700662 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800663 ret = queue_item(avsync->frame_q, frame);
664 if (avsync->state == AV_SYNC_STAT_INIT &&
665 queue_size(avsync->frame_q) >= avsync->start_thres) {
666 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaofd007632022-09-30 16:21:30 -0700667 log_debug("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800668 }
669
670 if (ret)
Song Zhaoe1b65602022-01-06 08:03:46 -0800671 log_error("queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400672 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800673 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800674}
675
676struct vframe *av_sync_pop_frame(void *sync)
677{
Song Zhaoea5a0412021-01-18 16:40:08 -0800678 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800679 struct av_sync_session *avsync = (struct av_sync_session *)sync;
680 int toggle_cnt = 0;
hanghang.luo02efd312022-08-26 09:49:53 +0800681 uint32_t systime = 0;
Song Zhao468fd652021-01-15 22:13:04 -0800682 bool pause_pts_reached = false;
hanghang.luo02efd312022-08-26 09:49:53 +0800683 uint32_t interval = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800684
Song Zhao95bd0922021-09-21 14:07:46 -0700685 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
686 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
687 return video_mono_pop_frame(avsync);
688
Song Zhaoc03ba122020-12-23 21:54:02 -0800689 pthread_mutex_lock(&avsync->lock);
690 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhao2f6744b2021-11-03 21:23:50 -0700691 log_debug("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800692 goto exit;
693 }
694
Song Zhaoea5a0412021-01-18 16:40:08 -0800695 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700696 uint32_t pts;
697
Song Zhaoc03ba122020-12-23 21:54:02 -0800698 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800699 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800700 goto exit;
701 }
Song Zhao35a82df2021-04-15 10:58:49 -0700702 msync_session_get_wall(avsync->fd, &systime, &interval);
703 pts = frame->pts - avsync->delay * interval;
704 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800705 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700706 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800707 }
708
Song Zhaoea5a0412021-01-18 16:40:08 -0800709 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700710 !avsync->first_frame_toggled &&
711 !msync_clock_started(avsync->fd)) {
712 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800713 log_trace("[%d]clock not started", avsync->session_id);
714 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800715 }
716
Song Zhaoea5a0412021-01-18 16:40:08 -0800717 enter_last_frame = avsync->last_frame;
718 msync_session_get_wall(avsync->fd, &systime, &interval);
719
720 /* handle refresh rate change */
721 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
722 avsync->vsync_interval != interval) {
723 log_info("[%d]vsync interval update %d --> %u",
724 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700725 if (avsync->fps_interval == -1)
726 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800727 avsync->vsync_interval = interval;
728 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800729 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700730 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800731 reset_pattern(avsync->pattern_detector);
732 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800733 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
734 struct vframe *next_frame = NULL;
735
736 peek_item(avsync->frame_q, (void **)&next_frame, 1);
737 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700738 log_debug("[%d]cur_f %u next_f %u size %d",
739 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800740 if (frame_expire(avsync, systime, interval,
741 frame, next_frame, toggle_cnt)) {
742 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800743 toggle_cnt++;
744
Song Zhao35a82df2021-04-15 10:58:49 -0700745 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800746 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700747 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700748 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700749 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
750 if (next_frame)
751 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
752 }
Song Zhao35a82df2021-04-15 10:58:49 -0700753
Song Zhaoc03ba122020-12-23 21:54:02 -0800754 if (avsync->last_frame)
755 avsync->last_holding_peroid = avsync->last_frame->hold_period;
756
757 dqueue_item(avsync->frame_q, (void **)&frame);
758 if (avsync->last_frame) {
759 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800760 if (toggle_cnt > 1) {
Song Zhaofd007632022-09-30 16:21:30 -0700761 log_info("[%d]free %u cur %u system/d %u/%u queue size %d", avsync->session_id,
762 avsync->last_frame->pts, frame->pts,
763 systime, systime - avsync->last_poptime,
764 queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800765 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800766 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800767 } else {
768 avsync->first_frame_toggled = true;
Song Zhaofd007632022-09-30 16:21:30 -0700769 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 -0800770 }
771 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800772 avsync->last_pts = frame->pts;
yongchun.li428390d2022-02-17 17:15:40 -0800773 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
Song Zhaoc03ba122020-12-23 21:54:02 -0800774 } else
775 break;
776 }
777
778 /* pause pts */
779 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800780 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800781 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800782 else
Song Zhao468fd652021-01-15 22:13:04 -0800783 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
784 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
785 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
786 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
787 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800788
Song Zhao468fd652021-01-15 22:13:04 -0800789 if (pause_pts_reached) {
Song Zhao468fd652021-01-15 22:13:04 -0800790 /* stay in paused until av_sync_pause(false) */
Song Zhaoa1742282022-09-30 16:17:26 -0700791 uint32_t local_pts = avsync->pause_pts;
Song Zhao468fd652021-01-15 22:13:04 -0800792 avsync->paused = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800793 log_info ("[%d]reach pause pts: %u",
Song Zhaob5458b32021-11-12 15:58:47 -0800794 avsync->session_id, avsync->pause_pts);
Song Zhaoad7c8232021-12-14 11:46:48 -0800795 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoa1742282022-09-30 16:17:26 -0700796 if (avsync->pause_pts_cb)
797 avsync->pause_pts_cb(local_pts,
798 avsync->pause_cb_priv);
799 log_info ("[%d] reach pause pts: %u handle done",
800 avsync->session_id, local_pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800801 }
802
803exit:
804 pthread_mutex_unlock(&avsync->lock);
yongchun.li428390d2022-02-17 17:15:40 -0800805
806 /* underflow check */
807 if (avsync->session_started && avsync->first_frame_toggled &&
808 (avsync->paused == false) && (avsync->state >= AV_SYNC_STAT_RUNNING) &&
809 avsync->underflow_cb && peek_item(avsync->frame_q, (void **)&frame, 0))
810 {/* empty queue in normal play */
811 struct timespec now;
812 int diff_ms;
813 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
814 diff_ms = time_diff(&now, &avsync->frame_last_update_time)/1000;
815 if(diff_ms >= (avsync->underflow_cfg.time_thresh
816 + avsync->vsync_interval*avsync->last_holding_peroid/90)) {
817 log_info ("[%d]underflow detected: %u", avsync->session_id, avsync->last_pts);
818 avsync->underflow_cb (avsync->last_pts,
819 avsync->underflow_cb_priv);
820 /* update time to control the underflow check call backs */
821 avsync->frame_last_update_time = now;
822 }
823 }
824
Song Zhaoc03ba122020-12-23 21:54:02 -0800825 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800826 if (enter_last_frame != avsync->last_frame)
827 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
bo.xiao1f94b352021-08-02 03:53:47 -0400828 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 -0700829 /* don't update vpts for out_lier */
830 if (avsync->last_frame->duration != -1)
831 msync_session_update_vpts(avsync->fd, systime,
832 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800833 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800834 if (enter_last_frame != avsync->last_frame)
835 log_debug("[%d]pop (nil)", avsync->session_id);
836
Song Zhao35a82df2021-04-15 10:58:49 -0700837 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800838 if (avsync->last_frame)
839 avsync->last_frame->hold_period++;
840 return avsync->last_frame;
841}
842
Song Zhaoc03ba122020-12-23 21:54:02 -0800843static inline uint32_t abs_diff(uint32_t a, uint32_t b)
844{
Song Zhaoea5a0412021-01-18 16:40:08 -0800845 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800846}
847
yongchun.li0ee6e372021-08-20 04:26:04 -0700848static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800849{
hanghang.luo02efd312022-08-26 09:49:53 +0800850 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 -0800851}
852
Song Zhaoc03ba122020-12-23 21:54:02 -0800853static bool frame_expire(struct av_sync_session* avsync,
854 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800855 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800856 struct vframe * frame,
857 struct vframe * next_frame,
858 int toggle_cnt)
859{
Song Zhao6dce2672022-01-13 11:32:44 -0800860 uint32_t fpts = frame->pts + avsync->extra_delay;
861 uint32_t nfpts = -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800862 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800863 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800864
865 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
866 return false;
867
868 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
869 return true;
870
Song Zhaoad7c8232021-12-14 11:46:48 -0800871 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS &&
872 avsync->pause_pts == frame->pts)
873 return true;
874
Song Zhao08fa16b2021-12-08 14:30:17 -0800875 if (systime == AV_SYNC_INVALID_PTS &&
876 avsync->mode == AV_SYNC_MODE_AMASTER)
877 return false;
878
Song Zhao6dce2672022-01-13 11:32:44 -0800879 if (next_frame)
880 nfpts = next_frame->pts + avsync->extra_delay;
881
Song Zhao7e24b182022-04-01 08:46:40 -0700882 if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
fei.deng63e43e12021-09-23 19:44:01 +0800883 /* We need to ensure that the video outputs smoothly,
884 so output video frame by frame hold_period */
885 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
886 avsync->last_frame &&
887 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
888 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
889 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700890 return true;
891 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700892 }
893
Song Zhaoc03ba122020-12-23 21:54:02 -0800894 if (!fpts) {
895 if (avsync->last_frame) {
896 /* try to accumulate duration as PTS */
897 fpts = avsync->vpts + avsync->last_frame->duration;
898 } else {
899 fpts = avsync->vpts;
900 }
901 }
902 systime += pts_correction;
903
904 /* phase adjustment */
905 if (avsync->phase_set)
906 systime += avsync->phase;
907
yongchun.lia50b1e92021-08-07 01:11:54 +0000908 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800909 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000910 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700911 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800912 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800913 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800914 return false;
915
Song Zhaoa2985cb2021-06-24 12:01:47 -0700916 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
917 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700918 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800919
yongchun.li0ee6e372021-08-20 04:26:04 -0700920 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700921 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800922 avsync->last_pts = fpts;
923 if (time_diff(&now, &avsync->sync_lost_print_time) >=
924 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700925 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800926 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800927 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700928 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800929 } else
930 avsync->sync_lost_cnt++;
931 }
Song Zhaod62bb392021-04-23 12:25:49 -0700932
933 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
934 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700935 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700936 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700937 /* outlier by stream error */
938 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700939 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700940 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
941 log_info("render outlier %u", fpts);
942 return true;
943 }
944 }
945
946 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800947 avsync->state = AV_SYNC_STAT_SYNC_LOST;
948 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800949 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700950 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800951 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700952
Song Zhao7e24b182022-04-01 08:46:40 -0700953 if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700954 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700955 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700956 msync_session_set_video_dis(avsync->fd, fpts);
957 avsync->last_disc_pts = fpts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700958 }
959
960 if ((int)(systime - fpts) > 0) {
961 if ((int)(systime - fpts) < avsync->disc_thres_max) {
962 /* catch up PCR */
Song Zhaof46932e2021-05-21 01:51:45 -0700963 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700964 } else {
965 /* render according to FPS */
966 if (!VALID_TS(avsync->last_r_syst) ||
967 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
968 avsync->last_r_syst = systime;
969 return true;
970 }
971 return false;
972 }
973 } else if (LIVE_MODE(avsync->mode)) {
974 /* hold if the gap is small */
975 if ((int)(fpts - systime) < avsync->disc_thres_max) {
976 return false;
977 } else {
978 /* render according to FPS */
979 if (!VALID_TS(avsync->last_r_syst) ||
980 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
981 avsync->last_r_syst = systime;
982 return true;
983 }
984 return false;
985 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800986 }
987 }
988
Song Zhao52f55192021-05-06 10:52:21 -0700989 /* In some cases, keeping pattern will enlarge the gap */
990 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
991 avsync->first_frame_toggled) {
992 reset_pattern(avsync->pattern_detector);
Song Zhaofd007632022-09-30 16:21:30 -0700993 log_info("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700994 systime, fpts);
995 }
996
Song Zhaoc03ba122020-12-23 21:54:02 -0800997 expire = (int)(systime - fpts) >= 0;
998
999 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -08001000 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001001 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -08001002 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001003 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001004 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001005 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -08001006 }
Song Zhao6dce2672022-01-13 11:32:44 -08001007 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -08001008 && avsync->first_frame_toggled) {
1009 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -08001010 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001011 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -08001012 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001013 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001014 }
1015 }
1016
Song Zhaoa58c3e92021-03-09 18:52:55 -08001017 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -08001018 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -08001019 (avsync->last_frame?avsync->last_frame->hold_period:0),
1020 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -08001021 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -08001022
1023 if (expire) {
1024 avsync->vpts = fpts;
1025 /* phase adjustment */
1026 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +00001027 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -08001028 if ((int)(systime - fpts) >= 0 &&
1029 (int)(fpts + interval - systime) > 0) {
1030 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -08001031 avsync->phase_set = true;
Song Zhaofd007632022-09-30 16:21:30 -07001032 log_debug("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -08001033 }
Song Zhao1561e542022-01-12 10:37:55 -08001034 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -08001035 if ((int)(systime - fpts) >= 0 &&
1036 (int)(fpts + interval - systime) > 0) {
1037 int vsync_pts_delta = (int)(systime - fpts);
1038
1039 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1040 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001041 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001042 log_info("[%d] too aligned adjust phase to %d",
1043 avsync->session_id, (int)avsync->phase);
1044 }
1045 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001046 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001047 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaofd007632022-09-30 16:21:30 -07001048 log_info("[%d]sync setup on frame %u", avsync->session_id, fpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001049 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001050 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001051 }
1052 return expire;
1053}
1054
Song Zhao35a82df2021-04-15 10:58:49 -07001055static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001056{
Song Zhao35a82df2021-04-15 10:58:49 -07001057 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001058 log_trace("[%d]cur_period: %d last_period: %d",
1059 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -07001060 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
1061 ret = true;
1062 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
1063 ret = true;
1064 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
1065 ret = true;
1066 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
1067 ret = true;
1068
1069 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -08001070}
1071
1072int av_sync_set_speed(void *sync, float speed)
1073{
1074 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1075
1076 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001077 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001078 return -1;
1079 }
1080
Song Zhao76005282022-03-08 16:49:41 -08001081 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001082 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001083 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001084 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001085
Song Zhaoea5a0412021-01-18 16:40:08 -08001086 avsync->speed = speed;
1087
1088 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
1089 if (speed == 1.0) {
1090 avsync->mode = avsync->backup_mode;
1091 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1092 } else {
1093 avsync->backup_mode = avsync->mode;
1094 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1095 log_info("[%d]audio to freerun mode", avsync->session_id);
1096 }
1097 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001098
Song Zhaoea5a0412021-01-18 16:40:08 -08001099 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1100 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001101}
1102
1103int av_sync_change_mode(void *sync, enum sync_mode mode)
1104{
1105 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1106
1107 if (!avsync)
1108 return -1;
1109
Song Zhaoea5a0412021-01-18 16:40:08 -08001110 if (msync_session_set_mode(avsync->fd, mode)) {
1111 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001112 return -1;
1113 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001114 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001115 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001116 return 0;
1117}
1118
Song Zhao01031bb2021-05-13 21:23:20 -07001119int av_sync_get_mode(void *sync, enum sync_mode *mode)
1120{
1121 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1122
1123 if (!avsync || !mode)
1124 return -1;
1125
1126 *mode = avsync->mode;
1127 return 0;
1128}
1129
Song Zhaoc03ba122020-12-23 21:54:02 -08001130int av_sync_set_pause_pts(void *sync, pts90K pts)
1131{
1132 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1133
1134 if (!avsync)
1135 return -1;
1136
1137 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001138 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001139 return 0;
1140}
1141
1142int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1143{
1144 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1145
1146 if (!avsync)
1147 return -1;
1148
1149 avsync->pause_pts_cb = cb;
1150 avsync->pause_cb_priv = priv;
1151 return 0;
1152}
Song Zhaoea5a0412021-01-18 16:40:08 -08001153
yongchun.li428390d2022-02-17 17:15:40 -08001154int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1155{
1156 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1157
1158 if (!avsync)
1159 return -1;
1160
1161 avsync->underflow_cb = cb;
1162 avsync->underflow_cb_priv = priv;
1163
1164 if (cfg)
1165 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1166 else
1167 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1168
1169 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1170 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1171 avsync->underflow_cfg.time_thresh);
1172 return 0;
1173}
Song Zhaoea5a0412021-01-18 16:40:08 -08001174static void trigger_audio_start_cb(struct av_sync_session *avsync,
1175 avs_ascb_reason reason)
1176{
1177 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001178 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001179 pthread_mutex_lock(&avsync->lock);
1180 if (avsync->audio_start) {
1181 avsync->audio_start(avsync->audio_start_priv, reason);
1182 avsync->session_started = true;
1183 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001184 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001185 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1186 }
1187 pthread_mutex_unlock(&avsync->lock);
1188 }
1189}
1190
1191avs_start_ret av_sync_audio_start(
1192 void *sync,
1193 pts90K pts,
1194 pts90K delay,
1195 audio_start_cb cb,
1196 void *priv)
1197{
1198 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1199 uint32_t start_mode;
yongchun.li06965172022-12-14 19:50:31 -08001200 uint32_t systime = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001201 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1202 bool create_poll_t = false;
1203
1204 if (!avsync)
1205 return ret;
1206
yongchun.li59e873d2021-07-07 11:42:38 -07001207 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1208 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001209
yongchun.li06965172022-12-14 19:50:31 -08001210 if (avsync->in_audio_switch) {
1211 msync_session_get_wall(avsync->fd, &systime, NULL);
1212 if (systime == AV_SYNC_INVALID_PTS) {
1213 log_info("%d Invalid systime could be paused pts %d ms switch_state %d again",
1214 avsync->session_id, (int) pts/90, avsync->audio_switch_state);
1215 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
1216 ret = AV_SYNC_ASTART_AGAIN;
1217 goto exit;
1218 }
1219 }
1220
yongchun.li59e873d2021-07-07 11:42:38 -07001221 if (avsync->in_audio_switch &&
1222 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1223 {
1224 start_mode = AVS_START_SYNC;
1225 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1226 } else {
1227 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1228 log_error("[%d]fail to set audio start", avsync->session_id);
1229 }
1230 if (avsync->in_audio_switch &&
1231 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1232 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
Song Zhao4bd18762022-09-30 16:39:52 -07001233 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB
1234 && start_mode == AVS_START_SYNC) {
yongchun.li59e873d2021-07-07 11:42:38 -07001235 log_info("%d audio_switch audio need drop first.ahead %d ms",
1236 avsync->session_id, (int)(systime - pts)/90);
1237 ret = AV_SYNC_ASTART_AGAIN;
1238 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1239 goto exit;
1240 }
1241 else {
1242 int diff = (int)(pts - systime);
1243 log_info("%d audio_switch_state to start mode %d diff %d ms",
1244 avsync->session_id, start_mode, diff/90);
yongchun.li59e873d2021-07-07 11:42:38 -07001245 if (diff < A_ADJ_THREDHOLD_LB) {
1246 log_info("%d orig mode %d already close enough direct start",
1247 avsync->session_id, start_mode);
1248 start_mode = AVS_START_SYNC;
Song Zhao4bd18762022-09-30 16:39:52 -07001249 } else if (start_mode != AVS_START_ASYNC) {
1250 log_info("%d drop too far mode %d need to try ASYNC",
1251 avsync->session_id, start_mode);
1252 msync_session_set_audio_stop(avsync->fd);
1253 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1254 log_error("[%d]fail to set audio start", avsync->session_id);
1255 log_info("%d New start mode %d",
1256 avsync->session_id, start_mode);
yongchun.li59e873d2021-07-07 11:42:38 -07001257 }
Song Zhao4bd18762022-09-30 16:39:52 -07001258 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
yongchun.li59e873d2021-07-07 11:42:38 -07001259 }
yongchun.li107a6162021-05-05 02:38:57 -07001260 }
1261
Song Zhaoea5a0412021-01-18 16:40:08 -08001262 if (start_mode == AVS_START_SYNC) {
1263 ret = AV_SYNC_ASTART_SYNC;
1264 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001265 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001266 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001267 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001268 avsync->state = AV_SYNC_STAT_RUNNING;
1269 } else if (start_mode == AVS_START_AGAIN) {
1270 ret = AV_SYNC_ASTART_AGAIN;
1271 }
1272
1273 if (ret == AV_SYNC_ASTART_AGAIN)
1274 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001275
Song Zhao76005282022-03-08 16:49:41 -08001276 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1277 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001278 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001279
1280 if (start_mode == AVS_START_ASYNC) {
1281 if (!cb) {
1282 log_error("[%d]invalid cb", avsync->session_id);
1283 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001284 }
Song Zhao76005282022-03-08 16:49:41 -08001285 avsync->audio_start = cb;
1286 avsync->audio_start_priv = priv;
1287 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001288
Song Zhaod62bb392021-04-23 12:25:49 -07001289 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001290 int ret;
1291
1292 log_info("[%d]start poll thread", avsync->session_id);
1293 avsync->quit_poll = false;
1294 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1295 if (ret) {
1296 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1297 return AV_SYNC_ASTART_ERR;
1298 }
1299 }
Song Zhaod62bb392021-04-23 12:25:49 -07001300 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001301 msync_session_get_wall(avsync->fd, &systime, NULL);
1302 log_info("[%d]return %u w %u pts %u d %u",
1303 avsync->session_id, ret, systime, pts, delay);
1304 }
1305exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001306 log_info("[%d]return %u", avsync->session_id, ret);
1307 return ret;
1308}
1309
1310int av_sync_audio_render(
1311 void *sync,
1312 pts90K pts,
1313 struct audio_policy *policy)
1314{
1315 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001316 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001317 uint32_t systime;
1318 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1319 avs_audio_action action = AA_SYNC_AA_MAX;
1320
1321 if (!avsync || !policy)
1322 return -1;
1323
yongchun.li107a6162021-05-05 02:38:57 -07001324 msync_session_get_wall(avsync->fd, &systime, NULL);
1325
1326 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1327 pts, systime, avsync->mode, (int)(pts-systime)/90);
1328
1329 if (avsync->in_audio_switch
1330 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
Song Zhao4bd18762022-09-30 16:39:52 -07001331 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_MB) {
yongchun.li107a6162021-05-05 02:38:57 -07001332 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1333 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1334 action = AV_SYNC_AA_RENDER;
1335 } else if ((int)(systime - pts) > 0) {
1336 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1337 (int)(systime - pts)/90, systime, pts);
1338 action = AV_SYNC_AA_DROP;
1339 } else {
1340 action = AV_SYNC_AA_INSERT;
1341 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1342 (int)(pts - systime)/90, systime, pts);
1343 }
1344 goto done;
1345 }
1346
Song Zhaoea5a0412021-01-18 16:40:08 -08001347 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 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001354 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001355 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1356 action = AV_SYNC_AA_DROP;
1357 goto done;
1358 }
1359
Song Zhao7daf3a12021-05-10 22:22:25 -07001360 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1361 avsync->mode == AV_SYNC_MODE_AMASTER) {
1362 action = AV_SYNC_AA_RENDER;
1363 goto done;
1364 }
1365
Song Zhaod62bb392021-04-23 12:25:49 -07001366 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1367 LIVE_MODE(avsync->mode) &&
1368 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1369 /* outlier by stream error */
1370 avsync->outlier_cnt++;
1371 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1372 /* treat as disc, just drop current frame */
1373 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1374 avsync->outlier_cnt = 0;
1375 action = AV_SYNC_AA_DROP;
1376 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001377 goto done;
1378 }
1379 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1380 pts = systime;
1381 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001382 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001383 goto done;
1384 }
1385
1386 avsync->outlier_cnt = 0;
1387 /* low bound from sync_lost to sync_setup */
1388 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1389 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1390 action = AV_SYNC_AA_RENDER;
1391 goto done;
1392 }
1393
1394 /* high bound of sync_setup */
1395 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1396 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1397 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001398 action = AV_SYNC_AA_RENDER;
1399 goto done;
1400 }
1401
1402 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001403 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001404 action = AV_SYNC_AA_DROP;
1405 goto done;
1406 }
1407
1408 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001409 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001410 action = AV_SYNC_AA_INSERT;
1411 goto done;
1412 }
1413
1414done:
1415 policy->action = action;
1416 policy->delta = (int)(systime - pts);
1417 if (action == AV_SYNC_AA_RENDER) {
1418 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001419 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001420 if (!out_lier)
1421 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001422 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001423 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001424 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1425 msync_session_update_apts(avsync->fd, systime, pts, 0);
1426 log_info("[%d] audio switch done sys %u pts %u",
1427 avsync->session_id, systime, pts);
1428 msync_session_set_audio_switch(avsync->fd, false);
1429 avsync->in_audio_switch = false;
1430 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1431 } else {
1432 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1433 avsync->session_id, action, systime, pts, systime - pts);
1434 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001435 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001436 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001437 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001438 avsync->last_disc_pts != pts &&
1439 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001440 log_info ("[%d]audio disc %u --> %u",
1441 avsync->session_id, systime, pts);
1442 msync_session_set_audio_dis(avsync->fd, pts);
1443 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001444 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001445 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001446
1447 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001448 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001449 if (!avsync->audio_drop_cnt)
1450 avsync->audio_drop_start = now;
1451 avsync->audio_drop_cnt++;
1452 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1453 log_info ("[%d]audio keep dropping sys %u vs a %u",
1454 avsync->session_id, systime, pts);
1455 msync_session_set_audio_dis(avsync->fd, pts);
1456 }
Song Zhao409739b2021-05-12 22:21:40 -07001457 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001458 if (action != AV_SYNC_AA_DROP)
1459 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001460 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001461 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001462 }
1463
1464 return ret;
1465}
1466
1467int av_sync_get_clock(void *sync, pts90K *pts)
1468{
1469 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1470
1471 if (!avsync || !pts)
1472 return -1;
1473 return msync_session_get_wall(avsync->fd, pts, NULL);
1474}
1475
1476static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001477 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001478 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001479{
Song Zhao76005282022-03-08 16:49:41 -08001480 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1481 avsync->session_id, avsync->active_mode, avsync->mode,
1482 v_active, a_active, v_timeout, stat);
1483
1484 /* iptv delayed start */
1485 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1486 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1487
Song Zhaoea5a0412021-01-18 16:40:08 -08001488 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1489 float speed;
Song Zhao7e8c68f2022-07-12 16:24:30 -07001490 if (a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001491 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001492 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhao6183ca92022-07-29 09:57:03 -07001493 } else if (!a_active && !avsync->session_started) {
1494 /* quit waiting ASAP */
1495 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoea5a0412021-01-18 16:40:08 -08001496 }
1497
1498 if (!msync_session_get_rate(avsync->fd, &speed)) {
1499 /* speed change is triggered by asink,
1500 * attached audio HAL will handle it
1501 */
1502 if (speed != avsync->speed)
1503 log_info("[%d]new rate %f", avsync->session_id, speed);
1504 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001505 if (avsync->mode != avsync->backup_mode) {
1506 avsync->mode = avsync->backup_mode;
1507 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1508 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001509 } else {
1510 avsync->backup_mode = avsync->mode;
1511 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1512 log_info("[%d]audio to freerun mode", avsync->session_id);
1513 }
1514 avsync->speed = speed;
1515 }
Song Zhaod62bb392021-04-23 12:25:49 -07001516 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1517 struct session_debug debug;
1518 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001519 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001520 avsync->backup_mode = avsync->mode;
1521 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001522 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001523 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001524 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001525 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001526 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001527 log_warn("[%d]audio back to mode %d",
1528 avsync->session_id, avsync->mode);
1529 }
1530 }
Song Zhao76005282022-03-08 16:49:41 -08001531 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1532 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001533 }
1534}
1535
1536static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001537 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001538 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001539{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001540 struct session_debug debug;
1541
Song Zhao76005282022-03-08 16:49:41 -08001542 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1543 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001544 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1545 if (debug.debug_freerun && !avsync->debug_freerun) {
1546 avsync->backup_mode = avsync->mode;
1547 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1548 avsync->debug_freerun = true;
1549 log_warn("[%d]video to freerun mode", avsync->session_id);
1550 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1551 avsync->mode = avsync->backup_mode;
1552 avsync->debug_freerun = false;
1553 log_warn("[%d]video back to mode %d",
1554 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001555 }
1556 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001557}
1558
1559static void * poll_thread(void * arg)
1560{
1561 int ret = 0;
1562 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1563 const int fd = avsync->fd;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001564 int poll_timeout = 10;
Song Zhaoea5a0412021-01-18 16:40:08 -08001565 struct pollfd pfd = {
1566 /* default blocking capture */
Song Zhao4bd18762022-09-30 16:39:52 -07001567 .events = POLLPRI,
Song Zhaoea5a0412021-01-18 16:40:08 -08001568 .fd = avsync->fd,
1569 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001570 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001571
Song Zhaoea5a0412021-01-18 16:40:08 -08001572 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001573
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001574 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001575 prctl (PR_SET_NAME, "avs_apoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001576 sflag = SRC_A;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001577 } else if (avsync->type == AV_SYNC_TYPE_VIDEO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001578 prctl (PR_SET_NAME, "avs_vpoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001579 sflag = SRC_V;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001580 poll_timeout = 100;
1581 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001582
Song Zhaoea5a0412021-01-18 16:40:08 -08001583 while (!avsync->quit_poll) {
1584 for (;;) {
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001585 ret = poll(&pfd, 1, poll_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001586 if (ret > 0)
1587 break;
1588 if (avsync->quit_poll)
1589 goto exit;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001590 if (errno == EINTR) {
1591 log_debug("[%d] poll interrupted", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001592 continue;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001593 }
Song Zhao4bd18762022-09-30 16:39:52 -07001594 if (errno == EAGAIN || errno == ENOMEM) {
1595 log_info("[%d] poll error %d", avsync->session_id, errno);
1596 continue;
1597 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001598 }
1599
1600 /* error handling */
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001601 if (pfd.revents & POLLERR) {
1602 usleep(poll_timeout * 1000);
1603 continue;
1604 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001605
Song Zhao4bd18762022-09-30 16:39:52 -07001606 if (pfd.revents & POLLNVAL) {
1607 log_warn("[%d] fd closed", avsync->session_id);
1608 goto exit;
1609 }
Song Zhaod62bb392021-04-23 12:25:49 -07001610 /* mode change. Non-exclusive wait so all the processes
1611 * shall be woken up
1612 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001613 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001614 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001615 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001616
Song Zhao9fef59c2022-08-17 12:43:10 -07001617 msync_session_get_stat(fd, true, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001618 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001619
1620 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001621 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001622 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001623 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001624 usleep(10000);
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001625 } else {
1626 log_debug("[%d] unexpected revents %x", avsync->session_id, pfd.revents);
1627 usleep(poll_timeout * 1000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001628 }
1629 }
1630exit:
1631 log_info("[%d]quit", avsync->session_id);
1632 return NULL;
1633}
1634
Song Zhao623e2f12021-09-03 15:54:04 -07001635#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1636/* return ppm between demod and PCR clock */
1637int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1638{
1639 int fd = -1, ppm = 0, nread;
1640 char buf[128];
1641 uint32_t reg_v, lock;
1642 float val;
1643
1644 fd = open(DEMOD_NODE, O_RDWR);
1645 if (fd < 0) {
1646 log_warn("node not found %s", DEMOD_NODE);
1647 /* do not retry */
1648 avsync->ppm_adjusted = true;
1649 return 0;
1650 }
1651 snprintf(buf, sizeof(buf), "%d", 5);
1652 write(fd, buf, 2);
1653
1654 lseek(fd, 0, SEEK_SET);
1655
hanghang.luo02efd312022-08-26 09:49:53 +08001656 nread = read(fd, buf, sizeof(buf)-1);
Song Zhao623e2f12021-09-03 15:54:04 -07001657 if (nread <= 0) {
1658 log_error("read error");
1659 goto err;
1660 }
1661 buf[nread] = 0;
1662 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1663 log_error("wrong format %s", buf);
1664 goto err;
1665 }
1666 if (lock != 0x1f) {
1667 log_info("demod not locked");
1668 goto err;
1669 }
1670 if (reg_v > ((2 << 20) - 1))
1671 reg_v -= (2 << 21);
1672 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1673 ppm = val;
1674 log_info("ppm from SFO %d", ppm);
1675 avsync->ppm_adjusted = true;
1676
1677err:
1678 if (fd >= 0)
1679 close(fd);
1680 return ppm;
1681}
1682
Song Zhaod62bb392021-04-23 12:25:49 -07001683int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001684{
1685 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001686 struct pcr_info pcr;
1687 enum pcr_monitor_status status;
1688 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001689 if (!avsync)
1690 return -1;
1691
1692 if (avsync->type != AV_SYNC_TYPE_PCR)
1693 return -2;
1694
Song Zhao623e2f12021-09-03 15:54:04 -07001695 /* initial estimation from Demod SFO HW */
1696 if (!avsync->ppm_adjusted) {
1697 ppm = dmod_get_sfo_dev(avsync);
1698 if (ppm != 0) {
1699 /* ppm > 0 means board clock is faster */
1700 msync_session_set_clock_dev(avsync->fd, -ppm);
1701 }
1702 }
wei.dubcc2ed22021-05-19 07:16:10 -04001703 pcr.monoclk = mono_clock / 1000;
1704 pcr.pts = (long long) pts * 1000 / 90;
1705 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1706
1707 status = pcr_monitor_get_status(avsync->pcr_monitor);
1708
1709 if (status >= DEVIATION_READY) {
1710 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1711 if (avsync->ppm != ppm) {
1712 avsync->ppm = ppm;
1713 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1714 if (msync_session_set_clock_dev(avsync->fd, ppm))
1715 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001716 else
1717 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001718 }
1719 }
1720
Song Zhaod62bb392021-04-23 12:25:49 -07001721 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001722}
1723
Song Zhaod62bb392021-04-23 12:25:49 -07001724int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001725{
1726 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1727
1728 if (!avsync)
1729 return -1;
1730
Song Zhaod62bb392021-04-23 12:25:49 -07001731 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001732}
1733
1734int av_sync_set_session_name(void *sync, const char *name)
1735{
1736 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1737
1738 if (!avsync)
1739 return -1;
1740
1741 return msync_session_set_name(avsync->fd, name);
1742}
yongchun.li107a6162021-05-05 02:38:57 -07001743
1744int av_sync_set_audio_switch(void *sync, bool start)
1745{
1746 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1747 bool v_active, a_active, v_timeout;
1748
1749 if (!avsync)
1750 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001751 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001752 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001753 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001754 log_error("[%d] can not get session state",
1755 avsync->session_id);
1756 return -1;
1757 }
1758 if (!v_active || !a_active) {
1759 log_error("[%d] no apply if not AV both active v %d a %d",
1760 avsync->session_id, v_active, a_active);
1761 return -1;
1762 }
1763 if (msync_session_set_audio_switch(avsync->fd, start)) {
1764 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1765 return -1;
1766 }
1767 avsync->in_audio_switch = start;
1768 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1769 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1770 return 0;
1771}
1772
1773int av_sync_get_audio_switch(void *sync, bool *start)
1774{
1775 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1776
1777 if (!avsync)
1778 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001779 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001780 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001781 log_error("[%d] can not audio seamless switch state",
1782 avsync->session_id);
1783 return -1;
1784 }
1785 if (start) *start = avsync->in_audio_switch;
1786 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001787}
Song Zhao8039f562021-05-18 18:11:25 -07001788
Song Zhao623e2f12021-09-03 15:54:04 -07001789enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001790{
1791 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1792
wei.dubcc2ed22021-05-19 07:16:10 -04001793 if (!avsync || !ppm)
1794 return CLK_RECOVERY_ERR;
1795 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001796 return CLK_RECOVERY_NOT_RUNNING;
1797
wei.dubcc2ed22021-05-19 07:16:10 -04001798 if (msync_session_get_clock_dev(avsync->fd, ppm))
1799 return CLK_RECOVERY_ERR;
1800
1801 if (*ppm == 0)
1802 return CLK_RECOVERY_ONGOING;
1803 else
1804 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001805}
Song Zhao95bd0922021-09-21 14:07:46 -07001806
1807static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1808{
1809 int ret;
1810
1811 if (!avsync->frame_q) {
1812 avsync->frame_q = create_q(MAX_FRAME_NUM);
1813 if (!avsync->frame_q) {
1814 log_error("[%d]create queue fail", avsync->session_id);
1815
1816 return -1;
1817 }
1818 }
1819
1820 ret = queue_item(avsync->frame_q, frame);
1821 if (ret)
hanghang.luo02efd312022-08-26 09:49:53 +08001822 log_error("queue fail:%d", ret);
Song Zhao95bd0922021-09-21 14:07:46 -07001823 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1824 return ret;
1825}
1826
1827int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1828{
1829 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1830
1831 if (!avsync)
1832 return -1;
1833 avsync->msys = msys;
1834 return 0;
1835}
1836
1837static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1838{
1839 struct vframe *frame = NULL, *enter_last_frame = NULL;
1840 uint64_t systime;
1841 int toggle_cnt = 0;
1842
1843 enter_last_frame = avsync->last_frame;
1844 systime = avsync->msys;
1845 log_debug("[%d]sys %llu", avsync->session_id, systime);
1846 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1847 if (systime >= frame->mts) {
1848 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1849 toggle_cnt++;
1850
1851 if (avsync->last_frame)
1852 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1853
1854 dqueue_item(avsync->frame_q, (void **)&frame);
1855 if (avsync->last_frame) {
1856 /* free frame that are not for display */
1857 if (toggle_cnt > 1) {
1858 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1859 avsync->last_frame->mts, frame->mts, systime);
1860 avsync->last_frame->free(avsync->last_frame);
1861 }
1862 } else {
1863 avsync->first_frame_toggled = true;
1864 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1865 }
1866 avsync->last_frame = frame;
1867 } else
1868 break;
1869 }
1870
1871 if (avsync->last_frame) {
1872 if (enter_last_frame != avsync->last_frame)
hanghang.luo02efd312022-08-26 09:49:53 +08001873 log_debug("[%d]pop %lu", avsync->session_id, avsync->last_frame->pts);
1874 log_trace("[%d]pop=%llu, system=%llu, diff %llu(ms), QNum=%d", avsync->session_id,
Song Zhao95bd0922021-09-21 14:07:46 -07001875 avsync->last_frame->mts,
1876 systime, (systime - avsync->last_frame->mts) / 1000000,
1877 queue_size(avsync->frame_q));
1878 } else
1879 if (enter_last_frame != avsync->last_frame)
1880 log_debug("[%d]pop (nil)", avsync->session_id);
1881
1882 if (avsync->last_frame)
1883 avsync->last_frame->hold_period++;
1884 return avsync->last_frame;
1885}
Song Zhao6183ca92022-07-29 09:57:03 -07001886
1887int avs_sync_stop_audio(void *sync)
1888{
1889 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1890
1891 if (!avsync)
1892 return -1;
1893
1894 return msync_session_stop_audio(avsync->fd);
1895}
bo.xiao05ba1ac2022-12-13 14:38:13 +08001896
1897int avs_sync_set_eos(void *sync)
1898{
1899 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1900
1901 if (!avsync)
1902 return -1;
1903
1904 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
1905 if (avsync->state == AV_SYNC_STAT_INIT) {
1906 avsync->state = AV_SYNC_STAT_RUNNING;
1907 log_debug("[%d]eos trigger state change: init --> running", avsync->session_id);
1908 }
1909 }
1910
1911 return 0;
1912}