blob: 0fd2dc58fc1e133c9d5700d4b1cc2e2457e76be8 [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
Song Zhaoe0bf6ad2021-07-09 11:28:42 -0700717 if (avsync->mode == AV_SYNC_MODE_FREE_RUN) {
718 /* render according to FPS */
719 if (!VALID_TS(avsync->last_r_syst) ||
720 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
721 avsync->last_r_syst = systime;
722 return true;
723 }
724 return false;
725 }
726
Song Zhaoc03ba122020-12-23 21:54:02 -0800727 if (!fpts) {
728 if (avsync->last_frame) {
729 /* try to accumulate duration as PTS */
730 fpts = avsync->vpts + avsync->last_frame->duration;
731 } else {
732 fpts = avsync->vpts;
733 }
734 }
735 systime += pts_correction;
736
737 /* phase adjustment */
738 if (avsync->phase_set)
739 systime += avsync->phase;
740
yongchun.lia50b1e92021-08-07 01:11:54 +0000741 log_trace("[%d]systime:%u phase:%d correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800742 avsync->session_id, systime,
yongchun.lia50b1e92021-08-07 01:11:54 +0000743 avsync->phase_set? (int)avsync->phase:0, pts_correction, fpts);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700744 if (abs_diff(systime, fpts) > avsync->disc_thres_min) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800745 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800746 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800747 return false;
748
Song Zhaoa2985cb2021-06-24 12:01:47 -0700749 if ((VALID_TS(avsync->last_log_syst) && avsync->last_log_syst != systime) ||
750 (VALID_TS(avsync->last_pts) && avsync->last_pts != fpts)) {
yongchun.li0ee6e372021-08-20 04:26:04 -0700751 struct timespec now;
Song Zhao5d2b4772021-01-18 16:40:08 -0800752
yongchun.li0ee6e372021-08-20 04:26:04 -0700753 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700754 avsync->last_log_syst = systime;
Song Zhao5d2b4772021-01-18 16:40:08 -0800755 avsync->last_pts = fpts;
756 if (time_diff(&now, &avsync->sync_lost_print_time) >=
757 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700758 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800759 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800760 avsync->sync_lost_cnt = 0;
yongchun.li0ee6e372021-08-20 04:26:04 -0700761 clock_gettime(CLOCK_MONOTONIC_RAW, &avsync->sync_lost_print_time);
Song Zhao5d2b4772021-01-18 16:40:08 -0800762 } else
763 avsync->sync_lost_cnt++;
764 }
Song Zhaod62bb392021-04-23 12:25:49 -0700765
766 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
767 LIVE_MODE(avsync->mode) &&
Song Zhaoa2985cb2021-06-24 12:01:47 -0700768 VALID_TS(avsync->last_pts) &&
Song Zhao065800e2021-05-26 15:56:06 -0700769 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700770 /* outlier by stream error */
771 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700772 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700773 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
774 log_info("render outlier %u", fpts);
775 return true;
776 }
777 }
778
779 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800780 avsync->state = AV_SYNC_STAT_SYNC_LOST;
781 avsync->phase_set = false;
Song Zhaode5f73b2021-07-23 22:38:07 -0700782 avsync->phase = 0;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800783 reset_pattern(avsync->pattern_detector);
Song Zhaoa2985cb2021-06-24 12:01:47 -0700784
785 if (LIVE_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaod62bb392021-04-23 12:25:49 -0700786 log_info ("[%d]video disc %u --> %u",
Song Zhaoa2985cb2021-06-24 12:01:47 -0700787 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700788 msync_session_set_video_dis(avsync->fd, fpts);
789 avsync->last_disc_pts = fpts;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700790 }
791
792 if ((int)(systime - fpts) > 0) {
793 if ((int)(systime - fpts) < avsync->disc_thres_max) {
794 /* catch up PCR */
Song Zhaof46932e2021-05-21 01:51:45 -0700795 return true;
Song Zhaoa2985cb2021-06-24 12:01:47 -0700796 } else {
797 /* render according to FPS */
798 if (!VALID_TS(avsync->last_r_syst) ||
799 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
800 avsync->last_r_syst = systime;
801 return true;
802 }
803 return false;
804 }
805 } else if (LIVE_MODE(avsync->mode)) {
806 /* hold if the gap is small */
807 if ((int)(fpts - systime) < avsync->disc_thres_max) {
808 return false;
809 } else {
810 /* render according to FPS */
811 if (!VALID_TS(avsync->last_r_syst) ||
812 (int)(systime - avsync->last_r_syst) >= avsync->fps_interval) {
813 avsync->last_r_syst = systime;
814 return true;
815 }
816 return false;
817 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800818 }
819 }
820
Song Zhao52f55192021-05-06 10:52:21 -0700821 /* In some cases, keeping pattern will enlarge the gap */
822 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
823 avsync->first_frame_toggled) {
824 reset_pattern(avsync->pattern_detector);
Song Zhaof46932e2021-05-21 01:51:45 -0700825 log_warn("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700826 systime, fpts);
827 }
828
Song Zhaoc03ba122020-12-23 21:54:02 -0800829 expire = (int)(systime - fpts) >= 0;
830
831 /* scatter the frame in different vsync whenever possible */
832 if (expire && next_frame && next_frame->pts && toggle_cnt) {
833 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhaoea5a0412021-01-18 16:40:08 -0800834 if (systime + interval < next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800835 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800836 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
837 avsync->session_id, systime, interval, next_frame->pts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800838 }
839 } else if (!expire && next_frame && next_frame->pts && !toggle_cnt
840 && avsync->first_frame_toggled) {
841 /* next vsync will have at least 2 frame expired */
Song Zhao35a82df2021-04-15 10:58:49 -0700842 if (systime + interval >= next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800843 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800844 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
845 avsync->session_id, systime, interval, next_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800846 }
847 }
848
Song Zhaoa58c3e92021-03-09 18:52:55 -0800849 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
850 correct_pattern(avsync->pattern_detector, frame, next_frame,
851 (avsync->last_frame?avsync->last_frame->hold_period:0),
852 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800853 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -0800854
855 if (expire) {
856 avsync->vpts = fpts;
857 /* phase adjustment */
858 if (!avsync->phase_set) {
yongchun.lia50b1e92021-08-07 01:11:54 +0000859 //always adjust to the half v-sync to give most pts tolerace and unify behavior
860 if ((int)(systime - fpts) >= 0 && (int)(fpts + interval - systime) > 0) {
861 avsync->phase = interval/2 + fpts - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800862 avsync->phase_set = true;
yongchun.lia50b1e92021-08-07 01:11:54 +0000863 log_info("[%d]adjust phase to %d", avsync->session_id, (int)avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800864 }
865 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800866 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -0800867 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800868 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -0800869 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800870 }
871 return expire;
872}
873
Song Zhao35a82df2021-04-15 10:58:49 -0700874static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -0800875{
Song Zhao35a82df2021-04-15 10:58:49 -0700876 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800877 log_trace("[%d]cur_period: %d last_period: %d",
878 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -0700879 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
880 ret = true;
881 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
882 ret = true;
883 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
884 ret = true;
885 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
886 ret = true;
887
888 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800889}
890
891int av_sync_set_speed(void *sync, float speed)
892{
893 struct av_sync_session *avsync = (struct av_sync_session *)sync;
894
895 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800896 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800897 return -1;
898 }
899
Song Zhaoea5a0412021-01-18 16:40:08 -0800900 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
901 avsync->mode == AV_SYNC_MODE_IPTV) {
902 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800903 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800904 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800905
Song Zhaoea5a0412021-01-18 16:40:08 -0800906 avsync->speed = speed;
907
908 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
909 if (speed == 1.0) {
910 avsync->mode = avsync->backup_mode;
911 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
912 } else {
913 avsync->backup_mode = avsync->mode;
914 avsync->mode = AV_SYNC_MODE_FREE_RUN;
915 log_info("[%d]audio to freerun mode", avsync->session_id);
916 }
917 }
918#if 0
Song Zhaoc03ba122020-12-23 21:54:02 -0800919 if (avsync->mode != AV_SYNC_MODE_VMASTER) {
920 log_info("ignore set speed in mode %d", avsync->mode);
921 return 0;
922 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800923#endif
Song Zhaoc03ba122020-12-23 21:54:02 -0800924
Song Zhaoea5a0412021-01-18 16:40:08 -0800925 log_info("session[%d] set rate to %f", avsync->session_id, speed);
926 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800927}
928
929int av_sync_change_mode(void *sync, enum sync_mode mode)
930{
931 struct av_sync_session *avsync = (struct av_sync_session *)sync;
932
933 if (!avsync)
934 return -1;
935
Song Zhaoea5a0412021-01-18 16:40:08 -0800936 if (msync_session_set_mode(avsync->fd, mode)) {
937 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800938 return -1;
939 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800940 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -0800941 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800942 return 0;
943}
944
Song Zhao01031bb2021-05-13 21:23:20 -0700945int av_sync_get_mode(void *sync, enum sync_mode *mode)
946{
947 struct av_sync_session *avsync = (struct av_sync_session *)sync;
948
949 if (!avsync || !mode)
950 return -1;
951
952 *mode = avsync->mode;
953 return 0;
954}
955
Song Zhaoc03ba122020-12-23 21:54:02 -0800956int av_sync_set_pause_pts(void *sync, pts90K pts)
957{
958 struct av_sync_session *avsync = (struct av_sync_session *)sync;
959
960 if (!avsync)
961 return -1;
962
963 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -0800964 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800965 return 0;
966}
967
968int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
969{
970 struct av_sync_session *avsync = (struct av_sync_session *)sync;
971
972 if (!avsync)
973 return -1;
974
975 avsync->pause_pts_cb = cb;
976 avsync->pause_cb_priv = priv;
977 return 0;
978}
Song Zhaoea5a0412021-01-18 16:40:08 -0800979
980static void trigger_audio_start_cb(struct av_sync_session *avsync,
981 avs_ascb_reason reason)
982{
983 if (avsync) {
984 pthread_mutex_lock(&avsync->lock);
985 if (avsync->audio_start) {
986 avsync->audio_start(avsync->audio_start_priv, reason);
987 avsync->session_started = true;
988 avsync->audio_start = NULL;
989 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
990 }
991 pthread_mutex_unlock(&avsync->lock);
992 }
993}
994
995avs_start_ret av_sync_audio_start(
996 void *sync,
997 pts90K pts,
998 pts90K delay,
999 audio_start_cb cb,
1000 void *priv)
1001{
1002 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1003 uint32_t start_mode;
yongchun.li59e873d2021-07-07 11:42:38 -07001004 uint32_t systime;
Song Zhaoea5a0412021-01-18 16:40:08 -08001005 avs_start_ret ret = AV_SYNC_ASTART_ERR;
1006 bool create_poll_t = false;
1007
1008 if (!avsync)
1009 return ret;
1010
yongchun.li59e873d2021-07-07 11:42:38 -07001011 log_info("%d av_sync_audio_start pts(ms) %d delay %d ms",
1012 avsync->session_id, (int)pts/90, (int)delay/90);
Song Zhaoea5a0412021-01-18 16:40:08 -08001013
yongchun.li59e873d2021-07-07 11:42:38 -07001014 if (avsync->in_audio_switch &&
1015 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)
1016 {
1017 start_mode = AVS_START_SYNC;
1018 log_info("%d AUDIO_SWITCH_STAT_AGAIN", avsync->session_id);
1019 } else {
1020 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
1021 log_error("[%d]fail to set audio start", avsync->session_id);
1022 }
1023 if (avsync->in_audio_switch &&
1024 (avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET ||
1025 avsync->audio_switch_state == AUDIO_SWITCH_STAT_AGAIN)) {
1026 msync_session_get_wall(avsync->fd, &systime, NULL);
1027 if ((int)(systime - pts) > A_ADJ_THREDHOLD_LB &&
1028 start_mode == AVS_START_SYNC) {
1029 log_info("%d audio_switch audio need drop first.ahead %d ms",
1030 avsync->session_id, (int)(systime - pts)/90);
1031 ret = AV_SYNC_ASTART_AGAIN;
1032 avsync->audio_switch_state = AUDIO_SWITCH_STAT_AGAIN;
1033 goto exit;
1034 }
1035 else {
1036 int diff = (int)(pts - systime);
1037 log_info("%d audio_switch_state to start mode %d diff %d ms",
1038 avsync->session_id, start_mode, diff/90);
1039 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
1040 if (diff < A_ADJ_THREDHOLD_LB) {
1041 log_info("%d orig mode %d already close enough direct start",
1042 avsync->session_id, start_mode);
1043 start_mode = AVS_START_SYNC;
1044 }
1045 }
yongchun.li107a6162021-05-05 02:38:57 -07001046 }
1047
Song Zhaoea5a0412021-01-18 16:40:08 -08001048 if (start_mode == AVS_START_SYNC) {
1049 ret = AV_SYNC_ASTART_SYNC;
1050 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -07001051 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -07001052 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001053 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -07001054 avsync->state = AV_SYNC_STAT_RUNNING;
1055 } else if (start_mode == AVS_START_AGAIN) {
1056 ret = AV_SYNC_ASTART_AGAIN;
1057 }
1058
1059 if (ret == AV_SYNC_ASTART_AGAIN)
1060 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -08001061
yongchun.li107a6162021-05-05 02:38:57 -07001062 if (avsync->mode == AV_SYNC_MODE_AMASTER || avsync->in_audio_switch) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001063 create_poll_t = true;
1064 if (start_mode == AVS_START_ASYNC) {
1065 if (!cb) {
1066 log_error("[%d]invalid cb", avsync->session_id);
1067 return AV_SYNC_ASTART_ERR;
1068 }
1069 avsync->audio_start = cb;
1070 avsync->audio_start_priv = priv;
1071 }
Song Zhaod62bb392021-04-23 12:25:49 -07001072 } else if (LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -08001073 create_poll_t = true;
1074
Song Zhaod62bb392021-04-23 12:25:49 -07001075 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -08001076 int ret;
1077
1078 log_info("[%d]start poll thread", avsync->session_id);
1079 avsync->quit_poll = false;
1080 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
1081 if (ret) {
1082 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
1083 return AV_SYNC_ASTART_ERR;
1084 }
1085 }
Song Zhaod62bb392021-04-23 12:25:49 -07001086 if (LIVE_MODE(avsync->mode)) {
Song Zhaod62bb392021-04-23 12:25:49 -07001087 msync_session_get_wall(avsync->fd, &systime, NULL);
1088 log_info("[%d]return %u w %u pts %u d %u",
1089 avsync->session_id, ret, systime, pts, delay);
1090 }
1091exit:
Song Zhaoea5a0412021-01-18 16:40:08 -08001092 log_info("[%d]return %u", avsync->session_id, ret);
1093 return ret;
1094}
1095
1096int av_sync_audio_render(
1097 void *sync,
1098 pts90K pts,
1099 struct audio_policy *policy)
1100{
1101 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -07001102 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -08001103 uint32_t systime;
1104 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1105 avs_audio_action action = AA_SYNC_AA_MAX;
1106
1107 if (!avsync || !policy)
1108 return -1;
1109
yongchun.li107a6162021-05-05 02:38:57 -07001110 msync_session_get_wall(avsync->fd, &systime, NULL);
1111
1112 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1113 pts, systime, avsync->mode, (int)(pts-systime)/90);
1114
1115 if (avsync->in_audio_switch
1116 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
1117 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
1118 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1119 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1120 action = AV_SYNC_AA_RENDER;
1121 } else if ((int)(systime - pts) > 0) {
1122 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1123 (int)(systime - pts)/90, systime, pts);
1124 action = AV_SYNC_AA_DROP;
1125 } else {
1126 action = AV_SYNC_AA_INSERT;
1127 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1128 (int)(pts - systime)/90, systime, pts);
1129 }
1130 goto done;
1131 }
1132
Song Zhaoea5a0412021-01-18 16:40:08 -08001133 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1134 avsync->mode == AV_SYNC_MODE_AMASTER) {
1135 action = AV_SYNC_AA_RENDER;
1136 goto done;
1137 }
1138
Song Zhaod62bb392021-04-23 12:25:49 -07001139 /* stopping procedure, unblock audio rendering */
1140 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER &&
1141 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1142 action = AV_SYNC_AA_DROP;
1143 goto done;
1144 }
1145
Song Zhao7daf3a12021-05-10 22:22:25 -07001146 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1147 avsync->mode == AV_SYNC_MODE_AMASTER) {
1148 action = AV_SYNC_AA_RENDER;
1149 goto done;
1150 }
1151
Song Zhaod62bb392021-04-23 12:25:49 -07001152 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1153 LIVE_MODE(avsync->mode) &&
1154 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1155 /* outlier by stream error */
1156 avsync->outlier_cnt++;
1157 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1158 /* treat as disc, just drop current frame */
1159 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1160 avsync->outlier_cnt = 0;
1161 action = AV_SYNC_AA_DROP;
1162 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001163 goto done;
1164 }
1165 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1166 pts = systime;
1167 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001168 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001169 goto done;
1170 }
1171
1172 avsync->outlier_cnt = 0;
1173 /* low bound from sync_lost to sync_setup */
1174 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1175 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1176 action = AV_SYNC_AA_RENDER;
1177 goto done;
1178 }
1179
1180 /* high bound of sync_setup */
1181 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1182 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1183 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001184 action = AV_SYNC_AA_RENDER;
1185 goto done;
1186 }
1187
1188 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001189 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001190 action = AV_SYNC_AA_DROP;
1191 goto done;
1192 }
1193
1194 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001195 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001196 action = AV_SYNC_AA_INSERT;
1197 goto done;
1198 }
1199
1200done:
1201 policy->action = action;
1202 policy->delta = (int)(systime - pts);
1203 if (action == AV_SYNC_AA_RENDER) {
1204 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001205 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001206 if (!out_lier)
1207 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001208 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001209 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001210 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1211 msync_session_update_apts(avsync->fd, systime, pts, 0);
1212 log_info("[%d] audio switch done sys %u pts %u",
1213 avsync->session_id, systime, pts);
1214 msync_session_set_audio_switch(avsync->fd, false);
1215 avsync->in_audio_switch = false;
1216 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1217 } else {
1218 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1219 avsync->session_id, action, systime, pts, systime - pts);
1220 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001221 avsync->audio_drop_cnt = 0;
Song Zhaoea5a0412021-01-18 16:40:08 -08001222 } else {
Song Zhaoa2985cb2021-06-24 12:01:47 -07001223 if (abs_diff(systime, pts) > avsync->disc_thres_min &&
yongchun.li085b5a42021-05-24 04:22:53 -07001224 avsync->last_disc_pts != pts &&
1225 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001226 log_info ("[%d]audio disc %u --> %u",
1227 avsync->session_id, systime, pts);
1228 msync_session_set_audio_dis(avsync->fd, pts);
1229 avsync->last_disc_pts = pts;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001230 } else if (action == AV_SYNC_AA_DROP) {
yongchun.li0ee6e372021-08-20 04:26:04 -07001231 struct timespec now;
Song Zhaoa2985cb2021-06-24 12:01:47 -07001232
1233 /* dropping recovery */
yongchun.li0ee6e372021-08-20 04:26:04 -07001234 clock_gettime(CLOCK_MONOTONIC_RAW, &now);
Song Zhaoa2985cb2021-06-24 12:01:47 -07001235 if (!avsync->audio_drop_cnt)
1236 avsync->audio_drop_start = now;
1237 avsync->audio_drop_cnt++;
1238 if (time_diff(&now, &avsync->audio_drop_start) > 500000) {
1239 log_info ("[%d]audio keep dropping sys %u vs a %u",
1240 avsync->session_id, systime, pts);
1241 msync_session_set_audio_dis(avsync->fd, pts);
1242 }
Song Zhao409739b2021-05-12 22:21:40 -07001243 }
Song Zhaoa2985cb2021-06-24 12:01:47 -07001244 if (action != AV_SYNC_AA_DROP)
1245 avsync->audio_drop_cnt = 0;
Song Zhaof46932e2021-05-21 01:51:45 -07001246 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001247 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001248 }
1249
1250 return ret;
1251}
1252
1253int av_sync_get_clock(void *sync, pts90K *pts)
1254{
1255 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1256
1257 if (!avsync || !pts)
1258 return -1;
1259 return msync_session_get_wall(avsync->fd, pts, NULL);
1260}
1261
1262static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001263 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001264{
bo.xiao1f94b352021-08-02 03:53:47 -04001265 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 -07001266 avsync->active_mode, avsync->mode, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001267 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1268 float speed;
1269 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaoe208d692021-04-19 15:38:52 -07001270 a_active && avsync->audio_start) {
yongchun.li107a6162021-05-05 02:38:57 -07001271 if (v_active || v_timeout || avsync->in_audio_switch) {
Song Zhaoe208d692021-04-19 15:38:52 -07001272 log_info("audio start cb");
1273 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
yongchun.li107a6162021-05-05 02:38:57 -07001274 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001275 }
1276
1277 if (!msync_session_get_rate(avsync->fd, &speed)) {
1278 /* speed change is triggered by asink,
1279 * attached audio HAL will handle it
1280 */
1281 if (speed != avsync->speed)
1282 log_info("[%d]new rate %f", avsync->session_id, speed);
1283 if (speed == 1.0) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001284 if (avsync->mode != avsync->backup_mode) {
1285 avsync->mode = avsync->backup_mode;
1286 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1287 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001288 } else {
1289 avsync->backup_mode = avsync->mode;
1290 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1291 log_info("[%d]audio to freerun mode", avsync->session_id);
1292 }
1293 avsync->speed = speed;
1294 }
Song Zhaod62bb392021-04-23 12:25:49 -07001295 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1296 struct session_debug debug;
1297 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001298 if (debug.debug_freerun && !avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001299 avsync->backup_mode = avsync->mode;
1300 avsync->mode = AV_SYNC_MODE_FREE_RUN;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001301 avsync->debug_freerun = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001302 log_warn("[%d]audio to freerun mode", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001303 } else if (!debug.debug_freerun && avsync->debug_freerun) {
Song Zhaod62bb392021-04-23 12:25:49 -07001304 avsync->mode = avsync->backup_mode;
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001305 avsync->debug_freerun = false;
Song Zhaod62bb392021-04-23 12:25:49 -07001306 log_warn("[%d]audio back to mode %d",
1307 avsync->session_id, avsync->mode);
1308 }
1309 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001310 }
1311}
1312
1313static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001314 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001315{
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001316 struct session_debug debug;
1317
bo.xiao1f94b352021-08-02 03:53:47 -04001318 log_info("[%d]av_sync amode mode %d %d v/a %d/%d", avsync->session_id,
Song Zhaoea5a0412021-01-18 16:40:08 -08001319 avsync->active_mode, avsync->mode, v_active, a_active);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001320 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1321 if (debug.debug_freerun && !avsync->debug_freerun) {
1322 avsync->backup_mode = avsync->mode;
1323 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1324 avsync->debug_freerun = true;
1325 log_warn("[%d]video to freerun mode", avsync->session_id);
1326 } else if (!debug.debug_freerun && avsync->debug_freerun) {
1327 avsync->mode = avsync->backup_mode;
1328 avsync->debug_freerun = false;
1329 log_warn("[%d]video back to mode %d",
1330 avsync->session_id, avsync->mode);
Song Zhaod62bb392021-04-23 12:25:49 -07001331 }
1332 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001333}
1334
1335static void * poll_thread(void * arg)
1336{
1337 int ret = 0;
1338 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1339 const int fd = avsync->fd;
1340 struct pollfd pfd = {
1341 /* default blocking capture */
1342 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1343 .fd = avsync->fd,
1344 };
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001345 enum src_flag sflag = SRC_A;
Song Zhaoea5a0412021-01-18 16:40:08 -08001346
1347 prctl (PR_SET_NAME, "avs_poll");
1348 log_info("[%d]enter", avsync->session_id);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001349
1350 if (avsync->type == AV_SYNC_TYPE_AUDIO)
1351 sflag = SRC_A;
1352 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
1353 sflag = SRC_V;
1354
Song Zhaoea5a0412021-01-18 16:40:08 -08001355 while (!avsync->quit_poll) {
1356 for (;;) {
1357 ret = poll(&pfd, 1, 10);
1358 if (ret > 0)
1359 break;
1360 if (avsync->quit_poll)
1361 goto exit;
1362 if (errno == EINTR)
1363 continue;
1364 }
1365
1366 /* error handling */
1367 if (pfd.revents & POLLERR)
1368 log_error("[%d]POLLERR received", avsync->session_id);
1369
Song Zhaod62bb392021-04-23 12:25:49 -07001370 /* mode change. Non-exclusive wait so all the processes
1371 * shall be woken up
1372 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001373 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001374 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -08001375
1376 msync_session_get_stat(fd, &avsync->active_mode,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001377 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch, sflag);
Song Zhaoea5a0412021-01-18 16:40:08 -08001378
1379 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhaoe208d692021-04-19 15:38:52 -07001380 handle_mode_change_a(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001381 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhaoe208d692021-04-19 15:38:52 -07001382 handle_mode_change_v(avsync, v_active, a_active, v_timeout);
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001383 usleep(10000);
Song Zhaoea5a0412021-01-18 16:40:08 -08001384 }
1385 }
1386exit:
1387 log_info("[%d]quit", avsync->session_id);
1388 return NULL;
1389}
1390
Song Zhao623e2f12021-09-03 15:54:04 -07001391#define DEMOD_NODE "/sys/class/dtvdemod/atsc_para"
1392/* return ppm between demod and PCR clock */
1393int32_t static dmod_get_sfo_dev(struct av_sync_session *avsync)
1394{
1395 int fd = -1, ppm = 0, nread;
1396 char buf[128];
1397 uint32_t reg_v, lock;
1398 float val;
1399
1400 fd = open(DEMOD_NODE, O_RDWR);
1401 if (fd < 0) {
1402 log_warn("node not found %s", DEMOD_NODE);
1403 /* do not retry */
1404 avsync->ppm_adjusted = true;
1405 return 0;
1406 }
1407 snprintf(buf, sizeof(buf), "%d", 5);
1408 write(fd, buf, 2);
1409
1410 lseek(fd, 0, SEEK_SET);
1411
1412 nread = read(fd, buf, sizeof(buf));
1413 if (nread <= 0) {
1414 log_error("read error");
1415 goto err;
1416 }
1417 buf[nread] = 0;
1418 if (sscanf(buf, "ck=0x%x lock=%d", &reg_v, &lock) != 2) {
1419 log_error("wrong format %s", buf);
1420 goto err;
1421 }
1422 if (lock != 0x1f) {
1423 log_info("demod not locked");
1424 goto err;
1425 }
1426 if (reg_v > ((2 << 20) - 1))
1427 reg_v -= (2 << 21);
1428 val = reg_v * 10.762238f / 12 * 1000000 / (2 << 25);
1429 ppm = val;
1430 log_info("ppm from SFO %d", ppm);
1431 avsync->ppm_adjusted = true;
1432
1433err:
1434 if (fd >= 0)
1435 close(fd);
1436 return ppm;
1437}
1438
Song Zhaod62bb392021-04-23 12:25:49 -07001439int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001440{
1441 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001442 struct pcr_info pcr;
1443 enum pcr_monitor_status status;
1444 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001445 if (!avsync)
1446 return -1;
1447
1448 if (avsync->type != AV_SYNC_TYPE_PCR)
1449 return -2;
1450
Song Zhao623e2f12021-09-03 15:54:04 -07001451 /* initial estimation from Demod SFO HW */
1452 if (!avsync->ppm_adjusted) {
1453 ppm = dmod_get_sfo_dev(avsync);
1454 if (ppm != 0) {
1455 /* ppm > 0 means board clock is faster */
1456 msync_session_set_clock_dev(avsync->fd, -ppm);
1457 }
1458 }
wei.dubcc2ed22021-05-19 07:16:10 -04001459 pcr.monoclk = mono_clock / 1000;
1460 pcr.pts = (long long) pts * 1000 / 90;
1461 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1462
1463 status = pcr_monitor_get_status(avsync->pcr_monitor);
1464
1465 if (status >= DEVIATION_READY) {
1466 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1467 if (avsync->ppm != ppm) {
1468 avsync->ppm = ppm;
1469 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1470 if (msync_session_set_clock_dev(avsync->fd, ppm))
1471 log_error("set clock dev fail");
Song Zhao623e2f12021-09-03 15:54:04 -07001472 else
1473 avsync->ppm_adjusted = true;
wei.dubcc2ed22021-05-19 07:16:10 -04001474 }
1475 }
1476
Song Zhaod62bb392021-04-23 12:25:49 -07001477 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001478}
1479
Song Zhaod62bb392021-04-23 12:25:49 -07001480int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001481{
1482 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1483
1484 if (!avsync)
1485 return -1;
1486
Song Zhaod62bb392021-04-23 12:25:49 -07001487 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001488}
1489
1490int av_sync_set_session_name(void *sync, const char *name)
1491{
1492 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1493
1494 if (!avsync)
1495 return -1;
1496
1497 return msync_session_set_name(avsync->fd, name);
1498}
yongchun.li107a6162021-05-05 02:38:57 -07001499
1500int av_sync_set_audio_switch(void *sync, bool start)
1501{
1502 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1503 bool v_active, a_active, v_timeout;
1504
1505 if (!avsync)
1506 return -1;
1507 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
1508 &v_active, &a_active,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001509 &v_timeout, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001510 log_error("[%d] can not get session state",
1511 avsync->session_id);
1512 return -1;
1513 }
1514 if (!v_active || !a_active) {
1515 log_error("[%d] no apply if not AV both active v %d a %d",
1516 avsync->session_id, v_active, a_active);
1517 return -1;
1518 }
1519 if (msync_session_set_audio_switch(avsync->fd, start)) {
1520 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1521 return -1;
1522 }
1523 avsync->in_audio_switch = start;
1524 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1525 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1526 return 0;
1527}
1528
1529int av_sync_get_audio_switch(void *sync, bool *start)
1530{
1531 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1532
1533 if (!avsync)
1534 return -1;
1535 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
Song Zhaoe0bf6ad2021-07-09 11:28:42 -07001536 NULL, NULL, NULL, &avsync->in_audio_switch, SRC_A)) {
yongchun.li107a6162021-05-05 02:38:57 -07001537 log_error("[%d] can not audio seamless switch state",
1538 avsync->session_id);
1539 return -1;
1540 }
1541 if (start) *start = avsync->in_audio_switch;
1542 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001543}
Song Zhao8039f562021-05-18 18:11:25 -07001544
Song Zhao623e2f12021-09-03 15:54:04 -07001545enum clock_recovery_stat av_sync_get_clock_deviation(void *sync, int32_t *ppm)
Song Zhao8039f562021-05-18 18:11:25 -07001546{
1547 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1548
wei.dubcc2ed22021-05-19 07:16:10 -04001549 if (!avsync || !ppm)
1550 return CLK_RECOVERY_ERR;
1551 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001552 return CLK_RECOVERY_NOT_RUNNING;
1553
wei.dubcc2ed22021-05-19 07:16:10 -04001554 if (msync_session_get_clock_dev(avsync->fd, ppm))
1555 return CLK_RECOVERY_ERR;
1556
1557 if (*ppm == 0)
1558 return CLK_RECOVERY_ONGOING;
1559 else
1560 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001561}