blob: f02c7e2f220ad8d61cf4c42a8f2b991ee17daff5 [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"
fei.deng66b4e812022-04-14 12:23:01 +080032#include "aml_version.h"
Song Zhao2f6744b2021-11-03 21:23:50 -070033
Song Zhaoc03ba122020-12-23 21:54:02 -080034enum sync_state {
35 AV_SYNC_STAT_INIT = 0,
36 AV_SYNC_STAT_RUNNING = 1,
37 AV_SYNC_STAT_SYNC_SETUP = 2,
38 AV_SYNC_STAT_SYNC_LOST = 3,
39};
40
yongchun.li107a6162021-05-05 02:38:57 -070041enum audio_switch_state_ {
42 AUDIO_SWITCH_STAT_INIT = 0,
43 AUDIO_SWITCH_STAT_RESET = 1,
44 AUDIO_SWITCH_STAT_START = 2,
45 AUDIO_SWITCH_STAT_FINISH = 3,
yongchun.li59e873d2021-07-07 11:42:38 -070046 AUDIO_SWITCH_STAT_AGAIN = 4,
yongchun.li107a6162021-05-05 02:38:57 -070047};
48
Song Zhaoea5a0412021-01-18 16:40:08 -080049#define SESSION_DEV "avsync_s"
50
Song Zhaoc03ba122020-12-23 21:54:02 -080051struct av_sync_session {
52 /* session id attached */
53 int session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -080054 int fd;
55 bool attached;
56 enum sync_mode mode;
57 /* for audio trickplay */
58 enum sync_mode backup_mode;
59 enum sync_type type;
60 uint32_t start_policy;
bo.xiao5821fc72021-07-11 22:47:00 -040061 int timeout;
Song Zhaoc03ba122020-12-23 21:54:02 -080062
Song Zhaoea5a0412021-01-18 16:40:08 -080063 /* playback time, will stop increasing during pause */
64 pts90K vpts;
65 pts90K apts;
66
67 /* phase adjustment of stream time for rate control (Video ONLY) */
Song Zhaoc03ba122020-12-23 21:54:02 -080068 pts90K phase;
69 bool phase_set;
Song Zhao1561e542022-01-12 10:37:55 -080070 bool phase_adjusted;
Song Zhaoc03ba122020-12-23 21:54:02 -080071
72 /* pts of last rendered frame */
Song Zhaoea5a0412021-01-18 16:40:08 -080073 pts90K last_wall;
Song Zhaoc03ba122020-12-23 21:54:02 -080074 pts90K last_pts;
75 struct vframe *last_frame;
76
Song Zhaoe0bf6ad2021-07-09 11:28:42 -070077 /* pts of last pushed frame */
78 pts90K last_q_pts;
79
Song Zhaoc03ba122020-12-23 21:54:02 -080080 bool first_frame_toggled;
Song Zhaoc03ba122020-12-23 21:54:02 -080081 bool paused;
Song Zhaoea5a0412021-01-18 16:40:08 -080082 enum sync_state state;
Song Zhaoc03ba122020-12-23 21:54:02 -080083 void *pattern_detector;
84 void *frame_q;
Song Zhaoc03ba122020-12-23 21:54:02 -080085
Song Zhaoea5a0412021-01-18 16:40:08 -080086 /* start control */
87 int start_thres;
88 audio_start_cb audio_start;
89 void *audio_start_priv;
90
91 /* render property */
Song Zhaoc03ba122020-12-23 21:54:02 -080092 int delay;
Song Zhao6dce2672022-01-13 11:32:44 -080093 int extra_delay;
Song Zhaoc03ba122020-12-23 21:54:02 -080094 pts90K vsync_interval;
95
96 /* state lock */
97 pthread_mutex_t lock;
98 /* pattern */
99 int last_holding_peroid;
Song Zhaoea5a0412021-01-18 16:40:08 -0800100 bool session_started;
Song Zhaoc03ba122020-12-23 21:54:02 -0800101
102 float speed;
103
Song Zhaoc03ba122020-12-23 21:54:02 -0800104 /* pause pts */
105 pts90K pause_pts;
106 pause_pts_done pause_pts_cb;
107 void *pause_cb_priv;
yongchun.li428390d2022-02-17 17:15:40 -0800108 /* underflow */
109 underflow_detected underflow_cb;
110 void *underflow_cb_priv;
111 struct underflow_config underflow_cfg;
112 struct timespec frame_last_update_time;
Song Zhao5d2b4772021-01-18 16:40:08 -0800113
114 /* log control */
Song Zhaoa2985cb2021-06-24 12:01:47 -0700115 uint32_t last_log_syst;
Song Zhao5d2b4772021-01-18 16:40:08 -0800116 uint32_t sync_lost_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700117 struct timespec sync_lost_print_time;
Song Zhaoea5a0412021-01-18 16:40:08 -0800118
119 pthread_t poll_thread;
120 /* pcr master, IPTV only */
121 bool quit_poll;
122 enum sync_mode active_mode;
Song Zhaof46932e2021-05-21 01:51:45 -0700123 uint32_t disc_thres_min;
124 uint32_t disc_thres_max;
Song Zhao35a82df2021-04-15 10:58:49 -0700125
126 /* error detection */
127 uint32_t last_poptime;
Song Zhaod62bb392021-04-23 12:25:49 -0700128 uint32_t outlier_cnt;
Song Zhao409739b2021-05-12 22:21:40 -0700129 pts90K last_disc_pts;
130
yongchun.li107a6162021-05-05 02:38:57 -0700131 // indicate set audio switch
132 bool in_audio_switch;
133 enum audio_switch_state_ audio_switch_state;
wei.dubcc2ed22021-05-19 07:16:10 -0400134
135 //pcr monitor handle
136 void *pcr_monitor;
137 int ppm;
Song Zhao623e2f12021-09-03 15:54:04 -0700138 bool ppm_adjusted;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700139
140 //video FPS detection
141 pts90K last_fpts;
142 int fps_interval;
143 int fps_interval_acc;
144 int fps_cnt;
145
146 //video freerun with rate control
147 uint32_t last_r_syst;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700148 bool debug_freerun;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700149
150 //Audio dropping detection
151 uint32_t audio_drop_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700152 struct timespec audio_drop_start;
Song Zhao95bd0922021-09-21 14:07:46 -0700153
154 /*system mono time for current vsync interrupt */
155 uint64_t msys;
Song Zhaoc03ba122020-12-23 21:54:02 -0800156};
157
158#define MAX_FRAME_NUM 32
159#define DEFAULT_START_THRESHOLD 2
160#define TIME_UNIT90K (90000)
Song Zhaof46932e2021-05-21 01:51:45 -0700161#define AV_DISC_THRES_MIN (TIME_UNIT90K / 3)
162#define AV_DISC_THRES_MAX (TIME_UNIT90K * 10)
Song Zhao7daf3a12021-05-10 22:22:25 -0700163#define A_ADJ_THREDHOLD_HB (900 * 6) //60ms
164#define A_ADJ_THREDHOLD_LB (900 * 2) //20ms
Song Zhao52f55192021-05-06 10:52:21 -0700165#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800166#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhao76005282022-03-08 16:49:41 -0800167#define LIVE_MODE(m) ((m) == AV_SYNC_MODE_PCR_MASTER || (m) == AV_SYNC_MODE_IPTV)
Song Zhao7e24b182022-04-01 08:46:40 -0700168#define V_DISC_MODE(mode) (LIVE_MODE(mode) || (mode) == AV_SYNC_MODE_VMASTER)
Song Zhaod62bb392021-04-23 12:25:49 -0700169
Song Zhao065800e2021-05-26 15:56:06 -0700170#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
Song Zhaod62bb392021-04-23 12:25:49 -0700171#define OUTLIER_MAX_CNT 8
Song Zhaoa2985cb2021-06-24 12:01:47 -0700172#define VALID_TS(x) ((x) != -1)
yongchun.li428390d2022-02-17 17:15:40 -0800173#define UNDERFLOW_CHECK_THRESH_MS (100)
Song Zhaoc03ba122020-12-23 21:54:02 -0800174
yongchun.li0ee6e372021-08-20 04:26:04 -0700175static uint64_t time_diff (struct timespec *b, struct timespec *a);
Song Zhaoc03ba122020-12-23 21:54:02 -0800176static bool frame_expire(struct av_sync_session* avsync,
177 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800178 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800179 struct vframe * frame,
180 struct vframe * next_frame,
181 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700182static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800183 int cur_period,
184 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800185static void * poll_thread(void * arg);
186static void trigger_audio_start_cb(struct av_sync_session *avsync,
187 avs_ascb_reason reason);
Song Zhao95bd0922021-09-21 14:07:46 -0700188static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync);
189static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame);
Song Zhao2f6744b2021-11-03 21:23:50 -0700190pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER;
Song Zhaoc03ba122020-12-23 21:54:02 -0800191
Song Zhaoea5a0412021-01-18 16:40:08 -0800192int av_sync_open_session(int *session_id)
193{
Song Zhao2f6744b2021-11-03 21:23:50 -0700194 int fd = -1;
Song Zhaoea5a0412021-01-18 16:40:08 -0800195 int id, rc;
196
Song Zhao2f6744b2021-11-03 21:23:50 -0700197 pthread_mutex_lock(&glock);
198 fd = msync_create_session();
Song Zhaoea5a0412021-01-18 16:40:08 -0800199 if (fd < 0) {
200 log_error("fail");
Song Zhao2f6744b2021-11-03 21:23:50 -0700201 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800202 }
203 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
204 if (rc) {
205 log_error("new session errno:%d", errno);
Song Zhao2f6744b2021-11-03 21:23:50 -0700206 msync_destory_session(fd);
207 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800208 }
209 *session_id = id;
Song Zhao2f6744b2021-11-03 21:23:50 -0700210 log_debug("new avsession id %d fd %d", id, fd);
211exit:
212 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800213 return fd;
214}
215
216void av_sync_close_session(int session)
217{
Song Zhao2f6744b2021-11-03 21:23:50 -0700218 log_debug("session closed fd %d", session);
219 pthread_mutex_lock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800220 msync_destory_session(session);
Song Zhao2f6744b2021-11-03 21:23:50 -0700221 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800222}
223
224static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800225 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800226 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800227 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800228 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800229{
230 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800231 char dev_name[20];
Song Zhao2f6744b2021-11-03 21:23:50 -0700232 int retry = 10;
Song Zhaoc03ba122020-12-23 21:54:02 -0800233
Song Zhao95bd0922021-09-21 14:07:46 -0700234 log_info("[%d] mode %d type %d", session_id, mode, type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800235 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
236 if (!avsync) {
237 log_error("OOM");
238 return NULL;
239 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800240
Song Zhao95bd0922021-09-21 14:07:46 -0700241 if (type == AV_SYNC_TYPE_VIDEO &&
242 mode == AV_SYNC_MODE_VIDEO_MONO) {
243 if (session_id < AV_SYNC_SESSION_V_MONO) {
244 log_error("wrong session id %d", session_id);
245 goto err;
246 }
247 avsync->type = type;
248 avsync->mode = mode;
249 avsync->fd = -1;
250 avsync->session_id = session_id;
251 log_info("[%d]init", avsync->session_id);
252 return avsync;
253 }
254
Song Zhaoea5a0412021-01-18 16:40:08 -0800255 if (type == AV_SYNC_TYPE_VIDEO) {
256 avsync->pattern_detector = create_pattern_detector();
257 if (!avsync->pattern_detector) {
258 log_error("pd create fail");
259 goto err;
260 }
261
262 if (!start_thres)
263 avsync->start_thres = DEFAULT_START_THRESHOLD;
264 else {
265 if (start_thres > 5) {
266 log_error("start_thres too big: %d", start_thres);
267 goto err2;
268 }
269 avsync->start_thres = start_thres;
270 }
271 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800272 avsync->phase_adjusted = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800273 avsync->first_frame_toggled = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800274 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800275
276 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800277 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800278 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800279 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800280 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800281 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800282 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800283 avsync->speed = 1.0f;
284 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhao409739b2021-05-12 22:21:40 -0700285 avsync->vsync_interval = -1;
286 avsync->last_disc_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700287 avsync->last_log_syst = -1;
288 avsync->last_pts = -1;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700289 avsync->last_q_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700290 avsync->last_wall = -1;
291 avsync->fps_interval = -1;
292 avsync->last_r_syst = -1;
bo.xiao5821fc72021-07-11 22:47:00 -0400293 avsync->timeout = -1;
294
Song Zhaof46932e2021-05-21 01:51:45 -0700295 if (msync_session_get_disc_thres(session_id,
296 &avsync->disc_thres_min, &avsync->disc_thres_max)) {
297 log_error("fail to get disc thres", dev_name, errno);
298 avsync->disc_thres_min = AV_DISC_THRES_MIN;
299 avsync->disc_thres_max = AV_DISC_THRES_MAX;
300 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800301
302 pthread_mutex_init(&avsync->lock, NULL);
Song Zhao9c09f772022-01-07 14:26:50 -0800303 log_info("[%d] start_thres %d disc_thres %u/%u", session_id,
Song Zhao95bd0922021-09-21 14:07:46 -0700304 start_thres, avsync->disc_thres_min, avsync->disc_thres_max);
Song Zhaoea5a0412021-01-18 16:40:08 -0800305
306 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
Song Zhao2f6744b2021-11-03 21:23:50 -0700307 while (retry) {
308 /* wait for sysfs to update */
309 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
310 if (avsync->fd > 0)
311 break;
312
313 retry--;
314 if (!retry) {
315 log_error("open %s errno %d", dev_name, errno);
316 goto err2;
317 }
318 usleep(20000);
Song Zhaoea5a0412021-01-18 16:40:08 -0800319 }
320
wei.dubcc2ed22021-05-19 07:16:10 -0400321 if (avsync->type == AV_SYNC_TYPE_PCR) {
322 if (pcr_monitor_init(&avsync->pcr_monitor)) {
323 log_error("pcr monitor init");
Song Zhao9cd27a52021-07-26 15:27:38 +0000324 goto err3;
wei.dubcc2ed22021-05-19 07:16:10 -0400325 }
326 }
327
Song Zhaoea5a0412021-01-18 16:40:08 -0800328 if (!attach) {
329 msync_session_set_mode(avsync->fd, mode);
330 avsync->mode = mode;
Song Zhao7e24b182022-04-01 08:46:40 -0700331 if (avsync->mode == AV_SYNC_MODE_VMASTER)
332 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
Song Zhaoea5a0412021-01-18 16:40:08 -0800333 } else {
334 avsync->attached = true;
335 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
336 log_error("get mode");
Song Zhao9cd27a52021-07-26 15:27:38 +0000337 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800338 }
339 avsync->backup_mode = avsync->mode;
bo.xiao5821fc72021-07-11 22:47:00 -0400340 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800341 log_error("get policy");
Song Zhao9cd27a52021-07-26 15:27:38 +0000342 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800343 }
Song Zhao76005282022-03-08 16:49:41 -0800344 if (msync_session_get_stat(avsync->fd, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700345 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -0700346 log_error("get state");
Song Zhao9cd27a52021-07-26 15:27:38 +0000347 goto err4;
yongchun.li107a6162021-05-05 02:38:57 -0700348 }
349 if (avsync->in_audio_switch) {
350 log_info("audio_switch_state reseted the audio");
351 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
352 }
353
Song Zhaoea5a0412021-01-18 16:40:08 -0800354 log_info("[%d]retrieve sync mode %d policy %d",
355 session_id, avsync->mode, avsync->start_policy);
356 }
357
Song Zhao67c937b2021-10-01 11:21:32 -0700358 /* debug log level */
359 {
360 const char *env= getenv( "AML_AVSYNC_DEBUG_LEVEL");
361 if ( env ) {
362 log_set_level(atoi(env));
363 }
364 }
365
Song Zhaoc03ba122020-12-23 21:54:02 -0800366 return avsync;
Song Zhao9cd27a52021-07-26 15:27:38 +0000367err4:
wei.dubcc2ed22021-05-19 07:16:10 -0400368 if (avsync->pcr_monitor)
369 pcr_monitor_destroy(avsync->pcr_monitor);
Song Zhao9cd27a52021-07-26 15:27:38 +0000370err3:
371 close(avsync->fd);
Song Zhaoea5a0412021-01-18 16:40:08 -0800372err2:
373 destroy_pattern_detector(avsync->pattern_detector);
374err:
375 free(avsync);
376 return NULL;
377}
378
379void* av_sync_create(int session_id,
380 enum sync_mode mode,
381 enum sync_type type,
382 int start_thres)
383{
384 return create_internal(session_id, mode,
385 type, start_thres, false);
386}
387
388void* av_sync_attach(int session_id, enum sync_type type)
389{
Song Zhao95bd0922021-09-21 14:07:46 -0700390 if (type == AV_SYNC_TYPE_VIDEO)
391 return NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800392 return create_internal(session_id, AV_SYNC_MODE_MAX,
393 type, 0, true);
394}
395
396int av_sync_video_config(void *sync, struct video_config* config)
397{
398 struct av_sync_session *avsync = (struct av_sync_session *)sync;
399
400 if (!avsync || !config)
401 return -1;
402
403 if (config->delay != 1 && config->delay != 2) {
404 log_error("invalid delay: %d\n", config->delay);
405 return -1;
406 }
407
408 avsync->delay = config->delay;
Song Zhao6dce2672022-01-13 11:32:44 -0800409 avsync->extra_delay = config->extra_delay * 90;
Song Zhaoea5a0412021-01-18 16:40:08 -0800410
Song Zhao6dce2672022-01-13 11:32:44 -0800411 log_info("[%d] vsync delay: %d extra_delay: %d ms",
412 avsync->session_id, config->delay, config->extra_delay);
Song Zhaoea5a0412021-01-18 16:40:08 -0800413 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800414}
415
416static int internal_stop(struct av_sync_session *avsync)
417{
418 int ret = 0;
419 struct vframe *frame;
420
421 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800422 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
423 frame->free(frame);
424 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800425 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800426 pthread_mutex_unlock(&avsync->lock);
427 return ret;
428}
429
430/* destroy and detach from kernel session */
431void av_sync_destroy(void *sync)
432{
433 struct av_sync_session *avsync = (struct av_sync_session *)sync;
434
435 if (!avsync)
436 return;
437
Song Zhao95bd0922021-09-21 14:07:46 -0700438 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
439 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
440 log_info("[%d]done", avsync->session_id);
441 internal_stop(avsync);
442 destroy_q(avsync->frame_q);
443 free(avsync);
444 return;
445 }
Song Zhaob5458b32021-11-12 15:58:47 -0800446 log_info("[%d]begin type %d", avsync->session_id, avsync->type);
Song Zhaoea5a0412021-01-18 16:40:08 -0800447 if (avsync->state != AV_SYNC_STAT_INIT) {
448 if (avsync->type == AV_SYNC_TYPE_VIDEO)
449 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800450
Song Zhaoea5a0412021-01-18 16:40:08 -0800451 avsync->quit_poll = true;
452 if (avsync->poll_thread) {
453 pthread_join(avsync->poll_thread, NULL);
454 avsync->poll_thread = 0;
455 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700456 if (avsync->type == AV_SYNC_TYPE_AUDIO)
457 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoaf368d52021-02-17 17:53:45 -0800458 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800459
Song Zhaoea5a0412021-01-18 16:40:08 -0800460 if (avsync->session_started) {
461 if (avsync->type == AV_SYNC_TYPE_VIDEO)
462 msync_session_set_video_stop(avsync->fd);
463 else
464 msync_session_set_audio_stop(avsync->fd);
465 }
wei.dubcc2ed22021-05-19 07:16:10 -0400466
467 if(avsync->pcr_monitor)
468 pcr_monitor_destroy(avsync->pcr_monitor);
469
Song Zhaoea5a0412021-01-18 16:40:08 -0800470 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800471 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800472 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
473 destroy_q(avsync->frame_q);
474 destroy_pattern_detector(avsync->pattern_detector);
475 }
Song Zhaob5458b32021-11-12 15:58:47 -0800476 log_info("[%d]done type %d", avsync->session_id, avsync->type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800477 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800478}
479
bo.xiao5821fc72021-07-11 22:47:00 -0400480int avs_sync_set_start_policy(void *sync, struct start_policy* st_policy)
Song Zhaoea5a0412021-01-18 16:40:08 -0800481{
482 struct av_sync_session *avsync = (struct av_sync_session *)sync;
483
484 if (!avsync || !avsync->fd)
485 return -1;
486
bo.xiao5821fc72021-07-11 22:47:00 -0400487 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 -0800488 if (LIVE_MODE(avsync->mode) &&
489 st_policy->policy != AV_SYNC_START_ASAP) {
490 log_error("policy %d not supported in live mode", st_policy->policy);
491 return -1;
492 }
493
bo.xiao5821fc72021-07-11 22:47:00 -0400494 avsync->start_policy = st_policy->policy;
495 avsync->timeout = st_policy->timeout;
Song Zhao76005282022-03-08 16:49:41 -0800496
Song Zhaoea5a0412021-01-18 16:40:08 -0800497 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400498 if (st_policy->policy != AV_SYNC_START_NONE &&
499 st_policy->policy != AV_SYNC_START_V_PEEK)
500 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800501
502 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800503}
504
505int av_sync_pause(void *sync, bool pause)
506{
507 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700508 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800509 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800510
Song Zhaob5458b32021-11-12 15:58:47 -0800511 if (!avsync) {
512 log_error("invalid handle");
Song Zhaoc03ba122020-12-23 21:54:02 -0800513 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800514 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800515
Song Zhaob5458b32021-11-12 15:58:47 -0800516 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
517 log_warn("ignore pause in pcr master mode");
Song Zhaoea5a0412021-01-18 16:40:08 -0800518 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800519 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800520
Song Zhao76005282022-03-08 16:49:41 -0800521 rc = msync_session_get_stat(avsync->fd, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -0700522 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700523 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700524
yongchun.li5f52fb02021-06-04 18:13:05 -0700525 /* ignore only when video try to pause when audio is acive, on which
526 the control of the STC will be relays.
527 When resume,it can do always as it is possible that video just
528 paused earlier without audio yet,then audio added later before resume.
529 We shall not igore that otherwise it could cause video freeze. */
530 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
531 avsync->type == AV_SYNC_TYPE_VIDEO &&
532 a_active &&
533 !avsync->in_audio_switch) {
534 if (!pause) {
535 log_info("[%d] clear video pause when audio active",
536 avsync->session_id);
537 avsync->paused = pause;
538 } else {
539 log_info("[%d] ignore the pause from video when audio active",
540 avsync->session_id);
541 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800542 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700543 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800544
yongchun.li107a6162021-05-05 02:38:57 -0700545 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
546 log_info("[%d] ignore the pause from audio", avsync->session_id);
547 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
548 return 0;
549 }
550
Song Zhaoea5a0412021-01-18 16:40:08 -0800551 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800552 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800553 log_info("[%d]paused:%d type:%d rc %d",
554 avsync->session_id, pause, avsync->type, rc);
yongchun.li428390d2022-02-17 17:15:40 -0800555 if (!avsync->paused && avsync->first_frame_toggled) {
556 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
557 log_info("[%d] resume update new frame time", avsync->session_id);
558 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800559 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800560}
561
562int av_sync_push_frame(void *sync , struct vframe *frame)
563{
564 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700565 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800566 struct av_sync_session *avsync = (struct av_sync_session *)sync;
567
568 if (!avsync)
569 return -1;
570
Song Zhao95bd0922021-09-21 14:07:46 -0700571 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
572 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
573 return video_mono_push_frame(avsync, frame);
574
Song Zhaoea5a0412021-01-18 16:40:08 -0800575 if (!avsync->frame_q) {
576 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400577 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800578 log_error("[%d]get policy", avsync->session_id);
579 return -1;
580 }
581
582 avsync->frame_q = create_q(MAX_FRAME_NUM);
583 if (!avsync->frame_q) {
584 log_error("[%d]create queue fail", avsync->session_id);
yongchun.li0ee6e372021-08-20 04:26:04 -0700585
Song Zhaoea5a0412021-01-18 16:40:08 -0800586 return -1;
587 }
588
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700589 {
Song Zhaoea5a0412021-01-18 16:40:08 -0800590 int ret;
591
592 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
593 if (ret) {
594 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
595 destroy_q(avsync->frame_q);
596 return -1;
597 }
598 }
599 }
600
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700601 if (avsync->last_q_pts != -1) {
Song Zhao7e24b182022-04-01 08:46:40 -0700602 if (frame->pts != -1 && avsync->mode == AV_SYNC_MODE_VMASTER) {
603 /* Sometimes app will fake PTS for trickplay, video PTS gap
604 * is really big depending on the speed. Have to adjust the
605 * threshold dynamically.
606 */
607 int gap = (int)(frame->pts - avsync->last_q_pts);
608 if (gap > avsync->disc_thres_min) {
609 avsync->disc_thres_min = gap * 6;
610 avsync->disc_thres_max = gap * 20;
611 msync_session_set_wall_adj_thres(avsync->fd, avsync->disc_thres_min);
612 msync_session_set_disc_thres(avsync->session_id,
613 avsync->disc_thres_min, avsync->disc_thres_max);
614 log_info("[%d] update disc_thres to %d/%d",avsync->session_id,
615 avsync->disc_thres_min, avsync->disc_thres_max);
616 }
617 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700618 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
619 /* TODO: wrong, should remove from back of queue */
Song Zhaoc03ba122020-12-23 21:54:02 -0800620 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700621 if (prev) {
622 prev->free(prev);
623 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
624 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700625 } else if (avsync->fps_cnt < 100) {
626 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700627
628 if (interval > 0 && interval <= 4500) {
629 if (avsync->fps_interval_acc == -1) {
630 avsync->fps_interval_acc = interval;
631 avsync->fps_cnt = 1;
632 } else {
633 avsync->fps_interval_acc += interval;
634 avsync->fps_cnt++;
635 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
636 if (avsync->fps_cnt == 100)
637 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
638 }
639 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800640 }
641 }
642
Song Zhao065800e2021-05-26 15:56:06 -0700643 if (frame->duration == -1)
644 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800645 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700646 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800647 ret = queue_item(avsync->frame_q, frame);
648 if (avsync->state == AV_SYNC_STAT_INIT &&
649 queue_size(avsync->frame_q) >= avsync->start_thres) {
650 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaoea5a0412021-01-18 16:40:08 -0800651 log_info("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800652 }
653
654 if (ret)
Song Zhaoe1b65602022-01-06 08:03:46 -0800655 log_error("queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400656 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800657 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800658}
659
660struct vframe *av_sync_pop_frame(void *sync)
661{
Song Zhaoea5a0412021-01-18 16:40:08 -0800662 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800663 struct av_sync_session *avsync = (struct av_sync_session *)sync;
664 int toggle_cnt = 0;
665 uint32_t systime;
Song Zhao468fd652021-01-15 22:13:04 -0800666 bool pause_pts_reached = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800667 uint32_t interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800668
Song Zhao95bd0922021-09-21 14:07:46 -0700669 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
670 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
671 return video_mono_pop_frame(avsync);
672
Song Zhaoc03ba122020-12-23 21:54:02 -0800673 pthread_mutex_lock(&avsync->lock);
674 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhao2f6744b2021-11-03 21:23:50 -0700675 log_debug("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800676 goto exit;
677 }
678
Song Zhaoea5a0412021-01-18 16:40:08 -0800679 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700680 uint32_t pts;
681
Song Zhaoc03ba122020-12-23 21:54:02 -0800682 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800683 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800684 goto exit;
685 }
Song Zhao35a82df2021-04-15 10:58:49 -0700686 msync_session_get_wall(avsync->fd, &systime, &interval);
687 pts = frame->pts - avsync->delay * interval;
688 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800689 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700690 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800691 }
692
Song Zhaoea5a0412021-01-18 16:40:08 -0800693 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700694 !avsync->first_frame_toggled &&
695 !msync_clock_started(avsync->fd)) {
696 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800697 log_trace("[%d]clock not started", avsync->session_id);
698 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800699 }
700
Song Zhaoea5a0412021-01-18 16:40:08 -0800701 enter_last_frame = avsync->last_frame;
702 msync_session_get_wall(avsync->fd, &systime, &interval);
703
704 /* handle refresh rate change */
705 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
706 avsync->vsync_interval != interval) {
707 log_info("[%d]vsync interval update %d --> %u",
708 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700709 if (avsync->fps_interval == -1)
710 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800711 avsync->vsync_interval = interval;
712 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800713 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700714 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800715 reset_pattern(avsync->pattern_detector);
716 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800717 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
718 struct vframe *next_frame = NULL;
719
720 peek_item(avsync->frame_q, (void **)&next_frame, 1);
721 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700722 log_debug("[%d]cur_f %u next_f %u size %d",
723 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800724 if (frame_expire(avsync, systime, interval,
725 frame, next_frame, toggle_cnt)) {
726 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800727 toggle_cnt++;
728
Song Zhao35a82df2021-04-15 10:58:49 -0700729 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800730 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700731 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700732 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700733 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
734 if (next_frame)
735 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
736 }
Song Zhao35a82df2021-04-15 10:58:49 -0700737
Song Zhaoc03ba122020-12-23 21:54:02 -0800738 if (avsync->last_frame)
739 avsync->last_holding_peroid = avsync->last_frame->hold_period;
740
741 dqueue_item(avsync->frame_q, (void **)&frame);
742 if (avsync->last_frame) {
743 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800744 if (toggle_cnt > 1) {
Song Zhao35a82df2021-04-15 10:58:49 -0700745 log_debug("[%d]free %u cur %u system/d %u/%u", avsync->session_id,
746 avsync->last_frame->pts, frame->pts, systime, systime - avsync->last_poptime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800747 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800748 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800749 } else {
750 avsync->first_frame_toggled = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800751 log_info("[%d]first frame %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800752 }
753 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800754 avsync->last_pts = frame->pts;
yongchun.li428390d2022-02-17 17:15:40 -0800755 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
Song Zhaoc03ba122020-12-23 21:54:02 -0800756 } else
757 break;
758 }
759
760 /* pause pts */
761 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800762 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800763 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800764 else
Song Zhao468fd652021-01-15 22:13:04 -0800765 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
766 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
767 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
768 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
769 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800770
Song Zhao468fd652021-01-15 22:13:04 -0800771 if (pause_pts_reached) {
772 if (avsync->pause_pts_cb)
773 avsync->pause_pts_cb(avsync->pause_pts,
Song Zhaoc03ba122020-12-23 21:54:02 -0800774 avsync->pause_cb_priv);
775
Song Zhao468fd652021-01-15 22:13:04 -0800776 /* stay in paused until av_sync_pause(false) */
777 avsync->paused = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800778 log_info ("[%d]reach pause pts: %u",
Song Zhaob5458b32021-11-12 15:58:47 -0800779 avsync->session_id, avsync->pause_pts);
Song Zhaoad7c8232021-12-14 11:46:48 -0800780 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoc03ba122020-12-23 21:54:02 -0800781 }
782
783exit:
784 pthread_mutex_unlock(&avsync->lock);
yongchun.li428390d2022-02-17 17:15:40 -0800785
786 /* underflow check */
787 if (avsync->session_started && avsync->first_frame_toggled &&
788 (avsync->paused == false) && (avsync->state >= AV_SYNC_STAT_RUNNING) &&
789 avsync->underflow_cb && peek_item(avsync->frame_q, (void **)&frame, 0))
790 {/* empty queue in normal play */
791 struct timespec now;
792 int diff_ms;
793 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
794 diff_ms = time_diff(&now, &avsync->frame_last_update_time)/1000;
795 if(diff_ms >= (avsync->underflow_cfg.time_thresh
796 + avsync->vsync_interval*avsync->last_holding_peroid/90)) {
797 log_info ("[%d]underflow detected: %u", avsync->session_id, avsync->last_pts);
798 avsync->underflow_cb (avsync->last_pts,
799 avsync->underflow_cb_priv);
800 /* update time to control the underflow check call backs */
801 avsync->frame_last_update_time = now;
802 }
803 }
804
Song Zhaoc03ba122020-12-23 21:54:02 -0800805 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800806 if (enter_last_frame != avsync->last_frame)
807 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
bo.xiao1f94b352021-08-02 03:53:47 -0400808 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 -0700809 /* don't update vpts for out_lier */
810 if (avsync->last_frame->duration != -1)
811 msync_session_update_vpts(avsync->fd, systime,
812 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800813 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800814 if (enter_last_frame != avsync->last_frame)
815 log_debug("[%d]pop (nil)", avsync->session_id);
816
Song Zhao35a82df2021-04-15 10:58:49 -0700817 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800818 if (avsync->last_frame)
819 avsync->last_frame->hold_period++;
820 return avsync->last_frame;
821}
822
Song Zhaoc03ba122020-12-23 21:54:02 -0800823static inline uint32_t abs_diff(uint32_t a, uint32_t b)
824{
Song Zhaoea5a0412021-01-18 16:40:08 -0800825 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800826}
827
yongchun.li0ee6e372021-08-20 04:26:04 -0700828static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800829{
yongchun.li0ee6e372021-08-20 04:26:04 -0700830 return (b->tv_sec - a->tv_sec)*1000000 + (b->tv_nsec/1000 - a->tv_nsec/1000);
Song Zhaoc03ba122020-12-23 21:54:02 -0800831}
832
Song Zhaoc03ba122020-12-23 21:54:02 -0800833static bool frame_expire(struct av_sync_session* avsync,
834 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800835 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800836 struct vframe * frame,
837 struct vframe * next_frame,
838 int toggle_cnt)
839{
Song Zhao6dce2672022-01-13 11:32:44 -0800840 uint32_t fpts = frame->pts + avsync->extra_delay;
841 uint32_t nfpts = -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800842 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800843 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800844
845 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
846 return false;
847
848 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
849 return true;
850
Song Zhaoad7c8232021-12-14 11:46:48 -0800851 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS &&
852 avsync->pause_pts == frame->pts)
853 return true;
854
Song Zhao08fa16b2021-12-08 14:30:17 -0800855 if (systime == AV_SYNC_INVALID_PTS &&
856 avsync->mode == AV_SYNC_MODE_AMASTER)
857 return false;
858
Song Zhao6dce2672022-01-13 11:32:44 -0800859 if (next_frame)
860 nfpts = next_frame->pts + avsync->extra_delay;
861
Song Zhao7e24b182022-04-01 08:46:40 -0700862 if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
fei.deng63e43e12021-09-23 19:44:01 +0800863 /* We need to ensure that the video outputs smoothly,
864 so output video frame by frame hold_period */
865 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
866 avsync->last_frame &&
867 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
868 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
869 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700870 return true;
871 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700872 }
873
Song Zhaoc03ba122020-12-23 21:54:02 -0800874 if (!fpts) {
875 if (avsync->last_frame) {
876 /* try to accumulate duration as PTS */
877 fpts = avsync->vpts + avsync->last_frame->duration;
878 } else {
879 fpts = avsync->vpts;
880 }
881 }
882 systime += pts_correction;
883
884 /* phase adjustment */
885 if (avsync->phase_set)
886 systime += avsync->phase;
887
yongchun.lia50b1e92021-08-07 01:11:54 +0000888 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800889 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000890 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700891 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800892 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800893 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800894 return false;
895
Song Zhaoa2985cb2021-06-24 12:01:47 -0700896 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
897 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700898 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800899
yongchun.li0ee6e372021-08-20 04:26:04 -0700900 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700901 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800902 avsync->last_pts = fpts;
903 if (time_diff(&now, &avsync->sync_lost_print_time) >=
904 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700905 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800906 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800907 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700908 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800909 } else
910 avsync->sync_lost_cnt++;
911 }
Song Zhaod62bb392021-04-23 12:25:49 -0700912
913 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
914 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700915 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700916 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700917 /* outlier by stream error */
918 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700919 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700920 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
921 log_info("render outlier %u", fpts);
922 return true;
923 }
924 }
925
926 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800927 avsync->state = AV_SYNC_STAT_SYNC_LOST;
928 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800929 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700930 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800931 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700932
Song Zhao7e24b182022-04-01 08:46:40 -0700933 if (V_DISC_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700934 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700935 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700936 msync_session_set_video_dis(avsync->fd, fpts);
937 avsync->last_disc_pts = fpts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700938 }
939
940 if ((int)(systime - fpts) > 0) {
941 if ((int)(systime - fpts) < avsync->disc_thres_max) {
942 /* catch up PCR */
Song Zhaof46932e2021-05-21 01:51:45 -0700943 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700944 } else {
945 /* render according to FPS */
946 if (!VALID_TS(avsync->last_r_syst) ||
947 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
948 avsync->last_r_syst = systime;
949 return true;
950 }
951 return false;
952 }
953 } else if (LIVE_MODE(avsync->mode)) {
954 /* hold if the gap is small */
955 if ((int)(fpts - systime) < avsync->disc_thres_max) {
956 return false;
957 } else {
958 /* render according to FPS */
959 if (!VALID_TS(avsync->last_r_syst) ||
960 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
961 avsync->last_r_syst = systime;
962 return true;
963 }
964 return false;
965 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800966 }
967 }
968
Song Zhao52f55192021-05-06 10:52:21 -0700969 /* In some cases, keeping pattern will enlarge the gap */
970 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
971 avsync->first_frame_toggled) {
972 reset_pattern(avsync->pattern_detector);
Song Zhaof46932e2021-05-21 01:51:45 -0700973 log_warn("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700974 systime, fpts);
975 }
976
Song Zhaoc03ba122020-12-23 21:54:02 -0800977 expire = (int)(systime - fpts) >= 0;
978
979 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -0800980 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800981 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -0800982 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800983 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800984 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -0800985 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800986 }
Song Zhao6dce2672022-01-13 11:32:44 -0800987 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -0800988 && avsync->first_frame_toggled) {
989 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -0800990 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800991 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800992 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -0800993 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800994 }
995 }
996
Song Zhaoa58c3e92021-03-09 18:52:55 -0800997 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -0800998 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -0800999 (avsync->last_frame?avsync->last_frame->hold_period:0),
1000 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -08001001 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -08001002
1003 if (expire) {
1004 avsync->vpts = fpts;
1005 /* phase adjustment */
1006 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +00001007 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -08001008 if ((int)(systime - fpts) >= 0 &&
1009 (int)(fpts + interval - systime) > 0) {
1010 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -08001011 avsync->phase_set = true;
yongchun.lia50b1e92021-08-07 01:11:54 +00001012 log_info("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -08001013 }
Song Zhao1561e542022-01-12 10:37:55 -08001014 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -08001015 if ((int)(systime - fpts) >= 0 &&
1016 (int)(fpts + interval - systime) > 0) {
1017 int vsync_pts_delta = (int)(systime - fpts);
1018
1019 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1020 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001021 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001022 log_info("[%d] too aligned adjust phase to %d",
1023 avsync->session_id, (int)avsync->phase);
1024 }
1025 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001026 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001027 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -08001028 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -08001029 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001030 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001031 }
1032 return expire;
1033}
1034
Song Zhao35a82df2021-04-15 10:58:49 -07001035static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001036{
Song Zhao35a82df2021-04-15 10:58:49 -07001037 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001038 log_trace("[%d]cur_period: %d last_period: %d",
1039 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -07001040 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
1041 ret = true;
1042 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
1043 ret = true;
1044 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
1045 ret = true;
1046 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
1047 ret = true;
1048
1049 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -08001050}
1051
1052int av_sync_set_speed(void *sync, float speed)
1053{
1054 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1055
1056 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001057 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001058 return -1;
1059 }
1060
Song Zhao76005282022-03-08 16:49:41 -08001061 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001062 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001063 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001064 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001065
Song Zhaoea5a0412021-01-18 16:40:08 -08001066 avsync->speed = speed;
1067
1068 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
1069 if (speed == 1.0) {
1070 avsync->mode = avsync->backup_mode;
1071 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1072 } else {
1073 avsync->backup_mode = avsync->mode;
1074 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1075 log_info("[%d]audio to freerun mode", avsync->session_id);
1076 }
1077 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001078
Song Zhaoea5a0412021-01-18 16:40:08 -08001079 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1080 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001081}
1082
1083int av_sync_change_mode(void *sync, enum sync_mode mode)
1084{
1085 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1086
1087 if (!avsync)
1088 return -1;
1089
Song Zhaoea5a0412021-01-18 16:40:08 -08001090 if (msync_session_set_mode(avsync->fd, mode)) {
1091 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001092 return -1;
1093 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001094 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001095 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001096 return 0;
1097}
1098
Song Zhao01031bb2021-05-13 21:23:20 -07001099int av_sync_get_mode(void *sync, enum sync_mode *mode)
1100{
1101 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1102
1103 if (!avsync || !mode)
1104 return -1;
1105
1106 *mode = avsync->mode;
1107 return 0;
1108}
1109
Song Zhaoc03ba122020-12-23 21:54:02 -08001110int av_sync_set_pause_pts(void *sync, pts90K pts)
1111{
1112 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1113
1114 if (!avsync)
1115 return -1;
1116
1117 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001118 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001119 return 0;
1120}
1121
1122int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1123{
1124 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1125
1126 if (!avsync)
1127 return -1;
1128
1129 avsync->pause_pts_cb = cb;
1130 avsync->pause_cb_priv = priv;
1131 return 0;
1132}
Song Zhaoea5a0412021-01-18 16:40:08 -08001133
yongchun.li428390d2022-02-17 17:15:40 -08001134int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1135{
1136 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1137
1138 if (!avsync)
1139 return -1;
1140
1141 avsync->underflow_cb = cb;
1142 avsync->underflow_cb_priv = priv;
1143
1144 if (cfg)
1145 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1146 else
1147 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1148
1149 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1150 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1151 avsync->underflow_cfg.time_thresh);
1152 return 0;
1153}
Song Zhaoea5a0412021-01-18 16:40:08 -08001154static void trigger_audio_start_cb(struct av_sync_session *avsync,
1155 avs_ascb_reason reason)
1156{
1157 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001158 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001159 pthread_mutex_lock(&avsync->lock);
1160 if (avsync->audio_start) {
1161 avsync->audio_start(avsync->audio_start_priv, reason);
1162 avsync->session_started = true;
1163 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001164 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001165 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1166 }
1167 pthread_mutex_unlock(&avsync->lock);
1168 }
1169}
1170
1171avs_start_ret av_sync_audio_start(
1172 void *sync,
1173 pts90K pts,
1174 pts90K delay,
1175 audio_start_cb cb,
1176 void *priv)
1177{
1178 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1179 uint32_t start_mode;
yongchun.li59e873d2021-07-07 11:42:38 -07001180 uint32_t systime;
Song Zhaoea5a0412021-01-18 16:40:08 -08001181 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1182 bool create_poll_t = false;
1183
1184 if (!avsync)
1185 return ret;
1186
yongchun.li59e873d2021-07-07 11:42:38 -07001187 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1188 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001189
yongchun.li59e873d2021-07-07 11:42:38 -07001190 if (avsync->in_audio_switch &&
1191 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1192 {
1193 start_mode = AVS_START_SYNC;
1194 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1195 } else {
1196 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1197 log_error("[%d]fail to set audio start", avsync->session_id);
1198 }
1199 if (avsync->in_audio_switch &&
1200 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1201 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
1202 msync_session_get_wall(avsync->fd, &systime, NULL);
1203 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB &&
1204 start_mode == AVS_START_SYNC) {
1205 log_info("%d audio_switch audio need drop first.ahead %d ms",
1206 avsync->session_id, (int)(systime - pts)/90);
1207 ret = AV_SYNC_ASTART_AGAIN;
1208 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1209 goto exit;
1210 }
1211 else {
1212 int diff = (int)(pts - systime);
1213 log_info("%d audio_switch_state to start mode %d diff %d ms",
1214 avsync->session_id, start_mode, diff/90);
1215 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
1216 if (diff < A_ADJ_THREDHOLD_LB) {
1217 log_info("%d orig mode %d already close enough direct start",
1218 avsync->session_id, start_mode);
1219 start_mode = AVS_START_SYNC;
1220 }
1221 }
yongchun.li107a6162021-05-05 02:38:57 -07001222 }
1223
Song Zhaoea5a0412021-01-18 16:40:08 -08001224 if (start_mode == AVS_START_SYNC) {
1225 ret = AV_SYNC_ASTART_SYNC;
1226 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001227 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001228 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001229 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001230 avsync->state = AV_SYNC_STAT_RUNNING;
1231 } else if (start_mode == AVS_START_AGAIN) {
1232 ret = AV_SYNC_ASTART_AGAIN;
1233 }
1234
1235 if (ret == AV_SYNC_ASTART_AGAIN)
1236 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001237
Song Zhao76005282022-03-08 16:49:41 -08001238 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1239 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001240 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001241
1242 if (start_mode == AVS_START_ASYNC) {
1243 if (!cb) {
1244 log_error("[%d]invalid cb", avsync->session_id);
1245 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001246 }
Song Zhao76005282022-03-08 16:49:41 -08001247 avsync->audio_start = cb;
1248 avsync->audio_start_priv = priv;
1249 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001250
Song Zhaod62bb392021-04-23 12:25:49 -07001251 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001252 int ret;
1253
1254 log_info("[%d]start poll thread", avsync->session_id);
1255 avsync->quit_poll = false;
1256 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1257 if (ret) {
1258 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1259 return AV_SYNC_ASTART_ERR;
1260 }
1261 }
Song Zhaod62bb392021-04-23 12:25:49 -07001262 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001263 msync_session_get_wall(avsync->fd, &systime, NULL);
1264 log_info("[%d]return %u w %u pts %u d %u",
1265 avsync->session_id, ret, systime, pts, delay);
1266 }
1267exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001268 log_info("[%d]return %u", avsync->session_id, ret);
1269 return ret;
1270}
1271
1272int av_sync_audio_render(
1273 void *sync,
1274 pts90K pts,
1275 struct audio_policy *policy)
1276{
1277 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001278 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001279 uint32_t systime;
1280 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1281 avs_audio_action action = AA_SYNC_AA_MAX;
1282
1283 if (!avsync || !policy)
1284 return -1;
1285
yongchun.li107a6162021-05-05 02:38:57 -07001286 msync_session_get_wall(avsync->fd, &systime, NULL);
1287
1288 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1289 pts, systime, avsync->mode, (int)(pts-systime)/90);
1290
1291 if (avsync->in_audio_switch
1292 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
1293 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
1294 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1295 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1296 action = AV_SYNC_AA_RENDER;
1297 } else if ((int)(systime - pts) > 0) {
1298 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1299 (int)(systime - pts)/90, systime, pts);
1300 action = AV_SYNC_AA_DROP;
1301 } else {
1302 action = AV_SYNC_AA_INSERT;
1303 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1304 (int)(pts - systime)/90, systime, pts);
1305 }
1306 goto done;
1307 }
1308
Song Zhaoea5a0412021-01-18 16:40:08 -08001309 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1310 avsync->mode == AV_SYNC_MODE_AMASTER) {
1311 action = AV_SYNC_AA_RENDER;
1312 goto done;
1313 }
1314
Song Zhaod62bb392021-04-23 12:25:49 -07001315 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001316 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001317 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1318 action = AV_SYNC_AA_DROP;
1319 goto done;
1320 }
1321
Song Zhao7daf3a12021-05-10 22:22:25 -07001322 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1323 avsync->mode == AV_SYNC_MODE_AMASTER) {
1324 action = AV_SYNC_AA_RENDER;
1325 goto done;
1326 }
1327
Song Zhaod62bb392021-04-23 12:25:49 -07001328 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1329 LIVE_MODE(avsync->mode) &&
1330 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1331 /* outlier by stream error */
1332 avsync->outlier_cnt++;
1333 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1334 /* treat as disc, just drop current frame */
1335 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1336 avsync->outlier_cnt = 0;
1337 action = AV_SYNC_AA_DROP;
1338 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001339 goto done;
1340 }
1341 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1342 pts = systime;
1343 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001344 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001345 goto done;
1346 }
1347
1348 avsync->outlier_cnt = 0;
1349 /* low bound from sync_lost to sync_setup */
1350 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1351 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1352 action = AV_SYNC_AA_RENDER;
1353 goto done;
1354 }
1355
1356 /* high bound of sync_setup */
1357 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1358 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1359 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001360 action = AV_SYNC_AA_RENDER;
1361 goto done;
1362 }
1363
1364 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001365 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001366 action = AV_SYNC_AA_DROP;
1367 goto done;
1368 }
1369
1370 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001371 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001372 action = AV_SYNC_AA_INSERT;
1373 goto done;
1374 }
1375
1376done:
1377 policy->action = action;
1378 policy->delta = (int)(systime - pts);
1379 if (action == AV_SYNC_AA_RENDER) {
1380 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001381 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001382 if (!out_lier)
1383 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001384 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001385 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001386 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1387 msync_session_update_apts(avsync->fd, systime, pts, 0);
1388 log_info("[%d] audio switch done sys %u pts %u",
1389 avsync->session_id, systime, pts);
1390 msync_session_set_audio_switch(avsync->fd, false);
1391 avsync->in_audio_switch = false;
1392 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1393 } else {
1394 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1395 avsync->session_id, action, systime, pts, systime - pts);
1396 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001397 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001398 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001399 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001400 avsync->last_disc_pts != pts &&
1401 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001402 log_info ("[%d]audio disc %u --> %u",
1403 avsync->session_id, systime, pts);
1404 msync_session_set_audio_dis(avsync->fd, pts);
1405 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001406 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001407 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001408
1409 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001410 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001411 if (!avsync->audio_drop_cnt)
1412 avsync->audio_drop_start = now;
1413 avsync->audio_drop_cnt++;
1414 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1415 log_info ("[%d]audio keep dropping sys %u vs a %u",
1416 avsync->session_id, systime, pts);
1417 msync_session_set_audio_dis(avsync->fd, pts);
1418 }
Song Zhao409739b2021-05-12 22:21:40 -07001419 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001420 if (action != AV_SYNC_AA_DROP)
1421 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001422 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001423 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001424 }
1425
1426 return ret;
1427}
1428
1429int av_sync_get_clock(void *sync, pts90K *pts)
1430{
1431 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1432
1433 if (!avsync || !pts)
1434 return -1;
1435 return msync_session_get_wall(avsync->fd, pts, NULL);
1436}
1437
1438static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001439 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001440 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001441{
Song Zhao76005282022-03-08 16:49:41 -08001442 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1443 avsync->session_id, avsync->active_mode, avsync->mode,
1444 v_active, a_active, v_timeout, stat);
1445
1446 /* iptv delayed start */
1447 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1448 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1449
Song Zhaoea5a0412021-01-18 16:40:08 -08001450 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1451 float speed;
1452 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaoe208d692021-04-19 15:38:52 -07001453 a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001454 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001455 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhaoea5a0412021-01-18 16:40:08 -08001456 }
1457
1458 if (!msync_session_get_rate(avsync->fd, &speed)) {
1459 /* speed change is triggered by asink,
1460 * attached audio HAL will handle it
1461 */
1462 if (speed != avsync->speed)
1463 log_info("[%d]new rate %f", avsync->session_id, speed);
1464 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001465 if (avsync->mode != avsync->backup_mode) {
1466 avsync->mode = avsync->backup_mode;
1467 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1468 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001469 } else {
1470 avsync->backup_mode = avsync->mode;
1471 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1472 log_info("[%d]audio to freerun mode", avsync->session_id);
1473 }
1474 avsync->speed = speed;
1475 }
Song Zhaod62bb392021-04-23 12:25:49 -07001476 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1477 struct session_debug debug;
1478 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001479 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001480 avsync->backup_mode = avsync->mode;
1481 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001482 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001483 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001484 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001485 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001486 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001487 log_warn("[%d]audio back to mode %d",
1488 avsync->session_id, avsync->mode);
1489 }
1490 }
Song Zhao76005282022-03-08 16:49:41 -08001491 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1492 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001493 }
1494}
1495
1496static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001497 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001498 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001499{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001500 struct session_debug debug;
1501
Song Zhao76005282022-03-08 16:49:41 -08001502 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1503 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001504 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1505 if (debug.debug_freerun && !avsync->debug_freerun) {
1506 avsync->backup_mode = avsync->mode;
1507 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1508 avsync->debug_freerun = true;
1509 log_warn("[%d]video to freerun mode", avsync->session_id);
1510 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1511 avsync->mode = avsync->backup_mode;
1512 avsync->debug_freerun = false;
1513 log_warn("[%d]video back to mode %d",
1514 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001515 }
1516 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001517}
1518
1519static void * poll_thread(void * arg)
1520{
1521 int ret = 0;
1522 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1523 const int fd = avsync->fd;
1524 struct pollfd pfd = {
1525 /* default blocking capture */
1526 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1527 .fd = avsync->fd,
1528 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001529 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001530
1531 prctl (PR_SET_NAME, "avs_poll");
1532 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001533
1534 if (avsync->type == AV_SYNC_TYPE_AUDIO)
1535 sflag = SRC_A;
1536 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
1537 sflag = SRC_V;
1538
Song Zhaoea5a0412021-01-18 16:40:08 -08001539 while (!avsync->quit_poll) {
1540 for (;;) {
1541 ret = poll(&pfd, 1, 10);
1542 if (ret > 0)
1543 break;
1544 if (avsync->quit_poll)
1545 goto exit;
1546 if (errno == EINTR)
1547 continue;
1548 }
1549
1550 /* error handling */
1551 if (pfd.revents & POLLERR)
1552 log_error("[%d]POLLERR received", avsync->session_id);
1553
Song Zhaod62bb392021-04-23 12:25:49 -07001554 /* mode change. Non-exclusive wait so all the processes
1555 * shall be woken up
1556 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001557 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001558 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001559 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001560
Song Zhao76005282022-03-08 16:49:41 -08001561 msync_session_get_stat(fd, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001562 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001563
1564 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001565 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001566 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001567 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001568 usleep(10000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001569 }
1570 }
1571exit:
1572 log_info("[%d]quit", avsync->session_id);
1573 return NULL;
1574}
1575
Song Zhao623e2f12021-09-03 15:54:04 -07001576#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1577/* return ppm between demod and PCR clock */
1578int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1579{
1580 int fd = -1, ppm = 0, nread;
1581 char buf[128];
1582 uint32_t reg_v, lock;
1583 float val;
1584
1585 fd = open(DEMOD_NODE, O_RDWR);
1586 if (fd < 0) {
1587 log_warn("node not found %s", DEMOD_NODE);
1588 /* do not retry */
1589 avsync->ppm_adjusted = true;
1590 return 0;
1591 }
1592 snprintf(buf, sizeof(buf), "%d", 5);
1593 write(fd, buf, 2);
1594
1595 lseek(fd, 0, SEEK_SET);
1596
1597 nread = read(fd, buf, sizeof(buf));
1598 if (nread <= 0) {
1599 log_error("read error");
1600 goto err;
1601 }
1602 buf[nread] = 0;
1603 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1604 log_error("wrong format %s", buf);
1605 goto err;
1606 }
1607 if (lock != 0x1f) {
1608 log_info("demod not locked");
1609 goto err;
1610 }
1611 if (reg_v > ((2 << 20) - 1))
1612 reg_v -= (2 << 21);
1613 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1614 ppm = val;
1615 log_info("ppm from SFO %d", ppm);
1616 avsync->ppm_adjusted = true;
1617
1618err:
1619 if (fd >= 0)
1620 close(fd);
1621 return ppm;
1622}
1623
Song Zhaod62bb392021-04-23 12:25:49 -07001624int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001625{
1626 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001627 struct pcr_info pcr;
1628 enum pcr_monitor_status status;
1629 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001630 if (!avsync)
1631 return -1;
1632
1633 if (avsync->type != AV_SYNC_TYPE_PCR)
1634 return -2;
1635
Song Zhao623e2f12021-09-03 15:54:04 -07001636 /* initial estimation from Demod SFO HW */
1637 if (!avsync->ppm_adjusted) {
1638 ppm = dmod_get_sfo_dev(avsync);
1639 if (ppm != 0) {
1640 /* ppm > 0 means board clock is faster */
1641 msync_session_set_clock_dev(avsync->fd, -ppm);
1642 }
1643 }
wei.dubcc2ed22021-05-19 07:16:10 -04001644 pcr.monoclk = mono_clock / 1000;
1645 pcr.pts = (long long) pts * 1000 / 90;
1646 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1647
1648 status = pcr_monitor_get_status(avsync->pcr_monitor);
1649
1650 if (status >= DEVIATION_READY) {
1651 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1652 if (avsync->ppm != ppm) {
1653 avsync->ppm = ppm;
1654 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1655 if (msync_session_set_clock_dev(avsync->fd, ppm))
1656 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001657 else
1658 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001659 }
1660 }
1661
Song Zhaod62bb392021-04-23 12:25:49 -07001662 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001663}
1664
Song Zhaod62bb392021-04-23 12:25:49 -07001665int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001666{
1667 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1668
1669 if (!avsync)
1670 return -1;
1671
Song Zhaod62bb392021-04-23 12:25:49 -07001672 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001673}
1674
1675int av_sync_set_session_name(void *sync, const char *name)
1676{
1677 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1678
1679 if (!avsync)
1680 return -1;
1681
1682 return msync_session_set_name(avsync->fd, name);
1683}
yongchun.li107a6162021-05-05 02:38:57 -07001684
1685int av_sync_set_audio_switch(void *sync, bool start)
1686{
1687 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1688 bool v_active, a_active, v_timeout;
1689
1690 if (!avsync)
1691 return -1;
Song Zhao76005282022-03-08 16:49:41 -08001692 if (msync_session_get_stat(avsync->fd, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001693 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001694 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001695 log_error("[%d] can not get session state",
1696 avsync->session_id);
1697 return -1;
1698 }
1699 if (!v_active || !a_active) {
1700 log_error("[%d] no apply if not AV both active v %d a %d",
1701 avsync->session_id, v_active, a_active);
1702 return -1;
1703 }
1704 if (msync_session_set_audio_switch(avsync->fd, start)) {
1705 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1706 return -1;
1707 }
1708 avsync->in_audio_switch = start;
1709 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1710 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1711 return 0;
1712}
1713
1714int av_sync_get_audio_switch(void *sync, bool *start)
1715{
1716 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1717
1718 if (!avsync)
1719 return -1;
Song Zhao76005282022-03-08 16:49:41 -08001720 if (msync_session_get_stat(avsync->fd, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001721 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001722 log_error("[%d] can not audio seamless switch state",
1723 avsync->session_id);
1724 return -1;
1725 }
1726 if (start) *start = avsync->in_audio_switch;
1727 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001728}
Song Zhao8039f562021-05-18 18:11:25 -07001729
Song Zhao623e2f12021-09-03 15:54:04 -07001730enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001731{
1732 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1733
wei.dubcc2ed22021-05-19 07:16:10 -04001734 if (!avsync || !ppm)
1735 return CLK_RECOVERY_ERR;
1736 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001737 return CLK_RECOVERY_NOT_RUNNING;
1738
wei.dubcc2ed22021-05-19 07:16:10 -04001739 if (msync_session_get_clock_dev(avsync->fd, ppm))
1740 return CLK_RECOVERY_ERR;
1741
1742 if (*ppm == 0)
1743 return CLK_RECOVERY_ONGOING;
1744 else
1745 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001746}
Song Zhao95bd0922021-09-21 14:07:46 -07001747
1748static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1749{
1750 int ret;
1751
1752 if (!avsync->frame_q) {
1753 avsync->frame_q = create_q(MAX_FRAME_NUM);
1754 if (!avsync->frame_q) {
1755 log_error("[%d]create queue fail", avsync->session_id);
1756
1757 return -1;
1758 }
1759 }
1760
1761 ret = queue_item(avsync->frame_q, frame);
1762 if (ret)
1763 log_error("%s queue fail:%d", ret);
1764 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1765 return ret;
1766}
1767
1768int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1769{
1770 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1771
1772 if (!avsync)
1773 return -1;
1774 avsync->msys = msys;
1775 return 0;
1776}
1777
1778static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1779{
1780 struct vframe *frame = NULL, *enter_last_frame = NULL;
1781 uint64_t systime;
1782 int toggle_cnt = 0;
1783
1784 enter_last_frame = avsync->last_frame;
1785 systime = avsync->msys;
1786 log_debug("[%d]sys %llu", avsync->session_id, systime);
1787 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1788 if (systime >= frame->mts) {
1789 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1790 toggle_cnt++;
1791
1792 if (avsync->last_frame)
1793 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1794
1795 dqueue_item(avsync->frame_q, (void **)&frame);
1796 if (avsync->last_frame) {
1797 /* free frame that are not for display */
1798 if (toggle_cnt > 1) {
1799 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1800 avsync->last_frame->mts, frame->mts, systime);
1801 avsync->last_frame->free(avsync->last_frame);
1802 }
1803 } else {
1804 avsync->first_frame_toggled = true;
1805 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1806 }
1807 avsync->last_frame = frame;
1808 } else
1809 break;
1810 }
1811
1812 if (avsync->last_frame) {
1813 if (enter_last_frame != avsync->last_frame)
1814 log_debug("[%d]pop %llu", avsync->session_id, avsync->last_frame->pts);
1815 log_trace("[%d]pop=%llu, system=%llu, diff %d(ms), QNum=%d", avsync->session_id,
1816 avsync->last_frame->mts,
1817 systime, (systime - avsync->last_frame->mts) / 1000000,
1818 queue_size(avsync->frame_q));
1819 } else
1820 if (enter_last_frame != avsync->last_frame)
1821 log_debug("[%d]pop (nil)", avsync->session_id);
1822
1823 if (avsync->last_frame)
1824 avsync->last_frame->hold_period++;
1825 return avsync->last_frame;
1826}