blob: 93fb27e4242cde5aa68dd465adde2b64b748cca6 [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;
Song Zhaoad8a0112024-03-26 22:37:23 +0000331 avsync->apts = AV_SYNC_INVALID_PTS;
bo.xiao5821fc72021-07-11 22:47:00 -0400332
Song Zhaof46932e2021-05-21 01:51:45 -0700333 if (msync_session_get_disc_thres(session_id,
334 &avsync->disc_thres_min, &avsync->disc_thres_max)) {
hanghang.luo02efd312022-08-26 09:49:53 +0800335 log_error("dev_name:%s; errno:%d; fail to get disc thres", dev_name, errno);
Song Zhaof46932e2021-05-21 01:51:45 -0700336 avsync->disc_thres_min = AV_DISC_THRES_MIN;
337 avsync->disc_thres_max = AV_DISC_THRES_MAX;
338 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800339
340 pthread_mutex_init(&avsync->lock, NULL);
Song Zhao9c09f772022-01-07 14:26:50 -0800341 log_info("[%d] start_thres %d disc_thres %u/%u", session_id,
Song Zhao95bd0922021-09-21 14:07:46 -0700342 start_thres, avsync->disc_thres_min, avsync->disc_thres_max);
Song Zhaoea5a0412021-01-18 16:40:08 -0800343
344 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
Song Zhao2f6744b2021-11-03 21:23:50 -0700345 while (retry) {
346 /* wait for sysfs to update */
347 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
348 if (avsync->fd > 0)
349 break;
350
351 retry--;
352 if (!retry) {
353 log_error("open %s errno %d", dev_name, errno);
354 goto err2;
355 }
356 usleep(20000);
Song Zhaoea5a0412021-01-18 16:40:08 -0800357 }
358
wei.dubcc2ed22021-05-19 07:16:10 -0400359 if (avsync->type == AV_SYNC_TYPE_PCR) {
360 if (pcr_monitor_init(&avsync->pcr_monitor)) {
361 log_error("pcr monitor init");
Song Zhao9cd27a52021-07-26 15:27:38 +0000362 goto err3;
wei.dubcc2ed22021-05-19 07:16:10 -0400363 }
364 }
365
Song Zhaoea5a0412021-01-18 16:40:08 -0800366 if (!attach) {
367 msync_session_set_mode(avsync->fd, mode);
368 avsync->mode = mode;
Song Zhaob8833c12024-02-02 21:54:36 +0000369 if ((avsync->mode == AV_SYNC_MODE_VMASTER ||
370 avsync->mode == AV_SYNC_MODE_IPTV) &&
371 avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao7e24b182022-04-01 08:46:40 -0700372 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -0800373 } else {
374 avsync->attached = true;
375 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
376 log_error("get mode");
Song Zhao9cd27a52021-07-26 15:27:38 +0000377 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800378 }
379 avsync->backup_mode = avsync->mode;
bo.xiao5821fc72021-07-11 22:47:00 -0400380 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800381 log_error("get policy");
Song Zhao9cd27a52021-07-26 15:27:38 +0000382 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800383 }
Song Zhao9fef59c2022-08-17 12:43:10 -0700384 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700385 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -0700386 log_error("get state");
Song Zhao9cd27a52021-07-26 15:27:38 +0000387 goto err4;
yongchun.li107a6162021-05-05 02:38:57 -0700388 }
389 if (avsync->in_audio_switch) {
390 log_info("audio_switch_state reseted the audio");
391 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
392 }
393
Song Zhaoea5a0412021-01-18 16:40:08 -0800394 log_info("[%d]retrieve sync mode %d policy %d",
395 session_id, avsync->mode, avsync->start_policy);
396 }
397
Song Zhaoc03ba122020-12-23 21:54:02 -0800398 return avsync;
Song Zhao9cd27a52021-07-26 15:27:38 +0000399err4:
wei.dubcc2ed22021-05-19 07:16:10 -0400400 if (avsync->pcr_monitor)
401 pcr_monitor_destroy(avsync->pcr_monitor);
Song Zhao9cd27a52021-07-26 15:27:38 +0000402err3:
Song Zhaofd007632022-09-30 16:21:30 -0700403 if (avsync->fd)
404 close(avsync->fd);
Song Zhaoea5a0412021-01-18 16:40:08 -0800405err2:
Song Zhaofd007632022-09-30 16:21:30 -0700406 avsync->quit_poll = true;
407 if (avsync->poll_thread) {
408 pthread_join(avsync->poll_thread, NULL);
409 avsync->poll_thread = 0;
410 }
411 if (avsync->frame_q)
412 destroy_q(avsync->frame_q);
413 if (avsync->pattern_detector)
414 destroy_pattern_detector(avsync->pattern_detector);
Song Zhaoea5a0412021-01-18 16:40:08 -0800415err:
416 free(avsync);
417 return NULL;
418}
419
420void* av_sync_create(int session_id,
421 enum sync_mode mode,
422 enum sync_type type,
423 int start_thres)
424{
425 return create_internal(session_id, mode,
426 type, start_thres, false);
427}
428
429void* av_sync_attach(int session_id, enum sync_type type)
430{
Song Zhao95bd0922021-09-21 14:07:46 -0700431 if (type == AV_SYNC_TYPE_VIDEO)
432 return NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800433 return create_internal(session_id, AV_SYNC_MODE_MAX,
434 type, 0, true);
435}
436
437int av_sync_video_config(void *sync, struct video_config* config)
438{
439 struct av_sync_session *avsync = (struct av_sync_session *)sync;
440
441 if (!avsync || !config)
442 return -1;
443
444 if (config->delay != 1 && config->delay != 2) {
445 log_error("invalid delay: %d\n", config->delay);
446 return -1;
447 }
448
449 avsync->delay = config->delay;
Song Zhao6dce2672022-01-13 11:32:44 -0800450 avsync->extra_delay = config->extra_delay * 90;
Song Zhaoea5a0412021-01-18 16:40:08 -0800451
Song Zhao6dce2672022-01-13 11:32:44 -0800452 log_info("[%d] vsync delay: %d extra_delay: %d ms",
453 avsync->session_id, config->delay, config->extra_delay);
Song Zhaoea5a0412021-01-18 16:40:08 -0800454 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800455}
456
457static int internal_stop(struct av_sync_session *avsync)
458{
459 int ret = 0;
460 struct vframe *frame;
461
462 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800463 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
464 frame->free(frame);
465 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800466 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800467 pthread_mutex_unlock(&avsync->lock);
468 return ret;
469}
470
471/* destroy and detach from kernel session */
472void av_sync_destroy(void *sync)
473{
474 struct av_sync_session *avsync = (struct av_sync_session *)sync;
475
476 if (!avsync)
477 return;
478
Song Zhao95bd0922021-09-21 14:07:46 -0700479 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
480 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
481 log_info("[%d]done", avsync->session_id);
482 internal_stop(avsync);
483 destroy_q(avsync->frame_q);
484 free(avsync);
485 return;
486 }
Song Zhaob5458b32021-11-12 15:58:47 -0800487 log_info("[%d]begin type %d", avsync->session_id, avsync->type);
Song Zhao6be9ac22022-09-30 16:44:50 -0700488 if (avsync->type == AV_SYNC_TYPE_VIDEO)
489 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800490
Song Zhao6be9ac22022-09-30 16:44:50 -0700491 avsync->quit_poll = true;
492 if (avsync->poll_thread) {
493 pthread_join(avsync->poll_thread, NULL);
494 avsync->poll_thread = 0;
Song Zhaoaf368d52021-02-17 17:53:45 -0800495 }
Song Zhao6be9ac22022-09-30 16:44:50 -0700496 if (avsync->type == AV_SYNC_TYPE_AUDIO)
497 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoc03ba122020-12-23 21:54:02 -0800498
Song Zhaoea5a0412021-01-18 16:40:08 -0800499 if (avsync->session_started) {
500 if (avsync->type == AV_SYNC_TYPE_VIDEO)
501 msync_session_set_video_stop(avsync->fd);
502 else
503 msync_session_set_audio_stop(avsync->fd);
504 }
wei.dubcc2ed22021-05-19 07:16:10 -0400505
506 if(avsync->pcr_monitor)
507 pcr_monitor_destroy(avsync->pcr_monitor);
508
Song Zhaoea5a0412021-01-18 16:40:08 -0800509 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800510 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800511 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
512 destroy_q(avsync->frame_q);
513 destroy_pattern_detector(avsync->pattern_detector);
514 }
Song Zhaob5458b32021-11-12 15:58:47 -0800515 log_info("[%d]done type %d", avsync->session_id, avsync->type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800516 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800517}
518
bo.xiao5821fc72021-07-11 22:47:00 -0400519int avs_sync_set_start_policy(void *sync, struct start_policy* st_policy)
Song Zhaoea5a0412021-01-18 16:40:08 -0800520{
521 struct av_sync_session *avsync = (struct av_sync_session *)sync;
522
523 if (!avsync || !avsync->fd)
524 return -1;
525
Song Zhao47961d72022-08-29 14:04:44 -0700526 log_info("[%d]policy %u --> %u, timeout %d --> %d", avsync->session_id,
527 avsync->start_policy, st_policy->policy, avsync->timeout, st_policy->timeout);
Song Zhaof4e3c862022-09-01 14:00:11 -0700528 if (avsync->mode == AV_SYNC_MODE_IPTV &&
Song Zhao76005282022-03-08 16:49:41 -0800529 st_policy->policy != AV_SYNC_START_ASAP) {
530 log_error("policy %d not supported in live mode", st_policy->policy);
531 return -1;
532 }
533
Song Zhaof4e3c862022-09-01 14:00:11 -0700534 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
535 msync_session_set_start_thres(avsync->fd, st_policy->timeout);
536
bo.xiao5821fc72021-07-11 22:47:00 -0400537 avsync->start_policy = st_policy->policy;
538 avsync->timeout = st_policy->timeout;
Song Zhao76005282022-03-08 16:49:41 -0800539
Song Zhaoea5a0412021-01-18 16:40:08 -0800540 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400541 if (st_policy->policy != AV_SYNC_START_NONE &&
542 st_policy->policy != AV_SYNC_START_V_PEEK)
543 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800544
545 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800546}
547
548int av_sync_pause(void *sync, bool pause)
549{
550 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700551 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800552 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800553
Song Zhaob5458b32021-11-12 15:58:47 -0800554 if (!avsync) {
555 log_error("invalid handle");
Song Zhaoc03ba122020-12-23 21:54:02 -0800556 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800557 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800558
fei.deng55389b62022-08-18 23:46:50 +0800559 if (avsync->type == AV_SYNC_TYPE_VIDEO && avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
560 log_warn("ignore pause in video mono mode");
561 return -1;
562 }
563
Song Zhaob5458b32021-11-12 15:58:47 -0800564 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
565 log_warn("ignore pause in pcr master mode");
Song Zhaoea5a0412021-01-18 16:40:08 -0800566 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800567 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800568
Song Zhao9fef59c2022-08-17 12:43:10 -0700569 rc = msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -0700570 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700571 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700572
yongchun.li5f52fb02021-06-04 18:13:05 -0700573 /* ignore only when video try to pause when audio is acive, on which
574 the control of the STC will be relays.
575 When resume,it can do always as it is possible that video just
576 paused earlier without audio yet,then audio added later before resume.
577 We shall not igore that otherwise it could cause video freeze. */
578 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
579 avsync->type == AV_SYNC_TYPE_VIDEO &&
580 a_active &&
581 !avsync->in_audio_switch) {
582 if (!pause) {
583 log_info("[%d] clear video pause when audio active",
584 avsync->session_id);
585 avsync->paused = pause;
586 } else {
587 log_info("[%d] ignore the pause from video when audio active",
588 avsync->session_id);
589 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800590 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700591 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800592
yongchun.li107a6162021-05-05 02:38:57 -0700593 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
594 log_info("[%d] ignore the pause from audio", avsync->session_id);
595 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
596 return 0;
597 }
598
Song Zhaoea5a0412021-01-18 16:40:08 -0800599 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800600 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800601 log_info("[%d]paused:%d type:%d rc %d",
602 avsync->session_id, pause, avsync->type, rc);
yongchun.li428390d2022-02-17 17:15:40 -0800603 if (!avsync->paused && avsync->first_frame_toggled) {
604 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
605 log_info("[%d] resume update new frame time", avsync->session_id);
606 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800607 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800608}
609
610int av_sync_push_frame(void *sync , struct vframe *frame)
611{
612 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700613 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800614 struct av_sync_session *avsync = (struct av_sync_session *)sync;
615
616 if (!avsync)
617 return -1;
618
Song Zhao95bd0922021-09-21 14:07:46 -0700619 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
fei.deng55389b62022-08-18 23:46:50 +0800620 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
Song Zhao95bd0922021-09-21 14:07:46 -0700621 return video_mono_push_frame(avsync, frame);
fei.deng55389b62022-08-18 23:46:50 +0800622 }
Song Zhao95bd0922021-09-21 14:07:46 -0700623
Song Zhaofd007632022-09-30 16:21:30 -0700624 if (avsync->state == AV_SYNC_STAT_INIT && !queue_size(avsync->frame_q)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800625 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400626 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800627 log_error("[%d]get policy", avsync->session_id);
628 return -1;
629 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800630 }
631
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700632 if (avsync->last_q_pts != -1) {
Song Zhao7e24b182022-04-01 08:46:40 -0700633 if (frame->pts != -1 && avsync->mode == AV_SYNC_MODE_VMASTER) {
634 /* Sometimes app will fake PTS for trickplay, video PTS gap
635 * is really big depending on the speed. Have to adjust the
636 * threshold dynamically.
637 */
638 int gap = (int)(frame->pts - avsync->last_q_pts);
639 if (gap > avsync->disc_thres_min) {
640 avsync->disc_thres_min = gap * 6;
641 avsync->disc_thres_max = gap * 20;
642 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
643 msync_session_set_disc_thres(avsync->session_id,
644 avsync->disc_thres_min, avsync->disc_thres_max);
645 log_info("[%d] update disc_thres to %d/%d",avsync->session_id,
646 avsync->disc_thres_min, avsync->disc_thres_max);
647 }
648 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700649 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
650 /* TODO: wrong, should remove from back of queue */
le.hanebaea1e2023-07-10 07:26:09 +0000651 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800652 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700653 if (prev) {
654 prev->free(prev);
655 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
656 }
le.hanebaea1e2023-07-10 07:26:09 +0000657 pthread_mutex_unlock(&avsync->lock);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700658 } else if (avsync->fps_cnt < 100) {
659 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700660
661 if (interval > 0 && interval <= 4500) {
662 if (avsync->fps_interval_acc == -1) {
663 avsync->fps_interval_acc = interval;
664 avsync->fps_cnt = 1;
665 } else {
666 avsync->fps_interval_acc += interval;
667 avsync->fps_cnt++;
668 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
669 if (avsync->fps_cnt == 100)
670 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
671 }
672 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800673 }
674 }
675
Song Zhao065800e2021-05-26 15:56:06 -0700676 if (frame->duration == -1)
677 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800678 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700679 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800680 ret = queue_item(avsync->frame_q, frame);
681 if (avsync->state == AV_SYNC_STAT_INIT &&
682 queue_size(avsync->frame_q) >= avsync->start_thres) {
683 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaofd007632022-09-30 16:21:30 -0700684 log_debug("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800685 }
686
687 if (ret)
Song Zhaoe1b65602022-01-06 08:03:46 -0800688 log_error("queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400689 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800690 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800691}
692
693struct vframe *av_sync_pop_frame(void *sync)
694{
Song Zhaoea5a0412021-01-18 16:40:08 -0800695 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800696 struct av_sync_session *avsync = (struct av_sync_session *)sync;
697 int toggle_cnt = 0;
hanghang.luo02efd312022-08-26 09:49:53 +0800698 uint32_t systime = 0;
Song Zhao468fd652021-01-15 22:13:04 -0800699 bool pause_pts_reached = false;
hanghang.luo02efd312022-08-26 09:49:53 +0800700 uint32_t interval = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800701
Song Zhao95bd0922021-09-21 14:07:46 -0700702 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
703 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
704 return video_mono_pop_frame(avsync);
705
Song Zhaoc03ba122020-12-23 21:54:02 -0800706 pthread_mutex_lock(&avsync->lock);
707 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhao2f6744b2021-11-03 21:23:50 -0700708 log_debug("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800709 goto exit;
710 }
711
Song Zhaoea5a0412021-01-18 16:40:08 -0800712 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700713 uint32_t pts;
714
Song Zhaoc03ba122020-12-23 21:54:02 -0800715 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800716 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800717 goto exit;
718 }
Song Zhao35a82df2021-04-15 10:58:49 -0700719 msync_session_get_wall(avsync->fd, &systime, &interval);
720 pts = frame->pts - avsync->delay * interval;
721 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800722 avsync->session_started = true;
Song Zhao5296acf2024-02-02 21:45:04 +0000723 log_info("[%d]video start %u frame %u sys %u",
724 avsync->session_id, pts, frame->pts, systime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800725 }
726
Song Zhaoea5a0412021-01-18 16:40:08 -0800727 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700728 !avsync->first_frame_toggled &&
729 !msync_clock_started(avsync->fd)) {
730 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800731 log_trace("[%d]clock not started", avsync->session_id);
732 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800733 }
734
Song Zhaoea5a0412021-01-18 16:40:08 -0800735 enter_last_frame = avsync->last_frame;
736 msync_session_get_wall(avsync->fd, &systime, &interval);
737
738 /* handle refresh rate change */
739 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
740 avsync->vsync_interval != interval) {
741 log_info("[%d]vsync interval update %d --> %u",
742 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700743 if (avsync->fps_interval == -1)
744 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800745 avsync->vsync_interval = interval;
746 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800747 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700748 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800749 reset_pattern(avsync->pattern_detector);
750 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800751 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
752 struct vframe *next_frame = NULL;
753
754 peek_item(avsync->frame_q, (void **)&next_frame, 1);
755 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700756 log_debug("[%d]cur_f %u next_f %u size %d",
757 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800758 if (frame_expire(avsync, systime, interval,
759 frame, next_frame, toggle_cnt)) {
760 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800761 toggle_cnt++;
762
Song Zhao35a82df2021-04-15 10:58:49 -0700763 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800764 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700765 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700766 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700767 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
768 if (next_frame)
769 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
770 }
Song Zhao35a82df2021-04-15 10:58:49 -0700771
Song Zhaoc03ba122020-12-23 21:54:02 -0800772 if (avsync->last_frame)
773 avsync->last_holding_peroid = avsync->last_frame->hold_period;
774
775 dqueue_item(avsync->frame_q, (void **)&frame);
776 if (avsync->last_frame) {
Song Zhao5296acf2024-02-02 21:45:04 +0000777 int qsize = queue_size(avsync->frame_q);
778
Song Zhaoc03ba122020-12-23 21:54:02 -0800779 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800780 if (toggle_cnt > 1) {
Song Zhaofd007632022-09-30 16:21:30 -0700781 log_info("[%d]free %u cur %u system/d %u/%u queue size %d", avsync->session_id,
782 avsync->last_frame->pts, frame->pts,
783 systime, systime - avsync->last_poptime,
Song Zhao5296acf2024-02-02 21:45:04 +0000784 qsize);
Song Zhaoc03ba122020-12-23 21:54:02 -0800785 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800786 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800787 } else {
788 avsync->first_frame_toggled = true;
Song Zhaofd007632022-09-30 16:21:30 -0700789 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 -0800790 }
791 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800792 avsync->last_pts = frame->pts;
yongchun.li428390d2022-02-17 17:15:40 -0800793 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
Song Zhaoc03ba122020-12-23 21:54:02 -0800794 } else
795 break;
796 }
797
798 /* pause pts */
799 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800800 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800801 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800802 else
Song Zhao468fd652021-01-15 22:13:04 -0800803 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
804 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
805 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
806 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
807 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800808
Song Zhao468fd652021-01-15 22:13:04 -0800809 if (pause_pts_reached) {
Song Zhao468fd652021-01-15 22:13:04 -0800810 /* stay in paused until av_sync_pause(false) */
Song Zhaoa1742282022-09-30 16:17:26 -0700811 uint32_t local_pts = avsync->pause_pts;
Song Zhao468fd652021-01-15 22:13:04 -0800812 avsync->paused = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800813 log_info ("[%d]reach pause pts: %u",
Song Zhaob5458b32021-11-12 15:58:47 -0800814 avsync->session_id, avsync->pause_pts);
Song Zhaoad7c8232021-12-14 11:46:48 -0800815 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoa1742282022-09-30 16:17:26 -0700816 if (avsync->pause_pts_cb)
817 avsync->pause_pts_cb(local_pts,
818 avsync->pause_cb_priv);
819 log_info ("[%d] reach pause pts: %u handle done",
820 avsync->session_id, local_pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800821 }
822
823exit:
824 pthread_mutex_unlock(&avsync->lock);
yongchun.li428390d2022-02-17 17:15:40 -0800825
826 /* underflow check */
827 if (avsync->session_started && avsync->first_frame_toggled &&
828 (avsync->paused == false) && (avsync->state >= AV_SYNC_STAT_RUNNING) &&
829 avsync->underflow_cb && peek_item(avsync->frame_q, (void **)&frame, 0))
830 {/* empty queue in normal play */
831 struct timespec now;
832 int diff_ms;
833 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
834 diff_ms = time_diff(&now, &avsync->frame_last_update_time)/1000;
835 if(diff_ms >= (avsync->underflow_cfg.time_thresh
836 + avsync->vsync_interval*avsync->last_holding_peroid/90)) {
837 log_info ("[%d]underflow detected: %u", avsync->session_id, avsync->last_pts);
838 avsync->underflow_cb (avsync->last_pts,
839 avsync->underflow_cb_priv);
840 /* update time to control the underflow check call backs */
841 avsync->frame_last_update_time = now;
842 }
843 }
844
Song Zhaoc03ba122020-12-23 21:54:02 -0800845 if (avsync->last_frame) {
Song Zhaof3350d32023-08-18 16:27:31 -0700846 if (enter_last_frame != avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800847 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhaof3350d32023-08-18 16:27:31 -0700848 /* don't update vpts for out_lier */
849 if (avsync->last_frame->duration != -1)
850 msync_session_update_vpts(avsync->fd, systime,
851 avsync->last_frame->pts + avsync->extra_delay, interval * avsync->delay);
852 }
bo.xiao1f94b352021-08-02 03:53:47 -0400853 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 -0800854 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800855 if (enter_last_frame != avsync->last_frame)
856 log_debug("[%d]pop (nil)", avsync->session_id);
857
Song Zhao35a82df2021-04-15 10:58:49 -0700858 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800859 if (avsync->last_frame)
860 avsync->last_frame->hold_period++;
861 return avsync->last_frame;
862}
863
Song Zhaoc03ba122020-12-23 21:54:02 -0800864static inline uint32_t abs_diff(uint32_t a, uint32_t b)
865{
Song Zhaoea5a0412021-01-18 16:40:08 -0800866 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800867}
868
yongchun.li0ee6e372021-08-20 04:26:04 -0700869static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800870{
hanghang.luo02efd312022-08-26 09:49:53 +0800871 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 -0800872}
873
Song Zhaoc03ba122020-12-23 21:54:02 -0800874static bool frame_expire(struct av_sync_session* avsync,
875 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800876 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800877 struct vframe * frame,
878 struct vframe * next_frame,
879 int toggle_cnt)
880{
Song Zhao6dce2672022-01-13 11:32:44 -0800881 uint32_t fpts = frame->pts + avsync->extra_delay;
882 uint32_t nfpts = -1;
Song Zhaoad8a0112024-03-26 22:37:23 +0000883 uint32_t last_pts = avsync->last_pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800884 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800885 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800886
Song Zhao9c0197e2024-03-12 18:05:20 +0000887 if (!VALID_TS(systime))
888 return false;
889
Song Zhaoc03ba122020-12-23 21:54:02 -0800890 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
891 return false;
892
893 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
894 return true;
895
Song Zhaoad7c8232021-12-14 11:46:48 -0800896 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS &&
897 avsync->pause_pts == frame->pts)
898 return true;
899
Song Zhao08fa16b2021-12-08 14:30:17 -0800900 if (systime == AV_SYNC_INVALID_PTS &&
901 avsync->mode == AV_SYNC_MODE_AMASTER)
902 return false;
903
Song Zhao6dce2672022-01-13 11:32:44 -0800904 if (next_frame)
905 nfpts = next_frame->pts + avsync->extra_delay;
906
Song Zhao7e24b182022-04-01 08:46:40 -0700907 if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
fei.deng63e43e12021-09-23 19:44:01 +0800908 /* We need to ensure that the video outputs smoothly,
909 so output video frame by frame hold_period */
910 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
911 avsync->last_frame &&
912 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
913 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
914 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700915 return true;
916 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700917 }
918
Song Zhaoc03ba122020-12-23 21:54:02 -0800919 if (!fpts) {
920 if (avsync->last_frame) {
921 /* try to accumulate duration as PTS */
922 fpts = avsync->vpts + avsync->last_frame->duration;
923 } else {
924 fpts = avsync->vpts;
925 }
926 }
927 systime += pts_correction;
928
929 /* phase adjustment */
930 if (avsync->phase_set)
931 systime += avsync->phase;
932
yongchun.lia50b1e92021-08-07 01:11:54 +0000933 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800934 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000935 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700936 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800937 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800938 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800939 return false;
940
Song Zhaoa2985cb2021-06-24 12:01:47 -0700941 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
942 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700943 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800944
yongchun.li0ee6e372021-08-20 04:26:04 -0700945 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700946 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800947 avsync->last_pts = fpts;
948 if (time_diff(&now, &avsync->sync_lost_print_time) >=
949 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700950 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800951 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800952 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700953 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800954 } else
955 avsync->sync_lost_cnt++;
956 }
Song Zhaod62bb392021-04-23 12:25:49 -0700957
958 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
959 LIVE_MODE(avsync->mode) &&
Song Zhaoad8a0112024-03-26 22:37:23 +0000960 VALID_TS(last_pts) &&
961 abs_diff(last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700962 /* outlier by stream error */
963 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700964 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700965 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
966 log_info("render outlier %u", fpts);
967 return true;
968 }
969 }
970
971 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800972 avsync->state = AV_SYNC_STAT_SYNC_LOST;
973 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800974 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700975 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800976 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700977
Song Zhao7e24b182022-04-01 08:46:40 -0700978 if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700979 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700980 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700981 msync_session_set_video_dis(avsync->fd, fpts);
982 avsync->last_disc_pts = fpts;
Song Zhao59d732d2024-01-23 22:09:15 -0800983 if (avsync->mode == AV_SYNC_MODE_VMASTER) {
984 systime = fpts;
985 avsync->last_r_syst = -1;
986 }
Song Zhaoa2985cb2021-06-24 12:01:47 -0700987 }
988
989 if ((int)(systime - fpts) > 0) {
990 if ((int)(systime - fpts) < avsync->disc_thres_max) {
991 /* catch up PCR */
Song Zhao59d732d2024-01-23 22:09:15 -0800992 avsync->last_r_syst = -1;
Song Zhaof46932e2021-05-21 01:51:45 -0700993 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700994 } else {
995 /* render according to FPS */
996 if (!VALID_TS(avsync->last_r_syst) ||
997 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
998 avsync->last_r_syst = systime;
999 return true;
1000 }
1001 return false;
1002 }
1003 } else if (LIVE_MODE(avsync->mode)) {
1004 /* hold if the gap is small */
1005 if ((int)(fpts - systime) < avsync->disc_thres_max) {
1006 return false;
1007 } else {
1008 /* render according to FPS */
1009 if (!VALID_TS(avsync->last_r_syst) ||
1010 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
1011 avsync->last_r_syst = systime;
1012 return true;
1013 }
1014 return false;
1015 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001016 }
1017 }
1018
Song Zhao52f55192021-05-06 10:52:21 -07001019 /* In some cases, keeping pattern will enlarge the gap */
1020 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
1021 avsync->first_frame_toggled) {
1022 reset_pattern(avsync->pattern_detector);
Song Zhaofd007632022-09-30 16:21:30 -07001023 log_info("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -07001024 systime, fpts);
1025 }
1026
Song Zhaoc03ba122020-12-23 21:54:02 -08001027 expire = (int)(systime - fpts) >= 0;
1028
1029 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -08001030 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001031 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -08001032 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001033 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001034 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001035 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -08001036 }
Song Zhao6dce2672022-01-13 11:32:44 -08001037 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -08001038 && avsync->first_frame_toggled) {
1039 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -08001040 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001041 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -08001042 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001043 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001044 }
1045 }
1046
Song Zhaoa58c3e92021-03-09 18:52:55 -08001047 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -08001048 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -08001049 (avsync->last_frame?avsync->last_frame->hold_period:0),
1050 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -08001051 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -08001052
1053 if (expire) {
1054 avsync->vpts = fpts;
1055 /* phase adjustment */
1056 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +00001057 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -08001058 if ((int)(systime - fpts) >= 0 &&
1059 (int)(fpts + interval - systime) > 0) {
1060 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -08001061 avsync->phase_set = true;
Song Zhaofd007632022-09-30 16:21:30 -07001062 log_debug("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -08001063 }
Song Zhao1561e542022-01-12 10:37:55 -08001064 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -08001065 if ((int)(systime - fpts) >= 0 &&
1066 (int)(fpts + interval - systime) > 0) {
1067 int vsync_pts_delta = (int)(systime - fpts);
1068
1069 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1070 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001071 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001072 log_info("[%d] too aligned adjust phase to %d",
1073 avsync->session_id, (int)avsync->phase);
1074 }
1075 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001076 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001077 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaofd007632022-09-30 16:21:30 -07001078 log_info("[%d]sync setup on frame %u", avsync->session_id, fpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001079 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001080 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001081 }
1082 return expire;
1083}
1084
Song Zhao35a82df2021-04-15 10:58:49 -07001085static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001086{
Song Zhaoea5a0412021-01-18 16:40:08 -08001087 log_trace("[%d]cur_period: %d last_period: %d",
1088 avsync->session_id, cur_period, last_period);
Song Zhaobb3b4f32023-10-17 16:08:12 -07001089 return detect_pattern(avsync->pattern_detector, cur_period, last_period);
Song Zhaoc03ba122020-12-23 21:54:02 -08001090}
1091
1092int av_sync_set_speed(void *sync, float speed)
1093{
1094 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1095
1096 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001097 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001098 return -1;
1099 }
1100
Song Zhao76005282022-03-08 16:49:41 -08001101 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001102 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001103 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001104 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001105
Song Zhaoea5a0412021-01-18 16:40:08 -08001106 avsync->speed = speed;
1107
1108 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhaoa73fcf32023-01-13 08:12:26 -08001109 if (speed == 1.0)
1110 msync_session_set_wall_adj_thres(avsync->fd, DEFAULT_WALL_ADJ_THRES);
1111 else
1112 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
1113 log_info("[%d]adjust wall adj threshold to %d", avsync->session_id,
1114 (speed == 1.0) ? DEFAULT_WALL_ADJ_THRES : avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -08001115 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001116
Song Zhaoea5a0412021-01-18 16:40:08 -08001117 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1118 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001119}
1120
1121int av_sync_change_mode(void *sync, enum sync_mode mode)
1122{
1123 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1124
1125 if (!avsync)
1126 return -1;
1127
Song Zhaoea5a0412021-01-18 16:40:08 -08001128 if (msync_session_set_mode(avsync->fd, mode)) {
1129 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001130 return -1;
1131 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001132 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001133 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001134 return 0;
1135}
1136
Song Zhaoebc92012024-03-12 18:36:44 +00001137int av_sync_change_mode_by_id(int id, enum sync_mode mode)
1138{
1139 int fd;
1140 char dev_name[20];
1141
1142 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, id);
1143 fd = open(dev_name, O_RDONLY | O_CLOEXEC);
1144 if (fd < 0) {
1145 log_error("open %s errno %d", dev_name, errno);
1146 return -1;
1147 }
1148
1149 if (msync_session_set_mode(fd, mode)) {
1150 log_error("[%d]fail to set mode %d", id, mode);
1151 close(fd);
1152 return -1;
1153 }
1154
1155 close(fd);
1156 log_info("session[%d] set mode %d", id, mode);
1157 return 0;
1158}
1159
Song Zhao01031bb2021-05-13 21:23:20 -07001160int av_sync_get_mode(void *sync, enum sync_mode *mode)
1161{
1162 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1163
1164 if (!avsync || !mode)
1165 return -1;
1166
1167 *mode = avsync->mode;
1168 return 0;
1169}
1170
Song Zhaoc03ba122020-12-23 21:54:02 -08001171int av_sync_set_pause_pts(void *sync, pts90K pts)
1172{
1173 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1174
1175 if (!avsync)
1176 return -1;
1177
1178 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001179 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001180 return 0;
1181}
1182
1183int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1184{
1185 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1186
1187 if (!avsync)
1188 return -1;
1189
1190 avsync->pause_pts_cb = cb;
1191 avsync->pause_cb_priv = priv;
1192 return 0;
1193}
Song Zhaoea5a0412021-01-18 16:40:08 -08001194
yongchun.li428390d2022-02-17 17:15:40 -08001195int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1196{
1197 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1198
1199 if (!avsync)
1200 return -1;
1201
1202 avsync->underflow_cb = cb;
1203 avsync->underflow_cb_priv = priv;
1204
1205 if (cfg)
1206 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1207 else
1208 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1209
1210 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1211 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1212 avsync->underflow_cfg.time_thresh);
1213 return 0;
1214}
Song Zhaoea5a0412021-01-18 16:40:08 -08001215static void trigger_audio_start_cb(struct av_sync_session *avsync,
1216 avs_ascb_reason reason)
1217{
1218 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001219 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001220 pthread_mutex_lock(&avsync->lock);
1221 if (avsync->audio_start) {
1222 avsync->audio_start(avsync->audio_start_priv, reason);
1223 avsync->session_started = true;
1224 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001225 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001226 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1227 }
1228 pthread_mutex_unlock(&avsync->lock);
1229 }
1230}
1231
Song Zhao5296acf2024-02-02 21:45:04 +00001232static int update_pcr_master_disc_thres(struct av_sync_session * avsync, pts90K pts)
1233{
1234 pts90K pcr = -1;
1235
1236 if (!msync_session_get_pcr(avsync->fd, &pcr, NULL) && pcr != -1) {
1237 pts90K delta = abs_diff(pcr, pts);
1238
1239 if (delta * 3 > avsync->disc_thres_min)
1240 avsync->disc_thres_min = 3 * delta;
1241
1242 log_info("%d update disc_thres_min to %u delta %u",
1243 avsync->session_id, avsync->disc_thres_min, delta);
1244 return 0;
1245 }
1246 return -1;
1247}
1248
Song Zhaoea5a0412021-01-18 16:40:08 -08001249avs_start_ret av_sync_audio_start(
1250 void *sync,
1251 pts90K pts,
1252 pts90K delay,
1253 audio_start_cb cb,
1254 void *priv)
1255{
1256 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1257 uint32_t start_mode;
yongchun.li06965172022-12-14 19:50:31 -08001258 uint32_t systime = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001259 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1260 bool create_poll_t = false;
1261
1262 if (!avsync)
1263 return ret;
1264
yongchun.li59e873d2021-07-07 11:42:38 -07001265 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1266 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001267
yongchun.li06965172022-12-14 19:50:31 -08001268 if (avsync->in_audio_switch) {
1269 msync_session_get_wall(avsync->fd, &systime, NULL);
1270 if (systime == AV_SYNC_INVALID_PTS) {
1271 log_info("%d Invalid systime could be paused pts %d ms switch_state %d again",
1272 avsync->session_id, (int) pts/90, avsync->audio_switch_state);
1273 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
1274 ret = AV_SYNC_ASTART_AGAIN;
1275 goto exit;
1276 }
1277 }
1278
yongchun.li59e873d2021-07-07 11:42:38 -07001279 if (avsync->in_audio_switch &&
1280 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1281 {
1282 start_mode = AVS_START_SYNC;
1283 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1284 } else {
1285 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1286 log_error("[%d]fail to set audio start", avsync->session_id);
1287 }
1288 if (avsync->in_audio_switch &&
1289 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1290 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
Song Zhao4bd18762022-09-30 16:39:52 -07001291 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB
1292 && start_mode == AVS_START_SYNC) {
yongchun.li59e873d2021-07-07 11:42:38 -07001293 log_info("%d audio_switch audio need drop first.ahead %d ms",
1294 avsync->session_id, (int)(systime - pts)/90);
1295 ret = AV_SYNC_ASTART_AGAIN;
1296 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1297 goto exit;
1298 }
1299 else {
1300 int diff = (int)(pts - systime);
1301 log_info("%d audio_switch_state to start mode %d diff %d ms",
1302 avsync->session_id, start_mode, diff/90);
yongchun.li59e873d2021-07-07 11:42:38 -07001303 if (diff < A_ADJ_THREDHOLD_LB) {
1304 log_info("%d orig mode %d already close enough direct start",
1305 avsync->session_id, start_mode);
1306 start_mode = AVS_START_SYNC;
Song Zhao4bd18762022-09-30 16:39:52 -07001307 } else if (start_mode != AVS_START_ASYNC) {
1308 log_info("%d drop too far mode %d need to try ASYNC",
1309 avsync->session_id, start_mode);
1310 msync_session_set_audio_stop(avsync->fd);
1311 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1312 log_error("[%d]fail to set audio start", avsync->session_id);
1313 log_info("%d New start mode %d",
1314 avsync->session_id, start_mode);
yongchun.li59e873d2021-07-07 11:42:38 -07001315 }
Song Zhao4bd18762022-09-30 16:39:52 -07001316 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
yongchun.li59e873d2021-07-07 11:42:38 -07001317 }
yongchun.li107a6162021-05-05 02:38:57 -07001318 }
1319
Song Zhaoea5a0412021-01-18 16:40:08 -08001320 if (start_mode == AVS_START_SYNC) {
1321 ret = AV_SYNC_ASTART_SYNC;
1322 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001323 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhao5296acf2024-02-02 21:45:04 +00001324
1325 /* for DTG stream, initial delta between apts and pcr is big */
1326 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
1327 update_pcr_master_disc_thres(avsync, pts);
1328
Song Zhaod62bb392021-04-23 12:25:49 -07001329 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001330 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001331 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhao5296acf2024-02-02 21:45:04 +00001332
1333 /* for DTG stream, initial delta between apts and pcr is big */
1334 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
1335 update_pcr_master_disc_thres(avsync, pts);
Song Zhaod62bb392021-04-23 12:25:49 -07001336 } else if (start_mode == AVS_START_AGAIN) {
1337 ret = AV_SYNC_ASTART_AGAIN;
1338 }
1339
Song Zhao5296acf2024-02-02 21:45:04 +00001340 avsync->last_pts = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001341 if (ret == AV_SYNC_ASTART_AGAIN)
1342 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001343
Song Zhao76005282022-03-08 16:49:41 -08001344 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1345 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001346 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001347
1348 if (start_mode == AVS_START_ASYNC) {
1349 if (!cb) {
1350 log_error("[%d]invalid cb", avsync->session_id);
1351 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001352 }
Song Zhao76005282022-03-08 16:49:41 -08001353 avsync->audio_start = cb;
1354 avsync->audio_start_priv = priv;
1355 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001356
Song Zhaod62bb392021-04-23 12:25:49 -07001357 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001358 int ret;
1359
1360 log_info("[%d]start poll thread", avsync->session_id);
1361 avsync->quit_poll = false;
1362 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1363 if (ret) {
1364 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1365 return AV_SYNC_ASTART_ERR;
1366 }
1367 }
Song Zhaod62bb392021-04-23 12:25:49 -07001368 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001369 msync_session_get_wall(avsync->fd, &systime, NULL);
1370 log_info("[%d]return %u w %u pts %u d %u",
1371 avsync->session_id, ret, systime, pts, delay);
1372 }
1373exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001374 log_info("[%d]return %u", avsync->session_id, ret);
1375 return ret;
1376}
1377
1378int av_sync_audio_render(
1379 void *sync,
1380 pts90K pts,
1381 struct audio_policy *policy)
1382{
1383 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001384 bool out_lier = false;
Song Zhaoad8a0112024-03-26 22:37:23 +00001385 bool send_disc = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001386 uint32_t systime;
1387 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1388 avs_audio_action action = AA_SYNC_AA_MAX;
1389
1390 if (!avsync || !policy)
1391 return -1;
1392
yongchun.li107a6162021-05-05 02:38:57 -07001393 msync_session_get_wall(avsync->fd, &systime, NULL);
Song Zhao5296acf2024-02-02 21:45:04 +00001394 avsync->last_pts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001395
1396 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1397 pts, systime, avsync->mode, (int)(pts-systime)/90);
1398
1399 if (avsync->in_audio_switch
1400 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
Song Zhao4bd18762022-09-30 16:39:52 -07001401 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_MB) {
yongchun.li107a6162021-05-05 02:38:57 -07001402 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1403 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1404 action = AV_SYNC_AA_RENDER;
1405 } else if ((int)(systime - pts) > 0) {
1406 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1407 (int)(systime - pts)/90, systime, pts);
1408 action = AV_SYNC_AA_DROP;
1409 } else {
1410 action = AV_SYNC_AA_INSERT;
1411 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1412 (int)(pts - systime)/90, systime, pts);
1413 }
1414 goto done;
1415 }
1416
Song Zhaoea5a0412021-01-18 16:40:08 -08001417 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1418 avsync->mode == AV_SYNC_MODE_AMASTER) {
1419 action = AV_SYNC_AA_RENDER;
1420 goto done;
1421 }
1422
Song Zhaod62bb392021-04-23 12:25:49 -07001423 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001424 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001425 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1426 action = AV_SYNC_AA_DROP;
1427 goto done;
1428 }
1429
Song Zhao7daf3a12021-05-10 22:22:25 -07001430 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
Song Zhaob8833c12024-02-02 21:54:36 +00001431 avsync->mode == AV_SYNC_MODE_AMASTER ||
1432 avsync->active_mode == AV_SYNC_MODE_AMASTER) {
Song Zhao7daf3a12021-05-10 22:22:25 -07001433 action = AV_SYNC_AA_RENDER;
1434 goto done;
1435 }
1436
Song Zhaoad8a0112024-03-26 22:37:23 +00001437 if (LIVE_MODE(avsync->mode) &&
1438 VALID_TS(avsync->apts) &&
1439 abs_diff(avsync->apts, pts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -07001440 /* outlier by stream error */
1441 avsync->outlier_cnt++;
1442 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
Song Zhaoad8a0112024-03-26 22:37:23 +00001443 /* treat as disc */
1444 send_disc = true;
1445 } else {
1446 log_info("[%d]ignore outlier %u vs %u sys %u", avsync->session_id, pts, avsync->apts, systime);
1447 pts = systime;
1448 action = AV_SYNC_AA_RENDER;
1449 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001450 goto done;
1451 }
Song Zhaod62bb392021-04-23 12:25:49 -07001452 }
1453
Song Zhaod62bb392021-04-23 12:25:49 -07001454 /* low bound from sync_lost to sync_setup */
1455 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
Song Zhaoad8a0112024-03-26 22:37:23 +00001456 avsync->outlier_cnt = 0;
Song Zhaod62bb392021-04-23 12:25:49 -07001457 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1458 action = AV_SYNC_AA_RENDER;
1459 goto done;
1460 }
1461
1462 /* high bound of sync_setup */
1463 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1464 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
Song Zhaoad8a0112024-03-26 22:37:23 +00001465 avsync->outlier_cnt = 0;
Song Zhaod62bb392021-04-23 12:25:49 -07001466 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001467 action = AV_SYNC_AA_RENDER;
1468 goto done;
1469 }
1470
1471 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001472 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001473 action = AV_SYNC_AA_DROP;
1474 goto done;
1475 }
1476
1477 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001478 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001479 action = AV_SYNC_AA_INSERT;
1480 goto done;
1481 }
1482
1483done:
1484 policy->action = action;
1485 policy->delta = (int)(systime - pts);
1486 if (action == AV_SYNC_AA_RENDER) {
Song Zhaoad8a0112024-03-26 22:37:23 +00001487 if (!out_lier)
1488 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001489 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001490 if (!out_lier)
1491 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001492 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001493 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001494 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1495 msync_session_update_apts(avsync->fd, systime, pts, 0);
1496 log_info("[%d] audio switch done sys %u pts %u",
1497 avsync->session_id, systime, pts);
1498 msync_session_set_audio_switch(avsync->fd, false);
1499 avsync->in_audio_switch = false;
1500 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1501 } else {
1502 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1503 avsync->session_id, action, systime, pts, systime - pts);
1504 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001505 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001506 } else {
Song Zhaoad8a0112024-03-26 22:37:23 +00001507 if (!avsync->in_audio_switch && avsync->last_disc_pts != pts &&
1508 (abs_diff(systime, pts) > avsync->disc_thres_min ||
1509 (action == AV_SYNC_AA_INSERT && send_disc))) {
Song Zhao409739b2021-05-12 22:21:40 -07001510 log_info ("[%d]audio disc %u --> %u",
1511 avsync->session_id, systime, pts);
1512 msync_session_set_audio_dis(avsync->fd, pts);
1513 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001514 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001515 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001516
Song Zhaoad8a0112024-03-26 22:37:23 +00001517 avsync->apts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001518 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001519 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001520 if (!avsync->audio_drop_cnt)
1521 avsync->audio_drop_start = now;
1522 avsync->audio_drop_cnt++;
1523 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1524 log_info ("[%d]audio keep dropping sys %u vs a %u",
1525 avsync->session_id, systime, pts);
1526 msync_session_set_audio_dis(avsync->fd, pts);
1527 }
Song Zhao409739b2021-05-12 22:21:40 -07001528 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001529 if (action != AV_SYNC_AA_DROP)
1530 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001531 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001532 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001533 }
1534
1535 return ret;
1536}
1537
Song Zhaof3350d32023-08-18 16:27:31 -07001538int av_sync_get_pos(void *sync, pts90K *pts, uint64_t *mono_clock)
1539{
1540 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1541
1542 if (!avsync || !pts)
1543 return -1;
1544
1545 if (avsync->type != AV_SYNC_TYPE_AUDIO &&
1546 avsync->type != AV_SYNC_TYPE_VIDEO)
1547 return -2;
1548 return msync_session_get_pts(avsync->fd, pts,
1549 mono_clock, avsync->type == AV_SYNC_TYPE_VIDEO);
1550}
1551
Song Zhaoea5a0412021-01-18 16:40:08 -08001552int av_sync_get_clock(void *sync, pts90K *pts)
1553{
1554 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1555
1556 if (!avsync || !pts)
1557 return -1;
1558 return msync_session_get_wall(avsync->fd, pts, NULL);
1559}
1560
1561static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001562 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001563 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001564{
Song Zhao76005282022-03-08 16:49:41 -08001565 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1566 avsync->session_id, avsync->active_mode, avsync->mode,
1567 v_active, a_active, v_timeout, stat);
1568
1569 /* iptv delayed start */
1570 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1571 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1572
Song Zhaoea5a0412021-01-18 16:40:08 -08001573 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1574 float speed;
Song Zhao7e8c68f2022-07-12 16:24:30 -07001575 if (a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001576 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001577 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhao6183ca92022-07-29 09:57:03 -07001578 } else if (!a_active && !avsync->session_started) {
1579 /* quit waiting ASAP */
1580 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoea5a0412021-01-18 16:40:08 -08001581 }
1582
1583 if (!msync_session_get_rate(avsync->fd, &speed)) {
1584 /* speed change is triggered by asink,
1585 * attached audio HAL will handle it
1586 */
1587 if (speed != avsync->speed)
1588 log_info("[%d]new rate %f", avsync->session_id, speed);
Song Zhaoea5a0412021-01-18 16:40:08 -08001589 avsync->speed = speed;
1590 }
Song Zhaoebc92012024-03-12 18:36:44 +00001591 } else if (avsync->mode == AV_SYNC_MODE_PCR_MASTER &&
1592 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1593 /* pcr master stopping procedure */
1594 if (a_active && avsync->audio_start) {
1595 if (v_active || v_timeout) {
1596 log_info("audio start cb");
1597 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1598 }
1599 }
Song Zhaod62bb392021-04-23 12:25:49 -07001600 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1601 struct session_debug debug;
Song Zhao5296acf2024-02-02 21:45:04 +00001602
1603 if (a_active && avsync->audio_start) {
1604 if (v_active || v_timeout) {
1605 log_info("audio start cb");
1606 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1607 }
1608 }
1609
Song Zhaod62bb392021-04-23 12:25:49 -07001610 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001611 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001612 avsync->backup_mode = avsync->mode;
1613 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001614 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001615 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001616 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001617 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001618 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001619 log_warn("[%d]audio back to mode %d",
1620 avsync->session_id, avsync->mode);
1621 }
1622 }
Song Zhao76005282022-03-08 16:49:41 -08001623 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1624 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaob8833c12024-02-02 21:54:36 +00001625 if (a_active && avsync->audio_start) {
1626 if (v_active || v_timeout) {
1627 log_info("audio start cb");
1628 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1629 }
1630 }
1631
Song Zhaoea5a0412021-01-18 16:40:08 -08001632 }
1633}
1634
1635static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001636 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001637 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001638{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001639 struct session_debug debug;
1640
Song Zhao76005282022-03-08 16:49:41 -08001641 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1642 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001643 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1644 if (debug.debug_freerun && !avsync->debug_freerun) {
1645 avsync->backup_mode = avsync->mode;
1646 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1647 avsync->debug_freerun = true;
1648 log_warn("[%d]video to freerun mode", avsync->session_id);
1649 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1650 avsync->mode = avsync->backup_mode;
1651 avsync->debug_freerun = false;
1652 log_warn("[%d]video back to mode %d",
1653 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001654 }
1655 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001656}
1657
1658static void * poll_thread(void * arg)
1659{
1660 int ret = 0;
1661 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1662 const int fd = avsync->fd;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001663 int poll_timeout = 10;
Song Zhaoea5a0412021-01-18 16:40:08 -08001664 struct pollfd pfd = {
1665 /* default blocking capture */
Song Zhao4bd18762022-09-30 16:39:52 -07001666 .events = POLLPRI,
Song Zhaoea5a0412021-01-18 16:40:08 -08001667 .fd = avsync->fd,
1668 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001669 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001670
Song Zhaoea5a0412021-01-18 16:40:08 -08001671 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001672
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001673 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001674 prctl (PR_SET_NAME, "avs_apoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001675 sflag = SRC_A;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001676 } else if (avsync->type == AV_SYNC_TYPE_VIDEO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001677 prctl (PR_SET_NAME, "avs_vpoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001678 sflag = SRC_V;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001679 poll_timeout = 100;
1680 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001681
Song Zhaoea5a0412021-01-18 16:40:08 -08001682 while (!avsync->quit_poll) {
1683 for (;;) {
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001684 ret = poll(&pfd, 1, poll_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001685 if (ret > 0)
1686 break;
1687 if (avsync->quit_poll)
1688 goto exit;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001689 if (errno == EINTR) {
1690 log_debug("[%d] poll interrupted", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001691 continue;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001692 }
Song Zhao4bd18762022-09-30 16:39:52 -07001693 if (errno == EAGAIN || errno == ENOMEM) {
1694 log_info("[%d] poll error %d", avsync->session_id, errno);
1695 continue;
1696 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001697 }
1698
1699 /* error handling */
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001700 if (pfd.revents & POLLERR) {
1701 usleep(poll_timeout * 1000);
1702 continue;
1703 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001704
Song Zhao4bd18762022-09-30 16:39:52 -07001705 if (pfd.revents & POLLNVAL) {
1706 log_warn("[%d] fd closed", avsync->session_id);
1707 goto exit;
1708 }
Song Zhaod62bb392021-04-23 12:25:49 -07001709 /* mode change. Non-exclusive wait so all the processes
1710 * shall be woken up
1711 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001712 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001713 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001714 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001715
Song Zhao9fef59c2022-08-17 12:43:10 -07001716 msync_session_get_stat(fd, true, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001717 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001718
1719 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001720 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001721 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001722 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001723 usleep(10000);
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001724 } else {
1725 log_debug("[%d] unexpected revents %x", avsync->session_id, pfd.revents);
1726 usleep(poll_timeout * 1000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001727 }
1728 }
1729exit:
1730 log_info("[%d]quit", avsync->session_id);
1731 return NULL;
1732}
1733
Song Zhao623e2f12021-09-03 15:54:04 -07001734#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1735/* return ppm between demod and PCR clock */
1736int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1737{
1738 int fd = -1, ppm = 0, nread;
1739 char buf[128];
1740 uint32_t reg_v, lock;
1741 float val;
1742
1743 fd = open(DEMOD_NODE, O_RDWR);
1744 if (fd < 0) {
1745 log_warn("node not found %s", DEMOD_NODE);
1746 /* do not retry */
1747 avsync->ppm_adjusted = true;
1748 return 0;
1749 }
1750 snprintf(buf, sizeof(buf), "%d", 5);
1751 write(fd, buf, 2);
1752
1753 lseek(fd, 0, SEEK_SET);
1754
hanghang.luo02efd312022-08-26 09:49:53 +08001755 nread = read(fd, buf, sizeof(buf)-1);
Song Zhao623e2f12021-09-03 15:54:04 -07001756 if (nread <= 0) {
1757 log_error("read error");
1758 goto err;
1759 }
1760 buf[nread] = 0;
1761 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1762 log_error("wrong format %s", buf);
1763 goto err;
1764 }
1765 if (lock != 0x1f) {
1766 log_info("demod not locked");
1767 goto err;
1768 }
1769 if (reg_v > ((2 << 20) - 1))
1770 reg_v -= (2 << 21);
1771 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1772 ppm = val;
1773 log_info("ppm from SFO %d", ppm);
1774 avsync->ppm_adjusted = true;
1775
1776err:
1777 if (fd >= 0)
1778 close(fd);
1779 return ppm;
1780}
1781
Song Zhaod62bb392021-04-23 12:25:49 -07001782int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001783{
1784 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001785 struct pcr_info pcr;
1786 enum pcr_monitor_status status;
1787 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001788 if (!avsync)
1789 return -1;
1790
1791 if (avsync->type != AV_SYNC_TYPE_PCR)
1792 return -2;
1793
Song Zhao623e2f12021-09-03 15:54:04 -07001794 /* initial estimation from Demod SFO HW */
1795 if (!avsync->ppm_adjusted) {
1796 ppm = dmod_get_sfo_dev(avsync);
1797 if (ppm != 0) {
1798 /* ppm > 0 means board clock is faster */
1799 msync_session_set_clock_dev(avsync->fd, -ppm);
1800 }
1801 }
wei.dubcc2ed22021-05-19 07:16:10 -04001802 pcr.monoclk = mono_clock / 1000;
1803 pcr.pts = (long long) pts * 1000 / 90;
1804 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1805
1806 status = pcr_monitor_get_status(avsync->pcr_monitor);
1807
1808 if (status >= DEVIATION_READY) {
1809 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1810 if (avsync->ppm != ppm) {
1811 avsync->ppm = ppm;
1812 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1813 if (msync_session_set_clock_dev(avsync->fd, ppm))
1814 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001815 else
1816 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001817 }
1818 }
1819
Song Zhaod62bb392021-04-23 12:25:49 -07001820 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001821}
1822
Song Zhaod62bb392021-04-23 12:25:49 -07001823int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001824{
1825 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1826
1827 if (!avsync)
1828 return -1;
1829
Song Zhaod62bb392021-04-23 12:25:49 -07001830 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001831}
1832
1833int av_sync_set_session_name(void *sync, const char *name)
1834{
1835 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1836
1837 if (!avsync)
1838 return -1;
1839
1840 return msync_session_set_name(avsync->fd, name);
1841}
yongchun.li107a6162021-05-05 02:38:57 -07001842
1843int av_sync_set_audio_switch(void *sync, bool start)
1844{
1845 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1846 bool v_active, a_active, v_timeout;
1847
1848 if (!avsync)
1849 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001850 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001851 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001852 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001853 log_error("[%d] can not get session state",
1854 avsync->session_id);
1855 return -1;
1856 }
1857 if (!v_active || !a_active) {
1858 log_error("[%d] no apply if not AV both active v %d a %d",
1859 avsync->session_id, v_active, a_active);
1860 return -1;
1861 }
1862 if (msync_session_set_audio_switch(avsync->fd, start)) {
1863 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1864 return -1;
1865 }
1866 avsync->in_audio_switch = start;
1867 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1868 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1869 return 0;
1870}
1871
1872int av_sync_get_audio_switch(void *sync, bool *start)
1873{
1874 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1875
1876 if (!avsync)
1877 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001878 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001879 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001880 log_error("[%d] can not audio seamless switch state",
1881 avsync->session_id);
1882 return -1;
1883 }
1884 if (start) *start = avsync->in_audio_switch;
1885 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001886}
Song Zhao8039f562021-05-18 18:11:25 -07001887
Song Zhao623e2f12021-09-03 15:54:04 -07001888enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001889{
1890 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1891
wei.dubcc2ed22021-05-19 07:16:10 -04001892 if (!avsync || !ppm)
1893 return CLK_RECOVERY_ERR;
1894 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001895 return CLK_RECOVERY_NOT_RUNNING;
1896
wei.dubcc2ed22021-05-19 07:16:10 -04001897 if (msync_session_get_clock_dev(avsync->fd, ppm))
1898 return CLK_RECOVERY_ERR;
1899
1900 if (*ppm == 0)
1901 return CLK_RECOVERY_ONGOING;
1902 else
1903 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001904}
Song Zhao95bd0922021-09-21 14:07:46 -07001905
1906static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1907{
1908 int ret;
1909
1910 if (!avsync->frame_q) {
1911 avsync->frame_q = create_q(MAX_FRAME_NUM);
1912 if (!avsync->frame_q) {
1913 log_error("[%d]create queue fail", avsync->session_id);
1914
1915 return -1;
1916 }
1917 }
1918
1919 ret = queue_item(avsync->frame_q, frame);
1920 if (ret)
hanghang.luo02efd312022-08-26 09:49:53 +08001921 log_error("queue fail:%d", ret);
Song Zhao95bd0922021-09-21 14:07:46 -07001922 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1923 return ret;
1924}
1925
1926int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1927{
1928 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1929
1930 if (!avsync)
1931 return -1;
1932 avsync->msys = msys;
1933 return 0;
1934}
1935
1936static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1937{
1938 struct vframe *frame = NULL, *enter_last_frame = NULL;
1939 uint64_t systime;
1940 int toggle_cnt = 0;
1941
1942 enter_last_frame = avsync->last_frame;
1943 systime = avsync->msys;
1944 log_debug("[%d]sys %llu", avsync->session_id, systime);
1945 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1946 if (systime >= frame->mts) {
1947 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1948 toggle_cnt++;
1949
1950 if (avsync->last_frame)
1951 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1952
1953 dqueue_item(avsync->frame_q, (void **)&frame);
1954 if (avsync->last_frame) {
1955 /* free frame that are not for display */
1956 if (toggle_cnt > 1) {
1957 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1958 avsync->last_frame->mts, frame->mts, systime);
1959 avsync->last_frame->free(avsync->last_frame);
1960 }
1961 } else {
1962 avsync->first_frame_toggled = true;
1963 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1964 }
1965 avsync->last_frame = frame;
1966 } else
1967 break;
1968 }
1969
1970 if (avsync->last_frame) {
1971 if (enter_last_frame != avsync->last_frame)
hanghang.luo02efd312022-08-26 09:49:53 +08001972 log_debug("[%d]pop %lu", avsync->session_id, avsync->last_frame->pts);
1973 log_trace("[%d]pop=%llu, system=%llu, diff %llu(ms), QNum=%d", avsync->session_id,
Song Zhao95bd0922021-09-21 14:07:46 -07001974 avsync->last_frame->mts,
1975 systime, (systime - avsync->last_frame->mts) / 1000000,
1976 queue_size(avsync->frame_q));
1977 } else
1978 if (enter_last_frame != avsync->last_frame)
1979 log_debug("[%d]pop (nil)", avsync->session_id);
1980
1981 if (avsync->last_frame)
1982 avsync->last_frame->hold_period++;
1983 return avsync->last_frame;
1984}
Song Zhao6183ca92022-07-29 09:57:03 -07001985
1986int avs_sync_stop_audio(void *sync)
1987{
1988 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1989
1990 if (!avsync)
1991 return -1;
1992
1993 return msync_session_stop_audio(avsync->fd);
1994}
bo.xiao05ba1ac2022-12-13 14:38:13 +08001995
1996int avs_sync_set_eos(void *sync)
1997{
1998 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1999
2000 if (!avsync)
2001 return -1;
2002
2003 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
2004 if (avsync->state == AV_SYNC_STAT_INIT) {
2005 avsync->state = AV_SYNC_STAT_RUNNING;
2006 log_debug("[%d]eos trigger state change: init --> running", avsync->session_id);
2007 }
2008 }
2009
2010 return 0;
2011}