blob: 0c4d3b48bf0586a08b897cd4c5ea7fa82b6ec3e8 [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 Zhaoc03ba122020-12-23 21:54:02 -0800306 return avsync;
Song Zhao9cd27a52021-07-26 15:27:38 +0000307err4:
wei.dubcc2ed22021-05-19 07:16:10 -0400308 if (avsync->pcr_monitor)
309 pcr_monitor_destroy(avsync->pcr_monitor);
Song Zhao9cd27a52021-07-26 15:27:38 +0000310err3:
311 close(avsync->fd);
Song Zhaoea5a0412021-01-18 16:40:08 -0800312err2:
313 destroy_pattern_detector(avsync->pattern_detector);
314err:
315 free(avsync);
316 return NULL;
317}
318
319void* av_sync_create(int session_id,
320 enum sync_mode mode,
321 enum sync_type type,
322 int start_thres)
323{
324 return create_internal(session_id, mode,
325 type, start_thres, false);
326}
327
328void* av_sync_attach(int session_id, enum sync_type type)
329{
330 return create_internal(session_id, AV_SYNC_MODE_MAX,
331 type, 0, true);
332}
333
334int av_sync_video_config(void *sync, struct video_config* config)
335{
336 struct av_sync_session *avsync = (struct av_sync_session *)sync;
337
338 if (!avsync || !config)
339 return -1;
340
341 if (config->delay != 1 && config->delay != 2) {
342 log_error("invalid delay: %d\n", config->delay);
343 return -1;
344 }
345
346 avsync->delay = config->delay;
347
348 log_info("[%d] delay: %d",
349 avsync->session_id, config->delay);
350 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800351}
352
353static int internal_stop(struct av_sync_session *avsync)
354{
355 int ret = 0;
356 struct vframe *frame;
357
358 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800359 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
360 frame->free(frame);
361 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800362 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800363 pthread_mutex_unlock(&avsync->lock);
364 return ret;
365}
366
367/* destroy and detach from kernel session */
368void av_sync_destroy(void *sync)
369{
370 struct av_sync_session *avsync = (struct av_sync_session *)sync;
371
372 if (!avsync)
373 return;
374
Song Zhaoea5a0412021-01-18 16:40:08 -0800375 log_info("[%d]begin", avsync->session_id);
376 if (avsync->state != AV_SYNC_STAT_INIT) {
377 if (avsync->type == AV_SYNC_TYPE_VIDEO)
378 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800379
Song Zhaoea5a0412021-01-18 16:40:08 -0800380 avsync->quit_poll = true;
381 if (avsync->poll_thread) {
382 pthread_join(avsync->poll_thread, NULL);
383 avsync->poll_thread = 0;
384 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700385 if (avsync->type == AV_SYNC_TYPE_AUDIO)
386 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoaf368d52021-02-17 17:53:45 -0800387 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800388
Song Zhaoea5a0412021-01-18 16:40:08 -0800389 if (avsync->session_started) {
390 if (avsync->type == AV_SYNC_TYPE_VIDEO)
391 msync_session_set_video_stop(avsync->fd);
392 else
393 msync_session_set_audio_stop(avsync->fd);
394 }
wei.dubcc2ed22021-05-19 07:16:10 -0400395
396 if(avsync->pcr_monitor)
397 pcr_monitor_destroy(avsync->pcr_monitor);
398
Song Zhaoea5a0412021-01-18 16:40:08 -0800399 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800400 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800401 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
402 destroy_q(avsync->frame_q);
403 destroy_pattern_detector(avsync->pattern_detector);
404 }
405 log_info("[%d]done", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800406 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800407}
408
bo.xiao5821fc72021-07-11 22:47:00 -0400409int avs_sync_set_start_policy(void *sync, struct start_policy* st_policy)
Song Zhaoea5a0412021-01-18 16:40:08 -0800410{
411 struct av_sync_session *avsync = (struct av_sync_session *)sync;
412
413 if (!avsync || !avsync->fd)
414 return -1;
415
bo.xiao5821fc72021-07-11 22:47:00 -0400416 log_info("[%d]policy %u --> %u, timeout %d --> %d", avsync->start_policy, st_policy->policy, avsync->timeout, st_policy->timeout);
417 avsync->start_policy = st_policy->policy;
418 avsync->timeout = st_policy->timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800419 /* v_peek will be handled by libamlavsync */
bo.xiao5821fc72021-07-11 22:47:00 -0400420 if (st_policy->policy != AV_SYNC_START_NONE &&
421 st_policy->policy != AV_SYNC_START_V_PEEK)
422 return msync_session_set_start_policy(avsync->fd, st_policy->policy, st_policy->timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800423
424 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800425}
426
427int av_sync_pause(void *sync, bool pause)
428{
429 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700430 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800431 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800432
433 if (!avsync)
434 return -1;
435
Song Zhaoea5a0412021-01-18 16:40:08 -0800436 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
437 return -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800438
yongchun.li107a6162021-05-05 02:38:57 -0700439 rc = msync_session_get_stat(avsync->fd, &avsync->active_mode,
440 &v_active, &a_active, &v_timeout,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700441 &avsync->in_audio_switch, SRC_A);
yongchun.li107a6162021-05-05 02:38:57 -0700442
yongchun.li5f52fb02021-06-04 18:13:05 -0700443 /* ignore only when video try to pause when audio is acive, on which
444 the control of the STC will be relays.
445 When resume,it can do always as it is possible that video just
446 paused earlier without audio yet,then audio added later before resume.
447 We shall not igore that otherwise it could cause video freeze. */
448 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
449 avsync->type == AV_SYNC_TYPE_VIDEO &&
450 a_active &&
451 !avsync->in_audio_switch) {
452 if (!pause) {
453 log_info("[%d] clear video pause when audio active",
454 avsync->session_id);
455 avsync->paused = pause;
456 } else {
457 log_info("[%d] ignore the pause from video when audio active",
458 avsync->session_id);
459 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800460 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700461 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800462
yongchun.li107a6162021-05-05 02:38:57 -0700463 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
464 log_info("[%d] ignore the pause from audio", avsync->session_id);
465 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
466 return 0;
467 }
468
Song Zhaoea5a0412021-01-18 16:40:08 -0800469 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800470 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800471 log_info("[%d]paused:%d type:%d rc %d",
472 avsync->session_id, pause, avsync->type, rc);
Song Zhaoc03ba122020-12-23 21:54:02 -0800473
Song Zhaoea5a0412021-01-18 16:40:08 -0800474 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800475}
476
477int av_sync_push_frame(void *sync , struct vframe *frame)
478{
479 int ret;
Song Zhaoee6a1512021-09-08 11:28:57 -0700480 struct vframe *prev = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800481 struct av_sync_session *avsync = (struct av_sync_session *)sync;
482
483 if (!avsync)
484 return -1;
485
Song Zhaoea5a0412021-01-18 16:40:08 -0800486 if (!avsync->frame_q) {
487 /* policy should be final now */
bo.xiao5821fc72021-07-11 22:47:00 -0400488 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy, &avsync->timeout)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800489 log_error("[%d]get policy", avsync->session_id);
490 return -1;
491 }
492
493 avsync->frame_q = create_q(MAX_FRAME_NUM);
494 if (!avsync->frame_q) {
495 log_error("[%d]create queue fail", avsync->session_id);
yongchun.li0ee6e372021-08-20 04:26:04 -0700496
Song Zhaoea5a0412021-01-18 16:40:08 -0800497 return -1;
498 }
499
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700500 /* for debugging */
501 {
Song Zhaoea5a0412021-01-18 16:40:08 -0800502 int ret;
503
504 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
505 if (ret) {
506 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
507 destroy_q(avsync->frame_q);
508 return -1;
509 }
510 }
511 }
512
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700513 if (avsync->last_q_pts != -1) {
514 if (avsync->last_q_pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
515 /* TODO: wrong, should remove from back of queue */
Song Zhaoc03ba122020-12-23 21:54:02 -0800516 dqueue_item(avsync->frame_q, (void **)&prev);
Song Zhaoee6a1512021-09-08 11:28:57 -0700517 if (prev) {
518 prev->free(prev);
519 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
520 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700521 } else if (avsync->fps_cnt < 100) {
522 int32_t interval = frame->pts - avsync->last_q_pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700523
524 if (interval > 0 && interval <= 4500) {
525 if (avsync->fps_interval_acc == -1) {
526 avsync->fps_interval_acc = interval;
527 avsync->fps_cnt = 1;
528 } else {
529 avsync->fps_interval_acc += interval;
530 avsync->fps_cnt++;
531 avsync->fps_interval = avsync->fps_interval_acc / avsync->fps_cnt;
532 if (avsync->fps_cnt == 100)
533 log_info("[%d] fps_interval = %d", avsync->session_id, avsync->fps_interval);
534 }
535 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800536 }
537 }
538
Song Zhao065800e2021-05-26 15:56:06 -0700539 if (frame->duration == -1)
540 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800541 frame->hold_period = 0;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700542 avsync->last_q_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800543 ret = queue_item(avsync->frame_q, frame);
544 if (avsync->state == AV_SYNC_STAT_INIT &&
545 queue_size(avsync->frame_q) >= avsync->start_thres) {
546 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaoea5a0412021-01-18 16:40:08 -0800547 log_info("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800548 }
549
550 if (ret)
551 log_error("%s queue fail:%d", ret);
bo.xiao1f94b352021-08-02 03:53:47 -0400552 log_debug("[%d]push %u, QNum=%d", avsync->session_id, frame->pts, queue_size(avsync->frame_q));
Song Zhaoc03ba122020-12-23 21:54:02 -0800553 return ret;
554
555}
556
557struct vframe *av_sync_pop_frame(void *sync)
558{
Song Zhaoea5a0412021-01-18 16:40:08 -0800559 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800560 struct av_sync_session *avsync = (struct av_sync_session *)sync;
561 int toggle_cnt = 0;
562 uint32_t systime;
Song Zhao468fd652021-01-15 22:13:04 -0800563 bool pause_pts_reached = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800564 uint32_t interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800565
566 pthread_mutex_lock(&avsync->lock);
567 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhaod62bb392021-04-23 12:25:49 -0700568 log_info("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800569 goto exit;
570 }
571
Song Zhaoea5a0412021-01-18 16:40:08 -0800572 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700573 uint32_t pts;
574
Song Zhaoc03ba122020-12-23 21:54:02 -0800575 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800576 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800577 goto exit;
578 }
Song Zhao35a82df2021-04-15 10:58:49 -0700579 msync_session_get_wall(avsync->fd, &systime, &interval);
580 pts = frame->pts - avsync->delay * interval;
581 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800582 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700583 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800584 }
585
Song Zhaoea5a0412021-01-18 16:40:08 -0800586 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700587 !avsync->first_frame_toggled &&
588 !msync_clock_started(avsync->fd)) {
589 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800590 log_trace("[%d]clock not started", avsync->session_id);
591 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800592 }
593
Song Zhaoea5a0412021-01-18 16:40:08 -0800594 enter_last_frame = avsync->last_frame;
595 msync_session_get_wall(avsync->fd, &systime, &interval);
596
597 /* handle refresh rate change */
598 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
599 avsync->vsync_interval != interval) {
600 log_info("[%d]vsync interval update %d --> %u",
601 avsync->session_id, avsync->vsync_interval, interval);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700602 if (avsync->fps_interval == -1)
603 avsync->fps_interval = interval;
Song Zhaoea5a0412021-01-18 16:40:08 -0800604 avsync->vsync_interval = interval;
605 avsync->phase_set = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700606 avsync->phase = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800607 reset_pattern(avsync->pattern_detector);
608 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800609 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
610 struct vframe *next_frame = NULL;
611
612 peek_item(avsync->frame_q, (void **)&next_frame, 1);
613 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700614 log_debug("[%d]cur_f %u next_f %u size %d",
615 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800616 if (frame_expire(avsync, systime, interval,
617 frame, next_frame, toggle_cnt)) {
618 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800619 toggle_cnt++;
620
Song Zhao35a82df2021-04-15 10:58:49 -0700621 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800622 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao35a82df2021-04-15 10:58:49 -0700623 avsync->last_holding_peroid))
624 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
625
Song Zhaoc03ba122020-12-23 21:54:02 -0800626 if (avsync->last_frame)
627 avsync->last_holding_peroid = avsync->last_frame->hold_period;
628
629 dqueue_item(avsync->frame_q, (void **)&frame);
630 if (avsync->last_frame) {
631 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800632 if (toggle_cnt > 1) {
Song Zhao35a82df2021-04-15 10:58:49 -0700633 log_debug("[%d]free %u cur %u system/d %u/%u", avsync->session_id,
634 avsync->last_frame->pts, frame->pts, systime, systime - avsync->last_poptime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800635 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800636 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800637 } else {
638 avsync->first_frame_toggled = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800639 log_info("[%d]first frame %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800640 }
641 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800642 avsync->last_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800643 } else
644 break;
645 }
646
647 /* pause pts */
648 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800649 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800650 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800651 else
Song Zhao468fd652021-01-15 22:13:04 -0800652 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
653 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
654 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
655 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
656 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800657
Song Zhao468fd652021-01-15 22:13:04 -0800658 if (pause_pts_reached) {
659 if (avsync->pause_pts_cb)
660 avsync->pause_pts_cb(avsync->pause_pts,
Song Zhaoc03ba122020-12-23 21:54:02 -0800661 avsync->pause_cb_priv);
662
Song Zhao468fd652021-01-15 22:13:04 -0800663 /* stay in paused until av_sync_pause(false) */
664 avsync->paused = true;
665 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoea5a0412021-01-18 16:40:08 -0800666 log_info ("[%d]reach pause pts: %u",
667 avsync->session_id, avsync->last_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800668 }
669
670exit:
671 pthread_mutex_unlock(&avsync->lock);
672 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800673 if (enter_last_frame != avsync->last_frame)
674 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
bo.xiao1f94b352021-08-02 03:53:47 -0400675 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 -0700676 /* don't update vpts for out_lier */
677 if (avsync->last_frame->duration != -1)
678 msync_session_update_vpts(avsync->fd, systime,
679 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800680 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800681 if (enter_last_frame != avsync->last_frame)
682 log_debug("[%d]pop (nil)", avsync->session_id);
683
Song Zhao35a82df2021-04-15 10:58:49 -0700684 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800685 if (avsync->last_frame)
686 avsync->last_frame->hold_period++;
687 return avsync->last_frame;
688}
689
Song Zhaoc03ba122020-12-23 21:54:02 -0800690static inline uint32_t abs_diff(uint32_t a, uint32_t b)
691{
Song Zhaoea5a0412021-01-18 16:40:08 -0800692 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800693}
694
yongchun.li0ee6e372021-08-20 04:26:04 -0700695static uint64_t time_diff (struct timespec *b, struct timespec *a)
Song Zhaoc03ba122020-12-23 21:54:02 -0800696{
yongchun.li0ee6e372021-08-20 04:26:04 -0700697 return (b->tv_sec - a->tv_sec)*1000000 + (b->tv_nsec/1000 - a->tv_nsec/1000);
Song Zhaoc03ba122020-12-23 21:54:02 -0800698}
699
Song Zhaoc03ba122020-12-23 21:54:02 -0800700static bool frame_expire(struct av_sync_session* avsync,
701 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800702 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800703 struct vframe * frame,
704 struct vframe * next_frame,
705 int toggle_cnt)
706{
707 uint32_t fpts = frame->pts;
708 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800709 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800710
711 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
712 return false;
713
714 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
715 return true;
716
fei.deng63e43e12021-09-23 19:44:01 +0800717 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
718 avsync->mode == AV_SYNC_MODE_VMASTER) {
719 /* We need to ensure that the video outputs smoothly,
720 so output video frame by frame hold_period */
721 if ((abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES) &&
722 avsync->last_frame &&
723 (avsync->last_frame->hold_period >= (avsync->fps_interval/interval))) {
724 log_debug("[%d]vmaster/freerun systime:%u --> fpts:%u,last hold_period:%d",
725 avsync->session_id, systime, fpts,avsync->last_frame->hold_period);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700726 return true;
727 }
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700728 }
729
Song Zhaoc03ba122020-12-23 21:54:02 -0800730 if (!fpts) {
731 if (avsync->last_frame) {
732 /* try to accumulate duration as PTS */
733 fpts = avsync->vpts + avsync->last_frame->duration;
734 } else {
735 fpts = avsync->vpts;
736 }
737 }
738 systime += pts_correction;
739
740 /* phase adjustment */
741 if (avsync->phase_set)
742 systime += avsync->phase;
743
yongchun.lia50b1e92021-08-07 01:11:54 +0000744 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800745 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000746 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700747 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800748 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800749 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800750 return false;
751
Song Zhaoa2985cb2021-06-24 12:01:47 -0700752 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
753 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700754 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800755
yongchun.li0ee6e372021-08-20 04:26:04 -0700756 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700757 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800758 avsync->last_pts = fpts;
759 if (time_diff(&now, &avsync->sync_lost_print_time) >=
760 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700761 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800762 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800763 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700764 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800765 } else
766 avsync->sync_lost_cnt++;
767 }
Song Zhaod62bb392021-04-23 12:25:49 -0700768
769 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
770 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700771 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700772 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700773 /* outlier by stream error */
774 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700775 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700776 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
777 log_info("render outlier %u", fpts);
778 return true;
779 }
780 }
781
782 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800783 avsync->state = AV_SYNC_STAT_SYNC_LOST;
784 avsync->phase_set = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700785 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800786 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700787
788 if (LIVE_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700789 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700790 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700791 msync_session_set_video_dis(avsync->fd, fpts);
792 avsync->last_disc_pts = fpts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700793 }
794
795 if ((int)(systime - fpts) > 0) {
796 if ((int)(systime - fpts) < avsync->disc_thres_max) {
797 /* catch up PCR */
Song Zhaof46932e2021-05-21 01:51:45 -0700798 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700799 } else {
800 /* render according to FPS */
801 if (!VALID_TS(avsync->last_r_syst) ||
802 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
803 avsync->last_r_syst = systime;
804 return true;
805 }
806 return false;
807 }
808 } else if (LIVE_MODE(avsync->mode)) {
809 /* hold if the gap is small */
810 if ((int)(fpts - systime) < avsync->disc_thres_max) {
811 return false;
812 } else {
813 /* render according to FPS */
814 if (!VALID_TS(avsync->last_r_syst) ||
815 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
816 avsync->last_r_syst = systime;
817 return true;
818 }
819 return false;
820 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800821 }
822 }
823
Song Zhao52f55192021-05-06 10:52:21 -0700824 /* In some cases, keeping pattern will enlarge the gap */
825 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
826 avsync->first_frame_toggled) {
827 reset_pattern(avsync->pattern_detector);
Song Zhaof46932e2021-05-21 01:51:45 -0700828 log_warn("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700829 systime, fpts);
830 }
831
Song Zhaoc03ba122020-12-23 21:54:02 -0800832 expire = (int)(systime - fpts) >= 0;
833
834 /* scatter the frame in different vsync whenever possible */
835 if (expire && next_frame && next_frame->pts && toggle_cnt) {
836 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhaoea5a0412021-01-18 16:40:08 -0800837 if (systime + interval < next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800838 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800839 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
840 avsync->session_id, systime, interval, next_frame->pts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800841 }
842 } else if (!expire && next_frame && next_frame->pts && !toggle_cnt
843 && avsync->first_frame_toggled) {
844 /* next vsync will have at least 2 frame expired */
Song Zhao35a82df2021-04-15 10:58:49 -0700845 if (systime + interval >= next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800846 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800847 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
848 avsync->session_id, systime, interval, next_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800849 }
850 }
851
Song Zhaoa58c3e92021-03-09 18:52:55 -0800852 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
853 correct_pattern(avsync->pattern_detector, frame, next_frame,
854 (avsync->last_frame?avsync->last_frame->hold_period:0),
855 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800856 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -0800857
858 if (expire) {
859 avsync->vpts = fpts;
860 /* phase adjustment */
861 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +0000862 //always adjust to the half v-sync to give most pts tolerace and unify behavior
863 if ((int)(systime - fpts) >= 0 && (int)(fpts + interval - systime) > 0) {
864 avsync->phase = interval/2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800865 avsync->phase_set = true;
yongchun.lia50b1e92021-08-07 01:11:54 +0000866 log_info("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800867 }
868 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800869 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -0800870 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800871 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -0800872 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800873 }
874 return expire;
875}
876
Song Zhao35a82df2021-04-15 10:58:49 -0700877static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -0800878{
Song Zhao35a82df2021-04-15 10:58:49 -0700879 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800880 log_trace("[%d]cur_period: %d last_period: %d",
881 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -0700882 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
883 ret = true;
884 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
885 ret = true;
886 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
887 ret = true;
888 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
889 ret = true;
890
891 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800892}
893
894int av_sync_set_speed(void *sync, float speed)
895{
896 struct av_sync_session *avsync = (struct av_sync_session *)sync;
897
898 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800899 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800900 return -1;
901 }
902
Song Zhaoea5a0412021-01-18 16:40:08 -0800903 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
904 avsync->mode == AV_SYNC_MODE_IPTV) {
905 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800906 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800907 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800908
Song Zhaoea5a0412021-01-18 16:40:08 -0800909 avsync->speed = speed;
910
911 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
912 if (speed == 1.0) {
913 avsync->mode = avsync->backup_mode;
914 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
915 } else {
916 avsync->backup_mode = avsync->mode;
917 avsync->mode = AV_SYNC_MODE_FREE_RUN;
918 log_info("[%d]audio to freerun mode", avsync->session_id);
919 }
920 }
921#if 0
Song Zhaoc03ba122020-12-23 21:54:02 -0800922 if (avsync->mode != AV_SYNC_MODE_VMASTER) {
923 log_info("ignore set speed in mode %d", avsync->mode);
924 return 0;
925 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800926#endif
Song Zhaoc03ba122020-12-23 21:54:02 -0800927
Song Zhaoea5a0412021-01-18 16:40:08 -0800928 log_info("session[%d] set rate to %f", avsync->session_id, speed);
929 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800930}
931
932int av_sync_change_mode(void *sync, enum sync_mode mode)
933{
934 struct av_sync_session *avsync = (struct av_sync_session *)sync;
935
936 if (!avsync)
937 return -1;
938
Song Zhaoea5a0412021-01-18 16:40:08 -0800939 if (msync_session_set_mode(avsync->fd, mode)) {
940 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800941 return -1;
942 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800943 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -0800944 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800945 return 0;
946}
947
Song Zhao01031bb2021-05-13 21:23:20 -0700948int av_sync_get_mode(void *sync, enum sync_mode *mode)
949{
950 struct av_sync_session *avsync = (struct av_sync_session *)sync;
951
952 if (!avsync || !mode)
953 return -1;
954
955 *mode = avsync->mode;
956 return 0;
957}
958
Song Zhaoc03ba122020-12-23 21:54:02 -0800959int av_sync_set_pause_pts(void *sync, pts90K pts)
960{
961 struct av_sync_session *avsync = (struct av_sync_session *)sync;
962
963 if (!avsync)
964 return -1;
965
966 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -0800967 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800968 return 0;
969}
970
971int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
972{
973 struct av_sync_session *avsync = (struct av_sync_session *)sync;
974
975 if (!avsync)
976 return -1;
977
978 avsync->pause_pts_cb = cb;
979 avsync->pause_cb_priv = priv;
980 return 0;
981}
Song Zhaoea5a0412021-01-18 16:40:08 -0800982
983static void trigger_audio_start_cb(struct av_sync_session *avsync,
984 avs_ascb_reason reason)
985{
986 if (avsync) {
987 pthread_mutex_lock(&avsync->lock);
988 if (avsync->audio_start) {
989 avsync->audio_start(avsync->audio_start_priv, reason);
990 avsync->session_started = true;
991 avsync->audio_start = NULL;
992 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
993 }
994 pthread_mutex_unlock(&avsync->lock);
995 }
996}
997
998avs_start_ret av_sync_audio_start(
999 void *sync,
1000 pts90K pts,
1001 pts90K delay,
1002 audio_start_cb cb,
1003 void *priv)
1004{
1005 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1006 uint32_t start_mode;
yongchun.li59e873d2021-07-07 11:42:38 -07001007 uint32_t systime;
Song Zhaoea5a0412021-01-18 16:40:08 -08001008 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1009 bool create_poll_t = false;
1010
1011 if (!avsync)
1012 return ret;
1013
yongchun.li59e873d2021-07-07 11:42:38 -07001014 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1015 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001016
yongchun.li59e873d2021-07-07 11:42:38 -07001017 if (avsync->in_audio_switch &&
1018 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1019 {
1020 start_mode = AVS_START_SYNC;
1021 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1022 } else {
1023 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1024 log_error("[%d]fail to set audio start", avsync->session_id);
1025 }
1026 if (avsync->in_audio_switch &&
1027 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1028 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
1029 msync_session_get_wall(avsync->fd, &systime, NULL);
1030 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB &&
1031 start_mode == AVS_START_SYNC) {
1032 log_info("%d audio_switch audio need drop first.ahead %d ms",
1033 avsync->session_id, (int)(systime - pts)/90);
1034 ret = AV_SYNC_ASTART_AGAIN;
1035 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1036 goto exit;
1037 }
1038 else {
1039 int diff = (int)(pts - systime);
1040 log_info("%d audio_switch_state to start mode %d diff %d ms",
1041 avsync->session_id, start_mode, diff/90);
1042 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
1043 if (diff < A_ADJ_THREDHOLD_LB) {
1044 log_info("%d orig mode %d already close enough direct start",
1045 avsync->session_id, start_mode);
1046 start_mode = AVS_START_SYNC;
1047 }
1048 }
yongchun.li107a6162021-05-05 02:38:57 -07001049 }
1050
Song Zhaoea5a0412021-01-18 16:40:08 -08001051 if (start_mode == AVS_START_SYNC) {
1052 ret = AV_SYNC_ASTART_SYNC;
1053 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001054 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001055 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001056 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001057 avsync->state = AV_SYNC_STAT_RUNNING;
1058 } else if (start_mode == AVS_START_AGAIN) {
1059 ret = AV_SYNC_ASTART_AGAIN;
1060 }
1061
1062 if (ret == AV_SYNC_ASTART_AGAIN)
1063 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001064
yongchun.li107a6162021-05-05 02:38:57 -07001065 if (avsync->mode == AV_SYNC_MODE_AMASTER || avsync->in_audio_switch) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001066 create_poll_t = true;
1067 if (start_mode == AVS_START_ASYNC) {
1068 if (!cb) {
1069 log_error("[%d]invalid cb", avsync->session_id);
1070 return AV_SYNC_ASTART_ERR;
1071 }
1072 avsync->audio_start = cb;
1073 avsync->audio_start_priv = priv;
1074 }
Song Zhaod62bb392021-04-23 12:25:49 -07001075 } else if (LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001076 create_poll_t = true;
1077
Song Zhaod62bb392021-04-23 12:25:49 -07001078 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001079 int ret;
1080
1081 log_info("[%d]start poll thread", avsync->session_id);
1082 avsync->quit_poll = false;
1083 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1084 if (ret) {
1085 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1086 return AV_SYNC_ASTART_ERR;
1087 }
1088 }
Song Zhaod62bb392021-04-23 12:25:49 -07001089 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001090 msync_session_get_wall(avsync->fd, &systime, NULL);
1091 log_info("[%d]return %u w %u pts %u d %u",
1092 avsync->session_id, ret, systime, pts, delay);
1093 }
1094exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001095 log_info("[%d]return %u", avsync->session_id, ret);
1096 return ret;
1097}
1098
1099int av_sync_audio_render(
1100 void *sync,
1101 pts90K pts,
1102 struct audio_policy *policy)
1103{
1104 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001105 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001106 uint32_t systime;
1107 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1108 avs_audio_action action = AA_SYNC_AA_MAX;
1109
1110 if (!avsync || !policy)
1111 return -1;
1112
yongchun.li107a6162021-05-05 02:38:57 -07001113 msync_session_get_wall(avsync->fd, &systime, NULL);
1114
1115 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1116 pts, systime, avsync->mode, (int)(pts-systime)/90);
1117
1118 if (avsync->in_audio_switch
1119 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
1120 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
1121 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1122 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1123 action = AV_SYNC_AA_RENDER;
1124 } else if ((int)(systime - pts) > 0) {
1125 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1126 (int)(systime - pts)/90, systime, pts);
1127 action = AV_SYNC_AA_DROP;
1128 } else {
1129 action = AV_SYNC_AA_INSERT;
1130 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1131 (int)(pts - systime)/90, systime, pts);
1132 }
1133 goto done;
1134 }
1135
Song Zhaoea5a0412021-01-18 16:40:08 -08001136 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1137 avsync->mode == AV_SYNC_MODE_AMASTER) {
1138 action = AV_SYNC_AA_RENDER;
1139 goto done;
1140 }
1141
Song Zhaod62bb392021-04-23 12:25:49 -07001142 /* stopping procedure, unblock audio rendering */
1143 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER &&
1144 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1145 action = AV_SYNC_AA_DROP;
1146 goto done;
1147 }
1148
Song Zhao7daf3a12021-05-10 22:22:25 -07001149 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1150 avsync->mode == AV_SYNC_MODE_AMASTER) {
1151 action = AV_SYNC_AA_RENDER;
1152 goto done;
1153 }
1154
Song Zhaod62bb392021-04-23 12:25:49 -07001155 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1156 LIVE_MODE(avsync->mode) &&
1157 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1158 /* outlier by stream error */
1159 avsync->outlier_cnt++;
1160 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1161 /* treat as disc, just drop current frame */
1162 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1163 avsync->outlier_cnt = 0;
1164 action = AV_SYNC_AA_DROP;
1165 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001166 goto done;
1167 }
1168 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1169 pts = systime;
1170 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001171 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001172 goto done;
1173 }
1174
1175 avsync->outlier_cnt = 0;
1176 /* low bound from sync_lost to sync_setup */
1177 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1178 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1179 action = AV_SYNC_AA_RENDER;
1180 goto done;
1181 }
1182
1183 /* high bound of sync_setup */
1184 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1185 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1186 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001187 action = AV_SYNC_AA_RENDER;
1188 goto done;
1189 }
1190
1191 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001192 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001193 action = AV_SYNC_AA_DROP;
1194 goto done;
1195 }
1196
1197 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001198 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001199 action = AV_SYNC_AA_INSERT;
1200 goto done;
1201 }
1202
1203done:
1204 policy->action = action;
1205 policy->delta = (int)(systime - pts);
1206 if (action == AV_SYNC_AA_RENDER) {
1207 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001208 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001209 if (!out_lier)
1210 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001211 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001212 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001213 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1214 msync_session_update_apts(avsync->fd, systime, pts, 0);
1215 log_info("[%d] audio switch done sys %u pts %u",
1216 avsync->session_id, systime, pts);
1217 msync_session_set_audio_switch(avsync->fd, false);
1218 avsync->in_audio_switch = false;
1219 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1220 } else {
1221 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1222 avsync->session_id, action, systime, pts, systime - pts);
1223 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001224 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001225 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001226 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001227 avsync->last_disc_pts != pts &&
1228 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001229 log_info ("[%d]audio disc %u --> %u",
1230 avsync->session_id, systime, pts);
1231 msync_session_set_audio_dis(avsync->fd, pts);
1232 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001233 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001234 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001235
1236 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001237 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001238 if (!avsync->audio_drop_cnt)
1239 avsync->audio_drop_start = now;
1240 avsync->audio_drop_cnt++;
1241 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1242 log_info ("[%d]audio keep dropping sys %u vs a %u",
1243 avsync->session_id, systime, pts);
1244 msync_session_set_audio_dis(avsync->fd, pts);
1245 }
Song Zhao409739b2021-05-12 22:21:40 -07001246 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001247 if (action != AV_SYNC_AA_DROP)
1248 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001249 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001250 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001251 }
1252
1253 return ret;
1254}
1255
1256int av_sync_get_clock(void *sync, pts90K *pts)
1257{
1258 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1259
1260 if (!avsync || !pts)
1261 return -1;
1262 return msync_session_get_wall(avsync->fd, pts, NULL);
1263}
1264
1265static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001266 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001267{
bo.xiao1f94b352021-08-02 03:53:47 -04001268 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 -07001269 avsync->active_mode, avsync->mode, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001270 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1271 float speed;
1272 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaoe208d692021-04-19 15:38:52 -07001273 a_active && avsync->audio_start) {
yongchun.li107a6162021-05-05 02:38:57 -07001274 if (v_active || v_timeout || avsync->in_audio_switch) {
Song Zhaoe208d692021-04-19 15:38:52 -07001275 log_info("audio start cb");
1276 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
yongchun.li107a6162021-05-05 02:38:57 -07001277 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001278 }
1279
1280 if (!msync_session_get_rate(avsync->fd, &speed)) {
1281 /* speed change is triggered by asink,
1282 * attached audio HAL will handle it
1283 */
1284 if (speed != avsync->speed)
1285 log_info("[%d]new rate %f", avsync->session_id, speed);
1286 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001287 if (avsync->mode != avsync->backup_mode) {
1288 avsync->mode = avsync->backup_mode;
1289 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1290 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001291 } else {
1292 avsync->backup_mode = avsync->mode;
1293 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1294 log_info("[%d]audio to freerun mode", avsync->session_id);
1295 }
1296 avsync->speed = speed;
1297 }
Song Zhaod62bb392021-04-23 12:25:49 -07001298 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1299 struct session_debug debug;
1300 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001301 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001302 avsync->backup_mode = avsync->mode;
1303 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001304 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001305 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001306 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001307 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001308 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001309 log_warn("[%d]audio back to mode %d",
1310 avsync->session_id, avsync->mode);
1311 }
1312 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001313 }
1314}
1315
1316static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001317 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001318{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001319 struct session_debug debug;
1320
bo.xiao1f94b352021-08-02 03:53:47 -04001321 log_info("[%d]av_sync amode mode %d %d v/a %d/%d", avsync->session_id,
Song Zhaoea5a0412021-01-18 16:40:08 -08001322 avsync->active_mode, avsync->mode, v_active, a_active);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001323 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1324 if (debug.debug_freerun && !avsync->debug_freerun) {
1325 avsync->backup_mode = avsync->mode;
1326 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1327 avsync->debug_freerun = true;
1328 log_warn("[%d]video to freerun mode", avsync->session_id);
1329 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1330 avsync->mode = avsync->backup_mode;
1331 avsync->debug_freerun = false;
1332 log_warn("[%d]video back to mode %d",
1333 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001334 }
1335 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001336}
1337
1338static void * poll_thread(void * arg)
1339{
1340 int ret = 0;
1341 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1342 const int fd = avsync->fd;
1343 struct pollfd pfd = {
1344 /* default blocking capture */
1345 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1346 .fd = avsync->fd,
1347 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001348 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001349
1350 prctl (PR_SET_NAME, "avs_poll");
1351 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001352
1353 if (avsync->type == AV_SYNC_TYPE_AUDIO)
1354 sflag = SRC_A;
1355 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
1356 sflag = SRC_V;
1357
Song Zhaoea5a0412021-01-18 16:40:08 -08001358 while (!avsync->quit_poll) {
1359 for (;;) {
1360 ret = poll(&pfd, 1, 10);
1361 if (ret > 0)
1362 break;
1363 if (avsync->quit_poll)
1364 goto exit;
1365 if (errno == EINTR)
1366 continue;
1367 }
1368
1369 /* error handling */
1370 if (pfd.revents & POLLERR)
1371 log_error("[%d]POLLERR received", avsync->session_id);
1372
Song Zhaod62bb392021-04-23 12:25:49 -07001373 /* mode change. Non-exclusive wait so all the processes
1374 * shall be woken up
1375 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001376 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001377 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -08001378
1379 msync_session_get_stat(fd, &avsync->active_mode,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001380 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001381
1382 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhaoe208d692021-04-19 15:38:52 -07001383 handle_mode_change_a(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001384 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhaoe208d692021-04-19 15:38:52 -07001385 handle_mode_change_v(avsync, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001386 usleep(10000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001387 }
1388 }
1389exit:
1390 log_info("[%d]quit", avsync->session_id);
1391 return NULL;
1392}
1393
Song Zhao623e2f12021-09-03 15:54:04 -07001394#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1395/* return ppm between demod and PCR clock */
1396int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1397{
1398 int fd = -1, ppm = 0, nread;
1399 char buf[128];
1400 uint32_t reg_v, lock;
1401 float val;
1402
1403 fd = open(DEMOD_NODE, O_RDWR);
1404 if (fd < 0) {
1405 log_warn("node not found %s", DEMOD_NODE);
1406 /* do not retry */
1407 avsync->ppm_adjusted = true;
1408 return 0;
1409 }
1410 snprintf(buf, sizeof(buf), "%d", 5);
1411 write(fd, buf, 2);
1412
1413 lseek(fd, 0, SEEK_SET);
1414
1415 nread = read(fd, buf, sizeof(buf));
1416 if (nread <= 0) {
1417 log_error("read error");
1418 goto err;
1419 }
1420 buf[nread] = 0;
1421 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1422 log_error("wrong format %s", buf);
1423 goto err;
1424 }
1425 if (lock != 0x1f) {
1426 log_info("demod not locked");
1427 goto err;
1428 }
1429 if (reg_v > ((2 << 20) - 1))
1430 reg_v -= (2 << 21);
1431 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1432 ppm = val;
1433 log_info("ppm from SFO %d", ppm);
1434 avsync->ppm_adjusted = true;
1435
1436err:
1437 if (fd >= 0)
1438 close(fd);
1439 return ppm;
1440}
1441
Song Zhaod62bb392021-04-23 12:25:49 -07001442int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001443{
1444 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001445 struct pcr_info pcr;
1446 enum pcr_monitor_status status;
1447 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001448 if (!avsync)
1449 return -1;
1450
1451 if (avsync->type != AV_SYNC_TYPE_PCR)
1452 return -2;
1453
Song Zhao623e2f12021-09-03 15:54:04 -07001454 /* initial estimation from Demod SFO HW */
1455 if (!avsync->ppm_adjusted) {
1456 ppm = dmod_get_sfo_dev(avsync);
1457 if (ppm != 0) {
1458 /* ppm > 0 means board clock is faster */
1459 msync_session_set_clock_dev(avsync->fd, -ppm);
1460 }
1461 }
wei.dubcc2ed22021-05-19 07:16:10 -04001462 pcr.monoclk = mono_clock / 1000;
1463 pcr.pts = (long long) pts * 1000 / 90;
1464 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1465
1466 status = pcr_monitor_get_status(avsync->pcr_monitor);
1467
1468 if (status >= DEVIATION_READY) {
1469 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1470 if (avsync->ppm != ppm) {
1471 avsync->ppm = ppm;
1472 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1473 if (msync_session_set_clock_dev(avsync->fd, ppm))
1474 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001475 else
1476 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001477 }
1478 }
1479
Song Zhaod62bb392021-04-23 12:25:49 -07001480 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001481}
1482
Song Zhaod62bb392021-04-23 12:25:49 -07001483int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001484{
1485 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1486
1487 if (!avsync)
1488 return -1;
1489
Song Zhaod62bb392021-04-23 12:25:49 -07001490 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001491}
1492
1493int av_sync_set_session_name(void *sync, const char *name)
1494{
1495 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1496
1497 if (!avsync)
1498 return -1;
1499
1500 return msync_session_set_name(avsync->fd, name);
1501}
yongchun.li107a6162021-05-05 02:38:57 -07001502
1503int av_sync_set_audio_switch(void *sync, bool start)
1504{
1505 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1506 bool v_active, a_active, v_timeout;
1507
1508 if (!avsync)
1509 return -1;
1510 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
1511 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001512 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001513 log_error("[%d] can not get session state",
1514 avsync->session_id);
1515 return -1;
1516 }
1517 if (!v_active || !a_active) {
1518 log_error("[%d] no apply if not AV both active v %d a %d",
1519 avsync->session_id, v_active, a_active);
1520 return -1;
1521 }
1522 if (msync_session_set_audio_switch(avsync->fd, start)) {
1523 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1524 return -1;
1525 }
1526 avsync->in_audio_switch = start;
1527 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1528 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1529 return 0;
1530}
1531
1532int av_sync_get_audio_switch(void *sync, bool *start)
1533{
1534 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1535
1536 if (!avsync)
1537 return -1;
1538 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001539 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001540 log_error("[%d] can not audio seamless switch state",
1541 avsync->session_id);
1542 return -1;
1543 }
1544 if (start) *start = avsync->in_audio_switch;
1545 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001546}
Song Zhao8039f562021-05-18 18:11:25 -07001547
Song Zhao623e2f12021-09-03 15:54:04 -07001548enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001549{
1550 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1551
wei.dubcc2ed22021-05-19 07:16:10 -04001552 if (!avsync || !ppm)
1553 return CLK_RECOVERY_ERR;
1554 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001555 return CLK_RECOVERY_NOT_RUNNING;
1556
wei.dubcc2ed22021-05-19 07:16:10 -04001557 if (msync_session_get_clock_dev(avsync->fd, ppm))
1558 return CLK_RECOVERY_ERR;
1559
1560 if (*ppm == 0)
1561 return CLK_RECOVERY_ONGOING;
1562 else
1563 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001564}