blob: ccd5e6182baaf7870a0af80c82158d1fdb1eea0b [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
888 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
889 return false;
890
891 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
892 return true;
893
Song Zhaoad7c8232021-12-14 11:46:48 -0800894 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS &&
895 avsync->pause_pts == frame->pts)
896 return true;
897
Song Zhao08fa16b2021-12-08 14:30:17 -0800898 if (systime == AV_SYNC_INVALID_PTS &&
899 avsync->mode == AV_SYNC_MODE_AMASTER)
900 return false;
901
Song Zhao6dce2672022-01-13 11:32:44 -0800902 if (next_frame)
903 nfpts = next_frame->pts + avsync->extra_delay;
904
Song Zhao7e24b182022-04-01 08:46:40 -0700905 if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
fei.deng63e43e12021-09-23 19:44:01 +0800906 /* We need to ensure that the video outputs smoothly,
907 so output video frame by frame hold_period */
908 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
909 avsync->last_frame &&
910 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
911 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
912 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700913 return true;
914 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700915 }
916
Song Zhaoc03ba122020-12-23 21:54:02 -0800917 if (!fpts) {
918 if (avsync->last_frame) {
919 /* try to accumulate duration as PTS */
920 fpts = avsync->vpts + avsync->last_frame->duration;
921 } else {
922 fpts = avsync->vpts;
923 }
924 }
925 systime += pts_correction;
926
927 /* phase adjustment */
928 if (avsync->phase_set)
929 systime += avsync->phase;
930
yongchun.lia50b1e92021-08-07 01:11:54 +0000931 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800932 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000933 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700934 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800935 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800936 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800937 return false;
938
Song Zhaoa2985cb2021-06-24 12:01:47 -0700939 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
940 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700941 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800942
yongchun.li0ee6e372021-08-20 04:26:04 -0700943 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700944 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800945 avsync->last_pts = fpts;
946 if (time_diff(&now, &avsync->sync_lost_print_time) >=
947 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700948 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800949 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800950 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700951 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800952 } else
953 avsync->sync_lost_cnt++;
954 }
Song Zhaod62bb392021-04-23 12:25:49 -0700955
956 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
957 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700958 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700959 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700960 /* outlier by stream error */
961 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700962 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700963 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
964 log_info("render outlier %u", fpts);
965 return true;
966 }
967 }
968
969 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800970 avsync->state = AV_SYNC_STAT_SYNC_LOST;
971 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800972 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700973 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800974 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700975
Song Zhao7e24b182022-04-01 08:46:40 -0700976 if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700977 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700978 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700979 msync_session_set_video_dis(avsync->fd, fpts);
980 avsync->last_disc_pts = fpts;
Song Zhao59d732d2024-01-23 22:09:15 -0800981 if (avsync->mode == AV_SYNC_MODE_VMASTER) {
982 systime = fpts;
983 avsync->last_r_syst = -1;
984 }
Song Zhaoa2985cb2021-06-24 12:01:47 -0700985 }
986
987 if ((int)(systime - fpts) > 0) {
988 if ((int)(systime - fpts) < avsync->disc_thres_max) {
989 /* catch up PCR */
Song Zhao59d732d2024-01-23 22:09:15 -0800990 avsync->last_r_syst = -1;
Song Zhaof46932e2021-05-21 01:51:45 -0700991 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700992 } else {
993 /* render according to FPS */
994 if (!VALID_TS(avsync->last_r_syst) ||
995 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
996 avsync->last_r_syst = systime;
997 return true;
998 }
999 return false;
1000 }
1001 } else if (LIVE_MODE(avsync->mode)) {
1002 /* hold if the gap is small */
1003 if ((int)(fpts - systime) < avsync->disc_thres_max) {
1004 return false;
1005 } else {
1006 /* render according to FPS */
1007 if (!VALID_TS(avsync->last_r_syst) ||
1008 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
1009 avsync->last_r_syst = systime;
1010 return true;
1011 }
1012 return false;
1013 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001014 }
1015 }
1016
Song Zhao52f55192021-05-06 10:52:21 -07001017 /* In some cases, keeping pattern will enlarge the gap */
1018 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
1019 avsync->first_frame_toggled) {
1020 reset_pattern(avsync->pattern_detector);
Song Zhaofd007632022-09-30 16:21:30 -07001021 log_info("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -07001022 systime, fpts);
1023 }
1024
Song Zhaoc03ba122020-12-23 21:54:02 -08001025 expire = (int)(systime - fpts) >= 0;
1026
1027 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -08001028 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001029 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -08001030 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001031 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001032 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001033 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -08001034 }
Song Zhao6dce2672022-01-13 11:32:44 -08001035 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -08001036 && avsync->first_frame_toggled) {
1037 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -08001038 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001039 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -08001040 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001041 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001042 }
1043 }
1044
Song Zhaoa58c3e92021-03-09 18:52:55 -08001045 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -08001046 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -08001047 (avsync->last_frame?avsync->last_frame->hold_period:0),
1048 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -08001049 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -08001050
1051 if (expire) {
1052 avsync->vpts = fpts;
1053 /* phase adjustment */
1054 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +00001055 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -08001056 if ((int)(systime - fpts) >= 0 &&
1057 (int)(fpts + interval - systime) > 0) {
1058 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -08001059 avsync->phase_set = true;
Song Zhaofd007632022-09-30 16:21:30 -07001060 log_debug("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -08001061 }
Song Zhao1561e542022-01-12 10:37:55 -08001062 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -08001063 if ((int)(systime - fpts) >= 0 &&
1064 (int)(fpts + interval - systime) > 0) {
1065 int vsync_pts_delta = (int)(systime - fpts);
1066
1067 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1068 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001069 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001070 log_info("[%d] too aligned adjust phase to %d",
1071 avsync->session_id, (int)avsync->phase);
1072 }
1073 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001074 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001075 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaofd007632022-09-30 16:21:30 -07001076 log_info("[%d]sync setup on frame %u", avsync->session_id, fpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001077 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001078 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001079 }
1080 return expire;
1081}
1082
Song Zhao35a82df2021-04-15 10:58:49 -07001083static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001084{
Song Zhaoea5a0412021-01-18 16:40:08 -08001085 log_trace("[%d]cur_period: %d last_period: %d",
1086 avsync->session_id, cur_period, last_period);
Song Zhaobb3b4f32023-10-17 16:08:12 -07001087 return detect_pattern(avsync->pattern_detector, cur_period, last_period);
Song Zhaoc03ba122020-12-23 21:54:02 -08001088}
1089
1090int av_sync_set_speed(void *sync, float speed)
1091{
1092 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1093
1094 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001095 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001096 return -1;
1097 }
1098
Song Zhao76005282022-03-08 16:49:41 -08001099 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001100 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001101 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001102 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001103
Song Zhaoea5a0412021-01-18 16:40:08 -08001104 avsync->speed = speed;
1105
1106 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhaoa73fcf32023-01-13 08:12:26 -08001107 if (speed == 1.0)
1108 msync_session_set_wall_adj_thres(avsync->fd, DEFAULT_WALL_ADJ_THRES);
1109 else
1110 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
1111 log_info("[%d]adjust wall adj threshold to %d", avsync->session_id,
1112 (speed == 1.0) ? DEFAULT_WALL_ADJ_THRES : avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -08001113 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001114
Song Zhaoea5a0412021-01-18 16:40:08 -08001115 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1116 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001117}
1118
1119int av_sync_change_mode(void *sync, enum sync_mode mode)
1120{
1121 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1122
1123 if (!avsync)
1124 return -1;
1125
Song Zhaoea5a0412021-01-18 16:40:08 -08001126 if (msync_session_set_mode(avsync->fd, mode)) {
1127 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001128 return -1;
1129 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001130 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001131 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001132 return 0;
1133}
1134
Song Zhao01031bb2021-05-13 21:23:20 -07001135int av_sync_get_mode(void *sync, enum sync_mode *mode)
1136{
1137 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1138
1139 if (!avsync || !mode)
1140 return -1;
1141
1142 *mode = avsync->mode;
1143 return 0;
1144}
1145
Song Zhaoc03ba122020-12-23 21:54:02 -08001146int av_sync_set_pause_pts(void *sync, pts90K pts)
1147{
1148 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1149
1150 if (!avsync)
1151 return -1;
1152
1153 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001154 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001155 return 0;
1156}
1157
1158int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1159{
1160 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1161
1162 if (!avsync)
1163 return -1;
1164
1165 avsync->pause_pts_cb = cb;
1166 avsync->pause_cb_priv = priv;
1167 return 0;
1168}
Song Zhaoea5a0412021-01-18 16:40:08 -08001169
yongchun.li428390d2022-02-17 17:15:40 -08001170int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1171{
1172 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1173
1174 if (!avsync)
1175 return -1;
1176
1177 avsync->underflow_cb = cb;
1178 avsync->underflow_cb_priv = priv;
1179
1180 if (cfg)
1181 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1182 else
1183 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1184
1185 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1186 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1187 avsync->underflow_cfg.time_thresh);
1188 return 0;
1189}
Song Zhaoea5a0412021-01-18 16:40:08 -08001190static void trigger_audio_start_cb(struct av_sync_session *avsync,
1191 avs_ascb_reason reason)
1192{
1193 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001194 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001195 pthread_mutex_lock(&avsync->lock);
1196 if (avsync->audio_start) {
1197 avsync->audio_start(avsync->audio_start_priv, reason);
1198 avsync->session_started = true;
1199 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001200 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001201 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1202 }
1203 pthread_mutex_unlock(&avsync->lock);
1204 }
1205}
1206
Song Zhao5296acf2024-02-02 21:45:04 +00001207static int update_pcr_master_disc_thres(struct av_sync_session * avsync, pts90K pts)
1208{
1209 pts90K pcr = -1;
1210
1211 if (!msync_session_get_pcr(avsync->fd, &pcr, NULL) && pcr != -1) {
1212 pts90K delta = abs_diff(pcr, pts);
1213
1214 if (delta * 3 > avsync->disc_thres_min)
1215 avsync->disc_thres_min = 3 * delta;
1216
1217 log_info("%d update disc_thres_min to %u delta %u",
1218 avsync->session_id, avsync->disc_thres_min, delta);
1219 return 0;
1220 }
1221 return -1;
1222}
1223
Song Zhaoea5a0412021-01-18 16:40:08 -08001224avs_start_ret av_sync_audio_start(
1225 void *sync,
1226 pts90K pts,
1227 pts90K delay,
1228 audio_start_cb cb,
1229 void *priv)
1230{
1231 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1232 uint32_t start_mode;
yongchun.li06965172022-12-14 19:50:31 -08001233 uint32_t systime = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001234 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1235 bool create_poll_t = false;
1236
1237 if (!avsync)
1238 return ret;
1239
yongchun.li59e873d2021-07-07 11:42:38 -07001240 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1241 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001242
yongchun.li06965172022-12-14 19:50:31 -08001243 if (avsync->in_audio_switch) {
1244 msync_session_get_wall(avsync->fd, &systime, NULL);
1245 if (systime == AV_SYNC_INVALID_PTS) {
1246 log_info("%d Invalid systime could be paused pts %d ms switch_state %d again",
1247 avsync->session_id, (int) pts/90, avsync->audio_switch_state);
1248 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
1249 ret = AV_SYNC_ASTART_AGAIN;
1250 goto exit;
1251 }
1252 }
1253
yongchun.li59e873d2021-07-07 11:42:38 -07001254 if (avsync->in_audio_switch &&
1255 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1256 {
1257 start_mode = AVS_START_SYNC;
1258 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1259 } else {
1260 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1261 log_error("[%d]fail to set audio start", avsync->session_id);
1262 }
1263 if (avsync->in_audio_switch &&
1264 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1265 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
Song Zhao4bd18762022-09-30 16:39:52 -07001266 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB
1267 && start_mode == AVS_START_SYNC) {
yongchun.li59e873d2021-07-07 11:42:38 -07001268 log_info("%d audio_switch audio need drop first.ahead %d ms",
1269 avsync->session_id, (int)(systime - pts)/90);
1270 ret = AV_SYNC_ASTART_AGAIN;
1271 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1272 goto exit;
1273 }
1274 else {
1275 int diff = (int)(pts - systime);
1276 log_info("%d audio_switch_state to start mode %d diff %d ms",
1277 avsync->session_id, start_mode, diff/90);
yongchun.li59e873d2021-07-07 11:42:38 -07001278 if (diff < A_ADJ_THREDHOLD_LB) {
1279 log_info("%d orig mode %d already close enough direct start",
1280 avsync->session_id, start_mode);
1281 start_mode = AVS_START_SYNC;
Song Zhao4bd18762022-09-30 16:39:52 -07001282 } else if (start_mode != AVS_START_ASYNC) {
1283 log_info("%d drop too far mode %d need to try ASYNC",
1284 avsync->session_id, start_mode);
1285 msync_session_set_audio_stop(avsync->fd);
1286 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1287 log_error("[%d]fail to set audio start", avsync->session_id);
1288 log_info("%d New start mode %d",
1289 avsync->session_id, start_mode);
yongchun.li59e873d2021-07-07 11:42:38 -07001290 }
Song Zhao4bd18762022-09-30 16:39:52 -07001291 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
yongchun.li59e873d2021-07-07 11:42:38 -07001292 }
yongchun.li107a6162021-05-05 02:38:57 -07001293 }
1294
Song Zhaoea5a0412021-01-18 16:40:08 -08001295 if (start_mode == AVS_START_SYNC) {
1296 ret = AV_SYNC_ASTART_SYNC;
1297 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001298 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhao5296acf2024-02-02 21:45:04 +00001299
1300 /* for DTG stream, initial delta between apts and pcr is big */
1301 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
1302 update_pcr_master_disc_thres(avsync, pts);
1303
Song Zhaod62bb392021-04-23 12:25:49 -07001304 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001305 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001306 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhao5296acf2024-02-02 21:45:04 +00001307
1308 /* for DTG stream, initial delta between apts and pcr is big */
1309 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
1310 update_pcr_master_disc_thres(avsync, pts);
Song Zhaod62bb392021-04-23 12:25:49 -07001311 } else if (start_mode == AVS_START_AGAIN) {
1312 ret = AV_SYNC_ASTART_AGAIN;
1313 }
1314
Song Zhao5296acf2024-02-02 21:45:04 +00001315 avsync->last_pts = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001316 if (ret == AV_SYNC_ASTART_AGAIN)
1317 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001318
Song Zhao76005282022-03-08 16:49:41 -08001319 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1320 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001321 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001322
1323 if (start_mode == AVS_START_ASYNC) {
1324 if (!cb) {
1325 log_error("[%d]invalid cb", avsync->session_id);
1326 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001327 }
Song Zhao76005282022-03-08 16:49:41 -08001328 avsync->audio_start = cb;
1329 avsync->audio_start_priv = priv;
1330 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001331
Song Zhaod62bb392021-04-23 12:25:49 -07001332 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001333 int ret;
1334
1335 log_info("[%d]start poll thread", avsync->session_id);
1336 avsync->quit_poll = false;
1337 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1338 if (ret) {
1339 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1340 return AV_SYNC_ASTART_ERR;
1341 }
1342 }
Song Zhaod62bb392021-04-23 12:25:49 -07001343 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001344 msync_session_get_wall(avsync->fd, &systime, NULL);
1345 log_info("[%d]return %u w %u pts %u d %u",
1346 avsync->session_id, ret, systime, pts, delay);
1347 }
1348exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001349 log_info("[%d]return %u", avsync->session_id, ret);
1350 return ret;
1351}
1352
1353int av_sync_audio_render(
1354 void *sync,
1355 pts90K pts,
1356 struct audio_policy *policy)
1357{
1358 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001359 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001360 uint32_t systime;
1361 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1362 avs_audio_action action = AA_SYNC_AA_MAX;
1363
1364 if (!avsync || !policy)
1365 return -1;
1366
yongchun.li107a6162021-05-05 02:38:57 -07001367 msync_session_get_wall(avsync->fd, &systime, NULL);
Song Zhao5296acf2024-02-02 21:45:04 +00001368 avsync->last_pts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001369
1370 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1371 pts, systime, avsync->mode, (int)(pts-systime)/90);
1372
1373 if (avsync->in_audio_switch
1374 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
Song Zhao4bd18762022-09-30 16:39:52 -07001375 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_MB) {
yongchun.li107a6162021-05-05 02:38:57 -07001376 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1377 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1378 action = AV_SYNC_AA_RENDER;
1379 } else if ((int)(systime - pts) > 0) {
1380 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1381 (int)(systime - pts)/90, systime, pts);
1382 action = AV_SYNC_AA_DROP;
1383 } else {
1384 action = AV_SYNC_AA_INSERT;
1385 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1386 (int)(pts - systime)/90, systime, pts);
1387 }
1388 goto done;
1389 }
1390
Song Zhaoea5a0412021-01-18 16:40:08 -08001391 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1392 avsync->mode == AV_SYNC_MODE_AMASTER) {
1393 action = AV_SYNC_AA_RENDER;
1394 goto done;
1395 }
1396
Song Zhaod62bb392021-04-23 12:25:49 -07001397 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001398 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001399 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1400 action = AV_SYNC_AA_DROP;
1401 goto done;
1402 }
1403
Song Zhao7daf3a12021-05-10 22:22:25 -07001404 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
Song Zhaob8833c12024-02-02 21:54:36 +00001405 avsync->mode == AV_SYNC_MODE_AMASTER ||
1406 avsync->active_mode == AV_SYNC_MODE_AMASTER) {
Song Zhao7daf3a12021-05-10 22:22:25 -07001407 action = AV_SYNC_AA_RENDER;
1408 goto done;
1409 }
1410
Song Zhaod62bb392021-04-23 12:25:49 -07001411 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1412 LIVE_MODE(avsync->mode) &&
1413 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1414 /* outlier by stream error */
1415 avsync->outlier_cnt++;
1416 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1417 /* treat as disc, just drop current frame */
1418 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1419 avsync->outlier_cnt = 0;
1420 action = AV_SYNC_AA_DROP;
1421 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001422 goto done;
1423 }
1424 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1425 pts = systime;
1426 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001427 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001428 goto done;
1429 }
1430
1431 avsync->outlier_cnt = 0;
1432 /* low bound from sync_lost to sync_setup */
1433 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1434 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1435 action = AV_SYNC_AA_RENDER;
1436 goto done;
1437 }
1438
1439 /* high bound of sync_setup */
1440 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1441 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1442 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001443 action = AV_SYNC_AA_RENDER;
1444 goto done;
1445 }
1446
1447 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001448 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001449 action = AV_SYNC_AA_DROP;
1450 goto done;
1451 }
1452
1453 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001454 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001455 action = AV_SYNC_AA_INSERT;
1456 goto done;
1457 }
1458
1459done:
1460 policy->action = action;
1461 policy->delta = (int)(systime - pts);
1462 if (action == AV_SYNC_AA_RENDER) {
1463 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001464 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001465 if (!out_lier)
1466 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001467 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001468 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001469 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1470 msync_session_update_apts(avsync->fd, systime, pts, 0);
1471 log_info("[%d] audio switch done sys %u pts %u",
1472 avsync->session_id, systime, pts);
1473 msync_session_set_audio_switch(avsync->fd, false);
1474 avsync->in_audio_switch = false;
1475 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1476 } else {
1477 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1478 avsync->session_id, action, systime, pts, systime - pts);
1479 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001480 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001481 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001482 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001483 avsync->last_disc_pts != pts &&
1484 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001485 log_info ("[%d]audio disc %u --> %u",
1486 avsync->session_id, systime, pts);
1487 msync_session_set_audio_dis(avsync->fd, pts);
1488 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001489 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001490 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001491
1492 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001493 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001494 if (!avsync->audio_drop_cnt)
1495 avsync->audio_drop_start = now;
1496 avsync->audio_drop_cnt++;
1497 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1498 log_info ("[%d]audio keep dropping sys %u vs a %u",
1499 avsync->session_id, systime, pts);
1500 msync_session_set_audio_dis(avsync->fd, pts);
1501 }
Song Zhao409739b2021-05-12 22:21:40 -07001502 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001503 if (action != AV_SYNC_AA_DROP)
1504 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001505 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001506 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001507 }
1508
1509 return ret;
1510}
1511
Song Zhaof3350d32023-08-18 16:27:31 -07001512int av_sync_get_pos(void *sync, pts90K *pts, uint64_t *mono_clock)
1513{
1514 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1515
1516 if (!avsync || !pts)
1517 return -1;
1518
1519 if (avsync->type != AV_SYNC_TYPE_AUDIO &&
1520 avsync->type != AV_SYNC_TYPE_VIDEO)
1521 return -2;
1522 return msync_session_get_pts(avsync->fd, pts,
1523 mono_clock, avsync->type == AV_SYNC_TYPE_VIDEO);
1524}
1525
Song Zhaoea5a0412021-01-18 16:40:08 -08001526int av_sync_get_clock(void *sync, pts90K *pts)
1527{
1528 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1529
1530 if (!avsync || !pts)
1531 return -1;
1532 return msync_session_get_wall(avsync->fd, pts, NULL);
1533}
1534
1535static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001536 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001537 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001538{
Song Zhao76005282022-03-08 16:49:41 -08001539 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1540 avsync->session_id, avsync->active_mode, avsync->mode,
1541 v_active, a_active, v_timeout, stat);
1542
1543 /* iptv delayed start */
1544 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1545 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1546
Song Zhaoea5a0412021-01-18 16:40:08 -08001547 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1548 float speed;
Song Zhao7e8c68f2022-07-12 16:24:30 -07001549 if (a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001550 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001551 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhao6183ca92022-07-29 09:57:03 -07001552 } else if (!a_active && !avsync->session_started) {
1553 /* quit waiting ASAP */
1554 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoea5a0412021-01-18 16:40:08 -08001555 }
1556
1557 if (!msync_session_get_rate(avsync->fd, &speed)) {
1558 /* speed change is triggered by asink,
1559 * attached audio HAL will handle it
1560 */
1561 if (speed != avsync->speed)
1562 log_info("[%d]new rate %f", avsync->session_id, speed);
Song Zhaoa73fcf32023-01-13 08:12:26 -08001563#if 0 //don't use freerun for trick mode. Or A/V gap will keep increasing
Song Zhaoea5a0412021-01-18 16:40:08 -08001564 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001565 if (avsync->mode != avsync->backup_mode) {
1566 avsync->mode = avsync->backup_mode;
1567 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1568 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001569 } else {
1570 avsync->backup_mode = avsync->mode;
1571 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1572 log_info("[%d]audio to freerun mode", avsync->session_id);
1573 }
Song Zhaoa73fcf32023-01-13 08:12:26 -08001574#endif
Song Zhaoea5a0412021-01-18 16:40:08 -08001575 avsync->speed = speed;
1576 }
Song Zhaod62bb392021-04-23 12:25:49 -07001577 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1578 struct session_debug debug;
Song Zhao5296acf2024-02-02 21:45:04 +00001579
1580 if (a_active && avsync->audio_start) {
1581 if (v_active || v_timeout) {
1582 log_info("audio start cb");
1583 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1584 }
1585 }
1586
Song Zhaod62bb392021-04-23 12:25:49 -07001587 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001588 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001589 avsync->backup_mode = avsync->mode;
1590 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001591 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001592 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001593 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001594 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001595 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001596 log_warn("[%d]audio back to mode %d",
1597 avsync->session_id, avsync->mode);
1598 }
1599 }
Song Zhao76005282022-03-08 16:49:41 -08001600 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1601 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaob8833c12024-02-02 21:54:36 +00001602 if (a_active && avsync->audio_start) {
1603 if (v_active || v_timeout) {
1604 log_info("audio start cb");
1605 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1606 }
1607 }
1608
Song Zhaoea5a0412021-01-18 16:40:08 -08001609 }
1610}
1611
1612static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001613 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001614 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001615{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001616 struct session_debug debug;
1617
Song Zhao76005282022-03-08 16:49:41 -08001618 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1619 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001620 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1621 if (debug.debug_freerun && !avsync->debug_freerun) {
1622 avsync->backup_mode = avsync->mode;
1623 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1624 avsync->debug_freerun = true;
1625 log_warn("[%d]video to freerun mode", avsync->session_id);
1626 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1627 avsync->mode = avsync->backup_mode;
1628 avsync->debug_freerun = false;
1629 log_warn("[%d]video back to mode %d",
1630 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001631 }
1632 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001633}
1634
1635static void * poll_thread(void * arg)
1636{
1637 int ret = 0;
1638 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1639 const int fd = avsync->fd;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001640 int poll_timeout = 10;
Song Zhaoea5a0412021-01-18 16:40:08 -08001641 struct pollfd pfd = {
1642 /* default blocking capture */
Song Zhao4bd18762022-09-30 16:39:52 -07001643 .events = POLLPRI,
Song Zhaoea5a0412021-01-18 16:40:08 -08001644 .fd = avsync->fd,
1645 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001646 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001647
Song Zhaoea5a0412021-01-18 16:40:08 -08001648 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001649
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001650 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001651 prctl (PR_SET_NAME, "avs_apoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001652 sflag = SRC_A;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001653 } else if (avsync->type == AV_SYNC_TYPE_VIDEO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001654 prctl (PR_SET_NAME, "avs_vpoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001655 sflag = SRC_V;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001656 poll_timeout = 100;
1657 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001658
Song Zhaoea5a0412021-01-18 16:40:08 -08001659 while (!avsync->quit_poll) {
1660 for (;;) {
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001661 ret = poll(&pfd, 1, poll_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001662 if (ret > 0)
1663 break;
1664 if (avsync->quit_poll)
1665 goto exit;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001666 if (errno == EINTR) {
1667 log_debug("[%d] poll interrupted", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001668 continue;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001669 }
Song Zhao4bd18762022-09-30 16:39:52 -07001670 if (errno == EAGAIN || errno == ENOMEM) {
1671 log_info("[%d] poll error %d", avsync->session_id, errno);
1672 continue;
1673 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001674 }
1675
1676 /* error handling */
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001677 if (pfd.revents & POLLERR) {
1678 usleep(poll_timeout * 1000);
1679 continue;
1680 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001681
Song Zhao4bd18762022-09-30 16:39:52 -07001682 if (pfd.revents & POLLNVAL) {
1683 log_warn("[%d] fd closed", avsync->session_id);
1684 goto exit;
1685 }
Song Zhaod62bb392021-04-23 12:25:49 -07001686 /* mode change. Non-exclusive wait so all the processes
1687 * shall be woken up
1688 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001689 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001690 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001691 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001692
Song Zhao9fef59c2022-08-17 12:43:10 -07001693 msync_session_get_stat(fd, true, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001694 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001695
1696 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001697 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001698 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001699 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001700 usleep(10000);
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001701 } else {
1702 log_debug("[%d] unexpected revents %x", avsync->session_id, pfd.revents);
1703 usleep(poll_timeout * 1000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001704 }
1705 }
1706exit:
1707 log_info("[%d]quit", avsync->session_id);
1708 return NULL;
1709}
1710
Song Zhao623e2f12021-09-03 15:54:04 -07001711#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1712/* return ppm between demod and PCR clock */
1713int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1714{
1715 int fd = -1, ppm = 0, nread;
1716 char buf[128];
1717 uint32_t reg_v, lock;
1718 float val;
1719
1720 fd = open(DEMOD_NODE, O_RDWR);
1721 if (fd < 0) {
1722 log_warn("node not found %s", DEMOD_NODE);
1723 /* do not retry */
1724 avsync->ppm_adjusted = true;
1725 return 0;
1726 }
1727 snprintf(buf, sizeof(buf), "%d", 5);
1728 write(fd, buf, 2);
1729
1730 lseek(fd, 0, SEEK_SET);
1731
hanghang.luo02efd312022-08-26 09:49:53 +08001732 nread = read(fd, buf, sizeof(buf)-1);
Song Zhao623e2f12021-09-03 15:54:04 -07001733 if (nread <= 0) {
1734 log_error("read error");
1735 goto err;
1736 }
1737 buf[nread] = 0;
1738 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1739 log_error("wrong format %s", buf);
1740 goto err;
1741 }
1742 if (lock != 0x1f) {
1743 log_info("demod not locked");
1744 goto err;
1745 }
1746 if (reg_v > ((2 << 20) - 1))
1747 reg_v -= (2 << 21);
1748 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1749 ppm = val;
1750 log_info("ppm from SFO %d", ppm);
1751 avsync->ppm_adjusted = true;
1752
1753err:
1754 if (fd >= 0)
1755 close(fd);
1756 return ppm;
1757}
1758
Song Zhaod62bb392021-04-23 12:25:49 -07001759int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001760{
1761 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001762 struct pcr_info pcr;
1763 enum pcr_monitor_status status;
1764 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001765 if (!avsync)
1766 return -1;
1767
1768 if (avsync->type != AV_SYNC_TYPE_PCR)
1769 return -2;
1770
Song Zhao623e2f12021-09-03 15:54:04 -07001771 /* initial estimation from Demod SFO HW */
1772 if (!avsync->ppm_adjusted) {
1773 ppm = dmod_get_sfo_dev(avsync);
1774 if (ppm != 0) {
1775 /* ppm > 0 means board clock is faster */
1776 msync_session_set_clock_dev(avsync->fd, -ppm);
1777 }
1778 }
wei.dubcc2ed22021-05-19 07:16:10 -04001779 pcr.monoclk = mono_clock / 1000;
1780 pcr.pts = (long long) pts * 1000 / 90;
1781 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1782
1783 status = pcr_monitor_get_status(avsync->pcr_monitor);
1784
1785 if (status >= DEVIATION_READY) {
1786 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1787 if (avsync->ppm != ppm) {
1788 avsync->ppm = ppm;
1789 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1790 if (msync_session_set_clock_dev(avsync->fd, ppm))
1791 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001792 else
1793 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001794 }
1795 }
1796
Song Zhaod62bb392021-04-23 12:25:49 -07001797 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001798}
1799
Song Zhaod62bb392021-04-23 12:25:49 -07001800int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001801{
1802 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1803
1804 if (!avsync)
1805 return -1;
1806
Song Zhaod62bb392021-04-23 12:25:49 -07001807 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001808}
1809
1810int av_sync_set_session_name(void *sync, const char *name)
1811{
1812 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1813
1814 if (!avsync)
1815 return -1;
1816
1817 return msync_session_set_name(avsync->fd, name);
1818}
yongchun.li107a6162021-05-05 02:38:57 -07001819
1820int av_sync_set_audio_switch(void *sync, bool start)
1821{
1822 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1823 bool v_active, a_active, v_timeout;
1824
1825 if (!avsync)
1826 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001827 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001828 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001829 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001830 log_error("[%d] can not get session state",
1831 avsync->session_id);
1832 return -1;
1833 }
1834 if (!v_active || !a_active) {
1835 log_error("[%d] no apply if not AV both active v %d a %d",
1836 avsync->session_id, v_active, a_active);
1837 return -1;
1838 }
1839 if (msync_session_set_audio_switch(avsync->fd, start)) {
1840 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1841 return -1;
1842 }
1843 avsync->in_audio_switch = start;
1844 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1845 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1846 return 0;
1847}
1848
1849int av_sync_get_audio_switch(void *sync, bool *start)
1850{
1851 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1852
1853 if (!avsync)
1854 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001855 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001856 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001857 log_error("[%d] can not audio seamless switch state",
1858 avsync->session_id);
1859 return -1;
1860 }
1861 if (start) *start = avsync->in_audio_switch;
1862 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001863}
Song Zhao8039f562021-05-18 18:11:25 -07001864
Song Zhao623e2f12021-09-03 15:54:04 -07001865enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001866{
1867 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1868
wei.dubcc2ed22021-05-19 07:16:10 -04001869 if (!avsync || !ppm)
1870 return CLK_RECOVERY_ERR;
1871 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001872 return CLK_RECOVERY_NOT_RUNNING;
1873
wei.dubcc2ed22021-05-19 07:16:10 -04001874 if (msync_session_get_clock_dev(avsync->fd, ppm))
1875 return CLK_RECOVERY_ERR;
1876
1877 if (*ppm == 0)
1878 return CLK_RECOVERY_ONGOING;
1879 else
1880 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001881}
Song Zhao95bd0922021-09-21 14:07:46 -07001882
1883static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1884{
1885 int ret;
1886
1887 if (!avsync->frame_q) {
1888 avsync->frame_q = create_q(MAX_FRAME_NUM);
1889 if (!avsync->frame_q) {
1890 log_error("[%d]create queue fail", avsync->session_id);
1891
1892 return -1;
1893 }
1894 }
1895
1896 ret = queue_item(avsync->frame_q, frame);
1897 if (ret)
hanghang.luo02efd312022-08-26 09:49:53 +08001898 log_error("queue fail:%d", ret);
Song Zhao95bd0922021-09-21 14:07:46 -07001899 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1900 return ret;
1901}
1902
1903int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1904{
1905 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1906
1907 if (!avsync)
1908 return -1;
1909 avsync->msys = msys;
1910 return 0;
1911}
1912
1913static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1914{
1915 struct vframe *frame = NULL, *enter_last_frame = NULL;
1916 uint64_t systime;
1917 int toggle_cnt = 0;
1918
1919 enter_last_frame = avsync->last_frame;
1920 systime = avsync->msys;
1921 log_debug("[%d]sys %llu", avsync->session_id, systime);
1922 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1923 if (systime >= frame->mts) {
1924 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1925 toggle_cnt++;
1926
1927 if (avsync->last_frame)
1928 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1929
1930 dqueue_item(avsync->frame_q, (void **)&frame);
1931 if (avsync->last_frame) {
1932 /* free frame that are not for display */
1933 if (toggle_cnt > 1) {
1934 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1935 avsync->last_frame->mts, frame->mts, systime);
1936 avsync->last_frame->free(avsync->last_frame);
1937 }
1938 } else {
1939 avsync->first_frame_toggled = true;
1940 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1941 }
1942 avsync->last_frame = frame;
1943 } else
1944 break;
1945 }
1946
1947 if (avsync->last_frame) {
1948 if (enter_last_frame != avsync->last_frame)
hanghang.luo02efd312022-08-26 09:49:53 +08001949 log_debug("[%d]pop %lu", avsync->session_id, avsync->last_frame->pts);
1950 log_trace("[%d]pop=%llu, system=%llu, diff %llu(ms), QNum=%d", avsync->session_id,
Song Zhao95bd0922021-09-21 14:07:46 -07001951 avsync->last_frame->mts,
1952 systime, (systime - avsync->last_frame->mts) / 1000000,
1953 queue_size(avsync->frame_q));
1954 } else
1955 if (enter_last_frame != avsync->last_frame)
1956 log_debug("[%d]pop (nil)", avsync->session_id);
1957
1958 if (avsync->last_frame)
1959 avsync->last_frame->hold_period++;
1960 return avsync->last_frame;
1961}
Song Zhao6183ca92022-07-29 09:57:03 -07001962
1963int avs_sync_stop_audio(void *sync)
1964{
1965 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1966
1967 if (!avsync)
1968 return -1;
1969
1970 return msync_session_stop_audio(avsync->fd);
1971}
bo.xiao05ba1ac2022-12-13 14:38:13 +08001972
1973int avs_sync_set_eos(void *sync)
1974{
1975 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1976
1977 if (!avsync)
1978 return -1;
1979
1980 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
1981 if (avsync->state == AV_SYNC_STAT_INIT) {
1982 avsync->state = AV_SYNC_STAT_RUNNING;
1983 log_debug("[%d]eos trigger state change: init --> running", avsync->session_id);
1984 }
1985 }
1986
1987 return 0;
1988}