blob: d0b8fa527f4e82c125c78a2e049050adbdc8f580 [file] [log] [blame]
Song Zhaoc03ba122020-12-23 21:54:02 -08001/*
bo.xiao00387eb2023-02-24 18:44:29 +08002 * Copyright (C) 2021 Amlogic Corporation.
Song Zhaoc03ba122020-12-23 21:54:02 -08003 *
bo.xiao00387eb2023-02-24 18:44:29 +08004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Song Zhaoc03ba122020-12-23 21:54:02 -08007 *
bo.xiao00387eb2023-02-24 18:44:29 +08008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Song Zhaoc03ba122020-12-23 21:54:02 -080015 */
Song Zhaoea5a0412021-01-18 16:40:08 -080016#include <errno.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080017#include <pthread.h>
18#include <stdbool.h>
19#include <stdlib.h>
20#include <stdio.h>
21#include <sys/time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080022#include <poll.h>
23#include <fcntl.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <sys/prctl.h>
27#include <sys/ioctl.h>
Song Zhaoa2985cb2021-06-24 12:01:47 -070028#include <time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080029#include <unistd.h>
30//#include <linux/amlogic/msync.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080031#include "aml_avsync.h"
Song Zhao4f632952021-12-16 09:00:18 -080032#include "aml_queue.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080033#include "pattern.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080034#include "aml_avsync_log.h"
Song Zhaoea5a0412021-01-18 16:40:08 -080035#include "msync_util.h"
36#include "msync.h"
37#include <pthread.h>
wei.dubcc2ed22021-05-19 07:16:10 -040038#include "pcr_monitor.h"
fei.deng66b4e812022-04-14 12:23:01 +080039#include "aml_version.h"
Song Zhao2f6744b2021-11-03 21:23:50 -070040
Song Zhaoc03ba122020-12-23 21:54:02 -080041enum sync_state {
42 AV_SYNC_STAT_INIT = 0,
43 AV_SYNC_STAT_RUNNING = 1,
44 AV_SYNC_STAT_SYNC_SETUP = 2,
45 AV_SYNC_STAT_SYNC_LOST = 3,
46};
47
yongchun.li107a6162021-05-05 02:38:57 -070048enum audio_switch_state_ {
49 AUDIO_SWITCH_STAT_INIT = 0,
50 AUDIO_SWITCH_STAT_RESET = 1,
51 AUDIO_SWITCH_STAT_START = 2,
52 AUDIO_SWITCH_STAT_FINISH = 3,
yongchun.li59e873d2021-07-07 11:42:38 -070053 AUDIO_SWITCH_STAT_AGAIN = 4,
yongchun.li107a6162021-05-05 02:38:57 -070054};
55
Song Zhaoea5a0412021-01-18 16:40:08 -080056#define SESSION_DEV "avsync_s"
57
Song Zhaoc03ba122020-12-23 21:54:02 -080058struct av_sync_session {
59 /* session id attached */
60 int session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -080061 int fd;
62 bool attached;
63 enum sync_mode mode;
64 /* for audio trickplay */
65 enum sync_mode backup_mode;
66 enum sync_type type;
67 uint32_t start_policy;
bo.xiao5821fc72021-07-11 22:47:00 -040068 int timeout;
Song Zhaoc03ba122020-12-23 21:54:02 -080069
Song Zhaoea5a0412021-01-18 16:40:08 -080070 /* playback time, will stop increasing during pause */
71 pts90K vpts;
72 pts90K apts;
73
74 /* phase adjustment of stream time for rate control (Video ONLY) */
Song Zhaoc03ba122020-12-23 21:54:02 -080075 pts90K phase;
76 bool phase_set;
Song Zhao1561e542022-01-12 10:37:55 -080077 bool phase_adjusted;
Song Zhaoc03ba122020-12-23 21:54:02 -080078
79 /* pts of last rendered frame */
Song Zhaoea5a0412021-01-18 16:40:08 -080080 pts90K last_wall;
Song Zhaoc03ba122020-12-23 21:54:02 -080081 pts90K last_pts;
82 struct vframe *last_frame;
83
Song Zhaoe0bf6ad2021-07-09 11:28:42 -070084 /* pts of last pushed frame */
85 pts90K last_q_pts;
86
Song Zhaoc03ba122020-12-23 21:54:02 -080087 bool first_frame_toggled;
Song Zhaoc03ba122020-12-23 21:54:02 -080088 bool paused;
Song Zhaoea5a0412021-01-18 16:40:08 -080089 enum sync_state state;
Song Zhaoc03ba122020-12-23 21:54:02 -080090 void *pattern_detector;
91 void *frame_q;
Song Zhaoc03ba122020-12-23 21:54:02 -080092
Song Zhaoea5a0412021-01-18 16:40:08 -080093 /* start control */
94 int start_thres;
95 audio_start_cb audio_start;
96 void *audio_start_priv;
97
98 /* render property */
Song Zhaoc03ba122020-12-23 21:54:02 -080099 int delay;
Song Zhao6dce2672022-01-13 11:32:44 -0800100 int extra_delay;
Song Zhaoc03ba122020-12-23 21:54:02 -0800101 pts90K vsync_interval;
102
103 /* state lock */
104 pthread_mutex_t lock;
105 /* pattern */
106 int last_holding_peroid;
Song Zhaoea5a0412021-01-18 16:40:08 -0800107 bool session_started;
Song Zhaoc03ba122020-12-23 21:54:02 -0800108
109 float speed;
110
Song Zhaoc03ba122020-12-23 21:54:02 -0800111 /* pause pts */
112 pts90K pause_pts;
113 pause_pts_done pause_pts_cb;
114 void *pause_cb_priv;
yongchun.li428390d2022-02-17 17:15:40 -0800115 /* underflow */
116 underflow_detected underflow_cb;
117 void *underflow_cb_priv;
118 struct underflow_config underflow_cfg;
119 struct timespec frame_last_update_time;
Song Zhao5d2b4772021-01-18 16:40:08 -0800120
121 /* log control */
Song Zhaoa2985cb2021-06-24 12:01:47 -0700122 uint32_t last_log_syst;
Song Zhao5d2b4772021-01-18 16:40:08 -0800123 uint32_t sync_lost_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700124 struct timespec sync_lost_print_time;
Song Zhaoea5a0412021-01-18 16:40:08 -0800125
126 pthread_t poll_thread;
127 /* pcr master, IPTV only */
128 bool quit_poll;
129 enum sync_mode active_mode;
Song Zhaof46932e2021-05-21 01:51:45 -0700130 uint32_t disc_thres_min;
131 uint32_t disc_thres_max;
Song Zhao35a82df2021-04-15 10:58:49 -0700132
133 /* error detection */
134 uint32_t last_poptime;
Song Zhaod62bb392021-04-23 12:25:49 -0700135 uint32_t outlier_cnt;
Song Zhao409739b2021-05-12 22:21:40 -0700136 pts90K last_disc_pts;
137
yongchun.li107a6162021-05-05 02:38:57 -0700138 // indicate set audio switch
139 bool in_audio_switch;
140 enum audio_switch_state_ audio_switch_state;
wei.dubcc2ed22021-05-19 07:16:10 -0400141
142 //pcr monitor handle
143 void *pcr_monitor;
144 int ppm;
Song Zhao623e2f12021-09-03 15:54:04 -0700145 bool ppm_adjusted;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700146
147 //video FPS detection
148 pts90K last_fpts;
149 int fps_interval;
150 int fps_interval_acc;
151 int fps_cnt;
152
153 //video freerun with rate control
154 uint32_t last_r_syst;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700155 bool debug_freerun;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700156
157 //Audio dropping detection
158 uint32_t audio_drop_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700159 struct timespec audio_drop_start;
Song Zhao95bd0922021-09-21 14:07:46 -0700160
161 /*system mono time for current vsync interrupt */
162 uint64_t msys;
Song Zhaoc03ba122020-12-23 21:54:02 -0800163};
164
165#define MAX_FRAME_NUM 32
166#define DEFAULT_START_THRESHOLD 2
167#define TIME_UNIT90K (90000)
Song Zhaoa73fcf32023-01-13 08:12:26 -0800168#define DEFAULT_WALL_ADJ_THRES (TIME_UNIT90K / 10) //100ms
Song Zhaof46932e2021-05-21 01:51:45 -0700169#define AV_DISC_THRES_MIN (TIME_UNIT90K / 3)
170#define AV_DISC_THRES_MAX (TIME_UNIT90K * 10)
Song Zhao7daf3a12021-05-10 22:22:25 -0700171#define A_ADJ_THREDHOLD_HB (900 * 6) //60ms
172#define A_ADJ_THREDHOLD_LB (900 * 2) //20ms
Song Zhao4bd18762022-09-30 16:39:52 -0700173#define A_ADJ_THREDHOLD_MB (900 * 3) //30ms
Song Zhao52f55192021-05-06 10:52:21 -0700174#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800175#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhao76005282022-03-08 16:49:41 -0800176#define LIVE_MODE(m) ((m) == AV_SYNC_MODE_PCR_MASTER || (m) == AV_SYNC_MODE_IPTV)
Song Zhao7e24b182022-04-01 08:46:40 -0700177#define V_DISC_MODE(mode) (LIVE_MODE(mode) || (mode) == AV_SYNC_MODE_VMASTER)
Song Zhaod62bb392021-04-23 12:25:49 -0700178
Song Zhao065800e2021-05-26 15:56:06 -0700179#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
Song Zhaod62bb392021-04-23 12:25:49 -0700180#define OUTLIER_MAX_CNT 8
Song Zhaoa2985cb2021-06-24 12:01:47 -0700181#define VALID_TS(x) ((x) != -1)
yongchun.li428390d2022-02-17 17:15:40 -0800182#define UNDERFLOW_CHECK_THRESH_MS (100)
Song Zhaoc03ba122020-12-23 21:54:02 -0800183
yongchun.li0ee6e372021-08-20 04:26:04 -0700184static uint64_t time_diff (struct timespec *b, struct timespec *a);
Song Zhaoc03ba122020-12-23 21:54:02 -0800185static bool frame_expire(struct av_sync_session* avsync,
186 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800187 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800188 struct vframe * frame,
189 struct vframe * next_frame,
190 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700191static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800192 int cur_period,
193 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800194static void * poll_thread(void * arg);
195static void trigger_audio_start_cb(struct av_sync_session *avsync,
196 avs_ascb_reason reason);
Song Zhao95bd0922021-09-21 14:07:46 -0700197static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync);
198static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame);
fei.deng55389b62022-08-18 23:46:50 +0800199
Song Zhao2f6744b2021-11-03 21:23:50 -0700200pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER;
Song Zhaoc03ba122020-12-23 21:54:02 -0800201
Song Zhaoea5a0412021-01-18 16:40:08 -0800202int av_sync_open_session(int *session_id)
203{
Song Zhao2f6744b2021-11-03 21:23:50 -0700204 int fd = -1;
Song Zhaoea5a0412021-01-18 16:40:08 -0800205 int id, rc;
206
Song Zhao2f6744b2021-11-03 21:23:50 -0700207 pthread_mutex_lock(&glock);
208 fd = msync_create_session();
Song Zhaoea5a0412021-01-18 16:40:08 -0800209 if (fd < 0) {
210 log_error("fail");
Song Zhao2f6744b2021-11-03 21:23:50 -0700211 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800212 }
213 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
214 if (rc) {
215 log_error("new session errno:%d", errno);
Song Zhao2f6744b2021-11-03 21:23:50 -0700216 msync_destory_session(fd);
217 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800218 }
219 *session_id = id;
Song Zhao2f6744b2021-11-03 21:23:50 -0700220 log_debug("new avsession id %d fd %d", id, fd);
221exit:
222 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800223 return fd;
224}
225
226void av_sync_close_session(int session)
227{
Song Zhao2f6744b2021-11-03 21:23:50 -0700228 log_debug("session closed fd %d", session);
229 pthread_mutex_lock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800230 msync_destory_session(session);
Song Zhao2f6744b2021-11-03 21:23:50 -0700231 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800232}
233
234static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800235 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800236 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800237 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800238 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800239{
240 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800241 char dev_name[20];
Song Zhao2f6744b2021-11-03 21:23:50 -0700242 int retry = 10;
Song Zhaoc03ba122020-12-23 21:54:02 -0800243
fei.deng55389b62022-08-18 23:46:50 +0800244 /* debug log level */
245 {
246 const char *env= getenv( "AML_AVSYNC_DEBUG_LEVEL");
247 if ( env ) {
248 log_set_level(atoi(env));
249 }
250 }
251
Song Zhao95bd0922021-09-21 14:07:46 -0700252 log_info("[%d] mode %d type %d", session_id, mode, type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800253 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
254 if (!avsync) {
255 log_error("OOM");
256 return NULL;
257 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800258
Song Zhao95bd0922021-09-21 14:07:46 -0700259 if (type == AV_SYNC_TYPE_VIDEO &&
260 mode == AV_SYNC_MODE_VIDEO_MONO) {
261 if (session_id < AV_SYNC_SESSION_V_MONO) {
262 log_error("wrong session id %d", session_id);
263 goto err;
264 }
265 avsync->type = type;
266 avsync->mode = mode;
267 avsync->fd = -1;
268 avsync->session_id = session_id;
269 log_info("[%d]init", avsync->session_id);
270 return avsync;
271 }
272
Song Zhaoea5a0412021-01-18 16:40:08 -0800273 if (type == AV_SYNC_TYPE_VIDEO) {
Song Zhaobb3b4f32023-10-17 16:08:12 -0700274 int32_t interval = 1500;
275
276 if (msync_session_get_vsync_interval(&interval))
277 log_error("read interval error");
278 avsync->pattern_detector = create_pattern_detector(interval);
Song Zhaoea5a0412021-01-18 16:40:08 -0800279 if (!avsync->pattern_detector) {
280 log_error("pd create fail");
281 goto err;
282 }
283
284 if (!start_thres)
285 avsync->start_thres = DEFAULT_START_THRESHOLD;
286 else {
287 if (start_thres > 5) {
288 log_error("start_thres too big: %d", start_thres);
289 goto err2;
290 }
291 avsync->start_thres = start_thres;
292 }
293 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800294 avsync->phase_adjusted = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800295 avsync->first_frame_toggled = false;
Song Zhaofd007632022-09-30 16:21:30 -0700296
297 avsync->frame_q = create_q(MAX_FRAME_NUM);
298 if (!avsync->frame_q) {
299 log_error("[%d]create queue fail", avsync->session_id);
300 goto err2;
301 }
Song Zhaofd007632022-09-30 16:21:30 -0700302 {
303 int ret;
304
305 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
306 if (ret) {
307 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
308 goto err2;
309 }
310 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800311 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800312
313 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800314 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800315 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800316 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800317 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800318 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800319 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800320 avsync->speed = 1.0f;
321 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhao409739b2021-05-12 22:21:40 -0700322 avsync->vsync_interval = -1;
323 avsync->last_disc_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700324 avsync->last_log_syst = -1;
325 avsync->last_pts = -1;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700326 avsync->last_q_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700327 avsync->last_wall = -1;
328 avsync->fps_interval = -1;
329 avsync->last_r_syst = -1;
bo.xiao5821fc72021-07-11 22:47:00 -0400330 avsync->timeout = -1;
331
Song Zhaof46932e2021-05-21 01:51:45 -0700332 if (msync_session_get_disc_thres(session_id,
333 &avsync->disc_thres_min, &avsync->disc_thres_max)) {
hanghang.luo02efd312022-08-26 09:49:53 +0800334 log_error("dev_name:%s; errno:%d; fail to get disc thres", dev_name, errno);
Song Zhaof46932e2021-05-21 01:51:45 -0700335 avsync->disc_thres_min = AV_DISC_THRES_MIN;
336 avsync->disc_thres_max = AV_DISC_THRES_MAX;
337 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800338
339 pthread_mutex_init(&avsync->lock, NULL);
Song Zhao9c09f772022-01-07 14:26:50 -0800340 log_info("[%d] start_thres %d disc_thres %u/%u", session_id,
Song Zhao95bd0922021-09-21 14:07:46 -0700341 start_thres, avsync->disc_thres_min, avsync->disc_thres_max);
Song Zhaoea5a0412021-01-18 16:40:08 -0800342
343 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
Song Zhao2f6744b2021-11-03 21:23:50 -0700344 while (retry) {
345 /* wait for sysfs to update */
346 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
347 if (avsync->fd > 0)
348 break;
349
350 retry--;
351 if (!retry) {
352 log_error("open %s errno %d", dev_name, errno);
353 goto err2;
354 }
355 usleep(20000);
Song Zhaoea5a0412021-01-18 16:40:08 -0800356 }
357
wei.dubcc2ed22021-05-19 07:16:10 -0400358 if (avsync->type == AV_SYNC_TYPE_PCR) {
359 if (pcr_monitor_init(&avsync->pcr_monitor)) {
360 log_error("pcr monitor init");
Song Zhao9cd27a52021-07-26 15:27:38 +0000361 goto err3;
wei.dubcc2ed22021-05-19 07:16:10 -0400362 }
363 }
364
Song Zhaoea5a0412021-01-18 16:40:08 -0800365 if (!attach) {
366 msync_session_set_mode(avsync->fd, mode);
367 avsync->mode = mode;
Song Zhaob8833c12024-02-02 21:54:36 +0000368 if ((avsync->mode == AV_SYNC_MODE_VMASTER ||
369 avsync->mode == AV_SYNC_MODE_IPTV) &&
370 avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao7e24b182022-04-01 08:46:40 -0700371 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -0800372 } else {
373 avsync->attached = true;
374 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
375 log_error("get mode");
Song Zhao9cd27a52021-07-26 15:27:38 +0000376 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800377 }
378 avsync->backup_mode = avsync->mode;
bo.xiao5821fc72021-07-11 22:47:00 -0400379 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800380 log_error("get policy");
Song Zhao9cd27a52021-07-26 15:27:38 +0000381 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800382 }
Song Zhao9fef59c2022-08-17 12:43:10 -0700383 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700384 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -0700385 log_error("get state");
Song Zhao9cd27a52021-07-26 15:27:38 +0000386 goto err4;
yongchun.li107a6162021-05-05 02:38:57 -0700387 }
388 if (avsync->in_audio_switch) {
389 log_info("audio_switch_state reseted the audio");
390 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
391 }
392
Song Zhaoea5a0412021-01-18 16:40:08 -0800393 log_info("[%d]retrieve sync mode %d policy %d",
394 session_id, avsync->mode, avsync->start_policy);
395 }
396
Song Zhaoc03ba122020-12-23 21:54:02 -0800397 return avsync;
Song Zhao9cd27a52021-07-26 15:27:38 +0000398err4:
wei.dubcc2ed22021-05-19 07:16:10 -0400399 if (avsync->pcr_monitor)
400 pcr_monitor_destroy(avsync->pcr_monitor);
Song Zhao9cd27a52021-07-26 15:27:38 +0000401err3:
Song Zhaofd007632022-09-30 16:21:30 -0700402 if (avsync->fd)
403 close(avsync->fd);
Song Zhaoea5a0412021-01-18 16:40:08 -0800404err2:
Song Zhaofd007632022-09-30 16:21:30 -0700405 avsync->quit_poll = true;
406 if (avsync->poll_thread) {
407 pthread_join(avsync->poll_thread, NULL);
408 avsync->poll_thread = 0;
409 }
410 if (avsync->frame_q)
411 destroy_q(avsync->frame_q);
412 if (avsync->pattern_detector)
413 destroy_pattern_detector(avsync->pattern_detector);
Song Zhaoea5a0412021-01-18 16:40:08 -0800414err:
415 free(avsync);
416 return NULL;
417}
418
419void* av_sync_create(int session_id,
420 enum sync_mode mode,
421 enum sync_type type,
422 int start_thres)
423{
424 return create_internal(session_id, mode,
425 type, start_thres, false);
426}
427
428void* av_sync_attach(int session_id, enum sync_type type)
429{
Song Zhao95bd0922021-09-21 14:07:46 -0700430 if (type == AV_SYNC_TYPE_VIDEO)
431 return NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800432 return create_internal(session_id, AV_SYNC_MODE_MAX,
433 type, 0, true);
434}
435
436int av_sync_video_config(void *sync, struct video_config* config)
437{
438 struct av_sync_session *avsync = (struct av_sync_session *)sync;
439
440 if (!avsync || !config)
441 return -1;
442
443 if (config->delay != 1 && config->delay != 2) {
444 log_error("invalid delay: %d\n", config->delay);
445 return -1;
446 }
447
448 avsync->delay = config->delay;
Song Zhao6dce2672022-01-13 11:32:44 -0800449 avsync->extra_delay = config->extra_delay * 90;
Song Zhaoea5a0412021-01-18 16:40:08 -0800450
Song Zhao6dce2672022-01-13 11:32:44 -0800451 log_info("[%d] vsync delay: %d extra_delay: %d ms",
452 avsync->session_id, config->delay, config->extra_delay);
Song Zhaoea5a0412021-01-18 16:40:08 -0800453 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800454}
455
456static int internal_stop(struct av_sync_session *avsync)
457{
458 int ret = 0;
459 struct vframe *frame;
460
461 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800462 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
463 frame->free(frame);
464 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800465 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800466 pthread_mutex_unlock(&avsync->lock);
467 return ret;
468}
469
470/* destroy and detach from kernel session */
471void av_sync_destroy(void *sync)
472{
473 struct av_sync_session *avsync = (struct av_sync_session *)sync;
474
475 if (!avsync)
476 return;
477
Song Zhao95bd0922021-09-21 14:07:46 -0700478 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
479 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
480 log_info("[%d]done", avsync->session_id);
481 internal_stop(avsync);
482 destroy_q(avsync->frame_q);
483 free(avsync);
484 return;
485 }
Song Zhaob5458b32021-11-12 15:58:47 -0800486 log_info("[%d]begin type %d", avsync->session_id, avsync->type);
Song Zhao6be9ac22022-09-30 16:44:50 -0700487 if (avsync->type == AV_SYNC_TYPE_VIDEO)
488 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800489
Song Zhao6be9ac22022-09-30 16:44:50 -0700490 avsync->quit_poll = true;
491 if (avsync->poll_thread) {
492 pthread_join(avsync->poll_thread, NULL);
493 avsync->poll_thread = 0;
Song Zhaoaf368d52021-02-17 17:53:45 -0800494 }
Song Zhao6be9ac22022-09-30 16:44:50 -0700495 if (avsync->type == AV_SYNC_TYPE_AUDIO)
496 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoc03ba122020-12-23 21:54:02 -0800497
Song Zhaoea5a0412021-01-18 16:40:08 -0800498 if (avsync->session_started) {
499 if (avsync->type == AV_SYNC_TYPE_VIDEO)
500 msync_session_set_video_stop(avsync->fd);
501 else
502 msync_session_set_audio_stop(avsync->fd);
503 }
wei.dubcc2ed22021-05-19 07:16:10 -0400504
505 if(avsync->pcr_monitor)
506 pcr_monitor_destroy(avsync->pcr_monitor);
507
Song Zhaoea5a0412021-01-18 16:40:08 -0800508 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800509 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800510 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
511 destroy_q(avsync->frame_q);
512 destroy_pattern_detector(avsync->pattern_detector);
513 }
Song Zhaob5458b32021-11-12 15:58:47 -0800514 log_info("[%d]done type %d", avsync->session_id, avsync->type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800515 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800516}
517
bo.xiao5821fc72021-07-11 22:47:00 -0400518int avs_sync_set_start_policy(void *sync, struct start_policy* st_policy)
Song Zhaoea5a0412021-01-18 16:40:08 -0800519{
520 struct av_sync_session *avsync = (struct av_sync_session *)sync;
521
522 if (!avsync || !avsync->fd)
523 return -1;
524
Song Zhao47961d72022-08-29 14:04:44 -0700525 log_info("[%d]policy %u --> %u, timeout %d --> %d", avsync->session_id,
526 avsync->start_policy, st_policy->policy, avsync->timeout, st_policy->timeout);
Song Zhaof4e3c862022-09-01 14:00:11 -0700527 if (avsync->mode == AV_SYNC_MODE_IPTV &&
Song Zhao76005282022-03-08 16:49:41 -0800528 st_policy->policy != AV_SYNC_START_ASAP) {
529 log_error("policy %d not supported in live mode", st_policy->policy);
530 return -1;
531 }
532
Song Zhaof4e3c862022-09-01 14:00:11 -0700533 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
534 msync_session_set_start_thres(avsync->fd, st_policy->timeout);
535
bo.xiao5821fc72021-07-11 22:47:00 -0400536 avsync->start_policy = st_policy->policy;
537 avsync->timeout = st_policy->timeout;
Song Zhao76005282022-03-08 16:49:41 -0800538
Song Zhaoea5a0412021-01-18 16:40:08 -0800539 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400540 if (st_policy->policy != AV_SYNC_START_NONE &&
541 st_policy->policy != AV_SYNC_START_V_PEEK)
542 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800543
544 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800545}
546
547int av_sync_pause(void *sync, bool pause)
548{
549 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700550 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800551 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800552
Song Zhaob5458b32021-11-12 15:58:47 -0800553 if (!avsync) {
554 log_error("invalid handle");
Song Zhaoc03ba122020-12-23 21:54:02 -0800555 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800556 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800557
fei.deng55389b62022-08-18 23:46:50 +0800558 if (avsync->type == AV_SYNC_TYPE_VIDEO && avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
559 log_warn("ignore pause in video mono mode");
560 return -1;
561 }
562
Song Zhaob5458b32021-11-12 15:58:47 -0800563 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
564 log_warn("ignore pause in pcr master mode");
Song Zhaoea5a0412021-01-18 16:40:08 -0800565 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800566 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800567
Song Zhao9fef59c2022-08-17 12:43:10 -0700568 rc = msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -0700569 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700570 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700571
yongchun.li5f52fb02021-06-04 18:13:05 -0700572 /* ignore only when video try to pause when audio is acive, on which
573 the control of the STC will be relays.
574 When resume,it can do always as it is possible that video just
575 paused earlier without audio yet,then audio added later before resume.
576 We shall not igore that otherwise it could cause video freeze. */
577 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
578 avsync->type == AV_SYNC_TYPE_VIDEO &&
579 a_active &&
580 !avsync->in_audio_switch) {
581 if (!pause) {
582 log_info("[%d] clear video pause when audio active",
583 avsync->session_id);
584 avsync->paused = pause;
585 } else {
586 log_info("[%d] ignore the pause from video when audio active",
587 avsync->session_id);
588 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800589 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700590 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800591
yongchun.li107a6162021-05-05 02:38:57 -0700592 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
593 log_info("[%d] ignore the pause from audio", avsync->session_id);
594 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
595 return 0;
596 }
597
Song Zhaoea5a0412021-01-18 16:40:08 -0800598 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800599 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800600 log_info("[%d]paused:%d type:%d rc %d",
601 avsync->session_id, pause, avsync->type, rc);
yongchun.li428390d2022-02-17 17:15:40 -0800602 if (!avsync->paused && avsync->first_frame_toggled) {
603 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
604 log_info("[%d] resume update new frame time", avsync->session_id);
605 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800606 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800607}
608
609int av_sync_push_frame(void *sync , struct vframe *frame)
610{
611 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700612 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800613 struct av_sync_session *avsync = (struct av_sync_session *)sync;
614
615 if (!avsync)
616 return -1;
617
Song Zhao95bd0922021-09-21 14:07:46 -0700618 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
fei.deng55389b62022-08-18 23:46:50 +0800619 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
Song Zhao95bd0922021-09-21 14:07:46 -0700620 return video_mono_push_frame(avsync, frame);
fei.deng55389b62022-08-18 23:46:50 +0800621 }
Song Zhao95bd0922021-09-21 14:07:46 -0700622
Song Zhaofd007632022-09-30 16:21:30 -0700623 if (avsync->state == AV_SYNC_STAT_INIT && !queue_size(avsync->frame_q)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800624 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400625 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800626 log_error("[%d]get policy", avsync->session_id);
627 return -1;
628 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800629 }
630
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700631 if (avsync->last_q_pts != -1) {
Song Zhao7e24b182022-04-01 08:46:40 -0700632 if (frame->pts != -1 && avsync->mode == AV_SYNC_MODE_VMASTER) {
633 /* Sometimes app will fake PTS for trickplay, video PTS gap
634 * is really big depending on the speed. Have to adjust the
635 * threshold dynamically.
636 */
637 int gap = (int)(frame->pts - avsync->last_q_pts);
638 if (gap > avsync->disc_thres_min) {
639 avsync->disc_thres_min = gap * 6;
640 avsync->disc_thres_max = gap * 20;
641 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
642 msync_session_set_disc_thres(avsync->session_id,
643 avsync->disc_thres_min, avsync->disc_thres_max);
644 log_info("[%d] update disc_thres to %d/%d",avsync->session_id,
645 avsync->disc_thres_min, avsync->disc_thres_max);
646 }
647 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700648 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
649 /* TODO: wrong, should remove from back of queue */
le.hanebaea1e2023-07-10 07:26:09 +0000650 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800651 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700652 if (prev) {
653 prev->free(prev);
654 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
655 }
le.hanebaea1e2023-07-10 07:26:09 +0000656 pthread_mutex_unlock(&avsync->lock);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700657 } else if (avsync->fps_cnt < 100) {
658 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700659
660 if (interval > 0 && interval <= 4500) {
661 if (avsync->fps_interval_acc == -1) {
662 avsync->fps_interval_acc = interval;
663 avsync->fps_cnt = 1;
664 } else {
665 avsync->fps_interval_acc += interval;
666 avsync->fps_cnt++;
667 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
668 if (avsync->fps_cnt == 100)
669 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
670 }
671 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800672 }
673 }
674
Song Zhao065800e2021-05-26 15:56:06 -0700675 if (frame->duration == -1)
676 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800677 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700678 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800679 ret = queue_item(avsync->frame_q, frame);
680 if (avsync->state == AV_SYNC_STAT_INIT &&
681 queue_size(avsync->frame_q) >= avsync->start_thres) {
682 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaofd007632022-09-30 16:21:30 -0700683 log_debug("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800684 }
685
686 if (ret)
Song Zhaoe1b65602022-01-06 08:03:46 -0800687 log_error("queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400688 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800689 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800690}
691
692struct vframe *av_sync_pop_frame(void *sync)
693{
Song Zhaoea5a0412021-01-18 16:40:08 -0800694 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800695 struct av_sync_session *avsync = (struct av_sync_session *)sync;
696 int toggle_cnt = 0;
hanghang.luo02efd312022-08-26 09:49:53 +0800697 uint32_t systime = 0;
Song Zhao468fd652021-01-15 22:13:04 -0800698 bool pause_pts_reached = false;
hanghang.luo02efd312022-08-26 09:49:53 +0800699 uint32_t interval = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800700
Song Zhao95bd0922021-09-21 14:07:46 -0700701 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
702 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
703 return video_mono_pop_frame(avsync);
704
Song Zhaoc03ba122020-12-23 21:54:02 -0800705 pthread_mutex_lock(&avsync->lock);
706 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhao2f6744b2021-11-03 21:23:50 -0700707 log_debug("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800708 goto exit;
709 }
710
Song Zhaoea5a0412021-01-18 16:40:08 -0800711 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700712 uint32_t pts;
713
Song Zhaoc03ba122020-12-23 21:54:02 -0800714 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800715 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800716 goto exit;
717 }
Song Zhao35a82df2021-04-15 10:58:49 -0700718 msync_session_get_wall(avsync->fd, &systime, &interval);
719 pts = frame->pts - avsync->delay * interval;
720 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800721 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700722 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800723 }
724
Song Zhaoea5a0412021-01-18 16:40:08 -0800725 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700726 !avsync->first_frame_toggled &&
727 !msync_clock_started(avsync->fd)) {
728 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800729 log_trace("[%d]clock not started", avsync->session_id);
730 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800731 }
732
Song Zhaoea5a0412021-01-18 16:40:08 -0800733 enter_last_frame = avsync->last_frame;
734 msync_session_get_wall(avsync->fd, &systime, &interval);
735
736 /* handle refresh rate change */
737 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
738 avsync->vsync_interval != interval) {
739 log_info("[%d]vsync interval update %d --> %u",
740 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700741 if (avsync->fps_interval == -1)
742 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800743 avsync->vsync_interval = interval;
744 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800745 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700746 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800747 reset_pattern(avsync->pattern_detector);
748 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800749 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
750 struct vframe *next_frame = NULL;
751
752 peek_item(avsync->frame_q, (void **)&next_frame, 1);
753 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700754 log_debug("[%d]cur_f %u next_f %u size %d",
755 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800756 if (frame_expire(avsync, systime, interval,
757 frame, next_frame, toggle_cnt)) {
758 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800759 toggle_cnt++;
760
Song Zhao35a82df2021-04-15 10:58:49 -0700761 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800762 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700763 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700764 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700765 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
766 if (next_frame)
767 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
768 }
Song Zhao35a82df2021-04-15 10:58:49 -0700769
Song Zhaoc03ba122020-12-23 21:54:02 -0800770 if (avsync->last_frame)
771 avsync->last_holding_peroid = avsync->last_frame->hold_period;
772
773 dqueue_item(avsync->frame_q, (void **)&frame);
774 if (avsync->last_frame) {
775 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800776 if (toggle_cnt > 1) {
Song Zhaofd007632022-09-30 16:21:30 -0700777 log_info("[%d]free %u cur %u system/d %u/%u queue size %d", avsync->session_id,
778 avsync->last_frame->pts, frame->pts,
779 systime, systime - avsync->last_poptime,
780 queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800781 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800782 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800783 } else {
784 avsync->first_frame_toggled = true;
Song Zhaofd007632022-09-30 16:21:30 -0700785 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 -0800786 }
787 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800788 avsync->last_pts = frame->pts;
yongchun.li428390d2022-02-17 17:15:40 -0800789 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
Song Zhaoc03ba122020-12-23 21:54:02 -0800790 } else
791 break;
792 }
793
794 /* pause pts */
795 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800796 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800797 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800798 else
Song Zhao468fd652021-01-15 22:13:04 -0800799 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
800 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
801 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
802 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
803 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800804
Song Zhao468fd652021-01-15 22:13:04 -0800805 if (pause_pts_reached) {
Song Zhao468fd652021-01-15 22:13:04 -0800806 /* stay in paused until av_sync_pause(false) */
Song Zhaoa1742282022-09-30 16:17:26 -0700807 uint32_t local_pts = avsync->pause_pts;
Song Zhao468fd652021-01-15 22:13:04 -0800808 avsync->paused = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800809 log_info ("[%d]reach pause pts: %u",
Song Zhaob5458b32021-11-12 15:58:47 -0800810 avsync->session_id, avsync->pause_pts);
Song Zhaoad7c8232021-12-14 11:46:48 -0800811 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoa1742282022-09-30 16:17:26 -0700812 if (avsync->pause_pts_cb)
813 avsync->pause_pts_cb(local_pts,
814 avsync->pause_cb_priv);
815 log_info ("[%d] reach pause pts: %u handle done",
816 avsync->session_id, local_pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800817 }
818
819exit:
820 pthread_mutex_unlock(&avsync->lock);
yongchun.li428390d2022-02-17 17:15:40 -0800821
822 /* underflow check */
823 if (avsync->session_started && avsync->first_frame_toggled &&
824 (avsync->paused == false) && (avsync->state >= AV_SYNC_STAT_RUNNING) &&
825 avsync->underflow_cb && peek_item(avsync->frame_q, (void **)&frame, 0))
826 {/* empty queue in normal play */
827 struct timespec now;
828 int diff_ms;
829 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
830 diff_ms = time_diff(&now, &avsync->frame_last_update_time)/1000;
831 if(diff_ms >= (avsync->underflow_cfg.time_thresh
832 + avsync->vsync_interval*avsync->last_holding_peroid/90)) {
833 log_info ("[%d]underflow detected: %u", avsync->session_id, avsync->last_pts);
834 avsync->underflow_cb (avsync->last_pts,
835 avsync->underflow_cb_priv);
836 /* update time to control the underflow check call backs */
837 avsync->frame_last_update_time = now;
838 }
839 }
840
Song Zhaoc03ba122020-12-23 21:54:02 -0800841 if (avsync->last_frame) {
Song Zhaof3350d32023-08-18 16:27:31 -0700842 if (enter_last_frame != avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800843 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhaof3350d32023-08-18 16:27:31 -0700844 /* don't update vpts for out_lier */
845 if (avsync->last_frame->duration != -1)
846 msync_session_update_vpts(avsync->fd, systime,
847 avsync->last_frame->pts + avsync->extra_delay, interval * avsync->delay);
848 }
bo.xiao1f94b352021-08-02 03:53:47 -0400849 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 -0800850 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800851 if (enter_last_frame != avsync->last_frame)
852 log_debug("[%d]pop (nil)", avsync->session_id);
853
Song Zhao35a82df2021-04-15 10:58:49 -0700854 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800855 if (avsync->last_frame)
856 avsync->last_frame->hold_period++;
857 return avsync->last_frame;
858}
859
Song Zhaoc03ba122020-12-23 21:54:02 -0800860static inline uint32_t abs_diff(uint32_t a, uint32_t b)
861{
Song Zhaoea5a0412021-01-18 16:40:08 -0800862 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800863}
864
yongchun.li0ee6e372021-08-20 04:26:04 -0700865static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800866{
hanghang.luo02efd312022-08-26 09:49:53 +0800867 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 -0800868}
869
Song Zhaoc03ba122020-12-23 21:54:02 -0800870static bool frame_expire(struct av_sync_session* avsync,
871 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800872 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800873 struct vframe * frame,
874 struct vframe * next_frame,
875 int toggle_cnt)
876{
Song Zhao6dce2672022-01-13 11:32:44 -0800877 uint32_t fpts = frame->pts + avsync->extra_delay;
878 uint32_t nfpts = -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800879 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800880 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800881
882 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
883 return false;
884
885 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
886 return true;
887
Song Zhaoad7c8232021-12-14 11:46:48 -0800888 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS &&
889 avsync->pause_pts == frame->pts)
890 return true;
891
Song Zhao08fa16b2021-12-08 14:30:17 -0800892 if (systime == AV_SYNC_INVALID_PTS &&
893 avsync->mode == AV_SYNC_MODE_AMASTER)
894 return false;
895
Song Zhao6dce2672022-01-13 11:32:44 -0800896 if (next_frame)
897 nfpts = next_frame->pts + avsync->extra_delay;
898
Song Zhao7e24b182022-04-01 08:46:40 -0700899 if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
fei.deng63e43e12021-09-23 19:44:01 +0800900 /* We need to ensure that the video outputs smoothly,
901 so output video frame by frame hold_period */
902 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
903 avsync->last_frame &&
904 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
905 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
906 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700907 return true;
908 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700909 }
910
Song Zhaoc03ba122020-12-23 21:54:02 -0800911 if (!fpts) {
912 if (avsync->last_frame) {
913 /* try to accumulate duration as PTS */
914 fpts = avsync->vpts + avsync->last_frame->duration;
915 } else {
916 fpts = avsync->vpts;
917 }
918 }
919 systime += pts_correction;
920
921 /* phase adjustment */
922 if (avsync->phase_set)
923 systime += avsync->phase;
924
yongchun.lia50b1e92021-08-07 01:11:54 +0000925 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800926 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000927 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700928 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800929 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800930 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800931 return false;
932
Song Zhaoa2985cb2021-06-24 12:01:47 -0700933 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
934 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700935 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800936
yongchun.li0ee6e372021-08-20 04:26:04 -0700937 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700938 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800939 avsync->last_pts = fpts;
940 if (time_diff(&now, &avsync->sync_lost_print_time) >=
941 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700942 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800943 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800944 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700945 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800946 } else
947 avsync->sync_lost_cnt++;
948 }
Song Zhaod62bb392021-04-23 12:25:49 -0700949
950 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
951 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700952 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700953 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700954 /* outlier by stream error */
955 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700956 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700957 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
958 log_info("render outlier %u", fpts);
959 return true;
960 }
961 }
962
963 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800964 avsync->state = AV_SYNC_STAT_SYNC_LOST;
965 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800966 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700967 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800968 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700969
Song Zhao7e24b182022-04-01 08:46:40 -0700970 if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700971 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700972 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700973 msync_session_set_video_dis(avsync->fd, fpts);
974 avsync->last_disc_pts = fpts;
Song Zhao59d732d2024-01-23 22:09:15 -0800975 if (avsync->mode == AV_SYNC_MODE_VMASTER) {
976 systime = fpts;
977 avsync->last_r_syst = -1;
978 }
Song Zhaoa2985cb2021-06-24 12:01:47 -0700979 }
980
981 if ((int)(systime - fpts) > 0) {
982 if ((int)(systime - fpts) < avsync->disc_thres_max) {
983 /* catch up PCR */
Song Zhao59d732d2024-01-23 22:09:15 -0800984 avsync->last_r_syst = -1;
Song Zhaof46932e2021-05-21 01:51:45 -0700985 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700986 } else {
987 /* render according to FPS */
988 if (!VALID_TS(avsync->last_r_syst) ||
989 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
990 avsync->last_r_syst = systime;
991 return true;
992 }
993 return false;
994 }
995 } else if (LIVE_MODE(avsync->mode)) {
996 /* hold if the gap is small */
997 if ((int)(fpts - systime) < avsync->disc_thres_max) {
998 return false;
999 } else {
1000 /* render according to FPS */
1001 if (!VALID_TS(avsync->last_r_syst) ||
1002 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
1003 avsync->last_r_syst = systime;
1004 return true;
1005 }
1006 return false;
1007 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001008 }
1009 }
1010
Song Zhao52f55192021-05-06 10:52:21 -07001011 /* In some cases, keeping pattern will enlarge the gap */
1012 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
1013 avsync->first_frame_toggled) {
1014 reset_pattern(avsync->pattern_detector);
Song Zhaofd007632022-09-30 16:21:30 -07001015 log_info("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -07001016 systime, fpts);
1017 }
1018
Song Zhaoc03ba122020-12-23 21:54:02 -08001019 expire = (int)(systime - fpts) >= 0;
1020
1021 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -08001022 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001023 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -08001024 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001025 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001026 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001027 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -08001028 }
Song Zhao6dce2672022-01-13 11:32:44 -08001029 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -08001030 && avsync->first_frame_toggled) {
1031 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -08001032 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001033 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -08001034 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001035 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001036 }
1037 }
1038
Song Zhaoa58c3e92021-03-09 18:52:55 -08001039 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -08001040 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -08001041 (avsync->last_frame?avsync->last_frame->hold_period:0),
1042 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -08001043 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -08001044
1045 if (expire) {
1046 avsync->vpts = fpts;
1047 /* phase adjustment */
1048 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +00001049 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -08001050 if ((int)(systime - fpts) >= 0 &&
1051 (int)(fpts + interval - systime) > 0) {
1052 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -08001053 avsync->phase_set = true;
Song Zhaofd007632022-09-30 16:21:30 -07001054 log_debug("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -08001055 }
Song Zhao1561e542022-01-12 10:37:55 -08001056 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -08001057 if ((int)(systime - fpts) >= 0 &&
1058 (int)(fpts + interval - systime) > 0) {
1059 int vsync_pts_delta = (int)(systime - fpts);
1060
1061 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1062 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001063 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001064 log_info("[%d] too aligned adjust phase to %d",
1065 avsync->session_id, (int)avsync->phase);
1066 }
1067 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001068 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001069 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaofd007632022-09-30 16:21:30 -07001070 log_info("[%d]sync setup on frame %u", avsync->session_id, fpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001071 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001072 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001073 }
1074 return expire;
1075}
1076
Song Zhao35a82df2021-04-15 10:58:49 -07001077static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001078{
Song Zhaoea5a0412021-01-18 16:40:08 -08001079 log_trace("[%d]cur_period: %d last_period: %d",
1080 avsync->session_id, cur_period, last_period);
Song Zhaobb3b4f32023-10-17 16:08:12 -07001081 return detect_pattern(avsync->pattern_detector, cur_period, last_period);
Song Zhaoc03ba122020-12-23 21:54:02 -08001082}
1083
1084int av_sync_set_speed(void *sync, float speed)
1085{
1086 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1087
1088 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001089 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001090 return -1;
1091 }
1092
Song Zhao76005282022-03-08 16:49:41 -08001093 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001094 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001095 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001096 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001097
Song Zhaoea5a0412021-01-18 16:40:08 -08001098 avsync->speed = speed;
1099
1100 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhaoa73fcf32023-01-13 08:12:26 -08001101 if (speed == 1.0)
1102 msync_session_set_wall_adj_thres(avsync->fd, DEFAULT_WALL_ADJ_THRES);
1103 else
1104 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
1105 log_info("[%d]adjust wall adj threshold to %d", avsync->session_id,
1106 (speed == 1.0) ? DEFAULT_WALL_ADJ_THRES : avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -08001107 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001108
Song Zhaoea5a0412021-01-18 16:40:08 -08001109 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1110 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001111}
1112
1113int av_sync_change_mode(void *sync, enum sync_mode mode)
1114{
1115 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1116
1117 if (!avsync)
1118 return -1;
1119
Song Zhaoea5a0412021-01-18 16:40:08 -08001120 if (msync_session_set_mode(avsync->fd, mode)) {
1121 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001122 return -1;
1123 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001124 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001125 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001126 return 0;
1127}
1128
Song Zhao01031bb2021-05-13 21:23:20 -07001129int av_sync_get_mode(void *sync, enum sync_mode *mode)
1130{
1131 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1132
1133 if (!avsync || !mode)
1134 return -1;
1135
1136 *mode = avsync->mode;
1137 return 0;
1138}
1139
Song Zhaoc03ba122020-12-23 21:54:02 -08001140int av_sync_set_pause_pts(void *sync, pts90K pts)
1141{
1142 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1143
1144 if (!avsync)
1145 return -1;
1146
1147 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001148 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001149 return 0;
1150}
1151
1152int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1153{
1154 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1155
1156 if (!avsync)
1157 return -1;
1158
1159 avsync->pause_pts_cb = cb;
1160 avsync->pause_cb_priv = priv;
1161 return 0;
1162}
Song Zhaoea5a0412021-01-18 16:40:08 -08001163
yongchun.li428390d2022-02-17 17:15:40 -08001164int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1165{
1166 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1167
1168 if (!avsync)
1169 return -1;
1170
1171 avsync->underflow_cb = cb;
1172 avsync->underflow_cb_priv = priv;
1173
1174 if (cfg)
1175 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1176 else
1177 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1178
1179 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1180 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1181 avsync->underflow_cfg.time_thresh);
1182 return 0;
1183}
Song Zhaoea5a0412021-01-18 16:40:08 -08001184static void trigger_audio_start_cb(struct av_sync_session *avsync,
1185 avs_ascb_reason reason)
1186{
1187 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001188 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001189 pthread_mutex_lock(&avsync->lock);
1190 if (avsync->audio_start) {
1191 avsync->audio_start(avsync->audio_start_priv, reason);
1192 avsync->session_started = true;
1193 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001194 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001195 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1196 }
1197 pthread_mutex_unlock(&avsync->lock);
1198 }
1199}
1200
1201avs_start_ret av_sync_audio_start(
1202 void *sync,
1203 pts90K pts,
1204 pts90K delay,
1205 audio_start_cb cb,
1206 void *priv)
1207{
1208 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1209 uint32_t start_mode;
yongchun.li06965172022-12-14 19:50:31 -08001210 uint32_t systime = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001211 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1212 bool create_poll_t = false;
1213
1214 if (!avsync)
1215 return ret;
1216
yongchun.li59e873d2021-07-07 11:42:38 -07001217 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1218 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001219
yongchun.li06965172022-12-14 19:50:31 -08001220 if (avsync->in_audio_switch) {
1221 msync_session_get_wall(avsync->fd, &systime, NULL);
1222 if (systime == AV_SYNC_INVALID_PTS) {
1223 log_info("%d Invalid systime could be paused pts %d ms switch_state %d again",
1224 avsync->session_id, (int) pts/90, avsync->audio_switch_state);
1225 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
1226 ret = AV_SYNC_ASTART_AGAIN;
1227 goto exit;
1228 }
1229 }
1230
yongchun.li59e873d2021-07-07 11:42:38 -07001231 if (avsync->in_audio_switch &&
1232 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1233 {
1234 start_mode = AVS_START_SYNC;
1235 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1236 } else {
1237 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1238 log_error("[%d]fail to set audio start", avsync->session_id);
1239 }
1240 if (avsync->in_audio_switch &&
1241 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1242 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
Song Zhao4bd18762022-09-30 16:39:52 -07001243 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB
1244 && start_mode == AVS_START_SYNC) {
yongchun.li59e873d2021-07-07 11:42:38 -07001245 log_info("%d audio_switch audio need drop first.ahead %d ms",
1246 avsync->session_id, (int)(systime - pts)/90);
1247 ret = AV_SYNC_ASTART_AGAIN;
1248 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1249 goto exit;
1250 }
1251 else {
1252 int diff = (int)(pts - systime);
1253 log_info("%d audio_switch_state to start mode %d diff %d ms",
1254 avsync->session_id, start_mode, diff/90);
yongchun.li59e873d2021-07-07 11:42:38 -07001255 if (diff < A_ADJ_THREDHOLD_LB) {
1256 log_info("%d orig mode %d already close enough direct start",
1257 avsync->session_id, start_mode);
1258 start_mode = AVS_START_SYNC;
Song Zhao4bd18762022-09-30 16:39:52 -07001259 } else if (start_mode != AVS_START_ASYNC) {
1260 log_info("%d drop too far mode %d need to try ASYNC",
1261 avsync->session_id, start_mode);
1262 msync_session_set_audio_stop(avsync->fd);
1263 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1264 log_error("[%d]fail to set audio start", avsync->session_id);
1265 log_info("%d New start mode %d",
1266 avsync->session_id, start_mode);
yongchun.li59e873d2021-07-07 11:42:38 -07001267 }
Song Zhao4bd18762022-09-30 16:39:52 -07001268 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
yongchun.li59e873d2021-07-07 11:42:38 -07001269 }
yongchun.li107a6162021-05-05 02:38:57 -07001270 }
1271
Song Zhaoea5a0412021-01-18 16:40:08 -08001272 if (start_mode == AVS_START_SYNC) {
1273 ret = AV_SYNC_ASTART_SYNC;
1274 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001275 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001276 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001277 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001278 avsync->state = AV_SYNC_STAT_RUNNING;
1279 } else if (start_mode == AVS_START_AGAIN) {
1280 ret = AV_SYNC_ASTART_AGAIN;
1281 }
1282
1283 if (ret == AV_SYNC_ASTART_AGAIN)
1284 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001285
Song Zhao76005282022-03-08 16:49:41 -08001286 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1287 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001288 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001289
1290 if (start_mode == AVS_START_ASYNC) {
1291 if (!cb) {
1292 log_error("[%d]invalid cb", avsync->session_id);
1293 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001294 }
Song Zhao76005282022-03-08 16:49:41 -08001295 avsync->audio_start = cb;
1296 avsync->audio_start_priv = priv;
1297 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001298
Song Zhaod62bb392021-04-23 12:25:49 -07001299 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001300 int ret;
1301
1302 log_info("[%d]start poll thread", avsync->session_id);
1303 avsync->quit_poll = false;
1304 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1305 if (ret) {
1306 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1307 return AV_SYNC_ASTART_ERR;
1308 }
1309 }
Song Zhaod62bb392021-04-23 12:25:49 -07001310 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001311 msync_session_get_wall(avsync->fd, &systime, NULL);
1312 log_info("[%d]return %u w %u pts %u d %u",
1313 avsync->session_id, ret, systime, pts, delay);
1314 }
1315exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001316 log_info("[%d]return %u", avsync->session_id, ret);
1317 return ret;
1318}
1319
1320int av_sync_audio_render(
1321 void *sync,
1322 pts90K pts,
1323 struct audio_policy *policy)
1324{
1325 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001326 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001327 uint32_t systime;
1328 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1329 avs_audio_action action = AA_SYNC_AA_MAX;
1330
1331 if (!avsync || !policy)
1332 return -1;
1333
yongchun.li107a6162021-05-05 02:38:57 -07001334 msync_session_get_wall(avsync->fd, &systime, NULL);
1335
1336 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1337 pts, systime, avsync->mode, (int)(pts-systime)/90);
1338
1339 if (avsync->in_audio_switch
1340 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
Song Zhao4bd18762022-09-30 16:39:52 -07001341 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_MB) {
yongchun.li107a6162021-05-05 02:38:57 -07001342 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1343 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1344 action = AV_SYNC_AA_RENDER;
1345 } else if ((int)(systime - pts) > 0) {
1346 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1347 (int)(systime - pts)/90, systime, pts);
1348 action = AV_SYNC_AA_DROP;
1349 } else {
1350 action = AV_SYNC_AA_INSERT;
1351 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1352 (int)(pts - systime)/90, systime, pts);
1353 }
1354 goto done;
1355 }
1356
Song Zhaoea5a0412021-01-18 16:40:08 -08001357 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1358 avsync->mode == AV_SYNC_MODE_AMASTER) {
1359 action = AV_SYNC_AA_RENDER;
1360 goto done;
1361 }
1362
Song Zhaod62bb392021-04-23 12:25:49 -07001363 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001364 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001365 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1366 action = AV_SYNC_AA_DROP;
1367 goto done;
1368 }
1369
Song Zhao7daf3a12021-05-10 22:22:25 -07001370 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
Song Zhaob8833c12024-02-02 21:54:36 +00001371 avsync->mode == AV_SYNC_MODE_AMASTER ||
1372 avsync->active_mode == AV_SYNC_MODE_AMASTER) {
Song Zhao7daf3a12021-05-10 22:22:25 -07001373 action = AV_SYNC_AA_RENDER;
1374 goto done;
1375 }
1376
Song Zhaod62bb392021-04-23 12:25:49 -07001377 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1378 LIVE_MODE(avsync->mode) &&
1379 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1380 /* outlier by stream error */
1381 avsync->outlier_cnt++;
1382 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1383 /* treat as disc, just drop current frame */
1384 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1385 avsync->outlier_cnt = 0;
1386 action = AV_SYNC_AA_DROP;
1387 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001388 goto done;
1389 }
1390 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1391 pts = systime;
1392 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001393 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001394 goto done;
1395 }
1396
1397 avsync->outlier_cnt = 0;
1398 /* low bound from sync_lost to sync_setup */
1399 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1400 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1401 action = AV_SYNC_AA_RENDER;
1402 goto done;
1403 }
1404
1405 /* high bound of sync_setup */
1406 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1407 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1408 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001409 action = AV_SYNC_AA_RENDER;
1410 goto done;
1411 }
1412
1413 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001414 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001415 action = AV_SYNC_AA_DROP;
1416 goto done;
1417 }
1418
1419 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001420 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001421 action = AV_SYNC_AA_INSERT;
1422 goto done;
1423 }
1424
1425done:
1426 policy->action = action;
1427 policy->delta = (int)(systime - pts);
1428 if (action == AV_SYNC_AA_RENDER) {
1429 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001430 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001431 if (!out_lier)
1432 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001433 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001434 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001435 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1436 msync_session_update_apts(avsync->fd, systime, pts, 0);
1437 log_info("[%d] audio switch done sys %u pts %u",
1438 avsync->session_id, systime, pts);
1439 msync_session_set_audio_switch(avsync->fd, false);
1440 avsync->in_audio_switch = false;
1441 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1442 } else {
1443 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1444 avsync->session_id, action, systime, pts, systime - pts);
1445 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001446 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001447 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001448 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001449 avsync->last_disc_pts != pts &&
1450 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001451 log_info ("[%d]audio disc %u --> %u",
1452 avsync->session_id, systime, pts);
1453 msync_session_set_audio_dis(avsync->fd, pts);
1454 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001455 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001456 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001457
1458 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001459 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001460 if (!avsync->audio_drop_cnt)
1461 avsync->audio_drop_start = now;
1462 avsync->audio_drop_cnt++;
1463 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1464 log_info ("[%d]audio keep dropping sys %u vs a %u",
1465 avsync->session_id, systime, pts);
1466 msync_session_set_audio_dis(avsync->fd, pts);
1467 }
Song Zhao409739b2021-05-12 22:21:40 -07001468 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001469 if (action != AV_SYNC_AA_DROP)
1470 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001471 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001472 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001473 }
1474
1475 return ret;
1476}
1477
Song Zhaof3350d32023-08-18 16:27:31 -07001478int av_sync_get_pos(void *sync, pts90K *pts, uint64_t *mono_clock)
1479{
1480 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1481
1482 if (!avsync || !pts)
1483 return -1;
1484
1485 if (avsync->type != AV_SYNC_TYPE_AUDIO &&
1486 avsync->type != AV_SYNC_TYPE_VIDEO)
1487 return -2;
1488 return msync_session_get_pts(avsync->fd, pts,
1489 mono_clock, avsync->type == AV_SYNC_TYPE_VIDEO);
1490}
1491
Song Zhaoea5a0412021-01-18 16:40:08 -08001492int av_sync_get_clock(void *sync, pts90K *pts)
1493{
1494 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1495
1496 if (!avsync || !pts)
1497 return -1;
1498 return msync_session_get_wall(avsync->fd, pts, NULL);
1499}
1500
1501static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001502 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001503 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001504{
Song Zhao76005282022-03-08 16:49:41 -08001505 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1506 avsync->session_id, avsync->active_mode, avsync->mode,
1507 v_active, a_active, v_timeout, stat);
1508
1509 /* iptv delayed start */
1510 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1511 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1512
Song Zhaoea5a0412021-01-18 16:40:08 -08001513 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1514 float speed;
Song Zhao7e8c68f2022-07-12 16:24:30 -07001515 if (a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001516 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001517 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhao6183ca92022-07-29 09:57:03 -07001518 } else if (!a_active && !avsync->session_started) {
1519 /* quit waiting ASAP */
1520 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoea5a0412021-01-18 16:40:08 -08001521 }
1522
1523 if (!msync_session_get_rate(avsync->fd, &speed)) {
1524 /* speed change is triggered by asink,
1525 * attached audio HAL will handle it
1526 */
1527 if (speed != avsync->speed)
1528 log_info("[%d]new rate %f", avsync->session_id, speed);
Song Zhaoa73fcf32023-01-13 08:12:26 -08001529#if 0 //don't use freerun for trick mode. Or A/V gap will keep increasing
Song Zhaoea5a0412021-01-18 16:40:08 -08001530 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001531 if (avsync->mode != avsync->backup_mode) {
1532 avsync->mode = avsync->backup_mode;
1533 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1534 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001535 } else {
1536 avsync->backup_mode = avsync->mode;
1537 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1538 log_info("[%d]audio to freerun mode", avsync->session_id);
1539 }
Song Zhaoa73fcf32023-01-13 08:12:26 -08001540#endif
Song Zhaoea5a0412021-01-18 16:40:08 -08001541 avsync->speed = speed;
1542 }
Song Zhaod62bb392021-04-23 12:25:49 -07001543 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1544 struct session_debug debug;
1545 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001546 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001547 avsync->backup_mode = avsync->mode;
1548 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001549 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001550 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001551 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001552 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001553 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001554 log_warn("[%d]audio back to mode %d",
1555 avsync->session_id, avsync->mode);
1556 }
1557 }
Song Zhao76005282022-03-08 16:49:41 -08001558 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1559 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaob8833c12024-02-02 21:54:36 +00001560 if (a_active && avsync->audio_start) {
1561 if (v_active || v_timeout) {
1562 log_info("audio start cb");
1563 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1564 }
1565 }
1566
Song Zhaoea5a0412021-01-18 16:40:08 -08001567 }
1568}
1569
1570static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001571 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001572 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001573{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001574 struct session_debug debug;
1575
Song Zhao76005282022-03-08 16:49:41 -08001576 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1577 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001578 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1579 if (debug.debug_freerun && !avsync->debug_freerun) {
1580 avsync->backup_mode = avsync->mode;
1581 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1582 avsync->debug_freerun = true;
1583 log_warn("[%d]video to freerun mode", avsync->session_id);
1584 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1585 avsync->mode = avsync->backup_mode;
1586 avsync->debug_freerun = false;
1587 log_warn("[%d]video back to mode %d",
1588 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001589 }
1590 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001591}
1592
1593static void * poll_thread(void * arg)
1594{
1595 int ret = 0;
1596 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1597 const int fd = avsync->fd;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001598 int poll_timeout = 10;
Song Zhaoea5a0412021-01-18 16:40:08 -08001599 struct pollfd pfd = {
1600 /* default blocking capture */
Song Zhao4bd18762022-09-30 16:39:52 -07001601 .events = POLLPRI,
Song Zhaoea5a0412021-01-18 16:40:08 -08001602 .fd = avsync->fd,
1603 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001604 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001605
Song Zhaoea5a0412021-01-18 16:40:08 -08001606 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001607
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001608 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001609 prctl (PR_SET_NAME, "avs_apoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001610 sflag = SRC_A;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001611 } else if (avsync->type == AV_SYNC_TYPE_VIDEO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001612 prctl (PR_SET_NAME, "avs_vpoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001613 sflag = SRC_V;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001614 poll_timeout = 100;
1615 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001616
Song Zhaoea5a0412021-01-18 16:40:08 -08001617 while (!avsync->quit_poll) {
1618 for (;;) {
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001619 ret = poll(&pfd, 1, poll_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001620 if (ret > 0)
1621 break;
1622 if (avsync->quit_poll)
1623 goto exit;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001624 if (errno == EINTR) {
1625 log_debug("[%d] poll interrupted", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001626 continue;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001627 }
Song Zhao4bd18762022-09-30 16:39:52 -07001628 if (errno == EAGAIN || errno == ENOMEM) {
1629 log_info("[%d] poll error %d", avsync->session_id, errno);
1630 continue;
1631 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001632 }
1633
1634 /* error handling */
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001635 if (pfd.revents & POLLERR) {
1636 usleep(poll_timeout * 1000);
1637 continue;
1638 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001639
Song Zhao4bd18762022-09-30 16:39:52 -07001640 if (pfd.revents & POLLNVAL) {
1641 log_warn("[%d] fd closed", avsync->session_id);
1642 goto exit;
1643 }
Song Zhaod62bb392021-04-23 12:25:49 -07001644 /* mode change. Non-exclusive wait so all the processes
1645 * shall be woken up
1646 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001647 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001648 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001649 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001650
Song Zhao9fef59c2022-08-17 12:43:10 -07001651 msync_session_get_stat(fd, true, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001652 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001653
1654 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001655 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001656 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001657 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001658 usleep(10000);
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001659 } else {
1660 log_debug("[%d] unexpected revents %x", avsync->session_id, pfd.revents);
1661 usleep(poll_timeout * 1000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001662 }
1663 }
1664exit:
1665 log_info("[%d]quit", avsync->session_id);
1666 return NULL;
1667}
1668
Song Zhao623e2f12021-09-03 15:54:04 -07001669#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1670/* return ppm between demod and PCR clock */
1671int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1672{
1673 int fd = -1, ppm = 0, nread;
1674 char buf[128];
1675 uint32_t reg_v, lock;
1676 float val;
1677
1678 fd = open(DEMOD_NODE, O_RDWR);
1679 if (fd < 0) {
1680 log_warn("node not found %s", DEMOD_NODE);
1681 /* do not retry */
1682 avsync->ppm_adjusted = true;
1683 return 0;
1684 }
1685 snprintf(buf, sizeof(buf), "%d", 5);
1686 write(fd, buf, 2);
1687
1688 lseek(fd, 0, SEEK_SET);
1689
hanghang.luo02efd312022-08-26 09:49:53 +08001690 nread = read(fd, buf, sizeof(buf)-1);
Song Zhao623e2f12021-09-03 15:54:04 -07001691 if (nread <= 0) {
1692 log_error("read error");
1693 goto err;
1694 }
1695 buf[nread] = 0;
1696 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1697 log_error("wrong format %s", buf);
1698 goto err;
1699 }
1700 if (lock != 0x1f) {
1701 log_info("demod not locked");
1702 goto err;
1703 }
1704 if (reg_v > ((2 << 20) - 1))
1705 reg_v -= (2 << 21);
1706 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1707 ppm = val;
1708 log_info("ppm from SFO %d", ppm);
1709 avsync->ppm_adjusted = true;
1710
1711err:
1712 if (fd >= 0)
1713 close(fd);
1714 return ppm;
1715}
1716
Song Zhaod62bb392021-04-23 12:25:49 -07001717int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001718{
1719 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001720 struct pcr_info pcr;
1721 enum pcr_monitor_status status;
1722 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001723 if (!avsync)
1724 return -1;
1725
1726 if (avsync->type != AV_SYNC_TYPE_PCR)
1727 return -2;
1728
Song Zhao623e2f12021-09-03 15:54:04 -07001729 /* initial estimation from Demod SFO HW */
1730 if (!avsync->ppm_adjusted) {
1731 ppm = dmod_get_sfo_dev(avsync);
1732 if (ppm != 0) {
1733 /* ppm > 0 means board clock is faster */
1734 msync_session_set_clock_dev(avsync->fd, -ppm);
1735 }
1736 }
wei.dubcc2ed22021-05-19 07:16:10 -04001737 pcr.monoclk = mono_clock / 1000;
1738 pcr.pts = (long long) pts * 1000 / 90;
1739 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1740
1741 status = pcr_monitor_get_status(avsync->pcr_monitor);
1742
1743 if (status >= DEVIATION_READY) {
1744 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1745 if (avsync->ppm != ppm) {
1746 avsync->ppm = ppm;
1747 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1748 if (msync_session_set_clock_dev(avsync->fd, ppm))
1749 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001750 else
1751 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001752 }
1753 }
1754
Song Zhaod62bb392021-04-23 12:25:49 -07001755 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001756}
1757
Song Zhaod62bb392021-04-23 12:25:49 -07001758int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001759{
1760 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1761
1762 if (!avsync)
1763 return -1;
1764
Song Zhaod62bb392021-04-23 12:25:49 -07001765 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001766}
1767
1768int av_sync_set_session_name(void *sync, const char *name)
1769{
1770 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1771
1772 if (!avsync)
1773 return -1;
1774
1775 return msync_session_set_name(avsync->fd, name);
1776}
yongchun.li107a6162021-05-05 02:38:57 -07001777
1778int av_sync_set_audio_switch(void *sync, bool start)
1779{
1780 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1781 bool v_active, a_active, v_timeout;
1782
1783 if (!avsync)
1784 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001785 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001786 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001787 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001788 log_error("[%d] can not get session state",
1789 avsync->session_id);
1790 return -1;
1791 }
1792 if (!v_active || !a_active) {
1793 log_error("[%d] no apply if not AV both active v %d a %d",
1794 avsync->session_id, v_active, a_active);
1795 return -1;
1796 }
1797 if (msync_session_set_audio_switch(avsync->fd, start)) {
1798 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1799 return -1;
1800 }
1801 avsync->in_audio_switch = start;
1802 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1803 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1804 return 0;
1805}
1806
1807int av_sync_get_audio_switch(void *sync, bool *start)
1808{
1809 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1810
1811 if (!avsync)
1812 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001813 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001814 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001815 log_error("[%d] can not audio seamless switch state",
1816 avsync->session_id);
1817 return -1;
1818 }
1819 if (start) *start = avsync->in_audio_switch;
1820 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001821}
Song Zhao8039f562021-05-18 18:11:25 -07001822
Song Zhao623e2f12021-09-03 15:54:04 -07001823enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001824{
1825 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1826
wei.dubcc2ed22021-05-19 07:16:10 -04001827 if (!avsync || !ppm)
1828 return CLK_RECOVERY_ERR;
1829 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001830 return CLK_RECOVERY_NOT_RUNNING;
1831
wei.dubcc2ed22021-05-19 07:16:10 -04001832 if (msync_session_get_clock_dev(avsync->fd, ppm))
1833 return CLK_RECOVERY_ERR;
1834
1835 if (*ppm == 0)
1836 return CLK_RECOVERY_ONGOING;
1837 else
1838 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001839}
Song Zhao95bd0922021-09-21 14:07:46 -07001840
1841static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1842{
1843 int ret;
1844
1845 if (!avsync->frame_q) {
1846 avsync->frame_q = create_q(MAX_FRAME_NUM);
1847 if (!avsync->frame_q) {
1848 log_error("[%d]create queue fail", avsync->session_id);
1849
1850 return -1;
1851 }
1852 }
1853
1854 ret = queue_item(avsync->frame_q, frame);
1855 if (ret)
hanghang.luo02efd312022-08-26 09:49:53 +08001856 log_error("queue fail:%d", ret);
Song Zhao95bd0922021-09-21 14:07:46 -07001857 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1858 return ret;
1859}
1860
1861int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1862{
1863 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1864
1865 if (!avsync)
1866 return -1;
1867 avsync->msys = msys;
1868 return 0;
1869}
1870
1871static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1872{
1873 struct vframe *frame = NULL, *enter_last_frame = NULL;
1874 uint64_t systime;
1875 int toggle_cnt = 0;
1876
1877 enter_last_frame = avsync->last_frame;
1878 systime = avsync->msys;
1879 log_debug("[%d]sys %llu", avsync->session_id, systime);
1880 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1881 if (systime >= frame->mts) {
1882 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1883 toggle_cnt++;
1884
1885 if (avsync->last_frame)
1886 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1887
1888 dqueue_item(avsync->frame_q, (void **)&frame);
1889 if (avsync->last_frame) {
1890 /* free frame that are not for display */
1891 if (toggle_cnt > 1) {
1892 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1893 avsync->last_frame->mts, frame->mts, systime);
1894 avsync->last_frame->free(avsync->last_frame);
1895 }
1896 } else {
1897 avsync->first_frame_toggled = true;
1898 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1899 }
1900 avsync->last_frame = frame;
1901 } else
1902 break;
1903 }
1904
1905 if (avsync->last_frame) {
1906 if (enter_last_frame != avsync->last_frame)
hanghang.luo02efd312022-08-26 09:49:53 +08001907 log_debug("[%d]pop %lu", avsync->session_id, avsync->last_frame->pts);
1908 log_trace("[%d]pop=%llu, system=%llu, diff %llu(ms), QNum=%d", avsync->session_id,
Song Zhao95bd0922021-09-21 14:07:46 -07001909 avsync->last_frame->mts,
1910 systime, (systime - avsync->last_frame->mts) / 1000000,
1911 queue_size(avsync->frame_q));
1912 } else
1913 if (enter_last_frame != avsync->last_frame)
1914 log_debug("[%d]pop (nil)", avsync->session_id);
1915
1916 if (avsync->last_frame)
1917 avsync->last_frame->hold_period++;
1918 return avsync->last_frame;
1919}
Song Zhao6183ca92022-07-29 09:57:03 -07001920
1921int avs_sync_stop_audio(void *sync)
1922{
1923 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1924
1925 if (!avsync)
1926 return -1;
1927
1928 return msync_session_stop_audio(avsync->fd);
1929}
bo.xiao05ba1ac2022-12-13 14:38:13 +08001930
1931int avs_sync_set_eos(void *sync)
1932{
1933 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1934
1935 if (!avsync)
1936 return -1;
1937
1938 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
1939 if (avsync->state == AV_SYNC_STAT_INIT) {
1940 avsync->state = AV_SYNC_STAT_RUNNING;
1941 log_debug("[%d]eos trigger state change: init --> running", avsync->session_id);
1942 }
1943 }
1944
1945 return 0;
1946}