blob: 11e83ef83efcc2a40441a0f14692caa795a516c0 [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"
25#include "queue.h"
26#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;
69
70 /* pts of last rendered frame */
Song Zhaoea5a0412021-01-18 16:40:08 -080071 pts90K last_wall;
Song Zhaoc03ba122020-12-23 21:54:02 -080072 pts90K last_pts;
73 struct vframe *last_frame;
74
Song Zhaoe0bf6ad2021-07-09 11:28:42 -070075 /* pts of last pushed frame */
76 pts90K last_q_pts;
77
Song Zhaoc03ba122020-12-23 21:54:02 -080078 bool first_frame_toggled;
Song Zhaoc03ba122020-12-23 21:54:02 -080079 bool paused;
Song Zhaoea5a0412021-01-18 16:40:08 -080080 enum sync_state state;
Song Zhaoc03ba122020-12-23 21:54:02 -080081 void *pattern_detector;
82 void *frame_q;
Song Zhaoc03ba122020-12-23 21:54:02 -080083
Song Zhaoea5a0412021-01-18 16:40:08 -080084 /* start control */
85 int start_thres;
86 audio_start_cb audio_start;
87 void *audio_start_priv;
88
89 /* render property */
Song Zhaoc03ba122020-12-23 21:54:02 -080090 int delay;
91 pts90K vsync_interval;
92
93 /* state lock */
94 pthread_mutex_t lock;
95 /* pattern */
96 int last_holding_peroid;
Song Zhaoea5a0412021-01-18 16:40:08 -080097 bool session_started;
Song Zhaoc03ba122020-12-23 21:54:02 -080098
99 float speed;
100
Song Zhaoc03ba122020-12-23 21:54:02 -0800101 /* pause pts */
102 pts90K pause_pts;
103 pause_pts_done pause_pts_cb;
104 void *pause_cb_priv;
Song Zhao5d2b4772021-01-18 16:40:08 -0800105
106 /* log control */
Song Zhaoa2985cb2021-06-24 12:01:47 -0700107 uint32_t last_log_syst;
Song Zhao5d2b4772021-01-18 16:40:08 -0800108 uint32_t sync_lost_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700109 struct timespec sync_lost_print_time;
Song Zhaoea5a0412021-01-18 16:40:08 -0800110
111 pthread_t poll_thread;
112 /* pcr master, IPTV only */
113 bool quit_poll;
114 enum sync_mode active_mode;
Song Zhaof46932e2021-05-21 01:51:45 -0700115 uint32_t disc_thres_min;
116 uint32_t disc_thres_max;
Song Zhao35a82df2021-04-15 10:58:49 -0700117
118 /* error detection */
119 uint32_t last_poptime;
Song Zhaod62bb392021-04-23 12:25:49 -0700120 uint32_t outlier_cnt;
Song Zhao409739b2021-05-12 22:21:40 -0700121 pts90K last_disc_pts;
122
yongchun.li107a6162021-05-05 02:38:57 -0700123 // indicate set audio switch
124 bool in_audio_switch;
125 enum audio_switch_state_ audio_switch_state;
wei.dubcc2ed22021-05-19 07:16:10 -0400126
127 //pcr monitor handle
128 void *pcr_monitor;
129 int ppm;
Song Zhao623e2f12021-09-03 15:54:04 -0700130 bool ppm_adjusted;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700131
132 //video FPS detection
133 pts90K last_fpts;
134 int fps_interval;
135 int fps_interval_acc;
136 int fps_cnt;
137
138 //video freerun with rate control
139 uint32_t last_r_syst;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700140 bool debug_freerun;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700141
142 //Audio dropping detection
143 uint32_t audio_drop_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700144 struct timespec audio_drop_start;
Song Zhao95bd0922021-09-21 14:07:46 -0700145
146 /*system mono time for current vsync interrupt */
147 uint64_t msys;
Song Zhaoc03ba122020-12-23 21:54:02 -0800148};
149
150#define MAX_FRAME_NUM 32
151#define DEFAULT_START_THRESHOLD 2
152#define TIME_UNIT90K (90000)
Song Zhaof46932e2021-05-21 01:51:45 -0700153#define AV_DISC_THRES_MIN (TIME_UNIT90K / 3)
154#define AV_DISC_THRES_MAX (TIME_UNIT90K * 10)
Song Zhao7daf3a12021-05-10 22:22:25 -0700155#define A_ADJ_THREDHOLD_HB (900 * 6) //60ms
156#define A_ADJ_THREDHOLD_LB (900 * 2) //20ms
Song Zhao52f55192021-05-06 10:52:21 -0700157#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800158#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhaod62bb392021-04-23 12:25:49 -0700159#define LIVE_MODE(mode) ((mode) == AV_SYNC_MODE_PCR_MASTER || (mode) == AV_SYNC_MODE_IPTV)
160
Song Zhao065800e2021-05-26 15:56:06 -0700161#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
Song Zhaod62bb392021-04-23 12:25:49 -0700162#define OUTLIER_MAX_CNT 8
Song Zhaoa2985cb2021-06-24 12:01:47 -0700163#define VALID_TS(x) ((x) != -1)
Song Zhaoc03ba122020-12-23 21:54:02 -0800164
yongchun.li0ee6e372021-08-20 04:26:04 -0700165static uint64_t time_diff (struct timespec *b, struct timespec *a);
Song Zhaoc03ba122020-12-23 21:54:02 -0800166static bool frame_expire(struct av_sync_session* avsync,
167 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800168 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800169 struct vframe * frame,
170 struct vframe * next_frame,
171 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700172static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800173 int cur_period,
174 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800175static void * poll_thread(void * arg);
176static void trigger_audio_start_cb(struct av_sync_session *avsync,
177 avs_ascb_reason reason);
Song Zhao95bd0922021-09-21 14:07:46 -0700178static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync);
179static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame);
Song Zhao2f6744b2021-11-03 21:23:50 -0700180pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER;
Song Zhaoc03ba122020-12-23 21:54:02 -0800181
Song Zhaoea5a0412021-01-18 16:40:08 -0800182int av_sync_open_session(int *session_id)
183{
Song Zhao2f6744b2021-11-03 21:23:50 -0700184 int fd = -1;
Song Zhaoea5a0412021-01-18 16:40:08 -0800185 int id, rc;
186
Song Zhao2f6744b2021-11-03 21:23:50 -0700187 pthread_mutex_lock(&glock);
188 fd = msync_create_session();
Song Zhaoea5a0412021-01-18 16:40:08 -0800189 if (fd < 0) {
190 log_error("fail");
Song Zhao2f6744b2021-11-03 21:23:50 -0700191 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800192 }
193 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
194 if (rc) {
195 log_error("new session errno:%d", errno);
Song Zhao2f6744b2021-11-03 21:23:50 -0700196 msync_destory_session(fd);
197 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800198 }
199 *session_id = id;
Song Zhao2f6744b2021-11-03 21:23:50 -0700200 log_debug("new avsession id %d fd %d", id, fd);
201exit:
202 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800203 return fd;
204}
205
206void av_sync_close_session(int session)
207{
Song Zhao2f6744b2021-11-03 21:23:50 -0700208 log_debug("session closed fd %d", session);
209 pthread_mutex_lock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800210 msync_destory_session(session);
Song Zhao2f6744b2021-11-03 21:23:50 -0700211 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800212}
213
214static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800215 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800216 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800217 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800218 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800219{
220 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800221 char dev_name[20];
Song Zhao2f6744b2021-11-03 21:23:50 -0700222 int retry = 10;
Song Zhaoc03ba122020-12-23 21:54:02 -0800223
Song Zhao95bd0922021-09-21 14:07:46 -0700224 log_info("[%d] mode %d type %d", session_id, mode, type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800225 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
226 if (!avsync) {
227 log_error("OOM");
228 return NULL;
229 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800230
Song Zhao95bd0922021-09-21 14:07:46 -0700231 if (type == AV_SYNC_TYPE_VIDEO &&
232 mode == AV_SYNC_MODE_VIDEO_MONO) {
233 if (session_id < AV_SYNC_SESSION_V_MONO) {
234 log_error("wrong session id %d", session_id);
235 goto err;
236 }
237 avsync->type = type;
238 avsync->mode = mode;
239 avsync->fd = -1;
240 avsync->session_id = session_id;
241 log_info("[%d]init", avsync->session_id);
242 return avsync;
243 }
244
Song Zhaoea5a0412021-01-18 16:40:08 -0800245 if (type == AV_SYNC_TYPE_VIDEO) {
246 avsync->pattern_detector = create_pattern_detector();
247 if (!avsync->pattern_detector) {
248 log_error("pd create fail");
249 goto err;
250 }
251
252 if (!start_thres)
253 avsync->start_thres = DEFAULT_START_THRESHOLD;
254 else {
255 if (start_thres > 5) {
256 log_error("start_thres too big: %d", start_thres);
257 goto err2;
258 }
259 avsync->start_thres = start_thres;
260 }
261 avsync->phase_set = false;
262 avsync->first_frame_toggled = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800263 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800264
265 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800266 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800267 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800268 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800269 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800270 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800271 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800272 avsync->speed = 1.0f;
273 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhao409739b2021-05-12 22:21:40 -0700274 avsync->vsync_interval = -1;
275 avsync->last_disc_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700276 avsync->last_log_syst = -1;
277 avsync->last_pts = -1;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700278 avsync->last_q_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700279 avsync->last_wall = -1;
280 avsync->fps_interval = -1;
281 avsync->last_r_syst = -1;
bo.xiao5821fc72021-07-11 22:47:00 -0400282 avsync->timeout = -1;
283
Song Zhaof46932e2021-05-21 01:51:45 -0700284 if (msync_session_get_disc_thres(session_id,
285 &avsync->disc_thres_min, &avsync->disc_thres_max)) {
286 log_error("fail to get disc thres", dev_name, errno);
287 avsync->disc_thres_min = AV_DISC_THRES_MIN;
288 avsync->disc_thres_max = AV_DISC_THRES_MAX;
289 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800290
291 pthread_mutex_init(&avsync->lock, NULL);
Song Zhao95bd0922021-09-21 14:07:46 -0700292 log_info("[%d] start_thres %d disc_thres %u/%u",
293 start_thres, avsync->disc_thres_min, avsync->disc_thres_max);
Song Zhaoea5a0412021-01-18 16:40:08 -0800294
295 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
Song Zhao2f6744b2021-11-03 21:23:50 -0700296 while (retry) {
297 /* wait for sysfs to update */
298 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
299 if (avsync->fd > 0)
300 break;
301
302 retry--;
303 if (!retry) {
304 log_error("open %s errno %d", dev_name, errno);
305 goto err2;
306 }
307 usleep(20000);
Song Zhaoea5a0412021-01-18 16:40:08 -0800308 }
309
wei.dubcc2ed22021-05-19 07:16:10 -0400310 if (avsync->type == AV_SYNC_TYPE_PCR) {
311 if (pcr_monitor_init(&avsync->pcr_monitor)) {
312 log_error("pcr monitor init");
Song Zhao9cd27a52021-07-26 15:27:38 +0000313 goto err3;
wei.dubcc2ed22021-05-19 07:16:10 -0400314 }
315 }
316
Song Zhaoea5a0412021-01-18 16:40:08 -0800317 if (!attach) {
318 msync_session_set_mode(avsync->fd, mode);
319 avsync->mode = mode;
320 } else {
321 avsync->attached = true;
322 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
323 log_error("get mode");
Song Zhao9cd27a52021-07-26 15:27:38 +0000324 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800325 }
326 avsync->backup_mode = avsync->mode;
bo.xiao5821fc72021-07-11 22:47:00 -0400327 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800328 log_error("get policy");
Song Zhao9cd27a52021-07-26 15:27:38 +0000329 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800330 }
yongchun.li107a6162021-05-05 02:38:57 -0700331 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700332 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -0700333 log_error("get state");
Song Zhao9cd27a52021-07-26 15:27:38 +0000334 goto err4;
yongchun.li107a6162021-05-05 02:38:57 -0700335 }
336 if (avsync->in_audio_switch) {
337 log_info("audio_switch_state reseted the audio");
338 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
339 }
340
Song Zhaoea5a0412021-01-18 16:40:08 -0800341 log_info("[%d]retrieve sync mode %d policy %d",
342 session_id, avsync->mode, avsync->start_policy);
343 }
344
Song Zhao67c937b2021-10-01 11:21:32 -0700345 /* debug log level */
346 {
347 const char *env= getenv( "AML_AVSYNC_DEBUG_LEVEL");
348 if ( env ) {
349 log_set_level(atoi(env));
350 }
351 }
352
Song Zhaoc03ba122020-12-23 21:54:02 -0800353 return avsync;
Song Zhao9cd27a52021-07-26 15:27:38 +0000354err4:
wei.dubcc2ed22021-05-19 07:16:10 -0400355 if (avsync->pcr_monitor)
356 pcr_monitor_destroy(avsync->pcr_monitor);
Song Zhao9cd27a52021-07-26 15:27:38 +0000357err3:
358 close(avsync->fd);
Song Zhaoea5a0412021-01-18 16:40:08 -0800359err2:
360 destroy_pattern_detector(avsync->pattern_detector);
361err:
362 free(avsync);
363 return NULL;
364}
365
366void* av_sync_create(int session_id,
367 enum sync_mode mode,
368 enum sync_type type,
369 int start_thres)
370{
371 return create_internal(session_id, mode,
372 type, start_thres, false);
373}
374
375void* av_sync_attach(int session_id, enum sync_type type)
376{
Song Zhao95bd0922021-09-21 14:07:46 -0700377 if (type == AV_SYNC_TYPE_VIDEO)
378 return NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800379 return create_internal(session_id, AV_SYNC_MODE_MAX,
380 type, 0, true);
381}
382
383int av_sync_video_config(void *sync, struct video_config* config)
384{
385 struct av_sync_session *avsync = (struct av_sync_session *)sync;
386
387 if (!avsync || !config)
388 return -1;
389
390 if (config->delay != 1 && config->delay != 2) {
391 log_error("invalid delay: %d\n", config->delay);
392 return -1;
393 }
394
395 avsync->delay = config->delay;
396
397 log_info("[%d] delay: %d",
398 avsync->session_id, config->delay);
399 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800400}
401
402static int internal_stop(struct av_sync_session *avsync)
403{
404 int ret = 0;
405 struct vframe *frame;
406
407 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800408 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
409 frame->free(frame);
410 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800411 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800412 pthread_mutex_unlock(&avsync->lock);
413 return ret;
414}
415
416/* destroy and detach from kernel session */
417void av_sync_destroy(void *sync)
418{
419 struct av_sync_session *avsync = (struct av_sync_session *)sync;
420
421 if (!avsync)
422 return;
423
Song Zhao95bd0922021-09-21 14:07:46 -0700424 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
425 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
426 log_info("[%d]done", avsync->session_id);
427 internal_stop(avsync);
428 destroy_q(avsync->frame_q);
429 free(avsync);
430 return;
431 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800432 log_info("[%d]begin", avsync->session_id);
433 if (avsync->state != AV_SYNC_STAT_INIT) {
434 if (avsync->type == AV_SYNC_TYPE_VIDEO)
435 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800436
Song Zhaoea5a0412021-01-18 16:40:08 -0800437 avsync->quit_poll = true;
438 if (avsync->poll_thread) {
439 pthread_join(avsync->poll_thread, NULL);
440 avsync->poll_thread = 0;
441 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700442 if (avsync->type == AV_SYNC_TYPE_AUDIO)
443 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoaf368d52021-02-17 17:53:45 -0800444 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800445
Song Zhaoea5a0412021-01-18 16:40:08 -0800446 if (avsync->session_started) {
447 if (avsync->type == AV_SYNC_TYPE_VIDEO)
448 msync_session_set_video_stop(avsync->fd);
449 else
450 msync_session_set_audio_stop(avsync->fd);
451 }
wei.dubcc2ed22021-05-19 07:16:10 -0400452
453 if(avsync->pcr_monitor)
454 pcr_monitor_destroy(avsync->pcr_monitor);
455
Song Zhaoea5a0412021-01-18 16:40:08 -0800456 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800457 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800458 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
459 destroy_q(avsync->frame_q);
460 destroy_pattern_detector(avsync->pattern_detector);
461 }
462 log_info("[%d]done", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800463 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800464}
465
bo.xiao5821fc72021-07-11 22:47:00 -0400466int avs_sync_set_start_policy(void *sync, struct start_policy* st_policy)
Song Zhaoea5a0412021-01-18 16:40:08 -0800467{
468 struct av_sync_session *avsync = (struct av_sync_session *)sync;
469
470 if (!avsync || !avsync->fd)
471 return -1;
472
bo.xiao5821fc72021-07-11 22:47:00 -0400473 log_info("[%d]policy %u --> %u, timeout %d --> %d", avsync->start_policy, st_policy->policy, avsync->timeout, st_policy->timeout);
474 avsync->start_policy = st_policy->policy;
475 avsync->timeout = st_policy->timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800476 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400477 if (st_policy->policy != AV_SYNC_START_NONE &&
478 st_policy->policy != AV_SYNC_START_V_PEEK)
479 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800480
481 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800482}
483
484int av_sync_pause(void *sync, bool pause)
485{
486 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700487 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800488 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800489
490 if (!avsync)
491 return -1;
492
Song Zhaoea5a0412021-01-18 16:40:08 -0800493 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
494 return -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800495
yongchun.li107a6162021-05-05 02:38:57 -0700496 rc = msync_session_get_stat(avsync->fd, &avsync->active_mode,
497 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700498 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700499
yongchun.li5f52fb02021-06-04 18:13:05 -0700500 /* ignore only when video try to pause when audio is acive, on which
501 the control of the STC will be relays.
502 When resume,it can do always as it is possible that video just
503 paused earlier without audio yet,then audio added later before resume.
504 We shall not igore that otherwise it could cause video freeze. */
505 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
506 avsync->type == AV_SYNC_TYPE_VIDEO &&
507 a_active &&
508 !avsync->in_audio_switch) {
509 if (!pause) {
510 log_info("[%d] clear video pause when audio active",
511 avsync->session_id);
512 avsync->paused = pause;
513 } else {
514 log_info("[%d] ignore the pause from video when audio active",
515 avsync->session_id);
516 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800517 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700518 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800519
yongchun.li107a6162021-05-05 02:38:57 -0700520 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
521 log_info("[%d] ignore the pause from audio", avsync->session_id);
522 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
523 return 0;
524 }
525
Song Zhaoea5a0412021-01-18 16:40:08 -0800526 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800527 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800528 log_info("[%d]paused:%d type:%d rc %d",
529 avsync->session_id, pause, avsync->type, rc);
Song Zhaoc03ba122020-12-23 21:54:02 -0800530
Song Zhaoea5a0412021-01-18 16:40:08 -0800531 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800532}
533
534int av_sync_push_frame(void *sync , struct vframe *frame)
535{
536 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700537 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800538 struct av_sync_session *avsync = (struct av_sync_session *)sync;
539
540 if (!avsync)
541 return -1;
542
Song Zhao95bd0922021-09-21 14:07:46 -0700543 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
544 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
545 return video_mono_push_frame(avsync, frame);
546
Song Zhaoea5a0412021-01-18 16:40:08 -0800547 if (!avsync->frame_q) {
548 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400549 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800550 log_error("[%d]get policy", avsync->session_id);
551 return -1;
552 }
553
554 avsync->frame_q = create_q(MAX_FRAME_NUM);
555 if (!avsync->frame_q) {
556 log_error("[%d]create queue fail", avsync->session_id);
yongchun.li0ee6e372021-08-20 04:26:04 -0700557
Song Zhaoea5a0412021-01-18 16:40:08 -0800558 return -1;
559 }
560
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700561 /* for debugging */
562 {
Song Zhaoea5a0412021-01-18 16:40:08 -0800563 int ret;
564
565 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
566 if (ret) {
567 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
568 destroy_q(avsync->frame_q);
569 return -1;
570 }
571 }
572 }
573
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700574 if (avsync->last_q_pts != -1) {
575 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
576 /* TODO: wrong, should remove from back of queue */
Song Zhaoc03ba122020-12-23 21:54:02 -0800577 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700578 if (prev) {
579 prev->free(prev);
580 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
581 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700582 } else if (avsync->fps_cnt < 100) {
583 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700584
585 if (interval > 0 && interval <= 4500) {
586 if (avsync->fps_interval_acc == -1) {
587 avsync->fps_interval_acc = interval;
588 avsync->fps_cnt = 1;
589 } else {
590 avsync->fps_interval_acc += interval;
591 avsync->fps_cnt++;
592 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
593 if (avsync->fps_cnt == 100)
594 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
595 }
596 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800597 }
598 }
599
Song Zhao065800e2021-05-26 15:56:06 -0700600 if (frame->duration == -1)
601 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800602 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700603 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800604 ret = queue_item(avsync->frame_q, frame);
605 if (avsync->state == AV_SYNC_STAT_INIT &&
606 queue_size(avsync->frame_q) >= avsync->start_thres) {
607 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaoea5a0412021-01-18 16:40:08 -0800608 log_info("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800609 }
610
611 if (ret)
612 log_error("%s queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400613 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800614 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800615}
616
617struct vframe *av_sync_pop_frame(void *sync)
618{
Song Zhaoea5a0412021-01-18 16:40:08 -0800619 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800620 struct av_sync_session *avsync = (struct av_sync_session *)sync;
621 int toggle_cnt = 0;
622 uint32_t systime;
Song Zhao468fd652021-01-15 22:13:04 -0800623 bool pause_pts_reached = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800624 uint32_t interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800625
Song Zhao95bd0922021-09-21 14:07:46 -0700626 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
627 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
628 return video_mono_pop_frame(avsync);
629
Song Zhaoc03ba122020-12-23 21:54:02 -0800630 pthread_mutex_lock(&avsync->lock);
631 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhao2f6744b2021-11-03 21:23:50 -0700632 log_debug("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800633 goto exit;
634 }
635
Song Zhaoea5a0412021-01-18 16:40:08 -0800636 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700637 uint32_t pts;
638
Song Zhaoc03ba122020-12-23 21:54:02 -0800639 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800640 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800641 goto exit;
642 }
Song Zhao35a82df2021-04-15 10:58:49 -0700643 msync_session_get_wall(avsync->fd, &systime, &interval);
644 pts = frame->pts - avsync->delay * interval;
645 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800646 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700647 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800648 }
649
Song Zhaoea5a0412021-01-18 16:40:08 -0800650 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700651 !avsync->first_frame_toggled &&
652 !msync_clock_started(avsync->fd)) {
653 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800654 log_trace("[%d]clock not started", avsync->session_id);
655 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800656 }
657
Song Zhaoea5a0412021-01-18 16:40:08 -0800658 enter_last_frame = avsync->last_frame;
659 msync_session_get_wall(avsync->fd, &systime, &interval);
660
661 /* handle refresh rate change */
662 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
663 avsync->vsync_interval != interval) {
664 log_info("[%d]vsync interval update %d --> %u",
665 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700666 if (avsync->fps_interval == -1)
667 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800668 avsync->vsync_interval = interval;
669 avsync->phase_set = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700670 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800671 reset_pattern(avsync->pattern_detector);
672 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800673 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
674 struct vframe *next_frame = NULL;
675
676 peek_item(avsync->frame_q, (void **)&next_frame, 1);
677 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700678 log_debug("[%d]cur_f %u next_f %u size %d",
679 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800680 if (frame_expire(avsync, systime, interval,
681 frame, next_frame, toggle_cnt)) {
682 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800683 toggle_cnt++;
684
Song Zhao35a82df2021-04-15 10:58:49 -0700685 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800686 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700687 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700688 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700689 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
690 if (next_frame)
691 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
692 }
Song Zhao35a82df2021-04-15 10:58:49 -0700693
Song Zhaoc03ba122020-12-23 21:54:02 -0800694 if (avsync->last_frame)
695 avsync->last_holding_peroid = avsync->last_frame->hold_period;
696
697 dqueue_item(avsync->frame_q, (void **)&frame);
698 if (avsync->last_frame) {
699 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800700 if (toggle_cnt > 1) {
Song Zhao35a82df2021-04-15 10:58:49 -0700701 log_debug("[%d]free %u cur %u system/d %u/%u", avsync->session_id,
702 avsync->last_frame->pts, frame->pts, systime, systime - avsync->last_poptime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800703 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800704 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800705 } else {
706 avsync->first_frame_toggled = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800707 log_info("[%d]first frame %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800708 }
709 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800710 avsync->last_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800711 } else
712 break;
713 }
714
715 /* pause pts */
716 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800717 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800718 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800719 else
Song Zhao468fd652021-01-15 22:13:04 -0800720 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
721 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
722 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
723 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
724 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800725
Song Zhao468fd652021-01-15 22:13:04 -0800726 if (pause_pts_reached) {
727 if (avsync->pause_pts_cb)
728 avsync->pause_pts_cb(avsync->pause_pts,
Song Zhaoc03ba122020-12-23 21:54:02 -0800729 avsync->pause_cb_priv);
730
Song Zhao468fd652021-01-15 22:13:04 -0800731 /* stay in paused until av_sync_pause(false) */
732 avsync->paused = true;
733 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoea5a0412021-01-18 16:40:08 -0800734 log_info ("[%d]reach pause pts: %u",
735 avsync->session_id, avsync->last_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800736 }
737
738exit:
739 pthread_mutex_unlock(&avsync->lock);
740 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800741 if (enter_last_frame != avsync->last_frame)
742 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
bo.xiao1f94b352021-08-02 03:53:47 -0400743 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 -0700744 /* don't update vpts for out_lier */
745 if (avsync->last_frame->duration != -1)
746 msync_session_update_vpts(avsync->fd, systime,
747 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800748 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800749 if (enter_last_frame != avsync->last_frame)
750 log_debug("[%d]pop (nil)", avsync->session_id);
751
Song Zhao35a82df2021-04-15 10:58:49 -0700752 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800753 if (avsync->last_frame)
754 avsync->last_frame->hold_period++;
755 return avsync->last_frame;
756}
757
Song Zhaoc03ba122020-12-23 21:54:02 -0800758static inline uint32_t abs_diff(uint32_t a, uint32_t b)
759{
Song Zhaoea5a0412021-01-18 16:40:08 -0800760 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800761}
762
yongchun.li0ee6e372021-08-20 04:26:04 -0700763static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800764{
yongchun.li0ee6e372021-08-20 04:26:04 -0700765 return (b->tv_sec - a->tv_sec)*1000000 + (b->tv_nsec/1000 - a->tv_nsec/1000);
Song Zhaoc03ba122020-12-23 21:54:02 -0800766}
767
Song Zhaoc03ba122020-12-23 21:54:02 -0800768static bool frame_expire(struct av_sync_session* avsync,
769 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800770 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800771 struct vframe * frame,
772 struct vframe * next_frame,
773 int toggle_cnt)
774{
775 uint32_t fpts = frame->pts;
776 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800777 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800778
779 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
780 return false;
781
782 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
783 return true;
784
fei.deng63e43e12021-09-23 19:44:01 +0800785 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
786 avsync->mode == AV_SYNC_MODE_VMASTER) {
787 /* We need to ensure that the video outputs smoothly,
788 so output video frame by frame hold_period */
789 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
790 avsync->last_frame &&
791 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
792 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
793 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700794 return true;
795 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700796 }
797
Song Zhaoc03ba122020-12-23 21:54:02 -0800798 if (!fpts) {
799 if (avsync->last_frame) {
800 /* try to accumulate duration as PTS */
801 fpts = avsync->vpts + avsync->last_frame->duration;
802 } else {
803 fpts = avsync->vpts;
804 }
805 }
806 systime += pts_correction;
807
808 /* phase adjustment */
809 if (avsync->phase_set)
810 systime += avsync->phase;
811
yongchun.lia50b1e92021-08-07 01:11:54 +0000812 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800813 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000814 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700815 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800816 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800817 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800818 return false;
819
Song Zhaoa2985cb2021-06-24 12:01:47 -0700820 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
821 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700822 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800823
yongchun.li0ee6e372021-08-20 04:26:04 -0700824 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700825 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800826 avsync->last_pts = fpts;
827 if (time_diff(&now, &avsync->sync_lost_print_time) >=
828 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700829 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800830 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800831 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700832 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800833 } else
834 avsync->sync_lost_cnt++;
835 }
Song Zhaod62bb392021-04-23 12:25:49 -0700836
837 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
838 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700839 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700840 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700841 /* outlier by stream error */
842 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700843 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700844 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
845 log_info("render outlier %u", fpts);
846 return true;
847 }
848 }
849
850 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800851 avsync->state = AV_SYNC_STAT_SYNC_LOST;
852 avsync->phase_set = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700853 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800854 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700855
856 if (LIVE_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700857 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700858 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700859 msync_session_set_video_dis(avsync->fd, fpts);
860 avsync->last_disc_pts = fpts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700861 }
862
863 if ((int)(systime - fpts) > 0) {
864 if ((int)(systime - fpts) < avsync->disc_thres_max) {
865 /* catch up PCR */
Song Zhaof46932e2021-05-21 01:51:45 -0700866 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700867 } else {
868 /* render according to FPS */
869 if (!VALID_TS(avsync->last_r_syst) ||
870 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
871 avsync->last_r_syst = systime;
872 return true;
873 }
874 return false;
875 }
876 } else if (LIVE_MODE(avsync->mode)) {
877 /* hold if the gap is small */
878 if ((int)(fpts - systime) < avsync->disc_thres_max) {
879 return false;
880 } else {
881 /* render according to FPS */
882 if (!VALID_TS(avsync->last_r_syst) ||
883 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
884 avsync->last_r_syst = systime;
885 return true;
886 }
887 return false;
888 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800889 }
890 }
891
Song Zhao52f55192021-05-06 10:52:21 -0700892 /* In some cases, keeping pattern will enlarge the gap */
893 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
894 avsync->first_frame_toggled) {
895 reset_pattern(avsync->pattern_detector);
Song Zhaof46932e2021-05-21 01:51:45 -0700896 log_warn("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700897 systime, fpts);
898 }
899
Song Zhaoc03ba122020-12-23 21:54:02 -0800900 expire = (int)(systime - fpts) >= 0;
901
902 /* scatter the frame in different vsync whenever possible */
903 if (expire && next_frame && next_frame->pts && toggle_cnt) {
904 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhaoea5a0412021-01-18 16:40:08 -0800905 if (systime + interval < next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800906 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800907 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
908 avsync->session_id, systime, interval, next_frame->pts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800909 }
910 } else if (!expire && next_frame && next_frame->pts && !toggle_cnt
911 && avsync->first_frame_toggled) {
912 /* next vsync will have at least 2 frame expired */
Song Zhao35a82df2021-04-15 10:58:49 -0700913 if (systime + interval >= next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800914 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800915 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
916 avsync->session_id, systime, interval, next_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800917 }
918 }
919
Song Zhaoa58c3e92021-03-09 18:52:55 -0800920 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
921 correct_pattern(avsync->pattern_detector, frame, next_frame,
922 (avsync->last_frame?avsync->last_frame->hold_period:0),
923 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800924 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -0800925
926 if (expire) {
927 avsync->vpts = fpts;
928 /* phase adjustment */
929 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +0000930 //always adjust to the half v-sync to give most pts tolerace and unify behavior
931 if ((int)(systime - fpts) >= 0 && (int)(fpts + interval - systime) > 0) {
932 avsync->phase = interval/2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800933 avsync->phase_set = true;
yongchun.lia50b1e92021-08-07 01:11:54 +0000934 log_info("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800935 }
936 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800937 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -0800938 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800939 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -0800940 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800941 }
942 return expire;
943}
944
Song Zhao35a82df2021-04-15 10:58:49 -0700945static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -0800946{
Song Zhao35a82df2021-04-15 10:58:49 -0700947 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800948 log_trace("[%d]cur_period: %d last_period: %d",
949 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -0700950 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
951 ret = true;
952 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
953 ret = true;
954 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
955 ret = true;
956 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
957 ret = true;
958
959 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800960}
961
962int av_sync_set_speed(void *sync, float speed)
963{
964 struct av_sync_session *avsync = (struct av_sync_session *)sync;
965
966 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800967 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800968 return -1;
969 }
970
Song Zhaoea5a0412021-01-18 16:40:08 -0800971 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
972 avsync->mode == AV_SYNC_MODE_IPTV) {
973 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800974 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800975 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800976
Song Zhaoea5a0412021-01-18 16:40:08 -0800977 avsync->speed = speed;
978
979 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
980 if (speed == 1.0) {
981 avsync->mode = avsync->backup_mode;
982 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
983 } else {
984 avsync->backup_mode = avsync->mode;
985 avsync->mode = AV_SYNC_MODE_FREE_RUN;
986 log_info("[%d]audio to freerun mode", avsync->session_id);
987 }
988 }
989#if 0
Song Zhaoc03ba122020-12-23 21:54:02 -0800990 if (avsync->mode != AV_SYNC_MODE_VMASTER) {
991 log_info("ignore set speed in mode %d", avsync->mode);
992 return 0;
993 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800994#endif
Song Zhaoc03ba122020-12-23 21:54:02 -0800995
Song Zhaoea5a0412021-01-18 16:40:08 -0800996 log_info("session[%d] set rate to %f", avsync->session_id, speed);
997 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800998}
999
1000int av_sync_change_mode(void *sync, enum sync_mode mode)
1001{
1002 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1003
1004 if (!avsync)
1005 return -1;
1006
Song Zhaoea5a0412021-01-18 16:40:08 -08001007 if (msync_session_set_mode(avsync->fd, mode)) {
1008 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001009 return -1;
1010 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001011 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001012 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001013 return 0;
1014}
1015
Song Zhao01031bb2021-05-13 21:23:20 -07001016int av_sync_get_mode(void *sync, enum sync_mode *mode)
1017{
1018 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1019
1020 if (!avsync || !mode)
1021 return -1;
1022
1023 *mode = avsync->mode;
1024 return 0;
1025}
1026
Song Zhaoc03ba122020-12-23 21:54:02 -08001027int av_sync_set_pause_pts(void *sync, pts90K pts)
1028{
1029 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1030
1031 if (!avsync)
1032 return -1;
1033
1034 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001035 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001036 return 0;
1037}
1038
1039int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1040{
1041 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1042
1043 if (!avsync)
1044 return -1;
1045
1046 avsync->pause_pts_cb = cb;
1047 avsync->pause_cb_priv = priv;
1048 return 0;
1049}
Song Zhaoea5a0412021-01-18 16:40:08 -08001050
1051static void trigger_audio_start_cb(struct av_sync_session *avsync,
1052 avs_ascb_reason reason)
1053{
1054 if (avsync) {
1055 pthread_mutex_lock(&avsync->lock);
1056 if (avsync->audio_start) {
1057 avsync->audio_start(avsync->audio_start_priv, reason);
1058 avsync->session_started = true;
1059 avsync->audio_start = NULL;
1060 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1061 }
1062 pthread_mutex_unlock(&avsync->lock);
1063 }
1064}
1065
1066avs_start_ret av_sync_audio_start(
1067 void *sync,
1068 pts90K pts,
1069 pts90K delay,
1070 audio_start_cb cb,
1071 void *priv)
1072{
1073 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1074 uint32_t start_mode;
yongchun.li59e873d2021-07-07 11:42:38 -07001075 uint32_t systime;
Song Zhaoea5a0412021-01-18 16:40:08 -08001076 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1077 bool create_poll_t = false;
1078
1079 if (!avsync)
1080 return ret;
1081
yongchun.li59e873d2021-07-07 11:42:38 -07001082 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1083 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001084
yongchun.li59e873d2021-07-07 11:42:38 -07001085 if (avsync->in_audio_switch &&
1086 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1087 {
1088 start_mode = AVS_START_SYNC;
1089 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1090 } else {
1091 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1092 log_error("[%d]fail to set audio start", avsync->session_id);
1093 }
1094 if (avsync->in_audio_switch &&
1095 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1096 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
1097 msync_session_get_wall(avsync->fd, &systime, NULL);
1098 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB &&
1099 start_mode == AVS_START_SYNC) {
1100 log_info("%d audio_switch audio need drop first.ahead %d ms",
1101 avsync->session_id, (int)(systime - pts)/90);
1102 ret = AV_SYNC_ASTART_AGAIN;
1103 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1104 goto exit;
1105 }
1106 else {
1107 int diff = (int)(pts - systime);
1108 log_info("%d audio_switch_state to start mode %d diff %d ms",
1109 avsync->session_id, start_mode, diff/90);
1110 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
1111 if (diff < A_ADJ_THREDHOLD_LB) {
1112 log_info("%d orig mode %d already close enough direct start",
1113 avsync->session_id, start_mode);
1114 start_mode = AVS_START_SYNC;
1115 }
1116 }
yongchun.li107a6162021-05-05 02:38:57 -07001117 }
1118
Song Zhaoea5a0412021-01-18 16:40:08 -08001119 if (start_mode == AVS_START_SYNC) {
1120 ret = AV_SYNC_ASTART_SYNC;
1121 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001122 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001123 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001124 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001125 avsync->state = AV_SYNC_STAT_RUNNING;
1126 } else if (start_mode == AVS_START_AGAIN) {
1127 ret = AV_SYNC_ASTART_AGAIN;
1128 }
1129
1130 if (ret == AV_SYNC_ASTART_AGAIN)
1131 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001132
yongchun.li107a6162021-05-05 02:38:57 -07001133 if (avsync->mode == AV_SYNC_MODE_AMASTER || avsync->in_audio_switch) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001134 create_poll_t = true;
1135 if (start_mode == AVS_START_ASYNC) {
1136 if (!cb) {
1137 log_error("[%d]invalid cb", avsync->session_id);
1138 return AV_SYNC_ASTART_ERR;
1139 }
1140 avsync->audio_start = cb;
1141 avsync->audio_start_priv = priv;
1142 }
Song Zhaod62bb392021-04-23 12:25:49 -07001143 } else if (LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001144 create_poll_t = true;
1145
Song Zhaod62bb392021-04-23 12:25:49 -07001146 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001147 int ret;
1148
1149 log_info("[%d]start poll thread", avsync->session_id);
1150 avsync->quit_poll = false;
1151 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1152 if (ret) {
1153 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1154 return AV_SYNC_ASTART_ERR;
1155 }
1156 }
Song Zhaod62bb392021-04-23 12:25:49 -07001157 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001158 msync_session_get_wall(avsync->fd, &systime, NULL);
1159 log_info("[%d]return %u w %u pts %u d %u",
1160 avsync->session_id, ret, systime, pts, delay);
1161 }
1162exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001163 log_info("[%d]return %u", avsync->session_id, ret);
1164 return ret;
1165}
1166
1167int av_sync_audio_render(
1168 void *sync,
1169 pts90K pts,
1170 struct audio_policy *policy)
1171{
1172 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001173 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001174 uint32_t systime;
1175 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1176 avs_audio_action action = AA_SYNC_AA_MAX;
1177
1178 if (!avsync || !policy)
1179 return -1;
1180
yongchun.li107a6162021-05-05 02:38:57 -07001181 msync_session_get_wall(avsync->fd, &systime, NULL);
1182
1183 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1184 pts, systime, avsync->mode, (int)(pts-systime)/90);
1185
1186 if (avsync->in_audio_switch
1187 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
1188 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
1189 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1190 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1191 action = AV_SYNC_AA_RENDER;
1192 } else if ((int)(systime - pts) > 0) {
1193 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1194 (int)(systime - pts)/90, systime, pts);
1195 action = AV_SYNC_AA_DROP;
1196 } else {
1197 action = AV_SYNC_AA_INSERT;
1198 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1199 (int)(pts - systime)/90, systime, pts);
1200 }
1201 goto done;
1202 }
1203
Song Zhaoea5a0412021-01-18 16:40:08 -08001204 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1205 avsync->mode == AV_SYNC_MODE_AMASTER) {
1206 action = AV_SYNC_AA_RENDER;
1207 goto done;
1208 }
1209
Song Zhaod62bb392021-04-23 12:25:49 -07001210 /* stopping procedure, unblock audio rendering */
1211 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER &&
1212 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1213 action = AV_SYNC_AA_DROP;
1214 goto done;
1215 }
1216
Song Zhao7daf3a12021-05-10 22:22:25 -07001217 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1218 avsync->mode == AV_SYNC_MODE_AMASTER) {
1219 action = AV_SYNC_AA_RENDER;
1220 goto done;
1221 }
1222
Song Zhaod62bb392021-04-23 12:25:49 -07001223 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1224 LIVE_MODE(avsync->mode) &&
1225 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1226 /* outlier by stream error */
1227 avsync->outlier_cnt++;
1228 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1229 /* treat as disc, just drop current frame */
1230 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1231 avsync->outlier_cnt = 0;
1232 action = AV_SYNC_AA_DROP;
1233 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001234 goto done;
1235 }
1236 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1237 pts = systime;
1238 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001239 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001240 goto done;
1241 }
1242
1243 avsync->outlier_cnt = 0;
1244 /* low bound from sync_lost to sync_setup */
1245 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1246 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1247 action = AV_SYNC_AA_RENDER;
1248 goto done;
1249 }
1250
1251 /* high bound of sync_setup */
1252 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1253 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1254 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001255 action = AV_SYNC_AA_RENDER;
1256 goto done;
1257 }
1258
1259 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001260 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001261 action = AV_SYNC_AA_DROP;
1262 goto done;
1263 }
1264
1265 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001266 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001267 action = AV_SYNC_AA_INSERT;
1268 goto done;
1269 }
1270
1271done:
1272 policy->action = action;
1273 policy->delta = (int)(systime - pts);
1274 if (action == AV_SYNC_AA_RENDER) {
1275 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001276 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001277 if (!out_lier)
1278 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001279 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001280 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001281 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1282 msync_session_update_apts(avsync->fd, systime, pts, 0);
1283 log_info("[%d] audio switch done sys %u pts %u",
1284 avsync->session_id, systime, pts);
1285 msync_session_set_audio_switch(avsync->fd, false);
1286 avsync->in_audio_switch = false;
1287 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1288 } else {
1289 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1290 avsync->session_id, action, systime, pts, systime - pts);
1291 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001292 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001293 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001294 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001295 avsync->last_disc_pts != pts &&
1296 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001297 log_info ("[%d]audio disc %u --> %u",
1298 avsync->session_id, systime, pts);
1299 msync_session_set_audio_dis(avsync->fd, pts);
1300 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001301 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001302 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001303
1304 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001305 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001306 if (!avsync->audio_drop_cnt)
1307 avsync->audio_drop_start = now;
1308 avsync->audio_drop_cnt++;
1309 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1310 log_info ("[%d]audio keep dropping sys %u vs a %u",
1311 avsync->session_id, systime, pts);
1312 msync_session_set_audio_dis(avsync->fd, pts);
1313 }
Song Zhao409739b2021-05-12 22:21:40 -07001314 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001315 if (action != AV_SYNC_AA_DROP)
1316 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001317 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001318 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001319 }
1320
1321 return ret;
1322}
1323
1324int av_sync_get_clock(void *sync, pts90K *pts)
1325{
1326 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1327
1328 if (!avsync || !pts)
1329 return -1;
1330 return msync_session_get_wall(avsync->fd, pts, NULL);
1331}
1332
1333static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001334 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001335{
bo.xiao1f94b352021-08-02 03:53:47 -04001336 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d", avsync->session_id,
Song Zhaoe208d692021-04-19 15:38:52 -07001337 avsync->active_mode, avsync->mode, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001338 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1339 float speed;
1340 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaoe208d692021-04-19 15:38:52 -07001341 a_active && avsync->audio_start) {
yongchun.li107a6162021-05-05 02:38:57 -07001342 if (v_active || v_timeout || avsync->in_audio_switch) {
Song Zhaoe208d692021-04-19 15:38:52 -07001343 log_info("audio start cb");
1344 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
yongchun.li107a6162021-05-05 02:38:57 -07001345 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001346 }
1347
1348 if (!msync_session_get_rate(avsync->fd, &speed)) {
1349 /* speed change is triggered by asink,
1350 * attached audio HAL will handle it
1351 */
1352 if (speed != avsync->speed)
1353 log_info("[%d]new rate %f", avsync->session_id, speed);
1354 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001355 if (avsync->mode != avsync->backup_mode) {
1356 avsync->mode = avsync->backup_mode;
1357 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1358 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001359 } else {
1360 avsync->backup_mode = avsync->mode;
1361 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1362 log_info("[%d]audio to freerun mode", avsync->session_id);
1363 }
1364 avsync->speed = speed;
1365 }
Song Zhaod62bb392021-04-23 12:25:49 -07001366 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1367 struct session_debug debug;
1368 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001369 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001370 avsync->backup_mode = avsync->mode;
1371 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001372 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001373 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001374 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001375 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001376 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001377 log_warn("[%d]audio back to mode %d",
1378 avsync->session_id, avsync->mode);
1379 }
1380 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001381 }
1382}
1383
1384static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001385 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001386{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001387 struct session_debug debug;
1388
bo.xiao1f94b352021-08-02 03:53:47 -04001389 log_info("[%d]av_sync amode mode %d %d v/a %d/%d", avsync->session_id,
Song Zhaoea5a0412021-01-18 16:40:08 -08001390 avsync->active_mode, avsync->mode, v_active, a_active);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001391 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1392 if (debug.debug_freerun && !avsync->debug_freerun) {
1393 avsync->backup_mode = avsync->mode;
1394 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1395 avsync->debug_freerun = true;
1396 log_warn("[%d]video to freerun mode", avsync->session_id);
1397 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1398 avsync->mode = avsync->backup_mode;
1399 avsync->debug_freerun = false;
1400 log_warn("[%d]video back to mode %d",
1401 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001402 }
1403 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001404}
1405
1406static void * poll_thread(void * arg)
1407{
1408 int ret = 0;
1409 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1410 const int fd = avsync->fd;
1411 struct pollfd pfd = {
1412 /* default blocking capture */
1413 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1414 .fd = avsync->fd,
1415 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001416 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001417
1418 prctl (PR_SET_NAME, "avs_poll");
1419 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001420
1421 if (avsync->type == AV_SYNC_TYPE_AUDIO)
1422 sflag = SRC_A;
1423 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
1424 sflag = SRC_V;
1425
Song Zhaoea5a0412021-01-18 16:40:08 -08001426 while (!avsync->quit_poll) {
1427 for (;;) {
1428 ret = poll(&pfd, 1, 10);
1429 if (ret > 0)
1430 break;
1431 if (avsync->quit_poll)
1432 goto exit;
1433 if (errno == EINTR)
1434 continue;
1435 }
1436
1437 /* error handling */
1438 if (pfd.revents & POLLERR)
1439 log_error("[%d]POLLERR received", avsync->session_id);
1440
Song Zhaod62bb392021-04-23 12:25:49 -07001441 /* mode change. Non-exclusive wait so all the processes
1442 * shall be woken up
1443 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001444 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001445 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -08001446
1447 msync_session_get_stat(fd, &avsync->active_mode,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001448 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001449
1450 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhaoe208d692021-04-19 15:38:52 -07001451 handle_mode_change_a(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001452 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhaoe208d692021-04-19 15:38:52 -07001453 handle_mode_change_v(avsync, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001454 usleep(10000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001455 }
1456 }
1457exit:
1458 log_info("[%d]quit", avsync->session_id);
1459 return NULL;
1460}
1461
Song Zhao623e2f12021-09-03 15:54:04 -07001462#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1463/* return ppm between demod and PCR clock */
1464int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1465{
1466 int fd = -1, ppm = 0, nread;
1467 char buf[128];
1468 uint32_t reg_v, lock;
1469 float val;
1470
1471 fd = open(DEMOD_NODE, O_RDWR);
1472 if (fd < 0) {
1473 log_warn("node not found %s", DEMOD_NODE);
1474 /* do not retry */
1475 avsync->ppm_adjusted = true;
1476 return 0;
1477 }
1478 snprintf(buf, sizeof(buf), "%d", 5);
1479 write(fd, buf, 2);
1480
1481 lseek(fd, 0, SEEK_SET);
1482
1483 nread = read(fd, buf, sizeof(buf));
1484 if (nread <= 0) {
1485 log_error("read error");
1486 goto err;
1487 }
1488 buf[nread] = 0;
1489 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1490 log_error("wrong format %s", buf);
1491 goto err;
1492 }
1493 if (lock != 0x1f) {
1494 log_info("demod not locked");
1495 goto err;
1496 }
1497 if (reg_v > ((2 << 20) - 1))
1498 reg_v -= (2 << 21);
1499 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1500 ppm = val;
1501 log_info("ppm from SFO %d", ppm);
1502 avsync->ppm_adjusted = true;
1503
1504err:
1505 if (fd >= 0)
1506 close(fd);
1507 return ppm;
1508}
1509
Song Zhaod62bb392021-04-23 12:25:49 -07001510int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001511{
1512 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001513 struct pcr_info pcr;
1514 enum pcr_monitor_status status;
1515 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001516 if (!avsync)
1517 return -1;
1518
1519 if (avsync->type != AV_SYNC_TYPE_PCR)
1520 return -2;
1521
Song Zhao623e2f12021-09-03 15:54:04 -07001522 /* initial estimation from Demod SFO HW */
1523 if (!avsync->ppm_adjusted) {
1524 ppm = dmod_get_sfo_dev(avsync);
1525 if (ppm != 0) {
1526 /* ppm > 0 means board clock is faster */
1527 msync_session_set_clock_dev(avsync->fd, -ppm);
1528 }
1529 }
wei.dubcc2ed22021-05-19 07:16:10 -04001530 pcr.monoclk = mono_clock / 1000;
1531 pcr.pts = (long long) pts * 1000 / 90;
1532 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1533
1534 status = pcr_monitor_get_status(avsync->pcr_monitor);
1535
1536 if (status >= DEVIATION_READY) {
1537 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1538 if (avsync->ppm != ppm) {
1539 avsync->ppm = ppm;
1540 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1541 if (msync_session_set_clock_dev(avsync->fd, ppm))
1542 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001543 else
1544 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001545 }
1546 }
1547
Song Zhaod62bb392021-04-23 12:25:49 -07001548 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001549}
1550
Song Zhaod62bb392021-04-23 12:25:49 -07001551int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001552{
1553 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1554
1555 if (!avsync)
1556 return -1;
1557
Song Zhaod62bb392021-04-23 12:25:49 -07001558 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001559}
1560
1561int av_sync_set_session_name(void *sync, const char *name)
1562{
1563 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1564
1565 if (!avsync)
1566 return -1;
1567
1568 return msync_session_set_name(avsync->fd, name);
1569}
yongchun.li107a6162021-05-05 02:38:57 -07001570
1571int av_sync_set_audio_switch(void *sync, bool start)
1572{
1573 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1574 bool v_active, a_active, v_timeout;
1575
1576 if (!avsync)
1577 return -1;
1578 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
1579 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001580 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001581 log_error("[%d] can not get session state",
1582 avsync->session_id);
1583 return -1;
1584 }
1585 if (!v_active || !a_active) {
1586 log_error("[%d] no apply if not AV both active v %d a %d",
1587 avsync->session_id, v_active, a_active);
1588 return -1;
1589 }
1590 if (msync_session_set_audio_switch(avsync->fd, start)) {
1591 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1592 return -1;
1593 }
1594 avsync->in_audio_switch = start;
1595 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1596 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1597 return 0;
1598}
1599
1600int av_sync_get_audio_switch(void *sync, bool *start)
1601{
1602 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1603
1604 if (!avsync)
1605 return -1;
1606 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001607 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001608 log_error("[%d] can not audio seamless switch state",
1609 avsync->session_id);
1610 return -1;
1611 }
1612 if (start) *start = avsync->in_audio_switch;
1613 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001614}
Song Zhao8039f562021-05-18 18:11:25 -07001615
Song Zhao623e2f12021-09-03 15:54:04 -07001616enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001617{
1618 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1619
wei.dubcc2ed22021-05-19 07:16:10 -04001620 if (!avsync || !ppm)
1621 return CLK_RECOVERY_ERR;
1622 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001623 return CLK_RECOVERY_NOT_RUNNING;
1624
wei.dubcc2ed22021-05-19 07:16:10 -04001625 if (msync_session_get_clock_dev(avsync->fd, ppm))
1626 return CLK_RECOVERY_ERR;
1627
1628 if (*ppm == 0)
1629 return CLK_RECOVERY_ONGOING;
1630 else
1631 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001632}
Song Zhao95bd0922021-09-21 14:07:46 -07001633
1634static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1635{
1636 int ret;
1637
1638 if (!avsync->frame_q) {
1639 avsync->frame_q = create_q(MAX_FRAME_NUM);
1640 if (!avsync->frame_q) {
1641 log_error("[%d]create queue fail", avsync->session_id);
1642
1643 return -1;
1644 }
1645 }
1646
1647 ret = queue_item(avsync->frame_q, frame);
1648 if (ret)
1649 log_error("%s queue fail:%d", ret);
1650 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1651 return ret;
1652}
1653
1654int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1655{
1656 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1657
1658 if (!avsync)
1659 return -1;
1660 avsync->msys = msys;
1661 return 0;
1662}
1663
1664static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1665{
1666 struct vframe *frame = NULL, *enter_last_frame = NULL;
1667 uint64_t systime;
1668 int toggle_cnt = 0;
1669
1670 enter_last_frame = avsync->last_frame;
1671 systime = avsync->msys;
1672 log_debug("[%d]sys %llu", avsync->session_id, systime);
1673 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1674 if (systime >= frame->mts) {
1675 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1676 toggle_cnt++;
1677
1678 if (avsync->last_frame)
1679 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1680
1681 dqueue_item(avsync->frame_q, (void **)&frame);
1682 if (avsync->last_frame) {
1683 /* free frame that are not for display */
1684 if (toggle_cnt > 1) {
1685 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1686 avsync->last_frame->mts, frame->mts, systime);
1687 avsync->last_frame->free(avsync->last_frame);
1688 }
1689 } else {
1690 avsync->first_frame_toggled = true;
1691 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1692 }
1693 avsync->last_frame = frame;
1694 } else
1695 break;
1696 }
1697
1698 if (avsync->last_frame) {
1699 if (enter_last_frame != avsync->last_frame)
1700 log_debug("[%d]pop %llu", avsync->session_id, avsync->last_frame->pts);
1701 log_trace("[%d]pop=%llu, system=%llu, diff %d(ms), QNum=%d", avsync->session_id,
1702 avsync->last_frame->mts,
1703 systime, (systime - avsync->last_frame->mts) / 1000000,
1704 queue_size(avsync->frame_q));
1705 } else
1706 if (enter_last_frame != avsync->last_frame)
1707 log_debug("[%d]pop (nil)", avsync->session_id);
1708
1709 if (avsync->last_frame)
1710 avsync->last_frame->hold_period++;
1711 return avsync->last_frame;
1712}