blob: b7aae7c351b59225202597c98a80ae695f1f894d [file] [log] [blame]
Song Zhaoc03ba122020-12-23 21:54:02 -08001/*
2 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
3 *
4 * This source code is subject to the terms and conditions defined in the
5 * file 'LICENSE' which is part of this source code package.
6 *
7 * Description:
8 */
Song Zhaoea5a0412021-01-18 16:40:08 -08009#include <errno.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080010#include <pthread.h>
11#include <stdbool.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <sys/time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080015#include <poll.h>
16#include <fcntl.h>
17#include <sys/types.h>
18#include <sys/stat.h>
19#include <sys/prctl.h>
20#include <sys/ioctl.h>
Song Zhaoa2985cb2021-06-24 12:01:47 -070021#include <time.h>
Song Zhaoea5a0412021-01-18 16:40:08 -080022#include <unistd.h>
23//#include <linux/amlogic/msync.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080024#include "aml_avsync.h"
25#include "queue.h"
26#include "pattern.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080027#include "aml_avsync_log.h"
Song Zhaoea5a0412021-01-18 16:40:08 -080028#include "msync_util.h"
29#include "msync.h"
30#include <pthread.h>
wei.dubcc2ed22021-05-19 07:16:10 -040031#include "pcr_monitor.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080032enum sync_state {
33 AV_SYNC_STAT_INIT = 0,
34 AV_SYNC_STAT_RUNNING = 1,
35 AV_SYNC_STAT_SYNC_SETUP = 2,
36 AV_SYNC_STAT_SYNC_LOST = 3,
37};
38
yongchun.li107a6162021-05-05 02:38:57 -070039enum audio_switch_state_ {
40 AUDIO_SWITCH_STAT_INIT = 0,
41 AUDIO_SWITCH_STAT_RESET = 1,
42 AUDIO_SWITCH_STAT_START = 2,
43 AUDIO_SWITCH_STAT_FINISH = 3,
yongchun.li59e873d2021-07-07 11:42:38 -070044 AUDIO_SWITCH_STAT_AGAIN = 4,
yongchun.li107a6162021-05-05 02:38:57 -070045};
46
Song Zhaoea5a0412021-01-18 16:40:08 -080047#define SESSION_DEV "avsync_s"
48
Song Zhaoc03ba122020-12-23 21:54:02 -080049struct av_sync_session {
50 /* session id attached */
51 int session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -080052 int fd;
53 bool attached;
54 enum sync_mode mode;
55 /* for audio trickplay */
56 enum sync_mode backup_mode;
57 enum sync_type type;
58 uint32_t start_policy;
bo.xiao5821fc72021-07-11 22:47:00 -040059 int timeout;
Song Zhaoc03ba122020-12-23 21:54:02 -080060
Song Zhaoea5a0412021-01-18 16:40:08 -080061 /* playback time, will stop increasing during pause */
62 pts90K vpts;
63 pts90K apts;
64
65 /* phase adjustment of stream time for rate control (Video ONLY) */
Song Zhaoc03ba122020-12-23 21:54:02 -080066 pts90K phase;
67 bool phase_set;
68
69 /* pts of last rendered frame */
Song Zhaoea5a0412021-01-18 16:40:08 -080070 pts90K last_wall;
Song Zhaoc03ba122020-12-23 21:54:02 -080071 pts90K last_pts;
72 struct vframe *last_frame;
73
Song Zhaoe0bf6ad2021-07-09 11:28:42 -070074 /* pts of last pushed frame */
75 pts90K last_q_pts;
76
Song Zhaoc03ba122020-12-23 21:54:02 -080077 bool first_frame_toggled;
Song Zhaoc03ba122020-12-23 21:54:02 -080078 bool paused;
Song Zhaoea5a0412021-01-18 16:40:08 -080079 enum sync_state state;
Song Zhaoc03ba122020-12-23 21:54:02 -080080 void *pattern_detector;
81 void *frame_q;
Song Zhaoc03ba122020-12-23 21:54:02 -080082
Song Zhaoea5a0412021-01-18 16:40:08 -080083 /* start control */
84 int start_thres;
85 audio_start_cb audio_start;
86 void *audio_start_priv;
87
88 /* render property */
Song Zhaoc03ba122020-12-23 21:54:02 -080089 int delay;
90 pts90K vsync_interval;
91
92 /* state lock */
93 pthread_mutex_t lock;
94 /* pattern */
95 int last_holding_peroid;
Song Zhaoea5a0412021-01-18 16:40:08 -080096 bool session_started;
Song Zhaoc03ba122020-12-23 21:54:02 -080097
98 float speed;
99
Song Zhaoc03ba122020-12-23 21:54:02 -0800100 /* pause pts */
101 pts90K pause_pts;
102 pause_pts_done pause_pts_cb;
103 void *pause_cb_priv;
Song Zhao5d2b4772021-01-18 16:40:08 -0800104
105 /* log control */
Song Zhaoa2985cb2021-06-24 12:01:47 -0700106 uint32_t last_log_syst;
Song Zhao5d2b4772021-01-18 16:40:08 -0800107 uint32_t sync_lost_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700108 struct timespec sync_lost_print_time;
Song Zhaoea5a0412021-01-18 16:40:08 -0800109
110 pthread_t poll_thread;
111 /* pcr master, IPTV only */
112 bool quit_poll;
113 enum sync_mode active_mode;
Song Zhaof46932e2021-05-21 01:51:45 -0700114 uint32_t disc_thres_min;
115 uint32_t disc_thres_max;
Song Zhao35a82df2021-04-15 10:58:49 -0700116
117 /* error detection */
118 uint32_t last_poptime;
Song Zhaod62bb392021-04-23 12:25:49 -0700119 uint32_t outlier_cnt;
Song Zhao409739b2021-05-12 22:21:40 -0700120 pts90K last_disc_pts;
121
yongchun.li107a6162021-05-05 02:38:57 -0700122 // indicate set audio switch
123 bool in_audio_switch;
124 enum audio_switch_state_ audio_switch_state;
wei.dubcc2ed22021-05-19 07:16:10 -0400125
126 //pcr monitor handle
127 void *pcr_monitor;
128 int ppm;
Song Zhao623e2f12021-09-03 15:54:04 -0700129 bool ppm_adjusted;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700130
131 //video FPS detection
132 pts90K last_fpts;
133 int fps_interval;
134 int fps_interval_acc;
135 int fps_cnt;
136
137 //video freerun with rate control
138 uint32_t last_r_syst;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700139 bool debug_freerun;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700140
141 //Audio dropping detection
142 uint32_t audio_drop_cnt;
yongchun.li0ee6e372021-08-20 04:26:04 -0700143 struct timespec audio_drop_start;
Song Zhaoc03ba122020-12-23 21:54:02 -0800144};
145
146#define MAX_FRAME_NUM 32
147#define DEFAULT_START_THRESHOLD 2
148#define TIME_UNIT90K (90000)
Song Zhaof46932e2021-05-21 01:51:45 -0700149#define AV_DISC_THRES_MIN (TIME_UNIT90K / 3)
150#define AV_DISC_THRES_MAX (TIME_UNIT90K * 10)
Song Zhao7daf3a12021-05-10 22:22:25 -0700151#define A_ADJ_THREDHOLD_HB (900 * 6) //60ms
152#define A_ADJ_THREDHOLD_LB (900 * 2) //20ms
Song Zhao52f55192021-05-06 10:52:21 -0700153#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800154#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhaod62bb392021-04-23 12:25:49 -0700155#define LIVE_MODE(mode) ((mode) == AV_SYNC_MODE_PCR_MASTER || (mode) == AV_SYNC_MODE_IPTV)
156
Song Zhao065800e2021-05-26 15:56:06 -0700157#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
Song Zhaod62bb392021-04-23 12:25:49 -0700158#define OUTLIER_MAX_CNT 8
Song Zhaoa2985cb2021-06-24 12:01:47 -0700159#define VALID_TS(x) ((x) != -1)
Song Zhaoc03ba122020-12-23 21:54:02 -0800160
yongchun.li0ee6e372021-08-20 04:26:04 -0700161static uint64_t time_diff (struct timespec *b, struct timespec *a);
Song Zhaoc03ba122020-12-23 21:54:02 -0800162static bool frame_expire(struct av_sync_session* avsync,
163 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800164 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800165 struct vframe * frame,
166 struct vframe * next_frame,
167 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700168static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800169 int cur_period,
170 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800171static void * poll_thread(void * arg);
172static void trigger_audio_start_cb(struct av_sync_session *avsync,
173 avs_ascb_reason reason);
Song Zhaoc03ba122020-12-23 21:54:02 -0800174
Song Zhaoea5a0412021-01-18 16:40:08 -0800175int av_sync_open_session(int *session_id)
176{
177 int fd = msync_create_session();
178 int id, rc;
179
180 if (fd < 0) {
181 log_error("fail");
182 return -1;
183 }
184 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
185 if (rc) {
186 log_error("new session errno:%d", errno);
187 return rc;
188 }
189 *session_id = id;
190 return fd;
191}
192
193void av_sync_close_session(int session)
194{
195 msync_destory_session(session);
196}
197
198static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800199 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800200 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800201 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800202 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800203{
204 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800205 char dev_name[20];
Song Zhaoc03ba122020-12-23 21:54:02 -0800206
207 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
208 if (!avsync) {
209 log_error("OOM");
210 return NULL;
211 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800212
213 if (type == AV_SYNC_TYPE_VIDEO) {
214 avsync->pattern_detector = create_pattern_detector();
215 if (!avsync->pattern_detector) {
216 log_error("pd create fail");
217 goto err;
218 }
219
220 if (!start_thres)
221 avsync->start_thres = DEFAULT_START_THRESHOLD;
222 else {
223 if (start_thres > 5) {
224 log_error("start_thres too big: %d", start_thres);
225 goto err2;
226 }
227 avsync->start_thres = start_thres;
228 }
229 avsync->phase_set = false;
230 avsync->first_frame_toggled = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800231 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800232
233 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800234 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800235 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800236 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800237 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800238 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800239 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800240 avsync->speed = 1.0f;
241 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhao409739b2021-05-12 22:21:40 -0700242 avsync->vsync_interval = -1;
243 avsync->last_disc_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700244 avsync->last_log_syst = -1;
245 avsync->last_pts = -1;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700246 avsync->last_q_pts = -1;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700247 avsync->last_wall = -1;
248 avsync->fps_interval = -1;
249 avsync->last_r_syst = -1;
bo.xiao5821fc72021-07-11 22:47:00 -0400250 avsync->timeout = -1;
251
Song Zhaof46932e2021-05-21 01:51:45 -0700252 if (msync_session_get_disc_thres(session_id,
253 &avsync->disc_thres_min, &avsync->disc_thres_max)) {
254 log_error("fail to get disc thres", dev_name, errno);
255 avsync->disc_thres_min = AV_DISC_THRES_MIN;
256 avsync->disc_thres_max = AV_DISC_THRES_MAX;
257 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800258
259 pthread_mutex_init(&avsync->lock, NULL);
Song Zhaof46932e2021-05-21 01:51:45 -0700260 log_info("[%d] mode %d type %d start_thres %d disc_thres %u/%u",
261 session_id, mode, type, start_thres,
262 avsync->disc_thres_min, avsync->disc_thres_max);
Song Zhaoea5a0412021-01-18 16:40:08 -0800263
264 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
265 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
266 if (avsync->fd < 0) {
267 log_error("open %s errno %d", dev_name, errno);
268 goto err2;
269 }
270
wei.dubcc2ed22021-05-19 07:16:10 -0400271 if (avsync->type == AV_SYNC_TYPE_PCR) {
272 if (pcr_monitor_init(&avsync->pcr_monitor)) {
273 log_error("pcr monitor init");
Song Zhao9cd27a52021-07-26 15:27:38 +0000274 goto err3;
wei.dubcc2ed22021-05-19 07:16:10 -0400275 }
276 }
277
Song Zhaoea5a0412021-01-18 16:40:08 -0800278 if (!attach) {
279 msync_session_set_mode(avsync->fd, mode);
280 avsync->mode = mode;
281 } else {
282 avsync->attached = true;
283 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
284 log_error("get mode");
Song Zhao9cd27a52021-07-26 15:27:38 +0000285 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800286 }
287 avsync->backup_mode = avsync->mode;
bo.xiao5821fc72021-07-11 22:47:00 -0400288 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800289 log_error("get policy");
Song Zhao9cd27a52021-07-26 15:27:38 +0000290 goto err4;
Song Zhaoea5a0412021-01-18 16:40:08 -0800291 }
yongchun.li107a6162021-05-05 02:38:57 -0700292 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700293 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -0700294 log_error("get state");
Song Zhao9cd27a52021-07-26 15:27:38 +0000295 goto err4;
yongchun.li107a6162021-05-05 02:38:57 -0700296 }
297 if (avsync->in_audio_switch) {
298 log_info("audio_switch_state reseted the audio");
299 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
300 }
301
Song Zhaoea5a0412021-01-18 16:40:08 -0800302 log_info("[%d]retrieve sync mode %d policy %d",
303 session_id, avsync->mode, avsync->start_policy);
304 }
305
Song Zhao67c937b2021-10-01 11:21:32 -0700306 /* debug log level */
307 {
308 const char *env= getenv( "AML_AVSYNC_DEBUG_LEVEL");
309 if ( env ) {
310 log_set_level(atoi(env));
311 }
312 }
313
Song Zhaoc03ba122020-12-23 21:54:02 -0800314 return avsync;
Song Zhao9cd27a52021-07-26 15:27:38 +0000315err4:
wei.dubcc2ed22021-05-19 07:16:10 -0400316 if (avsync->pcr_monitor)
317 pcr_monitor_destroy(avsync->pcr_monitor);
Song Zhao9cd27a52021-07-26 15:27:38 +0000318err3:
319 close(avsync->fd);
Song Zhaoea5a0412021-01-18 16:40:08 -0800320err2:
321 destroy_pattern_detector(avsync->pattern_detector);
322err:
323 free(avsync);
324 return NULL;
325}
326
327void* av_sync_create(int session_id,
328 enum sync_mode mode,
329 enum sync_type type,
330 int start_thres)
331{
332 return create_internal(session_id, mode,
333 type, start_thres, false);
334}
335
336void* av_sync_attach(int session_id, enum sync_type type)
337{
338 return create_internal(session_id, AV_SYNC_MODE_MAX,
339 type, 0, true);
340}
341
342int av_sync_video_config(void *sync, struct video_config* config)
343{
344 struct av_sync_session *avsync = (struct av_sync_session *)sync;
345
346 if (!avsync || !config)
347 return -1;
348
349 if (config->delay != 1 && config->delay != 2) {
350 log_error("invalid delay: %d\n", config->delay);
351 return -1;
352 }
353
354 avsync->delay = config->delay;
355
356 log_info("[%d] delay: %d",
357 avsync->session_id, config->delay);
358 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800359}
360
361static int internal_stop(struct av_sync_session *avsync)
362{
363 int ret = 0;
364 struct vframe *frame;
365
366 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800367 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
368 frame->free(frame);
369 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800370 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800371 pthread_mutex_unlock(&avsync->lock);
372 return ret;
373}
374
375/* destroy and detach from kernel session */
376void av_sync_destroy(void *sync)
377{
378 struct av_sync_session *avsync = (struct av_sync_session *)sync;
379
380 if (!avsync)
381 return;
382
Song Zhaoea5a0412021-01-18 16:40:08 -0800383 log_info("[%d]begin", avsync->session_id);
384 if (avsync->state != AV_SYNC_STAT_INIT) {
385 if (avsync->type == AV_SYNC_TYPE_VIDEO)
386 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800387
Song Zhaoea5a0412021-01-18 16:40:08 -0800388 avsync->quit_poll = true;
389 if (avsync->poll_thread) {
390 pthread_join(avsync->poll_thread, NULL);
391 avsync->poll_thread = 0;
392 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700393 if (avsync->type == AV_SYNC_TYPE_AUDIO)
394 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoaf368d52021-02-17 17:53:45 -0800395 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800396
Song Zhaoea5a0412021-01-18 16:40:08 -0800397 if (avsync->session_started) {
398 if (avsync->type == AV_SYNC_TYPE_VIDEO)
399 msync_session_set_video_stop(avsync->fd);
400 else
401 msync_session_set_audio_stop(avsync->fd);
402 }
wei.dubcc2ed22021-05-19 07:16:10 -0400403
404 if(avsync->pcr_monitor)
405 pcr_monitor_destroy(avsync->pcr_monitor);
406
Song Zhaoea5a0412021-01-18 16:40:08 -0800407 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800408 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800409 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
410 destroy_q(avsync->frame_q);
411 destroy_pattern_detector(avsync->pattern_detector);
412 }
413 log_info("[%d]done", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800414 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800415}
416
bo.xiao5821fc72021-07-11 22:47:00 -0400417int avs_sync_set_start_policy(void *sync, struct start_policy* st_policy)
Song Zhaoea5a0412021-01-18 16:40:08 -0800418{
419 struct av_sync_session *avsync = (struct av_sync_session *)sync;
420
421 if (!avsync || !avsync->fd)
422 return -1;
423
bo.xiao5821fc72021-07-11 22:47:00 -0400424 log_info("[%d]policy %u --> %u, timeout %d --> %d", avsync->start_policy, st_policy->policy, avsync->timeout, st_policy->timeout);
425 avsync->start_policy = st_policy->policy;
426 avsync->timeout = st_policy->timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800427 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400428 if (st_policy->policy != AV_SYNC_START_NONE &&
429 st_policy->policy != AV_SYNC_START_V_PEEK)
430 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800431
432 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800433}
434
435int av_sync_pause(void *sync, bool pause)
436{
437 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700438 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800439 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800440
441 if (!avsync)
442 return -1;
443
Song Zhaoea5a0412021-01-18 16:40:08 -0800444 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
445 return -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800446
yongchun.li107a6162021-05-05 02:38:57 -0700447 rc = msync_session_get_stat(avsync->fd, &avsync->active_mode,
448 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700449 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700450
yongchun.li5f52fb02021-06-04 18:13:05 -0700451 /* ignore only when video try to pause when audio is acive, on which
452 the control of the STC will be relays.
453 When resume,it can do always as it is possible that video just
454 paused earlier without audio yet,then audio added later before resume.
455 We shall not igore that otherwise it could cause video freeze. */
456 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
457 avsync->type == AV_SYNC_TYPE_VIDEO &&
458 a_active &&
459 !avsync->in_audio_switch) {
460 if (!pause) {
461 log_info("[%d] clear video pause when audio active",
462 avsync->session_id);
463 avsync->paused = pause;
464 } else {
465 log_info("[%d] ignore the pause from video when audio active",
466 avsync->session_id);
467 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800468 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700469 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800470
yongchun.li107a6162021-05-05 02:38:57 -0700471 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
472 log_info("[%d] ignore the pause from audio", avsync->session_id);
473 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
474 return 0;
475 }
476
Song Zhaoea5a0412021-01-18 16:40:08 -0800477 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800478 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800479 log_info("[%d]paused:%d type:%d rc %d",
480 avsync->session_id, pause, avsync->type, rc);
Song Zhaoc03ba122020-12-23 21:54:02 -0800481
Song Zhaoea5a0412021-01-18 16:40:08 -0800482 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800483}
484
485int av_sync_push_frame(void *sync , struct vframe *frame)
486{
487 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700488 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800489 struct av_sync_session *avsync = (struct av_sync_session *)sync;
490
491 if (!avsync)
492 return -1;
493
Song Zhaoea5a0412021-01-18 16:40:08 -0800494 if (!avsync->frame_q) {
495 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400496 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800497 log_error("[%d]get policy", avsync->session_id);
498 return -1;
499 }
500
501 avsync->frame_q = create_q(MAX_FRAME_NUM);
502 if (!avsync->frame_q) {
503 log_error("[%d]create queue fail", avsync->session_id);
yongchun.li0ee6e372021-08-20 04:26:04 -0700504
Song Zhaoea5a0412021-01-18 16:40:08 -0800505 return -1;
506 }
507
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700508 /* for debugging */
509 {
Song Zhaoea5a0412021-01-18 16:40:08 -0800510 int ret;
511
512 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
513 if (ret) {
514 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
515 destroy_q(avsync->frame_q);
516 return -1;
517 }
518 }
519 }
520
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700521 if (avsync->last_q_pts != -1) {
522 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
523 /* TODO: wrong, should remove from back of queue */
Song Zhaoc03ba122020-12-23 21:54:02 -0800524 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700525 if (prev) {
526 prev->free(prev);
527 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
528 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700529 } else if (avsync->fps_cnt < 100) {
530 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700531
532 if (interval > 0 && interval <= 4500) {
533 if (avsync->fps_interval_acc == -1) {
534 avsync->fps_interval_acc = interval;
535 avsync->fps_cnt = 1;
536 } else {
537 avsync->fps_interval_acc += interval;
538 avsync->fps_cnt++;
539 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
540 if (avsync->fps_cnt == 100)
541 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
542 }
543 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800544 }
545 }
546
Song Zhao065800e2021-05-26 15:56:06 -0700547 if (frame->duration == -1)
548 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800549 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700550 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800551 ret = queue_item(avsync->frame_q, frame);
552 if (avsync->state == AV_SYNC_STAT_INIT &&
553 queue_size(avsync->frame_q) >= avsync->start_thres) {
554 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaoea5a0412021-01-18 16:40:08 -0800555 log_info("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800556 }
557
558 if (ret)
559 log_error("%s queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400560 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800561 return ret;
562
563}
564
565struct vframe *av_sync_pop_frame(void *sync)
566{
Song Zhaoea5a0412021-01-18 16:40:08 -0800567 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800568 struct av_sync_session *avsync = (struct av_sync_session *)sync;
569 int toggle_cnt = 0;
570 uint32_t systime;
Song Zhao468fd652021-01-15 22:13:04 -0800571 bool pause_pts_reached = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800572 uint32_t interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800573
574 pthread_mutex_lock(&avsync->lock);
575 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhaod62bb392021-04-23 12:25:49 -0700576 log_info("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800577 goto exit;
578 }
579
Song Zhaoea5a0412021-01-18 16:40:08 -0800580 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700581 uint32_t pts;
582
Song Zhaoc03ba122020-12-23 21:54:02 -0800583 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800584 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800585 goto exit;
586 }
Song Zhao35a82df2021-04-15 10:58:49 -0700587 msync_session_get_wall(avsync->fd, &systime, &interval);
588 pts = frame->pts - avsync->delay * interval;
589 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800590 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700591 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800592 }
593
Song Zhaoea5a0412021-01-18 16:40:08 -0800594 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700595 !avsync->first_frame_toggled &&
596 !msync_clock_started(avsync->fd)) {
597 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800598 log_trace("[%d]clock not started", avsync->session_id);
599 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800600 }
601
Song Zhaoea5a0412021-01-18 16:40:08 -0800602 enter_last_frame = avsync->last_frame;
603 msync_session_get_wall(avsync->fd, &systime, &interval);
604
605 /* handle refresh rate change */
606 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
607 avsync->vsync_interval != interval) {
608 log_info("[%d]vsync interval update %d --> %u",
609 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700610 if (avsync->fps_interval == -1)
611 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800612 avsync->vsync_interval = interval;
613 avsync->phase_set = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700614 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800615 reset_pattern(avsync->pattern_detector);
616 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800617 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
618 struct vframe *next_frame = NULL;
619
620 peek_item(avsync->frame_q, (void **)&next_frame, 1);
621 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700622 log_debug("[%d]cur_f %u next_f %u size %d",
623 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800624 if (frame_expire(avsync, systime, interval,
625 frame, next_frame, toggle_cnt)) {
626 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800627 toggle_cnt++;
628
Song Zhao35a82df2021-04-15 10:58:49 -0700629 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800630 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao67c937b2021-10-01 11:21:32 -0700631 avsync->last_holding_peroid)) {
Song Zhao35a82df2021-04-15 10:58:49 -0700632 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
Song Zhao67c937b2021-10-01 11:21:32 -0700633 log_info("[%d] cur frame %u sys %u", avsync->session_id, frame->pts, systime);
634 if (next_frame)
635 log_info("[%d] next frame %u", avsync->session_id, next_frame->pts);
636 }
Song Zhao35a82df2021-04-15 10:58:49 -0700637
Song Zhaoc03ba122020-12-23 21:54:02 -0800638 if (avsync->last_frame)
639 avsync->last_holding_peroid = avsync->last_frame->hold_period;
640
641 dqueue_item(avsync->frame_q, (void **)&frame);
642 if (avsync->last_frame) {
643 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800644 if (toggle_cnt > 1) {
Song Zhao35a82df2021-04-15 10:58:49 -0700645 log_debug("[%d]free %u cur %u system/d %u/%u", avsync->session_id,
646 avsync->last_frame->pts, frame->pts, systime, systime - avsync->last_poptime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800647 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800648 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800649 } else {
650 avsync->first_frame_toggled = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800651 log_info("[%d]first frame %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800652 }
653 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800654 avsync->last_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800655 } else
656 break;
657 }
658
659 /* pause pts */
660 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800661 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800662 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800663 else
Song Zhao468fd652021-01-15 22:13:04 -0800664 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
665 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
666 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
667 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
668 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800669
Song Zhao468fd652021-01-15 22:13:04 -0800670 if (pause_pts_reached) {
671 if (avsync->pause_pts_cb)
672 avsync->pause_pts_cb(avsync->pause_pts,
Song Zhaoc03ba122020-12-23 21:54:02 -0800673 avsync->pause_cb_priv);
674
Song Zhao468fd652021-01-15 22:13:04 -0800675 /* stay in paused until av_sync_pause(false) */
676 avsync->paused = true;
677 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoea5a0412021-01-18 16:40:08 -0800678 log_info ("[%d]reach pause pts: %u",
679 avsync->session_id, avsync->last_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800680 }
681
682exit:
683 pthread_mutex_unlock(&avsync->lock);
684 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800685 if (enter_last_frame != avsync->last_frame)
686 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
bo.xiao1f94b352021-08-02 03:53:47 -0400687 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 -0700688 /* don't update vpts for out_lier */
689 if (avsync->last_frame->duration != -1)
690 msync_session_update_vpts(avsync->fd, systime,
691 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800692 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800693 if (enter_last_frame != avsync->last_frame)
694 log_debug("[%d]pop (nil)", avsync->session_id);
695
Song Zhao35a82df2021-04-15 10:58:49 -0700696 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800697 if (avsync->last_frame)
698 avsync->last_frame->hold_period++;
699 return avsync->last_frame;
700}
701
Song Zhaoc03ba122020-12-23 21:54:02 -0800702static inline uint32_t abs_diff(uint32_t a, uint32_t b)
703{
Song Zhaoea5a0412021-01-18 16:40:08 -0800704 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800705}
706
yongchun.li0ee6e372021-08-20 04:26:04 -0700707static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800708{
yongchun.li0ee6e372021-08-20 04:26:04 -0700709 return (b->tv_sec - a->tv_sec)*1000000 + (b->tv_nsec/1000 - a->tv_nsec/1000);
Song Zhaoc03ba122020-12-23 21:54:02 -0800710}
711
Song Zhaoc03ba122020-12-23 21:54:02 -0800712static bool frame_expire(struct av_sync_session* avsync,
713 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800714 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800715 struct vframe * frame,
716 struct vframe * next_frame,
717 int toggle_cnt)
718{
719 uint32_t fpts = frame->pts;
720 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800721 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800722
723 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
724 return false;
725
726 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
727 return true;
728
fei.deng63e43e12021-09-23 19:44:01 +0800729 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
730 avsync->mode == AV_SYNC_MODE_VMASTER) {
731 /* We need to ensure that the video outputs smoothly,
732 so output video frame by frame hold_period */
733 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
734 avsync->last_frame &&
735 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
736 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
737 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700738 return true;
739 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700740 }
741
Song Zhaoc03ba122020-12-23 21:54:02 -0800742 if (!fpts) {
743 if (avsync->last_frame) {
744 /* try to accumulate duration as PTS */
745 fpts = avsync->vpts + avsync->last_frame->duration;
746 } else {
747 fpts = avsync->vpts;
748 }
749 }
750 systime += pts_correction;
751
752 /* phase adjustment */
753 if (avsync->phase_set)
754 systime += avsync->phase;
755
yongchun.lia50b1e92021-08-07 01:11:54 +0000756 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800757 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000758 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700759 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800760 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800761 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800762 return false;
763
Song Zhaoa2985cb2021-06-24 12:01:47 -0700764 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
765 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700766 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800767
yongchun.li0ee6e372021-08-20 04:26:04 -0700768 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700769 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800770 avsync->last_pts = fpts;
771 if (time_diff(&now, &avsync->sync_lost_print_time) >=
772 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700773 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800774 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800775 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700776 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800777 } else
778 avsync->sync_lost_cnt++;
779 }
Song Zhaod62bb392021-04-23 12:25:49 -0700780
781 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
782 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700783 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700784 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700785 /* outlier by stream error */
786 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700787 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700788 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
789 log_info("render outlier %u", fpts);
790 return true;
791 }
792 }
793
794 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800795 avsync->state = AV_SYNC_STAT_SYNC_LOST;
796 avsync->phase_set = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700797 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800798 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700799
800 if (LIVE_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700801 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700802 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700803 msync_session_set_video_dis(avsync->fd, fpts);
804 avsync->last_disc_pts = fpts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700805 }
806
807 if ((int)(systime - fpts) > 0) {
808 if ((int)(systime - fpts) < avsync->disc_thres_max) {
809 /* catch up PCR */
Song Zhaof46932e2021-05-21 01:51:45 -0700810 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700811 } else {
812 /* render according to FPS */
813 if (!VALID_TS(avsync->last_r_syst) ||
814 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
815 avsync->last_r_syst = systime;
816 return true;
817 }
818 return false;
819 }
820 } else if (LIVE_MODE(avsync->mode)) {
821 /* hold if the gap is small */
822 if ((int)(fpts - systime) < avsync->disc_thres_max) {
823 return false;
824 } else {
825 /* render according to FPS */
826 if (!VALID_TS(avsync->last_r_syst) ||
827 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
828 avsync->last_r_syst = systime;
829 return true;
830 }
831 return false;
832 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800833 }
834 }
835
Song Zhao52f55192021-05-06 10:52:21 -0700836 /* In some cases, keeping pattern will enlarge the gap */
837 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
838 avsync->first_frame_toggled) {
839 reset_pattern(avsync->pattern_detector);
Song Zhaof46932e2021-05-21 01:51:45 -0700840 log_warn("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700841 systime, fpts);
842 }
843
Song Zhaoc03ba122020-12-23 21:54:02 -0800844 expire = (int)(systime - fpts) >= 0;
845
846 /* scatter the frame in different vsync whenever possible */
847 if (expire && next_frame && next_frame->pts && toggle_cnt) {
848 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhaoea5a0412021-01-18 16:40:08 -0800849 if (systime + interval < next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800850 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800851 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
852 avsync->session_id, systime, interval, next_frame->pts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800853 }
854 } else if (!expire && next_frame && next_frame->pts && !toggle_cnt
855 && avsync->first_frame_toggled) {
856 /* next vsync will have at least 2 frame expired */
Song Zhao35a82df2021-04-15 10:58:49 -0700857 if (systime + interval >= next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800858 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800859 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
860 avsync->session_id, systime, interval, next_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800861 }
862 }
863
Song Zhaoa58c3e92021-03-09 18:52:55 -0800864 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
865 correct_pattern(avsync->pattern_detector, frame, next_frame,
866 (avsync->last_frame?avsync->last_frame->hold_period:0),
867 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800868 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -0800869
870 if (expire) {
871 avsync->vpts = fpts;
872 /* phase adjustment */
873 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +0000874 //always adjust to the half v-sync to give most pts tolerace and unify behavior
875 if ((int)(systime - fpts) >= 0 && (int)(fpts + interval - systime) > 0) {
876 avsync->phase = interval/2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800877 avsync->phase_set = true;
yongchun.lia50b1e92021-08-07 01:11:54 +0000878 log_info("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800879 }
880 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800881 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -0800882 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800883 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -0800884 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800885 }
886 return expire;
887}
888
Song Zhao35a82df2021-04-15 10:58:49 -0700889static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -0800890{
Song Zhao35a82df2021-04-15 10:58:49 -0700891 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800892 log_trace("[%d]cur_period: %d last_period: %d",
893 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -0700894 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
895 ret = true;
896 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
897 ret = true;
898 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
899 ret = true;
900 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
901 ret = true;
902
903 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800904}
905
906int av_sync_set_speed(void *sync, float speed)
907{
908 struct av_sync_session *avsync = (struct av_sync_session *)sync;
909
910 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800911 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800912 return -1;
913 }
914
Song Zhaoea5a0412021-01-18 16:40:08 -0800915 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
916 avsync->mode == AV_SYNC_MODE_IPTV) {
917 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800918 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800919 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800920
Song Zhaoea5a0412021-01-18 16:40:08 -0800921 avsync->speed = speed;
922
923 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
924 if (speed == 1.0) {
925 avsync->mode = avsync->backup_mode;
926 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
927 } else {
928 avsync->backup_mode = avsync->mode;
929 avsync->mode = AV_SYNC_MODE_FREE_RUN;
930 log_info("[%d]audio to freerun mode", avsync->session_id);
931 }
932 }
933#if 0
Song Zhaoc03ba122020-12-23 21:54:02 -0800934 if (avsync->mode != AV_SYNC_MODE_VMASTER) {
935 log_info("ignore set speed in mode %d", avsync->mode);
936 return 0;
937 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800938#endif
Song Zhaoc03ba122020-12-23 21:54:02 -0800939
Song Zhaoea5a0412021-01-18 16:40:08 -0800940 log_info("session[%d] set rate to %f", avsync->session_id, speed);
941 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800942}
943
944int av_sync_change_mode(void *sync, enum sync_mode mode)
945{
946 struct av_sync_session *avsync = (struct av_sync_session *)sync;
947
948 if (!avsync)
949 return -1;
950
Song Zhaoea5a0412021-01-18 16:40:08 -0800951 if (msync_session_set_mode(avsync->fd, mode)) {
952 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800953 return -1;
954 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800955 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -0800956 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800957 return 0;
958}
959
Song Zhao01031bb2021-05-13 21:23:20 -0700960int av_sync_get_mode(void *sync, enum sync_mode *mode)
961{
962 struct av_sync_session *avsync = (struct av_sync_session *)sync;
963
964 if (!avsync || !mode)
965 return -1;
966
967 *mode = avsync->mode;
968 return 0;
969}
970
Song Zhaoc03ba122020-12-23 21:54:02 -0800971int av_sync_set_pause_pts(void *sync, pts90K pts)
972{
973 struct av_sync_session *avsync = (struct av_sync_session *)sync;
974
975 if (!avsync)
976 return -1;
977
978 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -0800979 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800980 return 0;
981}
982
983int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
984{
985 struct av_sync_session *avsync = (struct av_sync_session *)sync;
986
987 if (!avsync)
988 return -1;
989
990 avsync->pause_pts_cb = cb;
991 avsync->pause_cb_priv = priv;
992 return 0;
993}
Song Zhaoea5a0412021-01-18 16:40:08 -0800994
995static void trigger_audio_start_cb(struct av_sync_session *avsync,
996 avs_ascb_reason reason)
997{
998 if (avsync) {
999 pthread_mutex_lock(&avsync->lock);
1000 if (avsync->audio_start) {
1001 avsync->audio_start(avsync->audio_start_priv, reason);
1002 avsync->session_started = true;
1003 avsync->audio_start = NULL;
1004 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1005 }
1006 pthread_mutex_unlock(&avsync->lock);
1007 }
1008}
1009
1010avs_start_ret av_sync_audio_start(
1011 void *sync,
1012 pts90K pts,
1013 pts90K delay,
1014 audio_start_cb cb,
1015 void *priv)
1016{
1017 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1018 uint32_t start_mode;
yongchun.li59e873d2021-07-07 11:42:38 -07001019 uint32_t systime;
Song Zhaoea5a0412021-01-18 16:40:08 -08001020 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1021 bool create_poll_t = false;
1022
1023 if (!avsync)
1024 return ret;
1025
yongchun.li59e873d2021-07-07 11:42:38 -07001026 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1027 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001028
yongchun.li59e873d2021-07-07 11:42:38 -07001029 if (avsync->in_audio_switch &&
1030 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1031 {
1032 start_mode = AVS_START_SYNC;
1033 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1034 } else {
1035 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1036 log_error("[%d]fail to set audio start", avsync->session_id);
1037 }
1038 if (avsync->in_audio_switch &&
1039 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1040 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
1041 msync_session_get_wall(avsync->fd, &systime, NULL);
1042 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB &&
1043 start_mode == AVS_START_SYNC) {
1044 log_info("%d audio_switch audio need drop first.ahead %d ms",
1045 avsync->session_id, (int)(systime - pts)/90);
1046 ret = AV_SYNC_ASTART_AGAIN;
1047 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1048 goto exit;
1049 }
1050 else {
1051 int diff = (int)(pts - systime);
1052 log_info("%d audio_switch_state to start mode %d diff %d ms",
1053 avsync->session_id, start_mode, diff/90);
1054 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
1055 if (diff < A_ADJ_THREDHOLD_LB) {
1056 log_info("%d orig mode %d already close enough direct start",
1057 avsync->session_id, start_mode);
1058 start_mode = AVS_START_SYNC;
1059 }
1060 }
yongchun.li107a6162021-05-05 02:38:57 -07001061 }
1062
Song Zhaoea5a0412021-01-18 16:40:08 -08001063 if (start_mode == AVS_START_SYNC) {
1064 ret = AV_SYNC_ASTART_SYNC;
1065 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001066 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001067 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001068 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001069 avsync->state = AV_SYNC_STAT_RUNNING;
1070 } else if (start_mode == AVS_START_AGAIN) {
1071 ret = AV_SYNC_ASTART_AGAIN;
1072 }
1073
1074 if (ret == AV_SYNC_ASTART_AGAIN)
1075 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001076
yongchun.li107a6162021-05-05 02:38:57 -07001077 if (avsync->mode == AV_SYNC_MODE_AMASTER || avsync->in_audio_switch) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001078 create_poll_t = true;
1079 if (start_mode == AVS_START_ASYNC) {
1080 if (!cb) {
1081 log_error("[%d]invalid cb", avsync->session_id);
1082 return AV_SYNC_ASTART_ERR;
1083 }
1084 avsync->audio_start = cb;
1085 avsync->audio_start_priv = priv;
1086 }
Song Zhaod62bb392021-04-23 12:25:49 -07001087 } else if (LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001088 create_poll_t = true;
1089
Song Zhaod62bb392021-04-23 12:25:49 -07001090 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001091 int ret;
1092
1093 log_info("[%d]start poll thread", avsync->session_id);
1094 avsync->quit_poll = false;
1095 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1096 if (ret) {
1097 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1098 return AV_SYNC_ASTART_ERR;
1099 }
1100 }
Song Zhaod62bb392021-04-23 12:25:49 -07001101 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001102 msync_session_get_wall(avsync->fd, &systime, NULL);
1103 log_info("[%d]return %u w %u pts %u d %u",
1104 avsync->session_id, ret, systime, pts, delay);
1105 }
1106exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001107 log_info("[%d]return %u", avsync->session_id, ret);
1108 return ret;
1109}
1110
1111int av_sync_audio_render(
1112 void *sync,
1113 pts90K pts,
1114 struct audio_policy *policy)
1115{
1116 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001117 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001118 uint32_t systime;
1119 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1120 avs_audio_action action = AA_SYNC_AA_MAX;
1121
1122 if (!avsync || !policy)
1123 return -1;
1124
yongchun.li107a6162021-05-05 02:38:57 -07001125 msync_session_get_wall(avsync->fd, &systime, NULL);
1126
1127 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1128 pts, systime, avsync->mode, (int)(pts-systime)/90);
1129
1130 if (avsync->in_audio_switch
1131 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
1132 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
1133 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1134 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1135 action = AV_SYNC_AA_RENDER;
1136 } else if ((int)(systime - pts) > 0) {
1137 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1138 (int)(systime - pts)/90, systime, pts);
1139 action = AV_SYNC_AA_DROP;
1140 } else {
1141 action = AV_SYNC_AA_INSERT;
1142 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1143 (int)(pts - systime)/90, systime, pts);
1144 }
1145 goto done;
1146 }
1147
Song Zhaoea5a0412021-01-18 16:40:08 -08001148 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1149 avsync->mode == AV_SYNC_MODE_AMASTER) {
1150 action = AV_SYNC_AA_RENDER;
1151 goto done;
1152 }
1153
Song Zhaod62bb392021-04-23 12:25:49 -07001154 /* stopping procedure, unblock audio rendering */
1155 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER &&
1156 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1157 action = AV_SYNC_AA_DROP;
1158 goto done;
1159 }
1160
Song Zhao7daf3a12021-05-10 22:22:25 -07001161 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1162 avsync->mode == AV_SYNC_MODE_AMASTER) {
1163 action = AV_SYNC_AA_RENDER;
1164 goto done;
1165 }
1166
Song Zhaod62bb392021-04-23 12:25:49 -07001167 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1168 LIVE_MODE(avsync->mode) &&
1169 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1170 /* outlier by stream error */
1171 avsync->outlier_cnt++;
1172 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1173 /* treat as disc, just drop current frame */
1174 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1175 avsync->outlier_cnt = 0;
1176 action = AV_SYNC_AA_DROP;
1177 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001178 goto done;
1179 }
1180 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1181 pts = systime;
1182 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001183 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001184 goto done;
1185 }
1186
1187 avsync->outlier_cnt = 0;
1188 /* low bound from sync_lost to sync_setup */
1189 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1190 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1191 action = AV_SYNC_AA_RENDER;
1192 goto done;
1193 }
1194
1195 /* high bound of sync_setup */
1196 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1197 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1198 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001199 action = AV_SYNC_AA_RENDER;
1200 goto done;
1201 }
1202
1203 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001204 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001205 action = AV_SYNC_AA_DROP;
1206 goto done;
1207 }
1208
1209 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001210 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001211 action = AV_SYNC_AA_INSERT;
1212 goto done;
1213 }
1214
1215done:
1216 policy->action = action;
1217 policy->delta = (int)(systime - pts);
1218 if (action == AV_SYNC_AA_RENDER) {
1219 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001220 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001221 if (!out_lier)
1222 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001223 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001224 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001225 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1226 msync_session_update_apts(avsync->fd, systime, pts, 0);
1227 log_info("[%d] audio switch done sys %u pts %u",
1228 avsync->session_id, systime, pts);
1229 msync_session_set_audio_switch(avsync->fd, false);
1230 avsync->in_audio_switch = false;
1231 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1232 } else {
1233 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1234 avsync->session_id, action, systime, pts, systime - pts);
1235 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001236 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001237 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001238 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001239 avsync->last_disc_pts != pts &&
1240 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001241 log_info ("[%d]audio disc %u --> %u",
1242 avsync->session_id, systime, pts);
1243 msync_session_set_audio_dis(avsync->fd, pts);
1244 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001245 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001246 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001247
1248 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001249 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001250 if (!avsync->audio_drop_cnt)
1251 avsync->audio_drop_start = now;
1252 avsync->audio_drop_cnt++;
1253 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1254 log_info ("[%d]audio keep dropping sys %u vs a %u",
1255 avsync->session_id, systime, pts);
1256 msync_session_set_audio_dis(avsync->fd, pts);
1257 }
Song Zhao409739b2021-05-12 22:21:40 -07001258 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001259 if (action != AV_SYNC_AA_DROP)
1260 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001261 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001262 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001263 }
1264
1265 return ret;
1266}
1267
1268int av_sync_get_clock(void *sync, pts90K *pts)
1269{
1270 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1271
1272 if (!avsync || !pts)
1273 return -1;
1274 return msync_session_get_wall(avsync->fd, pts, NULL);
1275}
1276
1277static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001278 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001279{
bo.xiao1f94b352021-08-02 03:53:47 -04001280 log_info("[%d]av_sync amode %d mode %d v/a/vt %d/%d/%d", avsync->session_id,
Song Zhaoe208d692021-04-19 15:38:52 -07001281 avsync->active_mode, avsync->mode, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001282 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1283 float speed;
1284 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaoe208d692021-04-19 15:38:52 -07001285 a_active && avsync->audio_start) {
yongchun.li107a6162021-05-05 02:38:57 -07001286 if (v_active || v_timeout || avsync->in_audio_switch) {
Song Zhaoe208d692021-04-19 15:38:52 -07001287 log_info("audio start cb");
1288 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
yongchun.li107a6162021-05-05 02:38:57 -07001289 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001290 }
1291
1292 if (!msync_session_get_rate(avsync->fd, &speed)) {
1293 /* speed change is triggered by asink,
1294 * attached audio HAL will handle it
1295 */
1296 if (speed != avsync->speed)
1297 log_info("[%d]new rate %f", avsync->session_id, speed);
1298 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001299 if (avsync->mode != avsync->backup_mode) {
1300 avsync->mode = avsync->backup_mode;
1301 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1302 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001303 } else {
1304 avsync->backup_mode = avsync->mode;
1305 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1306 log_info("[%d]audio to freerun mode", avsync->session_id);
1307 }
1308 avsync->speed = speed;
1309 }
Song Zhaod62bb392021-04-23 12:25:49 -07001310 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1311 struct session_debug debug;
1312 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001313 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001314 avsync->backup_mode = avsync->mode;
1315 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001316 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001317 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001318 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001319 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001320 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001321 log_warn("[%d]audio back to mode %d",
1322 avsync->session_id, avsync->mode);
1323 }
1324 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001325 }
1326}
1327
1328static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001329 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001330{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001331 struct session_debug debug;
1332
bo.xiao1f94b352021-08-02 03:53:47 -04001333 log_info("[%d]av_sync amode mode %d %d v/a %d/%d", avsync->session_id,
Song Zhaoea5a0412021-01-18 16:40:08 -08001334 avsync->active_mode, avsync->mode, v_active, a_active);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001335 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1336 if (debug.debug_freerun && !avsync->debug_freerun) {
1337 avsync->backup_mode = avsync->mode;
1338 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1339 avsync->debug_freerun = true;
1340 log_warn("[%d]video to freerun mode", avsync->session_id);
1341 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1342 avsync->mode = avsync->backup_mode;
1343 avsync->debug_freerun = false;
1344 log_warn("[%d]video back to mode %d",
1345 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001346 }
1347 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001348}
1349
1350static void * poll_thread(void * arg)
1351{
1352 int ret = 0;
1353 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1354 const int fd = avsync->fd;
1355 struct pollfd pfd = {
1356 /* default blocking capture */
1357 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1358 .fd = avsync->fd,
1359 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001360 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001361
1362 prctl (PR_SET_NAME, "avs_poll");
1363 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001364
1365 if (avsync->type == AV_SYNC_TYPE_AUDIO)
1366 sflag = SRC_A;
1367 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
1368 sflag = SRC_V;
1369
Song Zhaoea5a0412021-01-18 16:40:08 -08001370 while (!avsync->quit_poll) {
1371 for (;;) {
1372 ret = poll(&pfd, 1, 10);
1373 if (ret > 0)
1374 break;
1375 if (avsync->quit_poll)
1376 goto exit;
1377 if (errno == EINTR)
1378 continue;
1379 }
1380
1381 /* error handling */
1382 if (pfd.revents & POLLERR)
1383 log_error("[%d]POLLERR received", avsync->session_id);
1384
Song Zhaod62bb392021-04-23 12:25:49 -07001385 /* mode change. Non-exclusive wait so all the processes
1386 * shall be woken up
1387 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001388 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001389 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -08001390
1391 msync_session_get_stat(fd, &avsync->active_mode,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001392 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001393
1394 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhaoe208d692021-04-19 15:38:52 -07001395 handle_mode_change_a(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001396 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhaoe208d692021-04-19 15:38:52 -07001397 handle_mode_change_v(avsync, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001398 usleep(10000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001399 }
1400 }
1401exit:
1402 log_info("[%d]quit", avsync->session_id);
1403 return NULL;
1404}
1405
Song Zhao623e2f12021-09-03 15:54:04 -07001406#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1407/* return ppm between demod and PCR clock */
1408int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1409{
1410 int fd = -1, ppm = 0, nread;
1411 char buf[128];
1412 uint32_t reg_v, lock;
1413 float val;
1414
1415 fd = open(DEMOD_NODE, O_RDWR);
1416 if (fd < 0) {
1417 log_warn("node not found %s", DEMOD_NODE);
1418 /* do not retry */
1419 avsync->ppm_adjusted = true;
1420 return 0;
1421 }
1422 snprintf(buf, sizeof(buf), "%d", 5);
1423 write(fd, buf, 2);
1424
1425 lseek(fd, 0, SEEK_SET);
1426
1427 nread = read(fd, buf, sizeof(buf));
1428 if (nread <= 0) {
1429 log_error("read error");
1430 goto err;
1431 }
1432 buf[nread] = 0;
1433 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1434 log_error("wrong format %s", buf);
1435 goto err;
1436 }
1437 if (lock != 0x1f) {
1438 log_info("demod not locked");
1439 goto err;
1440 }
1441 if (reg_v > ((2 << 20) - 1))
1442 reg_v -= (2 << 21);
1443 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1444 ppm = val;
1445 log_info("ppm from SFO %d", ppm);
1446 avsync->ppm_adjusted = true;
1447
1448err:
1449 if (fd >= 0)
1450 close(fd);
1451 return ppm;
1452}
1453
Song Zhaod62bb392021-04-23 12:25:49 -07001454int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001455{
1456 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001457 struct pcr_info pcr;
1458 enum pcr_monitor_status status;
1459 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001460 if (!avsync)
1461 return -1;
1462
1463 if (avsync->type != AV_SYNC_TYPE_PCR)
1464 return -2;
1465
Song Zhao623e2f12021-09-03 15:54:04 -07001466 /* initial estimation from Demod SFO HW */
1467 if (!avsync->ppm_adjusted) {
1468 ppm = dmod_get_sfo_dev(avsync);
1469 if (ppm != 0) {
1470 /* ppm > 0 means board clock is faster */
1471 msync_session_set_clock_dev(avsync->fd, -ppm);
1472 }
1473 }
wei.dubcc2ed22021-05-19 07:16:10 -04001474 pcr.monoclk = mono_clock / 1000;
1475 pcr.pts = (long long) pts * 1000 / 90;
1476 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1477
1478 status = pcr_monitor_get_status(avsync->pcr_monitor);
1479
1480 if (status >= DEVIATION_READY) {
1481 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1482 if (avsync->ppm != ppm) {
1483 avsync->ppm = ppm;
1484 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1485 if (msync_session_set_clock_dev(avsync->fd, ppm))
1486 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001487 else
1488 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001489 }
1490 }
1491
Song Zhaod62bb392021-04-23 12:25:49 -07001492 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001493}
1494
Song Zhaod62bb392021-04-23 12:25:49 -07001495int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001496{
1497 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1498
1499 if (!avsync)
1500 return -1;
1501
Song Zhaod62bb392021-04-23 12:25:49 -07001502 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001503}
1504
1505int av_sync_set_session_name(void *sync, const char *name)
1506{
1507 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1508
1509 if (!avsync)
1510 return -1;
1511
1512 return msync_session_set_name(avsync->fd, name);
1513}
yongchun.li107a6162021-05-05 02:38:57 -07001514
1515int av_sync_set_audio_switch(void *sync, bool start)
1516{
1517 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1518 bool v_active, a_active, v_timeout;
1519
1520 if (!avsync)
1521 return -1;
1522 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
1523 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001524 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001525 log_error("[%d] can not get session state",
1526 avsync->session_id);
1527 return -1;
1528 }
1529 if (!v_active || !a_active) {
1530 log_error("[%d] no apply if not AV both active v %d a %d",
1531 avsync->session_id, v_active, a_active);
1532 return -1;
1533 }
1534 if (msync_session_set_audio_switch(avsync->fd, start)) {
1535 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1536 return -1;
1537 }
1538 avsync->in_audio_switch = start;
1539 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1540 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1541 return 0;
1542}
1543
1544int av_sync_get_audio_switch(void *sync, bool *start)
1545{
1546 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1547
1548 if (!avsync)
1549 return -1;
1550 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001551 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001552 log_error("[%d] can not audio seamless switch state",
1553 avsync->session_id);
1554 return -1;
1555 }
1556 if (start) *start = avsync->in_audio_switch;
1557 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001558}
Song Zhao8039f562021-05-18 18:11:25 -07001559
Song Zhao623e2f12021-09-03 15:54:04 -07001560enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001561{
1562 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1563
wei.dubcc2ed22021-05-19 07:16:10 -04001564 if (!avsync || !ppm)
1565 return CLK_RECOVERY_ERR;
1566 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001567 return CLK_RECOVERY_NOT_RUNNING;
1568
wei.dubcc2ed22021-05-19 07:16:10 -04001569 if (msync_session_get_clock_dev(avsync->fd, ppm))
1570 return CLK_RECOVERY_ERR;
1571
1572 if (*ppm == 0)
1573 return CLK_RECOVERY_ONGOING;
1574 else
1575 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001576}