blob: 91a0232955772dcc614331288a4f391cf1b4b841 [file] [log] [blame]
Song Zhaoc03ba122020-12-23 21:54:02 -08001/*
2 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
3 *
4 * This source code is subject to the terms and conditions defined in the
5 * file 'LICENSE' which is part of this source code package.
6 *
7 * Description:
8 */
Song Zhaoea5a0412021-01-18 16:40:08 -08009#include <errno.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080010#include <pthread.h>
11#include <stdbool.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <sys/time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080015#include <poll.h>
16#include <fcntl.h>
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <sys/prctl.h>
20#include <sys/ioctl.h>
Song Zhaoa2985cb2021-06-24 12:01:47 -070021#include <time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080022#include <unistd.h>
23//#include <linux/amlogic/msync.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080024#include "aml_avsync.h"
Song Zhao4f632952021-12-16 09:00:18 -080025#include "aml_queue.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080026#include "pattern.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080027#include "aml_avsync_log.h"
Song Zhaoea5a0412021-01-18 16:40:08 -080028#include "msync_util.h"
29#include "msync.h"
30#include <pthread.h>
wei.dubcc2ed22021-05-19 07:16:10 -040031#include "pcr_monitor.h"
Song Zhao2f6744b2021-11-03 21:23:50 -070032
Song Zhaoc03ba122020-12-23 21:54:02 -080033enum sync_state {
34 AV_SYNC_STAT_INIT = 0,
35 AV_SYNC_STAT_RUNNING = 1,
36 AV_SYNC_STAT_SYNC_SETUP = 2,
37 AV_SYNC_STAT_SYNC_LOST = 3,
38};
39
yongchun.li107a6162021-05-05 02:38:57 -070040enum audio_switch_state_ {
41 AUDIO_SWITCH_STAT_INIT = 0,
42 AUDIO_SWITCH_STAT_RESET = 1,
43 AUDIO_SWITCH_STAT_START = 2,
44 AUDIO_SWITCH_STAT_FINISH = 3,
yongchun.li59e873d2021-07-07 11:42:38 -070045 AUDIO_SWITCH_STAT_AGAIN = 4,
yongchun.li107a6162021-05-05 02:38:57 -070046};
47
Song Zhaoea5a0412021-01-18 16:40:08 -080048#define SESSION_DEV "avsync_s"
49
Song Zhaoc03ba122020-12-23 21:54:02 -080050struct av_sync_session {
51 /* session id attached */
52 int session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -080053 int fd;
54 bool attached;
55 enum sync_mode mode;
56 /* for audio trickplay */
57 enum sync_mode backup_mode;
58 enum sync_type type;
59 uint32_t start_policy;
bo.xiao5821fc72021-07-11 22:47:00 -040060 int timeout;
Song Zhaoc03ba122020-12-23 21:54:02 -080061
Song Zhaoea5a0412021-01-18 16:40:08 -080062 /* playback time, will stop increasing during pause */
63 pts90K vpts;
64 pts90K apts;
65
66 /* phase adjustment of stream time for rate control (Video ONLY) */
Song Zhaoc03ba122020-12-23 21:54:02 -080067 pts90K phase;
68 bool phase_set;
Song Zhao1561e542022-01-12 10:37:55 -080069 bool phase_adjusted;
Song Zhaoc03ba122020-12-23 21:54:02 -080070
71 /* pts of last rendered frame */
Song Zhaoea5a0412021-01-18 16:40:08 -080072 pts90K last_wall;
Song Zhaoc03ba122020-12-23 21:54:02 -080073 pts90K last_pts;
74 struct vframe *last_frame;
75
Song Zhaoe0bf6ad2021-07-09 11:28:42 -070076 /* pts of last pushed frame */
77 pts90K last_q_pts;
78
Song Zhaoc03ba122020-12-23 21:54:02 -080079 bool first_frame_toggled;
Song Zhaoc03ba122020-12-23 21:54:02 -080080 bool paused;
Song Zhaoea5a0412021-01-18 16:40:08 -080081 enum sync_state state;
Song Zhaoc03ba122020-12-23 21:54:02 -080082 void *pattern_detector;
83 void *frame_q;
Song Zhaoc03ba122020-12-23 21:54:02 -080084
Song Zhaoea5a0412021-01-18 16:40:08 -080085 /* start control */
86 int start_thres;
87 audio_start_cb audio_start;
88 void *audio_start_priv;
89
90 /* render property */
Song Zhaoc03ba122020-12-23 21:54:02 -080091 int delay;
Song Zhao6dce2672022-01-13 11:32:44 -080092 int extra_delay;
Song Zhaoc03ba122020-12-23 21:54:02 -080093 pts90K vsync_interval;
94
95 /* state lock */
96 pthread_mutex_t lock;
97 /* pattern */
98 int last_holding_peroid;
Song Zhaoea5a0412021-01-18 16:40:08 -080099 bool session_started;
Song Zhaoc03ba122020-12-23 21:54:02 -0800100
101 float speed;
102
Song Zhaoc03ba122020-12-23 21:54:02 -0800103 /* pause pts */
104 pts90K pause_pts;
105 pause_pts_done pause_pts_cb;
106 void *pause_cb_priv;
yongchun.li428390d2022-02-17 17:15:40 -0800107 /* underflow */
108 underflow_detected underflow_cb;
109 void *underflow_cb_priv;
110 struct underflow_config underflow_cfg;
111 struct timespec frame_last_update_time;
Song Zhao5d2b4772021-01-18 16:40:08 -0800112
113 /* log control */
Song Zhaoa2985cb2021-06-24 12:01:47 -0700114 uint32_t last_log_syst;
Song Zhao5d2b4772021-01-18 16:40:08 -0800115 uint32_t sync_lost_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700116 struct timespec sync_lost_print_time;
Song Zhaoea5a0412021-01-18 16:40:08 -0800117
118 pthread_t poll_thread;
119 /* pcr master, IPTV only */
120 bool quit_poll;
121 enum sync_mode active_mode;
Song Zhaof46932e2021-05-21 01:51:45 -0700122 uint32_t disc_thres_min;
123 uint32_t disc_thres_max;
Song Zhao35a82df2021-04-15 10:58:49 -0700124
125 /* error detection */
126 uint32_t last_poptime;
Song Zhaod62bb392021-04-23 12:25:49 -0700127 uint32_t outlier_cnt;
Song Zhao409739b2021-05-12 22:21:40 -0700128 pts90K last_disc_pts;
129
yongchun.li107a6162021-05-05 02:38:57 -0700130 // indicate set audio switch
131 bool in_audio_switch;
132 enum audio_switch_state_ audio_switch_state;
wei.dubcc2ed22021-05-19 07:16:10 -0400133
134 //pcr monitor handle
135 void *pcr_monitor;
136 int ppm;
Song Zhao623e2f12021-09-03 15:54:04 -0700137 bool ppm_adjusted;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700138
139 //video FPS detection
140 pts90K last_fpts;
141 int fps_interval;
142 int fps_interval_acc;
143 int fps_cnt;
144
145 //video freerun with rate control
146 uint32_t last_r_syst;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700147 bool debug_freerun;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700148
149 //Audio dropping detection
150 uint32_t audio_drop_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700151 struct timespec audio_drop_start;
Song Zhao95bd0922021-09-21 14:07:46 -0700152
153 /*system mono time for current vsync interrupt */
154 uint64_t msys;
Song Zhaoc03ba122020-12-23 21:54:02 -0800155};
156
157#define MAX_FRAME_NUM 32
158#define DEFAULT_START_THRESHOLD 2
159#define TIME_UNIT90K (90000)
Song Zhaof46932e2021-05-21 01:51:45 -0700160#define AV_DISC_THRES_MIN (TIME_UNIT90K / 3)
161#define AV_DISC_THRES_MAX (TIME_UNIT90K * 10)
Song Zhao7daf3a12021-05-10 22:22:25 -0700162#define A_ADJ_THREDHOLD_HB (900 * 6) //60ms
163#define A_ADJ_THREDHOLD_LB (900 * 2) //20ms
Song Zhao52f55192021-05-06 10:52:21 -0700164#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800165#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhao76005282022-03-08 16:49:41 -0800166#define LIVE_MODE(m) ((m) == AV_SYNC_MODE_PCR_MASTER || (m) == AV_SYNC_MODE_IPTV)
Song Zhaod62bb392021-04-23 12:25:49 -0700167
Song Zhao065800e2021-05-26 15:56:06 -0700168#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
Song Zhaod62bb392021-04-23 12:25:49 -0700169#define OUTLIER_MAX_CNT 8
Song Zhaoa2985cb2021-06-24 12:01:47 -0700170#define VALID_TS(x) ((x) != -1)
yongchun.li428390d2022-02-17 17:15:40 -0800171#define UNDERFLOW_CHECK_THRESH_MS (100)
Song Zhaoc03ba122020-12-23 21:54:02 -0800172
yongchun.li0ee6e372021-08-20 04:26:04 -0700173static uint64_t time_diff (struct timespec *b, struct timespec *a);
Song Zhaoc03ba122020-12-23 21:54:02 -0800174static bool frame_expire(struct av_sync_session* avsync,
175 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800176 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800177 struct vframe * frame,
178 struct vframe * next_frame,
179 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700180static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800181 int cur_period,
182 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800183static void * poll_thread(void * arg);
184static void trigger_audio_start_cb(struct av_sync_session *avsync,
185 avs_ascb_reason reason);
Song Zhao95bd0922021-09-21 14:07:46 -0700186static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync);
187static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame);
Song Zhao2f6744b2021-11-03 21:23:50 -0700188pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER;
Song Zhaoc03ba122020-12-23 21:54:02 -0800189
Song Zhaoea5a0412021-01-18 16:40:08 -0800190int av_sync_open_session(int *session_id)
191{
Song Zhao2f6744b2021-11-03 21:23:50 -0700192 int fd = -1;
Song Zhaoea5a0412021-01-18 16:40:08 -0800193 int id, rc;
194
Song Zhao2f6744b2021-11-03 21:23:50 -0700195 pthread_mutex_lock(&glock);
196 fd = msync_create_session();
Song Zhaoea5a0412021-01-18 16:40:08 -0800197 if (fd < 0) {
198 log_error("fail");
Song Zhao2f6744b2021-11-03 21:23:50 -0700199 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800200 }
201 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
202 if (rc) {
203 log_error("new session errno:%d", errno);
Song Zhao2f6744b2021-11-03 21:23:50 -0700204 msync_destory_session(fd);
205 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800206 }
207 *session_id = id;
Song Zhao2f6744b2021-11-03 21:23:50 -0700208 log_debug("new avsession id %d fd %d", id, fd);
209exit:
210 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800211 return fd;
212}
213
214void av_sync_close_session(int session)
215{
Song Zhao2f6744b2021-11-03 21:23:50 -0700216 log_debug("session closed fd %d", session);
217 pthread_mutex_lock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800218 msync_destory_session(session);
Song Zhao2f6744b2021-11-03 21:23:50 -0700219 pthread_mutex_unlock(&glock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800220}
221
222static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800223 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800224 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800225 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800226 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800227{
228 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800229 char dev_name[20];
Song Zhao2f6744b2021-11-03 21:23:50 -0700230 int retry = 10;
Song Zhaoc03ba122020-12-23 21:54:02 -0800231
Song Zhao95bd0922021-09-21 14:07:46 -0700232 log_info("[%d] mode %d type %d", session_id, mode, type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800233 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
234 if (!avsync) {
235 log_error("OOM");
236 return NULL;
237 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800238
Song Zhao95bd0922021-09-21 14:07:46 -0700239 if (type == AV_SYNC_TYPE_VIDEO &&
240 mode == AV_SYNC_MODE_VIDEO_MONO) {
241 if (session_id < AV_SYNC_SESSION_V_MONO) {
242 log_error("wrong session id %d", session_id);
243 goto err;
244 }
245 avsync->type = type;
246 avsync->mode = mode;
247 avsync->fd = -1;
248 avsync->session_id = session_id;
249 log_info("[%d]init", avsync->session_id);
250 return avsync;
251 }
252
Song Zhaoea5a0412021-01-18 16:40:08 -0800253 if (type == AV_SYNC_TYPE_VIDEO) {
254 avsync->pattern_detector = create_pattern_detector();
255 if (!avsync->pattern_detector) {
256 log_error("pd create fail");
257 goto err;
258 }
259
260 if (!start_thres)
261 avsync->start_thres = DEFAULT_START_THRESHOLD;
262 else {
263 if (start_thres > 5) {
264 log_error("start_thres too big: %d", start_thres);
265 goto err2;
266 }
267 avsync->start_thres = start_thres;
268 }
269 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800270 avsync->phase_adjusted = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800271 avsync->first_frame_toggled = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800272 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800273
274 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800275 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800276 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800277 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800278 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800279 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800280 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800281 avsync->speed = 1.0f;
282 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhao409739b2021-05-12 22:21:40 -0700283 avsync->vsync_interval = -1;
284 avsync->last_disc_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700285 avsync->last_log_syst = -1;
286 avsync->last_pts = -1;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700287 avsync->last_q_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700288 avsync->last_wall = -1;
289 avsync->fps_interval = -1;
290 avsync->last_r_syst = -1;
bo.xiao5821fc72021-07-11 22:47:00 -0400291 avsync->timeout = -1;
292
Song Zhaof46932e2021-05-21 01:51:45 -0700293 if (msync_session_get_disc_thres(session_id,
294 &avsync->disc_thres_min, &avsync->disc_thres_max)) {
295 log_error("fail to get disc thres", dev_name, errno);
296 avsync->disc_thres_min = AV_DISC_THRES_MIN;
297 avsync->disc_thres_max = AV_DISC_THRES_MAX;
298 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800299
300 pthread_mutex_init(&avsync->lock, NULL);
Song Zhao9c09f772022-01-07 14:26:50 -0800301 log_info("[%d] start_thres %d disc_thres %u/%u", session_id,
Song Zhao95bd0922021-09-21 14:07:46 -0700302 start_thres, avsync->disc_thres_min, avsync->disc_thres_max);
Song Zhaoea5a0412021-01-18 16:40:08 -0800303
304 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
Song Zhao2f6744b2021-11-03 21:23:50 -0700305 while (retry) {
306 /* wait for sysfs to update */
307 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
308 if (avsync->fd > 0)
309 break;
310
311 retry--;
312 if (!retry) {
313 log_error("open %s errno %d", dev_name, errno);
314 goto err2;
315 }
316 usleep(20000);
Song Zhaoea5a0412021-01-18 16:40:08 -0800317 }
318
wei.dubcc2ed22021-05-19 07:16:10 -0400319 if (avsync->type == AV_SYNC_TYPE_PCR) {
320 if (pcr_monitor_init(&avsync->pcr_monitor)) {
321 log_error("pcr monitor init");
Song Zhao9cd27a52021-07-26 15:27:38 +0000322 goto err3;
wei.dubcc2ed22021-05-19 07:16:10 -0400323 }
324 }
325
Song Zhaoea5a0412021-01-18 16:40:08 -0800326 if (!attach) {
327 msync_session_set_mode(avsync->fd, mode);
328 avsync->mode = mode;
329 } else {
330 avsync->attached = true;
331 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
332 log_error("get mode");
Song Zhao9cd27a52021-07-26 15:27:38 +0000333 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800334 }
335 avsync->backup_mode = avsync->mode;
bo.xiao5821fc72021-07-11 22:47:00 -0400336 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800337 log_error("get policy");
Song Zhao9cd27a52021-07-26 15:27:38 +0000338 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800339 }
Song Zhao76005282022-03-08 16:49:41 -0800340 if (msync_session_get_stat(avsync->fd, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700341 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -0700342 log_error("get state");
Song Zhao9cd27a52021-07-26 15:27:38 +0000343 goto err4;
yongchun.li107a6162021-05-05 02:38:57 -0700344 }
345 if (avsync->in_audio_switch) {
346 log_info("audio_switch_state reseted the audio");
347 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
348 }
349
Song Zhaoea5a0412021-01-18 16:40:08 -0800350 log_info("[%d]retrieve sync mode %d policy %d",
351 session_id, avsync->mode, avsync->start_policy);
352 }
353
Song Zhao67c937b2021-10-01 11:21:32 -0700354 /* debug log level */
355 {
356 const char *env= getenv( "AML_AVSYNC_DEBUG_LEVEL");
357 if ( env ) {
358 log_set_level(atoi(env));
359 }
360 }
361
Song Zhaoc03ba122020-12-23 21:54:02 -0800362 return avsync;
Song Zhao9cd27a52021-07-26 15:27:38 +0000363err4:
wei.dubcc2ed22021-05-19 07:16:10 -0400364 if (avsync->pcr_monitor)
365 pcr_monitor_destroy(avsync->pcr_monitor);
Song Zhao9cd27a52021-07-26 15:27:38 +0000366err3:
367 close(avsync->fd);
Song Zhaoea5a0412021-01-18 16:40:08 -0800368err2:
369 destroy_pattern_detector(avsync->pattern_detector);
370err:
371 free(avsync);
372 return NULL;
373}
374
375void* av_sync_create(int session_id,
376 enum sync_mode mode,
377 enum sync_type type,
378 int start_thres)
379{
380 return create_internal(session_id, mode,
381 type, start_thres, false);
382}
383
384void* av_sync_attach(int session_id, enum sync_type type)
385{
Song Zhao95bd0922021-09-21 14:07:46 -0700386 if (type == AV_SYNC_TYPE_VIDEO)
387 return NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800388 return create_internal(session_id, AV_SYNC_MODE_MAX,
389 type, 0, true);
390}
391
392int av_sync_video_config(void *sync, struct video_config* config)
393{
394 struct av_sync_session *avsync = (struct av_sync_session *)sync;
395
396 if (!avsync || !config)
397 return -1;
398
399 if (config->delay != 1 && config->delay != 2) {
400 log_error("invalid delay: %d\n", config->delay);
401 return -1;
402 }
403
404 avsync->delay = config->delay;
Song Zhao6dce2672022-01-13 11:32:44 -0800405 avsync->extra_delay = config->extra_delay * 90;
Song Zhaoea5a0412021-01-18 16:40:08 -0800406
Song Zhao6dce2672022-01-13 11:32:44 -0800407 log_info("[%d] vsync delay: %d extra_delay: %d ms",
408 avsync->session_id, config->delay, config->extra_delay);
Song Zhaoea5a0412021-01-18 16:40:08 -0800409 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800410}
411
412static int internal_stop(struct av_sync_session *avsync)
413{
414 int ret = 0;
415 struct vframe *frame;
416
417 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800418 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
419 frame->free(frame);
420 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800421 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800422 pthread_mutex_unlock(&avsync->lock);
423 return ret;
424}
425
426/* destroy and detach from kernel session */
427void av_sync_destroy(void *sync)
428{
429 struct av_sync_session *avsync = (struct av_sync_session *)sync;
430
431 if (!avsync)
432 return;
433
Song Zhao95bd0922021-09-21 14:07:46 -0700434 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
435 avsync->mode == AV_SYNC_MODE_VIDEO_MONO) {
436 log_info("[%d]done", avsync->session_id);
437 internal_stop(avsync);
438 destroy_q(avsync->frame_q);
439 free(avsync);
440 return;
441 }
Song Zhaob5458b32021-11-12 15:58:47 -0800442 log_info("[%d]begin type %d", avsync->session_id, avsync->type);
Song Zhaoea5a0412021-01-18 16:40:08 -0800443 if (avsync->state != AV_SYNC_STAT_INIT) {
444 if (avsync->type == AV_SYNC_TYPE_VIDEO)
445 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800446
Song Zhaoea5a0412021-01-18 16:40:08 -0800447 avsync->quit_poll = true;
448 if (avsync->poll_thread) {
449 pthread_join(avsync->poll_thread, NULL);
450 avsync->poll_thread = 0;
451 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700452 if (avsync->type == AV_SYNC_TYPE_AUDIO)
453 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoaf368d52021-02-17 17:53:45 -0800454 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800455
Song Zhaoea5a0412021-01-18 16:40:08 -0800456 if (avsync->session_started) {
457 if (avsync->type == AV_SYNC_TYPE_VIDEO)
458 msync_session_set_video_stop(avsync->fd);
459 else
460 msync_session_set_audio_stop(avsync->fd);
461 }
wei.dubcc2ed22021-05-19 07:16:10 -0400462
463 if(avsync->pcr_monitor)
464 pcr_monitor_destroy(avsync->pcr_monitor);
465
Song Zhaoea5a0412021-01-18 16:40:08 -0800466 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800467 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800468 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
469 destroy_q(avsync->frame_q);
470 destroy_pattern_detector(avsync->pattern_detector);
471 }
Song Zhaob5458b32021-11-12 15:58:47 -0800472 log_info("[%d]done type %d", avsync->session_id, avsync->type);
Song Zhaoc03ba122020-12-23 21:54:02 -0800473 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800474}
475
bo.xiao5821fc72021-07-11 22:47:00 -0400476int avs_sync_set_start_policy(void *sync, struct start_policy* st_policy)
Song Zhaoea5a0412021-01-18 16:40:08 -0800477{
478 struct av_sync_session *avsync = (struct av_sync_session *)sync;
479
480 if (!avsync || !avsync->fd)
481 return -1;
482
bo.xiao5821fc72021-07-11 22:47:00 -0400483 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 -0800484 if (LIVE_MODE(avsync->mode) &&
485 st_policy->policy != AV_SYNC_START_ASAP) {
486 log_error("policy %d not supported in live mode", st_policy->policy);
487 return -1;
488 }
489
bo.xiao5821fc72021-07-11 22:47:00 -0400490 avsync->start_policy = st_policy->policy;
491 avsync->timeout = st_policy->timeout;
Song Zhao76005282022-03-08 16:49:41 -0800492
Song Zhaoea5a0412021-01-18 16:40:08 -0800493 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400494 if (st_policy->policy != AV_SYNC_START_NONE &&
495 st_policy->policy != AV_SYNC_START_V_PEEK)
496 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800497
498 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800499}
500
501int av_sync_pause(void *sync, bool pause)
502{
503 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700504 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800505 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800506
Song Zhaob5458b32021-11-12 15:58:47 -0800507 if (!avsync) {
508 log_error("invalid handle");
Song Zhaoc03ba122020-12-23 21:54:02 -0800509 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800510 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800511
Song Zhaob5458b32021-11-12 15:58:47 -0800512 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
513 log_warn("ignore pause in pcr master mode");
Song Zhaoea5a0412021-01-18 16:40:08 -0800514 return -1;
Song Zhaob5458b32021-11-12 15:58:47 -0800515 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800516
Song Zhao76005282022-03-08 16:49:41 -0800517 rc = msync_session_get_stat(avsync->fd, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -0700518 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700519 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700520
yongchun.li5f52fb02021-06-04 18:13:05 -0700521 /* ignore only when video try to pause when audio is acive, on which
522 the control of the STC will be relays.
523 When resume,it can do always as it is possible that video just
524 paused earlier without audio yet,then audio added later before resume.
525 We shall not igore that otherwise it could cause video freeze. */
526 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
527 avsync->type == AV_SYNC_TYPE_VIDEO &&
528 a_active &&
529 !avsync->in_audio_switch) {
530 if (!pause) {
531 log_info("[%d] clear video pause when audio active",
532 avsync->session_id);
533 avsync->paused = pause;
534 } else {
535 log_info("[%d] ignore the pause from video when audio active",
536 avsync->session_id);
537 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800538 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700539 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800540
yongchun.li107a6162021-05-05 02:38:57 -0700541 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
542 log_info("[%d] ignore the pause from audio", avsync->session_id);
543 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
544 return 0;
545 }
546
Song Zhaoea5a0412021-01-18 16:40:08 -0800547 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800548 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800549 log_info("[%d]paused:%d type:%d rc %d",
550 avsync->session_id, pause, avsync->type, rc);
yongchun.li428390d2022-02-17 17:15:40 -0800551 if (!avsync->paused && avsync->first_frame_toggled) {
552 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
553 log_info("[%d] resume update new frame time", avsync->session_id);
554 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800555 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800556}
557
558int av_sync_push_frame(void *sync , struct vframe *frame)
559{
560 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700561 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800562 struct av_sync_session *avsync = (struct av_sync_session *)sync;
563
564 if (!avsync)
565 return -1;
566
Song Zhao95bd0922021-09-21 14:07:46 -0700567 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
568 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
569 return video_mono_push_frame(avsync, frame);
570
Song Zhaoea5a0412021-01-18 16:40:08 -0800571 if (!avsync->frame_q) {
572 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400573 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800574 log_error("[%d]get policy", avsync->session_id);
575 return -1;
576 }
577
578 avsync->frame_q = create_q(MAX_FRAME_NUM);
579 if (!avsync->frame_q) {
580 log_error("[%d]create queue fail", avsync->session_id);
yongchun.li0ee6e372021-08-20 04:26:04 -0700581
Song Zhaoea5a0412021-01-18 16:40:08 -0800582 return -1;
583 }
584
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700585 {
Song Zhaoea5a0412021-01-18 16:40:08 -0800586 int ret;
587
588 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
589 if (ret) {
590 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
591 destroy_q(avsync->frame_q);
592 return -1;
593 }
594 }
595 }
596
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700597 if (avsync->last_q_pts != -1) {
598 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
599 /* TODO: wrong, should remove from back of queue */
Song Zhaoc03ba122020-12-23 21:54:02 -0800600 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700601 if (prev) {
602 prev->free(prev);
603 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
604 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700605 } else if (avsync->fps_cnt < 100) {
606 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700607
608 if (interval > 0 && interval <= 4500) {
609 if (avsync->fps_interval_acc == -1) {
610 avsync->fps_interval_acc = interval;
611 avsync->fps_cnt = 1;
612 } else {
613 avsync->fps_interval_acc += interval;
614 avsync->fps_cnt++;
615 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
616 if (avsync->fps_cnt == 100)
617 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
618 }
619 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800620 }
621 }
622
Song Zhao065800e2021-05-26 15:56:06 -0700623 if (frame->duration == -1)
624 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800625 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700626 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800627 ret = queue_item(avsync->frame_q, frame);
628 if (avsync->state == AV_SYNC_STAT_INIT &&
629 queue_size(avsync->frame_q) >= avsync->start_thres) {
630 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaoea5a0412021-01-18 16:40:08 -0800631 log_info("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800632 }
633
634 if (ret)
Song Zhaoe1b65602022-01-06 08:03:46 -0800635 log_error("queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400636 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800637 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800638}
639
640struct vframe *av_sync_pop_frame(void *sync)
641{
Song Zhaoea5a0412021-01-18 16:40:08 -0800642 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800643 struct av_sync_session *avsync = (struct av_sync_session *)sync;
644 int toggle_cnt = 0;
645 uint32_t systime;
Song Zhao468fd652021-01-15 22:13:04 -0800646 bool pause_pts_reached = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800647 uint32_t interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800648
Song Zhao95bd0922021-09-21 14:07:46 -0700649 if (avsync->type == AV_SYNC_TYPE_VIDEO &&
650 avsync->mode == AV_SYNC_MODE_VIDEO_MONO)
651 return video_mono_pop_frame(avsync);
652
Song Zhaoc03ba122020-12-23 21:54:02 -0800653 pthread_mutex_lock(&avsync->lock);
654 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhao2f6744b2021-11-03 21:23:50 -0700655 log_debug("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800656 goto exit;
657 }
658
Song Zhaoea5a0412021-01-18 16:40:08 -0800659 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700660 uint32_t pts;
661
Song Zhaoc03ba122020-12-23 21:54:02 -0800662 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800663 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800664 goto exit;
665 }
Song Zhao35a82df2021-04-15 10:58:49 -0700666 msync_session_get_wall(avsync->fd, &systime, &interval);
667 pts = frame->pts - avsync->delay * interval;
668 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800669 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700670 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800671 }
672
Song Zhaoea5a0412021-01-18 16:40:08 -0800673 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700674 !avsync->first_frame_toggled &&
675 !msync_clock_started(avsync->fd)) {
676 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800677 log_trace("[%d]clock not started", avsync->session_id);
678 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800679 }
680
Song Zhaoea5a0412021-01-18 16:40:08 -0800681 enter_last_frame = avsync->last_frame;
682 msync_session_get_wall(avsync->fd, &systime, &interval);
683
684 /* handle refresh rate change */
685 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
686 avsync->vsync_interval != interval) {
687 log_info("[%d]vsync interval update %d --> %u",
688 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700689 if (avsync->fps_interval == -1)
690 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800691 avsync->vsync_interval = interval;
692 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800693 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700694 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800695 reset_pattern(avsync->pattern_detector);
696 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800697 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
698 struct vframe *next_frame = NULL;
699
700 peek_item(avsync->frame_q, (void **)&next_frame, 1);
701 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700702 log_debug("[%d]cur_f %u next_f %u size %d",
703 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800704 if (frame_expire(avsync, systime, interval,
705 frame, next_frame, toggle_cnt)) {
706 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800707 toggle_cnt++;
708
Song Zhao35a82df2021-04-15 10:58:49 -0700709 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800710 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700711 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700712 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700713 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
714 if (next_frame)
715 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
716 }
Song Zhao35a82df2021-04-15 10:58:49 -0700717
Song Zhaoc03ba122020-12-23 21:54:02 -0800718 if (avsync->last_frame)
719 avsync->last_holding_peroid = avsync->last_frame->hold_period;
720
721 dqueue_item(avsync->frame_q, (void **)&frame);
722 if (avsync->last_frame) {
723 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800724 if (toggle_cnt > 1) {
Song Zhao35a82df2021-04-15 10:58:49 -0700725 log_debug("[%d]free %u cur %u system/d %u/%u", avsync->session_id,
726 avsync->last_frame->pts, frame->pts, systime, systime - avsync->last_poptime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800727 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800728 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800729 } else {
730 avsync->first_frame_toggled = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800731 log_info("[%d]first frame %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800732 }
733 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800734 avsync->last_pts = frame->pts;
yongchun.li428390d2022-02-17 17:15:40 -0800735 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->frame_last_update_time);
Song Zhaoc03ba122020-12-23 21:54:02 -0800736 } else
737 break;
738 }
739
740 /* pause pts */
741 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800742 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800743 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800744 else
Song Zhao468fd652021-01-15 22:13:04 -0800745 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
746 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
747 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
748 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
749 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800750
Song Zhao468fd652021-01-15 22:13:04 -0800751 if (pause_pts_reached) {
752 if (avsync->pause_pts_cb)
753 avsync->pause_pts_cb(avsync->pause_pts,
Song Zhaoc03ba122020-12-23 21:54:02 -0800754 avsync->pause_cb_priv);
755
Song Zhao468fd652021-01-15 22:13:04 -0800756 /* stay in paused until av_sync_pause(false) */
757 avsync->paused = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800758 log_info ("[%d]reach pause pts: %u",
Song Zhaob5458b32021-11-12 15:58:47 -0800759 avsync->session_id, avsync->pause_pts);
Song Zhaoad7c8232021-12-14 11:46:48 -0800760 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoc03ba122020-12-23 21:54:02 -0800761 }
762
763exit:
764 pthread_mutex_unlock(&avsync->lock);
yongchun.li428390d2022-02-17 17:15:40 -0800765
766 /* underflow check */
767 if (avsync->session_started && avsync->first_frame_toggled &&
768 (avsync->paused == false) && (avsync->state >= AV_SYNC_STAT_RUNNING) &&
769 avsync->underflow_cb && peek_item(avsync->frame_q, (void **)&frame, 0))
770 {/* empty queue in normal play */
771 struct timespec now;
772 int diff_ms;
773 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
774 diff_ms = time_diff(&now, &avsync->frame_last_update_time)/1000;
775 if(diff_ms >= (avsync->underflow_cfg.time_thresh
776 + avsync->vsync_interval*avsync->last_holding_peroid/90)) {
777 log_info ("[%d]underflow detected: %u", avsync->session_id, avsync->last_pts);
778 avsync->underflow_cb (avsync->last_pts,
779 avsync->underflow_cb_priv);
780 /* update time to control the underflow check call backs */
781 avsync->frame_last_update_time = now;
782 }
783 }
784
Song Zhaoc03ba122020-12-23 21:54:02 -0800785 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800786 if (enter_last_frame != avsync->last_frame)
787 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
bo.xiao1f94b352021-08-02 03:53:47 -0400788 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 -0700789 /* don't update vpts for out_lier */
790 if (avsync->last_frame->duration != -1)
791 msync_session_update_vpts(avsync->fd, systime,
792 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800793 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800794 if (enter_last_frame != avsync->last_frame)
795 log_debug("[%d]pop (nil)", avsync->session_id);
796
Song Zhao35a82df2021-04-15 10:58:49 -0700797 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800798 if (avsync->last_frame)
799 avsync->last_frame->hold_period++;
800 return avsync->last_frame;
801}
802
Song Zhaoc03ba122020-12-23 21:54:02 -0800803static inline uint32_t abs_diff(uint32_t a, uint32_t b)
804{
Song Zhaoea5a0412021-01-18 16:40:08 -0800805 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800806}
807
yongchun.li0ee6e372021-08-20 04:26:04 -0700808static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800809{
yongchun.li0ee6e372021-08-20 04:26:04 -0700810 return (b->tv_sec - a->tv_sec)*1000000 + (b->tv_nsec/1000 - a->tv_nsec/1000);
Song Zhaoc03ba122020-12-23 21:54:02 -0800811}
812
Song Zhaoc03ba122020-12-23 21:54:02 -0800813static bool frame_expire(struct av_sync_session* avsync,
814 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800815 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800816 struct vframe * frame,
817 struct vframe * next_frame,
818 int toggle_cnt)
819{
Song Zhao6dce2672022-01-13 11:32:44 -0800820 uint32_t fpts = frame->pts + avsync->extra_delay;
821 uint32_t nfpts = -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800822 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800823 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800824
825 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
826 return false;
827
828 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
829 return true;
830
Song Zhaoad7c8232021-12-14 11:46:48 -0800831 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS &&
832 avsync->pause_pts == frame->pts)
833 return true;
834
Song Zhao08fa16b2021-12-08 14:30:17 -0800835 if (systime == AV_SYNC_INVALID_PTS &&
836 avsync->mode == AV_SYNC_MODE_AMASTER)
837 return false;
838
Song Zhao6dce2672022-01-13 11:32:44 -0800839 if (next_frame)
840 nfpts = next_frame->pts + avsync->extra_delay;
841
fei.deng63e43e12021-09-23 19:44:01 +0800842 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
Song Zhao76005282022-03-08 16:49:41 -0800843 avsync->mode == AV_SYNC_MODE_VMASTER) {
fei.deng63e43e12021-09-23 19:44:01 +0800844 /* We need to ensure that the video outputs smoothly,
845 so output video frame by frame hold_period */
846 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
847 avsync->last_frame &&
848 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
849 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
850 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700851 return true;
852 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700853 }
854
Song Zhaoc03ba122020-12-23 21:54:02 -0800855 if (!fpts) {
856 if (avsync->last_frame) {
857 /* try to accumulate duration as PTS */
858 fpts = avsync->vpts + avsync->last_frame->duration;
859 } else {
860 fpts = avsync->vpts;
861 }
862 }
863 systime += pts_correction;
864
865 /* phase adjustment */
866 if (avsync->phase_set)
867 systime += avsync->phase;
868
yongchun.lia50b1e92021-08-07 01:11:54 +0000869 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800870 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000871 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700872 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800873 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800874 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800875 return false;
876
Song Zhaoa2985cb2021-06-24 12:01:47 -0700877 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
878 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700879 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800880
yongchun.li0ee6e372021-08-20 04:26:04 -0700881 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700882 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800883 avsync->last_pts = fpts;
884 if (time_diff(&now, &avsync->sync_lost_print_time) >=
885 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700886 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800887 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800888 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700889 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800890 } else
891 avsync->sync_lost_cnt++;
892 }
Song Zhaod62bb392021-04-23 12:25:49 -0700893
894 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
895 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700896 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700897 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700898 /* outlier by stream error */
899 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700900 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700901 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
902 log_info("render outlier %u", fpts);
903 return true;
904 }
905 }
906
907 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800908 avsync->state = AV_SYNC_STAT_SYNC_LOST;
909 avsync->phase_set = false;
Song Zhao1561e542022-01-12 10:37:55 -0800910 avsync->phase_adjusted = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700911 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800912 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700913
914 if (LIVE_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700915 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700916 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700917 msync_session_set_video_dis(avsync->fd, fpts);
918 avsync->last_disc_pts = fpts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700919 }
920
921 if ((int)(systime - fpts) > 0) {
922 if ((int)(systime - fpts) < avsync->disc_thres_max) {
923 /* catch up PCR */
Song Zhaof46932e2021-05-21 01:51:45 -0700924 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700925 } else {
926 /* render according to FPS */
927 if (!VALID_TS(avsync->last_r_syst) ||
928 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
929 avsync->last_r_syst = systime;
930 return true;
931 }
932 return false;
933 }
934 } else if (LIVE_MODE(avsync->mode)) {
935 /* hold if the gap is small */
936 if ((int)(fpts - systime) < avsync->disc_thres_max) {
937 return false;
938 } else {
939 /* render according to FPS */
940 if (!VALID_TS(avsync->last_r_syst) ||
941 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
942 avsync->last_r_syst = systime;
943 return true;
944 }
945 return false;
946 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800947 }
948 }
949
Song Zhao52f55192021-05-06 10:52:21 -0700950 /* In some cases, keeping pattern will enlarge the gap */
951 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
952 avsync->first_frame_toggled) {
953 reset_pattern(avsync->pattern_detector);
Song Zhaof46932e2021-05-21 01:51:45 -0700954 log_warn("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700955 systime, fpts);
956 }
957
Song Zhaoc03ba122020-12-23 21:54:02 -0800958 expire = (int)(systime - fpts) >= 0;
959
960 /* scatter the frame in different vsync whenever possible */
Song Zhao6dce2672022-01-13 11:32:44 -0800961 if (expire && nfpts != -1 && nfpts && toggle_cnt) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800962 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhao6dce2672022-01-13 11:32:44 -0800963 if (systime + interval < nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800964 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800965 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
Song Zhao6dce2672022-01-13 11:32:44 -0800966 avsync->session_id, systime, interval, nfpts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800967 }
Song Zhao6dce2672022-01-13 11:32:44 -0800968 } else if (!expire && nfpts != -1 && nfpts && !toggle_cnt
Song Zhaoc03ba122020-12-23 21:54:02 -0800969 && avsync->first_frame_toggled) {
970 /* next vsync will have at least 2 frame expired */
Song Zhao6dce2672022-01-13 11:32:44 -0800971 if (systime + interval >= nfpts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800972 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800973 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
Song Zhao6dce2672022-01-13 11:32:44 -0800974 avsync->session_id, systime, interval, nfpts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800975 }
976 }
977
Song Zhaoa58c3e92021-03-09 18:52:55 -0800978 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
Song Zhao6dce2672022-01-13 11:32:44 -0800979 correct_pattern(avsync->pattern_detector, fpts, nfpts,
Song Zhaoa58c3e92021-03-09 18:52:55 -0800980 (avsync->last_frame?avsync->last_frame->hold_period:0),
981 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800982 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -0800983
984 if (expire) {
985 avsync->vpts = fpts;
986 /* phase adjustment */
987 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +0000988 //always adjust to the half v-sync to give most pts tolerace and unify behavior
Song Zhao9c09f772022-01-07 14:26:50 -0800989 if ((int)(systime - fpts) >= 0 &&
990 (int)(fpts + interval - systime) > 0) {
991 avsync->phase = interval / 2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800992 avsync->phase_set = true;
yongchun.lia50b1e92021-08-07 01:11:54 +0000993 log_info("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800994 }
Song Zhao1561e542022-01-12 10:37:55 -0800995 } else if (get_pattern(avsync->pattern_detector) < 0 && !avsync->phase_adjusted) {
Song Zhao9c09f772022-01-07 14:26:50 -0800996 if ((int)(systime - fpts) >= 0 &&
997 (int)(fpts + interval - systime) > 0) {
998 int vsync_pts_delta = (int)(systime - fpts);
999
1000 if (vsync_pts_delta < 10 || vsync_pts_delta > (interval - 10)) {
1001 avsync->phase += interval / 8;
Song Zhao1561e542022-01-12 10:37:55 -08001002 avsync->phase_adjusted = true;
Song Zhao9c09f772022-01-07 14:26:50 -08001003 log_info("[%d] too aligned adjust phase to %d",
1004 avsync->session_id, (int)avsync->phase);
1005 }
1006 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001007 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001008 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -08001009 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -08001010 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -08001011 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -08001012 }
1013 return expire;
1014}
1015
Song Zhao35a82df2021-04-15 10:58:49 -07001016static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -08001017{
Song Zhao35a82df2021-04-15 10:58:49 -07001018 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001019 log_trace("[%d]cur_period: %d last_period: %d",
1020 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -07001021 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
1022 ret = true;
1023 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
1024 ret = true;
1025 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
1026 ret = true;
1027 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
1028 ret = true;
1029
1030 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -08001031}
1032
1033int av_sync_set_speed(void *sync, float speed)
1034{
1035 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1036
1037 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001038 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001039 return -1;
1040 }
1041
Song Zhao76005282022-03-08 16:49:41 -08001042 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001043 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001044 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001045 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001046
Song Zhaoea5a0412021-01-18 16:40:08 -08001047 avsync->speed = speed;
1048
1049 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
1050 if (speed == 1.0) {
1051 avsync->mode = avsync->backup_mode;
1052 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1053 } else {
1054 avsync->backup_mode = avsync->mode;
1055 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1056 log_info("[%d]audio to freerun mode", avsync->session_id);
1057 }
1058 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001059
Song Zhaoea5a0412021-01-18 16:40:08 -08001060 log_info("session[%d] set rate to %f", avsync->session_id, speed);
1061 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -08001062}
1063
1064int av_sync_change_mode(void *sync, enum sync_mode mode)
1065{
1066 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1067
1068 if (!avsync)
1069 return -1;
1070
Song Zhaoea5a0412021-01-18 16:40:08 -08001071 if (msync_session_set_mode(avsync->fd, mode)) {
1072 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001073 return -1;
1074 }
Song Zhaoc03ba122020-12-23 21:54:02 -08001075 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -08001076 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -08001077 return 0;
1078}
1079
Song Zhao01031bb2021-05-13 21:23:20 -07001080int av_sync_get_mode(void *sync, enum sync_mode *mode)
1081{
1082 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1083
1084 if (!avsync || !mode)
1085 return -1;
1086
1087 *mode = avsync->mode;
1088 return 0;
1089}
1090
Song Zhaoc03ba122020-12-23 21:54:02 -08001091int av_sync_set_pause_pts(void *sync, pts90K pts)
1092{
1093 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1094
1095 if (!avsync)
1096 return -1;
1097
1098 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -08001099 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -08001100 return 0;
1101}
1102
1103int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
1104{
1105 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1106
1107 if (!avsync)
1108 return -1;
1109
1110 avsync->pause_pts_cb = cb;
1111 avsync->pause_cb_priv = priv;
1112 return 0;
1113}
Song Zhaoea5a0412021-01-18 16:40:08 -08001114
yongchun.li428390d2022-02-17 17:15:40 -08001115int av_sync_set_underflow_check_cb(void *sync, underflow_detected cb, void *priv, struct underflow_config *cfg)
1116{
1117 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1118
1119 if (!avsync)
1120 return -1;
1121
1122 avsync->underflow_cb = cb;
1123 avsync->underflow_cb_priv = priv;
1124
1125 if (cfg)
1126 avsync->underflow_cfg.time_thresh = cfg->time_thresh;
1127 else
1128 avsync->underflow_cfg.time_thresh = UNDERFLOW_CHECK_THRESH_MS;
1129
1130 log_info("[%d] av_sync_set_underflow_check_cb %p priv %p time %d",
1131 avsync->session_id, avsync->underflow_cb, avsync->underflow_cb_priv,
1132 avsync->underflow_cfg.time_thresh);
1133 return 0;
1134}
Song Zhaoea5a0412021-01-18 16:40:08 -08001135static void trigger_audio_start_cb(struct av_sync_session *avsync,
1136 avs_ascb_reason reason)
1137{
1138 if (avsync) {
Song Zhao76005282022-03-08 16:49:41 -08001139 log_info("audio start cb");
Song Zhaoea5a0412021-01-18 16:40:08 -08001140 pthread_mutex_lock(&avsync->lock);
1141 if (avsync->audio_start) {
1142 avsync->audio_start(avsync->audio_start_priv, reason);
1143 avsync->session_started = true;
1144 avsync->audio_start = NULL;
Song Zhao76005282022-03-08 16:49:41 -08001145 avsync->audio_start_priv = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -08001146 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1147 }
1148 pthread_mutex_unlock(&avsync->lock);
1149 }
1150}
1151
1152avs_start_ret av_sync_audio_start(
1153 void *sync,
1154 pts90K pts,
1155 pts90K delay,
1156 audio_start_cb cb,
1157 void *priv)
1158{
1159 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1160 uint32_t start_mode;
yongchun.li59e873d2021-07-07 11:42:38 -07001161 uint32_t systime;
Song Zhaoea5a0412021-01-18 16:40:08 -08001162 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1163 bool create_poll_t = false;
1164
1165 if (!avsync)
1166 return ret;
1167
yongchun.li59e873d2021-07-07 11:42:38 -07001168 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1169 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001170
yongchun.li59e873d2021-07-07 11:42:38 -07001171 if (avsync->in_audio_switch &&
1172 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1173 {
1174 start_mode = AVS_START_SYNC;
1175 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1176 } else {
1177 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1178 log_error("[%d]fail to set audio start", avsync->session_id);
1179 }
1180 if (avsync->in_audio_switch &&
1181 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1182 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
1183 msync_session_get_wall(avsync->fd, &systime, NULL);
1184 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB &&
1185 start_mode == AVS_START_SYNC) {
1186 log_info("%d audio_switch audio need drop first.ahead %d ms",
1187 avsync->session_id, (int)(systime - pts)/90);
1188 ret = AV_SYNC_ASTART_AGAIN;
1189 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1190 goto exit;
1191 }
1192 else {
1193 int diff = (int)(pts - systime);
1194 log_info("%d audio_switch_state to start mode %d diff %d ms",
1195 avsync->session_id, start_mode, diff/90);
1196 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
1197 if (diff < A_ADJ_THREDHOLD_LB) {
1198 log_info("%d orig mode %d already close enough direct start",
1199 avsync->session_id, start_mode);
1200 start_mode = AVS_START_SYNC;
1201 }
1202 }
yongchun.li107a6162021-05-05 02:38:57 -07001203 }
1204
Song Zhaoea5a0412021-01-18 16:40:08 -08001205 if (start_mode == AVS_START_SYNC) {
1206 ret = AV_SYNC_ASTART_SYNC;
1207 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001208 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001209 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001210 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001211 avsync->state = AV_SYNC_STAT_RUNNING;
1212 } else if (start_mode == AVS_START_AGAIN) {
1213 ret = AV_SYNC_ASTART_AGAIN;
1214 }
1215
1216 if (ret == AV_SYNC_ASTART_AGAIN)
1217 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001218
Song Zhao76005282022-03-08 16:49:41 -08001219 if (avsync->mode == AV_SYNC_MODE_AMASTER ||
1220 avsync->in_audio_switch || LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001221 create_poll_t = true;
Song Zhao76005282022-03-08 16:49:41 -08001222
1223 if (start_mode == AVS_START_ASYNC) {
1224 if (!cb) {
1225 log_error("[%d]invalid cb", avsync->session_id);
1226 return AV_SYNC_ASTART_ERR;
Song Zhaoea5a0412021-01-18 16:40:08 -08001227 }
Song Zhao76005282022-03-08 16:49:41 -08001228 avsync->audio_start = cb;
1229 avsync->audio_start_priv = priv;
1230 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001231
Song Zhaod62bb392021-04-23 12:25:49 -07001232 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001233 int ret;
1234
1235 log_info("[%d]start poll thread", avsync->session_id);
1236 avsync->quit_poll = false;
1237 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1238 if (ret) {
1239 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1240 return AV_SYNC_ASTART_ERR;
1241 }
1242 }
Song Zhaod62bb392021-04-23 12:25:49 -07001243 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001244 msync_session_get_wall(avsync->fd, &systime, NULL);
1245 log_info("[%d]return %u w %u pts %u d %u",
1246 avsync->session_id, ret, systime, pts, delay);
1247 }
1248exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001249 log_info("[%d]return %u", avsync->session_id, ret);
1250 return ret;
1251}
1252
1253int av_sync_audio_render(
1254 void *sync,
1255 pts90K pts,
1256 struct audio_policy *policy)
1257{
1258 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001259 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001260 uint32_t systime;
1261 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1262 avs_audio_action action = AA_SYNC_AA_MAX;
1263
1264 if (!avsync || !policy)
1265 return -1;
1266
yongchun.li107a6162021-05-05 02:38:57 -07001267 msync_session_get_wall(avsync->fd, &systime, NULL);
1268
1269 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1270 pts, systime, avsync->mode, (int)(pts-systime)/90);
1271
1272 if (avsync->in_audio_switch
1273 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
1274 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
1275 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1276 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1277 action = AV_SYNC_AA_RENDER;
1278 } else if ((int)(systime - pts) > 0) {
1279 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1280 (int)(systime - pts)/90, systime, pts);
1281 action = AV_SYNC_AA_DROP;
1282 } else {
1283 action = AV_SYNC_AA_INSERT;
1284 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1285 (int)(pts - systime)/90, systime, pts);
1286 }
1287 goto done;
1288 }
1289
Song Zhaoea5a0412021-01-18 16:40:08 -08001290 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1291 avsync->mode == AV_SYNC_MODE_AMASTER) {
1292 action = AV_SYNC_AA_RENDER;
1293 goto done;
1294 }
1295
Song Zhaod62bb392021-04-23 12:25:49 -07001296 /* stopping procedure, unblock audio rendering */
Song Zhao76005282022-03-08 16:49:41 -08001297 if (LIVE_MODE(avsync->mode) &&
Song Zhaod62bb392021-04-23 12:25:49 -07001298 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1299 action = AV_SYNC_AA_DROP;
1300 goto done;
1301 }
1302
Song Zhao7daf3a12021-05-10 22:22:25 -07001303 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1304 avsync->mode == AV_SYNC_MODE_AMASTER) {
1305 action = AV_SYNC_AA_RENDER;
1306 goto done;
1307 }
1308
Song Zhaod62bb392021-04-23 12:25:49 -07001309 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1310 LIVE_MODE(avsync->mode) &&
1311 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1312 /* outlier by stream error */
1313 avsync->outlier_cnt++;
1314 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1315 /* treat as disc, just drop current frame */
1316 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1317 avsync->outlier_cnt = 0;
1318 action = AV_SYNC_AA_DROP;
1319 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001320 goto done;
1321 }
1322 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1323 pts = systime;
1324 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001325 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001326 goto done;
1327 }
1328
1329 avsync->outlier_cnt = 0;
1330 /* low bound from sync_lost to sync_setup */
1331 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1332 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1333 action = AV_SYNC_AA_RENDER;
1334 goto done;
1335 }
1336
1337 /* high bound of sync_setup */
1338 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1339 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1340 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001341 action = AV_SYNC_AA_RENDER;
1342 goto done;
1343 }
1344
1345 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001346 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001347 action = AV_SYNC_AA_DROP;
1348 goto done;
1349 }
1350
1351 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001352 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001353 action = AV_SYNC_AA_INSERT;
1354 goto done;
1355 }
1356
1357done:
1358 policy->action = action;
1359 policy->delta = (int)(systime - pts);
1360 if (action == AV_SYNC_AA_RENDER) {
1361 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001362 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001363 if (!out_lier)
1364 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001365 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001366 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001367 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1368 msync_session_update_apts(avsync->fd, systime, pts, 0);
1369 log_info("[%d] audio switch done sys %u pts %u",
1370 avsync->session_id, systime, pts);
1371 msync_session_set_audio_switch(avsync->fd, false);
1372 avsync->in_audio_switch = false;
1373 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1374 } else {
1375 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1376 avsync->session_id, action, systime, pts, systime - pts);
1377 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001378 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001379 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001380 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001381 avsync->last_disc_pts != pts &&
1382 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001383 log_info ("[%d]audio disc %u --> %u",
1384 avsync->session_id, systime, pts);
1385 msync_session_set_audio_dis(avsync->fd, pts);
1386 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001387 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001388 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001389
1390 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001391 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001392 if (!avsync->audio_drop_cnt)
1393 avsync->audio_drop_start = now;
1394 avsync->audio_drop_cnt++;
1395 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1396 log_info ("[%d]audio keep dropping sys %u vs a %u",
1397 avsync->session_id, systime, pts);
1398 msync_session_set_audio_dis(avsync->fd, pts);
1399 }
Song Zhao409739b2021-05-12 22:21:40 -07001400 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001401 if (action != AV_SYNC_AA_DROP)
1402 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001403 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001404 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001405 }
1406
1407 return ret;
1408}
1409
1410int av_sync_get_clock(void *sync, pts90K *pts)
1411{
1412 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1413
1414 if (!avsync || !pts)
1415 return -1;
1416 return msync_session_get_wall(avsync->fd, pts, NULL);
1417}
1418
1419static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001420 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001421 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001422{
Song Zhao76005282022-03-08 16:49:41 -08001423 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d stat %d",
1424 avsync->session_id, avsync->active_mode, avsync->mode,
1425 v_active, a_active, v_timeout, stat);
1426
1427 /* iptv delayed start */
1428 if (avsync->mode == AV_SYNC_MODE_IPTV && avsync->audio_start)
1429 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
1430
Song Zhaoea5a0412021-01-18 16:40:08 -08001431 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1432 float speed;
1433 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaoe208d692021-04-19 15:38:52 -07001434 a_active && avsync->audio_start) {
Song Zhao76005282022-03-08 16:49:41 -08001435 if (v_active || v_timeout || avsync->in_audio_switch)
Song Zhaoe208d692021-04-19 15:38:52 -07001436 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
Song Zhaoea5a0412021-01-18 16:40:08 -08001437 }
1438
1439 if (!msync_session_get_rate(avsync->fd, &speed)) {
1440 /* speed change is triggered by asink,
1441 * attached audio HAL will handle it
1442 */
1443 if (speed != avsync->speed)
1444 log_info("[%d]new rate %f", avsync->session_id, speed);
1445 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001446 if (avsync->mode != avsync->backup_mode) {
1447 avsync->mode = avsync->backup_mode;
1448 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1449 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001450 } else {
1451 avsync->backup_mode = avsync->mode;
1452 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1453 log_info("[%d]audio to freerun mode", avsync->session_id);
1454 }
1455 avsync->speed = speed;
1456 }
Song Zhaod62bb392021-04-23 12:25:49 -07001457 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1458 struct session_debug debug;
1459 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001460 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001461 avsync->backup_mode = avsync->mode;
1462 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001463 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001464 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001465 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001466 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001467 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001468 log_warn("[%d]audio back to mode %d",
1469 avsync->session_id, avsync->mode);
1470 }
1471 }
Song Zhao76005282022-03-08 16:49:41 -08001472 } else if (avsync->active_mode == AV_SYNC_MODE_VMASTER) {
1473 log_info("[%d]running in vmaster mode", avsync->session_id);
Song Zhaoea5a0412021-01-18 16:40:08 -08001474 }
1475}
1476
1477static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhao76005282022-03-08 16:49:41 -08001478 enum internal_sync_stat stat,
Song Zhaoe208d692021-04-19 15:38:52 -07001479 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001480{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001481 struct session_debug debug;
1482
Song Zhao76005282022-03-08 16:49:41 -08001483 log_info("[%d]av_sync amode mode %d %d v/a %d/%d stat %d", avsync->session_id,
1484 avsync->active_mode, avsync->mode, v_active, a_active, stat);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001485 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1486 if (debug.debug_freerun && !avsync->debug_freerun) {
1487 avsync->backup_mode = avsync->mode;
1488 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1489 avsync->debug_freerun = true;
1490 log_warn("[%d]video to freerun mode", avsync->session_id);
1491 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1492 avsync->mode = avsync->backup_mode;
1493 avsync->debug_freerun = false;
1494 log_warn("[%d]video back to mode %d",
1495 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001496 }
1497 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001498}
1499
1500static void * poll_thread(void * arg)
1501{
1502 int ret = 0;
1503 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1504 const int fd = avsync->fd;
1505 struct pollfd pfd = {
1506 /* default blocking capture */
1507 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1508 .fd = avsync->fd,
1509 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001510 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001511
1512 prctl (PR_SET_NAME, "avs_poll");
1513 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001514
1515 if (avsync->type == AV_SYNC_TYPE_AUDIO)
1516 sflag = SRC_A;
1517 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
1518 sflag = SRC_V;
1519
Song Zhaoea5a0412021-01-18 16:40:08 -08001520 while (!avsync->quit_poll) {
1521 for (;;) {
1522 ret = poll(&pfd, 1, 10);
1523 if (ret > 0)
1524 break;
1525 if (avsync->quit_poll)
1526 goto exit;
1527 if (errno == EINTR)
1528 continue;
1529 }
1530
1531 /* error handling */
1532 if (pfd.revents & POLLERR)
1533 log_error("[%d]POLLERR received", avsync->session_id);
1534
Song Zhaod62bb392021-04-23 12:25:49 -07001535 /* mode change. Non-exclusive wait so all the processes
1536 * shall be woken up
1537 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001538 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001539 bool v_active, a_active, v_timeout;
Song Zhao76005282022-03-08 16:49:41 -08001540 enum internal_sync_stat stat;
Song Zhaoea5a0412021-01-18 16:40:08 -08001541
Song Zhao76005282022-03-08 16:49:41 -08001542 msync_session_get_stat(fd, &avsync->active_mode, &stat,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001543 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001544
1545 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhao76005282022-03-08 16:49:41 -08001546 handle_mode_change_a(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001547 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhao76005282022-03-08 16:49:41 -08001548 handle_mode_change_v(avsync, stat, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001549 usleep(10000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001550 }
1551 }
1552exit:
1553 log_info("[%d]quit", avsync->session_id);
1554 return NULL;
1555}
1556
Song Zhao623e2f12021-09-03 15:54:04 -07001557#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1558/* return ppm between demod and PCR clock */
1559int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1560{
1561 int fd = -1, ppm = 0, nread;
1562 char buf[128];
1563 uint32_t reg_v, lock;
1564 float val;
1565
1566 fd = open(DEMOD_NODE, O_RDWR);
1567 if (fd < 0) {
1568 log_warn("node not found %s", DEMOD_NODE);
1569 /* do not retry */
1570 avsync->ppm_adjusted = true;
1571 return 0;
1572 }
1573 snprintf(buf, sizeof(buf), "%d", 5);
1574 write(fd, buf, 2);
1575
1576 lseek(fd, 0, SEEK_SET);
1577
1578 nread = read(fd, buf, sizeof(buf));
1579 if (nread <= 0) {
1580 log_error("read error");
1581 goto err;
1582 }
1583 buf[nread] = 0;
1584 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1585 log_error("wrong format %s", buf);
1586 goto err;
1587 }
1588 if (lock != 0x1f) {
1589 log_info("demod not locked");
1590 goto err;
1591 }
1592 if (reg_v > ((2 << 20) - 1))
1593 reg_v -= (2 << 21);
1594 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1595 ppm = val;
1596 log_info("ppm from SFO %d", ppm);
1597 avsync->ppm_adjusted = true;
1598
1599err:
1600 if (fd >= 0)
1601 close(fd);
1602 return ppm;
1603}
1604
Song Zhaod62bb392021-04-23 12:25:49 -07001605int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001606{
1607 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001608 struct pcr_info pcr;
1609 enum pcr_monitor_status status;
1610 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001611 if (!avsync)
1612 return -1;
1613
1614 if (avsync->type != AV_SYNC_TYPE_PCR)
1615 return -2;
1616
Song Zhao623e2f12021-09-03 15:54:04 -07001617 /* initial estimation from Demod SFO HW */
1618 if (!avsync->ppm_adjusted) {
1619 ppm = dmod_get_sfo_dev(avsync);
1620 if (ppm != 0) {
1621 /* ppm > 0 means board clock is faster */
1622 msync_session_set_clock_dev(avsync->fd, -ppm);
1623 }
1624 }
wei.dubcc2ed22021-05-19 07:16:10 -04001625 pcr.monoclk = mono_clock / 1000;
1626 pcr.pts = (long long) pts * 1000 / 90;
1627 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1628
1629 status = pcr_monitor_get_status(avsync->pcr_monitor);
1630
1631 if (status >= DEVIATION_READY) {
1632 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1633 if (avsync->ppm != ppm) {
1634 avsync->ppm = ppm;
1635 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1636 if (msync_session_set_clock_dev(avsync->fd, ppm))
1637 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001638 else
1639 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001640 }
1641 }
1642
Song Zhaod62bb392021-04-23 12:25:49 -07001643 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001644}
1645
Song Zhaod62bb392021-04-23 12:25:49 -07001646int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001647{
1648 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1649
1650 if (!avsync)
1651 return -1;
1652
Song Zhaod62bb392021-04-23 12:25:49 -07001653 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001654}
1655
1656int av_sync_set_session_name(void *sync, const char *name)
1657{
1658 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1659
1660 if (!avsync)
1661 return -1;
1662
1663 return msync_session_set_name(avsync->fd, name);
1664}
yongchun.li107a6162021-05-05 02:38:57 -07001665
1666int av_sync_set_audio_switch(void *sync, bool start)
1667{
1668 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1669 bool v_active, a_active, v_timeout;
1670
1671 if (!avsync)
1672 return -1;
Song Zhao76005282022-03-08 16:49:41 -08001673 if (msync_session_get_stat(avsync->fd, &avsync->active_mode, NULL,
yongchun.li107a6162021-05-05 02:38:57 -07001674 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001675 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001676 log_error("[%d] can not get session state",
1677 avsync->session_id);
1678 return -1;
1679 }
1680 if (!v_active || !a_active) {
1681 log_error("[%d] no apply if not AV both active v %d a %d",
1682 avsync->session_id, v_active, a_active);
1683 return -1;
1684 }
1685 if (msync_session_set_audio_switch(avsync->fd, start)) {
1686 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1687 return -1;
1688 }
1689 avsync->in_audio_switch = start;
1690 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1691 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1692 return 0;
1693}
1694
1695int av_sync_get_audio_switch(void *sync, bool *start)
1696{
1697 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1698
1699 if (!avsync)
1700 return -1;
Song Zhao76005282022-03-08 16:49:41 -08001701 if (msync_session_get_stat(avsync->fd, &avsync->active_mode, NULL,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001702 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001703 log_error("[%d] can not audio seamless switch state",
1704 avsync->session_id);
1705 return -1;
1706 }
1707 if (start) *start = avsync->in_audio_switch;
1708 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001709}
Song Zhao8039f562021-05-18 18:11:25 -07001710
Song Zhao623e2f12021-09-03 15:54:04 -07001711enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001712{
1713 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1714
wei.dubcc2ed22021-05-19 07:16:10 -04001715 if (!avsync || !ppm)
1716 return CLK_RECOVERY_ERR;
1717 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001718 return CLK_RECOVERY_NOT_RUNNING;
1719
wei.dubcc2ed22021-05-19 07:16:10 -04001720 if (msync_session_get_clock_dev(avsync->fd, ppm))
1721 return CLK_RECOVERY_ERR;
1722
1723 if (*ppm == 0)
1724 return CLK_RECOVERY_ONGOING;
1725 else
1726 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001727}
Song Zhao95bd0922021-09-21 14:07:46 -07001728
1729static int video_mono_push_frame(struct av_sync_session *avsync, struct vframe *frame)
1730{
1731 int ret;
1732
1733 if (!avsync->frame_q) {
1734 avsync->frame_q = create_q(MAX_FRAME_NUM);
1735 if (!avsync->frame_q) {
1736 log_error("[%d]create queue fail", avsync->session_id);
1737
1738 return -1;
1739 }
1740 }
1741
1742 ret = queue_item(avsync->frame_q, frame);
1743 if (ret)
1744 log_error("%s queue fail:%d", ret);
1745 log_debug("[%d]push %llu, QNum=%d", avsync->session_id, frame->mts, queue_size(avsync->frame_q));
1746 return ret;
1747}
1748
1749int av_sync_set_vsync_mono_time(void *sync , uint64_t msys)
1750{
1751 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1752
1753 if (!avsync)
1754 return -1;
1755 avsync->msys = msys;
1756 return 0;
1757}
1758
1759static struct vframe * video_mono_pop_frame(struct av_sync_session *avsync)
1760{
1761 struct vframe *frame = NULL, *enter_last_frame = NULL;
1762 uint64_t systime;
1763 int toggle_cnt = 0;
1764
1765 enter_last_frame = avsync->last_frame;
1766 systime = avsync->msys;
1767 log_debug("[%d]sys %llu", avsync->session_id, systime);
1768 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
1769 if (systime >= frame->mts) {
1770 log_debug("[%d]cur_f %llu expire", avsync->session_id, frame->mts);
1771 toggle_cnt++;
1772
1773 if (avsync->last_frame)
1774 avsync->last_holding_peroid = avsync->last_frame->hold_period;
1775
1776 dqueue_item(avsync->frame_q, (void **)&frame);
1777 if (avsync->last_frame) {
1778 /* free frame that are not for display */
1779 if (toggle_cnt > 1) {
1780 log_debug("[%d]free %llu cur %llu system %llu", avsync->session_id,
1781 avsync->last_frame->mts, frame->mts, systime);
1782 avsync->last_frame->free(avsync->last_frame);
1783 }
1784 } else {
1785 avsync->first_frame_toggled = true;
1786 log_info("[%d]first frame %llu", avsync->session_id, frame->mts);
1787 }
1788 avsync->last_frame = frame;
1789 } else
1790 break;
1791 }
1792
1793 if (avsync->last_frame) {
1794 if (enter_last_frame != avsync->last_frame)
1795 log_debug("[%d]pop %llu", avsync->session_id, avsync->last_frame->pts);
1796 log_trace("[%d]pop=%llu, system=%llu, diff %d(ms), QNum=%d", avsync->session_id,
1797 avsync->last_frame->mts,
1798 systime, (systime - avsync->last_frame->mts) / 1000000,
1799 queue_size(avsync->frame_q));
1800 } else
1801 if (enter_last_frame != avsync->last_frame)
1802 log_debug("[%d]pop (nil)", avsync->session_id);
1803
1804 if (avsync->last_frame)
1805 avsync->last_frame->hold_period++;
1806 return avsync->last_frame;
1807}