blob: 6d6bca194a8f36ea87fb6f3a0b992c30cfd516b9 [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 Zhaoa2985cb2021-06-24 12:01:47 -0700975 }
976
977 if ((int)(systime - fpts) > 0) {
978 if ((int)(systime - fpts) < avsync->disc_thres_max) {
979 /* catch up PCR */
Song Zhaof46932e2021-05-21 01:51:45 -0700980 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700981 } else {
982 /* render according to FPS */
983 if (!VALID_TS(avsync->last_r_syst) ||
984 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
985 avsync->last_r_syst = systime;
986 return true;
987 }
988 return false;
989 }
990 } else if (LIVE_MODE(avsync->mode)) {
991 /* hold if the gap is small */
992 if ((int)(fpts - systime) < avsync->disc_thres_max) {
993 return false;
994 } else {
995 /* render according to FPS */
996 if (!VALID_TS(avsync->last_r_syst) ||
997 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
998 avsync->last_r_syst = systime;
999 return true;
1000 }
1001 return false;
1002 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001003 }
1004 }
1005
Song Zhao52f55192021-05-06 10:52:21 -07001006 /* In some cases, keeping pattern will enlarge the gap */
1007 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
1008 avsync->first_frame_toggled) {
1009 reset_pattern(avsync->pattern_detector);
Song Zhaofd007632022-09-30 16:21:30 -07001010 log_info("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -07001011 systime, fpts);
1012 }
1013
Song Zhaoc03ba122020-12-23 21:54:02 -08001014 expire = (int)(systime - fpts) >= 0;
1015
1016 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -08001017 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001018 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -08001019 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001020 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001021 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001022 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -08001023 }
Song Zhao6dce2672022-01-13 11:32:44 -08001024 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -08001025 && avsync->first_frame_toggled) {
1026 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -08001027 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001028 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -08001029 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001030 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001031 }
1032 }
1033
Song Zhaoa58c3e92021-03-09 18:52:55 -08001034 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -08001035 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -08001036 (avsync->last_frame?avsync->last_frame->hold_period:0),
1037 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -08001038 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -08001039
1040 if (expire) {
1041 avsync->vpts = fpts;
1042 /* phase adjustment */
1043 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +00001044 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -08001045 if ((int)(systime - fpts) >= 0 &&
1046 (int)(fpts + interval - systime) > 0) {
1047 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -08001048 avsync->phase_set = true;
Song Zhaofd007632022-09-30 16:21:30 -07001049 log_debug("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -08001050 }
Song Zhao1561e542022-01-12 10:37:55 -08001051 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -08001052 if ((int)(systime - fpts) >= 0 &&
1053 (int)(fpts + interval - systime) > 0) {
1054 int vsync_pts_delta = (int)(systime - fpts);
1055
1056 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1057 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001058 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001059 log_info("[%d] too aligned adjust phase to %d",
1060 avsync->session_id, (int)avsync->phase);
1061 }
1062 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001063 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001064 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaofd007632022-09-30 16:21:30 -07001065 log_info("[%d]sync setup on frame %u", avsync->session_id, fpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001066 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001067 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001068 }
1069 return expire;
1070}
1071
Song Zhao35a82df2021-04-15 10:58:49 -07001072static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001073{
Song Zhaoea5a0412021-01-18 16:40:08 -08001074 log_trace("[%d]cur_period: %d last_period: %d",
1075 avsync->session_id, cur_period, last_period);
Song Zhaobb3b4f32023-10-17 16:08:12 -07001076 return detect_pattern(avsync->pattern_detector, cur_period, last_period);
Song Zhaoc03ba122020-12-23 21:54:02 -08001077}
1078
1079int av_sync_set_speed(void *sync, float speed)
1080{
1081 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1082
1083 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001084 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001085 return -1;
1086 }
1087
Song Zhao76005282022-03-08 16:49:41 -08001088 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001089 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001090 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001091 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001092
Song Zhaoea5a0412021-01-18 16:40:08 -08001093 avsync->speed = speed;
1094
1095 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhaoa73fcf32023-01-13 08:12:26 -08001096 if (speed == 1.0)
1097 msync_session_set_wall_adj_thres(avsync->fd, DEFAULT_WALL_ADJ_THRES);
1098 else
1099 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
1100 log_info("[%d]adjust wall adj threshold to %d", avsync->session_id,
1101 (speed == 1.0) ? DEFAULT_WALL_ADJ_THRES : avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -08001102 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001103
Song Zhaoea5a0412021-01-18 16:40:08 -08001104 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1105 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001106}
1107
1108int av_sync_change_mode(void *sync, enum sync_mode mode)
1109{
1110 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1111
1112 if (!avsync)
1113 return -1;
1114
Song Zhaoea5a0412021-01-18 16:40:08 -08001115 if (msync_session_set_mode(avsync->fd, mode)) {
1116 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001117 return -1;
1118 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001119 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001120 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001121 return 0;
1122}
1123
Song Zhao01031bb2021-05-13 21:23:20 -07001124int av_sync_get_mode(void *sync, enum sync_mode *mode)
1125{
1126 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1127
1128 if (!avsync || !mode)
1129 return -1;
1130
1131 *mode = avsync->mode;
1132 return 0;
1133}
1134
Song Zhaoc03ba122020-12-23 21:54:02 -08001135int av_sync_set_pause_pts(void *sync, pts90K pts)
1136{
1137 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1138
1139 if (!avsync)
1140 return -1;
1141
1142 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001143 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001144 return 0;
1145}
1146
1147int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1148{
1149 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1150
1151 if (!avsync)
1152 return -1;
1153
1154 avsync->pause_pts_cb = cb;
1155 avsync->pause_cb_priv = priv;
1156 return 0;
1157}
Song Zhaoea5a0412021-01-18 16:40:08 -08001158
yongchun.li428390d2022-02-17 17:15:40 -08001159int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1160{
1161 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1162
1163 if (!avsync)
1164 return -1;
1165
1166 avsync->underflow_cb = cb;
1167 avsync->underflow_cb_priv = priv;
1168
1169 if (cfg)
1170 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1171 else
1172 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1173
1174 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1175 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1176 avsync->underflow_cfg.time_thresh);
1177 return 0;
1178}
Song Zhaoea5a0412021-01-18 16:40:08 -08001179static void trigger_audio_start_cb(struct av_sync_session *avsync,
1180 avs_ascb_reason reason)
1181{
1182 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001183 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001184 pthread_mutex_lock(&avsync->lock);
1185 if (avsync->audio_start) {
1186 avsync->audio_start(avsync->audio_start_priv, reason);
1187 avsync->session_started = true;
1188 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001189 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001190 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1191 }
1192 pthread_mutex_unlock(&avsync->lock);
1193 }
1194}
1195
1196avs_start_ret av_sync_audio_start(
1197 void *sync,
1198 pts90K pts,
1199 pts90K delay,
1200 audio_start_cb cb,
1201 void *priv)
1202{
1203 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1204 uint32_t start_mode;
yongchun.li06965172022-12-14 19:50:31 -08001205 uint32_t systime = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001206 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1207 bool create_poll_t = false;
1208
1209 if (!avsync)
1210 return ret;
1211
yongchun.li59e873d2021-07-07 11:42:38 -07001212 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1213 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001214
yongchun.li06965172022-12-14 19:50:31 -08001215 if (avsync->in_audio_switch) {
1216 msync_session_get_wall(avsync->fd, &systime, NULL);
1217 if (systime == AV_SYNC_INVALID_PTS) {
1218 log_info("%d Invalid systime could be paused pts %d ms switch_state %d again",
1219 avsync->session_id, (int) pts/90, avsync->audio_switch_state);
1220 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
1221 ret = AV_SYNC_ASTART_AGAIN;
1222 goto exit;
1223 }
1224 }
1225
yongchun.li59e873d2021-07-07 11:42:38 -07001226 if (avsync->in_audio_switch &&
1227 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1228 {
1229 start_mode = AVS_START_SYNC;
1230 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1231 } else {
1232 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1233 log_error("[%d]fail to set audio start", avsync->session_id);
1234 }
1235 if (avsync->in_audio_switch &&
1236 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1237 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
Song Zhao4bd18762022-09-30 16:39:52 -07001238 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB
1239 && start_mode == AVS_START_SYNC) {
yongchun.li59e873d2021-07-07 11:42:38 -07001240 log_info("%d audio_switch audio need drop first.ahead %d ms",
1241 avsync->session_id, (int)(systime - pts)/90);
1242 ret = AV_SYNC_ASTART_AGAIN;
1243 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1244 goto exit;
1245 }
1246 else {
1247 int diff = (int)(pts - systime);
1248 log_info("%d audio_switch_state to start mode %d diff %d ms",
1249 avsync->session_id, start_mode, diff/90);
yongchun.li59e873d2021-07-07 11:42:38 -07001250 if (diff < A_ADJ_THREDHOLD_LB) {
1251 log_info("%d orig mode %d already close enough direct start",
1252 avsync->session_id, start_mode);
1253 start_mode = AVS_START_SYNC;
Song Zhao4bd18762022-09-30 16:39:52 -07001254 } else if (start_mode != AVS_START_ASYNC) {
1255 log_info("%d drop too far mode %d need to try ASYNC",
1256 avsync->session_id, start_mode);
1257 msync_session_set_audio_stop(avsync->fd);
1258 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1259 log_error("[%d]fail to set audio start", avsync->session_id);
1260 log_info("%d New start mode %d",
1261 avsync->session_id, start_mode);
yongchun.li59e873d2021-07-07 11:42:38 -07001262 }
Song Zhao4bd18762022-09-30 16:39:52 -07001263 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
yongchun.li59e873d2021-07-07 11:42:38 -07001264 }
yongchun.li107a6162021-05-05 02:38:57 -07001265 }
1266
Song Zhaoea5a0412021-01-18 16:40:08 -08001267 if (start_mode == AVS_START_SYNC) {
1268 ret = AV_SYNC_ASTART_SYNC;
1269 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001270 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001271 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001272 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001273 avsync->state = AV_SYNC_STAT_RUNNING;
1274 } else if (start_mode == AVS_START_AGAIN) {
1275 ret = AV_SYNC_ASTART_AGAIN;
1276 }
1277
1278 if (ret == AV_SYNC_ASTART_AGAIN)
1279 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001280
Song Zhao76005282022-03-08 16:49:41 -08001281 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1282 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001283 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001284
1285 if (start_mode == AVS_START_ASYNC) {
1286 if (!cb) {
1287 log_error("[%d]invalid cb", avsync->session_id);
1288 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001289 }
Song Zhao76005282022-03-08 16:49:41 -08001290 avsync->audio_start = cb;
1291 avsync->audio_start_priv = priv;
1292 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001293
Song Zhaod62bb392021-04-23 12:25:49 -07001294 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001295 int ret;
1296
1297 log_info("[%d]start poll thread", avsync->session_id);
1298 avsync->quit_poll = false;
1299 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1300 if (ret) {
1301 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1302 return AV_SYNC_ASTART_ERR;
1303 }
1304 }
Song Zhaod62bb392021-04-23 12:25:49 -07001305 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001306 msync_session_get_wall(avsync->fd, &systime, NULL);
1307 log_info("[%d]return %u w %u pts %u d %u",
1308 avsync->session_id, ret, systime, pts, delay);
1309 }
1310exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001311 log_info("[%d]return %u", avsync->session_id, ret);
1312 return ret;
1313}
1314
1315int av_sync_audio_render(
1316 void *sync,
1317 pts90K pts,
1318 struct audio_policy *policy)
1319{
1320 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001321 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001322 uint32_t systime;
1323 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1324 avs_audio_action action = AA_SYNC_AA_MAX;
1325
1326 if (!avsync || !policy)
1327 return -1;
1328
yongchun.li107a6162021-05-05 02:38:57 -07001329 msync_session_get_wall(avsync->fd, &systime, NULL);
1330
1331 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1332 pts, systime, avsync->mode, (int)(pts-systime)/90);
1333
1334 if (avsync->in_audio_switch
1335 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
Song Zhao4bd18762022-09-30 16:39:52 -07001336 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_MB) {
yongchun.li107a6162021-05-05 02:38:57 -07001337 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1338 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1339 action = AV_SYNC_AA_RENDER;
1340 } else if ((int)(systime - pts) > 0) {
1341 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1342 (int)(systime - pts)/90, systime, pts);
1343 action = AV_SYNC_AA_DROP;
1344 } else {
1345 action = AV_SYNC_AA_INSERT;
1346 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1347 (int)(pts - systime)/90, systime, pts);
1348 }
1349 goto done;
1350 }
1351
Song Zhaoea5a0412021-01-18 16:40:08 -08001352 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1353 avsync->mode == AV_SYNC_MODE_AMASTER) {
1354 action = AV_SYNC_AA_RENDER;
1355 goto done;
1356 }
1357
Song Zhaod62bb392021-04-23 12:25:49 -07001358 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001359 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001360 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1361 action = AV_SYNC_AA_DROP;
1362 goto done;
1363 }
1364
Song Zhao7daf3a12021-05-10 22:22:25 -07001365 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
Song Zhaob8833c12024-02-02 21:54:36 +00001366 avsync->mode == AV_SYNC_MODE_AMASTER ||
1367 avsync->active_mode == AV_SYNC_MODE_AMASTER) {
Song Zhao7daf3a12021-05-10 22:22:25 -07001368 action = AV_SYNC_AA_RENDER;
1369 goto done;
1370 }
1371
Song Zhaod62bb392021-04-23 12:25:49 -07001372 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1373 LIVE_MODE(avsync->mode) &&
1374 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1375 /* outlier by stream error */
1376 avsync->outlier_cnt++;
1377 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1378 /* treat as disc, just drop current frame */
1379 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1380 avsync->outlier_cnt = 0;
1381 action = AV_SYNC_AA_DROP;
1382 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001383 goto done;
1384 }
1385 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1386 pts = systime;
1387 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001388 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001389 goto done;
1390 }
1391
1392 avsync->outlier_cnt = 0;
1393 /* low bound from sync_lost to sync_setup */
1394 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1395 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1396 action = AV_SYNC_AA_RENDER;
1397 goto done;
1398 }
1399
1400 /* high bound of sync_setup */
1401 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1402 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1403 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001404 action = AV_SYNC_AA_RENDER;
1405 goto done;
1406 }
1407
1408 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001409 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001410 action = AV_SYNC_AA_DROP;
1411 goto done;
1412 }
1413
1414 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001415 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001416 action = AV_SYNC_AA_INSERT;
1417 goto done;
1418 }
1419
1420done:
1421 policy->action = action;
1422 policy->delta = (int)(systime - pts);
1423 if (action == AV_SYNC_AA_RENDER) {
1424 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001425 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001426 if (!out_lier)
1427 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001428 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001429 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001430 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1431 msync_session_update_apts(avsync->fd, systime, pts, 0);
1432 log_info("[%d] audio switch done sys %u pts %u",
1433 avsync->session_id, systime, pts);
1434 msync_session_set_audio_switch(avsync->fd, false);
1435 avsync->in_audio_switch = false;
1436 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1437 } else {
1438 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1439 avsync->session_id, action, systime, pts, systime - pts);
1440 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001441 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001442 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001443 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001444 avsync->last_disc_pts != pts &&
1445 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001446 log_info ("[%d]audio disc %u --> %u",
1447 avsync->session_id, systime, pts);
1448 msync_session_set_audio_dis(avsync->fd, pts);
1449 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001450 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001451 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001452
1453 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001454 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001455 if (!avsync->audio_drop_cnt)
1456 avsync->audio_drop_start = now;
1457 avsync->audio_drop_cnt++;
1458 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1459 log_info ("[%d]audio keep dropping sys %u vs a %u",
1460 avsync->session_id, systime, pts);
1461 msync_session_set_audio_dis(avsync->fd, pts);
1462 }
Song Zhao409739b2021-05-12 22:21:40 -07001463 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001464 if (action != AV_SYNC_AA_DROP)
1465 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001466 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001467 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001468 }
1469
1470 return ret;
1471}
1472
Song Zhaof3350d32023-08-18 16:27:31 -07001473int av_sync_get_pos(void *sync, pts90K *pts, uint64_t *mono_clock)
1474{
1475 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1476
1477 if (!avsync || !pts)
1478 return -1;
1479
1480 if (avsync->type != AV_SYNC_TYPE_AUDIO &&
1481 avsync->type != AV_SYNC_TYPE_VIDEO)
1482 return -2;
1483 return msync_session_get_pts(avsync->fd, pts,
1484 mono_clock, avsync->type == AV_SYNC_TYPE_VIDEO);
1485}
1486
Song Zhaoea5a0412021-01-18 16:40:08 -08001487int av_sync_get_clock(void *sync, pts90K *pts)
1488{
1489 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1490
1491 if (!avsync || !pts)
1492 return -1;
1493 return msync_session_get_wall(avsync->fd, pts, NULL);
1494}
1495
1496static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001497 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001498 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001499{
Song Zhao76005282022-03-08 16:49:41 -08001500 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1501 avsync->session_id, avsync->active_mode, avsync->mode,
1502 v_active, a_active, v_timeout, stat);
1503
1504 /* iptv delayed start */
1505 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1506 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1507
Song Zhaoea5a0412021-01-18 16:40:08 -08001508 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1509 float speed;
Song Zhao7e8c68f2022-07-12 16:24:30 -07001510 if (a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001511 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001512 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhao6183ca92022-07-29 09:57:03 -07001513 } else if (!a_active && !avsync->session_started) {
1514 /* quit waiting ASAP */
1515 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoea5a0412021-01-18 16:40:08 -08001516 }
1517
1518 if (!msync_session_get_rate(avsync->fd, &speed)) {
1519 /* speed change is triggered by asink,
1520 * attached audio HAL will handle it
1521 */
1522 if (speed != avsync->speed)
1523 log_info("[%d]new rate %f", avsync->session_id, speed);
Song Zhaoa73fcf32023-01-13 08:12:26 -08001524#if 0 //don't use freerun for trick mode. Or A/V gap will keep increasing
Song Zhaoea5a0412021-01-18 16:40:08 -08001525 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001526 if (avsync->mode != avsync->backup_mode) {
1527 avsync->mode = avsync->backup_mode;
1528 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1529 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001530 } else {
1531 avsync->backup_mode = avsync->mode;
1532 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1533 log_info("[%d]audio to freerun mode", avsync->session_id);
1534 }
Song Zhaoa73fcf32023-01-13 08:12:26 -08001535#endif
Song Zhaoea5a0412021-01-18 16:40:08 -08001536 avsync->speed = speed;
1537 }
Song Zhaod62bb392021-04-23 12:25:49 -07001538 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1539 struct session_debug debug;
1540 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001541 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001542 avsync->backup_mode = avsync->mode;
1543 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001544 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001545 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001546 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001547 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001548 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001549 log_warn("[%d]audio back to mode %d",
1550 avsync->session_id, avsync->mode);
1551 }
1552 }
Song Zhao76005282022-03-08 16:49:41 -08001553 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1554 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaob8833c12024-02-02 21:54:36 +00001555 if (a_active && avsync->audio_start) {
1556 if (v_active || v_timeout) {
1557 log_info("audio start cb");
1558 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1559 }
1560 }
1561
Song Zhaoea5a0412021-01-18 16:40:08 -08001562 }
1563}
1564
1565static void handle_mode_change_v(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 Zhaoe0bf6ad2021-07-09 11:28:42 -07001569 struct session_debug debug;
1570
Song Zhao76005282022-03-08 16:49:41 -08001571 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1572 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001573 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1574 if (debug.debug_freerun && !avsync->debug_freerun) {
1575 avsync->backup_mode = avsync->mode;
1576 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1577 avsync->debug_freerun = true;
1578 log_warn("[%d]video to freerun mode", avsync->session_id);
1579 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1580 avsync->mode = avsync->backup_mode;
1581 avsync->debug_freerun = false;
1582 log_warn("[%d]video back to mode %d",
1583 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001584 }
1585 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001586}
1587
1588static void * poll_thread(void * arg)
1589{
1590 int ret = 0;
1591 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1592 const int fd = avsync->fd;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001593 int poll_timeout = 10;
Song Zhaoea5a0412021-01-18 16:40:08 -08001594 struct pollfd pfd = {
1595 /* default blocking capture */
Song Zhao4bd18762022-09-30 16:39:52 -07001596 .events = POLLPRI,
Song Zhaoea5a0412021-01-18 16:40:08 -08001597 .fd = avsync->fd,
1598 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001599 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001600
Song Zhaoea5a0412021-01-18 16:40:08 -08001601 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001602
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001603 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001604 prctl (PR_SET_NAME, "avs_apoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001605 sflag = SRC_A;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001606 } else if (avsync->type == AV_SYNC_TYPE_VIDEO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001607 prctl (PR_SET_NAME, "avs_vpoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001608 sflag = SRC_V;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001609 poll_timeout = 100;
1610 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001611
Song Zhaoea5a0412021-01-18 16:40:08 -08001612 while (!avsync->quit_poll) {
1613 for (;;) {
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001614 ret = poll(&pfd, 1, poll_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001615 if (ret > 0)
1616 break;
1617 if (avsync->quit_poll)
1618 goto exit;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001619 if (errno == EINTR) {
1620 log_debug("[%d] poll interrupted", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001621 continue;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001622 }
Song Zhao4bd18762022-09-30 16:39:52 -07001623 if (errno == EAGAIN || errno == ENOMEM) {
1624 log_info("[%d] poll error %d", avsync->session_id, errno);
1625 continue;
1626 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001627 }
1628
1629 /* error handling */
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001630 if (pfd.revents & POLLERR) {
1631 usleep(poll_timeout * 1000);
1632 continue;
1633 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001634
Song Zhao4bd18762022-09-30 16:39:52 -07001635 if (pfd.revents & POLLNVAL) {
1636 log_warn("[%d] fd closed", avsync->session_id);
1637 goto exit;
1638 }
Song Zhaod62bb392021-04-23 12:25:49 -07001639 /* mode change. Non-exclusive wait so all the processes
1640 * shall be woken up
1641 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001642 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001643 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001644 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001645
Song Zhao9fef59c2022-08-17 12:43:10 -07001646 msync_session_get_stat(fd, true, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001647 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001648
1649 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001650 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001651 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001652 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001653 usleep(10000);
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001654 } else {
1655 log_debug("[%d] unexpected revents %x", avsync->session_id, pfd.revents);
1656 usleep(poll_timeout * 1000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001657 }
1658 }
1659exit:
1660 log_info("[%d]quit", avsync->session_id);
1661 return NULL;
1662}
1663
Song Zhao623e2f12021-09-03 15:54:04 -07001664#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1665/* return ppm between demod and PCR clock */
1666int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1667{
1668 int fd = -1, ppm = 0, nread;
1669 char buf[128];
1670 uint32_t reg_v, lock;
1671 float val;
1672
1673 fd = open(DEMOD_NODE, O_RDWR);
1674 if (fd < 0) {
1675 log_warn("node not found %s", DEMOD_NODE);
1676 /* do not retry */
1677 avsync->ppm_adjusted = true;
1678 return 0;
1679 }
1680 snprintf(buf, sizeof(buf), "%d", 5);
1681 write(fd, buf, 2);
1682
1683 lseek(fd, 0, SEEK_SET);
1684
hanghang.luo02efd312022-08-26 09:49:53 +08001685 nread = read(fd, buf, sizeof(buf)-1);
Song Zhao623e2f12021-09-03 15:54:04 -07001686 if (nread <= 0) {
1687 log_error("read error");
1688 goto err;
1689 }
1690 buf[nread] = 0;
1691 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1692 log_error("wrong format %s", buf);
1693 goto err;
1694 }
1695 if (lock != 0x1f) {
1696 log_info("demod not locked");
1697 goto err;
1698 }
1699 if (reg_v > ((2 << 20) - 1))
1700 reg_v -= (2 << 21);
1701 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1702 ppm = val;
1703 log_info("ppm from SFO %d", ppm);
1704 avsync->ppm_adjusted = true;
1705
1706err:
1707 if (fd >= 0)
1708 close(fd);
1709 return ppm;
1710}
1711
Song Zhaod62bb392021-04-23 12:25:49 -07001712int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001713{
1714 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001715 struct pcr_info pcr;
1716 enum pcr_monitor_status status;
1717 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001718 if (!avsync)
1719 return -1;
1720
1721 if (avsync->type != AV_SYNC_TYPE_PCR)
1722 return -2;
1723
Song Zhao623e2f12021-09-03 15:54:04 -07001724 /* initial estimation from Demod SFO HW */
1725 if (!avsync->ppm_adjusted) {
1726 ppm = dmod_get_sfo_dev(avsync);
1727 if (ppm != 0) {
1728 /* ppm > 0 means board clock is faster */
1729 msync_session_set_clock_dev(avsync->fd, -ppm);
1730 }
1731 }
wei.dubcc2ed22021-05-19 07:16:10 -04001732 pcr.monoclk = mono_clock / 1000;
1733 pcr.pts = (long long) pts * 1000 / 90;
1734 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1735
1736 status = pcr_monitor_get_status(avsync->pcr_monitor);
1737
1738 if (status >= DEVIATION_READY) {
1739 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1740 if (avsync->ppm != ppm) {
1741 avsync->ppm = ppm;
1742 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1743 if (msync_session_set_clock_dev(avsync->fd, ppm))
1744 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001745 else
1746 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001747 }
1748 }
1749
Song Zhaod62bb392021-04-23 12:25:49 -07001750 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001751}
1752
Song Zhaod62bb392021-04-23 12:25:49 -07001753int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001754{
1755 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1756
1757 if (!avsync)
1758 return -1;
1759
Song Zhaod62bb392021-04-23 12:25:49 -07001760 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001761}
1762
1763int av_sync_set_session_name(void *sync, const char *name)
1764{
1765 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1766
1767 if (!avsync)
1768 return -1;
1769
1770 return msync_session_set_name(avsync->fd, name);
1771}
yongchun.li107a6162021-05-05 02:38:57 -07001772
1773int av_sync_set_audio_switch(void *sync, bool start)
1774{
1775 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1776 bool v_active, a_active, v_timeout;
1777
1778 if (!avsync)
1779 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001780 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001781 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001782 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001783 log_error("[%d] can not get session state",
1784 avsync->session_id);
1785 return -1;
1786 }
1787 if (!v_active || !a_active) {
1788 log_error("[%d] no apply if not AV both active v %d a %d",
1789 avsync->session_id, v_active, a_active);
1790 return -1;
1791 }
1792 if (msync_session_set_audio_switch(avsync->fd, start)) {
1793 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1794 return -1;
1795 }
1796 avsync->in_audio_switch = start;
1797 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1798 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1799 return 0;
1800}
1801
1802int av_sync_get_audio_switch(void *sync, bool *start)
1803{
1804 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1805
1806 if (!avsync)
1807 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001808 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001809 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001810 log_error("[%d] can not audio seamless switch state",
1811 avsync->session_id);
1812 return -1;
1813 }
1814 if (start) *start = avsync->in_audio_switch;
1815 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001816}
Song Zhao8039f562021-05-18 18:11:25 -07001817
Song Zhao623e2f12021-09-03 15:54:04 -07001818enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001819{
1820 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1821
wei.dubcc2ed22021-05-19 07:16:10 -04001822 if (!avsync || !ppm)
1823 return CLK_RECOVERY_ERR;
1824 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001825 return CLK_RECOVERY_NOT_RUNNING;
1826
wei.dubcc2ed22021-05-19 07:16:10 -04001827 if (msync_session_get_clock_dev(avsync->fd, ppm))
1828 return CLK_RECOVERY_ERR;
1829
1830 if (*ppm == 0)
1831 return CLK_RECOVERY_ONGOING;
1832 else
1833 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001834}
Song Zhao95bd0922021-09-21 14:07:46 -07001835
1836static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1837{
1838 int ret;
1839
1840 if (!avsync->frame_q) {
1841 avsync->frame_q = create_q(MAX_FRAME_NUM);
1842 if (!avsync->frame_q) {
1843 log_error("[%d]create queue fail", avsync->session_id);
1844
1845 return -1;
1846 }
1847 }
1848
1849 ret = queue_item(avsync->frame_q, frame);
1850 if (ret)
hanghang.luo02efd312022-08-26 09:49:53 +08001851 log_error("queue fail:%d", ret);
Song Zhao95bd0922021-09-21 14:07:46 -07001852 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1853 return ret;
1854}
1855
1856int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1857{
1858 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1859
1860 if (!avsync)
1861 return -1;
1862 avsync->msys = msys;
1863 return 0;
1864}
1865
1866static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1867{
1868 struct vframe *frame = NULL, *enter_last_frame = NULL;
1869 uint64_t systime;
1870 int toggle_cnt = 0;
1871
1872 enter_last_frame = avsync->last_frame;
1873 systime = avsync->msys;
1874 log_debug("[%d]sys %llu", avsync->session_id, systime);
1875 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1876 if (systime >= frame->mts) {
1877 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1878 toggle_cnt++;
1879
1880 if (avsync->last_frame)
1881 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1882
1883 dqueue_item(avsync->frame_q, (void **)&frame);
1884 if (avsync->last_frame) {
1885 /* free frame that are not for display */
1886 if (toggle_cnt > 1) {
1887 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1888 avsync->last_frame->mts, frame->mts, systime);
1889 avsync->last_frame->free(avsync->last_frame);
1890 }
1891 } else {
1892 avsync->first_frame_toggled = true;
1893 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1894 }
1895 avsync->last_frame = frame;
1896 } else
1897 break;
1898 }
1899
1900 if (avsync->last_frame) {
1901 if (enter_last_frame != avsync->last_frame)
hanghang.luo02efd312022-08-26 09:49:53 +08001902 log_debug("[%d]pop %lu", avsync->session_id, avsync->last_frame->pts);
1903 log_trace("[%d]pop=%llu, system=%llu, diff %llu(ms), QNum=%d", avsync->session_id,
Song Zhao95bd0922021-09-21 14:07:46 -07001904 avsync->last_frame->mts,
1905 systime, (systime - avsync->last_frame->mts) / 1000000,
1906 queue_size(avsync->frame_q));
1907 } else
1908 if (enter_last_frame != avsync->last_frame)
1909 log_debug("[%d]pop (nil)", avsync->session_id);
1910
1911 if (avsync->last_frame)
1912 avsync->last_frame->hold_period++;
1913 return avsync->last_frame;
1914}
Song Zhao6183ca92022-07-29 09:57:03 -07001915
1916int avs_sync_stop_audio(void *sync)
1917{
1918 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1919
1920 if (!avsync)
1921 return -1;
1922
1923 return msync_session_stop_audio(avsync->fd);
1924}
bo.xiao05ba1ac2022-12-13 14:38:13 +08001925
1926int avs_sync_set_eos(void *sync)
1927{
1928 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1929
1930 if (!avsync)
1931 return -1;
1932
1933 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
1934 if (avsync->state == AV_SYNC_STAT_INIT) {
1935 avsync->state = AV_SYNC_STAT_RUNNING;
1936 log_debug("[%d]eos trigger state change: init --> running", avsync->session_id);
1937 }
1938 }
1939
1940 return 0;
1941}