blob: e3fd905fd43448998fd9f8ca58b90315516fba30 [file] [log] [blame]
Song Zhaoc03ba122020-12-23 21:54:02 -08001/*
2 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
3 *
4 * This source code is subject to the terms and conditions defined in the
5 * file 'LICENSE' which is part of this source code package.
6 *
7 * Description:
8 */
Song Zhaoea5a0412021-01-18 16:40:08 -08009#include <errno.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080010#include <pthread.h>
11#include <stdbool.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <sys/time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080015#include <poll.h>
16#include <fcntl.h>
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <sys/prctl.h>
20#include <sys/ioctl.h>
Song Zhaoa2985cb2021-06-24 12:01:47 -070021#include <time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080022#include <unistd.h>
23//#include <linux/amlogic/msync.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080024#include "aml_avsync.h"
Song Zhao4f632952021-12-16 09:00:18 -080025#include "aml_queue.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080026#include "pattern.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080027#include "aml_avsync_log.h"
Song Zhaoea5a0412021-01-18 16:40:08 -080028#include "msync_util.h"
29#include "msync.h"
30#include <pthread.h>
wei.dubcc2ed22021-05-19 07:16:10 -040031#include "pcr_monitor.h"
Song Zhao2f6744b2021-11-03 21:23:50 -070032
Song Zhaoc03ba122020-12-23 21:54:02 -080033enum sync_state {
34 AV_SYNC_STAT_INIT = 0,
35 AV_SYNC_STAT_RUNNING = 1,
36 AV_SYNC_STAT_SYNC_SETUP = 2,
37 AV_SYNC_STAT_SYNC_LOST = 3,
38};
39
yongchun.li107a6162021-05-05 02:38:57 -070040enum audio_switch_state_ {
41 AUDIO_SWITCH_STAT_INIT = 0,
42 AUDIO_SWITCH_STAT_RESET = 1,
43 AUDIO_SWITCH_STAT_START = 2,
44 AUDIO_SWITCH_STAT_FINISH = 3,
yongchun.li59e873d2021-07-07 11:42:38 -070045 AUDIO_SWITCH_STAT_AGAIN = 4,
yongchun.li107a6162021-05-05 02:38:57 -070046};
47
Song Zhaoea5a0412021-01-18 16:40:08 -080048#define SESSION_DEV "avsync_s"
49
Song Zhaoc03ba122020-12-23 21:54:02 -080050struct av_sync_session {
51 /* session id attached */
52 int session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -080053 int fd;
54 bool attached;
55 enum sync_mode mode;
56 /* for audio trickplay */
57 enum sync_mode backup_mode;
58 enum sync_type type;
59 uint32_t start_policy;
bo.xiao5821fc72021-07-11 22:47:00 -040060 int timeout;
Song Zhaoc03ba122020-12-23 21:54:02 -080061
Song Zhaoea5a0412021-01-18 16:40:08 -080062 /* playback time, will stop increasing during pause */
63 pts90K vpts;
64 pts90K apts;
65
66 /* phase adjustment of stream time for rate control (Video ONLY) */
Song Zhaoc03ba122020-12-23 21:54:02 -080067 pts90K phase;
68 bool phase_set;
Song Zhao1561e542022-01-12 10:37:55 -080069 bool phase_adjusted;
Song Zhaoc03ba122020-12-23 21:54:02 -080070
71 /* pts of last rendered frame */
Song Zhaoea5a0412021-01-18 16:40:08 -080072 pts90K last_wall;
Song Zhaoc03ba122020-12-23 21:54:02 -080073 pts90K last_pts;
74 struct vframe *last_frame;
75
Song Zhaoe0bf6ad2021-07-09 11:28:42 -070076 /* pts of last pushed frame */
77 pts90K last_q_pts;
78
Song Zhaoc03ba122020-12-23 21:54:02 -080079 bool first_frame_toggled;
Song Zhaoc03ba122020-12-23 21:54:02 -080080 bool paused;
Song Zhaoea5a0412021-01-18 16:40:08 -080081 enum sync_state state;
Song Zhaoc03ba122020-12-23 21:54:02 -080082 void *pattern_detector;
83 void *frame_q;
Song Zhaoc03ba122020-12-23 21:54:02 -080084
Song Zhaoea5a0412021-01-18 16:40:08 -080085 /* start control */
86 int start_thres;
87 audio_start_cb audio_start;
88 void *audio_start_priv;
89
90 /* render property */
Song Zhaoc03ba122020-12-23 21:54:02 -080091 int delay;
Song Zhao6dce2672022-01-13 11:32:44 -080092 int extra_delay;
Song Zhaoc03ba122020-12-23 21:54:02 -080093 pts90K vsync_interval;
94
95 /* state lock */
96 pthread_mutex_t lock;
97 /* pattern */
98 int last_holding_peroid;
Song Zhaoea5a0412021-01-18 16:40:08 -080099 bool session_started;
Song Zhaoc03ba122020-12-23 21:54:02 -0800100
101 float speed;
102
Song Zhaoc03ba122020-12-23 21:54:02 -0800103 /* pause pts */
104 pts90K pause_pts;
105 pause_pts_done pause_pts_cb;
106 void *pause_cb_priv;
yongchun.li428390d2022-02-17 17:15:40 -0800107 /* underflow */
108 underflow_detected underflow_cb;
109 void *underflow_cb_priv;
110 struct underflow_config underflow_cfg;
111 struct timespec frame_last_update_time;
Song Zhao5d2b4772021-01-18 16:40:08 -0800112
113 /* log control */
Song Zhaoa2985cb2021-06-24 12:01:47 -0700114 uint32_t last_log_syst;
Song Zhao5d2b4772021-01-18 16:40:08 -0800115 uint32_t sync_lost_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700116 struct timespec sync_lost_print_time;
Song Zhaoea5a0412021-01-18 16:40:08 -0800117
118 pthread_t poll_thread;
119 /* pcr master, IPTV only */
120 bool quit_poll;
121 enum sync_mode active_mode;
Song Zhaof46932e2021-05-21 01:51:45 -0700122 uint32_t disc_thres_min;
123 uint32_t disc_thres_max;
Song Zhao35a82df2021-04-15 10:58:49 -0700124
125 /* error detection */
126 uint32_t last_poptime;
Song Zhaod62bb392021-04-23 12:25:49 -0700127 uint32_t outlier_cnt;
Song Zhao409739b2021-05-12 22:21:40 -0700128 pts90K last_disc_pts;
129
yongchun.li107a6162021-05-05 02:38:57 -0700130 // indicate set audio switch
131 bool in_audio_switch;
132 enum audio_switch_state_ audio_switch_state;
wei.dubcc2ed22021-05-19 07:16:10 -0400133
134 //pcr monitor handle
135 void *pcr_monitor;
136 int ppm;
Song Zhao623e2f12021-09-03 15:54:04 -0700137 bool ppm_adjusted;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700138
139 //video FPS detection
140 pts90K last_fpts;
141 int fps_interval;
142 int fps_interval_acc;
143 int fps_cnt;
144
145 //video freerun with rate control
146 uint32_t last_r_syst;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700147 bool debug_freerun;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700148
149 //Audio dropping detection
150 uint32_t audio_drop_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700151 struct timespec audio_drop_start;
Song Zhao95bd0922021-09-21 14:07:46 -0700152
153 /*system mono time for current vsync interrupt */
154 uint64_t msys;
Song Zhaoc03ba122020-12-23 21:54:02 -0800155};
156
157#define MAX_FRAME_NUM 32
158#define DEFAULT_START_THRESHOLD 2
159#define TIME_UNIT90K (90000)
Song Zhaof46932e2021-05-21 01:51:45 -0700160#define AV_DISC_THRES_MIN (TIME_UNIT90K / 3)
161#define AV_DISC_THRES_MAX (TIME_UNIT90K * 10)
Song Zhao7daf3a12021-05-10 22:22:25 -0700162#define A_ADJ_THREDHOLD_HB (900 * 6) //60ms
163#define A_ADJ_THREDHOLD_LB (900 * 2) //20ms
Song Zhao52f55192021-05-06 10:52:21 -0700164#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800165#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhao76005282022-03-08 16:49:41 -0800166#define LIVE_MODE(m) ((m) == AV_SYNC_MODE_PCR_MASTER || (m) == AV_SYNC_MODE_IPTV)
Song Zhao7e24b182022-04-01 08:46:40 -0700167#define V_DISC_MODE(mode) (LIVE_MODE(mode) || (mode) == AV_SYNC_MODE_VMASTER)
Song Zhaod62bb392021-04-23 12:25:49 -0700168
Song Zhao065800e2021-05-26 15:56:06 -0700169#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
Song Zhaod62bb392021-04-23 12:25:49 -0700170#define OUTLIER_MAX_CNT 8
Song Zhaoa2985cb2021-06-24 12:01:47 -0700171#define VALID_TS(x) ((x) != -1)
yongchun.li428390d2022-02-17 17:15:40 -0800172#define UNDERFLOW_CHECK_THRESH_MS (100)
Song Zhaoc03ba122020-12-23 21:54:02 -0800173
yongchun.li0ee6e372021-08-20 04:26:04 -0700174static uint64_t time_diff (struct timespec *b, struct timespec *a);
Song Zhaoc03ba122020-12-23 21:54:02 -0800175static bool frame_expire(struct av_sync_session* avsync,
176 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800177 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800178 struct vframe * frame,
179 struct vframe * next_frame,
180 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700181static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800182 int cur_period,
183 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800184static void * poll_thread(void * arg);
185static void trigger_audio_start_cb(struct av_sync_session *avsync,
186 avs_ascb_reason reason);
Song Zhao95bd0922021-09-21 14:07:46 -0700187static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync);
188static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame);
Song Zhao2f6744b2021-11-03 21:23:50 -0700189pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER;
Song Zhaoc03ba122020-12-23 21:54:02 -0800190
Song Zhaoea5a0412021-01-18 16:40:08 -0800191int av_sync_open_session(int *session_id)
192{
Song Zhao2f6744b2021-11-03 21:23:50 -0700193 int fd = -1;
Song Zhaoea5a0412021-01-18 16:40:08 -0800194 int id, rc;
195
Song Zhao2f6744b2021-11-03 21:23:50 -0700196 pthread_mutex_lock(&glock);
197 fd = msync_create_session();
Song Zhaoea5a0412021-01-18 16:40:08 -0800198 if (fd < 0) {
199 log_error("fail");
Song Zhao2f6744b2021-11-03 21:23:50 -0700200 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800201 }
202 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
203 if (rc) {
204 log_error("new session errno:%d", errno);
Song Zhao2f6744b2021-11-03 21:23:50 -0700205 msync_destory_session(fd);
206 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800207 }
208 *session_id = id;
Song Zhao2f6744b2021-11-03 21:23:50 -0700209 log_debug("new avsession id %d fd %d", id, fd);
210exit:
211 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800212 return fd;
213}
214
215void av_sync_close_session(int session)
216{
Song Zhao2f6744b2021-11-03 21:23:50 -0700217 log_debug("session closed fd %d", session);
218 pthread_mutex_lock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800219 msync_destory_session(session);
Song Zhao2f6744b2021-11-03 21:23:50 -0700220 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800221}
222
223static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800224 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800225 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800226 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800227 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800228{
229 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800230 char dev_name[20];
Song Zhao2f6744b2021-11-03 21:23:50 -0700231 int retry = 10;
Song Zhaoc03ba122020-12-23 21:54:02 -0800232
Song Zhao95bd0922021-09-21 14:07:46 -0700233 log_info("[%d] mode %d type %d", session_id, mode, type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800234 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
235 if (!avsync) {
236 log_error("OOM");
237 return NULL;
238 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800239
Song Zhao95bd0922021-09-21 14:07:46 -0700240 if (type == AV_SYNC_TYPE_VIDEO &&
241 mode == AV_SYNC_MODE_VIDEO_MONO) {
242 if (session_id < AV_SYNC_SESSION_V_MONO) {
243 log_error("wrong session id %d", session_id);
244 goto err;
245 }
246 avsync->type = type;
247 avsync->mode = mode;
248 avsync->fd = -1;
249 avsync->session_id = session_id;
250 log_info("[%d]init", avsync->session_id);
251 return avsync;
252 }
253
Song Zhaoea5a0412021-01-18 16:40:08 -0800254 if (type == AV_SYNC_TYPE_VIDEO) {
255 avsync->pattern_detector = create_pattern_detector();
256 if (!avsync->pattern_detector) {
257 log_error("pd create fail");
258 goto err;
259 }
260
261 if (!start_thres)
262 avsync->start_thres = DEFAULT_START_THRESHOLD;
263 else {
264 if (start_thres > 5) {
265 log_error("start_thres too big: %d", start_thres);
266 goto err2;
267 }
268 avsync->start_thres = start_thres;
269 }
270 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800271 avsync->phase_adjusted = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800272 avsync->first_frame_toggled = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800273 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800274
275 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800276 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800277 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800278 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800279 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800280 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800281 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800282 avsync->speed = 1.0f;
283 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhao409739b2021-05-12 22:21:40 -0700284 avsync->vsync_interval = -1;
285 avsync->last_disc_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700286 avsync->last_log_syst = -1;
287 avsync->last_pts = -1;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700288 avsync->last_q_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700289 avsync->last_wall = -1;
290 avsync->fps_interval = -1;
291 avsync->last_r_syst = -1;
bo.xiao5821fc72021-07-11 22:47:00 -0400292 avsync->timeout = -1;
293
Song Zhaof46932e2021-05-21 01:51:45 -0700294 if (msync_session_get_disc_thres(session_id,
295 &avsync->disc_thres_min, &avsync->disc_thres_max)) {
296 log_error("fail to get disc thres", dev_name, errno);
297 avsync->disc_thres_min = AV_DISC_THRES_MIN;
298 avsync->disc_thres_max = AV_DISC_THRES_MAX;
299 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800300
301 pthread_mutex_init(&avsync->lock, NULL);
Song Zhao9c09f772022-01-07 14:26:50 -0800302 log_info("[%d] start_thres %d disc_thres %u/%u", session_id,
Song Zhao95bd0922021-09-21 14:07:46 -0700303 start_thres, avsync->disc_thres_min, avsync->disc_thres_max);
Song Zhaoea5a0412021-01-18 16:40:08 -0800304
305 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
Song Zhao2f6744b2021-11-03 21:23:50 -0700306 while (retry) {
307 /* wait for sysfs to update */
308 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
309 if (avsync->fd > 0)
310 break;
311
312 retry--;
313 if (!retry) {
314 log_error("open %s errno %d", dev_name, errno);
315 goto err2;
316 }
317 usleep(20000);
Song Zhaoea5a0412021-01-18 16:40:08 -0800318 }
319
wei.dubcc2ed22021-05-19 07:16:10 -0400320 if (avsync->type == AV_SYNC_TYPE_PCR) {
321 if (pcr_monitor_init(&avsync->pcr_monitor)) {
322 log_error("pcr monitor init");
Song Zhao9cd27a52021-07-26 15:27:38 +0000323 goto err3;
wei.dubcc2ed22021-05-19 07:16:10 -0400324 }
325 }
326
Song Zhaoea5a0412021-01-18 16:40:08 -0800327 if (!attach) {
328 msync_session_set_mode(avsync->fd, mode);
329 avsync->mode = mode;
Song Zhao7e24b182022-04-01 08:46:40 -0700330 if (avsync->mode == AV_SYNC_MODE_VMASTER)
331 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -0800332 } else {
333 avsync->attached = true;
334 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
335 log_error("get mode");
Song Zhao9cd27a52021-07-26 15:27:38 +0000336 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800337 }
338 avsync->backup_mode = avsync->mode;
bo.xiao5821fc72021-07-11 22:47:00 -0400339 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800340 log_error("get policy");
Song Zhao9cd27a52021-07-26 15:27:38 +0000341 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800342 }
Song Zhao76005282022-03-08 16:49:41 -0800343 if (msync_session_get_stat(avsync->fd, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700344 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -0700345 log_error("get state");
Song Zhao9cd27a52021-07-26 15:27:38 +0000346 goto err4;
yongchun.li107a6162021-05-05 02:38:57 -0700347 }
348 if (avsync->in_audio_switch) {
349 log_info("audio_switch_state reseted the audio");
350 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
351 }
352
Song Zhaoea5a0412021-01-18 16:40:08 -0800353 log_info("[%d]retrieve sync mode %d policy %d",
354 session_id, avsync->mode, avsync->start_policy);
355 }
356
Song Zhao67c937b2021-10-01 11:21:32 -0700357 /* debug log level */
358 {
359 const char *env= getenv( "AML_AVSYNC_DEBUG_LEVEL");
360 if ( env ) {
361 log_set_level(atoi(env));
362 }
363 }
364
Song Zhaoc03ba122020-12-23 21:54:02 -0800365 return avsync;
Song Zhao9cd27a52021-07-26 15:27:38 +0000366err4:
wei.dubcc2ed22021-05-19 07:16:10 -0400367 if (avsync->pcr_monitor)
368 pcr_monitor_destroy(avsync->pcr_monitor);
Song Zhao9cd27a52021-07-26 15:27:38 +0000369err3:
370 close(avsync->fd);
Song Zhaoea5a0412021-01-18 16:40:08 -0800371err2:
372 destroy_pattern_detector(avsync->pattern_detector);
373err:
374 free(avsync);
375 return NULL;
376}
377
378void* av_sync_create(int session_id,
379 enum sync_mode mode,
380 enum sync_type type,
381 int start_thres)
382{
383 return create_internal(session_id, mode,
384 type, start_thres, false);
385}
386
387void* av_sync_attach(int session_id, enum sync_type type)
388{
Song Zhao95bd0922021-09-21 14:07:46 -0700389 if (type == AV_SYNC_TYPE_VIDEO)
390 return NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800391 return create_internal(session_id, AV_SYNC_MODE_MAX,
392 type, 0, true);
393}
394
395int av_sync_video_config(void *sync, struct video_config* config)
396{
397 struct av_sync_session *avsync = (struct av_sync_session *)sync;
398
399 if (!avsync || !config)
400 return -1;
401
402 if (config->delay != 1 && config->delay != 2) {
403 log_error("invalid delay: %d\n", config->delay);
404 return -1;
405 }
406
407 avsync->delay = config->delay;
Song Zhao6dce2672022-01-13 11:32:44 -0800408 avsync->extra_delay = config->extra_delay * 90;
Song Zhaoea5a0412021-01-18 16:40:08 -0800409
Song Zhao6dce2672022-01-13 11:32:44 -0800410 log_info("[%d] vsync delay: %d extra_delay: %d ms",
411 avsync->session_id, config->delay, config->extra_delay);
Song Zhaoea5a0412021-01-18 16:40:08 -0800412 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800413}
414
415static int internal_stop(struct av_sync_session *avsync)
416{
417 int ret = 0;
418 struct vframe *frame;
419
420 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800421 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
422 frame->free(frame);
423 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800424 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800425 pthread_mutex_unlock(&avsync->lock);
426 return ret;
427}
428
429/* destroy and detach from kernel session */
430void av_sync_destroy(void *sync)
431{
432 struct av_sync_session *avsync = (struct av_sync_session *)sync;
433
434 if (!avsync)
435 return;
436
Song Zhao95bd0922021-09-21 14:07:46 -0700437 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
438 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
439 log_info("[%d]done", avsync->session_id);
440 internal_stop(avsync);
441 destroy_q(avsync->frame_q);
442 free(avsync);
443 return;
444 }
Song Zhaob5458b32021-11-12 15:58:47 -0800445 log_info("[%d]begin type %d", avsync->session_id, avsync->type);
Song Zhaoea5a0412021-01-18 16:40:08 -0800446 if (avsync->state != AV_SYNC_STAT_INIT) {
447 if (avsync->type == AV_SYNC_TYPE_VIDEO)
448 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800449
Song Zhaoea5a0412021-01-18 16:40:08 -0800450 avsync->quit_poll = true;
451 if (avsync->poll_thread) {
452 pthread_join(avsync->poll_thread, NULL);
453 avsync->poll_thread = 0;
454 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700455 if (avsync->type == AV_SYNC_TYPE_AUDIO)
456 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoaf368d52021-02-17 17:53:45 -0800457 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800458
Song Zhaoea5a0412021-01-18 16:40:08 -0800459 if (avsync->session_started) {
460 if (avsync->type == AV_SYNC_TYPE_VIDEO)
461 msync_session_set_video_stop(avsync->fd);
462 else
463 msync_session_set_audio_stop(avsync->fd);
464 }
wei.dubcc2ed22021-05-19 07:16:10 -0400465
466 if(avsync->pcr_monitor)
467 pcr_monitor_destroy(avsync->pcr_monitor);
468
Song Zhaoea5a0412021-01-18 16:40:08 -0800469 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800470 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800471 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
472 destroy_q(avsync->frame_q);
473 destroy_pattern_detector(avsync->pattern_detector);
474 }
Song Zhaob5458b32021-11-12 15:58:47 -0800475 log_info("[%d]done type %d", avsync->session_id, avsync->type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800476 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800477}
478
bo.xiao5821fc72021-07-11 22:47:00 -0400479int avs_sync_set_start_policy(void *sync, struct start_policy* st_policy)
Song Zhaoea5a0412021-01-18 16:40:08 -0800480{
481 struct av_sync_session *avsync = (struct av_sync_session *)sync;
482
483 if (!avsync || !avsync->fd)
484 return -1;
485
bo.xiao5821fc72021-07-11 22:47:00 -0400486 log_info("[%d]policy %u --> %u, timeout %d --> %d", avsync->start_policy, st_policy->policy, avsync->timeout, st_policy->timeout);
Song Zhao76005282022-03-08 16:49:41 -0800487 if (LIVE_MODE(avsync->mode) &&
488 st_policy->policy != AV_SYNC_START_ASAP) {
489 log_error("policy %d not supported in live mode", st_policy->policy);
490 return -1;
491 }
492
bo.xiao5821fc72021-07-11 22:47:00 -0400493 avsync->start_policy = st_policy->policy;
494 avsync->timeout = st_policy->timeout;
Song Zhao76005282022-03-08 16:49:41 -0800495
Song Zhaoea5a0412021-01-18 16:40:08 -0800496 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400497 if (st_policy->policy != AV_SYNC_START_NONE &&
498 st_policy->policy != AV_SYNC_START_V_PEEK)
499 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800500
501 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800502}
503
504int av_sync_pause(void *sync, bool pause)
505{
506 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700507 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800508 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800509
Song Zhaob5458b32021-11-12 15:58:47 -0800510 if (!avsync) {
511 log_error("invalid handle");
Song Zhaoc03ba122020-12-23 21:54:02 -0800512 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800513 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800514
Song Zhaob5458b32021-11-12 15:58:47 -0800515 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
516 log_warn("ignore pause in pcr master mode");
Song Zhaoea5a0412021-01-18 16:40:08 -0800517 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800518 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800519
Song Zhao76005282022-03-08 16:49:41 -0800520 rc = msync_session_get_stat(avsync->fd, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -0700521 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700522 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700523
yongchun.li5f52fb02021-06-04 18:13:05 -0700524 /* ignore only when video try to pause when audio is acive, on which
525 the control of the STC will be relays.
526 When resume,it can do always as it is possible that video just
527 paused earlier without audio yet,then audio added later before resume.
528 We shall not igore that otherwise it could cause video freeze. */
529 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
530 avsync->type == AV_SYNC_TYPE_VIDEO &&
531 a_active &&
532 !avsync->in_audio_switch) {
533 if (!pause) {
534 log_info("[%d] clear video pause when audio active",
535 avsync->session_id);
536 avsync->paused = pause;
537 } else {
538 log_info("[%d] ignore the pause from video when audio active",
539 avsync->session_id);
540 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800541 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700542 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800543
yongchun.li107a6162021-05-05 02:38:57 -0700544 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
545 log_info("[%d] ignore the pause from audio", avsync->session_id);
546 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
547 return 0;
548 }
549
Song Zhaoea5a0412021-01-18 16:40:08 -0800550 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800551 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800552 log_info("[%d]paused:%d type:%d rc %d",
553 avsync->session_id, pause, avsync->type, rc);
yongchun.li428390d2022-02-17 17:15:40 -0800554 if (!avsync->paused && avsync->first_frame_toggled) {
555 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
556 log_info("[%d] resume update new frame time", avsync->session_id);
557 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800558 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800559}
560
561int av_sync_push_frame(void *sync , struct vframe *frame)
562{
563 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700564 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800565 struct av_sync_session *avsync = (struct av_sync_session *)sync;
566
567 if (!avsync)
568 return -1;
569
Song Zhao95bd0922021-09-21 14:07:46 -0700570 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
571 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
572 return video_mono_push_frame(avsync, frame);
573
Song Zhaoea5a0412021-01-18 16:40:08 -0800574 if (!avsync->frame_q) {
575 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400576 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800577 log_error("[%d]get policy", avsync->session_id);
578 return -1;
579 }
580
581 avsync->frame_q = create_q(MAX_FRAME_NUM);
582 if (!avsync->frame_q) {
583 log_error("[%d]create queue fail", avsync->session_id);
yongchun.li0ee6e372021-08-20 04:26:04 -0700584
Song Zhaoea5a0412021-01-18 16:40:08 -0800585 return -1;
586 }
587
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700588 {
Song Zhaoea5a0412021-01-18 16:40:08 -0800589 int ret;
590
591 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
592 if (ret) {
593 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
594 destroy_q(avsync->frame_q);
595 return -1;
596 }
597 }
598 }
599
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700600 if (avsync->last_q_pts != -1) {
Song Zhao7e24b182022-04-01 08:46:40 -0700601 if (frame->pts != -1 && avsync->mode == AV_SYNC_MODE_VMASTER) {
602 /* Sometimes app will fake PTS for trickplay, video PTS gap
603 * is really big depending on the speed. Have to adjust the
604 * threshold dynamically.
605 */
606 int gap = (int)(frame->pts - avsync->last_q_pts);
607 if (gap > avsync->disc_thres_min) {
608 avsync->disc_thres_min = gap * 6;
609 avsync->disc_thres_max = gap * 20;
610 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
611 msync_session_set_disc_thres(avsync->session_id,
612 avsync->disc_thres_min, avsync->disc_thres_max);
613 log_info("[%d] update disc_thres to %d/%d",avsync->session_id,
614 avsync->disc_thres_min, avsync->disc_thres_max);
615 }
616 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700617 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
618 /* TODO: wrong, should remove from back of queue */
Song Zhaoc03ba122020-12-23 21:54:02 -0800619 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700620 if (prev) {
621 prev->free(prev);
622 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
623 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700624 } else if (avsync->fps_cnt < 100) {
625 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700626
627 if (interval > 0 && interval <= 4500) {
628 if (avsync->fps_interval_acc == -1) {
629 avsync->fps_interval_acc = interval;
630 avsync->fps_cnt = 1;
631 } else {
632 avsync->fps_interval_acc += interval;
633 avsync->fps_cnt++;
634 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
635 if (avsync->fps_cnt == 100)
636 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
637 }
638 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800639 }
640 }
641
Song Zhao065800e2021-05-26 15:56:06 -0700642 if (frame->duration == -1)
643 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800644 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700645 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800646 ret = queue_item(avsync->frame_q, frame);
647 if (avsync->state == AV_SYNC_STAT_INIT &&
648 queue_size(avsync->frame_q) >= avsync->start_thres) {
649 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaoea5a0412021-01-18 16:40:08 -0800650 log_info("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800651 }
652
653 if (ret)
Song Zhaoe1b65602022-01-06 08:03:46 -0800654 log_error("queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400655 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800656 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800657}
658
659struct vframe *av_sync_pop_frame(void *sync)
660{
Song Zhaoea5a0412021-01-18 16:40:08 -0800661 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800662 struct av_sync_session *avsync = (struct av_sync_session *)sync;
663 int toggle_cnt = 0;
664 uint32_t systime;
Song Zhao468fd652021-01-15 22:13:04 -0800665 bool pause_pts_reached = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800666 uint32_t interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800667
Song Zhao95bd0922021-09-21 14:07:46 -0700668 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
669 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
670 return video_mono_pop_frame(avsync);
671
Song Zhaoc03ba122020-12-23 21:54:02 -0800672 pthread_mutex_lock(&avsync->lock);
673 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhao2f6744b2021-11-03 21:23:50 -0700674 log_debug("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800675 goto exit;
676 }
677
Song Zhaoea5a0412021-01-18 16:40:08 -0800678 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700679 uint32_t pts;
680
Song Zhaoc03ba122020-12-23 21:54:02 -0800681 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800682 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800683 goto exit;
684 }
Song Zhao35a82df2021-04-15 10:58:49 -0700685 msync_session_get_wall(avsync->fd, &systime, &interval);
686 pts = frame->pts - avsync->delay * interval;
687 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800688 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700689 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800690 }
691
Song Zhaoea5a0412021-01-18 16:40:08 -0800692 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700693 !avsync->first_frame_toggled &&
694 !msync_clock_started(avsync->fd)) {
695 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800696 log_trace("[%d]clock not started", avsync->session_id);
697 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800698 }
699
Song Zhaoea5a0412021-01-18 16:40:08 -0800700 enter_last_frame = avsync->last_frame;
701 msync_session_get_wall(avsync->fd, &systime, &interval);
702
703 /* handle refresh rate change */
704 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
705 avsync->vsync_interval != interval) {
706 log_info("[%d]vsync interval update %d --> %u",
707 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700708 if (avsync->fps_interval == -1)
709 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800710 avsync->vsync_interval = interval;
711 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800712 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700713 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800714 reset_pattern(avsync->pattern_detector);
715 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800716 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
717 struct vframe *next_frame = NULL;
718
719 peek_item(avsync->frame_q, (void **)&next_frame, 1);
720 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700721 log_debug("[%d]cur_f %u next_f %u size %d",
722 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800723 if (frame_expire(avsync, systime, interval,
724 frame, next_frame, toggle_cnt)) {
725 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800726 toggle_cnt++;
727
Song Zhao35a82df2021-04-15 10:58:49 -0700728 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800729 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700730 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700731 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700732 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
733 if (next_frame)
734 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
735 }
Song Zhao35a82df2021-04-15 10:58:49 -0700736
Song Zhaoc03ba122020-12-23 21:54:02 -0800737 if (avsync->last_frame)
738 avsync->last_holding_peroid = avsync->last_frame->hold_period;
739
740 dqueue_item(avsync->frame_q, (void **)&frame);
741 if (avsync->last_frame) {
742 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800743 if (toggle_cnt > 1) {
Song Zhao35a82df2021-04-15 10:58:49 -0700744 log_debug("[%d]free %u cur %u system/d %u/%u", avsync->session_id,
745 avsync->last_frame->pts, frame->pts, systime, systime - avsync->last_poptime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800746 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800747 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800748 } else {
749 avsync->first_frame_toggled = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800750 log_info("[%d]first frame %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800751 }
752 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800753 avsync->last_pts = frame->pts;
yongchun.li428390d2022-02-17 17:15:40 -0800754 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
Song Zhaoc03ba122020-12-23 21:54:02 -0800755 } else
756 break;
757 }
758
759 /* pause pts */
760 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800761 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800762 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800763 else
Song Zhao468fd652021-01-15 22:13:04 -0800764 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
765 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
766 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
767 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
768 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800769
Song Zhao468fd652021-01-15 22:13:04 -0800770 if (pause_pts_reached) {
771 if (avsync->pause_pts_cb)
772 avsync->pause_pts_cb(avsync->pause_pts,
Song Zhaoc03ba122020-12-23 21:54:02 -0800773 avsync->pause_cb_priv);
774
Song Zhao468fd652021-01-15 22:13:04 -0800775 /* stay in paused until av_sync_pause(false) */
776 avsync->paused = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800777 log_info ("[%d]reach pause pts: %u",
Song Zhaob5458b32021-11-12 15:58:47 -0800778 avsync->session_id, avsync->pause_pts);
Song Zhaoad7c8232021-12-14 11:46:48 -0800779 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoc03ba122020-12-23 21:54:02 -0800780 }
781
782exit:
783 pthread_mutex_unlock(&avsync->lock);
yongchun.li428390d2022-02-17 17:15:40 -0800784
785 /* underflow check */
786 if (avsync->session_started && avsync->first_frame_toggled &&
787 (avsync->paused == false) && (avsync->state >= AV_SYNC_STAT_RUNNING) &&
788 avsync->underflow_cb && peek_item(avsync->frame_q, (void **)&frame, 0))
789 {/* empty queue in normal play */
790 struct timespec now;
791 int diff_ms;
792 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
793 diff_ms = time_diff(&now, &avsync->frame_last_update_time)/1000;
794 if(diff_ms >= (avsync->underflow_cfg.time_thresh
795 + avsync->vsync_interval*avsync->last_holding_peroid/90)) {
796 log_info ("[%d]underflow detected: %u", avsync->session_id, avsync->last_pts);
797 avsync->underflow_cb (avsync->last_pts,
798 avsync->underflow_cb_priv);
799 /* update time to control the underflow check call backs */
800 avsync->frame_last_update_time = now;
801 }
802 }
803
Song Zhaoc03ba122020-12-23 21:54:02 -0800804 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800805 if (enter_last_frame != avsync->last_frame)
806 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
bo.xiao1f94b352021-08-02 03:53:47 -0400807 log_trace("[%d]pop=%u, stc=%u, QNum=%d", avsync->session_id, avsync->last_frame->pts, systime, queue_size(avsync->frame_q));
Song Zhao065800e2021-05-26 15:56:06 -0700808 /* don't update vpts for out_lier */
809 if (avsync->last_frame->duration != -1)
810 msync_session_update_vpts(avsync->fd, systime,
811 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800812 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800813 if (enter_last_frame != avsync->last_frame)
814 log_debug("[%d]pop (nil)", avsync->session_id);
815
Song Zhao35a82df2021-04-15 10:58:49 -0700816 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800817 if (avsync->last_frame)
818 avsync->last_frame->hold_period++;
819 return avsync->last_frame;
820}
821
Song Zhaoc03ba122020-12-23 21:54:02 -0800822static inline uint32_t abs_diff(uint32_t a, uint32_t b)
823{
Song Zhaoea5a0412021-01-18 16:40:08 -0800824 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800825}
826
yongchun.li0ee6e372021-08-20 04:26:04 -0700827static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800828{
yongchun.li0ee6e372021-08-20 04:26:04 -0700829 return (b->tv_sec - a->tv_sec)*1000000 + (b->tv_nsec/1000 - a->tv_nsec/1000);
Song Zhaoc03ba122020-12-23 21:54:02 -0800830}
831
Song Zhaoc03ba122020-12-23 21:54:02 -0800832static bool frame_expire(struct av_sync_session* avsync,
833 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800834 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800835 struct vframe * frame,
836 struct vframe * next_frame,
837 int toggle_cnt)
838{
Song Zhao6dce2672022-01-13 11:32:44 -0800839 uint32_t fpts = frame->pts + avsync->extra_delay;
840 uint32_t nfpts = -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800841 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800842 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800843
844 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
845 return false;
846
847 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
848 return true;
849
Song Zhaoad7c8232021-12-14 11:46:48 -0800850 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS &&
851 avsync->pause_pts == frame->pts)
852 return true;
853
Song Zhao08fa16b2021-12-08 14:30:17 -0800854 if (systime == AV_SYNC_INVALID_PTS &&
855 avsync->mode == AV_SYNC_MODE_AMASTER)
856 return false;
857
Song Zhao6dce2672022-01-13 11:32:44 -0800858 if (next_frame)
859 nfpts = next_frame->pts + avsync->extra_delay;
860
Song Zhao7e24b182022-04-01 08:46:40 -0700861 if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
fei.deng63e43e12021-09-23 19:44:01 +0800862 /* We need to ensure that the video outputs smoothly,
863 so output video frame by frame hold_period */
864 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
865 avsync->last_frame &&
866 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
867 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
868 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700869 return true;
870 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700871 }
872
Song Zhaoc03ba122020-12-23 21:54:02 -0800873 if (!fpts) {
874 if (avsync->last_frame) {
875 /* try to accumulate duration as PTS */
876 fpts = avsync->vpts + avsync->last_frame->duration;
877 } else {
878 fpts = avsync->vpts;
879 }
880 }
881 systime += pts_correction;
882
883 /* phase adjustment */
884 if (avsync->phase_set)
885 systime += avsync->phase;
886
yongchun.lia50b1e92021-08-07 01:11:54 +0000887 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800888 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000889 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700890 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800891 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800892 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800893 return false;
894
Song Zhaoa2985cb2021-06-24 12:01:47 -0700895 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
896 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700897 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800898
yongchun.li0ee6e372021-08-20 04:26:04 -0700899 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700900 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800901 avsync->last_pts = fpts;
902 if (time_diff(&now, &avsync->sync_lost_print_time) >=
903 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700904 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800905 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800906 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700907 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800908 } else
909 avsync->sync_lost_cnt++;
910 }
Song Zhaod62bb392021-04-23 12:25:49 -0700911
912 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
913 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700914 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700915 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700916 /* outlier by stream error */
917 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700918 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700919 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
920 log_info("render outlier %u", fpts);
921 return true;
922 }
923 }
924
925 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800926 avsync->state = AV_SYNC_STAT_SYNC_LOST;
927 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800928 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700929 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800930 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700931
Song Zhao7e24b182022-04-01 08:46:40 -0700932 if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700933 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700934 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700935 msync_session_set_video_dis(avsync->fd, fpts);
936 avsync->last_disc_pts = fpts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700937 }
938
939 if ((int)(systime - fpts) > 0) {
940 if ((int)(systime - fpts) < avsync->disc_thres_max) {
941 /* catch up PCR */
Song Zhaof46932e2021-05-21 01:51:45 -0700942 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700943 } else {
944 /* render according to FPS */
945 if (!VALID_TS(avsync->last_r_syst) ||
946 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
947 avsync->last_r_syst = systime;
948 return true;
949 }
950 return false;
951 }
952 } else if (LIVE_MODE(avsync->mode)) {
953 /* hold if the gap is small */
954 if ((int)(fpts - systime) < avsync->disc_thres_max) {
955 return false;
956 } else {
957 /* render according to FPS */
958 if (!VALID_TS(avsync->last_r_syst) ||
959 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
960 avsync->last_r_syst = systime;
961 return true;
962 }
963 return false;
964 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800965 }
966 }
967
Song Zhao52f55192021-05-06 10:52:21 -0700968 /* In some cases, keeping pattern will enlarge the gap */
969 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
970 avsync->first_frame_toggled) {
971 reset_pattern(avsync->pattern_detector);
Song Zhaof46932e2021-05-21 01:51:45 -0700972 log_warn("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700973 systime, fpts);
974 }
975
Song Zhaoc03ba122020-12-23 21:54:02 -0800976 expire = (int)(systime - fpts) >= 0;
977
978 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -0800979 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800980 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -0800981 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800982 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800983 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -0800984 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800985 }
Song Zhao6dce2672022-01-13 11:32:44 -0800986 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -0800987 && avsync->first_frame_toggled) {
988 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -0800989 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800990 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800991 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -0800992 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800993 }
994 }
995
Song Zhaoa58c3e92021-03-09 18:52:55 -0800996 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -0800997 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -0800998 (avsync->last_frame?avsync->last_frame->hold_period:0),
999 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -08001000 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -08001001
1002 if (expire) {
1003 avsync->vpts = fpts;
1004 /* phase adjustment */
1005 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +00001006 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -08001007 if ((int)(systime - fpts) >= 0 &&
1008 (int)(fpts + interval - systime) > 0) {
1009 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -08001010 avsync->phase_set = true;
yongchun.lia50b1e92021-08-07 01:11:54 +00001011 log_info("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -08001012 }
Song Zhao1561e542022-01-12 10:37:55 -08001013 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -08001014 if ((int)(systime - fpts) >= 0 &&
1015 (int)(fpts + interval - systime) > 0) {
1016 int vsync_pts_delta = (int)(systime - fpts);
1017
1018 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1019 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001020 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001021 log_info("[%d] too aligned adjust phase to %d",
1022 avsync->session_id, (int)avsync->phase);
1023 }
1024 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001025 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001026 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -08001027 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -08001028 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001029 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001030 }
1031 return expire;
1032}
1033
Song Zhao35a82df2021-04-15 10:58:49 -07001034static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001035{
Song Zhao35a82df2021-04-15 10:58:49 -07001036 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001037 log_trace("[%d]cur_period: %d last_period: %d",
1038 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -07001039 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
1040 ret = true;
1041 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
1042 ret = true;
1043 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
1044 ret = true;
1045 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
1046 ret = true;
1047
1048 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -08001049}
1050
1051int av_sync_set_speed(void *sync, float speed)
1052{
1053 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1054
1055 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001056 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001057 return -1;
1058 }
1059
Song Zhao76005282022-03-08 16:49:41 -08001060 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001061 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001062 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001063 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001064
Song Zhaoea5a0412021-01-18 16:40:08 -08001065 avsync->speed = speed;
1066
1067 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
1068 if (speed == 1.0) {
1069 avsync->mode = avsync->backup_mode;
1070 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1071 } else {
1072 avsync->backup_mode = avsync->mode;
1073 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1074 log_info("[%d]audio to freerun mode", avsync->session_id);
1075 }
1076 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001077
Song Zhaoea5a0412021-01-18 16:40:08 -08001078 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1079 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001080}
1081
1082int av_sync_change_mode(void *sync, enum sync_mode mode)
1083{
1084 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1085
1086 if (!avsync)
1087 return -1;
1088
Song Zhaoea5a0412021-01-18 16:40:08 -08001089 if (msync_session_set_mode(avsync->fd, mode)) {
1090 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001091 return -1;
1092 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001093 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001094 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001095 return 0;
1096}
1097
Song Zhao01031bb2021-05-13 21:23:20 -07001098int av_sync_get_mode(void *sync, enum sync_mode *mode)
1099{
1100 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1101
1102 if (!avsync || !mode)
1103 return -1;
1104
1105 *mode = avsync->mode;
1106 return 0;
1107}
1108
Song Zhaoc03ba122020-12-23 21:54:02 -08001109int av_sync_set_pause_pts(void *sync, pts90K pts)
1110{
1111 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1112
1113 if (!avsync)
1114 return -1;
1115
1116 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001117 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001118 return 0;
1119}
1120
1121int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1122{
1123 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1124
1125 if (!avsync)
1126 return -1;
1127
1128 avsync->pause_pts_cb = cb;
1129 avsync->pause_cb_priv = priv;
1130 return 0;
1131}
Song Zhaoea5a0412021-01-18 16:40:08 -08001132
yongchun.li428390d2022-02-17 17:15:40 -08001133int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1134{
1135 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1136
1137 if (!avsync)
1138 return -1;
1139
1140 avsync->underflow_cb = cb;
1141 avsync->underflow_cb_priv = priv;
1142
1143 if (cfg)
1144 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1145 else
1146 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1147
1148 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1149 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1150 avsync->underflow_cfg.time_thresh);
1151 return 0;
1152}
Song Zhaoea5a0412021-01-18 16:40:08 -08001153static void trigger_audio_start_cb(struct av_sync_session *avsync,
1154 avs_ascb_reason reason)
1155{
1156 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001157 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001158 pthread_mutex_lock(&avsync->lock);
1159 if (avsync->audio_start) {
1160 avsync->audio_start(avsync->audio_start_priv, reason);
1161 avsync->session_started = true;
1162 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001163 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001164 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1165 }
1166 pthread_mutex_unlock(&avsync->lock);
1167 }
1168}
1169
1170avs_start_ret av_sync_audio_start(
1171 void *sync,
1172 pts90K pts,
1173 pts90K delay,
1174 audio_start_cb cb,
1175 void *priv)
1176{
1177 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1178 uint32_t start_mode;
yongchun.li59e873d2021-07-07 11:42:38 -07001179 uint32_t systime;
Song Zhaoea5a0412021-01-18 16:40:08 -08001180 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1181 bool create_poll_t = false;
1182
1183 if (!avsync)
1184 return ret;
1185
yongchun.li59e873d2021-07-07 11:42:38 -07001186 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1187 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001188
yongchun.li59e873d2021-07-07 11:42:38 -07001189 if (avsync->in_audio_switch &&
1190 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1191 {
1192 start_mode = AVS_START_SYNC;
1193 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1194 } else {
1195 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1196 log_error("[%d]fail to set audio start", avsync->session_id);
1197 }
1198 if (avsync->in_audio_switch &&
1199 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1200 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
1201 msync_session_get_wall(avsync->fd, &systime, NULL);
1202 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB &&
1203 start_mode == AVS_START_SYNC) {
1204 log_info("%d audio_switch audio need drop first.ahead %d ms",
1205 avsync->session_id, (int)(systime - pts)/90);
1206 ret = AV_SYNC_ASTART_AGAIN;
1207 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1208 goto exit;
1209 }
1210 else {
1211 int diff = (int)(pts - systime);
1212 log_info("%d audio_switch_state to start mode %d diff %d ms",
1213 avsync->session_id, start_mode, diff/90);
1214 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
1215 if (diff < A_ADJ_THREDHOLD_LB) {
1216 log_info("%d orig mode %d already close enough direct start",
1217 avsync->session_id, start_mode);
1218 start_mode = AVS_START_SYNC;
1219 }
1220 }
yongchun.li107a6162021-05-05 02:38:57 -07001221 }
1222
Song Zhaoea5a0412021-01-18 16:40:08 -08001223 if (start_mode == AVS_START_SYNC) {
1224 ret = AV_SYNC_ASTART_SYNC;
1225 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001226 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001227 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001228 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001229 avsync->state = AV_SYNC_STAT_RUNNING;
1230 } else if (start_mode == AVS_START_AGAIN) {
1231 ret = AV_SYNC_ASTART_AGAIN;
1232 }
1233
1234 if (ret == AV_SYNC_ASTART_AGAIN)
1235 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001236
Song Zhao76005282022-03-08 16:49:41 -08001237 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1238 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001239 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001240
1241 if (start_mode == AVS_START_ASYNC) {
1242 if (!cb) {
1243 log_error("[%d]invalid cb", avsync->session_id);
1244 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001245 }
Song Zhao76005282022-03-08 16:49:41 -08001246 avsync->audio_start = cb;
1247 avsync->audio_start_priv = priv;
1248 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001249
Song Zhaod62bb392021-04-23 12:25:49 -07001250 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001251 int ret;
1252
1253 log_info("[%d]start poll thread", avsync->session_id);
1254 avsync->quit_poll = false;
1255 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1256 if (ret) {
1257 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1258 return AV_SYNC_ASTART_ERR;
1259 }
1260 }
Song Zhaod62bb392021-04-23 12:25:49 -07001261 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001262 msync_session_get_wall(avsync->fd, &systime, NULL);
1263 log_info("[%d]return %u w %u pts %u d %u",
1264 avsync->session_id, ret, systime, pts, delay);
1265 }
1266exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001267 log_info("[%d]return %u", avsync->session_id, ret);
1268 return ret;
1269}
1270
1271int av_sync_audio_render(
1272 void *sync,
1273 pts90K pts,
1274 struct audio_policy *policy)
1275{
1276 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001277 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001278 uint32_t systime;
1279 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1280 avs_audio_action action = AA_SYNC_AA_MAX;
1281
1282 if (!avsync || !policy)
1283 return -1;
1284
yongchun.li107a6162021-05-05 02:38:57 -07001285 msync_session_get_wall(avsync->fd, &systime, NULL);
1286
1287 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1288 pts, systime, avsync->mode, (int)(pts-systime)/90);
1289
1290 if (avsync->in_audio_switch
1291 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
1292 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
1293 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1294 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1295 action = AV_SYNC_AA_RENDER;
1296 } else if ((int)(systime - pts) > 0) {
1297 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1298 (int)(systime - pts)/90, systime, pts);
1299 action = AV_SYNC_AA_DROP;
1300 } else {
1301 action = AV_SYNC_AA_INSERT;
1302 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1303 (int)(pts - systime)/90, systime, pts);
1304 }
1305 goto done;
1306 }
1307
Song Zhaoea5a0412021-01-18 16:40:08 -08001308 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1309 avsync->mode == AV_SYNC_MODE_AMASTER) {
1310 action = AV_SYNC_AA_RENDER;
1311 goto done;
1312 }
1313
Song Zhaod62bb392021-04-23 12:25:49 -07001314 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001315 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001316 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1317 action = AV_SYNC_AA_DROP;
1318 goto done;
1319 }
1320
Song Zhao7daf3a12021-05-10 22:22:25 -07001321 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1322 avsync->mode == AV_SYNC_MODE_AMASTER) {
1323 action = AV_SYNC_AA_RENDER;
1324 goto done;
1325 }
1326
Song Zhaod62bb392021-04-23 12:25:49 -07001327 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1328 LIVE_MODE(avsync->mode) &&
1329 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1330 /* outlier by stream error */
1331 avsync->outlier_cnt++;
1332 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1333 /* treat as disc, just drop current frame */
1334 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1335 avsync->outlier_cnt = 0;
1336 action = AV_SYNC_AA_DROP;
1337 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001338 goto done;
1339 }
1340 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1341 pts = systime;
1342 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001343 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001344 goto done;
1345 }
1346
1347 avsync->outlier_cnt = 0;
1348 /* low bound from sync_lost to sync_setup */
1349 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1350 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1351 action = AV_SYNC_AA_RENDER;
1352 goto done;
1353 }
1354
1355 /* high bound of sync_setup */
1356 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1357 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1358 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001359 action = AV_SYNC_AA_RENDER;
1360 goto done;
1361 }
1362
1363 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001364 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001365 action = AV_SYNC_AA_DROP;
1366 goto done;
1367 }
1368
1369 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001370 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001371 action = AV_SYNC_AA_INSERT;
1372 goto done;
1373 }
1374
1375done:
1376 policy->action = action;
1377 policy->delta = (int)(systime - pts);
1378 if (action == AV_SYNC_AA_RENDER) {
1379 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001380 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001381 if (!out_lier)
1382 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001383 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001384 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001385 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1386 msync_session_update_apts(avsync->fd, systime, pts, 0);
1387 log_info("[%d] audio switch done sys %u pts %u",
1388 avsync->session_id, systime, pts);
1389 msync_session_set_audio_switch(avsync->fd, false);
1390 avsync->in_audio_switch = false;
1391 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1392 } else {
1393 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1394 avsync->session_id, action, systime, pts, systime - pts);
1395 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001396 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001397 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001398 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001399 avsync->last_disc_pts != pts &&
1400 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001401 log_info ("[%d]audio disc %u --> %u",
1402 avsync->session_id, systime, pts);
1403 msync_session_set_audio_dis(avsync->fd, pts);
1404 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001405 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001406 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001407
1408 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001409 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001410 if (!avsync->audio_drop_cnt)
1411 avsync->audio_drop_start = now;
1412 avsync->audio_drop_cnt++;
1413 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1414 log_info ("[%d]audio keep dropping sys %u vs a %u",
1415 avsync->session_id, systime, pts);
1416 msync_session_set_audio_dis(avsync->fd, pts);
1417 }
Song Zhao409739b2021-05-12 22:21:40 -07001418 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001419 if (action != AV_SYNC_AA_DROP)
1420 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001421 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001422 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001423 }
1424
1425 return ret;
1426}
1427
1428int av_sync_get_clock(void *sync, pts90K *pts)
1429{
1430 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1431
1432 if (!avsync || !pts)
1433 return -1;
1434 return msync_session_get_wall(avsync->fd, pts, NULL);
1435}
1436
1437static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001438 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001439 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001440{
Song Zhao76005282022-03-08 16:49:41 -08001441 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1442 avsync->session_id, avsync->active_mode, avsync->mode,
1443 v_active, a_active, v_timeout, stat);
1444
1445 /* iptv delayed start */
1446 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1447 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1448
Song Zhaoea5a0412021-01-18 16:40:08 -08001449 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1450 float speed;
1451 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaoe208d692021-04-19 15:38:52 -07001452 a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001453 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001454 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhaoea5a0412021-01-18 16:40:08 -08001455 }
1456
1457 if (!msync_session_get_rate(avsync->fd, &speed)) {
1458 /* speed change is triggered by asink,
1459 * attached audio HAL will handle it
1460 */
1461 if (speed != avsync->speed)
1462 log_info("[%d]new rate %f", avsync->session_id, speed);
1463 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001464 if (avsync->mode != avsync->backup_mode) {
1465 avsync->mode = avsync->backup_mode;
1466 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1467 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001468 } else {
1469 avsync->backup_mode = avsync->mode;
1470 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1471 log_info("[%d]audio to freerun mode", avsync->session_id);
1472 }
1473 avsync->speed = speed;
1474 }
Song Zhaod62bb392021-04-23 12:25:49 -07001475 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1476 struct session_debug debug;
1477 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001478 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001479 avsync->backup_mode = avsync->mode;
1480 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001481 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001482 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001483 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001484 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001485 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001486 log_warn("[%d]audio back to mode %d",
1487 avsync->session_id, avsync->mode);
1488 }
1489 }
Song Zhao76005282022-03-08 16:49:41 -08001490 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1491 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001492 }
1493}
1494
1495static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001496 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001497 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001498{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001499 struct session_debug debug;
1500
Song Zhao76005282022-03-08 16:49:41 -08001501 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1502 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001503 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1504 if (debug.debug_freerun && !avsync->debug_freerun) {
1505 avsync->backup_mode = avsync->mode;
1506 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1507 avsync->debug_freerun = true;
1508 log_warn("[%d]video to freerun mode", avsync->session_id);
1509 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1510 avsync->mode = avsync->backup_mode;
1511 avsync->debug_freerun = false;
1512 log_warn("[%d]video back to mode %d",
1513 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001514 }
1515 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001516}
1517
1518static void * poll_thread(void * arg)
1519{
1520 int ret = 0;
1521 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1522 const int fd = avsync->fd;
1523 struct pollfd pfd = {
1524 /* default blocking capture */
1525 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1526 .fd = avsync->fd,
1527 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001528 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001529
1530 prctl (PR_SET_NAME, "avs_poll");
1531 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001532
1533 if (avsync->type == AV_SYNC_TYPE_AUDIO)
1534 sflag = SRC_A;
1535 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
1536 sflag = SRC_V;
1537
Song Zhaoea5a0412021-01-18 16:40:08 -08001538 while (!avsync->quit_poll) {
1539 for (;;) {
1540 ret = poll(&pfd, 1, 10);
1541 if (ret > 0)
1542 break;
1543 if (avsync->quit_poll)
1544 goto exit;
1545 if (errno == EINTR)
1546 continue;
1547 }
1548
1549 /* error handling */
1550 if (pfd.revents & POLLERR)
1551 log_error("[%d]POLLERR received", avsync->session_id);
1552
Song Zhaod62bb392021-04-23 12:25:49 -07001553 /* mode change. Non-exclusive wait so all the processes
1554 * shall be woken up
1555 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001556 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001557 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001558 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001559
Song Zhao76005282022-03-08 16:49:41 -08001560 msync_session_get_stat(fd, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001561 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001562
1563 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001564 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001565 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001566 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001567 usleep(10000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001568 }
1569 }
1570exit:
1571 log_info("[%d]quit", avsync->session_id);
1572 return NULL;
1573}
1574
Song Zhao623e2f12021-09-03 15:54:04 -07001575#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1576/* return ppm between demod and PCR clock */
1577int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1578{
1579 int fd = -1, ppm = 0, nread;
1580 char buf[128];
1581 uint32_t reg_v, lock;
1582 float val;
1583
1584 fd = open(DEMOD_NODE, O_RDWR);
1585 if (fd < 0) {
1586 log_warn("node not found %s", DEMOD_NODE);
1587 /* do not retry */
1588 avsync->ppm_adjusted = true;
1589 return 0;
1590 }
1591 snprintf(buf, sizeof(buf), "%d", 5);
1592 write(fd, buf, 2);
1593
1594 lseek(fd, 0, SEEK_SET);
1595
1596 nread = read(fd, buf, sizeof(buf));
1597 if (nread <= 0) {
1598 log_error("read error");
1599 goto err;
1600 }
1601 buf[nread] = 0;
1602 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1603 log_error("wrong format %s", buf);
1604 goto err;
1605 }
1606 if (lock != 0x1f) {
1607 log_info("demod not locked");
1608 goto err;
1609 }
1610 if (reg_v > ((2 << 20) - 1))
1611 reg_v -= (2 << 21);
1612 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1613 ppm = val;
1614 log_info("ppm from SFO %d", ppm);
1615 avsync->ppm_adjusted = true;
1616
1617err:
1618 if (fd >= 0)
1619 close(fd);
1620 return ppm;
1621}
1622
Song Zhaod62bb392021-04-23 12:25:49 -07001623int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001624{
1625 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001626 struct pcr_info pcr;
1627 enum pcr_monitor_status status;
1628 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001629 if (!avsync)
1630 return -1;
1631
1632 if (avsync->type != AV_SYNC_TYPE_PCR)
1633 return -2;
1634
Song Zhao623e2f12021-09-03 15:54:04 -07001635 /* initial estimation from Demod SFO HW */
1636 if (!avsync->ppm_adjusted) {
1637 ppm = dmod_get_sfo_dev(avsync);
1638 if (ppm != 0) {
1639 /* ppm > 0 means board clock is faster */
1640 msync_session_set_clock_dev(avsync->fd, -ppm);
1641 }
1642 }
wei.dubcc2ed22021-05-19 07:16:10 -04001643 pcr.monoclk = mono_clock / 1000;
1644 pcr.pts = (long long) pts * 1000 / 90;
1645 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1646
1647 status = pcr_monitor_get_status(avsync->pcr_monitor);
1648
1649 if (status >= DEVIATION_READY) {
1650 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1651 if (avsync->ppm != ppm) {
1652 avsync->ppm = ppm;
1653 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1654 if (msync_session_set_clock_dev(avsync->fd, ppm))
1655 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001656 else
1657 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001658 }
1659 }
1660
Song Zhaod62bb392021-04-23 12:25:49 -07001661 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001662}
1663
Song Zhaod62bb392021-04-23 12:25:49 -07001664int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001665{
1666 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1667
1668 if (!avsync)
1669 return -1;
1670
Song Zhaod62bb392021-04-23 12:25:49 -07001671 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001672}
1673
1674int av_sync_set_session_name(void *sync, const char *name)
1675{
1676 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1677
1678 if (!avsync)
1679 return -1;
1680
1681 return msync_session_set_name(avsync->fd, name);
1682}
yongchun.li107a6162021-05-05 02:38:57 -07001683
1684int av_sync_set_audio_switch(void *sync, bool start)
1685{
1686 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1687 bool v_active, a_active, v_timeout;
1688
1689 if (!avsync)
1690 return -1;
Song Zhao76005282022-03-08 16:49:41 -08001691 if (msync_session_get_stat(avsync->fd, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001692 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001693 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001694 log_error("[%d] can not get session state",
1695 avsync->session_id);
1696 return -1;
1697 }
1698 if (!v_active || !a_active) {
1699 log_error("[%d] no apply if not AV both active v %d a %d",
1700 avsync->session_id, v_active, a_active);
1701 return -1;
1702 }
1703 if (msync_session_set_audio_switch(avsync->fd, start)) {
1704 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1705 return -1;
1706 }
1707 avsync->in_audio_switch = start;
1708 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1709 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1710 return 0;
1711}
1712
1713int av_sync_get_audio_switch(void *sync, bool *start)
1714{
1715 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1716
1717 if (!avsync)
1718 return -1;
Song Zhao76005282022-03-08 16:49:41 -08001719 if (msync_session_get_stat(avsync->fd, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001720 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001721 log_error("[%d] can not audio seamless switch state",
1722 avsync->session_id);
1723 return -1;
1724 }
1725 if (start) *start = avsync->in_audio_switch;
1726 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001727}
Song Zhao8039f562021-05-18 18:11:25 -07001728
Song Zhao623e2f12021-09-03 15:54:04 -07001729enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001730{
1731 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1732
wei.dubcc2ed22021-05-19 07:16:10 -04001733 if (!avsync || !ppm)
1734 return CLK_RECOVERY_ERR;
1735 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001736 return CLK_RECOVERY_NOT_RUNNING;
1737
wei.dubcc2ed22021-05-19 07:16:10 -04001738 if (msync_session_get_clock_dev(avsync->fd, ppm))
1739 return CLK_RECOVERY_ERR;
1740
1741 if (*ppm == 0)
1742 return CLK_RECOVERY_ONGOING;
1743 else
1744 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001745}
Song Zhao95bd0922021-09-21 14:07:46 -07001746
1747static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1748{
1749 int ret;
1750
1751 if (!avsync->frame_q) {
1752 avsync->frame_q = create_q(MAX_FRAME_NUM);
1753 if (!avsync->frame_q) {
1754 log_error("[%d]create queue fail", avsync->session_id);
1755
1756 return -1;
1757 }
1758 }
1759
1760 ret = queue_item(avsync->frame_q, frame);
1761 if (ret)
1762 log_error("%s queue fail:%d", ret);
1763 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1764 return ret;
1765}
1766
1767int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1768{
1769 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1770
1771 if (!avsync)
1772 return -1;
1773 avsync->msys = msys;
1774 return 0;
1775}
1776
1777static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1778{
1779 struct vframe *frame = NULL, *enter_last_frame = NULL;
1780 uint64_t systime;
1781 int toggle_cnt = 0;
1782
1783 enter_last_frame = avsync->last_frame;
1784 systime = avsync->msys;
1785 log_debug("[%d]sys %llu", avsync->session_id, systime);
1786 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1787 if (systime >= frame->mts) {
1788 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1789 toggle_cnt++;
1790
1791 if (avsync->last_frame)
1792 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1793
1794 dqueue_item(avsync->frame_q, (void **)&frame);
1795 if (avsync->last_frame) {
1796 /* free frame that are not for display */
1797 if (toggle_cnt > 1) {
1798 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1799 avsync->last_frame->mts, frame->mts, systime);
1800 avsync->last_frame->free(avsync->last_frame);
1801 }
1802 } else {
1803 avsync->first_frame_toggled = true;
1804 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1805 }
1806 avsync->last_frame = frame;
1807 } else
1808 break;
1809 }
1810
1811 if (avsync->last_frame) {
1812 if (enter_last_frame != avsync->last_frame)
1813 log_debug("[%d]pop %llu", avsync->session_id, avsync->last_frame->pts);
1814 log_trace("[%d]pop=%llu, system=%llu, diff %d(ms), QNum=%d", avsync->session_id,
1815 avsync->last_frame->mts,
1816 systime, (systime - avsync->last_frame->mts) / 1000000,
1817 queue_size(avsync->frame_q));
1818 } else
1819 if (enter_last_frame != avsync->last_frame)
1820 log_debug("[%d]pop (nil)", avsync->session_id);
1821
1822 if (avsync->last_frame)
1823 avsync->last_frame->hold_period++;
1824 return avsync->last_frame;
1825}