blob: d5903181a2a633cdc94799113c258b5fbcbe973a [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 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);
Song Zhao4bd18762022-09-30 16:39:52 -07001222 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB
1223 && start_mode == AVS_START_SYNC) {
yongchun.li59e873d2021-07-07 11:42:38 -07001224 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);
yongchun.li59e873d2021-07-07 11:42:38 -07001234 if (diff < A_ADJ_THREDHOLD_LB) {
1235 log_info("%d orig mode %d already close enough direct start",
1236 avsync->session_id, start_mode);
1237 start_mode = AVS_START_SYNC;
Song Zhao4bd18762022-09-30 16:39:52 -07001238 } else if (start_mode != AVS_START_ASYNC) {
1239 log_info("%d drop too far mode %d need to try ASYNC",
1240 avsync->session_id, start_mode);
1241 msync_session_set_audio_stop(avsync->fd);
1242 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1243 log_error("[%d]fail to set audio start", avsync->session_id);
1244 log_info("%d New start mode %d",
1245 avsync->session_id, start_mode);
yongchun.li59e873d2021-07-07 11:42:38 -07001246 }
Song Zhao4bd18762022-09-30 16:39:52 -07001247 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
yongchun.li59e873d2021-07-07 11:42:38 -07001248 }
yongchun.li107a6162021-05-05 02:38:57 -07001249 }
1250
Song Zhaoea5a0412021-01-18 16:40:08 -08001251 if (start_mode == AVS_START_SYNC) {
1252 ret = AV_SYNC_ASTART_SYNC;
1253 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001254 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001255 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001256 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001257 avsync->state = AV_SYNC_STAT_RUNNING;
1258 } else if (start_mode == AVS_START_AGAIN) {
1259 ret = AV_SYNC_ASTART_AGAIN;
1260 }
1261
1262 if (ret == AV_SYNC_ASTART_AGAIN)
1263 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001264
Song Zhao76005282022-03-08 16:49:41 -08001265 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1266 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001267 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001268
1269 if (start_mode == AVS_START_ASYNC) {
1270 if (!cb) {
1271 log_error("[%d]invalid cb", avsync->session_id);
1272 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001273 }
Song Zhao76005282022-03-08 16:49:41 -08001274 avsync->audio_start = cb;
1275 avsync->audio_start_priv = priv;
1276 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001277
Song Zhaod62bb392021-04-23 12:25:49 -07001278 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001279 int ret;
1280
1281 log_info("[%d]start poll thread", avsync->session_id);
1282 avsync->quit_poll = false;
1283 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1284 if (ret) {
1285 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1286 return AV_SYNC_ASTART_ERR;
1287 }
1288 }
Song Zhaod62bb392021-04-23 12:25:49 -07001289 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001290 msync_session_get_wall(avsync->fd, &systime, NULL);
1291 log_info("[%d]return %u w %u pts %u d %u",
1292 avsync->session_id, ret, systime, pts, delay);
1293 }
1294exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001295 log_info("[%d]return %u", avsync->session_id, ret);
1296 return ret;
1297}
1298
1299int av_sync_audio_render(
1300 void *sync,
1301 pts90K pts,
1302 struct audio_policy *policy)
1303{
1304 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001305 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001306 uint32_t systime;
1307 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1308 avs_audio_action action = AA_SYNC_AA_MAX;
1309
1310 if (!avsync || !policy)
1311 return -1;
1312
yongchun.li107a6162021-05-05 02:38:57 -07001313 msync_session_get_wall(avsync->fd, &systime, NULL);
1314
1315 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1316 pts, systime, avsync->mode, (int)(pts-systime)/90);
1317
1318 if (avsync->in_audio_switch
1319 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
Song Zhao4bd18762022-09-30 16:39:52 -07001320 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_MB) {
yongchun.li107a6162021-05-05 02:38:57 -07001321 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1322 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1323 action = AV_SYNC_AA_RENDER;
1324 } else if ((int)(systime - pts) > 0) {
1325 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1326 (int)(systime - pts)/90, systime, pts);
1327 action = AV_SYNC_AA_DROP;
1328 } else {
1329 action = AV_SYNC_AA_INSERT;
1330 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1331 (int)(pts - systime)/90, systime, pts);
1332 }
1333 goto done;
1334 }
1335
Song Zhaoea5a0412021-01-18 16:40:08 -08001336 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1337 avsync->mode == AV_SYNC_MODE_AMASTER) {
1338 action = AV_SYNC_AA_RENDER;
1339 goto done;
1340 }
1341
Song Zhaod62bb392021-04-23 12:25:49 -07001342 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001343 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001344 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1345 action = AV_SYNC_AA_DROP;
1346 goto done;
1347 }
1348
Song Zhao7daf3a12021-05-10 22:22:25 -07001349 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1350 avsync->mode == AV_SYNC_MODE_AMASTER) {
1351 action = AV_SYNC_AA_RENDER;
1352 goto done;
1353 }
1354
Song Zhaod62bb392021-04-23 12:25:49 -07001355 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1356 LIVE_MODE(avsync->mode) &&
1357 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1358 /* outlier by stream error */
1359 avsync->outlier_cnt++;
1360 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1361 /* treat as disc, just drop current frame */
1362 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1363 avsync->outlier_cnt = 0;
1364 action = AV_SYNC_AA_DROP;
1365 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001366 goto done;
1367 }
1368 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1369 pts = systime;
1370 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001371 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001372 goto done;
1373 }
1374
1375 avsync->outlier_cnt = 0;
1376 /* low bound from sync_lost to sync_setup */
1377 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1378 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1379 action = AV_SYNC_AA_RENDER;
1380 goto done;
1381 }
1382
1383 /* high bound of sync_setup */
1384 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1385 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1386 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001387 action = AV_SYNC_AA_RENDER;
1388 goto done;
1389 }
1390
1391 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001392 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001393 action = AV_SYNC_AA_DROP;
1394 goto done;
1395 }
1396
1397 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001398 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001399 action = AV_SYNC_AA_INSERT;
1400 goto done;
1401 }
1402
1403done:
1404 policy->action = action;
1405 policy->delta = (int)(systime - pts);
1406 if (action == AV_SYNC_AA_RENDER) {
1407 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001408 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001409 if (!out_lier)
1410 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001411 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001412 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001413 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1414 msync_session_update_apts(avsync->fd, systime, pts, 0);
1415 log_info("[%d] audio switch done sys %u pts %u",
1416 avsync->session_id, systime, pts);
1417 msync_session_set_audio_switch(avsync->fd, false);
1418 avsync->in_audio_switch = false;
1419 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1420 } else {
1421 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1422 avsync->session_id, action, systime, pts, systime - pts);
1423 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001424 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001425 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001426 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001427 avsync->last_disc_pts != pts &&
1428 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001429 log_info ("[%d]audio disc %u --> %u",
1430 avsync->session_id, systime, pts);
1431 msync_session_set_audio_dis(avsync->fd, pts);
1432 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001433 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001434 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001435
1436 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001437 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001438 if (!avsync->audio_drop_cnt)
1439 avsync->audio_drop_start = now;
1440 avsync->audio_drop_cnt++;
1441 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1442 log_info ("[%d]audio keep dropping sys %u vs a %u",
1443 avsync->session_id, systime, pts);
1444 msync_session_set_audio_dis(avsync->fd, pts);
1445 }
Song Zhao409739b2021-05-12 22:21:40 -07001446 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001447 if (action != AV_SYNC_AA_DROP)
1448 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001449 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001450 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001451 }
1452
1453 return ret;
1454}
1455
1456int av_sync_get_clock(void *sync, pts90K *pts)
1457{
1458 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1459
1460 if (!avsync || !pts)
1461 return -1;
1462 return msync_session_get_wall(avsync->fd, pts, NULL);
1463}
1464
1465static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001466 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001467 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001468{
Song Zhao76005282022-03-08 16:49:41 -08001469 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1470 avsync->session_id, avsync->active_mode, avsync->mode,
1471 v_active, a_active, v_timeout, stat);
1472
1473 /* iptv delayed start */
1474 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1475 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1476
Song Zhaoea5a0412021-01-18 16:40:08 -08001477 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1478 float speed;
Song Zhao7e8c68f2022-07-12 16:24:30 -07001479 if (a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001480 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001481 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhao6183ca92022-07-29 09:57:03 -07001482 } else if (!a_active && !avsync->session_started) {
1483 /* quit waiting ASAP */
1484 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoea5a0412021-01-18 16:40:08 -08001485 }
1486
1487 if (!msync_session_get_rate(avsync->fd, &speed)) {
1488 /* speed change is triggered by asink,
1489 * attached audio HAL will handle it
1490 */
1491 if (speed != avsync->speed)
1492 log_info("[%d]new rate %f", avsync->session_id, speed);
1493 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001494 if (avsync->mode != avsync->backup_mode) {
1495 avsync->mode = avsync->backup_mode;
1496 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1497 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001498 } else {
1499 avsync->backup_mode = avsync->mode;
1500 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1501 log_info("[%d]audio to freerun mode", avsync->session_id);
1502 }
1503 avsync->speed = speed;
1504 }
Song Zhaod62bb392021-04-23 12:25:49 -07001505 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1506 struct session_debug debug;
1507 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001508 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001509 avsync->backup_mode = avsync->mode;
1510 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001511 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001512 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001513 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001514 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001515 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001516 log_warn("[%d]audio back to mode %d",
1517 avsync->session_id, avsync->mode);
1518 }
1519 }
Song Zhao76005282022-03-08 16:49:41 -08001520 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1521 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001522 }
1523}
1524
1525static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001526 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001527 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001528{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001529 struct session_debug debug;
1530
Song Zhao76005282022-03-08 16:49:41 -08001531 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1532 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001533 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1534 if (debug.debug_freerun && !avsync->debug_freerun) {
1535 avsync->backup_mode = avsync->mode;
1536 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1537 avsync->debug_freerun = true;
1538 log_warn("[%d]video to freerun mode", avsync->session_id);
1539 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1540 avsync->mode = avsync->backup_mode;
1541 avsync->debug_freerun = false;
1542 log_warn("[%d]video back to mode %d",
1543 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001544 }
1545 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001546}
1547
1548static void * poll_thread(void * arg)
1549{
1550 int ret = 0;
1551 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1552 const int fd = avsync->fd;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001553 int poll_timeout = 10;
Song Zhaoea5a0412021-01-18 16:40:08 -08001554 struct pollfd pfd = {
1555 /* default blocking capture */
Song Zhao4bd18762022-09-30 16:39:52 -07001556 .events = POLLPRI,
Song Zhaoea5a0412021-01-18 16:40:08 -08001557 .fd = avsync->fd,
1558 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001559 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001560
Song Zhaoea5a0412021-01-18 16:40:08 -08001561 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001562
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001563 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001564 prctl (PR_SET_NAME, "avs_apoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001565 sflag = SRC_A;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001566 } else if (avsync->type == AV_SYNC_TYPE_VIDEO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001567 prctl (PR_SET_NAME, "avs_vpoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001568 sflag = SRC_V;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001569 poll_timeout = 100;
1570 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001571
Song Zhaoea5a0412021-01-18 16:40:08 -08001572 while (!avsync->quit_poll) {
1573 for (;;) {
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001574 ret = poll(&pfd, 1, poll_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001575 if (ret > 0)
1576 break;
1577 if (avsync->quit_poll)
1578 goto exit;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001579 if (errno == EINTR) {
1580 log_debug("[%d] poll interrupted", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001581 continue;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001582 }
Song Zhao4bd18762022-09-30 16:39:52 -07001583 if (errno == EAGAIN || errno == ENOMEM) {
1584 log_info("[%d] poll error %d", avsync->session_id, errno);
1585 continue;
1586 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001587 }
1588
1589 /* error handling */
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001590 if (pfd.revents & POLLERR) {
1591 usleep(poll_timeout * 1000);
1592 continue;
1593 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001594
Song Zhao4bd18762022-09-30 16:39:52 -07001595 if (pfd.revents & POLLNVAL) {
1596 log_warn("[%d] fd closed", avsync->session_id);
1597 goto exit;
1598 }
Song Zhaod62bb392021-04-23 12:25:49 -07001599 /* mode change. Non-exclusive wait so all the processes
1600 * shall be woken up
1601 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001602 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001603 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001604 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001605
Song Zhao9fef59c2022-08-17 12:43:10 -07001606 msync_session_get_stat(fd, true, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001607 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001608
1609 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001610 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001611 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001612 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001613 usleep(10000);
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001614 } else {
1615 log_debug("[%d] unexpected revents %x", avsync->session_id, pfd.revents);
1616 usleep(poll_timeout * 1000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001617 }
1618 }
1619exit:
1620 log_info("[%d]quit", avsync->session_id);
1621 return NULL;
1622}
1623
Song Zhao623e2f12021-09-03 15:54:04 -07001624#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1625/* return ppm between demod and PCR clock */
1626int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1627{
1628 int fd = -1, ppm = 0, nread;
1629 char buf[128];
1630 uint32_t reg_v, lock;
1631 float val;
1632
1633 fd = open(DEMOD_NODE, O_RDWR);
1634 if (fd < 0) {
1635 log_warn("node not found %s", DEMOD_NODE);
1636 /* do not retry */
1637 avsync->ppm_adjusted = true;
1638 return 0;
1639 }
1640 snprintf(buf, sizeof(buf), "%d", 5);
1641 write(fd, buf, 2);
1642
1643 lseek(fd, 0, SEEK_SET);
1644
hanghang.luo02efd312022-08-26 09:49:53 +08001645 nread = read(fd, buf, sizeof(buf)-1);
Song Zhao623e2f12021-09-03 15:54:04 -07001646 if (nread <= 0) {
1647 log_error("read error");
1648 goto err;
1649 }
1650 buf[nread] = 0;
1651 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1652 log_error("wrong format %s", buf);
1653 goto err;
1654 }
1655 if (lock != 0x1f) {
1656 log_info("demod not locked");
1657 goto err;
1658 }
1659 if (reg_v > ((2 << 20) - 1))
1660 reg_v -= (2 << 21);
1661 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1662 ppm = val;
1663 log_info("ppm from SFO %d", ppm);
1664 avsync->ppm_adjusted = true;
1665
1666err:
1667 if (fd >= 0)
1668 close(fd);
1669 return ppm;
1670}
1671
Song Zhaod62bb392021-04-23 12:25:49 -07001672int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001673{
1674 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001675 struct pcr_info pcr;
1676 enum pcr_monitor_status status;
1677 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001678 if (!avsync)
1679 return -1;
1680
1681 if (avsync->type != AV_SYNC_TYPE_PCR)
1682 return -2;
1683
Song Zhao623e2f12021-09-03 15:54:04 -07001684 /* initial estimation from Demod SFO HW */
1685 if (!avsync->ppm_adjusted) {
1686 ppm = dmod_get_sfo_dev(avsync);
1687 if (ppm != 0) {
1688 /* ppm > 0 means board clock is faster */
1689 msync_session_set_clock_dev(avsync->fd, -ppm);
1690 }
1691 }
wei.dubcc2ed22021-05-19 07:16:10 -04001692 pcr.monoclk = mono_clock / 1000;
1693 pcr.pts = (long long) pts * 1000 / 90;
1694 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1695
1696 status = pcr_monitor_get_status(avsync->pcr_monitor);
1697
1698 if (status >= DEVIATION_READY) {
1699 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1700 if (avsync->ppm != ppm) {
1701 avsync->ppm = ppm;
1702 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1703 if (msync_session_set_clock_dev(avsync->fd, ppm))
1704 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001705 else
1706 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001707 }
1708 }
1709
Song Zhaod62bb392021-04-23 12:25:49 -07001710 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001711}
1712
Song Zhaod62bb392021-04-23 12:25:49 -07001713int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001714{
1715 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1716
1717 if (!avsync)
1718 return -1;
1719
Song Zhaod62bb392021-04-23 12:25:49 -07001720 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001721}
1722
1723int av_sync_set_session_name(void *sync, const char *name)
1724{
1725 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1726
1727 if (!avsync)
1728 return -1;
1729
1730 return msync_session_set_name(avsync->fd, name);
1731}
yongchun.li107a6162021-05-05 02:38:57 -07001732
1733int av_sync_set_audio_switch(void *sync, bool start)
1734{
1735 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1736 bool v_active, a_active, v_timeout;
1737
1738 if (!avsync)
1739 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001740 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001741 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001742 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001743 log_error("[%d] can not get session state",
1744 avsync->session_id);
1745 return -1;
1746 }
1747 if (!v_active || !a_active) {
1748 log_error("[%d] no apply if not AV both active v %d a %d",
1749 avsync->session_id, v_active, a_active);
1750 return -1;
1751 }
1752 if (msync_session_set_audio_switch(avsync->fd, start)) {
1753 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1754 return -1;
1755 }
1756 avsync->in_audio_switch = start;
1757 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1758 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1759 return 0;
1760}
1761
1762int av_sync_get_audio_switch(void *sync, bool *start)
1763{
1764 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1765
1766 if (!avsync)
1767 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001768 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001769 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001770 log_error("[%d] can not audio seamless switch state",
1771 avsync->session_id);
1772 return -1;
1773 }
1774 if (start) *start = avsync->in_audio_switch;
1775 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001776}
Song Zhao8039f562021-05-18 18:11:25 -07001777
Song Zhao623e2f12021-09-03 15:54:04 -07001778enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001779{
1780 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1781
wei.dubcc2ed22021-05-19 07:16:10 -04001782 if (!avsync || !ppm)
1783 return CLK_RECOVERY_ERR;
1784 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001785 return CLK_RECOVERY_NOT_RUNNING;
1786
wei.dubcc2ed22021-05-19 07:16:10 -04001787 if (msync_session_get_clock_dev(avsync->fd, ppm))
1788 return CLK_RECOVERY_ERR;
1789
1790 if (*ppm == 0)
1791 return CLK_RECOVERY_ONGOING;
1792 else
1793 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001794}
Song Zhao95bd0922021-09-21 14:07:46 -07001795
1796static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1797{
1798 int ret;
1799
1800 if (!avsync->frame_q) {
1801 avsync->frame_q = create_q(MAX_FRAME_NUM);
1802 if (!avsync->frame_q) {
1803 log_error("[%d]create queue fail", avsync->session_id);
1804
1805 return -1;
1806 }
1807 }
1808
1809 ret = queue_item(avsync->frame_q, frame);
1810 if (ret)
hanghang.luo02efd312022-08-26 09:49:53 +08001811 log_error("queue fail:%d", ret);
Song Zhao95bd0922021-09-21 14:07:46 -07001812 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1813 return ret;
1814}
1815
1816int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1817{
1818 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1819
1820 if (!avsync)
1821 return -1;
1822 avsync->msys = msys;
1823 return 0;
1824}
1825
1826static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1827{
1828 struct vframe *frame = NULL, *enter_last_frame = NULL;
1829 uint64_t systime;
1830 int toggle_cnt = 0;
1831
1832 enter_last_frame = avsync->last_frame;
1833 systime = avsync->msys;
1834 log_debug("[%d]sys %llu", avsync->session_id, systime);
1835 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1836 if (systime >= frame->mts) {
1837 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1838 toggle_cnt++;
1839
1840 if (avsync->last_frame)
1841 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1842
1843 dqueue_item(avsync->frame_q, (void **)&frame);
1844 if (avsync->last_frame) {
1845 /* free frame that are not for display */
1846 if (toggle_cnt > 1) {
1847 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1848 avsync->last_frame->mts, frame->mts, systime);
1849 avsync->last_frame->free(avsync->last_frame);
1850 }
1851 } else {
1852 avsync->first_frame_toggled = true;
1853 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1854 }
1855 avsync->last_frame = frame;
1856 } else
1857 break;
1858 }
1859
1860 if (avsync->last_frame) {
1861 if (enter_last_frame != avsync->last_frame)
hanghang.luo02efd312022-08-26 09:49:53 +08001862 log_debug("[%d]pop %lu", avsync->session_id, avsync->last_frame->pts);
1863 log_trace("[%d]pop=%llu, system=%llu, diff %llu(ms), QNum=%d", avsync->session_id,
Song Zhao95bd0922021-09-21 14:07:46 -07001864 avsync->last_frame->mts,
1865 systime, (systime - avsync->last_frame->mts) / 1000000,
1866 queue_size(avsync->frame_q));
1867 } else
1868 if (enter_last_frame != avsync->last_frame)
1869 log_debug("[%d]pop (nil)", avsync->session_id);
1870
1871 if (avsync->last_frame)
1872 avsync->last_frame->hold_period++;
1873 return avsync->last_frame;
1874}
Song Zhao6183ca92022-07-29 09:57:03 -07001875
1876int avs_sync_stop_audio(void *sync)
1877{
1878 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1879
1880 if (!avsync)
1881 return -1;
1882
1883 return msync_session_stop_audio(avsync->fd);
1884}