blob: f50ed1a10417f36bd897d324a7d2b7b18487ef7b [file] [log] [blame]
Song Zhaoc03ba122020-12-23 21:54:02 -08001/*
bo.xiao00387eb2023-02-24 18:44:29 +08002 * Copyright (C) 2021 Amlogic Corporation.
Song Zhaoc03ba122020-12-23 21:54:02 -08003 *
bo.xiao00387eb2023-02-24 18:44:29 +08004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Song Zhaoc03ba122020-12-23 21:54:02 -08007 *
bo.xiao00387eb2023-02-24 18:44:29 +08008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Song Zhaoc03ba122020-12-23 21:54:02 -080015 */
Song Zhaoea5a0412021-01-18 16:40:08 -080016#include <errno.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080017#include <pthread.h>
18#include <stdbool.h>
19#include <stdlib.h>
20#include <stdio.h>
21#include <sys/time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080022#include <poll.h>
23#include <fcntl.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <sys/prctl.h>
27#include <sys/ioctl.h>
Song Zhaoa2985cb2021-06-24 12:01:47 -070028#include <time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080029#include <unistd.h>
30//#include <linux/amlogic/msync.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080031#include "aml_avsync.h"
Song Zhao4f632952021-12-16 09:00:18 -080032#include "aml_queue.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080033#include "pattern.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080034#include "aml_avsync_log.h"
Song Zhaoea5a0412021-01-18 16:40:08 -080035#include "msync_util.h"
36#include "msync.h"
37#include <pthread.h>
wei.dubcc2ed22021-05-19 07:16:10 -040038#include "pcr_monitor.h"
fei.deng66b4e812022-04-14 12:23:01 +080039#include "aml_version.h"
Song Zhao2f6744b2021-11-03 21:23:50 -070040
Song Zhaoc03ba122020-12-23 21:54:02 -080041enum sync_state {
42 AV_SYNC_STAT_INIT = 0,
43 AV_SYNC_STAT_RUNNING = 1,
44 AV_SYNC_STAT_SYNC_SETUP = 2,
45 AV_SYNC_STAT_SYNC_LOST = 3,
46};
47
yongchun.li107a6162021-05-05 02:38:57 -070048enum audio_switch_state_ {
49 AUDIO_SWITCH_STAT_INIT = 0,
50 AUDIO_SWITCH_STAT_RESET = 1,
51 AUDIO_SWITCH_STAT_START = 2,
52 AUDIO_SWITCH_STAT_FINISH = 3,
yongchun.li59e873d2021-07-07 11:42:38 -070053 AUDIO_SWITCH_STAT_AGAIN = 4,
yongchun.li107a6162021-05-05 02:38:57 -070054};
55
Song Zhaoea5a0412021-01-18 16:40:08 -080056#define SESSION_DEV "avsync_s"
57
Song Zhaoc03ba122020-12-23 21:54:02 -080058struct av_sync_session {
59 /* session id attached */
60 int session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -080061 int fd;
62 bool attached;
63 enum sync_mode mode;
64 /* for audio trickplay */
65 enum sync_mode backup_mode;
66 enum sync_type type;
67 uint32_t start_policy;
bo.xiao5821fc72021-07-11 22:47:00 -040068 int timeout;
Song Zhaoc03ba122020-12-23 21:54:02 -080069
Song Zhaoea5a0412021-01-18 16:40:08 -080070 /* playback time, will stop increasing during pause */
71 pts90K vpts;
72 pts90K apts;
73
74 /* phase adjustment of stream time for rate control (Video ONLY) */
Song Zhaoc03ba122020-12-23 21:54:02 -080075 pts90K phase;
76 bool phase_set;
Song Zhao1561e542022-01-12 10:37:55 -080077 bool phase_adjusted;
Song Zhaoc03ba122020-12-23 21:54:02 -080078
79 /* pts of last rendered frame */
Song Zhaoea5a0412021-01-18 16:40:08 -080080 pts90K last_wall;
Song Zhaoc03ba122020-12-23 21:54:02 -080081 pts90K last_pts;
82 struct vframe *last_frame;
83
Song Zhaoe0bf6ad2021-07-09 11:28:42 -070084 /* pts of last pushed frame */
85 pts90K last_q_pts;
86
Song Zhaoc03ba122020-12-23 21:54:02 -080087 bool first_frame_toggled;
Song Zhaoc03ba122020-12-23 21:54:02 -080088 bool paused;
Song Zhaoea5a0412021-01-18 16:40:08 -080089 enum sync_state state;
Song Zhaoc03ba122020-12-23 21:54:02 -080090 void *pattern_detector;
91 void *frame_q;
Song Zhaoc03ba122020-12-23 21:54:02 -080092
Song Zhaoea5a0412021-01-18 16:40:08 -080093 /* start control */
94 int start_thres;
95 audio_start_cb audio_start;
96 void *audio_start_priv;
97
98 /* render property */
Song Zhaoc03ba122020-12-23 21:54:02 -080099 int delay;
Song Zhao6dce2672022-01-13 11:32:44 -0800100 int extra_delay;
Song Zhaoc03ba122020-12-23 21:54:02 -0800101 pts90K vsync_interval;
102
103 /* state lock */
104 pthread_mutex_t lock;
105 /* pattern */
106 int last_holding_peroid;
Song Zhaoea5a0412021-01-18 16:40:08 -0800107 bool session_started;
Song Zhaoc03ba122020-12-23 21:54:02 -0800108
109 float speed;
110
Song Zhaoc03ba122020-12-23 21:54:02 -0800111 /* pause pts */
112 pts90K pause_pts;
113 pause_pts_done pause_pts_cb;
114 void *pause_cb_priv;
yongchun.li428390d2022-02-17 17:15:40 -0800115 /* underflow */
116 underflow_detected underflow_cb;
117 void *underflow_cb_priv;
118 struct underflow_config underflow_cfg;
119 struct timespec frame_last_update_time;
Song Zhao5d2b4772021-01-18 16:40:08 -0800120
121 /* log control */
Song Zhaoa2985cb2021-06-24 12:01:47 -0700122 uint32_t last_log_syst;
Song Zhao5d2b4772021-01-18 16:40:08 -0800123 uint32_t sync_lost_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700124 struct timespec sync_lost_print_time;
Song Zhaoea5a0412021-01-18 16:40:08 -0800125
126 pthread_t poll_thread;
127 /* pcr master, IPTV only */
128 bool quit_poll;
129 enum sync_mode active_mode;
Song Zhaof46932e2021-05-21 01:51:45 -0700130 uint32_t disc_thres_min;
131 uint32_t disc_thres_max;
Song Zhao35a82df2021-04-15 10:58:49 -0700132
133 /* error detection */
134 uint32_t last_poptime;
Song Zhaod62bb392021-04-23 12:25:49 -0700135 uint32_t outlier_cnt;
Song Zhao409739b2021-05-12 22:21:40 -0700136 pts90K last_disc_pts;
137
yongchun.li107a6162021-05-05 02:38:57 -0700138 // indicate set audio switch
139 bool in_audio_switch;
140 enum audio_switch_state_ audio_switch_state;
wei.dubcc2ed22021-05-19 07:16:10 -0400141
142 //pcr monitor handle
143 void *pcr_monitor;
144 int ppm;
Song Zhao623e2f12021-09-03 15:54:04 -0700145 bool ppm_adjusted;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700146
147 //video FPS detection
148 pts90K last_fpts;
149 int fps_interval;
150 int fps_interval_acc;
151 int fps_cnt;
152
153 //video freerun with rate control
154 uint32_t last_r_syst;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700155 bool debug_freerun;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700156
157 //Audio dropping detection
158 uint32_t audio_drop_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700159 struct timespec audio_drop_start;
Song Zhao95bd0922021-09-21 14:07:46 -0700160
161 /*system mono time for current vsync interrupt */
162 uint64_t msys;
Song Zhaoc03ba122020-12-23 21:54:02 -0800163};
164
165#define MAX_FRAME_NUM 32
166#define DEFAULT_START_THRESHOLD 2
167#define TIME_UNIT90K (90000)
Song Zhaoa73fcf32023-01-13 08:12:26 -0800168#define DEFAULT_WALL_ADJ_THRES (TIME_UNIT90K / 10) //100ms
Song Zhaof46932e2021-05-21 01:51:45 -0700169#define AV_DISC_THRES_MIN (TIME_UNIT90K / 3)
170#define AV_DISC_THRES_MAX (TIME_UNIT90K * 10)
Song Zhao7daf3a12021-05-10 22:22:25 -0700171#define A_ADJ_THREDHOLD_HB (900 * 6) //60ms
172#define A_ADJ_THREDHOLD_LB (900 * 2) //20ms
Song Zhao4bd18762022-09-30 16:39:52 -0700173#define A_ADJ_THREDHOLD_MB (900 * 3) //30ms
Song Zhao52f55192021-05-06 10:52:21 -0700174#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800175#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhao76005282022-03-08 16:49:41 -0800176#define LIVE_MODE(m) ((m) == AV_SYNC_MODE_PCR_MASTER || (m) == AV_SYNC_MODE_IPTV)
Song Zhao7e24b182022-04-01 08:46:40 -0700177#define V_DISC_MODE(mode) (LIVE_MODE(mode) || (mode) == AV_SYNC_MODE_VMASTER)
Song Zhaod62bb392021-04-23 12:25:49 -0700178
Song Zhao065800e2021-05-26 15:56:06 -0700179#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
Song Zhaod62bb392021-04-23 12:25:49 -0700180#define OUTLIER_MAX_CNT 8
Song Zhaoa2985cb2021-06-24 12:01:47 -0700181#define VALID_TS(x) ((x) != -1)
yongchun.li428390d2022-02-17 17:15:40 -0800182#define UNDERFLOW_CHECK_THRESH_MS (100)
Song Zhaoc03ba122020-12-23 21:54:02 -0800183
yongchun.li0ee6e372021-08-20 04:26:04 -0700184static uint64_t time_diff (struct timespec *b, struct timespec *a);
Song Zhaoc03ba122020-12-23 21:54:02 -0800185static bool frame_expire(struct av_sync_session* avsync,
186 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800187 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800188 struct vframe * frame,
189 struct vframe * next_frame,
190 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700191static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800192 int cur_period,
193 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800194static void * poll_thread(void * arg);
195static void trigger_audio_start_cb(struct av_sync_session *avsync,
196 avs_ascb_reason reason);
Song Zhao95bd0922021-09-21 14:07:46 -0700197static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync);
198static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame);
fei.deng55389b62022-08-18 23:46:50 +0800199
Song Zhao2f6744b2021-11-03 21:23:50 -0700200pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER;
Song Zhaoc03ba122020-12-23 21:54:02 -0800201
Song Zhaoea5a0412021-01-18 16:40:08 -0800202int av_sync_open_session(int *session_id)
203{
Song Zhao2f6744b2021-11-03 21:23:50 -0700204 int fd = -1;
Song Zhaoea5a0412021-01-18 16:40:08 -0800205 int id, rc;
206
Song Zhao2f6744b2021-11-03 21:23:50 -0700207 pthread_mutex_lock(&glock);
208 fd = msync_create_session();
Song Zhaoea5a0412021-01-18 16:40:08 -0800209 if (fd < 0) {
210 log_error("fail");
Song Zhao2f6744b2021-11-03 21:23:50 -0700211 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800212 }
213 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
214 if (rc) {
215 log_error("new session errno:%d", errno);
Song Zhao2f6744b2021-11-03 21:23:50 -0700216 msync_destory_session(fd);
217 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800218 }
219 *session_id = id;
Song Zhao2f6744b2021-11-03 21:23:50 -0700220 log_debug("new avsession id %d fd %d", id, fd);
221exit:
222 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800223 return fd;
224}
225
226void av_sync_close_session(int session)
227{
Song Zhao2f6744b2021-11-03 21:23:50 -0700228 log_debug("session closed fd %d", session);
229 pthread_mutex_lock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800230 msync_destory_session(session);
Song Zhao2f6744b2021-11-03 21:23:50 -0700231 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800232}
233
234static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800235 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800236 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800237 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800238 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800239{
240 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800241 char dev_name[20];
Song Zhao2f6744b2021-11-03 21:23:50 -0700242 int retry = 10;
Song Zhaoc03ba122020-12-23 21:54:02 -0800243
fei.deng55389b62022-08-18 23:46:50 +0800244 /* debug log level */
245 {
246 const char *env= getenv( "AML_AVSYNC_DEBUG_LEVEL");
247 if ( env ) {
248 log_set_level(atoi(env));
249 }
250 }
251
Song Zhao95bd0922021-09-21 14:07:46 -0700252 log_info("[%d] mode %d type %d", session_id, mode, type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800253 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
254 if (!avsync) {
255 log_error("OOM");
256 return NULL;
257 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800258
Song Zhao95bd0922021-09-21 14:07:46 -0700259 if (type == AV_SYNC_TYPE_VIDEO &&
260 mode == AV_SYNC_MODE_VIDEO_MONO) {
261 if (session_id < AV_SYNC_SESSION_V_MONO) {
262 log_error("wrong session id %d", session_id);
263 goto err;
264 }
265 avsync->type = type;
266 avsync->mode = mode;
267 avsync->fd = -1;
268 avsync->session_id = session_id;
269 log_info("[%d]init", avsync->session_id);
270 return avsync;
271 }
272
Song Zhaoea5a0412021-01-18 16:40:08 -0800273 if (type == AV_SYNC_TYPE_VIDEO) {
Song Zhaobb3b4f32023-10-17 16:08:12 -0700274 int32_t interval = 1500;
275
276 if (msync_session_get_vsync_interval(&interval))
277 log_error("read interval error");
278 avsync->pattern_detector = create_pattern_detector(interval);
Song Zhaoea5a0412021-01-18 16:40:08 -0800279 if (!avsync->pattern_detector) {
280 log_error("pd create fail");
281 goto err;
282 }
283
284 if (!start_thres)
285 avsync->start_thres = DEFAULT_START_THRESHOLD;
286 else {
287 if (start_thres > 5) {
288 log_error("start_thres too big: %d", start_thres);
289 goto err2;
290 }
291 avsync->start_thres = start_thres;
292 }
293 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800294 avsync->phase_adjusted = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800295 avsync->first_frame_toggled = false;
Song Zhaofd007632022-09-30 16:21:30 -0700296
297 avsync->frame_q = create_q(MAX_FRAME_NUM);
298 if (!avsync->frame_q) {
299 log_error("[%d]create queue fail", avsync->session_id);
300 goto err2;
301 }
Song Zhaofd007632022-09-30 16:21:30 -0700302 {
303 int ret;
304
305 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
306 if (ret) {
307 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
308 goto err2;
309 }
310 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800311 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800312
313 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800314 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800315 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800316 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800317 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800318 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800319 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800320 avsync->speed = 1.0f;
321 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhao409739b2021-05-12 22:21:40 -0700322 avsync->vsync_interval = -1;
323 avsync->last_disc_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700324 avsync->last_log_syst = -1;
325 avsync->last_pts = -1;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700326 avsync->last_q_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700327 avsync->last_wall = -1;
328 avsync->fps_interval = -1;
329 avsync->last_r_syst = -1;
bo.xiao5821fc72021-07-11 22:47:00 -0400330 avsync->timeout = -1;
331
Song Zhaof46932e2021-05-21 01:51:45 -0700332 if (msync_session_get_disc_thres(session_id,
333 &avsync->disc_thres_min, &avsync->disc_thres_max)) {
hanghang.luo02efd312022-08-26 09:49:53 +0800334 log_error("dev_name:%s; errno:%d; fail to get disc thres", dev_name, errno);
Song Zhaof46932e2021-05-21 01:51:45 -0700335 avsync->disc_thres_min = AV_DISC_THRES_MIN;
336 avsync->disc_thres_max = AV_DISC_THRES_MAX;
337 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800338
339 pthread_mutex_init(&avsync->lock, NULL);
Song Zhao9c09f772022-01-07 14:26:50 -0800340 log_info("[%d] start_thres %d disc_thres %u/%u", session_id,
Song Zhao95bd0922021-09-21 14:07:46 -0700341 start_thres, avsync->disc_thres_min, avsync->disc_thres_max);
Song Zhaoea5a0412021-01-18 16:40:08 -0800342
343 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
Song Zhao2f6744b2021-11-03 21:23:50 -0700344 while (retry) {
345 /* wait for sysfs to update */
346 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
347 if (avsync->fd > 0)
348 break;
349
350 retry--;
351 if (!retry) {
352 log_error("open %s errno %d", dev_name, errno);
353 goto err2;
354 }
355 usleep(20000);
Song Zhaoea5a0412021-01-18 16:40:08 -0800356 }
357
wei.dubcc2ed22021-05-19 07:16:10 -0400358 if (avsync->type == AV_SYNC_TYPE_PCR) {
359 if (pcr_monitor_init(&avsync->pcr_monitor)) {
360 log_error("pcr monitor init");
Song Zhao9cd27a52021-07-26 15:27:38 +0000361 goto err3;
wei.dubcc2ed22021-05-19 07:16:10 -0400362 }
363 }
364
Song Zhaoea5a0412021-01-18 16:40:08 -0800365 if (!attach) {
366 msync_session_set_mode(avsync->fd, mode);
367 avsync->mode = mode;
Song Zhaob8833c12024-02-02 21:54:36 +0000368 if ((avsync->mode == AV_SYNC_MODE_VMASTER ||
369 avsync->mode == AV_SYNC_MODE_IPTV) &&
370 avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao7e24b182022-04-01 08:46:40 -0700371 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -0800372 } else {
373 avsync->attached = true;
374 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
375 log_error("get mode");
Song Zhao9cd27a52021-07-26 15:27:38 +0000376 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800377 }
378 avsync->backup_mode = avsync->mode;
bo.xiao5821fc72021-07-11 22:47:00 -0400379 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800380 log_error("get policy");
Song Zhao9cd27a52021-07-26 15:27:38 +0000381 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800382 }
Song Zhao9fef59c2022-08-17 12:43:10 -0700383 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700384 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -0700385 log_error("get state");
Song Zhao9cd27a52021-07-26 15:27:38 +0000386 goto err4;
yongchun.li107a6162021-05-05 02:38:57 -0700387 }
388 if (avsync->in_audio_switch) {
389 log_info("audio_switch_state reseted the audio");
390 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
391 }
392
Song Zhaoea5a0412021-01-18 16:40:08 -0800393 log_info("[%d]retrieve sync mode %d policy %d",
394 session_id, avsync->mode, avsync->start_policy);
395 }
396
Song Zhaoc03ba122020-12-23 21:54:02 -0800397 return avsync;
Song Zhao9cd27a52021-07-26 15:27:38 +0000398err4:
wei.dubcc2ed22021-05-19 07:16:10 -0400399 if (avsync->pcr_monitor)
400 pcr_monitor_destroy(avsync->pcr_monitor);
Song Zhao9cd27a52021-07-26 15:27:38 +0000401err3:
Song Zhaofd007632022-09-30 16:21:30 -0700402 if (avsync->fd)
403 close(avsync->fd);
Song Zhaoea5a0412021-01-18 16:40:08 -0800404err2:
Song Zhaofd007632022-09-30 16:21:30 -0700405 avsync->quit_poll = true;
406 if (avsync->poll_thread) {
407 pthread_join(avsync->poll_thread, NULL);
408 avsync->poll_thread = 0;
409 }
410 if (avsync->frame_q)
411 destroy_q(avsync->frame_q);
412 if (avsync->pattern_detector)
413 destroy_pattern_detector(avsync->pattern_detector);
Song Zhaoea5a0412021-01-18 16:40:08 -0800414err:
415 free(avsync);
416 return NULL;
417}
418
419void* av_sync_create(int session_id,
420 enum sync_mode mode,
421 enum sync_type type,
422 int start_thres)
423{
424 return create_internal(session_id, mode,
425 type, start_thres, false);
426}
427
428void* av_sync_attach(int session_id, enum sync_type type)
429{
Song Zhao95bd0922021-09-21 14:07:46 -0700430 if (type == AV_SYNC_TYPE_VIDEO)
431 return NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800432 return create_internal(session_id, AV_SYNC_MODE_MAX,
433 type, 0, true);
434}
435
436int av_sync_video_config(void *sync, struct video_config* config)
437{
438 struct av_sync_session *avsync = (struct av_sync_session *)sync;
439
440 if (!avsync || !config)
441 return -1;
442
443 if (config->delay != 1 && config->delay != 2) {
444 log_error("invalid delay: %d\n", config->delay);
445 return -1;
446 }
447
448 avsync->delay = config->delay;
Song Zhao6dce2672022-01-13 11:32:44 -0800449 avsync->extra_delay = config->extra_delay * 90;
Song Zhaoea5a0412021-01-18 16:40:08 -0800450
Song Zhao6dce2672022-01-13 11:32:44 -0800451 log_info("[%d] vsync delay: %d extra_delay: %d ms",
452 avsync->session_id, config->delay, config->extra_delay);
Song Zhaoea5a0412021-01-18 16:40:08 -0800453 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800454}
455
456static int internal_stop(struct av_sync_session *avsync)
457{
458 int ret = 0;
459 struct vframe *frame;
460
461 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800462 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
463 frame->free(frame);
464 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800465 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800466 pthread_mutex_unlock(&avsync->lock);
467 return ret;
468}
469
470/* destroy and detach from kernel session */
471void av_sync_destroy(void *sync)
472{
473 struct av_sync_session *avsync = (struct av_sync_session *)sync;
474
475 if (!avsync)
476 return;
477
Song Zhao95bd0922021-09-21 14:07:46 -0700478 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
479 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
480 log_info("[%d]done", avsync->session_id);
481 internal_stop(avsync);
482 destroy_q(avsync->frame_q);
483 free(avsync);
484 return;
485 }
Song Zhaob5458b32021-11-12 15:58:47 -0800486 log_info("[%d]begin type %d", avsync->session_id, avsync->type);
Song Zhao6be9ac22022-09-30 16:44:50 -0700487 if (avsync->type == AV_SYNC_TYPE_VIDEO)
488 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800489
Song Zhao6be9ac22022-09-30 16:44:50 -0700490 avsync->quit_poll = true;
491 if (avsync->poll_thread) {
492 pthread_join(avsync->poll_thread, NULL);
493 avsync->poll_thread = 0;
Song Zhaoaf368d52021-02-17 17:53:45 -0800494 }
Song Zhao6be9ac22022-09-30 16:44:50 -0700495 if (avsync->type == AV_SYNC_TYPE_AUDIO)
496 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoc03ba122020-12-23 21:54:02 -0800497
Song Zhaoea5a0412021-01-18 16:40:08 -0800498 if (avsync->session_started) {
499 if (avsync->type == AV_SYNC_TYPE_VIDEO)
500 msync_session_set_video_stop(avsync->fd);
501 else
502 msync_session_set_audio_stop(avsync->fd);
503 }
wei.dubcc2ed22021-05-19 07:16:10 -0400504
505 if(avsync->pcr_monitor)
506 pcr_monitor_destroy(avsync->pcr_monitor);
507
Song Zhaoea5a0412021-01-18 16:40:08 -0800508 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800509 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800510 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
511 destroy_q(avsync->frame_q);
512 destroy_pattern_detector(avsync->pattern_detector);
513 }
Song Zhaob5458b32021-11-12 15:58:47 -0800514 log_info("[%d]done type %d", avsync->session_id, avsync->type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800515 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800516}
517
bo.xiao5821fc72021-07-11 22:47:00 -0400518int avs_sync_set_start_policy(void *sync, struct start_policy* st_policy)
Song Zhaoea5a0412021-01-18 16:40:08 -0800519{
520 struct av_sync_session *avsync = (struct av_sync_session *)sync;
521
522 if (!avsync || !avsync->fd)
523 return -1;
524
Song Zhao47961d72022-08-29 14:04:44 -0700525 log_info("[%d]policy %u --> %u, timeout %d --> %d", avsync->session_id,
526 avsync->start_policy, st_policy->policy, avsync->timeout, st_policy->timeout);
Song Zhaof4e3c862022-09-01 14:00:11 -0700527 if (avsync->mode == AV_SYNC_MODE_IPTV &&
Song Zhao76005282022-03-08 16:49:41 -0800528 st_policy->policy != AV_SYNC_START_ASAP) {
529 log_error("policy %d not supported in live mode", st_policy->policy);
530 return -1;
531 }
532
Song Zhaof4e3c862022-09-01 14:00:11 -0700533 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
534 msync_session_set_start_thres(avsync->fd, st_policy->timeout);
535
bo.xiao5821fc72021-07-11 22:47:00 -0400536 avsync->start_policy = st_policy->policy;
537 avsync->timeout = st_policy->timeout;
Song Zhao76005282022-03-08 16:49:41 -0800538
Song Zhaoea5a0412021-01-18 16:40:08 -0800539 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400540 if (st_policy->policy != AV_SYNC_START_NONE &&
541 st_policy->policy != AV_SYNC_START_V_PEEK)
542 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800543
544 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800545}
546
547int av_sync_pause(void *sync, bool pause)
548{
549 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700550 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800551 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800552
Song Zhaob5458b32021-11-12 15:58:47 -0800553 if (!avsync) {
554 log_error("invalid handle");
Song Zhaoc03ba122020-12-23 21:54:02 -0800555 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800556 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800557
fei.deng55389b62022-08-18 23:46:50 +0800558 if (avsync->type == AV_SYNC_TYPE_VIDEO && avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
559 log_warn("ignore pause in video mono mode");
560 return -1;
561 }
562
Song Zhaob5458b32021-11-12 15:58:47 -0800563 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
564 log_warn("ignore pause in pcr master mode");
Song Zhaoea5a0412021-01-18 16:40:08 -0800565 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800566 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800567
Song Zhao9fef59c2022-08-17 12:43:10 -0700568 rc = msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -0700569 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700570 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700571
yongchun.li5f52fb02021-06-04 18:13:05 -0700572 /* ignore only when video try to pause when audio is acive, on which
573 the control of the STC will be relays.
574 When resume,it can do always as it is possible that video just
575 paused earlier without audio yet,then audio added later before resume.
576 We shall not igore that otherwise it could cause video freeze. */
577 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
578 avsync->type == AV_SYNC_TYPE_VIDEO &&
579 a_active &&
580 !avsync->in_audio_switch) {
581 if (!pause) {
582 log_info("[%d] clear video pause when audio active",
583 avsync->session_id);
584 avsync->paused = pause;
585 } else {
586 log_info("[%d] ignore the pause from video when audio active",
587 avsync->session_id);
588 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800589 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700590 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800591
yongchun.li107a6162021-05-05 02:38:57 -0700592 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
593 log_info("[%d] ignore the pause from audio", avsync->session_id);
594 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
595 return 0;
596 }
597
Song Zhaoea5a0412021-01-18 16:40:08 -0800598 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800599 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800600 log_info("[%d]paused:%d type:%d rc %d",
601 avsync->session_id, pause, avsync->type, rc);
yongchun.li428390d2022-02-17 17:15:40 -0800602 if (!avsync->paused && avsync->first_frame_toggled) {
603 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
604 log_info("[%d] resume update new frame time", avsync->session_id);
605 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800606 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800607}
608
609int av_sync_push_frame(void *sync , struct vframe *frame)
610{
611 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700612 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800613 struct av_sync_session *avsync = (struct av_sync_session *)sync;
614
615 if (!avsync)
616 return -1;
617
Song Zhao95bd0922021-09-21 14:07:46 -0700618 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
fei.deng55389b62022-08-18 23:46:50 +0800619 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
Song Zhao95bd0922021-09-21 14:07:46 -0700620 return video_mono_push_frame(avsync, frame);
fei.deng55389b62022-08-18 23:46:50 +0800621 }
Song Zhao95bd0922021-09-21 14:07:46 -0700622
Song Zhaofd007632022-09-30 16:21:30 -0700623 if (avsync->state == AV_SYNC_STAT_INIT && !queue_size(avsync->frame_q)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800624 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400625 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800626 log_error("[%d]get policy", avsync->session_id);
627 return -1;
628 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800629 }
630
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700631 if (avsync->last_q_pts != -1) {
Song Zhao7e24b182022-04-01 08:46:40 -0700632 if (frame->pts != -1 && avsync->mode == AV_SYNC_MODE_VMASTER) {
633 /* Sometimes app will fake PTS for trickplay, video PTS gap
634 * is really big depending on the speed. Have to adjust the
635 * threshold dynamically.
636 */
637 int gap = (int)(frame->pts - avsync->last_q_pts);
638 if (gap > avsync->disc_thres_min) {
639 avsync->disc_thres_min = gap * 6;
640 avsync->disc_thres_max = gap * 20;
641 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
642 msync_session_set_disc_thres(avsync->session_id,
643 avsync->disc_thres_min, avsync->disc_thres_max);
644 log_info("[%d] update disc_thres to %d/%d",avsync->session_id,
645 avsync->disc_thres_min, avsync->disc_thres_max);
646 }
647 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700648 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
649 /* TODO: wrong, should remove from back of queue */
le.hanebaea1e2023-07-10 07:26:09 +0000650 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800651 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700652 if (prev) {
653 prev->free(prev);
654 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
655 }
le.hanebaea1e2023-07-10 07:26:09 +0000656 pthread_mutex_unlock(&avsync->lock);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700657 } else if (avsync->fps_cnt < 100) {
658 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700659
660 if (interval > 0 && interval <= 4500) {
661 if (avsync->fps_interval_acc == -1) {
662 avsync->fps_interval_acc = interval;
663 avsync->fps_cnt = 1;
664 } else {
665 avsync->fps_interval_acc += interval;
666 avsync->fps_cnt++;
667 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
668 if (avsync->fps_cnt == 100)
669 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
670 }
671 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800672 }
673 }
674
Song Zhao065800e2021-05-26 15:56:06 -0700675 if (frame->duration == -1)
676 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800677 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700678 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800679 ret = queue_item(avsync->frame_q, frame);
680 if (avsync->state == AV_SYNC_STAT_INIT &&
681 queue_size(avsync->frame_q) >= avsync->start_thres) {
682 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaofd007632022-09-30 16:21:30 -0700683 log_debug("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800684 }
685
686 if (ret)
Song Zhaoe1b65602022-01-06 08:03:46 -0800687 log_error("queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400688 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800689 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800690}
691
692struct vframe *av_sync_pop_frame(void *sync)
693{
Song Zhaoea5a0412021-01-18 16:40:08 -0800694 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800695 struct av_sync_session *avsync = (struct av_sync_session *)sync;
696 int toggle_cnt = 0;
hanghang.luo02efd312022-08-26 09:49:53 +0800697 uint32_t systime = 0;
Song Zhao468fd652021-01-15 22:13:04 -0800698 bool pause_pts_reached = false;
hanghang.luo02efd312022-08-26 09:49:53 +0800699 uint32_t interval = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800700
Song Zhao95bd0922021-09-21 14:07:46 -0700701 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
702 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
703 return video_mono_pop_frame(avsync);
704
Song Zhaoc03ba122020-12-23 21:54:02 -0800705 pthread_mutex_lock(&avsync->lock);
706 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhao2f6744b2021-11-03 21:23:50 -0700707 log_debug("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800708 goto exit;
709 }
710
Song Zhaoea5a0412021-01-18 16:40:08 -0800711 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700712 uint32_t pts;
713
Song Zhaoc03ba122020-12-23 21:54:02 -0800714 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800715 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800716 goto exit;
717 }
Song Zhao35a82df2021-04-15 10:58:49 -0700718 msync_session_get_wall(avsync->fd, &systime, &interval);
719 pts = frame->pts - avsync->delay * interval;
720 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800721 avsync->session_started = true;
Song Zhao5296acf2024-02-02 21:45:04 +0000722 log_info("[%d]video start %u frame %u sys %u",
723 avsync->session_id, pts, frame->pts, systime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800724 }
725
Song Zhaoea5a0412021-01-18 16:40:08 -0800726 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700727 !avsync->first_frame_toggled &&
728 !msync_clock_started(avsync->fd)) {
729 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800730 log_trace("[%d]clock not started", avsync->session_id);
731 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800732 }
733
Song Zhaoea5a0412021-01-18 16:40:08 -0800734 enter_last_frame = avsync->last_frame;
735 msync_session_get_wall(avsync->fd, &systime, &interval);
736
737 /* handle refresh rate change */
738 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
739 avsync->vsync_interval != interval) {
740 log_info("[%d]vsync interval update %d --> %u",
741 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700742 if (avsync->fps_interval == -1)
743 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800744 avsync->vsync_interval = interval;
745 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800746 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700747 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800748 reset_pattern(avsync->pattern_detector);
749 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800750 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
751 struct vframe *next_frame = NULL;
752
753 peek_item(avsync->frame_q, (void **)&next_frame, 1);
754 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700755 log_debug("[%d]cur_f %u next_f %u size %d",
756 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800757 if (frame_expire(avsync, systime, interval,
758 frame, next_frame, toggle_cnt)) {
759 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800760 toggle_cnt++;
761
Song Zhao35a82df2021-04-15 10:58:49 -0700762 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800763 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700764 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700765 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700766 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
767 if (next_frame)
768 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
769 }
Song Zhao35a82df2021-04-15 10:58:49 -0700770
Song Zhaoc03ba122020-12-23 21:54:02 -0800771 if (avsync->last_frame)
772 avsync->last_holding_peroid = avsync->last_frame->hold_period;
773
774 dqueue_item(avsync->frame_q, (void **)&frame);
775 if (avsync->last_frame) {
Song Zhao5296acf2024-02-02 21:45:04 +0000776 int qsize = queue_size(avsync->frame_q);
777
Song Zhaoc03ba122020-12-23 21:54:02 -0800778 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800779 if (toggle_cnt > 1) {
Song Zhaofd007632022-09-30 16:21:30 -0700780 log_info("[%d]free %u cur %u system/d %u/%u queue size %d", avsync->session_id,
781 avsync->last_frame->pts, frame->pts,
782 systime, systime - avsync->last_poptime,
Song Zhao5296acf2024-02-02 21:45:04 +0000783 qsize);
Song Zhaoc03ba122020-12-23 21:54:02 -0800784 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800785 }
Song Zhao5296acf2024-02-02 21:45:04 +0000786 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER && qsize <= 1) {
787 msync_session_set_video_dis(avsync->fd, frame->pts);
788 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800789 } else {
790 avsync->first_frame_toggled = true;
Song Zhaofd007632022-09-30 16:21:30 -0700791 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 -0800792 }
793 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800794 avsync->last_pts = frame->pts;
yongchun.li428390d2022-02-17 17:15:40 -0800795 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
Song Zhaoc03ba122020-12-23 21:54:02 -0800796 } else
797 break;
798 }
799
800 /* pause pts */
801 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800802 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800803 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800804 else
Song Zhao468fd652021-01-15 22:13:04 -0800805 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
806 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
807 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
808 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
809 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800810
Song Zhao468fd652021-01-15 22:13:04 -0800811 if (pause_pts_reached) {
Song Zhao468fd652021-01-15 22:13:04 -0800812 /* stay in paused until av_sync_pause(false) */
Song Zhaoa1742282022-09-30 16:17:26 -0700813 uint32_t local_pts = avsync->pause_pts;
Song Zhao468fd652021-01-15 22:13:04 -0800814 avsync->paused = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800815 log_info ("[%d]reach pause pts: %u",
Song Zhaob5458b32021-11-12 15:58:47 -0800816 avsync->session_id, avsync->pause_pts);
Song Zhaoad7c8232021-12-14 11:46:48 -0800817 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoa1742282022-09-30 16:17:26 -0700818 if (avsync->pause_pts_cb)
819 avsync->pause_pts_cb(local_pts,
820 avsync->pause_cb_priv);
821 log_info ("[%d] reach pause pts: %u handle done",
822 avsync->session_id, local_pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800823 }
824
825exit:
826 pthread_mutex_unlock(&avsync->lock);
yongchun.li428390d2022-02-17 17:15:40 -0800827
828 /* underflow check */
829 if (avsync->session_started && avsync->first_frame_toggled &&
830 (avsync->paused == false) && (avsync->state >= AV_SYNC_STAT_RUNNING) &&
831 avsync->underflow_cb && peek_item(avsync->frame_q, (void **)&frame, 0))
832 {/* empty queue in normal play */
833 struct timespec now;
834 int diff_ms;
835 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
836 diff_ms = time_diff(&now, &avsync->frame_last_update_time)/1000;
837 if(diff_ms >= (avsync->underflow_cfg.time_thresh
838 + avsync->vsync_interval*avsync->last_holding_peroid/90)) {
839 log_info ("[%d]underflow detected: %u", avsync->session_id, avsync->last_pts);
840 avsync->underflow_cb (avsync->last_pts,
841 avsync->underflow_cb_priv);
842 /* update time to control the underflow check call backs */
843 avsync->frame_last_update_time = now;
844 }
845 }
846
Song Zhaoc03ba122020-12-23 21:54:02 -0800847 if (avsync->last_frame) {
Song Zhaof3350d32023-08-18 16:27:31 -0700848 if (enter_last_frame != avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800849 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhaof3350d32023-08-18 16:27:31 -0700850 /* don't update vpts for out_lier */
851 if (avsync->last_frame->duration != -1)
852 msync_session_update_vpts(avsync->fd, systime,
853 avsync->last_frame->pts + avsync->extra_delay, interval * avsync->delay);
854 }
bo.xiao1f94b352021-08-02 03:53:47 -0400855 log_trace("[%d]pop=%u, stc=%u, QNum=%d", avsync->session_id, avsync->last_frame->pts, systime, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800856 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800857 if (enter_last_frame != avsync->last_frame)
858 log_debug("[%d]pop (nil)", avsync->session_id);
859
Song Zhao35a82df2021-04-15 10:58:49 -0700860 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800861 if (avsync->last_frame)
862 avsync->last_frame->hold_period++;
863 return avsync->last_frame;
864}
865
Song Zhaoc03ba122020-12-23 21:54:02 -0800866static inline uint32_t abs_diff(uint32_t a, uint32_t b)
867{
Song Zhaoea5a0412021-01-18 16:40:08 -0800868 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800869}
870
yongchun.li0ee6e372021-08-20 04:26:04 -0700871static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800872{
hanghang.luo02efd312022-08-26 09:49:53 +0800873 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 -0800874}
875
Song Zhaoc03ba122020-12-23 21:54:02 -0800876static bool frame_expire(struct av_sync_session* avsync,
877 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800878 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800879 struct vframe * frame,
880 struct vframe * next_frame,
881 int toggle_cnt)
882{
Song Zhao6dce2672022-01-13 11:32:44 -0800883 uint32_t fpts = frame->pts + avsync->extra_delay;
884 uint32_t nfpts = -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800885 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800886 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800887
Song Zhao9c0197e2024-03-12 18:05:20 +0000888 if (!VALID_TS(systime))
889 return false;
890
Song Zhaoc03ba122020-12-23 21:54:02 -0800891 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
892 return false;
893
894 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
895 return true;
896
Song Zhaoad7c8232021-12-14 11:46:48 -0800897 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS &&
898 avsync->pause_pts == frame->pts)
899 return true;
900
Song Zhao08fa16b2021-12-08 14:30:17 -0800901 if (systime == AV_SYNC_INVALID_PTS &&
902 avsync->mode == AV_SYNC_MODE_AMASTER)
903 return false;
904
Song Zhao6dce2672022-01-13 11:32:44 -0800905 if (next_frame)
906 nfpts = next_frame->pts + avsync->extra_delay;
907
Song Zhao7e24b182022-04-01 08:46:40 -0700908 if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
fei.deng63e43e12021-09-23 19:44:01 +0800909 /* We need to ensure that the video outputs smoothly,
910 so output video frame by frame hold_period */
911 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
912 avsync->last_frame &&
913 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
914 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
915 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700916 return true;
917 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700918 }
919
Song Zhaoc03ba122020-12-23 21:54:02 -0800920 if (!fpts) {
921 if (avsync->last_frame) {
922 /* try to accumulate duration as PTS */
923 fpts = avsync->vpts + avsync->last_frame->duration;
924 } else {
925 fpts = avsync->vpts;
926 }
927 }
928 systime += pts_correction;
929
930 /* phase adjustment */
931 if (avsync->phase_set)
932 systime += avsync->phase;
933
yongchun.lia50b1e92021-08-07 01:11:54 +0000934 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800935 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000936 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700937 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800938 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800939 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800940 return false;
941
Song Zhaoa2985cb2021-06-24 12:01:47 -0700942 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
943 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700944 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800945
yongchun.li0ee6e372021-08-20 04:26:04 -0700946 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700947 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800948 avsync->last_pts = fpts;
949 if (time_diff(&now, &avsync->sync_lost_print_time) >=
950 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700951 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800952 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800953 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700954 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800955 } else
956 avsync->sync_lost_cnt++;
957 }
Song Zhaod62bb392021-04-23 12:25:49 -0700958
959 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
960 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700961 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700962 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700963 /* outlier by stream error */
964 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700965 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700966 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
967 log_info("render outlier %u", fpts);
968 return true;
969 }
970 }
971
972 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800973 avsync->state = AV_SYNC_STAT_SYNC_LOST;
974 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800975 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700976 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800977 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700978
Song Zhao7e24b182022-04-01 08:46:40 -0700979 if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700980 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700981 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700982 msync_session_set_video_dis(avsync->fd, fpts);
983 avsync->last_disc_pts = fpts;
Song Zhao59d732d2024-01-23 22:09:15 -0800984 if (avsync->mode == AV_SYNC_MODE_VMASTER) {
985 systime = fpts;
986 avsync->last_r_syst = -1;
987 }
Song Zhaoa2985cb2021-06-24 12:01:47 -0700988 }
989
990 if ((int)(systime - fpts) > 0) {
991 if ((int)(systime - fpts) < avsync->disc_thres_max) {
992 /* catch up PCR */
Song Zhao59d732d2024-01-23 22:09:15 -0800993 avsync->last_r_syst = -1;
Song Zhaof46932e2021-05-21 01:51:45 -0700994 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700995 } else {
996 /* render according to FPS */
997 if (!VALID_TS(avsync->last_r_syst) ||
998 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
999 avsync->last_r_syst = systime;
1000 return true;
1001 }
1002 return false;
1003 }
1004 } else if (LIVE_MODE(avsync->mode)) {
1005 /* hold if the gap is small */
1006 if ((int)(fpts - systime) < avsync->disc_thres_max) {
1007 return false;
1008 } else {
1009 /* render according to FPS */
1010 if (!VALID_TS(avsync->last_r_syst) ||
1011 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
1012 avsync->last_r_syst = systime;
1013 return true;
1014 }
1015 return false;
1016 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001017 }
1018 }
1019
Song Zhao52f55192021-05-06 10:52:21 -07001020 /* In some cases, keeping pattern will enlarge the gap */
1021 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
1022 avsync->first_frame_toggled) {
1023 reset_pattern(avsync->pattern_detector);
Song Zhaofd007632022-09-30 16:21:30 -07001024 log_info("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -07001025 systime, fpts);
1026 }
1027
Song Zhaoc03ba122020-12-23 21:54:02 -08001028 expire = (int)(systime - fpts) >= 0;
1029
1030 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -08001031 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001032 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -08001033 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001034 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001035 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001036 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -08001037 }
Song Zhao6dce2672022-01-13 11:32:44 -08001038 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -08001039 && avsync->first_frame_toggled) {
1040 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -08001041 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001042 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -08001043 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001044 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001045 }
1046 }
1047
Song Zhaoa58c3e92021-03-09 18:52:55 -08001048 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -08001049 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -08001050 (avsync->last_frame?avsync->last_frame->hold_period:0),
1051 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -08001052 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -08001053
1054 if (expire) {
1055 avsync->vpts = fpts;
1056 /* phase adjustment */
1057 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +00001058 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -08001059 if ((int)(systime - fpts) >= 0 &&
1060 (int)(fpts + interval - systime) > 0) {
1061 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -08001062 avsync->phase_set = true;
Song Zhaofd007632022-09-30 16:21:30 -07001063 log_debug("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -08001064 }
Song Zhao1561e542022-01-12 10:37:55 -08001065 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -08001066 if ((int)(systime - fpts) >= 0 &&
1067 (int)(fpts + interval - systime) > 0) {
1068 int vsync_pts_delta = (int)(systime - fpts);
1069
1070 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1071 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001072 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001073 log_info("[%d] too aligned adjust phase to %d",
1074 avsync->session_id, (int)avsync->phase);
1075 }
1076 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001077 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001078 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaofd007632022-09-30 16:21:30 -07001079 log_info("[%d]sync setup on frame %u", avsync->session_id, fpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001080 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001081 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001082 }
1083 return expire;
1084}
1085
Song Zhao35a82df2021-04-15 10:58:49 -07001086static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001087{
Song Zhaoea5a0412021-01-18 16:40:08 -08001088 log_trace("[%d]cur_period: %d last_period: %d",
1089 avsync->session_id, cur_period, last_period);
Song Zhaobb3b4f32023-10-17 16:08:12 -07001090 return detect_pattern(avsync->pattern_detector, cur_period, last_period);
Song Zhaoc03ba122020-12-23 21:54:02 -08001091}
1092
1093int av_sync_set_speed(void *sync, float speed)
1094{
1095 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1096
1097 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001098 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001099 return -1;
1100 }
1101
Song Zhao76005282022-03-08 16:49:41 -08001102 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001103 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001104 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001105 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001106
Song Zhaoea5a0412021-01-18 16:40:08 -08001107 avsync->speed = speed;
1108
1109 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhaoa73fcf32023-01-13 08:12:26 -08001110 if (speed == 1.0)
1111 msync_session_set_wall_adj_thres(avsync->fd, DEFAULT_WALL_ADJ_THRES);
1112 else
1113 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
1114 log_info("[%d]adjust wall adj threshold to %d", avsync->session_id,
1115 (speed == 1.0) ? DEFAULT_WALL_ADJ_THRES : avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -08001116 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001117
Song Zhaoea5a0412021-01-18 16:40:08 -08001118 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1119 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001120}
1121
1122int av_sync_change_mode(void *sync, enum sync_mode mode)
1123{
1124 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1125
1126 if (!avsync)
1127 return -1;
1128
Song Zhaoea5a0412021-01-18 16:40:08 -08001129 if (msync_session_set_mode(avsync->fd, mode)) {
1130 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001131 return -1;
1132 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001133 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001134 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001135 return 0;
1136}
1137
Song Zhao01031bb2021-05-13 21:23:20 -07001138int av_sync_get_mode(void *sync, enum sync_mode *mode)
1139{
1140 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1141
1142 if (!avsync || !mode)
1143 return -1;
1144
1145 *mode = avsync->mode;
1146 return 0;
1147}
1148
Song Zhaoc03ba122020-12-23 21:54:02 -08001149int av_sync_set_pause_pts(void *sync, pts90K pts)
1150{
1151 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1152
1153 if (!avsync)
1154 return -1;
1155
1156 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001157 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001158 return 0;
1159}
1160
1161int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1162{
1163 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1164
1165 if (!avsync)
1166 return -1;
1167
1168 avsync->pause_pts_cb = cb;
1169 avsync->pause_cb_priv = priv;
1170 return 0;
1171}
Song Zhaoea5a0412021-01-18 16:40:08 -08001172
yongchun.li428390d2022-02-17 17:15:40 -08001173int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1174{
1175 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1176
1177 if (!avsync)
1178 return -1;
1179
1180 avsync->underflow_cb = cb;
1181 avsync->underflow_cb_priv = priv;
1182
1183 if (cfg)
1184 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1185 else
1186 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1187
1188 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1189 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1190 avsync->underflow_cfg.time_thresh);
1191 return 0;
1192}
Song Zhaoea5a0412021-01-18 16:40:08 -08001193static void trigger_audio_start_cb(struct av_sync_session *avsync,
1194 avs_ascb_reason reason)
1195{
1196 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001197 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001198 pthread_mutex_lock(&avsync->lock);
1199 if (avsync->audio_start) {
1200 avsync->audio_start(avsync->audio_start_priv, reason);
1201 avsync->session_started = true;
1202 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001203 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001204 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1205 }
1206 pthread_mutex_unlock(&avsync->lock);
1207 }
1208}
1209
Song Zhao5296acf2024-02-02 21:45:04 +00001210static int update_pcr_master_disc_thres(struct av_sync_session * avsync, pts90K pts)
1211{
1212 pts90K pcr = -1;
1213
1214 if (!msync_session_get_pcr(avsync->fd, &pcr, NULL) && pcr != -1) {
1215 pts90K delta = abs_diff(pcr, pts);
1216
1217 if (delta * 3 > avsync->disc_thres_min)
1218 avsync->disc_thres_min = 3 * delta;
1219
1220 log_info("%d update disc_thres_min to %u delta %u",
1221 avsync->session_id, avsync->disc_thres_min, delta);
1222 return 0;
1223 }
1224 return -1;
1225}
1226
Song Zhaoea5a0412021-01-18 16:40:08 -08001227avs_start_ret av_sync_audio_start(
1228 void *sync,
1229 pts90K pts,
1230 pts90K delay,
1231 audio_start_cb cb,
1232 void *priv)
1233{
1234 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1235 uint32_t start_mode;
yongchun.li06965172022-12-14 19:50:31 -08001236 uint32_t systime = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001237 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1238 bool create_poll_t = false;
1239
1240 if (!avsync)
1241 return ret;
1242
yongchun.li59e873d2021-07-07 11:42:38 -07001243 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1244 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001245
yongchun.li06965172022-12-14 19:50:31 -08001246 if (avsync->in_audio_switch) {
1247 msync_session_get_wall(avsync->fd, &systime, NULL);
1248 if (systime == AV_SYNC_INVALID_PTS) {
1249 log_info("%d Invalid systime could be paused pts %d ms switch_state %d again",
1250 avsync->session_id, (int) pts/90, avsync->audio_switch_state);
1251 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
1252 ret = AV_SYNC_ASTART_AGAIN;
1253 goto exit;
1254 }
1255 }
1256
yongchun.li59e873d2021-07-07 11:42:38 -07001257 if (avsync->in_audio_switch &&
1258 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1259 {
1260 start_mode = AVS_START_SYNC;
1261 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1262 } else {
1263 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1264 log_error("[%d]fail to set audio start", avsync->session_id);
1265 }
1266 if (avsync->in_audio_switch &&
1267 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1268 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
Song Zhao4bd18762022-09-30 16:39:52 -07001269 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB
1270 && start_mode == AVS_START_SYNC) {
yongchun.li59e873d2021-07-07 11:42:38 -07001271 log_info("%d audio_switch audio need drop first.ahead %d ms",
1272 avsync->session_id, (int)(systime - pts)/90);
1273 ret = AV_SYNC_ASTART_AGAIN;
1274 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1275 goto exit;
1276 }
1277 else {
1278 int diff = (int)(pts - systime);
1279 log_info("%d audio_switch_state to start mode %d diff %d ms",
1280 avsync->session_id, start_mode, diff/90);
yongchun.li59e873d2021-07-07 11:42:38 -07001281 if (diff < A_ADJ_THREDHOLD_LB) {
1282 log_info("%d orig mode %d already close enough direct start",
1283 avsync->session_id, start_mode);
1284 start_mode = AVS_START_SYNC;
Song Zhao4bd18762022-09-30 16:39:52 -07001285 } else if (start_mode != AVS_START_ASYNC) {
1286 log_info("%d drop too far mode %d need to try ASYNC",
1287 avsync->session_id, start_mode);
1288 msync_session_set_audio_stop(avsync->fd);
1289 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1290 log_error("[%d]fail to set audio start", avsync->session_id);
1291 log_info("%d New start mode %d",
1292 avsync->session_id, start_mode);
yongchun.li59e873d2021-07-07 11:42:38 -07001293 }
Song Zhao4bd18762022-09-30 16:39:52 -07001294 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
yongchun.li59e873d2021-07-07 11:42:38 -07001295 }
yongchun.li107a6162021-05-05 02:38:57 -07001296 }
1297
Song Zhaoea5a0412021-01-18 16:40:08 -08001298 if (start_mode == AVS_START_SYNC) {
1299 ret = AV_SYNC_ASTART_SYNC;
1300 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001301 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhao5296acf2024-02-02 21:45:04 +00001302
1303 /* for DTG stream, initial delta between apts and pcr is big */
1304 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
1305 update_pcr_master_disc_thres(avsync, pts);
1306
Song Zhaod62bb392021-04-23 12:25:49 -07001307 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001308 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001309 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhao5296acf2024-02-02 21:45:04 +00001310
1311 /* for DTG stream, initial delta between apts and pcr is big */
1312 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
1313 update_pcr_master_disc_thres(avsync, pts);
Song Zhaod62bb392021-04-23 12:25:49 -07001314 } else if (start_mode == AVS_START_AGAIN) {
1315 ret = AV_SYNC_ASTART_AGAIN;
1316 }
1317
Song Zhao5296acf2024-02-02 21:45:04 +00001318 avsync->last_pts = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001319 if (ret == AV_SYNC_ASTART_AGAIN)
1320 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001321
Song Zhao76005282022-03-08 16:49:41 -08001322 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1323 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001324 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001325
1326 if (start_mode == AVS_START_ASYNC) {
1327 if (!cb) {
1328 log_error("[%d]invalid cb", avsync->session_id);
1329 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001330 }
Song Zhao76005282022-03-08 16:49:41 -08001331 avsync->audio_start = cb;
1332 avsync->audio_start_priv = priv;
1333 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001334
Song Zhaod62bb392021-04-23 12:25:49 -07001335 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001336 int ret;
1337
1338 log_info("[%d]start poll thread", avsync->session_id);
1339 avsync->quit_poll = false;
1340 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1341 if (ret) {
1342 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1343 return AV_SYNC_ASTART_ERR;
1344 }
1345 }
Song Zhaod62bb392021-04-23 12:25:49 -07001346 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001347 msync_session_get_wall(avsync->fd, &systime, NULL);
1348 log_info("[%d]return %u w %u pts %u d %u",
1349 avsync->session_id, ret, systime, pts, delay);
1350 }
1351exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001352 log_info("[%d]return %u", avsync->session_id, ret);
1353 return ret;
1354}
1355
1356int av_sync_audio_render(
1357 void *sync,
1358 pts90K pts,
1359 struct audio_policy *policy)
1360{
1361 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001362 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001363 uint32_t systime;
1364 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1365 avs_audio_action action = AA_SYNC_AA_MAX;
1366
1367 if (!avsync || !policy)
1368 return -1;
1369
yongchun.li107a6162021-05-05 02:38:57 -07001370 msync_session_get_wall(avsync->fd, &systime, NULL);
Song Zhao5296acf2024-02-02 21:45:04 +00001371 avsync->last_pts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001372
1373 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1374 pts, systime, avsync->mode, (int)(pts-systime)/90);
1375
1376 if (avsync->in_audio_switch
1377 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
Song Zhao4bd18762022-09-30 16:39:52 -07001378 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_MB) {
yongchun.li107a6162021-05-05 02:38:57 -07001379 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1380 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1381 action = AV_SYNC_AA_RENDER;
1382 } else if ((int)(systime - pts) > 0) {
1383 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1384 (int)(systime - pts)/90, systime, pts);
1385 action = AV_SYNC_AA_DROP;
1386 } else {
1387 action = AV_SYNC_AA_INSERT;
1388 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1389 (int)(pts - systime)/90, systime, pts);
1390 }
1391 goto done;
1392 }
1393
Song Zhaoea5a0412021-01-18 16:40:08 -08001394 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1395 avsync->mode == AV_SYNC_MODE_AMASTER) {
1396 action = AV_SYNC_AA_RENDER;
1397 goto done;
1398 }
1399
Song Zhaod62bb392021-04-23 12:25:49 -07001400 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001401 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001402 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1403 action = AV_SYNC_AA_DROP;
1404 goto done;
1405 }
1406
Song Zhao7daf3a12021-05-10 22:22:25 -07001407 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
Song Zhaob8833c12024-02-02 21:54:36 +00001408 avsync->mode == AV_SYNC_MODE_AMASTER ||
1409 avsync->active_mode == AV_SYNC_MODE_AMASTER) {
Song Zhao7daf3a12021-05-10 22:22:25 -07001410 action = AV_SYNC_AA_RENDER;
1411 goto done;
1412 }
1413
Song Zhaod62bb392021-04-23 12:25:49 -07001414 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1415 LIVE_MODE(avsync->mode) &&
1416 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1417 /* outlier by stream error */
1418 avsync->outlier_cnt++;
1419 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1420 /* treat as disc, just drop current frame */
1421 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1422 avsync->outlier_cnt = 0;
1423 action = AV_SYNC_AA_DROP;
1424 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001425 goto done;
1426 }
1427 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1428 pts = systime;
1429 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001430 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001431 goto done;
1432 }
1433
1434 avsync->outlier_cnt = 0;
1435 /* low bound from sync_lost to sync_setup */
1436 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1437 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1438 action = AV_SYNC_AA_RENDER;
1439 goto done;
1440 }
1441
1442 /* high bound of sync_setup */
1443 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1444 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1445 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001446 action = AV_SYNC_AA_RENDER;
1447 goto done;
1448 }
1449
1450 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001451 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001452 action = AV_SYNC_AA_DROP;
1453 goto done;
1454 }
1455
1456 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001457 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001458 action = AV_SYNC_AA_INSERT;
1459 goto done;
1460 }
1461
1462done:
1463 policy->action = action;
1464 policy->delta = (int)(systime - pts);
1465 if (action == AV_SYNC_AA_RENDER) {
1466 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001467 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001468 if (!out_lier)
1469 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001470 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001471 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001472 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1473 msync_session_update_apts(avsync->fd, systime, pts, 0);
1474 log_info("[%d] audio switch done sys %u pts %u",
1475 avsync->session_id, systime, pts);
1476 msync_session_set_audio_switch(avsync->fd, false);
1477 avsync->in_audio_switch = false;
1478 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1479 } else {
1480 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1481 avsync->session_id, action, systime, pts, systime - pts);
1482 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001483 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001484 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001485 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001486 avsync->last_disc_pts != pts &&
1487 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001488 log_info ("[%d]audio disc %u --> %u",
1489 avsync->session_id, systime, pts);
1490 msync_session_set_audio_dis(avsync->fd, pts);
1491 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001492 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001493 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001494
1495 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001496 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001497 if (!avsync->audio_drop_cnt)
1498 avsync->audio_drop_start = now;
1499 avsync->audio_drop_cnt++;
1500 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1501 log_info ("[%d]audio keep dropping sys %u vs a %u",
1502 avsync->session_id, systime, pts);
1503 msync_session_set_audio_dis(avsync->fd, pts);
1504 }
Song Zhao409739b2021-05-12 22:21:40 -07001505 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001506 if (action != AV_SYNC_AA_DROP)
1507 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001508 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001509 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001510 }
1511
1512 return ret;
1513}
1514
Song Zhaof3350d32023-08-18 16:27:31 -07001515int av_sync_get_pos(void *sync, pts90K *pts, uint64_t *mono_clock)
1516{
1517 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1518
1519 if (!avsync || !pts)
1520 return -1;
1521
1522 if (avsync->type != AV_SYNC_TYPE_AUDIO &&
1523 avsync->type != AV_SYNC_TYPE_VIDEO)
1524 return -2;
1525 return msync_session_get_pts(avsync->fd, pts,
1526 mono_clock, avsync->type == AV_SYNC_TYPE_VIDEO);
1527}
1528
Song Zhaoea5a0412021-01-18 16:40:08 -08001529int av_sync_get_clock(void *sync, pts90K *pts)
1530{
1531 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1532
1533 if (!avsync || !pts)
1534 return -1;
1535 return msync_session_get_wall(avsync->fd, pts, NULL);
1536}
1537
1538static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001539 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001540 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001541{
Song Zhao76005282022-03-08 16:49:41 -08001542 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1543 avsync->session_id, avsync->active_mode, avsync->mode,
1544 v_active, a_active, v_timeout, stat);
1545
1546 /* iptv delayed start */
1547 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1548 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1549
Song Zhaoea5a0412021-01-18 16:40:08 -08001550 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1551 float speed;
Song Zhao7e8c68f2022-07-12 16:24:30 -07001552 if (a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001553 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001554 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhao6183ca92022-07-29 09:57:03 -07001555 } else if (!a_active && !avsync->session_started) {
1556 /* quit waiting ASAP */
1557 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoea5a0412021-01-18 16:40:08 -08001558 }
1559
1560 if (!msync_session_get_rate(avsync->fd, &speed)) {
1561 /* speed change is triggered by asink,
1562 * attached audio HAL will handle it
1563 */
1564 if (speed != avsync->speed)
1565 log_info("[%d]new rate %f", avsync->session_id, speed);
Song Zhaoa73fcf32023-01-13 08:12:26 -08001566#if 0 //don't use freerun for trick mode. Or A/V gap will keep increasing
Song Zhaoea5a0412021-01-18 16:40:08 -08001567 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001568 if (avsync->mode != avsync->backup_mode) {
1569 avsync->mode = avsync->backup_mode;
1570 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1571 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001572 } else {
1573 avsync->backup_mode = avsync->mode;
1574 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1575 log_info("[%d]audio to freerun mode", avsync->session_id);
1576 }
Song Zhaoa73fcf32023-01-13 08:12:26 -08001577#endif
Song Zhaoea5a0412021-01-18 16:40:08 -08001578 avsync->speed = speed;
1579 }
Song Zhaod62bb392021-04-23 12:25:49 -07001580 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1581 struct session_debug debug;
Song Zhao5296acf2024-02-02 21:45:04 +00001582
1583 if (a_active && avsync->audio_start) {
1584 if (v_active || v_timeout) {
1585 log_info("audio start cb");
1586 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1587 }
1588 }
1589
Song Zhaod62bb392021-04-23 12:25:49 -07001590 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001591 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001592 avsync->backup_mode = avsync->mode;
1593 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001594 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001595 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001596 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001597 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001598 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001599 log_warn("[%d]audio back to mode %d",
1600 avsync->session_id, avsync->mode);
1601 }
1602 }
Song Zhao76005282022-03-08 16:49:41 -08001603 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1604 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaob8833c12024-02-02 21:54:36 +00001605 if (a_active && avsync->audio_start) {
1606 if (v_active || v_timeout) {
1607 log_info("audio start cb");
1608 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1609 }
1610 }
1611
Song Zhaoea5a0412021-01-18 16:40:08 -08001612 }
1613}
1614
1615static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001616 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001617 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001618{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001619 struct session_debug debug;
1620
Song Zhao76005282022-03-08 16:49:41 -08001621 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1622 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001623 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1624 if (debug.debug_freerun && !avsync->debug_freerun) {
1625 avsync->backup_mode = avsync->mode;
1626 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1627 avsync->debug_freerun = true;
1628 log_warn("[%d]video to freerun mode", avsync->session_id);
1629 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1630 avsync->mode = avsync->backup_mode;
1631 avsync->debug_freerun = false;
1632 log_warn("[%d]video back to mode %d",
1633 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001634 }
1635 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001636}
1637
1638static void * poll_thread(void * arg)
1639{
1640 int ret = 0;
1641 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1642 const int fd = avsync->fd;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001643 int poll_timeout = 10;
Song Zhaoea5a0412021-01-18 16:40:08 -08001644 struct pollfd pfd = {
1645 /* default blocking capture */
Song Zhao4bd18762022-09-30 16:39:52 -07001646 .events = POLLPRI,
Song Zhaoea5a0412021-01-18 16:40:08 -08001647 .fd = avsync->fd,
1648 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001649 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001650
Song Zhaoea5a0412021-01-18 16:40:08 -08001651 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001652
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001653 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001654 prctl (PR_SET_NAME, "avs_apoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001655 sflag = SRC_A;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001656 } else if (avsync->type == AV_SYNC_TYPE_VIDEO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001657 prctl (PR_SET_NAME, "avs_vpoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001658 sflag = SRC_V;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001659 poll_timeout = 100;
1660 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001661
Song Zhaoea5a0412021-01-18 16:40:08 -08001662 while (!avsync->quit_poll) {
1663 for (;;) {
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001664 ret = poll(&pfd, 1, poll_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001665 if (ret > 0)
1666 break;
1667 if (avsync->quit_poll)
1668 goto exit;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001669 if (errno == EINTR) {
1670 log_debug("[%d] poll interrupted", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001671 continue;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001672 }
Song Zhao4bd18762022-09-30 16:39:52 -07001673 if (errno == EAGAIN || errno == ENOMEM) {
1674 log_info("[%d] poll error %d", avsync->session_id, errno);
1675 continue;
1676 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001677 }
1678
1679 /* error handling */
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001680 if (pfd.revents & POLLERR) {
1681 usleep(poll_timeout * 1000);
1682 continue;
1683 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001684
Song Zhao4bd18762022-09-30 16:39:52 -07001685 if (pfd.revents & POLLNVAL) {
1686 log_warn("[%d] fd closed", avsync->session_id);
1687 goto exit;
1688 }
Song Zhaod62bb392021-04-23 12:25:49 -07001689 /* mode change. Non-exclusive wait so all the processes
1690 * shall be woken up
1691 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001692 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001693 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001694 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001695
Song Zhao9fef59c2022-08-17 12:43:10 -07001696 msync_session_get_stat(fd, true, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001697 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001698
1699 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001700 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001701 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001702 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001703 usleep(10000);
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001704 } else {
1705 log_debug("[%d] unexpected revents %x", avsync->session_id, pfd.revents);
1706 usleep(poll_timeout * 1000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001707 }
1708 }
1709exit:
1710 log_info("[%d]quit", avsync->session_id);
1711 return NULL;
1712}
1713
Song Zhao623e2f12021-09-03 15:54:04 -07001714#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1715/* return ppm between demod and PCR clock */
1716int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1717{
1718 int fd = -1, ppm = 0, nread;
1719 char buf[128];
1720 uint32_t reg_v, lock;
1721 float val;
1722
1723 fd = open(DEMOD_NODE, O_RDWR);
1724 if (fd < 0) {
1725 log_warn("node not found %s", DEMOD_NODE);
1726 /* do not retry */
1727 avsync->ppm_adjusted = true;
1728 return 0;
1729 }
1730 snprintf(buf, sizeof(buf), "%d", 5);
1731 write(fd, buf, 2);
1732
1733 lseek(fd, 0, SEEK_SET);
1734
hanghang.luo02efd312022-08-26 09:49:53 +08001735 nread = read(fd, buf, sizeof(buf)-1);
Song Zhao623e2f12021-09-03 15:54:04 -07001736 if (nread <= 0) {
1737 log_error("read error");
1738 goto err;
1739 }
1740 buf[nread] = 0;
1741 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1742 log_error("wrong format %s", buf);
1743 goto err;
1744 }
1745 if (lock != 0x1f) {
1746 log_info("demod not locked");
1747 goto err;
1748 }
1749 if (reg_v > ((2 << 20) - 1))
1750 reg_v -= (2 << 21);
1751 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1752 ppm = val;
1753 log_info("ppm from SFO %d", ppm);
1754 avsync->ppm_adjusted = true;
1755
1756err:
1757 if (fd >= 0)
1758 close(fd);
1759 return ppm;
1760}
1761
Song Zhaod62bb392021-04-23 12:25:49 -07001762int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001763{
1764 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001765 struct pcr_info pcr;
1766 enum pcr_monitor_status status;
1767 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001768 if (!avsync)
1769 return -1;
1770
1771 if (avsync->type != AV_SYNC_TYPE_PCR)
1772 return -2;
1773
Song Zhao623e2f12021-09-03 15:54:04 -07001774 /* initial estimation from Demod SFO HW */
1775 if (!avsync->ppm_adjusted) {
1776 ppm = dmod_get_sfo_dev(avsync);
1777 if (ppm != 0) {
1778 /* ppm > 0 means board clock is faster */
1779 msync_session_set_clock_dev(avsync->fd, -ppm);
1780 }
1781 }
wei.dubcc2ed22021-05-19 07:16:10 -04001782 pcr.monoclk = mono_clock / 1000;
1783 pcr.pts = (long long) pts * 1000 / 90;
1784 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1785
1786 status = pcr_monitor_get_status(avsync->pcr_monitor);
1787
1788 if (status >= DEVIATION_READY) {
1789 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1790 if (avsync->ppm != ppm) {
1791 avsync->ppm = ppm;
1792 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1793 if (msync_session_set_clock_dev(avsync->fd, ppm))
1794 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001795 else
1796 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001797 }
1798 }
1799
Song Zhaod62bb392021-04-23 12:25:49 -07001800 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001801}
1802
Song Zhaod62bb392021-04-23 12:25:49 -07001803int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001804{
1805 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1806
1807 if (!avsync)
1808 return -1;
1809
Song Zhaod62bb392021-04-23 12:25:49 -07001810 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001811}
1812
1813int av_sync_set_session_name(void *sync, const char *name)
1814{
1815 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1816
1817 if (!avsync)
1818 return -1;
1819
1820 return msync_session_set_name(avsync->fd, name);
1821}
yongchun.li107a6162021-05-05 02:38:57 -07001822
1823int av_sync_set_audio_switch(void *sync, bool start)
1824{
1825 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1826 bool v_active, a_active, v_timeout;
1827
1828 if (!avsync)
1829 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001830 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001831 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001832 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001833 log_error("[%d] can not get session state",
1834 avsync->session_id);
1835 return -1;
1836 }
1837 if (!v_active || !a_active) {
1838 log_error("[%d] no apply if not AV both active v %d a %d",
1839 avsync->session_id, v_active, a_active);
1840 return -1;
1841 }
1842 if (msync_session_set_audio_switch(avsync->fd, start)) {
1843 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1844 return -1;
1845 }
1846 avsync->in_audio_switch = start;
1847 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1848 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1849 return 0;
1850}
1851
1852int av_sync_get_audio_switch(void *sync, bool *start)
1853{
1854 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1855
1856 if (!avsync)
1857 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001858 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001859 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001860 log_error("[%d] can not audio seamless switch state",
1861 avsync->session_id);
1862 return -1;
1863 }
1864 if (start) *start = avsync->in_audio_switch;
1865 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001866}
Song Zhao8039f562021-05-18 18:11:25 -07001867
Song Zhao623e2f12021-09-03 15:54:04 -07001868enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001869{
1870 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1871
wei.dubcc2ed22021-05-19 07:16:10 -04001872 if (!avsync || !ppm)
1873 return CLK_RECOVERY_ERR;
1874 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001875 return CLK_RECOVERY_NOT_RUNNING;
1876
wei.dubcc2ed22021-05-19 07:16:10 -04001877 if (msync_session_get_clock_dev(avsync->fd, ppm))
1878 return CLK_RECOVERY_ERR;
1879
1880 if (*ppm == 0)
1881 return CLK_RECOVERY_ONGOING;
1882 else
1883 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001884}
Song Zhao95bd0922021-09-21 14:07:46 -07001885
1886static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1887{
1888 int ret;
1889
1890 if (!avsync->frame_q) {
1891 avsync->frame_q = create_q(MAX_FRAME_NUM);
1892 if (!avsync->frame_q) {
1893 log_error("[%d]create queue fail", avsync->session_id);
1894
1895 return -1;
1896 }
1897 }
1898
1899 ret = queue_item(avsync->frame_q, frame);
1900 if (ret)
hanghang.luo02efd312022-08-26 09:49:53 +08001901 log_error("queue fail:%d", ret);
Song Zhao95bd0922021-09-21 14:07:46 -07001902 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1903 return ret;
1904}
1905
1906int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1907{
1908 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1909
1910 if (!avsync)
1911 return -1;
1912 avsync->msys = msys;
1913 return 0;
1914}
1915
1916static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1917{
1918 struct vframe *frame = NULL, *enter_last_frame = NULL;
1919 uint64_t systime;
1920 int toggle_cnt = 0;
1921
1922 enter_last_frame = avsync->last_frame;
1923 systime = avsync->msys;
1924 log_debug("[%d]sys %llu", avsync->session_id, systime);
1925 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1926 if (systime >= frame->mts) {
1927 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1928 toggle_cnt++;
1929
1930 if (avsync->last_frame)
1931 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1932
1933 dqueue_item(avsync->frame_q, (void **)&frame);
1934 if (avsync->last_frame) {
1935 /* free frame that are not for display */
1936 if (toggle_cnt > 1) {
1937 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1938 avsync->last_frame->mts, frame->mts, systime);
1939 avsync->last_frame->free(avsync->last_frame);
1940 }
1941 } else {
1942 avsync->first_frame_toggled = true;
1943 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1944 }
1945 avsync->last_frame = frame;
1946 } else
1947 break;
1948 }
1949
1950 if (avsync->last_frame) {
1951 if (enter_last_frame != avsync->last_frame)
hanghang.luo02efd312022-08-26 09:49:53 +08001952 log_debug("[%d]pop %lu", avsync->session_id, avsync->last_frame->pts);
1953 log_trace("[%d]pop=%llu, system=%llu, diff %llu(ms), QNum=%d", avsync->session_id,
Song Zhao95bd0922021-09-21 14:07:46 -07001954 avsync->last_frame->mts,
1955 systime, (systime - avsync->last_frame->mts) / 1000000,
1956 queue_size(avsync->frame_q));
1957 } else
1958 if (enter_last_frame != avsync->last_frame)
1959 log_debug("[%d]pop (nil)", avsync->session_id);
1960
1961 if (avsync->last_frame)
1962 avsync->last_frame->hold_period++;
1963 return avsync->last_frame;
1964}
Song Zhao6183ca92022-07-29 09:57:03 -07001965
1966int avs_sync_stop_audio(void *sync)
1967{
1968 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1969
1970 if (!avsync)
1971 return -1;
1972
1973 return msync_session_stop_audio(avsync->fd);
1974}
bo.xiao05ba1ac2022-12-13 14:38:13 +08001975
1976int avs_sync_set_eos(void *sync)
1977{
1978 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1979
1980 if (!avsync)
1981 return -1;
1982
1983 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
1984 if (avsync->state == AV_SYNC_STAT_INIT) {
1985 avsync->state = AV_SYNC_STAT_RUNNING;
1986 log_debug("[%d]eos trigger state change: init --> running", avsync->session_id);
1987 }
1988 }
1989
1990 return 0;
1991}