blob: 5f456e635de4ecbb211ae9d7d71fad03e9d988d2 [file] [log] [blame]
Song Zhaoc03ba122020-12-23 21:54:02 -08001/*
2 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
3 *
4 * This source code is subject to the terms and conditions defined in the
5 * file 'LICENSE' which is part of this source code package.
6 *
7 * Description:
8 */
Song Zhaoea5a0412021-01-18 16:40:08 -08009#include <errno.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080010#include <pthread.h>
11#include <stdbool.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <sys/time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080015#include <poll.h>
16#include <fcntl.h>
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <sys/prctl.h>
20#include <sys/ioctl.h>
Song Zhaoa2985cb2021-06-24 12:01:47 -070021#include <time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080022#include <unistd.h>
23//#include <linux/amlogic/msync.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080024#include "aml_avsync.h"
Song Zhao4f632952021-12-16 09:00:18 -080025#include "aml_queue.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080026#include "pattern.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080027#include "aml_avsync_log.h"
Song Zhaoea5a0412021-01-18 16:40:08 -080028#include "msync_util.h"
29#include "msync.h"
30#include <pthread.h>
wei.dubcc2ed22021-05-19 07:16:10 -040031#include "pcr_monitor.h"
fei.deng66b4e812022-04-14 12:23:01 +080032#include "aml_version.h"
Song Zhao2f6744b2021-11-03 21:23:50 -070033
Song Zhaoc03ba122020-12-23 21:54:02 -080034enum sync_state {
35 AV_SYNC_STAT_INIT = 0,
36 AV_SYNC_STAT_RUNNING = 1,
37 AV_SYNC_STAT_SYNC_SETUP = 2,
38 AV_SYNC_STAT_SYNC_LOST = 3,
39};
40
yongchun.li107a6162021-05-05 02:38:57 -070041enum audio_switch_state_ {
42 AUDIO_SWITCH_STAT_INIT = 0,
43 AUDIO_SWITCH_STAT_RESET = 1,
44 AUDIO_SWITCH_STAT_START = 2,
45 AUDIO_SWITCH_STAT_FINISH = 3,
yongchun.li59e873d2021-07-07 11:42:38 -070046 AUDIO_SWITCH_STAT_AGAIN = 4,
yongchun.li107a6162021-05-05 02:38:57 -070047};
48
Song Zhaoea5a0412021-01-18 16:40:08 -080049#define SESSION_DEV "avsync_s"
50
Song Zhaoc03ba122020-12-23 21:54:02 -080051struct av_sync_session {
52 /* session id attached */
53 int session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -080054 int fd;
55 bool attached;
56 enum sync_mode mode;
57 /* for audio trickplay */
58 enum sync_mode backup_mode;
59 enum sync_type type;
60 uint32_t start_policy;
bo.xiao5821fc72021-07-11 22:47:00 -040061 int timeout;
Song Zhaoc03ba122020-12-23 21:54:02 -080062
Song Zhaoea5a0412021-01-18 16:40:08 -080063 /* playback time, will stop increasing during pause */
64 pts90K vpts;
65 pts90K apts;
66
67 /* phase adjustment of stream time for rate control (Video ONLY) */
Song Zhaoc03ba122020-12-23 21:54:02 -080068 pts90K phase;
69 bool phase_set;
Song Zhao1561e542022-01-12 10:37:55 -080070 bool phase_adjusted;
Song Zhaoc03ba122020-12-23 21:54:02 -080071
72 /* pts of last rendered frame */
Song Zhaoea5a0412021-01-18 16:40:08 -080073 pts90K last_wall;
Song Zhaoc03ba122020-12-23 21:54:02 -080074 pts90K last_pts;
75 struct vframe *last_frame;
76
Song Zhaoe0bf6ad2021-07-09 11:28:42 -070077 /* pts of last pushed frame */
78 pts90K last_q_pts;
79
Song Zhaoc03ba122020-12-23 21:54:02 -080080 bool first_frame_toggled;
Song Zhaoc03ba122020-12-23 21:54:02 -080081 bool paused;
Song Zhaoea5a0412021-01-18 16:40:08 -080082 enum sync_state state;
Song Zhaoc03ba122020-12-23 21:54:02 -080083 void *pattern_detector;
84 void *frame_q;
Song Zhaoc03ba122020-12-23 21:54:02 -080085
Song Zhaoea5a0412021-01-18 16:40:08 -080086 /* start control */
87 int start_thres;
88 audio_start_cb audio_start;
89 void *audio_start_priv;
90
91 /* render property */
Song Zhaoc03ba122020-12-23 21:54:02 -080092 int delay;
Song Zhao6dce2672022-01-13 11:32:44 -080093 int extra_delay;
Song Zhaoc03ba122020-12-23 21:54:02 -080094 pts90K vsync_interval;
95
96 /* state lock */
97 pthread_mutex_t lock;
98 /* pattern */
99 int last_holding_peroid;
Song Zhaoea5a0412021-01-18 16:40:08 -0800100 bool session_started;
Song Zhaoc03ba122020-12-23 21:54:02 -0800101
102 float speed;
103
Song Zhaoc03ba122020-12-23 21:54:02 -0800104 /* pause pts */
105 pts90K pause_pts;
106 pause_pts_done pause_pts_cb;
107 void *pause_cb_priv;
yongchun.li428390d2022-02-17 17:15:40 -0800108 /* underflow */
109 underflow_detected underflow_cb;
110 void *underflow_cb_priv;
111 struct underflow_config underflow_cfg;
112 struct timespec frame_last_update_time;
Song Zhao5d2b4772021-01-18 16:40:08 -0800113
114 /* log control */
Song Zhaoa2985cb2021-06-24 12:01:47 -0700115 uint32_t last_log_syst;
Song Zhao5d2b4772021-01-18 16:40:08 -0800116 uint32_t sync_lost_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700117 struct timespec sync_lost_print_time;
Song Zhaoea5a0412021-01-18 16:40:08 -0800118
119 pthread_t poll_thread;
120 /* pcr master, IPTV only */
121 bool quit_poll;
122 enum sync_mode active_mode;
Song Zhaof46932e2021-05-21 01:51:45 -0700123 uint32_t disc_thres_min;
124 uint32_t disc_thres_max;
Song Zhao35a82df2021-04-15 10:58:49 -0700125
126 /* error detection */
127 uint32_t last_poptime;
Song Zhaod62bb392021-04-23 12:25:49 -0700128 uint32_t outlier_cnt;
Song Zhao409739b2021-05-12 22:21:40 -0700129 pts90K last_disc_pts;
130
yongchun.li107a6162021-05-05 02:38:57 -0700131 // indicate set audio switch
132 bool in_audio_switch;
133 enum audio_switch_state_ audio_switch_state;
wei.dubcc2ed22021-05-19 07:16:10 -0400134
135 //pcr monitor handle
136 void *pcr_monitor;
137 int ppm;
Song Zhao623e2f12021-09-03 15:54:04 -0700138 bool ppm_adjusted;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700139
140 //video FPS detection
141 pts90K last_fpts;
142 int fps_interval;
143 int fps_interval_acc;
144 int fps_cnt;
145
146 //video freerun with rate control
147 uint32_t last_r_syst;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700148 bool debug_freerun;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700149
150 //Audio dropping detection
151 uint32_t audio_drop_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700152 struct timespec audio_drop_start;
Song Zhao95bd0922021-09-21 14:07:46 -0700153
154 /*system mono time for current vsync interrupt */
155 uint64_t msys;
Song Zhaoc03ba122020-12-23 21:54:02 -0800156};
157
158#define MAX_FRAME_NUM 32
159#define DEFAULT_START_THRESHOLD 2
160#define TIME_UNIT90K (90000)
Song Zhaof46932e2021-05-21 01:51:45 -0700161#define AV_DISC_THRES_MIN (TIME_UNIT90K / 3)
162#define AV_DISC_THRES_MAX (TIME_UNIT90K * 10)
Song Zhao7daf3a12021-05-10 22:22:25 -0700163#define A_ADJ_THREDHOLD_HB (900 * 6) //60ms
164#define A_ADJ_THREDHOLD_LB (900 * 2) //20ms
Song Zhao52f55192021-05-06 10:52:21 -0700165#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800166#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhao76005282022-03-08 16:49:41 -0800167#define LIVE_MODE(m) ((m) == AV_SYNC_MODE_PCR_MASTER || (m) == AV_SYNC_MODE_IPTV)
Song Zhao7e24b182022-04-01 08:46:40 -0700168#define V_DISC_MODE(mode) (LIVE_MODE(mode) || (mode) == AV_SYNC_MODE_VMASTER)
Song Zhaod62bb392021-04-23 12:25:49 -0700169
Song Zhao065800e2021-05-26 15:56:06 -0700170#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
Song Zhaod62bb392021-04-23 12:25:49 -0700171#define OUTLIER_MAX_CNT 8
Song Zhaoa2985cb2021-06-24 12:01:47 -0700172#define VALID_TS(x) ((x) != -1)
yongchun.li428390d2022-02-17 17:15:40 -0800173#define UNDERFLOW_CHECK_THRESH_MS (100)
Song Zhaoc03ba122020-12-23 21:54:02 -0800174
yongchun.li0ee6e372021-08-20 04:26:04 -0700175static uint64_t time_diff (struct timespec *b, struct timespec *a);
Song Zhaoc03ba122020-12-23 21:54:02 -0800176static bool frame_expire(struct av_sync_session* avsync,
177 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800178 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800179 struct vframe * frame,
180 struct vframe * next_frame,
181 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700182static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800183 int cur_period,
184 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800185static void * poll_thread(void * arg);
186static void trigger_audio_start_cb(struct av_sync_session *avsync,
187 avs_ascb_reason reason);
Song Zhao95bd0922021-09-21 14:07:46 -0700188static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync);
189static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame);
fei.deng55389b62022-08-18 23:46:50 +0800190
Song Zhao2f6744b2021-11-03 21:23:50 -0700191pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER;
Song Zhaoc03ba122020-12-23 21:54:02 -0800192
Song Zhaoea5a0412021-01-18 16:40:08 -0800193int av_sync_open_session(int *session_id)
194{
Song Zhao2f6744b2021-11-03 21:23:50 -0700195 int fd = -1;
Song Zhaoea5a0412021-01-18 16:40:08 -0800196 int id, rc;
197
Song Zhao2f6744b2021-11-03 21:23:50 -0700198 pthread_mutex_lock(&glock);
199 fd = msync_create_session();
Song Zhaoea5a0412021-01-18 16:40:08 -0800200 if (fd < 0) {
201 log_error("fail");
Song Zhao2f6744b2021-11-03 21:23:50 -0700202 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800203 }
204 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
205 if (rc) {
206 log_error("new session errno:%d", errno);
Song Zhao2f6744b2021-11-03 21:23:50 -0700207 msync_destory_session(fd);
208 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800209 }
210 *session_id = id;
Song Zhao2f6744b2021-11-03 21:23:50 -0700211 log_debug("new avsession id %d fd %d", id, fd);
212exit:
213 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800214 return fd;
215}
216
217void av_sync_close_session(int session)
218{
Song Zhao2f6744b2021-11-03 21:23:50 -0700219 log_debug("session closed fd %d", session);
220 pthread_mutex_lock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800221 msync_destory_session(session);
Song Zhao2f6744b2021-11-03 21:23:50 -0700222 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800223}
224
225static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800226 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800227 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800228 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800229 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800230{
231 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800232 char dev_name[20];
Song Zhao2f6744b2021-11-03 21:23:50 -0700233 int retry = 10;
Song Zhaoc03ba122020-12-23 21:54:02 -0800234
fei.deng55389b62022-08-18 23:46:50 +0800235 /* debug log level */
236 {
237 const char *env= getenv( "AML_AVSYNC_DEBUG_LEVEL");
238 if ( env ) {
239 log_set_level(atoi(env));
240 }
241 }
242
Song Zhao95bd0922021-09-21 14:07:46 -0700243 log_info("[%d] mode %d type %d", session_id, mode, type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800244 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
245 if (!avsync) {
246 log_error("OOM");
247 return NULL;
248 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800249
Song Zhao95bd0922021-09-21 14:07:46 -0700250 if (type == AV_SYNC_TYPE_VIDEO &&
251 mode == AV_SYNC_MODE_VIDEO_MONO) {
252 if (session_id < AV_SYNC_SESSION_V_MONO) {
253 log_error("wrong session id %d", session_id);
254 goto err;
255 }
256 avsync->type = type;
257 avsync->mode = mode;
258 avsync->fd = -1;
259 avsync->session_id = session_id;
260 log_info("[%d]init", avsync->session_id);
261 return avsync;
262 }
263
Song Zhaoea5a0412021-01-18 16:40:08 -0800264 if (type == AV_SYNC_TYPE_VIDEO) {
265 avsync->pattern_detector = create_pattern_detector();
266 if (!avsync->pattern_detector) {
267 log_error("pd create fail");
268 goto err;
269 }
270
271 if (!start_thres)
272 avsync->start_thres = DEFAULT_START_THRESHOLD;
273 else {
274 if (start_thres > 5) {
275 log_error("start_thres too big: %d", start_thres);
276 goto err2;
277 }
278 avsync->start_thres = start_thres;
279 }
280 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800281 avsync->phase_adjusted = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800282 avsync->first_frame_toggled = false;
Song Zhaofd007632022-09-30 16:21:30 -0700283
284 avsync->frame_q = create_q(MAX_FRAME_NUM);
285 if (!avsync->frame_q) {
286 log_error("[%d]create queue fail", avsync->session_id);
287 goto err2;
288 }
289 /* for debugging */
290 {
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 Zhaoea5a0412021-01-18 16:40:08 -0800473 if (avsync->state != AV_SYNC_STAT_INIT) {
474 if (avsync->type == AV_SYNC_TYPE_VIDEO)
475 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800476
Song Zhaoea5a0412021-01-18 16:40:08 -0800477 avsync->quit_poll = true;
478 if (avsync->poll_thread) {
479 pthread_join(avsync->poll_thread, NULL);
480 avsync->poll_thread = 0;
481 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700482 if (avsync->type == AV_SYNC_TYPE_AUDIO)
483 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoaf368d52021-02-17 17:53:45 -0800484 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800485
Song Zhaoea5a0412021-01-18 16:40:08 -0800486 if (avsync->session_started) {
487 if (avsync->type == AV_SYNC_TYPE_VIDEO)
488 msync_session_set_video_stop(avsync->fd);
489 else
490 msync_session_set_audio_stop(avsync->fd);
491 }
wei.dubcc2ed22021-05-19 07:16:10 -0400492
493 if(avsync->pcr_monitor)
494 pcr_monitor_destroy(avsync->pcr_monitor);
495
Song Zhaoea5a0412021-01-18 16:40:08 -0800496 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800497 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800498 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
499 destroy_q(avsync->frame_q);
500 destroy_pattern_detector(avsync->pattern_detector);
501 }
Song Zhaob5458b32021-11-12 15:58:47 -0800502 log_info("[%d]done type %d", avsync->session_id, avsync->type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800503 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800504}
505
bo.xiao5821fc72021-07-11 22:47:00 -0400506int avs_sync_set_start_policy(void *sync, struct start_policy* st_policy)
Song Zhaoea5a0412021-01-18 16:40:08 -0800507{
508 struct av_sync_session *avsync = (struct av_sync_session *)sync;
509
510 if (!avsync || !avsync->fd)
511 return -1;
512
Song Zhao47961d72022-08-29 14:04:44 -0700513 log_info("[%d]policy %u --> %u, timeout %d --> %d", avsync->session_id,
514 avsync->start_policy, st_policy->policy, avsync->timeout, st_policy->timeout);
Song Zhao76005282022-03-08 16:49:41 -0800515 if (LIVE_MODE(avsync->mode) &&
516 st_policy->policy != AV_SYNC_START_ASAP) {
517 log_error("policy %d not supported in live mode", st_policy->policy);
518 return -1;
519 }
520
bo.xiao5821fc72021-07-11 22:47:00 -0400521 avsync->start_policy = st_policy->policy;
522 avsync->timeout = st_policy->timeout;
Song Zhao76005282022-03-08 16:49:41 -0800523
Song Zhaoea5a0412021-01-18 16:40:08 -0800524 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400525 if (st_policy->policy != AV_SYNC_START_NONE &&
526 st_policy->policy != AV_SYNC_START_V_PEEK)
527 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800528
529 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800530}
531
532int av_sync_pause(void *sync, bool pause)
533{
534 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700535 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800536 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800537
Song Zhaob5458b32021-11-12 15:58:47 -0800538 if (!avsync) {
539 log_error("invalid handle");
Song Zhaoc03ba122020-12-23 21:54:02 -0800540 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800541 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800542
fei.deng55389b62022-08-18 23:46:50 +0800543 if (avsync->type == AV_SYNC_TYPE_VIDEO && avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
544 log_warn("ignore pause in video mono mode");
545 return -1;
546 }
547
Song Zhaob5458b32021-11-12 15:58:47 -0800548 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
549 log_warn("ignore pause in pcr master mode");
Song Zhaoea5a0412021-01-18 16:40:08 -0800550 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800551 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800552
Song Zhao9fef59c2022-08-17 12:43:10 -0700553 rc = msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -0700554 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700555 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700556
yongchun.li5f52fb02021-06-04 18:13:05 -0700557 /* ignore only when video try to pause when audio is acive, on which
558 the control of the STC will be relays.
559 When resume,it can do always as it is possible that video just
560 paused earlier without audio yet,then audio added later before resume.
561 We shall not igore that otherwise it could cause video freeze. */
562 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
563 avsync->type == AV_SYNC_TYPE_VIDEO &&
564 a_active &&
565 !avsync->in_audio_switch) {
566 if (!pause) {
567 log_info("[%d] clear video pause when audio active",
568 avsync->session_id);
569 avsync->paused = pause;
570 } else {
571 log_info("[%d] ignore the pause from video when audio active",
572 avsync->session_id);
573 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800574 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700575 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800576
yongchun.li107a6162021-05-05 02:38:57 -0700577 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
578 log_info("[%d] ignore the pause from audio", avsync->session_id);
579 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
580 return 0;
581 }
582
Song Zhaoea5a0412021-01-18 16:40:08 -0800583 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800584 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800585 log_info("[%d]paused:%d type:%d rc %d",
586 avsync->session_id, pause, avsync->type, rc);
yongchun.li428390d2022-02-17 17:15:40 -0800587 if (!avsync->paused && avsync->first_frame_toggled) {
588 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
589 log_info("[%d] resume update new frame time", avsync->session_id);
590 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800591 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800592}
593
594int av_sync_push_frame(void *sync , struct vframe *frame)
595{
596 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700597 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800598 struct av_sync_session *avsync = (struct av_sync_session *)sync;
599
600 if (!avsync)
601 return -1;
602
Song Zhao95bd0922021-09-21 14:07:46 -0700603 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
fei.deng55389b62022-08-18 23:46:50 +0800604 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
Song Zhao95bd0922021-09-21 14:07:46 -0700605 return video_mono_push_frame(avsync, frame);
fei.deng55389b62022-08-18 23:46:50 +0800606 }
Song Zhao95bd0922021-09-21 14:07:46 -0700607
Song Zhaofd007632022-09-30 16:21:30 -0700608 if (avsync->state == AV_SYNC_STAT_INIT && !queue_size(avsync->frame_q)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800609 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400610 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800611 log_error("[%d]get policy", avsync->session_id);
612 return -1;
613 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800614 }
615
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700616 if (avsync->last_q_pts != -1) {
Song Zhao7e24b182022-04-01 08:46:40 -0700617 if (frame->pts != -1 && avsync->mode == AV_SYNC_MODE_VMASTER) {
618 /* Sometimes app will fake PTS for trickplay, video PTS gap
619 * is really big depending on the speed. Have to adjust the
620 * threshold dynamically.
621 */
622 int gap = (int)(frame->pts - avsync->last_q_pts);
623 if (gap > avsync->disc_thres_min) {
624 avsync->disc_thres_min = gap * 6;
625 avsync->disc_thres_max = gap * 20;
626 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
627 msync_session_set_disc_thres(avsync->session_id,
628 avsync->disc_thres_min, avsync->disc_thres_max);
629 log_info("[%d] update disc_thres to %d/%d",avsync->session_id,
630 avsync->disc_thres_min, avsync->disc_thres_max);
631 }
632 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700633 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
634 /* TODO: wrong, should remove from back of queue */
Song Zhaoc03ba122020-12-23 21:54:02 -0800635 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700636 if (prev) {
637 prev->free(prev);
638 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
639 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700640 } else if (avsync->fps_cnt < 100) {
641 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700642
643 if (interval > 0 && interval <= 4500) {
644 if (avsync->fps_interval_acc == -1) {
645 avsync->fps_interval_acc = interval;
646 avsync->fps_cnt = 1;
647 } else {
648 avsync->fps_interval_acc += interval;
649 avsync->fps_cnt++;
650 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
651 if (avsync->fps_cnt == 100)
652 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
653 }
654 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800655 }
656 }
657
Song Zhao065800e2021-05-26 15:56:06 -0700658 if (frame->duration == -1)
659 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800660 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700661 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800662 ret = queue_item(avsync->frame_q, frame);
663 if (avsync->state == AV_SYNC_STAT_INIT &&
664 queue_size(avsync->frame_q) >= avsync->start_thres) {
665 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaofd007632022-09-30 16:21:30 -0700666 log_debug("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800667 }
668
669 if (ret)
Song Zhaoe1b65602022-01-06 08:03:46 -0800670 log_error("queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400671 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800672 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800673}
674
675struct vframe *av_sync_pop_frame(void *sync)
676{
Song Zhaoea5a0412021-01-18 16:40:08 -0800677 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800678 struct av_sync_session *avsync = (struct av_sync_session *)sync;
679 int toggle_cnt = 0;
hanghang.luo02efd312022-08-26 09:49:53 +0800680 uint32_t systime = 0;
Song Zhao468fd652021-01-15 22:13:04 -0800681 bool pause_pts_reached = false;
hanghang.luo02efd312022-08-26 09:49:53 +0800682 uint32_t interval = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800683
Song Zhao95bd0922021-09-21 14:07:46 -0700684 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
685 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
686 return video_mono_pop_frame(avsync);
687
Song Zhaoc03ba122020-12-23 21:54:02 -0800688 pthread_mutex_lock(&avsync->lock);
689 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhao2f6744b2021-11-03 21:23:50 -0700690 log_debug("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800691 goto exit;
692 }
693
Song Zhaoea5a0412021-01-18 16:40:08 -0800694 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700695 uint32_t pts;
696
Song Zhaoc03ba122020-12-23 21:54:02 -0800697 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800698 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800699 goto exit;
700 }
Song Zhao35a82df2021-04-15 10:58:49 -0700701 msync_session_get_wall(avsync->fd, &systime, &interval);
702 pts = frame->pts - avsync->delay * interval;
703 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800704 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700705 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800706 }
707
Song Zhaoea5a0412021-01-18 16:40:08 -0800708 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700709 !avsync->first_frame_toggled &&
710 !msync_clock_started(avsync->fd)) {
711 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800712 log_trace("[%d]clock not started", avsync->session_id);
713 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800714 }
715
Song Zhaoea5a0412021-01-18 16:40:08 -0800716 enter_last_frame = avsync->last_frame;
717 msync_session_get_wall(avsync->fd, &systime, &interval);
718
719 /* handle refresh rate change */
720 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
721 avsync->vsync_interval != interval) {
722 log_info("[%d]vsync interval update %d --> %u",
723 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700724 if (avsync->fps_interval == -1)
725 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800726 avsync->vsync_interval = interval;
727 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800728 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700729 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800730 reset_pattern(avsync->pattern_detector);
731 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800732 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
733 struct vframe *next_frame = NULL;
734
735 peek_item(avsync->frame_q, (void **)&next_frame, 1);
736 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700737 log_debug("[%d]cur_f %u next_f %u size %d",
738 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800739 if (frame_expire(avsync, systime, interval,
740 frame, next_frame, toggle_cnt)) {
741 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800742 toggle_cnt++;
743
Song Zhao35a82df2021-04-15 10:58:49 -0700744 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800745 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700746 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700747 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700748 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
749 if (next_frame)
750 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
751 }
Song Zhao35a82df2021-04-15 10:58:49 -0700752
Song Zhaoc03ba122020-12-23 21:54:02 -0800753 if (avsync->last_frame)
754 avsync->last_holding_peroid = avsync->last_frame->hold_period;
755
756 dqueue_item(avsync->frame_q, (void **)&frame);
757 if (avsync->last_frame) {
758 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800759 if (toggle_cnt > 1) {
Song Zhaofd007632022-09-30 16:21:30 -0700760 log_info("[%d]free %u cur %u system/d %u/%u queue size %d", avsync->session_id,
761 avsync->last_frame->pts, frame->pts,
762 systime, systime - avsync->last_poptime,
763 queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800764 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800765 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800766 } else {
767 avsync->first_frame_toggled = true;
Song Zhaofd007632022-09-30 16:21:30 -0700768 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 -0800769 }
770 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800771 avsync->last_pts = frame->pts;
yongchun.li428390d2022-02-17 17:15:40 -0800772 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
Song Zhaoc03ba122020-12-23 21:54:02 -0800773 } else
774 break;
775 }
776
777 /* pause pts */
778 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800779 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800780 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800781 else
Song Zhao468fd652021-01-15 22:13:04 -0800782 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
783 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
784 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
785 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
786 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800787
Song Zhao468fd652021-01-15 22:13:04 -0800788 if (pause_pts_reached) {
Song Zhao468fd652021-01-15 22:13:04 -0800789 /* stay in paused until av_sync_pause(false) */
Song Zhaoa1742282022-09-30 16:17:26 -0700790 uint32_t local_pts = avsync->pause_pts;
Song Zhao468fd652021-01-15 22:13:04 -0800791 avsync->paused = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800792 log_info ("[%d]reach pause pts: %u",
Song Zhaob5458b32021-11-12 15:58:47 -0800793 avsync->session_id, avsync->pause_pts);
Song Zhaoad7c8232021-12-14 11:46:48 -0800794 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoa1742282022-09-30 16:17:26 -0700795 if (avsync->pause_pts_cb)
796 avsync->pause_pts_cb(local_pts,
797 avsync->pause_cb_priv);
798 log_info ("[%d] reach pause pts: %u handle done",
799 avsync->session_id, local_pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800800 }
801
802exit:
803 pthread_mutex_unlock(&avsync->lock);
yongchun.li428390d2022-02-17 17:15:40 -0800804
805 /* underflow check */
806 if (avsync->session_started && avsync->first_frame_toggled &&
807 (avsync->paused == false) && (avsync->state >= AV_SYNC_STAT_RUNNING) &&
808 avsync->underflow_cb && peek_item(avsync->frame_q, (void **)&frame, 0))
809 {/* empty queue in normal play */
810 struct timespec now;
811 int diff_ms;
812 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
813 diff_ms = time_diff(&now, &avsync->frame_last_update_time)/1000;
814 if(diff_ms >= (avsync->underflow_cfg.time_thresh
815 + avsync->vsync_interval*avsync->last_holding_peroid/90)) {
816 log_info ("[%d]underflow detected: %u", avsync->session_id, avsync->last_pts);
817 avsync->underflow_cb (avsync->last_pts,
818 avsync->underflow_cb_priv);
819 /* update time to control the underflow check call backs */
820 avsync->frame_last_update_time = now;
821 }
822 }
823
Song Zhaoc03ba122020-12-23 21:54:02 -0800824 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800825 if (enter_last_frame != avsync->last_frame)
826 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
bo.xiao1f94b352021-08-02 03:53:47 -0400827 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 -0700828 /* don't update vpts for out_lier */
829 if (avsync->last_frame->duration != -1)
830 msync_session_update_vpts(avsync->fd, systime,
831 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800832 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800833 if (enter_last_frame != avsync->last_frame)
834 log_debug("[%d]pop (nil)", avsync->session_id);
835
Song Zhao35a82df2021-04-15 10:58:49 -0700836 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800837 if (avsync->last_frame)
838 avsync->last_frame->hold_period++;
839 return avsync->last_frame;
840}
841
Song Zhaoc03ba122020-12-23 21:54:02 -0800842static inline uint32_t abs_diff(uint32_t a, uint32_t b)
843{
Song Zhaoea5a0412021-01-18 16:40:08 -0800844 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800845}
846
yongchun.li0ee6e372021-08-20 04:26:04 -0700847static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800848{
hanghang.luo02efd312022-08-26 09:49:53 +0800849 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 -0800850}
851
Song Zhaoc03ba122020-12-23 21:54:02 -0800852static bool frame_expire(struct av_sync_session* avsync,
853 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800854 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800855 struct vframe * frame,
856 struct vframe * next_frame,
857 int toggle_cnt)
858{
Song Zhao6dce2672022-01-13 11:32:44 -0800859 uint32_t fpts = frame->pts + avsync->extra_delay;
860 uint32_t nfpts = -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800861 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800862 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800863
864 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
865 return false;
866
867 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
868 return true;
869
Song Zhaoad7c8232021-12-14 11:46:48 -0800870 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS &&
871 avsync->pause_pts == frame->pts)
872 return true;
873
Song Zhao08fa16b2021-12-08 14:30:17 -0800874 if (systime == AV_SYNC_INVALID_PTS &&
875 avsync->mode == AV_SYNC_MODE_AMASTER)
876 return false;
877
Song Zhao6dce2672022-01-13 11:32:44 -0800878 if (next_frame)
879 nfpts = next_frame->pts + avsync->extra_delay;
880
Song Zhao7e24b182022-04-01 08:46:40 -0700881 if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
fei.deng63e43e12021-09-23 19:44:01 +0800882 /* We need to ensure that the video outputs smoothly,
883 so output video frame by frame hold_period */
884 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
885 avsync->last_frame &&
886 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
887 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
888 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700889 return true;
890 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700891 }
892
Song Zhaoc03ba122020-12-23 21:54:02 -0800893 if (!fpts) {
894 if (avsync->last_frame) {
895 /* try to accumulate duration as PTS */
896 fpts = avsync->vpts + avsync->last_frame->duration;
897 } else {
898 fpts = avsync->vpts;
899 }
900 }
901 systime += pts_correction;
902
903 /* phase adjustment */
904 if (avsync->phase_set)
905 systime += avsync->phase;
906
yongchun.lia50b1e92021-08-07 01:11:54 +0000907 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800908 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000909 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700910 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800911 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800912 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800913 return false;
914
Song Zhaoa2985cb2021-06-24 12:01:47 -0700915 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
916 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700917 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800918
yongchun.li0ee6e372021-08-20 04:26:04 -0700919 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700920 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800921 avsync->last_pts = fpts;
922 if (time_diff(&now, &avsync->sync_lost_print_time) >=
923 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700924 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800925 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800926 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700927 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800928 } else
929 avsync->sync_lost_cnt++;
930 }
Song Zhaod62bb392021-04-23 12:25:49 -0700931
932 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
933 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700934 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700935 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700936 /* outlier by stream error */
937 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700938 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700939 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
940 log_info("render outlier %u", fpts);
941 return true;
942 }
943 }
944
945 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800946 avsync->state = AV_SYNC_STAT_SYNC_LOST;
947 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800948 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700949 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800950 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700951
Song Zhao7e24b182022-04-01 08:46:40 -0700952 if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700953 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700954 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700955 msync_session_set_video_dis(avsync->fd, fpts);
956 avsync->last_disc_pts = fpts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700957 }
958
959 if ((int)(systime - fpts) > 0) {
960 if ((int)(systime - fpts) < avsync->disc_thres_max) {
961 /* catch up PCR */
Song Zhaof46932e2021-05-21 01:51:45 -0700962 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700963 } else {
964 /* render according to FPS */
965 if (!VALID_TS(avsync->last_r_syst) ||
966 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
967 avsync->last_r_syst = systime;
968 return true;
969 }
970 return false;
971 }
972 } else if (LIVE_MODE(avsync->mode)) {
973 /* hold if the gap is small */
974 if ((int)(fpts - systime) < avsync->disc_thres_max) {
975 return false;
976 } else {
977 /* render according to FPS */
978 if (!VALID_TS(avsync->last_r_syst) ||
979 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
980 avsync->last_r_syst = systime;
981 return true;
982 }
983 return false;
984 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800985 }
986 }
987
Song Zhao52f55192021-05-06 10:52:21 -0700988 /* In some cases, keeping pattern will enlarge the gap */
989 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
990 avsync->first_frame_toggled) {
991 reset_pattern(avsync->pattern_detector);
Song Zhaofd007632022-09-30 16:21:30 -0700992 log_info("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700993 systime, fpts);
994 }
995
Song Zhaoc03ba122020-12-23 21:54:02 -0800996 expire = (int)(systime - fpts) >= 0;
997
998 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -0800999 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001000 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -08001001 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001002 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001003 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001004 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -08001005 }
Song Zhao6dce2672022-01-13 11:32:44 -08001006 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -08001007 && avsync->first_frame_toggled) {
1008 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -08001009 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001010 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -08001011 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001012 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001013 }
1014 }
1015
Song Zhaoa58c3e92021-03-09 18:52:55 -08001016 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -08001017 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -08001018 (avsync->last_frame?avsync->last_frame->hold_period:0),
1019 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -08001020 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -08001021
1022 if (expire) {
1023 avsync->vpts = fpts;
1024 /* phase adjustment */
1025 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +00001026 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -08001027 if ((int)(systime - fpts) >= 0 &&
1028 (int)(fpts + interval - systime) > 0) {
1029 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -08001030 avsync->phase_set = true;
Song Zhaofd007632022-09-30 16:21:30 -07001031 log_debug("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -08001032 }
Song Zhao1561e542022-01-12 10:37:55 -08001033 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -08001034 if ((int)(systime - fpts) >= 0 &&
1035 (int)(fpts + interval - systime) > 0) {
1036 int vsync_pts_delta = (int)(systime - fpts);
1037
1038 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1039 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001040 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001041 log_info("[%d] too aligned adjust phase to %d",
1042 avsync->session_id, (int)avsync->phase);
1043 }
1044 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001045 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001046 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaofd007632022-09-30 16:21:30 -07001047 log_info("[%d]sync setup on frame %u", avsync->session_id, fpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001048 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001049 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001050 }
1051 return expire;
1052}
1053
Song Zhao35a82df2021-04-15 10:58:49 -07001054static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001055{
Song Zhao35a82df2021-04-15 10:58:49 -07001056 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001057 log_trace("[%d]cur_period: %d last_period: %d",
1058 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -07001059 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
1060 ret = true;
1061 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
1062 ret = true;
1063 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
1064 ret = true;
1065 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
1066 ret = true;
1067
1068 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -08001069}
1070
1071int av_sync_set_speed(void *sync, float speed)
1072{
1073 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1074
1075 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001076 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001077 return -1;
1078 }
1079
Song Zhao76005282022-03-08 16:49:41 -08001080 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001081 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001082 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001083 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001084
Song Zhaoea5a0412021-01-18 16:40:08 -08001085 avsync->speed = speed;
1086
1087 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
1088 if (speed == 1.0) {
1089 avsync->mode = avsync->backup_mode;
1090 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1091 } else {
1092 avsync->backup_mode = avsync->mode;
1093 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1094 log_info("[%d]audio to freerun mode", avsync->session_id);
1095 }
1096 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001097
Song Zhaoea5a0412021-01-18 16:40:08 -08001098 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1099 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001100}
1101
1102int av_sync_change_mode(void *sync, enum sync_mode mode)
1103{
1104 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1105
1106 if (!avsync)
1107 return -1;
1108
Song Zhaoea5a0412021-01-18 16:40:08 -08001109 if (msync_session_set_mode(avsync->fd, mode)) {
1110 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001111 return -1;
1112 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001113 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001114 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001115 return 0;
1116}
1117
Song Zhao01031bb2021-05-13 21:23:20 -07001118int av_sync_get_mode(void *sync, enum sync_mode *mode)
1119{
1120 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1121
1122 if (!avsync || !mode)
1123 return -1;
1124
1125 *mode = avsync->mode;
1126 return 0;
1127}
1128
Song Zhaoc03ba122020-12-23 21:54:02 -08001129int av_sync_set_pause_pts(void *sync, pts90K pts)
1130{
1131 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1132
1133 if (!avsync)
1134 return -1;
1135
1136 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001137 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001138 return 0;
1139}
1140
1141int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1142{
1143 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1144
1145 if (!avsync)
1146 return -1;
1147
1148 avsync->pause_pts_cb = cb;
1149 avsync->pause_cb_priv = priv;
1150 return 0;
1151}
Song Zhaoea5a0412021-01-18 16:40:08 -08001152
yongchun.li428390d2022-02-17 17:15:40 -08001153int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1154{
1155 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1156
1157 if (!avsync)
1158 return -1;
1159
1160 avsync->underflow_cb = cb;
1161 avsync->underflow_cb_priv = priv;
1162
1163 if (cfg)
1164 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1165 else
1166 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1167
1168 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1169 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1170 avsync->underflow_cfg.time_thresh);
1171 return 0;
1172}
Song Zhaoea5a0412021-01-18 16:40:08 -08001173static void trigger_audio_start_cb(struct av_sync_session *avsync,
1174 avs_ascb_reason reason)
1175{
1176 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001177 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001178 pthread_mutex_lock(&avsync->lock);
1179 if (avsync->audio_start) {
1180 avsync->audio_start(avsync->audio_start_priv, reason);
1181 avsync->session_started = true;
1182 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001183 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001184 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1185 }
1186 pthread_mutex_unlock(&avsync->lock);
1187 }
1188}
1189
1190avs_start_ret av_sync_audio_start(
1191 void *sync,
1192 pts90K pts,
1193 pts90K delay,
1194 audio_start_cb cb,
1195 void *priv)
1196{
1197 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1198 uint32_t start_mode;
yongchun.li59e873d2021-07-07 11:42:38 -07001199 uint32_t systime;
Song Zhaoea5a0412021-01-18 16:40:08 -08001200 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1201 bool create_poll_t = false;
1202
1203 if (!avsync)
1204 return ret;
1205
yongchun.li59e873d2021-07-07 11:42:38 -07001206 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1207 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001208
yongchun.li59e873d2021-07-07 11:42:38 -07001209 if (avsync->in_audio_switch &&
1210 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1211 {
1212 start_mode = AVS_START_SYNC;
1213 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1214 } else {
1215 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1216 log_error("[%d]fail to set audio start", avsync->session_id);
1217 }
1218 if (avsync->in_audio_switch &&
1219 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1220 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
1221 msync_session_get_wall(avsync->fd, &systime, NULL);
1222 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB &&
1223 start_mode == AVS_START_SYNC) {
1224 log_info("%d audio_switch audio need drop first.ahead %d ms",
1225 avsync->session_id, (int)(systime - pts)/90);
1226 ret = AV_SYNC_ASTART_AGAIN;
1227 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1228 goto exit;
1229 }
1230 else {
1231 int diff = (int)(pts - systime);
1232 log_info("%d audio_switch_state to start mode %d diff %d ms",
1233 avsync->session_id, start_mode, diff/90);
1234 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
1235 if (diff < A_ADJ_THREDHOLD_LB) {
1236 log_info("%d orig mode %d already close enough direct start",
1237 avsync->session_id, start_mode);
1238 start_mode = AVS_START_SYNC;
1239 }
1240 }
yongchun.li107a6162021-05-05 02:38:57 -07001241 }
1242
Song Zhaoea5a0412021-01-18 16:40:08 -08001243 if (start_mode == AVS_START_SYNC) {
1244 ret = AV_SYNC_ASTART_SYNC;
1245 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001246 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001247 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001248 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001249 avsync->state = AV_SYNC_STAT_RUNNING;
1250 } else if (start_mode == AVS_START_AGAIN) {
1251 ret = AV_SYNC_ASTART_AGAIN;
1252 }
1253
1254 if (ret == AV_SYNC_ASTART_AGAIN)
1255 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001256
Song Zhao76005282022-03-08 16:49:41 -08001257 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1258 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001259 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001260
1261 if (start_mode == AVS_START_ASYNC) {
1262 if (!cb) {
1263 log_error("[%d]invalid cb", avsync->session_id);
1264 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001265 }
Song Zhao76005282022-03-08 16:49:41 -08001266 avsync->audio_start = cb;
1267 avsync->audio_start_priv = priv;
1268 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001269
Song Zhaod62bb392021-04-23 12:25:49 -07001270 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001271 int ret;
1272
1273 log_info("[%d]start poll thread", avsync->session_id);
1274 avsync->quit_poll = false;
1275 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1276 if (ret) {
1277 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1278 return AV_SYNC_ASTART_ERR;
1279 }
1280 }
Song Zhaod62bb392021-04-23 12:25:49 -07001281 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001282 msync_session_get_wall(avsync->fd, &systime, NULL);
1283 log_info("[%d]return %u w %u pts %u d %u",
1284 avsync->session_id, ret, systime, pts, delay);
1285 }
1286exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001287 log_info("[%d]return %u", avsync->session_id, ret);
1288 return ret;
1289}
1290
1291int av_sync_audio_render(
1292 void *sync,
1293 pts90K pts,
1294 struct audio_policy *policy)
1295{
1296 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001297 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001298 uint32_t systime;
1299 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1300 avs_audio_action action = AA_SYNC_AA_MAX;
1301
1302 if (!avsync || !policy)
1303 return -1;
1304
yongchun.li107a6162021-05-05 02:38:57 -07001305 msync_session_get_wall(avsync->fd, &systime, NULL);
1306
1307 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1308 pts, systime, avsync->mode, (int)(pts-systime)/90);
1309
1310 if (avsync->in_audio_switch
1311 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
1312 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
1313 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1314 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1315 action = AV_SYNC_AA_RENDER;
1316 } else if ((int)(systime - pts) > 0) {
1317 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1318 (int)(systime - pts)/90, systime, pts);
1319 action = AV_SYNC_AA_DROP;
1320 } else {
1321 action = AV_SYNC_AA_INSERT;
1322 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1323 (int)(pts - systime)/90, systime, pts);
1324 }
1325 goto done;
1326 }
1327
Song Zhaoea5a0412021-01-18 16:40:08 -08001328 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1329 avsync->mode == AV_SYNC_MODE_AMASTER) {
1330 action = AV_SYNC_AA_RENDER;
1331 goto done;
1332 }
1333
Song Zhaod62bb392021-04-23 12:25:49 -07001334 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001335 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001336 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1337 action = AV_SYNC_AA_DROP;
1338 goto done;
1339 }
1340
Song Zhao7daf3a12021-05-10 22:22:25 -07001341 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1342 avsync->mode == AV_SYNC_MODE_AMASTER) {
1343 action = AV_SYNC_AA_RENDER;
1344 goto done;
1345 }
1346
Song Zhaod62bb392021-04-23 12:25:49 -07001347 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1348 LIVE_MODE(avsync->mode) &&
1349 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1350 /* outlier by stream error */
1351 avsync->outlier_cnt++;
1352 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1353 /* treat as disc, just drop current frame */
1354 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1355 avsync->outlier_cnt = 0;
1356 action = AV_SYNC_AA_DROP;
1357 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001358 goto done;
1359 }
1360 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1361 pts = systime;
1362 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001363 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001364 goto done;
1365 }
1366
1367 avsync->outlier_cnt = 0;
1368 /* low bound from sync_lost to sync_setup */
1369 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1370 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1371 action = AV_SYNC_AA_RENDER;
1372 goto done;
1373 }
1374
1375 /* high bound of sync_setup */
1376 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1377 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1378 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001379 action = AV_SYNC_AA_RENDER;
1380 goto done;
1381 }
1382
1383 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001384 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001385 action = AV_SYNC_AA_DROP;
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_INSERT;
1392 goto done;
1393 }
1394
1395done:
1396 policy->action = action;
1397 policy->delta = (int)(systime - pts);
1398 if (action == AV_SYNC_AA_RENDER) {
1399 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001400 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001401 if (!out_lier)
1402 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001403 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001404 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001405 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1406 msync_session_update_apts(avsync->fd, systime, pts, 0);
1407 log_info("[%d] audio switch done sys %u pts %u",
1408 avsync->session_id, systime, pts);
1409 msync_session_set_audio_switch(avsync->fd, false);
1410 avsync->in_audio_switch = false;
1411 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1412 } else {
1413 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1414 avsync->session_id, action, systime, pts, systime - pts);
1415 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001416 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001417 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001418 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001419 avsync->last_disc_pts != pts &&
1420 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001421 log_info ("[%d]audio disc %u --> %u",
1422 avsync->session_id, systime, pts);
1423 msync_session_set_audio_dis(avsync->fd, pts);
1424 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001425 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001426 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001427
1428 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001429 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001430 if (!avsync->audio_drop_cnt)
1431 avsync->audio_drop_start = now;
1432 avsync->audio_drop_cnt++;
1433 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1434 log_info ("[%d]audio keep dropping sys %u vs a %u",
1435 avsync->session_id, systime, pts);
1436 msync_session_set_audio_dis(avsync->fd, pts);
1437 }
Song Zhao409739b2021-05-12 22:21:40 -07001438 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001439 if (action != AV_SYNC_AA_DROP)
1440 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001441 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001442 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001443 }
1444
1445 return ret;
1446}
1447
1448int av_sync_get_clock(void *sync, pts90K *pts)
1449{
1450 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1451
1452 if (!avsync || !pts)
1453 return -1;
1454 return msync_session_get_wall(avsync->fd, pts, NULL);
1455}
1456
1457static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001458 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001459 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001460{
Song Zhao76005282022-03-08 16:49:41 -08001461 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1462 avsync->session_id, avsync->active_mode, avsync->mode,
1463 v_active, a_active, v_timeout, stat);
1464
1465 /* iptv delayed start */
1466 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1467 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1468
Song Zhaoea5a0412021-01-18 16:40:08 -08001469 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1470 float speed;
Song Zhao7e8c68f2022-07-12 16:24:30 -07001471 if (a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001472 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001473 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhao6183ca92022-07-29 09:57:03 -07001474 } else if (!a_active && !avsync->session_started) {
1475 /* quit waiting ASAP */
1476 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoea5a0412021-01-18 16:40:08 -08001477 }
1478
1479 if (!msync_session_get_rate(avsync->fd, &speed)) {
1480 /* speed change is triggered by asink,
1481 * attached audio HAL will handle it
1482 */
1483 if (speed != avsync->speed)
1484 log_info("[%d]new rate %f", avsync->session_id, speed);
1485 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001486 if (avsync->mode != avsync->backup_mode) {
1487 avsync->mode = avsync->backup_mode;
1488 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1489 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001490 } else {
1491 avsync->backup_mode = avsync->mode;
1492 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1493 log_info("[%d]audio to freerun mode", avsync->session_id);
1494 }
1495 avsync->speed = speed;
1496 }
Song Zhaod62bb392021-04-23 12:25:49 -07001497 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1498 struct session_debug debug;
1499 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001500 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001501 avsync->backup_mode = avsync->mode;
1502 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001503 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001504 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001505 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001506 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001507 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001508 log_warn("[%d]audio back to mode %d",
1509 avsync->session_id, avsync->mode);
1510 }
1511 }
Song Zhao76005282022-03-08 16:49:41 -08001512 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1513 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001514 }
1515}
1516
1517static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001518 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001519 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001520{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001521 struct session_debug debug;
1522
Song Zhao76005282022-03-08 16:49:41 -08001523 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1524 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001525 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1526 if (debug.debug_freerun && !avsync->debug_freerun) {
1527 avsync->backup_mode = avsync->mode;
1528 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1529 avsync->debug_freerun = true;
1530 log_warn("[%d]video to freerun mode", avsync->session_id);
1531 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1532 avsync->mode = avsync->backup_mode;
1533 avsync->debug_freerun = false;
1534 log_warn("[%d]video back to mode %d",
1535 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001536 }
1537 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001538}
1539
1540static void * poll_thread(void * arg)
1541{
1542 int ret = 0;
1543 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1544 const int fd = avsync->fd;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001545 int poll_timeout = 10;
Song Zhaoea5a0412021-01-18 16:40:08 -08001546 struct pollfd pfd = {
1547 /* default blocking capture */
1548 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1549 .fd = avsync->fd,
1550 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001551 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001552
1553 prctl (PR_SET_NAME, "avs_poll");
1554 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001555
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001556 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001557 sflag = SRC_A;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001558 } else if (avsync->type == AV_SYNC_TYPE_VIDEO) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001559 sflag = SRC_V;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001560 poll_timeout = 100;
1561 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001562
Song Zhaoea5a0412021-01-18 16:40:08 -08001563 while (!avsync->quit_poll) {
1564 for (;;) {
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001565 ret = poll(&pfd, 1, poll_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001566 if (ret > 0)
1567 break;
1568 if (avsync->quit_poll)
1569 goto exit;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001570 if (errno == EINTR) {
1571 log_debug("[%d] poll interrupted", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001572 continue;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001573 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001574 }
1575
1576 /* error handling */
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001577 if (pfd.revents & POLLERR) {
1578 usleep(poll_timeout * 1000);
1579 continue;
1580 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001581
Song Zhaod62bb392021-04-23 12:25:49 -07001582 /* mode change. Non-exclusive wait so all the processes
1583 * shall be woken up
1584 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001585 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001586 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001587 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001588
Song Zhao9fef59c2022-08-17 12:43:10 -07001589 msync_session_get_stat(fd, true, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001590 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001591
1592 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001593 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001594 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001595 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001596 usleep(10000);
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001597 } else {
1598 log_debug("[%d] unexpected revents %x", avsync->session_id, pfd.revents);
1599 usleep(poll_timeout * 1000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001600 }
1601 }
1602exit:
1603 log_info("[%d]quit", avsync->session_id);
1604 return NULL;
1605}
1606
Song Zhao623e2f12021-09-03 15:54:04 -07001607#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1608/* return ppm between demod and PCR clock */
1609int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1610{
1611 int fd = -1, ppm = 0, nread;
1612 char buf[128];
1613 uint32_t reg_v, lock;
1614 float val;
1615
1616 fd = open(DEMOD_NODE, O_RDWR);
1617 if (fd < 0) {
1618 log_warn("node not found %s", DEMOD_NODE);
1619 /* do not retry */
1620 avsync->ppm_adjusted = true;
1621 return 0;
1622 }
1623 snprintf(buf, sizeof(buf), "%d", 5);
1624 write(fd, buf, 2);
1625
1626 lseek(fd, 0, SEEK_SET);
1627
hanghang.luo02efd312022-08-26 09:49:53 +08001628 nread = read(fd, buf, sizeof(buf)-1);
Song Zhao623e2f12021-09-03 15:54:04 -07001629 if (nread <= 0) {
1630 log_error("read error");
1631 goto err;
1632 }
1633 buf[nread] = 0;
1634 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1635 log_error("wrong format %s", buf);
1636 goto err;
1637 }
1638 if (lock != 0x1f) {
1639 log_info("demod not locked");
1640 goto err;
1641 }
1642 if (reg_v > ((2 << 20) - 1))
1643 reg_v -= (2 << 21);
1644 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1645 ppm = val;
1646 log_info("ppm from SFO %d", ppm);
1647 avsync->ppm_adjusted = true;
1648
1649err:
1650 if (fd >= 0)
1651 close(fd);
1652 return ppm;
1653}
1654
Song Zhaod62bb392021-04-23 12:25:49 -07001655int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001656{
1657 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001658 struct pcr_info pcr;
1659 enum pcr_monitor_status status;
1660 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001661 if (!avsync)
1662 return -1;
1663
1664 if (avsync->type != AV_SYNC_TYPE_PCR)
1665 return -2;
1666
Song Zhao623e2f12021-09-03 15:54:04 -07001667 /* initial estimation from Demod SFO HW */
1668 if (!avsync->ppm_adjusted) {
1669 ppm = dmod_get_sfo_dev(avsync);
1670 if (ppm != 0) {
1671 /* ppm > 0 means board clock is faster */
1672 msync_session_set_clock_dev(avsync->fd, -ppm);
1673 }
1674 }
wei.dubcc2ed22021-05-19 07:16:10 -04001675 pcr.monoclk = mono_clock / 1000;
1676 pcr.pts = (long long) pts * 1000 / 90;
1677 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1678
1679 status = pcr_monitor_get_status(avsync->pcr_monitor);
1680
1681 if (status >= DEVIATION_READY) {
1682 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1683 if (avsync->ppm != ppm) {
1684 avsync->ppm = ppm;
1685 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1686 if (msync_session_set_clock_dev(avsync->fd, ppm))
1687 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001688 else
1689 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001690 }
1691 }
1692
Song Zhaod62bb392021-04-23 12:25:49 -07001693 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001694}
1695
Song Zhaod62bb392021-04-23 12:25:49 -07001696int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001697{
1698 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1699
1700 if (!avsync)
1701 return -1;
1702
Song Zhaod62bb392021-04-23 12:25:49 -07001703 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001704}
1705
1706int av_sync_set_session_name(void *sync, const char *name)
1707{
1708 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1709
1710 if (!avsync)
1711 return -1;
1712
1713 return msync_session_set_name(avsync->fd, name);
1714}
yongchun.li107a6162021-05-05 02:38:57 -07001715
1716int av_sync_set_audio_switch(void *sync, bool start)
1717{
1718 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1719 bool v_active, a_active, v_timeout;
1720
1721 if (!avsync)
1722 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001723 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001724 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001725 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001726 log_error("[%d] can not get session state",
1727 avsync->session_id);
1728 return -1;
1729 }
1730 if (!v_active || !a_active) {
1731 log_error("[%d] no apply if not AV both active v %d a %d",
1732 avsync->session_id, v_active, a_active);
1733 return -1;
1734 }
1735 if (msync_session_set_audio_switch(avsync->fd, start)) {
1736 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1737 return -1;
1738 }
1739 avsync->in_audio_switch = start;
1740 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1741 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1742 return 0;
1743}
1744
1745int av_sync_get_audio_switch(void *sync, bool *start)
1746{
1747 struct av_sync_session *avsync = (struct av_sync_session *)sync;
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,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001752 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001753 log_error("[%d] can not audio seamless switch state",
1754 avsync->session_id);
1755 return -1;
1756 }
1757 if (start) *start = avsync->in_audio_switch;
1758 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001759}
Song Zhao8039f562021-05-18 18:11:25 -07001760
Song Zhao623e2f12021-09-03 15:54:04 -07001761enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001762{
1763 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1764
wei.dubcc2ed22021-05-19 07:16:10 -04001765 if (!avsync || !ppm)
1766 return CLK_RECOVERY_ERR;
1767 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001768 return CLK_RECOVERY_NOT_RUNNING;
1769
wei.dubcc2ed22021-05-19 07:16:10 -04001770 if (msync_session_get_clock_dev(avsync->fd, ppm))
1771 return CLK_RECOVERY_ERR;
1772
1773 if (*ppm == 0)
1774 return CLK_RECOVERY_ONGOING;
1775 else
1776 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001777}
Song Zhao95bd0922021-09-21 14:07:46 -07001778
1779static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1780{
1781 int ret;
1782
1783 if (!avsync->frame_q) {
1784 avsync->frame_q = create_q(MAX_FRAME_NUM);
1785 if (!avsync->frame_q) {
1786 log_error("[%d]create queue fail", avsync->session_id);
1787
1788 return -1;
1789 }
1790 }
1791
1792 ret = queue_item(avsync->frame_q, frame);
1793 if (ret)
hanghang.luo02efd312022-08-26 09:49:53 +08001794 log_error("queue fail:%d", ret);
Song Zhao95bd0922021-09-21 14:07:46 -07001795 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1796 return ret;
1797}
1798
1799int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1800{
1801 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1802
1803 if (!avsync)
1804 return -1;
1805 avsync->msys = msys;
1806 return 0;
1807}
1808
1809static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1810{
1811 struct vframe *frame = NULL, *enter_last_frame = NULL;
1812 uint64_t systime;
1813 int toggle_cnt = 0;
1814
1815 enter_last_frame = avsync->last_frame;
1816 systime = avsync->msys;
1817 log_debug("[%d]sys %llu", avsync->session_id, systime);
1818 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1819 if (systime >= frame->mts) {
1820 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1821 toggle_cnt++;
1822
1823 if (avsync->last_frame)
1824 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1825
1826 dqueue_item(avsync->frame_q, (void **)&frame);
1827 if (avsync->last_frame) {
1828 /* free frame that are not for display */
1829 if (toggle_cnt > 1) {
1830 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1831 avsync->last_frame->mts, frame->mts, systime);
1832 avsync->last_frame->free(avsync->last_frame);
1833 }
1834 } else {
1835 avsync->first_frame_toggled = true;
1836 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1837 }
1838 avsync->last_frame = frame;
1839 } else
1840 break;
1841 }
1842
1843 if (avsync->last_frame) {
1844 if (enter_last_frame != avsync->last_frame)
hanghang.luo02efd312022-08-26 09:49:53 +08001845 log_debug("[%d]pop %lu", avsync->session_id, avsync->last_frame->pts);
1846 log_trace("[%d]pop=%llu, system=%llu, diff %llu(ms), QNum=%d", avsync->session_id,
Song Zhao95bd0922021-09-21 14:07:46 -07001847 avsync->last_frame->mts,
1848 systime, (systime - avsync->last_frame->mts) / 1000000,
1849 queue_size(avsync->frame_q));
1850 } else
1851 if (enter_last_frame != avsync->last_frame)
1852 log_debug("[%d]pop (nil)", avsync->session_id);
1853
1854 if (avsync->last_frame)
1855 avsync->last_frame->hold_period++;
1856 return avsync->last_frame;
1857}
Song Zhao6183ca92022-07-29 09:57:03 -07001858
1859int avs_sync_stop_audio(void *sync)
1860{
1861 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1862
1863 if (!avsync)
1864 return -1;
1865
1866 return msync_session_stop_audio(avsync->fd);
1867}