blob: fcf139b407db37ce25ff3ed133b7cd58c9799ee4 [file] [log] [blame]
Song Zhaoc03ba122020-12-23 21:54:02 -08001/*
bo.xiao00387eb2023-02-24 18:44:29 +08002 * Copyright (C) 2021 Amlogic Corporation.
Song Zhaoc03ba122020-12-23 21:54:02 -08003 *
bo.xiao00387eb2023-02-24 18:44:29 +08004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Song Zhaoc03ba122020-12-23 21:54:02 -08007 *
bo.xiao00387eb2023-02-24 18:44:29 +08008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Song Zhaoc03ba122020-12-23 21:54:02 -080015 */
Song Zhaoea5a0412021-01-18 16:40:08 -080016#include <errno.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080017#include <pthread.h>
18#include <stdbool.h>
19#include <stdlib.h>
20#include <stdio.h>
21#include <sys/time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080022#include <poll.h>
23#include <fcntl.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <sys/prctl.h>
27#include <sys/ioctl.h>
Song Zhaoa2985cb2021-06-24 12:01:47 -070028#include <time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080029#include <unistd.h>
30//#include <linux/amlogic/msync.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080031#include "aml_avsync.h"
Song Zhao4f632952021-12-16 09:00:18 -080032#include "aml_queue.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080033#include "pattern.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080034#include "aml_avsync_log.h"
Song Zhaoea5a0412021-01-18 16:40:08 -080035#include "msync_util.h"
36#include "msync.h"
37#include <pthread.h>
wei.dubcc2ed22021-05-19 07:16:10 -040038#include "pcr_monitor.h"
fei.deng66b4e812022-04-14 12:23:01 +080039#include "aml_version.h"
Song Zhao2f6744b2021-11-03 21:23:50 -070040
Song Zhaoc03ba122020-12-23 21:54:02 -080041enum sync_state {
42 AV_SYNC_STAT_INIT = 0,
43 AV_SYNC_STAT_RUNNING = 1,
44 AV_SYNC_STAT_SYNC_SETUP = 2,
45 AV_SYNC_STAT_SYNC_LOST = 3,
46};
47
yongchun.li107a6162021-05-05 02:38:57 -070048enum audio_switch_state_ {
49 AUDIO_SWITCH_STAT_INIT = 0,
50 AUDIO_SWITCH_STAT_RESET = 1,
51 AUDIO_SWITCH_STAT_START = 2,
52 AUDIO_SWITCH_STAT_FINISH = 3,
yongchun.li59e873d2021-07-07 11:42:38 -070053 AUDIO_SWITCH_STAT_AGAIN = 4,
yongchun.li107a6162021-05-05 02:38:57 -070054};
55
Song Zhaoea5a0412021-01-18 16:40:08 -080056#define SESSION_DEV "avsync_s"
57
Song Zhaoc03ba122020-12-23 21:54:02 -080058struct av_sync_session {
59 /* session id attached */
60 int session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -080061 int fd;
62 bool attached;
63 enum sync_mode mode;
64 /* for audio trickplay */
65 enum sync_mode backup_mode;
66 enum sync_type type;
67 uint32_t start_policy;
bo.xiao5821fc72021-07-11 22:47:00 -040068 int timeout;
Song Zhaoc03ba122020-12-23 21:54:02 -080069
Song Zhaoea5a0412021-01-18 16:40:08 -080070 /* playback time, will stop increasing during pause */
71 pts90K vpts;
72 pts90K apts;
73
74 /* phase adjustment of stream time for rate control (Video ONLY) */
Song Zhaoc03ba122020-12-23 21:54:02 -080075 pts90K phase;
76 bool phase_set;
Song Zhao1561e542022-01-12 10:37:55 -080077 bool phase_adjusted;
Song Zhaoc03ba122020-12-23 21:54:02 -080078
79 /* pts of last rendered frame */
Song Zhaoea5a0412021-01-18 16:40:08 -080080 pts90K last_wall;
Song Zhaoc03ba122020-12-23 21:54:02 -080081 pts90K last_pts;
82 struct vframe *last_frame;
83
Song Zhaoe0bf6ad2021-07-09 11:28:42 -070084 /* pts of last pushed frame */
85 pts90K last_q_pts;
86
Song Zhaoc03ba122020-12-23 21:54:02 -080087 bool first_frame_toggled;
Song Zhaoc03ba122020-12-23 21:54:02 -080088 bool paused;
Song Zhaoea5a0412021-01-18 16:40:08 -080089 enum sync_state state;
Song Zhaoc03ba122020-12-23 21:54:02 -080090 void *pattern_detector;
91 void *frame_q;
Song Zhaoc03ba122020-12-23 21:54:02 -080092
Song Zhaoea5a0412021-01-18 16:40:08 -080093 /* start control */
94 int start_thres;
95 audio_start_cb audio_start;
96 void *audio_start_priv;
97
98 /* render property */
Song Zhaoc03ba122020-12-23 21:54:02 -080099 int delay;
Song Zhao6dce2672022-01-13 11:32:44 -0800100 int extra_delay;
Song Zhaoc03ba122020-12-23 21:54:02 -0800101 pts90K vsync_interval;
102
103 /* state lock */
104 pthread_mutex_t lock;
105 /* pattern */
106 int last_holding_peroid;
Song Zhaoea5a0412021-01-18 16:40:08 -0800107 bool session_started;
Song Zhaoc03ba122020-12-23 21:54:02 -0800108
109 float speed;
110
Song Zhaoc03ba122020-12-23 21:54:02 -0800111 /* pause pts */
112 pts90K pause_pts;
113 pause_pts_done pause_pts_cb;
114 void *pause_cb_priv;
yongchun.li428390d2022-02-17 17:15:40 -0800115 /* underflow */
116 underflow_detected underflow_cb;
117 void *underflow_cb_priv;
118 struct underflow_config underflow_cfg;
119 struct timespec frame_last_update_time;
Song Zhao5d2b4772021-01-18 16:40:08 -0800120
121 /* log control */
Song Zhaoa2985cb2021-06-24 12:01:47 -0700122 uint32_t last_log_syst;
Song Zhao5d2b4772021-01-18 16:40:08 -0800123 uint32_t sync_lost_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700124 struct timespec sync_lost_print_time;
Song Zhaoea5a0412021-01-18 16:40:08 -0800125
126 pthread_t poll_thread;
127 /* pcr master, IPTV only */
128 bool quit_poll;
129 enum sync_mode active_mode;
Song Zhaof46932e2021-05-21 01:51:45 -0700130 uint32_t disc_thres_min;
131 uint32_t disc_thres_max;
Song Zhao35a82df2021-04-15 10:58:49 -0700132
133 /* error detection */
134 uint32_t last_poptime;
Song Zhaod62bb392021-04-23 12:25:49 -0700135 uint32_t outlier_cnt;
Song Zhao409739b2021-05-12 22:21:40 -0700136 pts90K last_disc_pts;
137
yongchun.li107a6162021-05-05 02:38:57 -0700138 // indicate set audio switch
139 bool in_audio_switch;
140 enum audio_switch_state_ audio_switch_state;
wei.dubcc2ed22021-05-19 07:16:10 -0400141
142 //pcr monitor handle
143 void *pcr_monitor;
144 int ppm;
Song Zhao623e2f12021-09-03 15:54:04 -0700145 bool ppm_adjusted;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700146
147 //video FPS detection
148 pts90K last_fpts;
149 int fps_interval;
150 int fps_interval_acc;
151 int fps_cnt;
152
153 //video freerun with rate control
154 uint32_t last_r_syst;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700155 bool debug_freerun;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700156
157 //Audio dropping detection
158 uint32_t audio_drop_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700159 struct timespec audio_drop_start;
Song Zhao95bd0922021-09-21 14:07:46 -0700160
161 /*system mono time for current vsync interrupt */
162 uint64_t msys;
Song Zhaoc03ba122020-12-23 21:54:02 -0800163};
164
165#define MAX_FRAME_NUM 32
166#define DEFAULT_START_THRESHOLD 2
167#define TIME_UNIT90K (90000)
Song Zhaoa73fcf32023-01-13 08:12:26 -0800168#define DEFAULT_WALL_ADJ_THRES (TIME_UNIT90K / 10) //100ms
Song Zhaof46932e2021-05-21 01:51:45 -0700169#define AV_DISC_THRES_MIN (TIME_UNIT90K / 3)
170#define AV_DISC_THRES_MAX (TIME_UNIT90K * 10)
Song Zhao7daf3a12021-05-10 22:22:25 -0700171#define A_ADJ_THREDHOLD_HB (900 * 6) //60ms
172#define A_ADJ_THREDHOLD_LB (900 * 2) //20ms
Song Zhao4bd18762022-09-30 16:39:52 -0700173#define A_ADJ_THREDHOLD_MB (900 * 3) //30ms
Song Zhao52f55192021-05-06 10:52:21 -0700174#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800175#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhao76005282022-03-08 16:49:41 -0800176#define LIVE_MODE(m) ((m) == AV_SYNC_MODE_PCR_MASTER || (m) == AV_SYNC_MODE_IPTV)
Song Zhao7e24b182022-04-01 08:46:40 -0700177#define V_DISC_MODE(mode) (LIVE_MODE(mode) || (mode) == AV_SYNC_MODE_VMASTER)
Song Zhaod62bb392021-04-23 12:25:49 -0700178
Song Zhao065800e2021-05-26 15:56:06 -0700179#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
Song Zhaod62bb392021-04-23 12:25:49 -0700180#define OUTLIER_MAX_CNT 8
Song Zhaoa2985cb2021-06-24 12:01:47 -0700181#define VALID_TS(x) ((x) != -1)
yongchun.li428390d2022-02-17 17:15:40 -0800182#define UNDERFLOW_CHECK_THRESH_MS (100)
Song Zhaoc03ba122020-12-23 21:54:02 -0800183
yongchun.li0ee6e372021-08-20 04:26:04 -0700184static uint64_t time_diff (struct timespec *b, struct timespec *a);
Song Zhaoc03ba122020-12-23 21:54:02 -0800185static bool frame_expire(struct av_sync_session* avsync,
186 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800187 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800188 struct vframe * frame,
189 struct vframe * next_frame,
190 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700191static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800192 int cur_period,
193 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800194static void * poll_thread(void * arg);
195static void trigger_audio_start_cb(struct av_sync_session *avsync,
196 avs_ascb_reason reason);
Song Zhao95bd0922021-09-21 14:07:46 -0700197static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync);
198static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame);
fei.deng55389b62022-08-18 23:46:50 +0800199
Song Zhao2f6744b2021-11-03 21:23:50 -0700200pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER;
Song Zhaoc03ba122020-12-23 21:54:02 -0800201
Song Zhaoea5a0412021-01-18 16:40:08 -0800202int av_sync_open_session(int *session_id)
203{
Song Zhao2f6744b2021-11-03 21:23:50 -0700204 int fd = -1;
Song Zhaoea5a0412021-01-18 16:40:08 -0800205 int id, rc;
206
Song Zhao2f6744b2021-11-03 21:23:50 -0700207 pthread_mutex_lock(&glock);
208 fd = msync_create_session();
Song Zhaoea5a0412021-01-18 16:40:08 -0800209 if (fd < 0) {
210 log_error("fail");
Song Zhao2f6744b2021-11-03 21:23:50 -0700211 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800212 }
213 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
214 if (rc) {
215 log_error("new session errno:%d", errno);
Song Zhao2f6744b2021-11-03 21:23:50 -0700216 msync_destory_session(fd);
217 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800218 }
219 *session_id = id;
Song Zhao2f6744b2021-11-03 21:23:50 -0700220 log_debug("new avsession id %d fd %d", id, fd);
221exit:
222 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800223 return fd;
224}
225
226void av_sync_close_session(int session)
227{
Song Zhao2f6744b2021-11-03 21:23:50 -0700228 log_debug("session closed fd %d", session);
229 pthread_mutex_lock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800230 msync_destory_session(session);
Song Zhao2f6744b2021-11-03 21:23:50 -0700231 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800232}
233
234static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800235 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800236 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800237 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800238 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800239{
240 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800241 char dev_name[20];
Song Zhao2f6744b2021-11-03 21:23:50 -0700242 int retry = 10;
Song Zhaoc03ba122020-12-23 21:54:02 -0800243
fei.deng55389b62022-08-18 23:46:50 +0800244 /* debug log level */
245 {
246 const char *env= getenv( "AML_AVSYNC_DEBUG_LEVEL");
247 if ( env ) {
248 log_set_level(atoi(env));
249 }
250 }
251
Song Zhao95bd0922021-09-21 14:07:46 -0700252 log_info("[%d] mode %d type %d", session_id, mode, type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800253 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
254 if (!avsync) {
255 log_error("OOM");
256 return NULL;
257 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800258
Song Zhao95bd0922021-09-21 14:07:46 -0700259 if (type == AV_SYNC_TYPE_VIDEO &&
260 mode == AV_SYNC_MODE_VIDEO_MONO) {
261 if (session_id < AV_SYNC_SESSION_V_MONO) {
262 log_error("wrong session id %d", session_id);
263 goto err;
264 }
265 avsync->type = type;
266 avsync->mode = mode;
267 avsync->fd = -1;
268 avsync->session_id = session_id;
269 log_info("[%d]init", avsync->session_id);
270 return avsync;
271 }
272
Song Zhaoea5a0412021-01-18 16:40:08 -0800273 if (type == AV_SYNC_TYPE_VIDEO) {
Song Zhaobb3b4f32023-10-17 16:08:12 -0700274 int32_t interval = 1500;
275
276 if (msync_session_get_vsync_interval(&interval))
277 log_error("read interval error");
278 avsync->pattern_detector = create_pattern_detector(interval);
Song Zhaoea5a0412021-01-18 16:40:08 -0800279 if (!avsync->pattern_detector) {
280 log_error("pd create fail");
281 goto err;
282 }
283
284 if (!start_thres)
285 avsync->start_thres = DEFAULT_START_THRESHOLD;
286 else {
287 if (start_thres > 5) {
288 log_error("start_thres too big: %d", start_thres);
289 goto err2;
290 }
291 avsync->start_thres = start_thres;
292 }
293 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800294 avsync->phase_adjusted = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800295 avsync->first_frame_toggled = false;
Song Zhaofd007632022-09-30 16:21:30 -0700296
297 avsync->frame_q = create_q(MAX_FRAME_NUM);
298 if (!avsync->frame_q) {
299 log_error("[%d]create queue fail", avsync->session_id);
300 goto err2;
301 }
Song Zhaofd007632022-09-30 16:21:30 -0700302 {
303 int ret;
304
305 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
306 if (ret) {
307 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
308 goto err2;
309 }
310 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800311 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800312
313 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800314 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800315 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800316 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800317 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800318 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800319 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800320 avsync->speed = 1.0f;
321 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhao409739b2021-05-12 22:21:40 -0700322 avsync->vsync_interval = -1;
323 avsync->last_disc_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700324 avsync->last_log_syst = -1;
325 avsync->last_pts = -1;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700326 avsync->last_q_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700327 avsync->last_wall = -1;
328 avsync->fps_interval = -1;
329 avsync->last_r_syst = -1;
bo.xiao5821fc72021-07-11 22:47:00 -0400330 avsync->timeout = -1;
331
Song Zhaof46932e2021-05-21 01:51:45 -0700332 if (msync_session_get_disc_thres(session_id,
333 &avsync->disc_thres_min, &avsync->disc_thres_max)) {
hanghang.luo02efd312022-08-26 09:49:53 +0800334 log_error("dev_name:%s; errno:%d; fail to get disc thres", dev_name, errno);
Song Zhaof46932e2021-05-21 01:51:45 -0700335 avsync->disc_thres_min = AV_DISC_THRES_MIN;
336 avsync->disc_thres_max = AV_DISC_THRES_MAX;
337 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800338
339 pthread_mutex_init(&avsync->lock, NULL);
Song Zhao9c09f772022-01-07 14:26:50 -0800340 log_info("[%d] start_thres %d disc_thres %u/%u", session_id,
Song Zhao95bd0922021-09-21 14:07:46 -0700341 start_thres, avsync->disc_thres_min, avsync->disc_thres_max);
Song Zhaoea5a0412021-01-18 16:40:08 -0800342
343 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
Song Zhao2f6744b2021-11-03 21:23:50 -0700344 while (retry) {
345 /* wait for sysfs to update */
346 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
347 if (avsync->fd > 0)
348 break;
349
350 retry--;
351 if (!retry) {
352 log_error("open %s errno %d", dev_name, errno);
353 goto err2;
354 }
355 usleep(20000);
Song Zhaoea5a0412021-01-18 16:40:08 -0800356 }
357
wei.dubcc2ed22021-05-19 07:16:10 -0400358 if (avsync->type == AV_SYNC_TYPE_PCR) {
359 if (pcr_monitor_init(&avsync->pcr_monitor)) {
360 log_error("pcr monitor init");
Song Zhao9cd27a52021-07-26 15:27:38 +0000361 goto err3;
wei.dubcc2ed22021-05-19 07:16:10 -0400362 }
363 }
364
Song Zhaoea5a0412021-01-18 16:40:08 -0800365 if (!attach) {
366 msync_session_set_mode(avsync->fd, mode);
367 avsync->mode = mode;
Song Zhaob8833c12024-02-02 21:54:36 +0000368 if ((avsync->mode == AV_SYNC_MODE_VMASTER ||
369 avsync->mode == AV_SYNC_MODE_IPTV) &&
370 avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao7e24b182022-04-01 08:46:40 -0700371 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -0800372 } else {
373 avsync->attached = true;
374 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
375 log_error("get mode");
Song Zhao9cd27a52021-07-26 15:27:38 +0000376 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800377 }
378 avsync->backup_mode = avsync->mode;
bo.xiao5821fc72021-07-11 22:47:00 -0400379 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800380 log_error("get policy");
Song Zhao9cd27a52021-07-26 15:27:38 +0000381 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800382 }
Song Zhao9fef59c2022-08-17 12:43:10 -0700383 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700384 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -0700385 log_error("get state");
Song Zhao9cd27a52021-07-26 15:27:38 +0000386 goto err4;
yongchun.li107a6162021-05-05 02:38:57 -0700387 }
388 if (avsync->in_audio_switch) {
389 log_info("audio_switch_state reseted the audio");
390 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
391 }
392
Song Zhaoea5a0412021-01-18 16:40:08 -0800393 log_info("[%d]retrieve sync mode %d policy %d",
394 session_id, avsync->mode, avsync->start_policy);
395 }
396
Song Zhaoc03ba122020-12-23 21:54:02 -0800397 return avsync;
Song Zhao9cd27a52021-07-26 15:27:38 +0000398err4:
wei.dubcc2ed22021-05-19 07:16:10 -0400399 if (avsync->pcr_monitor)
400 pcr_monitor_destroy(avsync->pcr_monitor);
Song Zhao9cd27a52021-07-26 15:27:38 +0000401err3:
Song Zhaofd007632022-09-30 16:21:30 -0700402 if (avsync->fd)
403 close(avsync->fd);
Song Zhaoea5a0412021-01-18 16:40:08 -0800404err2:
Song Zhaofd007632022-09-30 16:21:30 -0700405 avsync->quit_poll = true;
406 if (avsync->poll_thread) {
407 pthread_join(avsync->poll_thread, NULL);
408 avsync->poll_thread = 0;
409 }
410 if (avsync->frame_q)
411 destroy_q(avsync->frame_q);
412 if (avsync->pattern_detector)
413 destroy_pattern_detector(avsync->pattern_detector);
Song Zhaoea5a0412021-01-18 16:40:08 -0800414err:
415 free(avsync);
416 return NULL;
417}
418
419void* av_sync_create(int session_id,
420 enum sync_mode mode,
421 enum sync_type type,
422 int start_thres)
423{
424 return create_internal(session_id, mode,
425 type, start_thres, false);
426}
427
428void* av_sync_attach(int session_id, enum sync_type type)
429{
Song Zhao95bd0922021-09-21 14:07:46 -0700430 if (type == AV_SYNC_TYPE_VIDEO)
431 return NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800432 return create_internal(session_id, AV_SYNC_MODE_MAX,
433 type, 0, true);
434}
435
436int av_sync_video_config(void *sync, struct video_config* config)
437{
438 struct av_sync_session *avsync = (struct av_sync_session *)sync;
439
440 if (!avsync || !config)
441 return -1;
442
443 if (config->delay != 1 && config->delay != 2) {
444 log_error("invalid delay: %d\n", config->delay);
445 return -1;
446 }
447
448 avsync->delay = config->delay;
Song Zhao6dce2672022-01-13 11:32:44 -0800449 avsync->extra_delay = config->extra_delay * 90;
Song Zhaoea5a0412021-01-18 16:40:08 -0800450
Song Zhao6dce2672022-01-13 11:32:44 -0800451 log_info("[%d] vsync delay: %d extra_delay: %d ms",
452 avsync->session_id, config->delay, config->extra_delay);
Song Zhaoea5a0412021-01-18 16:40:08 -0800453 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800454}
455
456static int internal_stop(struct av_sync_session *avsync)
457{
458 int ret = 0;
459 struct vframe *frame;
460
461 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800462 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
463 frame->free(frame);
464 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800465 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800466 pthread_mutex_unlock(&avsync->lock);
467 return ret;
468}
469
470/* destroy and detach from kernel session */
471void av_sync_destroy(void *sync)
472{
473 struct av_sync_session *avsync = (struct av_sync_session *)sync;
474
475 if (!avsync)
476 return;
477
Song Zhao95bd0922021-09-21 14:07:46 -0700478 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
479 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
480 log_info("[%d]done", avsync->session_id);
481 internal_stop(avsync);
482 destroy_q(avsync->frame_q);
483 free(avsync);
484 return;
485 }
Song Zhaob5458b32021-11-12 15:58:47 -0800486 log_info("[%d]begin type %d", avsync->session_id, avsync->type);
Song Zhao6be9ac22022-09-30 16:44:50 -0700487 if (avsync->type == AV_SYNC_TYPE_VIDEO)
488 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800489
Song Zhao6be9ac22022-09-30 16:44:50 -0700490 avsync->quit_poll = true;
491 if (avsync->poll_thread) {
492 pthread_join(avsync->poll_thread, NULL);
493 avsync->poll_thread = 0;
Song Zhaoaf368d52021-02-17 17:53:45 -0800494 }
Song Zhao6be9ac22022-09-30 16:44:50 -0700495 if (avsync->type == AV_SYNC_TYPE_AUDIO)
496 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoc03ba122020-12-23 21:54:02 -0800497
Song Zhaoea5a0412021-01-18 16:40:08 -0800498 if (avsync->session_started) {
499 if (avsync->type == AV_SYNC_TYPE_VIDEO)
500 msync_session_set_video_stop(avsync->fd);
501 else
502 msync_session_set_audio_stop(avsync->fd);
503 }
wei.dubcc2ed22021-05-19 07:16:10 -0400504
505 if(avsync->pcr_monitor)
506 pcr_monitor_destroy(avsync->pcr_monitor);
507
Song Zhaoea5a0412021-01-18 16:40:08 -0800508 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800509 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800510 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
511 destroy_q(avsync->frame_q);
512 destroy_pattern_detector(avsync->pattern_detector);
513 }
Song Zhaob5458b32021-11-12 15:58:47 -0800514 log_info("[%d]done type %d", avsync->session_id, avsync->type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800515 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800516}
517
bo.xiao5821fc72021-07-11 22:47:00 -0400518int avs_sync_set_start_policy(void *sync, struct start_policy* st_policy)
Song Zhaoea5a0412021-01-18 16:40:08 -0800519{
520 struct av_sync_session *avsync = (struct av_sync_session *)sync;
521
522 if (!avsync || !avsync->fd)
523 return -1;
524
Song Zhao47961d72022-08-29 14:04:44 -0700525 log_info("[%d]policy %u --> %u, timeout %d --> %d", avsync->session_id,
526 avsync->start_policy, st_policy->policy, avsync->timeout, st_policy->timeout);
Song Zhaof4e3c862022-09-01 14:00:11 -0700527 if (avsync->mode == AV_SYNC_MODE_IPTV &&
Song Zhao76005282022-03-08 16:49:41 -0800528 st_policy->policy != AV_SYNC_START_ASAP) {
529 log_error("policy %d not supported in live mode", st_policy->policy);
530 return -1;
531 }
532
Song Zhaof4e3c862022-09-01 14:00:11 -0700533 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
534 msync_session_set_start_thres(avsync->fd, st_policy->timeout);
535
bo.xiao5821fc72021-07-11 22:47:00 -0400536 avsync->start_policy = st_policy->policy;
537 avsync->timeout = st_policy->timeout;
Song Zhao76005282022-03-08 16:49:41 -0800538
Song Zhaoea5a0412021-01-18 16:40:08 -0800539 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400540 if (st_policy->policy != AV_SYNC_START_NONE &&
541 st_policy->policy != AV_SYNC_START_V_PEEK)
542 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800543
544 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800545}
546
547int av_sync_pause(void *sync, bool pause)
548{
549 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700550 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800551 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800552
Song Zhaob5458b32021-11-12 15:58:47 -0800553 if (!avsync) {
554 log_error("invalid handle");
Song Zhaoc03ba122020-12-23 21:54:02 -0800555 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800556 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800557
fei.deng55389b62022-08-18 23:46:50 +0800558 if (avsync->type == AV_SYNC_TYPE_VIDEO && avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
559 log_warn("ignore pause in video mono mode");
560 return -1;
561 }
562
Song Zhaob5458b32021-11-12 15:58:47 -0800563 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
564 log_warn("ignore pause in pcr master mode");
Song Zhaoea5a0412021-01-18 16:40:08 -0800565 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800566 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800567
Song Zhao9fef59c2022-08-17 12:43:10 -0700568 rc = msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -0700569 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700570 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700571
yongchun.li5f52fb02021-06-04 18:13:05 -0700572 /* ignore only when video try to pause when audio is acive, on which
573 the control of the STC will be relays.
574 When resume,it can do always as it is possible that video just
575 paused earlier without audio yet,then audio added later before resume.
576 We shall not igore that otherwise it could cause video freeze. */
577 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
578 avsync->type == AV_SYNC_TYPE_VIDEO &&
579 a_active &&
580 !avsync->in_audio_switch) {
581 if (!pause) {
582 log_info("[%d] clear video pause when audio active",
583 avsync->session_id);
584 avsync->paused = pause;
585 } else {
586 log_info("[%d] ignore the pause from video when audio active",
587 avsync->session_id);
588 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800589 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700590 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800591
yongchun.li107a6162021-05-05 02:38:57 -0700592 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
593 log_info("[%d] ignore the pause from audio", avsync->session_id);
594 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
595 return 0;
596 }
597
Song Zhaoea5a0412021-01-18 16:40:08 -0800598 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800599 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800600 log_info("[%d]paused:%d type:%d rc %d",
601 avsync->session_id, pause, avsync->type, rc);
yongchun.li428390d2022-02-17 17:15:40 -0800602 if (!avsync->paused && avsync->first_frame_toggled) {
603 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
604 log_info("[%d] resume update new frame time", avsync->session_id);
605 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800606 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800607}
608
609int av_sync_push_frame(void *sync , struct vframe *frame)
610{
611 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700612 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800613 struct av_sync_session *avsync = (struct av_sync_session *)sync;
614
615 if (!avsync)
616 return -1;
617
Song Zhao95bd0922021-09-21 14:07:46 -0700618 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
fei.deng55389b62022-08-18 23:46:50 +0800619 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
Song Zhao95bd0922021-09-21 14:07:46 -0700620 return video_mono_push_frame(avsync, frame);
fei.deng55389b62022-08-18 23:46:50 +0800621 }
Song Zhao95bd0922021-09-21 14:07:46 -0700622
Song Zhaofd007632022-09-30 16:21:30 -0700623 if (avsync->state == AV_SYNC_STAT_INIT && !queue_size(avsync->frame_q)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800624 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400625 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800626 log_error("[%d]get policy", avsync->session_id);
627 return -1;
628 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800629 }
630
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700631 if (avsync->last_q_pts != -1) {
Song Zhao7e24b182022-04-01 08:46:40 -0700632 if (frame->pts != -1 && avsync->mode == AV_SYNC_MODE_VMASTER) {
633 /* Sometimes app will fake PTS for trickplay, video PTS gap
634 * is really big depending on the speed. Have to adjust the
635 * threshold dynamically.
636 */
637 int gap = (int)(frame->pts - avsync->last_q_pts);
638 if (gap > avsync->disc_thres_min) {
639 avsync->disc_thres_min = gap * 6;
640 avsync->disc_thres_max = gap * 20;
641 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
642 msync_session_set_disc_thres(avsync->session_id,
643 avsync->disc_thres_min, avsync->disc_thres_max);
644 log_info("[%d] update disc_thres to %d/%d",avsync->session_id,
645 avsync->disc_thres_min, avsync->disc_thres_max);
646 }
647 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700648 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
649 /* TODO: wrong, should remove from back of queue */
le.hanebaea1e2023-07-10 07:26:09 +0000650 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800651 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700652 if (prev) {
653 prev->free(prev);
654 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
655 }
le.hanebaea1e2023-07-10 07:26:09 +0000656 pthread_mutex_unlock(&avsync->lock);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700657 } else if (avsync->fps_cnt < 100) {
658 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700659
660 if (interval > 0 && interval <= 4500) {
661 if (avsync->fps_interval_acc == -1) {
662 avsync->fps_interval_acc = interval;
663 avsync->fps_cnt = 1;
664 } else {
665 avsync->fps_interval_acc += interval;
666 avsync->fps_cnt++;
667 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
668 if (avsync->fps_cnt == 100)
669 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
670 }
671 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800672 }
673 }
674
Song Zhao065800e2021-05-26 15:56:06 -0700675 if (frame->duration == -1)
676 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800677 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700678 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800679 ret = queue_item(avsync->frame_q, frame);
680 if (avsync->state == AV_SYNC_STAT_INIT &&
681 queue_size(avsync->frame_q) >= avsync->start_thres) {
682 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaofd007632022-09-30 16:21:30 -0700683 log_debug("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800684 }
685
686 if (ret)
Song Zhaoe1b65602022-01-06 08:03:46 -0800687 log_error("queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400688 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800689 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800690}
691
692struct vframe *av_sync_pop_frame(void *sync)
693{
Song Zhaoea5a0412021-01-18 16:40:08 -0800694 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800695 struct av_sync_session *avsync = (struct av_sync_session *)sync;
696 int toggle_cnt = 0;
hanghang.luo02efd312022-08-26 09:49:53 +0800697 uint32_t systime = 0;
Song Zhao468fd652021-01-15 22:13:04 -0800698 bool pause_pts_reached = false;
hanghang.luo02efd312022-08-26 09:49:53 +0800699 uint32_t interval = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800700
Song Zhao95bd0922021-09-21 14:07:46 -0700701 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
702 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
703 return video_mono_pop_frame(avsync);
704
Song Zhaoc03ba122020-12-23 21:54:02 -0800705 pthread_mutex_lock(&avsync->lock);
706 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhao2f6744b2021-11-03 21:23:50 -0700707 log_debug("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800708 goto exit;
709 }
710
Song Zhaoea5a0412021-01-18 16:40:08 -0800711 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700712 uint32_t pts;
713
Song Zhaoc03ba122020-12-23 21:54:02 -0800714 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800715 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800716 goto exit;
717 }
Song Zhao35a82df2021-04-15 10:58:49 -0700718 msync_session_get_wall(avsync->fd, &systime, &interval);
719 pts = frame->pts - avsync->delay * interval;
720 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800721 avsync->session_started = true;
Song Zhao5296acf2024-02-02 21:45:04 +0000722 log_info("[%d]video start %u frame %u sys %u",
723 avsync->session_id, pts, frame->pts, systime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800724 }
725
Song Zhaoea5a0412021-01-18 16:40:08 -0800726 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700727 !avsync->first_frame_toggled &&
728 !msync_clock_started(avsync->fd)) {
729 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800730 log_trace("[%d]clock not started", avsync->session_id);
731 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800732 }
733
Song Zhaoea5a0412021-01-18 16:40:08 -0800734 enter_last_frame = avsync->last_frame;
735 msync_session_get_wall(avsync->fd, &systime, &interval);
736
737 /* handle refresh rate change */
738 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
739 avsync->vsync_interval != interval) {
740 log_info("[%d]vsync interval update %d --> %u",
741 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700742 if (avsync->fps_interval == -1)
743 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800744 avsync->vsync_interval = interval;
745 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800746 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700747 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800748 reset_pattern(avsync->pattern_detector);
749 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800750 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
751 struct vframe *next_frame = NULL;
752
753 peek_item(avsync->frame_q, (void **)&next_frame, 1);
754 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700755 log_debug("[%d]cur_f %u next_f %u size %d",
756 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800757 if (frame_expire(avsync, systime, interval,
758 frame, next_frame, toggle_cnt)) {
759 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800760 toggle_cnt++;
761
Song Zhao35a82df2021-04-15 10:58:49 -0700762 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800763 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700764 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700765 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700766 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
767 if (next_frame)
768 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
769 }
Song Zhao35a82df2021-04-15 10:58:49 -0700770
Song Zhaoc03ba122020-12-23 21:54:02 -0800771 if (avsync->last_frame)
772 avsync->last_holding_peroid = avsync->last_frame->hold_period;
773
774 dqueue_item(avsync->frame_q, (void **)&frame);
775 if (avsync->last_frame) {
Song Zhao5296acf2024-02-02 21:45:04 +0000776 int qsize = queue_size(avsync->frame_q);
777
Song Zhaoc03ba122020-12-23 21:54:02 -0800778 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800779 if (toggle_cnt > 1) {
Song Zhaofd007632022-09-30 16:21:30 -0700780 log_info("[%d]free %u cur %u system/d %u/%u queue size %d", avsync->session_id,
781 avsync->last_frame->pts, frame->pts,
782 systime, systime - avsync->last_poptime,
Song Zhao5296acf2024-02-02 21:45:04 +0000783 qsize);
Song Zhaoc03ba122020-12-23 21:54:02 -0800784 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800785 }
Song Zhao5296acf2024-02-02 21:45:04 +0000786 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER && qsize <= 1) {
787 msync_session_set_video_dis(avsync->fd, frame->pts);
788 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800789 } else {
790 avsync->first_frame_toggled = true;
Song Zhaofd007632022-09-30 16:21:30 -0700791 log_info("[%d]first frame %u queue size %d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800792 }
793 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800794 avsync->last_pts = frame->pts;
yongchun.li428390d2022-02-17 17:15:40 -0800795 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
Song Zhaoc03ba122020-12-23 21:54:02 -0800796 } else
797 break;
798 }
799
800 /* pause pts */
801 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800802 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800803 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800804 else
Song Zhao468fd652021-01-15 22:13:04 -0800805 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
806 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
807 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
808 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
809 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800810
Song Zhao468fd652021-01-15 22:13:04 -0800811 if (pause_pts_reached) {
Song Zhao468fd652021-01-15 22:13:04 -0800812 /* stay in paused until av_sync_pause(false) */
Song Zhaoa1742282022-09-30 16:17:26 -0700813 uint32_t local_pts = avsync->pause_pts;
Song Zhao468fd652021-01-15 22:13:04 -0800814 avsync->paused = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800815 log_info ("[%d]reach pause pts: %u",
Song Zhaob5458b32021-11-12 15:58:47 -0800816 avsync->session_id, avsync->pause_pts);
Song Zhaoad7c8232021-12-14 11:46:48 -0800817 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoa1742282022-09-30 16:17:26 -0700818 if (avsync->pause_pts_cb)
819 avsync->pause_pts_cb(local_pts,
820 avsync->pause_cb_priv);
821 log_info ("[%d] reach pause pts: %u handle done",
822 avsync->session_id, local_pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800823 }
824
825exit:
826 pthread_mutex_unlock(&avsync->lock);
yongchun.li428390d2022-02-17 17:15:40 -0800827
828 /* underflow check */
829 if (avsync->session_started && avsync->first_frame_toggled &&
830 (avsync->paused == false) && (avsync->state >= AV_SYNC_STAT_RUNNING) &&
831 avsync->underflow_cb && peek_item(avsync->frame_q, (void **)&frame, 0))
832 {/* empty queue in normal play */
833 struct timespec now;
834 int diff_ms;
835 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
836 diff_ms = time_diff(&now, &avsync->frame_last_update_time)/1000;
837 if(diff_ms >= (avsync->underflow_cfg.time_thresh
838 + avsync->vsync_interval*avsync->last_holding_peroid/90)) {
839 log_info ("[%d]underflow detected: %u", avsync->session_id, avsync->last_pts);
840 avsync->underflow_cb (avsync->last_pts,
841 avsync->underflow_cb_priv);
842 /* update time to control the underflow check call backs */
843 avsync->frame_last_update_time = now;
844 }
845 }
846
Song Zhaoc03ba122020-12-23 21:54:02 -0800847 if (avsync->last_frame) {
Song Zhaof3350d32023-08-18 16:27:31 -0700848 if (enter_last_frame != avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800849 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhaof3350d32023-08-18 16:27:31 -0700850 /* don't update vpts for out_lier */
851 if (avsync->last_frame->duration != -1)
852 msync_session_update_vpts(avsync->fd, systime,
853 avsync->last_frame->pts + avsync->extra_delay, interval * avsync->delay);
854 }
bo.xiao1f94b352021-08-02 03:53:47 -0400855 log_trace("[%d]pop=%u, stc=%u, QNum=%d", avsync->session_id, avsync->last_frame->pts, systime, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800856 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800857 if (enter_last_frame != avsync->last_frame)
858 log_debug("[%d]pop (nil)", avsync->session_id);
859
Song Zhao35a82df2021-04-15 10:58:49 -0700860 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800861 if (avsync->last_frame)
862 avsync->last_frame->hold_period++;
863 return avsync->last_frame;
864}
865
Song Zhaoc03ba122020-12-23 21:54:02 -0800866static inline uint32_t abs_diff(uint32_t a, uint32_t b)
867{
Song Zhaoea5a0412021-01-18 16:40:08 -0800868 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800869}
870
yongchun.li0ee6e372021-08-20 04:26:04 -0700871static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800872{
hanghang.luo02efd312022-08-26 09:49:53 +0800873 return (uint64_t)(b->tv_sec - a->tv_sec)*1000000 + (b->tv_nsec/1000 - a->tv_nsec/1000);
Song Zhaoc03ba122020-12-23 21:54:02 -0800874}
875
Song Zhaoc03ba122020-12-23 21:54:02 -0800876static bool frame_expire(struct av_sync_session* avsync,
877 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800878 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800879 struct vframe * frame,
880 struct vframe * next_frame,
881 int toggle_cnt)
882{
Song Zhao6dce2672022-01-13 11:32:44 -0800883 uint32_t fpts = frame->pts + avsync->extra_delay;
884 uint32_t nfpts = -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800885 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800886 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800887
888 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
889 return false;
890
891 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
892 return true;
893
Song Zhaoad7c8232021-12-14 11:46:48 -0800894 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS &&
895 avsync->pause_pts == frame->pts)
896 return true;
897
Song Zhao08fa16b2021-12-08 14:30:17 -0800898 if (systime == AV_SYNC_INVALID_PTS &&
899 avsync->mode == AV_SYNC_MODE_AMASTER)
900 return false;
901
Song Zhao6dce2672022-01-13 11:32:44 -0800902 if (next_frame)
903 nfpts = next_frame->pts + avsync->extra_delay;
904
Song Zhao7e24b182022-04-01 08:46:40 -0700905 if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
fei.deng63e43e12021-09-23 19:44:01 +0800906 /* We need to ensure that the video outputs smoothly,
907 so output video frame by frame hold_period */
908 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
909 avsync->last_frame &&
910 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
911 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
912 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700913 return true;
914 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700915 }
916
Song Zhaoc03ba122020-12-23 21:54:02 -0800917 if (!fpts) {
918 if (avsync->last_frame) {
919 /* try to accumulate duration as PTS */
920 fpts = avsync->vpts + avsync->last_frame->duration;
921 } else {
922 fpts = avsync->vpts;
923 }
924 }
925 systime += pts_correction;
926
927 /* phase adjustment */
928 if (avsync->phase_set)
929 systime += avsync->phase;
930
yongchun.lia50b1e92021-08-07 01:11:54 +0000931 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800932 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000933 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700934 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800935 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800936 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800937 return false;
938
Song Zhaoa2985cb2021-06-24 12:01:47 -0700939 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
940 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700941 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800942
yongchun.li0ee6e372021-08-20 04:26:04 -0700943 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700944 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800945 avsync->last_pts = fpts;
946 if (time_diff(&now, &avsync->sync_lost_print_time) >=
947 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700948 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800949 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800950 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700951 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800952 } else
953 avsync->sync_lost_cnt++;
954 }
Song Zhaod62bb392021-04-23 12:25:49 -0700955
956 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
957 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700958 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700959 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700960 /* outlier by stream error */
961 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700962 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700963 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
964 log_info("render outlier %u", fpts);
965 return true;
966 }
967 }
968
969 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800970 avsync->state = AV_SYNC_STAT_SYNC_LOST;
971 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800972 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700973 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800974 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700975
Song Zhao7e24b182022-04-01 08:46:40 -0700976 if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700977 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700978 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700979 msync_session_set_video_dis(avsync->fd, fpts);
980 avsync->last_disc_pts = fpts;
Song Zhao59d732d2024-01-23 22:09:15 -0800981 if (avsync->mode == AV_SYNC_MODE_VMASTER) {
982 systime = fpts;
983 avsync->last_r_syst = -1;
984 }
Song Zhaoa2985cb2021-06-24 12:01:47 -0700985 }
986
987 if ((int)(systime - fpts) > 0) {
988 if ((int)(systime - fpts) < avsync->disc_thres_max) {
989 /* catch up PCR */
Song Zhao59d732d2024-01-23 22:09:15 -0800990 avsync->last_r_syst = -1;
Song Zhaof46932e2021-05-21 01:51:45 -0700991 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700992 } else {
993 /* render according to FPS */
994 if (!VALID_TS(avsync->last_r_syst) ||
995 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
996 avsync->last_r_syst = systime;
997 return true;
998 }
999 return false;
1000 }
1001 } else if (LIVE_MODE(avsync->mode)) {
1002 /* hold if the gap is small */
1003 if ((int)(fpts - systime) < avsync->disc_thres_max) {
1004 return false;
1005 } else {
1006 /* render according to FPS */
1007 if (!VALID_TS(avsync->last_r_syst) ||
1008 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
1009 avsync->last_r_syst = systime;
1010 return true;
1011 }
1012 return false;
1013 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001014 }
1015 }
1016
Song Zhao52f55192021-05-06 10:52:21 -07001017 /* In some cases, keeping pattern will enlarge the gap */
1018 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
1019 avsync->first_frame_toggled) {
1020 reset_pattern(avsync->pattern_detector);
Song Zhaofd007632022-09-30 16:21:30 -07001021 log_info("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -07001022 systime, fpts);
1023 }
1024
Song Zhaoc03ba122020-12-23 21:54:02 -08001025 expire = (int)(systime - fpts) >= 0;
1026
1027 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -08001028 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001029 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -08001030 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001031 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001032 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001033 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -08001034 }
Song Zhao6dce2672022-01-13 11:32:44 -08001035 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -08001036 && avsync->first_frame_toggled) {
1037 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -08001038 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -08001039 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -08001040 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -08001041 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001042 }
1043 }
1044
Song Zhaoa58c3e92021-03-09 18:52:55 -08001045 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -08001046 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -08001047 (avsync->last_frame?avsync->last_frame->hold_period:0),
1048 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -08001049 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -08001050
1051 if (expire) {
1052 avsync->vpts = fpts;
1053 /* phase adjustment */
1054 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +00001055 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -08001056 if ((int)(systime - fpts) >= 0 &&
1057 (int)(fpts + interval - systime) > 0) {
1058 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -08001059 avsync->phase_set = true;
Song Zhaofd007632022-09-30 16:21:30 -07001060 log_debug("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -08001061 }
Song Zhao1561e542022-01-12 10:37:55 -08001062 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -08001063 if ((int)(systime - fpts) >= 0 &&
1064 (int)(fpts + interval - systime) > 0) {
1065 int vsync_pts_delta = (int)(systime - fpts);
1066
1067 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1068 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001069 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001070 log_info("[%d] too aligned adjust phase to %d",
1071 avsync->session_id, (int)avsync->phase);
1072 }
1073 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001074 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001075 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaofd007632022-09-30 16:21:30 -07001076 log_info("[%d]sync setup on frame %u", avsync->session_id, fpts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001077 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001078 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001079 }
1080 return expire;
1081}
1082
Song Zhao35a82df2021-04-15 10:58:49 -07001083static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001084{
Song Zhaoea5a0412021-01-18 16:40:08 -08001085 log_trace("[%d]cur_period: %d last_period: %d",
1086 avsync->session_id, cur_period, last_period);
Song Zhaobb3b4f32023-10-17 16:08:12 -07001087 return detect_pattern(avsync->pattern_detector, cur_period, last_period);
Song Zhaoc03ba122020-12-23 21:54:02 -08001088}
1089
1090int av_sync_set_speed(void *sync, float speed)
1091{
1092 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1093
1094 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001095 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001096 return -1;
1097 }
1098
Song Zhao76005282022-03-08 16:49:41 -08001099 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001100 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001101 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001102 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001103
Song Zhaoea5a0412021-01-18 16:40:08 -08001104 avsync->speed = speed;
1105
1106 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhaoa73fcf32023-01-13 08:12:26 -08001107 if (speed == 1.0)
1108 msync_session_set_wall_adj_thres(avsync->fd, DEFAULT_WALL_ADJ_THRES);
1109 else
1110 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
1111 log_info("[%d]adjust wall adj threshold to %d", avsync->session_id,
1112 (speed == 1.0) ? DEFAULT_WALL_ADJ_THRES : avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -08001113 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001114
Song Zhaoea5a0412021-01-18 16:40:08 -08001115 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1116 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001117}
1118
1119int av_sync_change_mode(void *sync, enum sync_mode mode)
1120{
1121 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1122
1123 if (!avsync)
1124 return -1;
1125
Song Zhaoea5a0412021-01-18 16:40:08 -08001126 if (msync_session_set_mode(avsync->fd, mode)) {
1127 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001128 return -1;
1129 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001130 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001131 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001132 return 0;
1133}
1134
Song Zhaoebc92012024-03-12 18:36:44 +00001135int av_sync_change_mode_by_id(int id, enum sync_mode mode)
1136{
1137 int fd;
1138 char dev_name[20];
1139
1140 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, id);
1141 fd = open(dev_name, O_RDONLY | O_CLOEXEC);
1142 if (fd < 0) {
1143 log_error("open %s errno %d", dev_name, errno);
1144 return -1;
1145 }
1146
1147 if (msync_session_set_mode(fd, mode)) {
1148 log_error("[%d]fail to set mode %d", id, mode);
1149 close(fd);
1150 return -1;
1151 }
1152
1153 close(fd);
1154 log_info("session[%d] set mode %d", id, mode);
1155 return 0;
1156}
1157
Song Zhao01031bb2021-05-13 21:23:20 -07001158int av_sync_get_mode(void *sync, enum sync_mode *mode)
1159{
1160 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1161
1162 if (!avsync || !mode)
1163 return -1;
1164
1165 *mode = avsync->mode;
1166 return 0;
1167}
1168
Song Zhaoc03ba122020-12-23 21:54:02 -08001169int av_sync_set_pause_pts(void *sync, pts90K pts)
1170{
1171 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1172
1173 if (!avsync)
1174 return -1;
1175
1176 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001177 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001178 return 0;
1179}
1180
1181int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1182{
1183 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1184
1185 if (!avsync)
1186 return -1;
1187
1188 avsync->pause_pts_cb = cb;
1189 avsync->pause_cb_priv = priv;
1190 return 0;
1191}
Song Zhaoea5a0412021-01-18 16:40:08 -08001192
yongchun.li428390d2022-02-17 17:15:40 -08001193int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1194{
1195 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1196
1197 if (!avsync)
1198 return -1;
1199
1200 avsync->underflow_cb = cb;
1201 avsync->underflow_cb_priv = priv;
1202
1203 if (cfg)
1204 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1205 else
1206 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1207
1208 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1209 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1210 avsync->underflow_cfg.time_thresh);
1211 return 0;
1212}
Song Zhaoea5a0412021-01-18 16:40:08 -08001213static void trigger_audio_start_cb(struct av_sync_session *avsync,
1214 avs_ascb_reason reason)
1215{
1216 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001217 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001218 pthread_mutex_lock(&avsync->lock);
1219 if (avsync->audio_start) {
1220 avsync->audio_start(avsync->audio_start_priv, reason);
1221 avsync->session_started = true;
1222 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001223 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001224 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1225 }
1226 pthread_mutex_unlock(&avsync->lock);
1227 }
1228}
1229
Song Zhao5296acf2024-02-02 21:45:04 +00001230static int update_pcr_master_disc_thres(struct av_sync_session * avsync, pts90K pts)
1231{
1232 pts90K pcr = -1;
1233
1234 if (!msync_session_get_pcr(avsync->fd, &pcr, NULL) && pcr != -1) {
1235 pts90K delta = abs_diff(pcr, pts);
1236
1237 if (delta * 3 > avsync->disc_thres_min)
1238 avsync->disc_thres_min = 3 * delta;
1239
1240 log_info("%d update disc_thres_min to %u delta %u",
1241 avsync->session_id, avsync->disc_thres_min, delta);
1242 return 0;
1243 }
1244 return -1;
1245}
1246
Song Zhaoea5a0412021-01-18 16:40:08 -08001247avs_start_ret av_sync_audio_start(
1248 void *sync,
1249 pts90K pts,
1250 pts90K delay,
1251 audio_start_cb cb,
1252 void *priv)
1253{
1254 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1255 uint32_t start_mode;
yongchun.li06965172022-12-14 19:50:31 -08001256 uint32_t systime = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001257 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1258 bool create_poll_t = false;
1259
1260 if (!avsync)
1261 return ret;
1262
yongchun.li59e873d2021-07-07 11:42:38 -07001263 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1264 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001265
yongchun.li06965172022-12-14 19:50:31 -08001266 if (avsync->in_audio_switch) {
1267 msync_session_get_wall(avsync->fd, &systime, NULL);
1268 if (systime == AV_SYNC_INVALID_PTS) {
1269 log_info("%d Invalid systime could be paused pts %d ms switch_state %d again",
1270 avsync->session_id, (int) pts/90, avsync->audio_switch_state);
1271 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
1272 ret = AV_SYNC_ASTART_AGAIN;
1273 goto exit;
1274 }
1275 }
1276
yongchun.li59e873d2021-07-07 11:42:38 -07001277 if (avsync->in_audio_switch &&
1278 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1279 {
1280 start_mode = AVS_START_SYNC;
1281 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1282 } else {
1283 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1284 log_error("[%d]fail to set audio start", avsync->session_id);
1285 }
1286 if (avsync->in_audio_switch &&
1287 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1288 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
Song Zhao4bd18762022-09-30 16:39:52 -07001289 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB
1290 && start_mode == AVS_START_SYNC) {
yongchun.li59e873d2021-07-07 11:42:38 -07001291 log_info("%d audio_switch audio need drop first.ahead %d ms",
1292 avsync->session_id, (int)(systime - pts)/90);
1293 ret = AV_SYNC_ASTART_AGAIN;
1294 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1295 goto exit;
1296 }
1297 else {
1298 int diff = (int)(pts - systime);
1299 log_info("%d audio_switch_state to start mode %d diff %d ms",
1300 avsync->session_id, start_mode, diff/90);
yongchun.li59e873d2021-07-07 11:42:38 -07001301 if (diff < A_ADJ_THREDHOLD_LB) {
1302 log_info("%d orig mode %d already close enough direct start",
1303 avsync->session_id, start_mode);
1304 start_mode = AVS_START_SYNC;
Song Zhao4bd18762022-09-30 16:39:52 -07001305 } else if (start_mode != AVS_START_ASYNC) {
1306 log_info("%d drop too far mode %d need to try ASYNC",
1307 avsync->session_id, start_mode);
1308 msync_session_set_audio_stop(avsync->fd);
1309 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1310 log_error("[%d]fail to set audio start", avsync->session_id);
1311 log_info("%d New start mode %d",
1312 avsync->session_id, start_mode);
yongchun.li59e873d2021-07-07 11:42:38 -07001313 }
Song Zhao4bd18762022-09-30 16:39:52 -07001314 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
yongchun.li59e873d2021-07-07 11:42:38 -07001315 }
yongchun.li107a6162021-05-05 02:38:57 -07001316 }
1317
Song Zhaoea5a0412021-01-18 16:40:08 -08001318 if (start_mode == AVS_START_SYNC) {
1319 ret = AV_SYNC_ASTART_SYNC;
1320 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001321 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhao5296acf2024-02-02 21:45:04 +00001322
1323 /* for DTG stream, initial delta between apts and pcr is big */
1324 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
1325 update_pcr_master_disc_thres(avsync, pts);
1326
Song Zhaod62bb392021-04-23 12:25:49 -07001327 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001328 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001329 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhao5296acf2024-02-02 21:45:04 +00001330
1331 /* for DTG stream, initial delta between apts and pcr is big */
1332 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
1333 update_pcr_master_disc_thres(avsync, pts);
Song Zhaod62bb392021-04-23 12:25:49 -07001334 } else if (start_mode == AVS_START_AGAIN) {
1335 ret = AV_SYNC_ASTART_AGAIN;
1336 }
1337
Song Zhao5296acf2024-02-02 21:45:04 +00001338 avsync->last_pts = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001339 if (ret == AV_SYNC_ASTART_AGAIN)
1340 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001341
Song Zhao76005282022-03-08 16:49:41 -08001342 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1343 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001344 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001345
1346 if (start_mode == AVS_START_ASYNC) {
1347 if (!cb) {
1348 log_error("[%d]invalid cb", avsync->session_id);
1349 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001350 }
Song Zhao76005282022-03-08 16:49:41 -08001351 avsync->audio_start = cb;
1352 avsync->audio_start_priv = priv;
1353 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001354
Song Zhaod62bb392021-04-23 12:25:49 -07001355 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001356 int ret;
1357
1358 log_info("[%d]start poll thread", avsync->session_id);
1359 avsync->quit_poll = false;
1360 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1361 if (ret) {
1362 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1363 return AV_SYNC_ASTART_ERR;
1364 }
1365 }
Song Zhaod62bb392021-04-23 12:25:49 -07001366 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001367 msync_session_get_wall(avsync->fd, &systime, NULL);
1368 log_info("[%d]return %u w %u pts %u d %u",
1369 avsync->session_id, ret, systime, pts, delay);
1370 }
1371exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001372 log_info("[%d]return %u", avsync->session_id, ret);
1373 return ret;
1374}
1375
1376int av_sync_audio_render(
1377 void *sync,
1378 pts90K pts,
1379 struct audio_policy *policy)
1380{
1381 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001382 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001383 uint32_t systime;
1384 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1385 avs_audio_action action = AA_SYNC_AA_MAX;
1386
1387 if (!avsync || !policy)
1388 return -1;
1389
yongchun.li107a6162021-05-05 02:38:57 -07001390 msync_session_get_wall(avsync->fd, &systime, NULL);
Song Zhao5296acf2024-02-02 21:45:04 +00001391 avsync->last_pts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001392
1393 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1394 pts, systime, avsync->mode, (int)(pts-systime)/90);
1395
1396 if (avsync->in_audio_switch
1397 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
Song Zhao4bd18762022-09-30 16:39:52 -07001398 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_MB) {
yongchun.li107a6162021-05-05 02:38:57 -07001399 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1400 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1401 action = AV_SYNC_AA_RENDER;
1402 } else if ((int)(systime - pts) > 0) {
1403 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1404 (int)(systime - pts)/90, systime, pts);
1405 action = AV_SYNC_AA_DROP;
1406 } else {
1407 action = AV_SYNC_AA_INSERT;
1408 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1409 (int)(pts - systime)/90, systime, pts);
1410 }
1411 goto done;
1412 }
1413
Song Zhaoea5a0412021-01-18 16:40:08 -08001414 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1415 avsync->mode == AV_SYNC_MODE_AMASTER) {
1416 action = AV_SYNC_AA_RENDER;
1417 goto done;
1418 }
1419
Song Zhaod62bb392021-04-23 12:25:49 -07001420 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001421 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001422 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1423 action = AV_SYNC_AA_DROP;
1424 goto done;
1425 }
1426
Song Zhao7daf3a12021-05-10 22:22:25 -07001427 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
Song Zhaob8833c12024-02-02 21:54:36 +00001428 avsync->mode == AV_SYNC_MODE_AMASTER ||
1429 avsync->active_mode == AV_SYNC_MODE_AMASTER) {
Song Zhao7daf3a12021-05-10 22:22:25 -07001430 action = AV_SYNC_AA_RENDER;
1431 goto done;
1432 }
1433
Song Zhaod62bb392021-04-23 12:25:49 -07001434 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1435 LIVE_MODE(avsync->mode) &&
1436 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1437 /* outlier by stream error */
1438 avsync->outlier_cnt++;
1439 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1440 /* treat as disc, just drop current frame */
1441 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1442 avsync->outlier_cnt = 0;
1443 action = AV_SYNC_AA_DROP;
1444 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001445 goto done;
1446 }
1447 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1448 pts = systime;
1449 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001450 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001451 goto done;
1452 }
1453
1454 avsync->outlier_cnt = 0;
1455 /* low bound from sync_lost to sync_setup */
1456 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1457 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1458 action = AV_SYNC_AA_RENDER;
1459 goto done;
1460 }
1461
1462 /* high bound of sync_setup */
1463 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1464 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1465 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001466 action = AV_SYNC_AA_RENDER;
1467 goto done;
1468 }
1469
1470 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001471 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001472 action = AV_SYNC_AA_DROP;
1473 goto done;
1474 }
1475
1476 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001477 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001478 action = AV_SYNC_AA_INSERT;
1479 goto done;
1480 }
1481
1482done:
1483 policy->action = action;
1484 policy->delta = (int)(systime - pts);
1485 if (action == AV_SYNC_AA_RENDER) {
1486 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001487 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001488 if (!out_lier)
1489 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001490 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001491 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001492 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1493 msync_session_update_apts(avsync->fd, systime, pts, 0);
1494 log_info("[%d] audio switch done sys %u pts %u",
1495 avsync->session_id, systime, pts);
1496 msync_session_set_audio_switch(avsync->fd, false);
1497 avsync->in_audio_switch = false;
1498 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1499 } else {
1500 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1501 avsync->session_id, action, systime, pts, systime - pts);
1502 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001503 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001504 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001505 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001506 avsync->last_disc_pts != pts &&
1507 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001508 log_info ("[%d]audio disc %u --> %u",
1509 avsync->session_id, systime, pts);
1510 msync_session_set_audio_dis(avsync->fd, pts);
1511 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001512 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001513 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001514
1515 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001516 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001517 if (!avsync->audio_drop_cnt)
1518 avsync->audio_drop_start = now;
1519 avsync->audio_drop_cnt++;
1520 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1521 log_info ("[%d]audio keep dropping sys %u vs a %u",
1522 avsync->session_id, systime, pts);
1523 msync_session_set_audio_dis(avsync->fd, pts);
1524 }
Song Zhao409739b2021-05-12 22:21:40 -07001525 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001526 if (action != AV_SYNC_AA_DROP)
1527 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001528 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001529 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001530 }
1531
1532 return ret;
1533}
1534
Song Zhaof3350d32023-08-18 16:27:31 -07001535int av_sync_get_pos(void *sync, pts90K *pts, uint64_t *mono_clock)
1536{
1537 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1538
1539 if (!avsync || !pts)
1540 return -1;
1541
1542 if (avsync->type != AV_SYNC_TYPE_AUDIO &&
1543 avsync->type != AV_SYNC_TYPE_VIDEO)
1544 return -2;
1545 return msync_session_get_pts(avsync->fd, pts,
1546 mono_clock, avsync->type == AV_SYNC_TYPE_VIDEO);
1547}
1548
Song Zhaoea5a0412021-01-18 16:40:08 -08001549int av_sync_get_clock(void *sync, pts90K *pts)
1550{
1551 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1552
1553 if (!avsync || !pts)
1554 return -1;
1555 return msync_session_get_wall(avsync->fd, pts, NULL);
1556}
1557
1558static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001559 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001560 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001561{
Song Zhao76005282022-03-08 16:49:41 -08001562 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1563 avsync->session_id, avsync->active_mode, avsync->mode,
1564 v_active, a_active, v_timeout, stat);
1565
1566 /* iptv delayed start */
1567 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1568 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1569
Song Zhaoea5a0412021-01-18 16:40:08 -08001570 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1571 float speed;
Song Zhao7e8c68f2022-07-12 16:24:30 -07001572 if (a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001573 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001574 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhao6183ca92022-07-29 09:57:03 -07001575 } else if (!a_active && !avsync->session_started) {
1576 /* quit waiting ASAP */
1577 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoea5a0412021-01-18 16:40:08 -08001578 }
1579
1580 if (!msync_session_get_rate(avsync->fd, &speed)) {
1581 /* speed change is triggered by asink,
1582 * attached audio HAL will handle it
1583 */
1584 if (speed != avsync->speed)
1585 log_info("[%d]new rate %f", avsync->session_id, speed);
Song Zhaoea5a0412021-01-18 16:40:08 -08001586 avsync->speed = speed;
1587 }
Song Zhaoebc92012024-03-12 18:36:44 +00001588 } else if (avsync->mode == AV_SYNC_MODE_PCR_MASTER &&
1589 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1590 /* pcr master stopping procedure */
1591 if (a_active && avsync->audio_start) {
1592 if (v_active || v_timeout) {
1593 log_info("audio start cb");
1594 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1595 }
1596 }
Song Zhaod62bb392021-04-23 12:25:49 -07001597 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1598 struct session_debug debug;
Song Zhao5296acf2024-02-02 21:45:04 +00001599
1600 if (a_active && avsync->audio_start) {
1601 if (v_active || v_timeout) {
1602 log_info("audio start cb");
1603 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1604 }
1605 }
1606
Song Zhaod62bb392021-04-23 12:25:49 -07001607 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001608 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001609 avsync->backup_mode = avsync->mode;
1610 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001611 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001612 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001613 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001614 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001615 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001616 log_warn("[%d]audio back to mode %d",
1617 avsync->session_id, avsync->mode);
1618 }
1619 }
Song Zhao76005282022-03-08 16:49:41 -08001620 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1621 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaob8833c12024-02-02 21:54:36 +00001622 if (a_active && avsync->audio_start) {
1623 if (v_active || v_timeout) {
1624 log_info("audio start cb");
1625 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1626 }
1627 }
1628
Song Zhaoea5a0412021-01-18 16:40:08 -08001629 }
1630}
1631
1632static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001633 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001634 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001635{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001636 struct session_debug debug;
1637
Song Zhao76005282022-03-08 16:49:41 -08001638 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1639 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001640 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1641 if (debug.debug_freerun && !avsync->debug_freerun) {
1642 avsync->backup_mode = avsync->mode;
1643 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1644 avsync->debug_freerun = true;
1645 log_warn("[%d]video to freerun mode", avsync->session_id);
1646 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1647 avsync->mode = avsync->backup_mode;
1648 avsync->debug_freerun = false;
1649 log_warn("[%d]video back to mode %d",
1650 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001651 }
1652 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001653}
1654
1655static void * poll_thread(void * arg)
1656{
1657 int ret = 0;
1658 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1659 const int fd = avsync->fd;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001660 int poll_timeout = 10;
Song Zhaoea5a0412021-01-18 16:40:08 -08001661 struct pollfd pfd = {
1662 /* default blocking capture */
Song Zhao4bd18762022-09-30 16:39:52 -07001663 .events = POLLPRI,
Song Zhaoea5a0412021-01-18 16:40:08 -08001664 .fd = avsync->fd,
1665 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001666 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001667
Song Zhaoea5a0412021-01-18 16:40:08 -08001668 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001669
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001670 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001671 prctl (PR_SET_NAME, "avs_apoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001672 sflag = SRC_A;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001673 } else if (avsync->type == AV_SYNC_TYPE_VIDEO) {
Song Zhao4bd18762022-09-30 16:39:52 -07001674 prctl (PR_SET_NAME, "avs_vpoll");
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001675 sflag = SRC_V;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001676 poll_timeout = 100;
1677 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001678
Song Zhaoea5a0412021-01-18 16:40:08 -08001679 while (!avsync->quit_poll) {
1680 for (;;) {
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001681 ret = poll(&pfd, 1, poll_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001682 if (ret > 0)
1683 break;
1684 if (avsync->quit_poll)
1685 goto exit;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001686 if (errno == EINTR) {
1687 log_debug("[%d] poll interrupted", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001688 continue;
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001689 }
Song Zhao4bd18762022-09-30 16:39:52 -07001690 if (errno == EAGAIN || errno == ENOMEM) {
1691 log_info("[%d] poll error %d", avsync->session_id, errno);
1692 continue;
1693 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001694 }
1695
1696 /* error handling */
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001697 if (pfd.revents & POLLERR) {
1698 usleep(poll_timeout * 1000);
1699 continue;
1700 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001701
Song Zhao4bd18762022-09-30 16:39:52 -07001702 if (pfd.revents & POLLNVAL) {
1703 log_warn("[%d] fd closed", avsync->session_id);
1704 goto exit;
1705 }
Song Zhaod62bb392021-04-23 12:25:49 -07001706 /* mode change. Non-exclusive wait so all the processes
1707 * shall be woken up
1708 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001709 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001710 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001711 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001712
Song Zhao9fef59c2022-08-17 12:43:10 -07001713 msync_session_get_stat(fd, true, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001714 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001715
1716 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001717 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001718 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001719 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001720 usleep(10000);
Song Zhao7dbf7ee2022-09-01 14:50:02 -07001721 } else {
1722 log_debug("[%d] unexpected revents %x", avsync->session_id, pfd.revents);
1723 usleep(poll_timeout * 1000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001724 }
1725 }
1726exit:
1727 log_info("[%d]quit", avsync->session_id);
1728 return NULL;
1729}
1730
Song Zhao623e2f12021-09-03 15:54:04 -07001731#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1732/* return ppm between demod and PCR clock */
1733int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1734{
1735 int fd = -1, ppm = 0, nread;
1736 char buf[128];
1737 uint32_t reg_v, lock;
1738 float val;
1739
1740 fd = open(DEMOD_NODE, O_RDWR);
1741 if (fd < 0) {
1742 log_warn("node not found %s", DEMOD_NODE);
1743 /* do not retry */
1744 avsync->ppm_adjusted = true;
1745 return 0;
1746 }
1747 snprintf(buf, sizeof(buf), "%d", 5);
1748 write(fd, buf, 2);
1749
1750 lseek(fd, 0, SEEK_SET);
1751
hanghang.luo02efd312022-08-26 09:49:53 +08001752 nread = read(fd, buf, sizeof(buf)-1);
Song Zhao623e2f12021-09-03 15:54:04 -07001753 if (nread <= 0) {
1754 log_error("read error");
1755 goto err;
1756 }
1757 buf[nread] = 0;
1758 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1759 log_error("wrong format %s", buf);
1760 goto err;
1761 }
1762 if (lock != 0x1f) {
1763 log_info("demod not locked");
1764 goto err;
1765 }
1766 if (reg_v > ((2 << 20) - 1))
1767 reg_v -= (2 << 21);
1768 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1769 ppm = val;
1770 log_info("ppm from SFO %d", ppm);
1771 avsync->ppm_adjusted = true;
1772
1773err:
1774 if (fd >= 0)
1775 close(fd);
1776 return ppm;
1777}
1778
Song Zhaod62bb392021-04-23 12:25:49 -07001779int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001780{
1781 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001782 struct pcr_info pcr;
1783 enum pcr_monitor_status status;
1784 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001785 if (!avsync)
1786 return -1;
1787
1788 if (avsync->type != AV_SYNC_TYPE_PCR)
1789 return -2;
1790
Song Zhao623e2f12021-09-03 15:54:04 -07001791 /* initial estimation from Demod SFO HW */
1792 if (!avsync->ppm_adjusted) {
1793 ppm = dmod_get_sfo_dev(avsync);
1794 if (ppm != 0) {
1795 /* ppm > 0 means board clock is faster */
1796 msync_session_set_clock_dev(avsync->fd, -ppm);
1797 }
1798 }
wei.dubcc2ed22021-05-19 07:16:10 -04001799 pcr.monoclk = mono_clock / 1000;
1800 pcr.pts = (long long) pts * 1000 / 90;
1801 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1802
1803 status = pcr_monitor_get_status(avsync->pcr_monitor);
1804
1805 if (status >= DEVIATION_READY) {
1806 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1807 if (avsync->ppm != ppm) {
1808 avsync->ppm = ppm;
1809 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1810 if (msync_session_set_clock_dev(avsync->fd, ppm))
1811 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001812 else
1813 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001814 }
1815 }
1816
Song Zhaod62bb392021-04-23 12:25:49 -07001817 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001818}
1819
Song Zhaod62bb392021-04-23 12:25:49 -07001820int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001821{
1822 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1823
1824 if (!avsync)
1825 return -1;
1826
Song Zhaod62bb392021-04-23 12:25:49 -07001827 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001828}
1829
1830int av_sync_set_session_name(void *sync, const char *name)
1831{
1832 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1833
1834 if (!avsync)
1835 return -1;
1836
1837 return msync_session_set_name(avsync->fd, name);
1838}
yongchun.li107a6162021-05-05 02:38:57 -07001839
1840int av_sync_set_audio_switch(void *sync, bool start)
1841{
1842 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1843 bool v_active, a_active, v_timeout;
1844
1845 if (!avsync)
1846 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001847 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001848 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001849 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001850 log_error("[%d] can not get session state",
1851 avsync->session_id);
1852 return -1;
1853 }
1854 if (!v_active || !a_active) {
1855 log_error("[%d] no apply if not AV both active v %d a %d",
1856 avsync->session_id, v_active, a_active);
1857 return -1;
1858 }
1859 if (msync_session_set_audio_switch(avsync->fd, start)) {
1860 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1861 return -1;
1862 }
1863 avsync->in_audio_switch = start;
1864 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1865 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1866 return 0;
1867}
1868
1869int av_sync_get_audio_switch(void *sync, bool *start)
1870{
1871 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1872
1873 if (!avsync)
1874 return -1;
Song Zhao9fef59c2022-08-17 12:43:10 -07001875 if (msync_session_get_stat(avsync->fd, false, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001876 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001877 log_error("[%d] can not audio seamless switch state",
1878 avsync->session_id);
1879 return -1;
1880 }
1881 if (start) *start = avsync->in_audio_switch;
1882 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001883}
Song Zhao8039f562021-05-18 18:11:25 -07001884
Song Zhao623e2f12021-09-03 15:54:04 -07001885enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001886{
1887 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1888
wei.dubcc2ed22021-05-19 07:16:10 -04001889 if (!avsync || !ppm)
1890 return CLK_RECOVERY_ERR;
1891 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001892 return CLK_RECOVERY_NOT_RUNNING;
1893
wei.dubcc2ed22021-05-19 07:16:10 -04001894 if (msync_session_get_clock_dev(avsync->fd, ppm))
1895 return CLK_RECOVERY_ERR;
1896
1897 if (*ppm == 0)
1898 return CLK_RECOVERY_ONGOING;
1899 else
1900 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001901}
Song Zhao95bd0922021-09-21 14:07:46 -07001902
1903static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1904{
1905 int ret;
1906
1907 if (!avsync->frame_q) {
1908 avsync->frame_q = create_q(MAX_FRAME_NUM);
1909 if (!avsync->frame_q) {
1910 log_error("[%d]create queue fail", avsync->session_id);
1911
1912 return -1;
1913 }
1914 }
1915
1916 ret = queue_item(avsync->frame_q, frame);
1917 if (ret)
hanghang.luo02efd312022-08-26 09:49:53 +08001918 log_error("queue fail:%d", ret);
Song Zhao95bd0922021-09-21 14:07:46 -07001919 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1920 return ret;
1921}
1922
1923int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1924{
1925 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1926
1927 if (!avsync)
1928 return -1;
1929 avsync->msys = msys;
1930 return 0;
1931}
1932
1933static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1934{
1935 struct vframe *frame = NULL, *enter_last_frame = NULL;
1936 uint64_t systime;
1937 int toggle_cnt = 0;
1938
1939 enter_last_frame = avsync->last_frame;
1940 systime = avsync->msys;
1941 log_debug("[%d]sys %llu", avsync->session_id, systime);
1942 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1943 if (systime >= frame->mts) {
1944 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1945 toggle_cnt++;
1946
1947 if (avsync->last_frame)
1948 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1949
1950 dqueue_item(avsync->frame_q, (void **)&frame);
1951 if (avsync->last_frame) {
1952 /* free frame that are not for display */
1953 if (toggle_cnt > 1) {
1954 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1955 avsync->last_frame->mts, frame->mts, systime);
1956 avsync->last_frame->free(avsync->last_frame);
1957 }
1958 } else {
1959 avsync->first_frame_toggled = true;
1960 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1961 }
1962 avsync->last_frame = frame;
1963 } else
1964 break;
1965 }
1966
1967 if (avsync->last_frame) {
1968 if (enter_last_frame != avsync->last_frame)
hanghang.luo02efd312022-08-26 09:49:53 +08001969 log_debug("[%d]pop %lu", avsync->session_id, avsync->last_frame->pts);
1970 log_trace("[%d]pop=%llu, system=%llu, diff %llu(ms), QNum=%d", avsync->session_id,
Song Zhao95bd0922021-09-21 14:07:46 -07001971 avsync->last_frame->mts,
1972 systime, (systime - avsync->last_frame->mts) / 1000000,
1973 queue_size(avsync->frame_q));
1974 } else
1975 if (enter_last_frame != avsync->last_frame)
1976 log_debug("[%d]pop (nil)", avsync->session_id);
1977
1978 if (avsync->last_frame)
1979 avsync->last_frame->hold_period++;
1980 return avsync->last_frame;
1981}
Song Zhao6183ca92022-07-29 09:57:03 -07001982
1983int avs_sync_stop_audio(void *sync)
1984{
1985 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1986
1987 if (!avsync)
1988 return -1;
1989
1990 return msync_session_stop_audio(avsync->fd);
1991}
bo.xiao05ba1ac2022-12-13 14:38:13 +08001992
1993int avs_sync_set_eos(void *sync)
1994{
1995 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1996
1997 if (!avsync)
1998 return -1;
1999
2000 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
2001 if (avsync->state == AV_SYNC_STAT_INIT) {
2002 avsync->state = AV_SYNC_STAT_RUNNING;
2003 log_debug("[%d]eos trigger state change: init --> running", avsync->session_id);
2004 }
2005 }
2006
2007 return 0;
2008}