blob: cf9c8ee287848a1ba8fb05bb01731edcb97d1ee8 [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);
le.hand946d202024-09-27 10:16:57 +0000488 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
489 if (msync_session_set_audio_switch(avsync->fd, false)) {
490 log_error("[%d]fail to set audio switch false", avsync->session_id);
491 }
Song Zhao6be9ac22022-09-30 16:44:50 -0700492 internal_stop(avsync);
le.hand946d202024-09-27 10:16:57 +0000493 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800494
Song Zhao6be9ac22022-09-30 16:44:50 -0700495 avsync->quit_poll = true;
496 if (avsync->poll_thread) {
497 pthread_join(avsync->poll_thread, NULL);
498 avsync->poll_thread = 0;
Song Zhaoaf368d52021-02-17 17:53:45 -0800499 }
Song Zhao6be9ac22022-09-30 16:44:50 -0700500 if (avsync->type == AV_SYNC_TYPE_AUDIO)
501 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoc03ba122020-12-23 21:54:02 -0800502
Song Zhaoea5a0412021-01-18 16:40:08 -0800503 if (avsync->session_started) {
504 if (avsync->type == AV_SYNC_TYPE_VIDEO)
505 msync_session_set_video_stop(avsync->fd);
506 else
507 msync_session_set_audio_stop(avsync->fd);
508 }
wei.dubcc2ed22021-05-19 07:16:10 -0400509
510 if(avsync->pcr_monitor)
511 pcr_monitor_destroy(avsync->pcr_monitor);
512
Song Zhaoea5a0412021-01-18 16:40:08 -0800513 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800514 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800515 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
516 destroy_q(avsync->frame_q);
517 destroy_pattern_detector(avsync->pattern_detector);
518 }
Song Zhaob5458b32021-11-12 15:58:47 -0800519 log_info("[%d]done type %d", avsync->session_id, avsync->type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800520 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800521}
522
bo.xiao5821fc72021-07-11 22:47:00 -0400523int avs_sync_set_start_policy(void *sync, struct start_policy* st_policy)
Song Zhaoea5a0412021-01-18 16:40:08 -0800524{
525 struct av_sync_session *avsync = (struct av_sync_session *)sync;
526
527 if (!avsync || !avsync->fd)
528 return -1;
529
Song Zhao47961d72022-08-29 14:04:44 -0700530 log_info("[%d]policy %u --> %u, timeout %d --> %d", avsync->session_id,
531 avsync->start_policy, st_policy->policy, avsync->timeout, st_policy->timeout);
Song Zhaof4e3c862022-09-01 14:00:11 -0700532 if (avsync->mode == AV_SYNC_MODE_IPTV &&
Song Zhao76005282022-03-08 16:49:41 -0800533 st_policy->policy != AV_SYNC_START_ASAP) {
534 log_error("policy %d not supported in live mode", st_policy->policy);
535 return -1;
536 }
537
Song Zhaof4e3c862022-09-01 14:00:11 -0700538 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
539 msync_session_set_start_thres(avsync->fd, st_policy->timeout);
540
bo.xiao5821fc72021-07-11 22:47:00 -0400541 avsync->start_policy = st_policy->policy;
542 avsync->timeout = st_policy->timeout;
Song Zhao76005282022-03-08 16:49:41 -0800543
Song Zhaoea5a0412021-01-18 16:40:08 -0800544 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400545 if (st_policy->policy != AV_SYNC_START_NONE &&
546 st_policy->policy != AV_SYNC_START_V_PEEK)
547 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800548
549 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800550}
551
552int av_sync_pause(void *sync, bool pause)
553{
554 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700555 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800556 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800557
Song Zhaob5458b32021-11-12 15:58:47 -0800558 if (!avsync) {
559 log_error("invalid handle");
Song Zhaoc03ba122020-12-23 21:54:02 -0800560 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800561 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800562
fei.deng55389b62022-08-18 23:46:50 +0800563 if (avsync->type == AV_SYNC_TYPE_VIDEO && avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
564 log_warn("ignore pause in video mono mode");
565 return -1;
566 }
567
Song Zhaob5458b32021-11-12 15:58:47 -0800568 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
569 log_warn("ignore pause in pcr master mode");
Song Zhaoea5a0412021-01-18 16:40:08 -0800570 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800571 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800572
Song Zhao9fef59c2022-08-17 12:43:10 -0700573 rc = msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -0700574 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700575 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700576
yongchun.li5f52fb02021-06-04 18:13:05 -0700577 /* ignore only when video try to pause when audio is acive, on which
578 the control of the STC will be relays.
579 When resume,it can do always as it is possible that video just
580 paused earlier without audio yet,then audio added later before resume.
581 We shall not igore that otherwise it could cause video freeze. */
582 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
583 avsync->type == AV_SYNC_TYPE_VIDEO &&
584 a_active &&
585 !avsync->in_audio_switch) {
586 if (!pause) {
587 log_info("[%d] clear video pause when audio active",
588 avsync->session_id);
589 avsync->paused = pause;
590 } else {
591 log_info("[%d] ignore the pause from video when audio active",
592 avsync->session_id);
593 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800594 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700595 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800596
yongchun.li107a6162021-05-05 02:38:57 -0700597 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
598 log_info("[%d] ignore the pause from audio", avsync->session_id);
599 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
600 return 0;
601 }
602
Song Zhaoea5a0412021-01-18 16:40:08 -0800603 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800604 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800605 log_info("[%d]paused:%d type:%d rc %d",
606 avsync->session_id, pause, avsync->type, rc);
yongchun.li428390d2022-02-17 17:15:40 -0800607 if (!avsync->paused && avsync->first_frame_toggled) {
608 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
609 log_info("[%d] resume update new frame time", avsync->session_id);
610 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800611 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800612}
613
614int av_sync_push_frame(void *sync , struct vframe *frame)
615{
616 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700617 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800618 struct av_sync_session *avsync = (struct av_sync_session *)sync;
619
620 if (!avsync)
621 return -1;
622
Song Zhao95bd0922021-09-21 14:07:46 -0700623 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
fei.deng55389b62022-08-18 23:46:50 +0800624 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
Song Zhao95bd0922021-09-21 14:07:46 -0700625 return video_mono_push_frame(avsync, frame);
fei.deng55389b62022-08-18 23:46:50 +0800626 }
Song Zhao95bd0922021-09-21 14:07:46 -0700627
Song Zhaofd007632022-09-30 16:21:30 -0700628 if (avsync->state == AV_SYNC_STAT_INIT && !queue_size(avsync->frame_q)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800629 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400630 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800631 log_error("[%d]get policy", avsync->session_id);
632 return -1;
633 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800634 }
635
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700636 if (avsync->last_q_pts != -1) {
Song Zhao7e24b182022-04-01 08:46:40 -0700637 if (frame->pts != -1 && avsync->mode == AV_SYNC_MODE_VMASTER) {
638 /* Sometimes app will fake PTS for trickplay, video PTS gap
639 * is really big depending on the speed. Have to adjust the
640 * threshold dynamically.
641 */
642 int gap = (int)(frame->pts - avsync->last_q_pts);
643 if (gap > avsync->disc_thres_min) {
644 avsync->disc_thres_min = gap * 6;
645 avsync->disc_thres_max = gap * 20;
646 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
647 msync_session_set_disc_thres(avsync->session_id,
648 avsync->disc_thres_min, avsync->disc_thres_max);
649 log_info("[%d] update disc_thres to %d/%d",avsync->session_id,
650 avsync->disc_thres_min, avsync->disc_thres_max);
651 }
652 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700653 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
654 /* TODO: wrong, should remove from back of queue */
le.hanebaea1e2023-07-10 07:26:09 +0000655 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800656 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700657 if (prev) {
658 prev->free(prev);
659 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
660 }
le.hanebaea1e2023-07-10 07:26:09 +0000661 pthread_mutex_unlock(&avsync->lock);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700662 } else if (avsync->fps_cnt < 100) {
663 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700664
665 if (interval > 0 && interval <= 4500) {
666 if (avsync->fps_interval_acc == -1) {
667 avsync->fps_interval_acc = interval;
668 avsync->fps_cnt = 1;
669 } else {
670 avsync->fps_interval_acc += interval;
671 avsync->fps_cnt++;
672 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
673 if (avsync->fps_cnt == 100)
674 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
675 }
676 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800677 }
678 }
679
Song Zhao065800e2021-05-26 15:56:06 -0700680 if (frame->duration == -1)
681 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800682 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700683 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800684 ret = queue_item(avsync->frame_q, frame);
685 if (avsync->state == AV_SYNC_STAT_INIT &&
686 queue_size(avsync->frame_q) >= avsync->start_thres) {
687 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaofd007632022-09-30 16:21:30 -0700688 log_debug("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800689 }
690
691 if (ret)
Song Zhaoe1b65602022-01-06 08:03:46 -0800692 log_error("queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400693 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800694 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800695}
696
697struct vframe *av_sync_pop_frame(void *sync)
698{
Song Zhaoea5a0412021-01-18 16:40:08 -0800699 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800700 struct av_sync_session *avsync = (struct av_sync_session *)sync;
701 int toggle_cnt = 0;
hanghang.luo02efd312022-08-26 09:49:53 +0800702 uint32_t systime = 0;
Song Zhao468fd652021-01-15 22:13:04 -0800703 bool pause_pts_reached = false;
hanghang.luo02efd312022-08-26 09:49:53 +0800704 uint32_t interval = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800705
Song Zhao95bd0922021-09-21 14:07:46 -0700706 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
707 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
708 return video_mono_pop_frame(avsync);
709
Song Zhaoc03ba122020-12-23 21:54:02 -0800710 pthread_mutex_lock(&avsync->lock);
711 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhao2f6744b2021-11-03 21:23:50 -0700712 log_debug("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800713 goto exit;
714 }
715
Song Zhaoea5a0412021-01-18 16:40:08 -0800716 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700717 uint32_t pts;
718
Song Zhaoc03ba122020-12-23 21:54:02 -0800719 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800720 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800721 goto exit;
722 }
Song Zhao35a82df2021-04-15 10:58:49 -0700723 msync_session_get_wall(avsync->fd, &systime, &interval);
724 pts = frame->pts - avsync->delay * interval;
725 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800726 avsync->session_started = true;
Song Zhao5296acf2024-02-02 21:45:04 +0000727 log_info("[%d]video start %u frame %u sys %u",
728 avsync->session_id, pts, frame->pts, systime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800729 }
730
Song Zhaoea5a0412021-01-18 16:40:08 -0800731 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700732 !avsync->first_frame_toggled &&
733 !msync_clock_started(avsync->fd)) {
734 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800735 log_trace("[%d]clock not started", avsync->session_id);
736 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800737 }
738
Song Zhaoea5a0412021-01-18 16:40:08 -0800739 enter_last_frame = avsync->last_frame;
740 msync_session_get_wall(avsync->fd, &systime, &interval);
741
742 /* handle refresh rate change */
743 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
744 avsync->vsync_interval != interval) {
745 log_info("[%d]vsync interval update %d --> %u",
746 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700747 if (avsync->fps_interval == -1)
748 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800749 avsync->vsync_interval = interval;
750 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800751 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700752 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800753 reset_pattern(avsync->pattern_detector);
754 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800755 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
756 struct vframe *next_frame = NULL;
757
758 peek_item(avsync->frame_q, (void **)&next_frame, 1);
759 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700760 log_debug("[%d]cur_f %u next_f %u size %d",
761 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800762 if (frame_expire(avsync, systime, interval,
763 frame, next_frame, toggle_cnt)) {
764 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800765 toggle_cnt++;
766
Song Zhao35a82df2021-04-15 10:58:49 -0700767 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800768 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700769 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700770 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700771 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
772 if (next_frame)
773 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
774 }
Song Zhao35a82df2021-04-15 10:58:49 -0700775
Song Zhaoc03ba122020-12-23 21:54:02 -0800776 if (avsync->last_frame)
777 avsync->last_holding_peroid = avsync->last_frame->hold_period;
778
779 dqueue_item(avsync->frame_q, (void **)&frame);
780 if (avsync->last_frame) {
Song Zhao5296acf2024-02-02 21:45:04 +0000781 int qsize = queue_size(avsync->frame_q);
782
Song Zhaoc03ba122020-12-23 21:54:02 -0800783 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800784 if (toggle_cnt > 1) {
Song Zhaofd007632022-09-30 16:21:30 -0700785 log_info("[%d]free %u cur %u system/d %u/%u queue size %d", avsync->session_id,
786 avsync->last_frame->pts, frame->pts,
787 systime, systime - avsync->last_poptime,
Song Zhao5296acf2024-02-02 21:45:04 +0000788 qsize);
Song Zhaoc03ba122020-12-23 21:54:02 -0800789 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800790 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800791 } else {
792 avsync->first_frame_toggled = true;
Song Zhaofd007632022-09-30 16:21:30 -0700793 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 -0800794 }
795 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800796 avsync->last_pts = frame->pts;
yongchun.li428390d2022-02-17 17:15:40 -0800797 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
Song Zhaoc03ba122020-12-23 21:54:02 -0800798 } else
799 break;
800 }
801
802 /* pause pts */
803 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800804 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800805 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800806 else
Song Zhao468fd652021-01-15 22:13:04 -0800807 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
808 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
809 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
810 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
811 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800812
Song Zhao468fd652021-01-15 22:13:04 -0800813 if (pause_pts_reached) {
Song Zhao468fd652021-01-15 22:13:04 -0800814 /* stay in paused until av_sync_pause(false) */
Song Zhaoa1742282022-09-30 16:17:26 -0700815 uint32_t local_pts = avsync->pause_pts;
Song Zhao468fd652021-01-15 22:13:04 -0800816 avsync->paused = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800817 log_info ("[%d]reach pause pts: %u",
Song Zhaob5458b32021-11-12 15:58:47 -0800818 avsync->session_id, avsync->pause_pts);
Song Zhaoad7c8232021-12-14 11:46:48 -0800819 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoa1742282022-09-30 16:17:26 -0700820 if (avsync->pause_pts_cb)
821 avsync->pause_pts_cb(local_pts,
822 avsync->pause_cb_priv);
823 log_info ("[%d] reach pause pts: %u handle done",
824 avsync->session_id, local_pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800825 }
826
827exit:
828 pthread_mutex_unlock(&avsync->lock);
yongchun.li428390d2022-02-17 17:15:40 -0800829
830 /* underflow check */
831 if (avsync->session_started && avsync->first_frame_toggled &&
832 (avsync->paused == false) && (avsync->state >= AV_SYNC_STAT_RUNNING) &&
833 avsync->underflow_cb && peek_item(avsync->frame_q, (void **)&frame, 0))
834 {/* empty queue in normal play */
835 struct timespec now;
836 int diff_ms;
837 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
838 diff_ms = time_diff(&now, &avsync->frame_last_update_time)/1000;
839 if(diff_ms >= (avsync->underflow_cfg.time_thresh
840 + avsync->vsync_interval*avsync->last_holding_peroid/90)) {
841 log_info ("[%d]underflow detected: %u", avsync->session_id, avsync->last_pts);
842 avsync->underflow_cb (avsync->last_pts,
843 avsync->underflow_cb_priv);
844 /* update time to control the underflow check call backs */
845 avsync->frame_last_update_time = now;
846 }
847 }
848
Song Zhaoc03ba122020-12-23 21:54:02 -0800849 if (avsync->last_frame) {
Song Zhaof3350d32023-08-18 16:27:31 -0700850 if (enter_last_frame != avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800851 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhaof3350d32023-08-18 16:27:31 -0700852 /* don't update vpts for out_lier */
853 if (avsync->last_frame->duration != -1)
854 msync_session_update_vpts(avsync->fd, systime,
855 avsync->last_frame->pts + avsync->extra_delay, interval * avsync->delay);
856 }
bo.xiao1f94b352021-08-02 03:53:47 -0400857 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 -0800858 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800859 if (enter_last_frame != avsync->last_frame)
860 log_debug("[%d]pop (nil)", avsync->session_id);
861
Song Zhao35a82df2021-04-15 10:58:49 -0700862 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800863 if (avsync->last_frame)
864 avsync->last_frame->hold_period++;
865 return avsync->last_frame;
866}
867
Song Zhaoc03ba122020-12-23 21:54:02 -0800868static inline uint32_t abs_diff(uint32_t a, uint32_t b)
869{
Song Zhaoea5a0412021-01-18 16:40:08 -0800870 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800871}
872
yongchun.li0ee6e372021-08-20 04:26:04 -0700873static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800874{
hanghang.luo02efd312022-08-26 09:49:53 +0800875 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 -0800876}
877
Song Zhaoc03ba122020-12-23 21:54:02 -0800878static bool frame_expire(struct av_sync_session* avsync,
879 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800880 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800881 struct vframe * frame,
882 struct vframe * next_frame,
883 int toggle_cnt)
884{
Song Zhao6dce2672022-01-13 11:32:44 -0800885 uint32_t fpts = frame->pts + avsync->extra_delay;
886 uint32_t nfpts = -1;
Song Zhaoad8a0112024-03-26 22:37:23 +0000887 uint32_t last_pts = avsync->last_pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800888 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800889 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800890
Song Zhao9c0197e2024-03-12 18:05:20 +0000891 if (!VALID_TS(systime))
892 return false;
893
Song Zhaoc03ba122020-12-23 21:54:02 -0800894 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
895 return false;
896
897 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
898 return true;
899
Song Zhaoad7c8232021-12-14 11:46:48 -0800900 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS &&
901 avsync->pause_pts == frame->pts)
902 return true;
903
Song Zhao08fa16b2021-12-08 14:30:17 -0800904 if (systime == AV_SYNC_INVALID_PTS &&
905 avsync->mode == AV_SYNC_MODE_AMASTER)
906 return false;
907
Song Zhao6dce2672022-01-13 11:32:44 -0800908 if (next_frame)
909 nfpts = next_frame->pts + avsync->extra_delay;
910
Song Zhao7e24b182022-04-01 08:46:40 -0700911 if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
fei.deng63e43e12021-09-23 19:44:01 +0800912 /* We need to ensure that the video outputs smoothly,
913 so output video frame by frame hold_period */
914 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
915 avsync->last_frame &&
916 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
917 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
918 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700919 return true;
920 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700921 }
922
Song Zhaoc03ba122020-12-23 21:54:02 -0800923 if (!fpts) {
924 if (avsync->last_frame) {
925 /* try to accumulate duration as PTS */
926 fpts = avsync->vpts + avsync->last_frame->duration;
927 } else {
928 fpts = avsync->vpts;
929 }
930 }
931 systime += pts_correction;
932
933 /* phase adjustment */
934 if (avsync->phase_set)
935 systime += avsync->phase;
936
yongchun.lia50b1e92021-08-07 01:11:54 +0000937 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800938 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000939 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700940 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800941 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800942 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800943 return false;
944
Song Zhaoa2985cb2021-06-24 12:01:47 -0700945 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
946 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700947 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800948
yongchun.li0ee6e372021-08-20 04:26:04 -0700949 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700950 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800951 avsync->last_pts = fpts;
952 if (time_diff(&now, &avsync->sync_lost_print_time) >=
953 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700954 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800955 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800956 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700957 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800958 } else
959 avsync->sync_lost_cnt++;
960 }
Song Zhaod62bb392021-04-23 12:25:49 -0700961
962 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
963 LIVE_MODE(avsync->mode) &&
Song Zhaoad8a0112024-03-26 22:37:23 +0000964 VALID_TS(last_pts) &&
965 abs_diff(last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700966 /* outlier by stream error */
967 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700968 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700969 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
970 log_info("render outlier %u", fpts);
971 return true;
972 }
973 }
974
975 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800976 avsync->state = AV_SYNC_STAT_SYNC_LOST;
977 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800978 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700979 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800980 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700981
Song Zhao7e24b182022-04-01 08:46:40 -0700982 if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700983 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700984 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700985 msync_session_set_video_dis(avsync->fd, fpts);
986 avsync->last_disc_pts = fpts;
Song Zhao59d732d2024-01-23 22:09:15 -0800987 if (avsync->mode == AV_SYNC_MODE_VMASTER) {
988 systime = fpts;
989 avsync->last_r_syst = -1;
990 }
Song Zhaoa2985cb2021-06-24 12:01:47 -0700991 }
992
993 if ((int)(systime - fpts) > 0) {
994 if ((int)(systime - fpts) < avsync->disc_thres_max) {
995 /* catch up PCR */
Song Zhao59d732d2024-01-23 22:09:15 -0800996 avsync->last_r_syst = -1;
Song Zhaof46932e2021-05-21 01:51:45 -0700997 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700998 } else {
999 /* render according to FPS */
1000 if (!VALID_TS(avsync->last_r_syst) ||
1001 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
1002 avsync->last_r_syst = systime;
1003 return true;
1004 }
1005 return false;
1006 }
1007 } else if (LIVE_MODE(avsync->mode)) {
1008 /* hold if the gap is small */
1009 if ((int)(fpts - systime) < avsync->disc_thres_max) {
1010 return false;
1011 } else {
1012 /* render according to FPS */
1013 if (!VALID_TS(avsync->last_r_syst) ||
1014 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
1015 avsync->last_r_syst = systime;
1016 return true;
1017 }
1018 return false;
1019 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001020 }
1021 }
1022
Song Zhao52f55192021-05-06 10:52:21 -07001023 /* In some cases, keeping pattern will enlarge the gap */
1024 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
1025 avsync->first_frame_toggled) {
1026 reset_pattern(avsync->pattern_detector);
Song Zhaofd007632022-09-30 16:21:30 -07001027 log_info("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -07001028 systime, fpts);
1029 }
1030
Song Zhaoc03ba122020-12-23 21:54:02 -08001031 expire = (int)(systime - fpts) >= 0;
1032
1033 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -08001034 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001035 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -08001036 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001037 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001038 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001039 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -08001040 }
Song Zhao6dce2672022-01-13 11:32:44 -08001041 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -08001042 && avsync->first_frame_toggled) {
1043 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -08001044 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001045 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -08001046 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001047 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001048 }
1049 }
1050
Song Zhaoa58c3e92021-03-09 18:52:55 -08001051 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -08001052 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -08001053 (avsync->last_frame?avsync->last_frame->hold_period:0),
1054 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -08001055 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -08001056
1057 if (expire) {
1058 avsync->vpts = fpts;
1059 /* phase adjustment */
1060 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +00001061 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -08001062 if ((int)(systime - fpts) >= 0 &&
1063 (int)(fpts + interval - systime) > 0) {
1064 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -08001065 avsync->phase_set = true;
Song Zhaofd007632022-09-30 16:21:30 -07001066 log_debug("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -08001067 }
Song Zhao1561e542022-01-12 10:37:55 -08001068 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -08001069 if ((int)(systime - fpts) >= 0 &&
1070 (int)(fpts + interval - systime) > 0) {
1071 int vsync_pts_delta = (int)(systime - fpts);
1072
1073 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1074 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001075 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001076 log_info("[%d] too aligned adjust phase to %d",
1077 avsync->session_id, (int)avsync->phase);
1078 }
1079 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001080 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001081 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaofd007632022-09-30 16:21:30 -07001082 log_info("[%d]sync setup on frame %u", avsync->session_id, fpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001083 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001084 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001085 }
1086 return expire;
1087}
1088
Song Zhao35a82df2021-04-15 10:58:49 -07001089static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001090{
Song Zhaoea5a0412021-01-18 16:40:08 -08001091 log_trace("[%d]cur_period: %d last_period: %d",
1092 avsync->session_id, cur_period, last_period);
Song Zhaobb3b4f32023-10-17 16:08:12 -07001093 return detect_pattern(avsync->pattern_detector, cur_period, last_period);
Song Zhaoc03ba122020-12-23 21:54:02 -08001094}
1095
1096int av_sync_set_speed(void *sync, float speed)
1097{
1098 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1099
1100 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001101 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001102 return -1;
1103 }
1104
Song Zhao76005282022-03-08 16:49:41 -08001105 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001106 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001107 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001108 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001109
Song Zhaoea5a0412021-01-18 16:40:08 -08001110 avsync->speed = speed;
1111
1112 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhaoa73fcf32023-01-13 08:12:26 -08001113 if (speed == 1.0)
1114 msync_session_set_wall_adj_thres(avsync->fd, DEFAULT_WALL_ADJ_THRES);
1115 else
1116 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
1117 log_info("[%d]adjust wall adj threshold to %d", avsync->session_id,
1118 (speed == 1.0) ? DEFAULT_WALL_ADJ_THRES : avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -08001119 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001120
Song Zhaoea5a0412021-01-18 16:40:08 -08001121 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1122 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001123}
1124
1125int av_sync_change_mode(void *sync, enum sync_mode mode)
1126{
1127 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1128
1129 if (!avsync)
1130 return -1;
1131
Song Zhaoea5a0412021-01-18 16:40:08 -08001132 if (msync_session_set_mode(avsync->fd, mode)) {
1133 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001134 return -1;
1135 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001136 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001137 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001138 return 0;
1139}
1140
Song Zhaoebc92012024-03-12 18:36:44 +00001141int av_sync_change_mode_by_id(int id, enum sync_mode mode)
1142{
1143 int fd;
1144 char dev_name[20];
1145
1146 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, id);
1147 fd = open(dev_name, O_RDONLY | O_CLOEXEC);
1148 if (fd < 0) {
1149 log_error("open %s errno %d", dev_name, errno);
1150 return -1;
1151 }
1152
1153 if (msync_session_set_mode(fd, mode)) {
1154 log_error("[%d]fail to set mode %d", id, mode);
1155 close(fd);
1156 return -1;
1157 }
1158
1159 close(fd);
1160 log_info("session[%d] set mode %d", id, mode);
1161 return 0;
1162}
1163
Song Zhao01031bb2021-05-13 21:23:20 -07001164int av_sync_get_mode(void *sync, enum sync_mode *mode)
1165{
1166 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1167
1168 if (!avsync || !mode)
1169 return -1;
1170
1171 *mode = avsync->mode;
1172 return 0;
1173}
1174
Song Zhaoc03ba122020-12-23 21:54:02 -08001175int av_sync_set_pause_pts(void *sync, pts90K pts)
1176{
1177 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1178
1179 if (!avsync)
1180 return -1;
1181
1182 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001183 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001184 return 0;
1185}
1186
1187int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1188{
1189 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1190
1191 if (!avsync)
1192 return -1;
1193
1194 avsync->pause_pts_cb = cb;
1195 avsync->pause_cb_priv = priv;
1196 return 0;
1197}
Song Zhaoea5a0412021-01-18 16:40:08 -08001198
yongchun.li428390d2022-02-17 17:15:40 -08001199int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1200{
1201 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1202
1203 if (!avsync)
1204 return -1;
1205
1206 avsync->underflow_cb = cb;
1207 avsync->underflow_cb_priv = priv;
1208
1209 if (cfg)
1210 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1211 else
1212 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1213
1214 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1215 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1216 avsync->underflow_cfg.time_thresh);
1217 return 0;
1218}
Song Zhaoea5a0412021-01-18 16:40:08 -08001219static void trigger_audio_start_cb(struct av_sync_session *avsync,
1220 avs_ascb_reason reason)
1221{
1222 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001223 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001224 pthread_mutex_lock(&avsync->lock);
1225 if (avsync->audio_start) {
1226 avsync->audio_start(avsync->audio_start_priv, reason);
1227 avsync->session_started = true;
1228 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001229 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001230 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1231 }
1232 pthread_mutex_unlock(&avsync->lock);
1233 }
1234}
1235
Song Zhao5296acf2024-02-02 21:45:04 +00001236static int update_pcr_master_disc_thres(struct av_sync_session * avsync, pts90K pts)
1237{
1238 pts90K pcr = -1;
1239
1240 if (!msync_session_get_pcr(avsync->fd, &pcr, NULL) && pcr != -1) {
1241 pts90K delta = abs_diff(pcr, pts);
1242
1243 if (delta * 3 > avsync->disc_thres_min)
1244 avsync->disc_thres_min = 3 * delta;
1245
1246 log_info("%d update disc_thres_min to %u delta %u",
1247 avsync->session_id, avsync->disc_thres_min, delta);
1248 return 0;
1249 }
1250 return -1;
1251}
1252
Song Zhaoea5a0412021-01-18 16:40:08 -08001253avs_start_ret av_sync_audio_start(
1254 void *sync,
1255 pts90K pts,
1256 pts90K delay,
1257 audio_start_cb cb,
1258 void *priv)
1259{
1260 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1261 uint32_t start_mode;
yongchun.li06965172022-12-14 19:50:31 -08001262 uint32_t systime = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001263 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1264 bool create_poll_t = false;
1265
1266 if (!avsync)
1267 return ret;
1268
yongchun.li59e873d2021-07-07 11:42:38 -07001269 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1270 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001271
yongchun.li06965172022-12-14 19:50:31 -08001272 if (avsync->in_audio_switch) {
1273 msync_session_get_wall(avsync->fd, &systime, NULL);
1274 if (systime == AV_SYNC_INVALID_PTS) {
1275 log_info("%d Invalid systime could be paused pts %d ms switch_state %d again",
1276 avsync->session_id, (int) pts/90, avsync->audio_switch_state);
1277 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
1278 ret = AV_SYNC_ASTART_AGAIN;
1279 goto exit;
1280 }
1281 }
1282
yongchun.li59e873d2021-07-07 11:42:38 -07001283 if (avsync->in_audio_switch &&
1284 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1285 {
1286 start_mode = AVS_START_SYNC;
1287 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1288 } else {
1289 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1290 log_error("[%d]fail to set audio start", avsync->session_id);
1291 }
1292 if (avsync->in_audio_switch &&
1293 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1294 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
Song Zhao4bd18762022-09-30 16:39:52 -07001295 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB
1296 && start_mode == AVS_START_SYNC) {
yongchun.li59e873d2021-07-07 11:42:38 -07001297 log_info("%d audio_switch audio need drop first.ahead %d ms",
1298 avsync->session_id, (int)(systime - pts)/90);
1299 ret = AV_SYNC_ASTART_AGAIN;
1300 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1301 goto exit;
1302 }
1303 else {
1304 int diff = (int)(pts - systime);
1305 log_info("%d audio_switch_state to start mode %d diff %d ms",
1306 avsync->session_id, start_mode, diff/90);
yongchun.li59e873d2021-07-07 11:42:38 -07001307 if (diff < A_ADJ_THREDHOLD_LB) {
1308 log_info("%d orig mode %d already close enough direct start",
1309 avsync->session_id, start_mode);
1310 start_mode = AVS_START_SYNC;
Song Zhao4bd18762022-09-30 16:39:52 -07001311 } else if (start_mode != AVS_START_ASYNC) {
1312 log_info("%d drop too far mode %d need to try ASYNC",
1313 avsync->session_id, start_mode);
1314 msync_session_set_audio_stop(avsync->fd);
1315 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1316 log_error("[%d]fail to set audio start", avsync->session_id);
1317 log_info("%d New start mode %d",
1318 avsync->session_id, start_mode);
yongchun.li59e873d2021-07-07 11:42:38 -07001319 }
Song Zhao4bd18762022-09-30 16:39:52 -07001320 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
yongchun.li59e873d2021-07-07 11:42:38 -07001321 }
yongchun.li107a6162021-05-05 02:38:57 -07001322 }
1323
Song Zhaoea5a0412021-01-18 16:40:08 -08001324 if (start_mode == AVS_START_SYNC) {
1325 ret = AV_SYNC_ASTART_SYNC;
1326 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001327 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhao5296acf2024-02-02 21:45:04 +00001328
1329 /* for DTG stream, initial delta between apts and pcr is big */
1330 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
1331 update_pcr_master_disc_thres(avsync, pts);
1332
Song Zhaod62bb392021-04-23 12:25:49 -07001333 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001334 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001335 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhao5296acf2024-02-02 21:45:04 +00001336
1337 /* for DTG stream, initial delta between apts and pcr is big */
1338 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
1339 update_pcr_master_disc_thres(avsync, pts);
Song Zhaod62bb392021-04-23 12:25:49 -07001340 } else if (start_mode == AVS_START_AGAIN) {
1341 ret = AV_SYNC_ASTART_AGAIN;
1342 }
1343
Song Zhao5296acf2024-02-02 21:45:04 +00001344 avsync->last_pts = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001345 if (ret == AV_SYNC_ASTART_AGAIN)
1346 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001347
Song Zhao76005282022-03-08 16:49:41 -08001348 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1349 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001350 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001351
1352 if (start_mode == AVS_START_ASYNC) {
1353 if (!cb) {
1354 log_error("[%d]invalid cb", avsync->session_id);
1355 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001356 }
Song Zhao76005282022-03-08 16:49:41 -08001357 avsync->audio_start = cb;
1358 avsync->audio_start_priv = priv;
1359 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001360
Song Zhaod62bb392021-04-23 12:25:49 -07001361 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001362 int ret;
1363
1364 log_info("[%d]start poll thread", avsync->session_id);
1365 avsync->quit_poll = false;
1366 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1367 if (ret) {
1368 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1369 return AV_SYNC_ASTART_ERR;
1370 }
1371 }
Song Zhaod62bb392021-04-23 12:25:49 -07001372 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001373 msync_session_get_wall(avsync->fd, &systime, NULL);
1374 log_info("[%d]return %u w %u pts %u d %u",
1375 avsync->session_id, ret, systime, pts, delay);
1376 }
1377exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001378 log_info("[%d]return %u", avsync->session_id, ret);
1379 return ret;
1380}
1381
1382int av_sync_audio_render(
1383 void *sync,
1384 pts90K pts,
1385 struct audio_policy *policy)
1386{
1387 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001388 bool out_lier = false;
Song Zhaoad8a0112024-03-26 22:37:23 +00001389 bool send_disc = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001390 uint32_t systime;
1391 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1392 avs_audio_action action = AA_SYNC_AA_MAX;
1393
1394 if (!avsync || !policy)
1395 return -1;
1396
yongchun.li107a6162021-05-05 02:38:57 -07001397 msync_session_get_wall(avsync->fd, &systime, NULL);
Song Zhao5296acf2024-02-02 21:45:04 +00001398 avsync->last_pts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001399
1400 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1401 pts, systime, avsync->mode, (int)(pts-systime)/90);
1402
1403 if (avsync->in_audio_switch
1404 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
Song Zhao4bd18762022-09-30 16:39:52 -07001405 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_MB) {
yongchun.li107a6162021-05-05 02:38:57 -07001406 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1407 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1408 action = AV_SYNC_AA_RENDER;
1409 } else if ((int)(systime - pts) > 0) {
1410 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1411 (int)(systime - pts)/90, systime, pts);
1412 action = AV_SYNC_AA_DROP;
1413 } else {
1414 action = AV_SYNC_AA_INSERT;
1415 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1416 (int)(pts - systime)/90, systime, pts);
1417 }
1418 goto done;
1419 }
1420
Song Zhaoea5a0412021-01-18 16:40:08 -08001421 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1422 avsync->mode == AV_SYNC_MODE_AMASTER) {
1423 action = AV_SYNC_AA_RENDER;
1424 goto done;
1425 }
1426
Song Zhaod62bb392021-04-23 12:25:49 -07001427 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001428 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001429 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1430 action = AV_SYNC_AA_DROP;
1431 goto done;
1432 }
1433
Song Zhao7daf3a12021-05-10 22:22:25 -07001434 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
Song Zhaob8833c12024-02-02 21:54:36 +00001435 avsync->mode == AV_SYNC_MODE_AMASTER ||
1436 avsync->active_mode == AV_SYNC_MODE_AMASTER) {
Song Zhao7daf3a12021-05-10 22:22:25 -07001437 action = AV_SYNC_AA_RENDER;
1438 goto done;
1439 }
1440
Song Zhaoad8a0112024-03-26 22:37:23 +00001441 if (LIVE_MODE(avsync->mode) &&
1442 VALID_TS(avsync->apts) &&
1443 abs_diff(avsync->apts, pts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -07001444 /* outlier by stream error */
1445 avsync->outlier_cnt++;
1446 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
Song Zhaoad8a0112024-03-26 22:37:23 +00001447 /* treat as disc */
1448 send_disc = true;
1449 } else {
1450 log_info("[%d]ignore outlier %u vs %u sys %u", avsync->session_id, pts, avsync->apts, systime);
1451 pts = systime;
1452 action = AV_SYNC_AA_RENDER;
1453 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001454 goto done;
1455 }
Song Zhaod62bb392021-04-23 12:25:49 -07001456 }
1457
Song Zhaod62bb392021-04-23 12:25:49 -07001458 /* low bound from sync_lost to sync_setup */
1459 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
Song Zhaoad8a0112024-03-26 22:37:23 +00001460 avsync->outlier_cnt = 0;
Song Zhaod62bb392021-04-23 12:25:49 -07001461 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1462 action = AV_SYNC_AA_RENDER;
1463 goto done;
1464 }
1465
1466 /* high bound of sync_setup */
1467 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1468 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
Song Zhaoad8a0112024-03-26 22:37:23 +00001469 avsync->outlier_cnt = 0;
Song Zhaod62bb392021-04-23 12:25:49 -07001470 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001471 action = AV_SYNC_AA_RENDER;
1472 goto done;
1473 }
1474
1475 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001476 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001477 action = AV_SYNC_AA_DROP;
1478 goto done;
1479 }
1480
1481 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001482 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001483 action = AV_SYNC_AA_INSERT;
1484 goto done;
1485 }
1486
1487done:
1488 policy->action = action;
1489 policy->delta = (int)(systime - pts);
1490 if (action == AV_SYNC_AA_RENDER) {
Song Zhaoad8a0112024-03-26 22:37:23 +00001491 if (!out_lier)
1492 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001493 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001494 if (!out_lier)
1495 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001496 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001497 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001498 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1499 msync_session_update_apts(avsync->fd, systime, pts, 0);
1500 log_info("[%d] audio switch done sys %u pts %u",
1501 avsync->session_id, systime, pts);
1502 msync_session_set_audio_switch(avsync->fd, false);
1503 avsync->in_audio_switch = false;
1504 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1505 } else {
1506 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1507 avsync->session_id, action, systime, pts, systime - pts);
1508 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001509 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001510 } else {
Song Zhaoad8a0112024-03-26 22:37:23 +00001511 if (!avsync->in_audio_switch && avsync->last_disc_pts != pts &&
1512 (abs_diff(systime, pts) > avsync->disc_thres_min ||
1513 (action == AV_SYNC_AA_INSERT && send_disc))) {
Song Zhao409739b2021-05-12 22:21:40 -07001514 log_info ("[%d]audio disc %u --> %u",
1515 avsync->session_id, systime, pts);
1516 msync_session_set_audio_dis(avsync->fd, pts);
1517 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001518 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001519 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001520
Song Zhaoad8a0112024-03-26 22:37:23 +00001521 avsync->apts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001522 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001523 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001524 if (!avsync->audio_drop_cnt)
1525 avsync->audio_drop_start = now;
1526 avsync->audio_drop_cnt++;
1527 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1528 log_info ("[%d]audio keep dropping sys %u vs a %u",
1529 avsync->session_id, systime, pts);
1530 msync_session_set_audio_dis(avsync->fd, pts);
1531 }
Song Zhao409739b2021-05-12 22:21:40 -07001532 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001533 if (action != AV_SYNC_AA_DROP)
1534 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001535 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001536 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001537 }
1538
1539 return ret;
1540}
1541
Song Zhaof3350d32023-08-18 16:27:31 -07001542int av_sync_get_pos(void *sync, pts90K *pts, uint64_t *mono_clock)
1543{
1544 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1545
1546 if (!avsync || !pts)
1547 return -1;
1548
1549 if (avsync->type != AV_SYNC_TYPE_AUDIO &&
1550 avsync->type != AV_SYNC_TYPE_VIDEO)
1551 return -2;
1552 return msync_session_get_pts(avsync->fd, pts,
1553 mono_clock, avsync->type == AV_SYNC_TYPE_VIDEO);
1554}
1555
Song Zhaoea5a0412021-01-18 16:40:08 -08001556int av_sync_get_clock(void *sync, pts90K *pts)
1557{
1558 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1559
1560 if (!avsync || !pts)
1561 return -1;
1562 return msync_session_get_wall(avsync->fd, pts, NULL);
1563}
1564
1565static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001566 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001567 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001568{
Song Zhao76005282022-03-08 16:49:41 -08001569 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1570 avsync->session_id, avsync->active_mode, avsync->mode,
1571 v_active, a_active, v_timeout, stat);
1572
1573 /* iptv delayed start */
1574 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1575 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1576
Song Zhaoea5a0412021-01-18 16:40:08 -08001577 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1578 float speed;
Song Zhao7e8c68f2022-07-12 16:24:30 -07001579 if (a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001580 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001581 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhao6183ca92022-07-29 09:57:03 -07001582 } else if (!a_active && !avsync->session_started) {
1583 /* quit waiting ASAP */
1584 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoea5a0412021-01-18 16:40:08 -08001585 }
1586
1587 if (!msync_session_get_rate(avsync->fd, &speed)) {
1588 /* speed change is triggered by asink,
1589 * attached audio HAL will handle it
1590 */
1591 if (speed != avsync->speed)
1592 log_info("[%d]new rate %f", avsync->session_id, speed);
Song Zhaoea5a0412021-01-18 16:40:08 -08001593 avsync->speed = speed;
1594 }
Song Zhaoebc92012024-03-12 18:36:44 +00001595 } else if (avsync->mode == AV_SYNC_MODE_PCR_MASTER &&
1596 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1597 /* pcr master stopping procedure */
1598 if (a_active && avsync->audio_start) {
1599 if (v_active || v_timeout) {
1600 log_info("audio start cb");
1601 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1602 }
1603 }
Song Zhaod62bb392021-04-23 12:25:49 -07001604 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1605 struct session_debug debug;
Song Zhao5296acf2024-02-02 21:45:04 +00001606
1607 if (a_active && avsync->audio_start) {
1608 if (v_active || v_timeout) {
1609 log_info("audio start cb");
1610 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1611 }
1612 }
1613
Song Zhaod62bb392021-04-23 12:25:49 -07001614 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001615 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001616 avsync->backup_mode = avsync->mode;
1617 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001618 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001619 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001620 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001621 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001622 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001623 log_warn("[%d]audio back to mode %d",
1624 avsync->session_id, avsync->mode);
1625 }
1626 }
Song Zhao76005282022-03-08 16:49:41 -08001627 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1628 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaob8833c12024-02-02 21:54:36 +00001629 if (a_active && avsync->audio_start) {
1630 if (v_active || v_timeout) {
1631 log_info("audio start cb");
1632 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1633 }
1634 }
1635
Song Zhaoea5a0412021-01-18 16:40:08 -08001636 }
1637}
1638
1639static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001640 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001641 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001642{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001643 struct session_debug debug;
1644
Song Zhao76005282022-03-08 16:49:41 -08001645 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1646 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001647 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1648 if (debug.debug_freerun && !avsync->debug_freerun) {
1649 avsync->backup_mode = avsync->mode;
1650 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1651 avsync->debug_freerun = true;
1652 log_warn("[%d]video to freerun mode", avsync->session_id);
1653 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1654 avsync->mode = avsync->backup_mode;
1655 avsync->debug_freerun = false;
1656 log_warn("[%d]video back to mode %d",
1657 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001658 }
1659 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001660}
1661
1662static void * poll_thread(void * arg)
1663{
1664 int ret = 0;
1665 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1666 const int fd = avsync->fd;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001667 int poll_timeout = 10;
Song Zhaoea5a0412021-01-18 16:40:08 -08001668 struct pollfd pfd = {
1669 /* default blocking capture */
Song Zhao4bd18762022-09-30 16:39:52 -07001670 .events = POLLPRI,
Song Zhaoea5a0412021-01-18 16:40:08 -08001671 .fd = avsync->fd,
1672 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001673 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001674
Song Zhaoea5a0412021-01-18 16:40:08 -08001675 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001676
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001677 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001678 prctl (PR_SET_NAME, "avs_apoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001679 sflag = SRC_A;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001680 } else if (avsync->type == AV_SYNC_TYPE_VIDEO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001681 prctl (PR_SET_NAME, "avs_vpoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001682 sflag = SRC_V;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001683 poll_timeout = 100;
1684 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001685
Song Zhaoea5a0412021-01-18 16:40:08 -08001686 while (!avsync->quit_poll) {
1687 for (;;) {
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001688 ret = poll(&pfd, 1, poll_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001689 if (ret > 0)
1690 break;
1691 if (avsync->quit_poll)
1692 goto exit;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001693 if (errno == EINTR) {
1694 log_debug("[%d] poll interrupted", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001695 continue;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001696 }
Song Zhao4bd18762022-09-30 16:39:52 -07001697 if (errno == EAGAIN || errno == ENOMEM) {
1698 log_info("[%d] poll error %d", avsync->session_id, errno);
1699 continue;
1700 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001701 }
1702
1703 /* error handling */
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001704 if (pfd.revents & POLLERR) {
1705 usleep(poll_timeout * 1000);
1706 continue;
1707 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001708
Song Zhao4bd18762022-09-30 16:39:52 -07001709 if (pfd.revents & POLLNVAL) {
1710 log_warn("[%d] fd closed", avsync->session_id);
1711 goto exit;
1712 }
Song Zhaod62bb392021-04-23 12:25:49 -07001713 /* mode change. Non-exclusive wait so all the processes
1714 * shall be woken up
1715 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001716 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001717 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001718 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001719
Song Zhao9fef59c2022-08-17 12:43:10 -07001720 msync_session_get_stat(fd, true, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001721 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001722
1723 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001724 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001725 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001726 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001727 usleep(10000);
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001728 } else {
1729 log_debug("[%d] unexpected revents %x", avsync->session_id, pfd.revents);
1730 usleep(poll_timeout * 1000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001731 }
1732 }
1733exit:
1734 log_info("[%d]quit", avsync->session_id);
1735 return NULL;
1736}
1737
Song Zhao623e2f12021-09-03 15:54:04 -07001738#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1739/* return ppm between demod and PCR clock */
1740int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1741{
1742 int fd = -1, ppm = 0, nread;
1743 char buf[128];
1744 uint32_t reg_v, lock;
1745 float val;
1746
1747 fd = open(DEMOD_NODE, O_RDWR);
1748 if (fd < 0) {
1749 log_warn("node not found %s", DEMOD_NODE);
1750 /* do not retry */
1751 avsync->ppm_adjusted = true;
1752 return 0;
1753 }
1754 snprintf(buf, sizeof(buf), "%d", 5);
1755 write(fd, buf, 2);
1756
1757 lseek(fd, 0, SEEK_SET);
1758
hanghang.luo02efd312022-08-26 09:49:53 +08001759 nread = read(fd, buf, sizeof(buf)-1);
Song Zhao623e2f12021-09-03 15:54:04 -07001760 if (nread <= 0) {
1761 log_error("read error");
1762 goto err;
1763 }
1764 buf[nread] = 0;
1765 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1766 log_error("wrong format %s", buf);
1767 goto err;
1768 }
1769 if (lock != 0x1f) {
1770 log_info("demod not locked");
1771 goto err;
1772 }
1773 if (reg_v > ((2 << 20) - 1))
1774 reg_v -= (2 << 21);
1775 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1776 ppm = val;
1777 log_info("ppm from SFO %d", ppm);
1778 avsync->ppm_adjusted = true;
1779
1780err:
1781 if (fd >= 0)
1782 close(fd);
1783 return ppm;
1784}
1785
Song Zhaod62bb392021-04-23 12:25:49 -07001786int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001787{
1788 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001789 struct pcr_info pcr;
1790 enum pcr_monitor_status status;
1791 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001792 if (!avsync)
1793 return -1;
1794
1795 if (avsync->type != AV_SYNC_TYPE_PCR)
1796 return -2;
1797
Song Zhao623e2f12021-09-03 15:54:04 -07001798 /* initial estimation from Demod SFO HW */
1799 if (!avsync->ppm_adjusted) {
1800 ppm = dmod_get_sfo_dev(avsync);
1801 if (ppm != 0) {
1802 /* ppm > 0 means board clock is faster */
1803 msync_session_set_clock_dev(avsync->fd, -ppm);
1804 }
1805 }
wei.dubcc2ed22021-05-19 07:16:10 -04001806 pcr.monoclk = mono_clock / 1000;
1807 pcr.pts = (long long) pts * 1000 / 90;
1808 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1809
1810 status = pcr_monitor_get_status(avsync->pcr_monitor);
1811
1812 if (status >= DEVIATION_READY) {
1813 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1814 if (avsync->ppm != ppm) {
1815 avsync->ppm = ppm;
1816 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1817 if (msync_session_set_clock_dev(avsync->fd, ppm))
1818 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001819 else
1820 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001821 }
1822 }
1823
Song Zhaod62bb392021-04-23 12:25:49 -07001824 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001825}
1826
Song Zhaod62bb392021-04-23 12:25:49 -07001827int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001828{
1829 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1830
1831 if (!avsync)
1832 return -1;
1833
Song Zhaod62bb392021-04-23 12:25:49 -07001834 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001835}
1836
1837int av_sync_set_session_name(void *sync, const char *name)
1838{
1839 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1840
1841 if (!avsync)
1842 return -1;
1843
1844 return msync_session_set_name(avsync->fd, name);
1845}
yongchun.li107a6162021-05-05 02:38:57 -07001846
1847int av_sync_set_audio_switch(void *sync, bool start)
1848{
1849 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1850 bool v_active, a_active, v_timeout;
1851
1852 if (!avsync)
1853 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001854 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001855 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001856 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001857 log_error("[%d] can not get session state",
1858 avsync->session_id);
1859 return -1;
1860 }
1861 if (!v_active || !a_active) {
1862 log_error("[%d] no apply if not AV both active v %d a %d",
1863 avsync->session_id, v_active, a_active);
1864 return -1;
1865 }
1866 if (msync_session_set_audio_switch(avsync->fd, start)) {
1867 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1868 return -1;
1869 }
1870 avsync->in_audio_switch = start;
1871 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1872 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1873 return 0;
1874}
1875
1876int av_sync_get_audio_switch(void *sync, bool *start)
1877{
1878 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1879
1880 if (!avsync)
1881 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001882 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001883 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001884 log_error("[%d] can not audio seamless switch state",
1885 avsync->session_id);
1886 return -1;
1887 }
1888 if (start) *start = avsync->in_audio_switch;
1889 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001890}
Song Zhao8039f562021-05-18 18:11:25 -07001891
Song Zhao623e2f12021-09-03 15:54:04 -07001892enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001893{
1894 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1895
wei.dubcc2ed22021-05-19 07:16:10 -04001896 if (!avsync || !ppm)
1897 return CLK_RECOVERY_ERR;
1898 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001899 return CLK_RECOVERY_NOT_RUNNING;
1900
wei.dubcc2ed22021-05-19 07:16:10 -04001901 if (msync_session_get_clock_dev(avsync->fd, ppm))
1902 return CLK_RECOVERY_ERR;
1903
1904 if (*ppm == 0)
1905 return CLK_RECOVERY_ONGOING;
1906 else
1907 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001908}
Song Zhao95bd0922021-09-21 14:07:46 -07001909
1910static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1911{
1912 int ret;
1913
1914 if (!avsync->frame_q) {
1915 avsync->frame_q = create_q(MAX_FRAME_NUM);
1916 if (!avsync->frame_q) {
1917 log_error("[%d]create queue fail", avsync->session_id);
1918
1919 return -1;
1920 }
1921 }
1922
1923 ret = queue_item(avsync->frame_q, frame);
1924 if (ret)
hanghang.luo02efd312022-08-26 09:49:53 +08001925 log_error("queue fail:%d", ret);
Song Zhao95bd0922021-09-21 14:07:46 -07001926 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1927 return ret;
1928}
1929
1930int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1931{
1932 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1933
1934 if (!avsync)
1935 return -1;
1936 avsync->msys = msys;
1937 return 0;
1938}
1939
1940static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1941{
1942 struct vframe *frame = NULL, *enter_last_frame = NULL;
1943 uint64_t systime;
1944 int toggle_cnt = 0;
1945
1946 enter_last_frame = avsync->last_frame;
1947 systime = avsync->msys;
1948 log_debug("[%d]sys %llu", avsync->session_id, systime);
1949 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1950 if (systime >= frame->mts) {
1951 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1952 toggle_cnt++;
1953
1954 if (avsync->last_frame)
1955 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1956
1957 dqueue_item(avsync->frame_q, (void **)&frame);
1958 if (avsync->last_frame) {
1959 /* free frame that are not for display */
1960 if (toggle_cnt > 1) {
1961 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1962 avsync->last_frame->mts, frame->mts, systime);
1963 avsync->last_frame->free(avsync->last_frame);
1964 }
1965 } else {
1966 avsync->first_frame_toggled = true;
1967 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1968 }
1969 avsync->last_frame = frame;
1970 } else
1971 break;
1972 }
1973
1974 if (avsync->last_frame) {
1975 if (enter_last_frame != avsync->last_frame)
hanghang.luo02efd312022-08-26 09:49:53 +08001976 log_debug("[%d]pop %lu", avsync->session_id, avsync->last_frame->pts);
1977 log_trace("[%d]pop=%llu, system=%llu, diff %llu(ms), QNum=%d", avsync->session_id,
Song Zhao95bd0922021-09-21 14:07:46 -07001978 avsync->last_frame->mts,
1979 systime, (systime - avsync->last_frame->mts) / 1000000,
1980 queue_size(avsync->frame_q));
1981 } else
1982 if (enter_last_frame != avsync->last_frame)
1983 log_debug("[%d]pop (nil)", avsync->session_id);
1984
1985 if (avsync->last_frame)
1986 avsync->last_frame->hold_period++;
1987 return avsync->last_frame;
1988}
Song Zhao6183ca92022-07-29 09:57:03 -07001989
1990int avs_sync_stop_audio(void *sync)
1991{
1992 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1993
1994 if (!avsync)
1995 return -1;
1996
1997 return msync_session_stop_audio(avsync->fd);
1998}
bo.xiao05ba1ac2022-12-13 14:38:13 +08001999
2000int avs_sync_set_eos(void *sync)
2001{
2002 struct av_sync_session *avsync = (struct av_sync_session *)sync;
2003
2004 if (!avsync)
2005 return -1;
2006
2007 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
2008 if (avsync->state == AV_SYNC_STAT_INIT) {
2009 avsync->state = AV_SYNC_STAT_RUNNING;
2010 log_debug("[%d]eos trigger state change: init --> running", avsync->session_id);
2011 }
2012 }
2013
2014 return 0;
2015}