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