blob: b0f136f858e8f3177e42bee3058b55b3a47f8bc7 [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>
21#include <unistd.h>
22//#include <linux/amlogic/msync.h>
Song Zhaoc03ba122020-12-23 21:54:02 -080023#include "aml_avsync.h"
24#include "queue.h"
25#include "pattern.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080026#include "aml_avsync_log.h"
Song Zhaoea5a0412021-01-18 16:40:08 -080027#include "msync_util.h"
28#include "msync.h"
29#include <pthread.h>
wei.dubcc2ed22021-05-19 07:16:10 -040030#include "pcr_monitor.h"
Song Zhaoc03ba122020-12-23 21:54:02 -080031enum sync_state {
32 AV_SYNC_STAT_INIT = 0,
33 AV_SYNC_STAT_RUNNING = 1,
34 AV_SYNC_STAT_SYNC_SETUP = 2,
35 AV_SYNC_STAT_SYNC_LOST = 3,
36};
37
yongchun.li107a6162021-05-05 02:38:57 -070038enum audio_switch_state_ {
39 AUDIO_SWITCH_STAT_INIT = 0,
40 AUDIO_SWITCH_STAT_RESET = 1,
41 AUDIO_SWITCH_STAT_START = 2,
42 AUDIO_SWITCH_STAT_FINISH = 3,
43};
44
Song Zhaoea5a0412021-01-18 16:40:08 -080045#define SESSION_DEV "avsync_s"
46
Song Zhaoc03ba122020-12-23 21:54:02 -080047struct av_sync_session {
48 /* session id attached */
49 int session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -080050 int fd;
51 bool attached;
52 enum sync_mode mode;
53 /* for audio trickplay */
54 enum sync_mode backup_mode;
55 enum sync_type type;
56 uint32_t start_policy;
Song Zhaoc03ba122020-12-23 21:54:02 -080057
Song Zhaoea5a0412021-01-18 16:40:08 -080058 /* playback time, will stop increasing during pause */
59 pts90K vpts;
60 pts90K apts;
61
62 /* phase adjustment of stream time for rate control (Video ONLY) */
Song Zhaoc03ba122020-12-23 21:54:02 -080063 pts90K phase;
64 bool phase_set;
65
66 /* pts of last rendered frame */
Song Zhaoea5a0412021-01-18 16:40:08 -080067 pts90K last_wall;
Song Zhaoc03ba122020-12-23 21:54:02 -080068 pts90K last_pts;
69 struct vframe *last_frame;
70
71 bool first_frame_toggled;
72 /* Whether in pause state */
73 bool paused;
Song Zhaoea5a0412021-01-18 16:40:08 -080074 enum sync_state state;
Song Zhaoc03ba122020-12-23 21:54:02 -080075 void *pattern_detector;
76 void *frame_q;
Song Zhaoc03ba122020-12-23 21:54:02 -080077
Song Zhaoea5a0412021-01-18 16:40:08 -080078 /* start control */
79 int start_thres;
80 audio_start_cb audio_start;
81 void *audio_start_priv;
82
83 /* render property */
Song Zhaoc03ba122020-12-23 21:54:02 -080084 int delay;
85 pts90K vsync_interval;
86
87 /* state lock */
88 pthread_mutex_t lock;
89 /* pattern */
90 int last_holding_peroid;
Song Zhaoea5a0412021-01-18 16:40:08 -080091 bool session_started;
Song Zhaoc03ba122020-12-23 21:54:02 -080092
93 float speed;
94
Song Zhaoc03ba122020-12-23 21:54:02 -080095 /* pause pts */
96 pts90K pause_pts;
97 pause_pts_done pause_pts_cb;
98 void *pause_cb_priv;
Song Zhao5d2b4772021-01-18 16:40:08 -080099
100 /* log control */
101 uint32_t last_systime;
102 uint32_t sync_lost_cnt;
103 struct timeval sync_lost_print_time;
Song Zhaoea5a0412021-01-18 16:40:08 -0800104
105 pthread_t poll_thread;
106 /* pcr master, IPTV only */
107 bool quit_poll;
108 enum sync_mode active_mode;
Song Zhaof46932e2021-05-21 01:51:45 -0700109 uint32_t disc_thres_min;
110 uint32_t disc_thres_max;
Song Zhao35a82df2021-04-15 10:58:49 -0700111
112 /* error detection */
113 uint32_t last_poptime;
Song Zhaod62bb392021-04-23 12:25:49 -0700114 uint32_t outlier_cnt;
Song Zhao409739b2021-05-12 22:21:40 -0700115 pts90K last_disc_pts;
116
yongchun.li107a6162021-05-05 02:38:57 -0700117 // indicate set audio switch
118 bool in_audio_switch;
119 enum audio_switch_state_ audio_switch_state;
wei.dubcc2ed22021-05-19 07:16:10 -0400120
121 //pcr monitor handle
122 void *pcr_monitor;
123 int ppm;
Song Zhaoc03ba122020-12-23 21:54:02 -0800124};
125
126#define MAX_FRAME_NUM 32
127#define DEFAULT_START_THRESHOLD 2
128#define TIME_UNIT90K (90000)
Song Zhaof46932e2021-05-21 01:51:45 -0700129#define AV_DISC_THRES_MIN (TIME_UNIT90K / 3)
130#define AV_DISC_THRES_MAX (TIME_UNIT90K * 10)
Song Zhao7daf3a12021-05-10 22:22:25 -0700131#define A_ADJ_THREDHOLD_HB (900 * 6) //60ms
132#define A_ADJ_THREDHOLD_LB (900 * 2) //20ms
Song Zhao52f55192021-05-06 10:52:21 -0700133#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800134#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhaod62bb392021-04-23 12:25:49 -0700135#define LIVE_MODE(mode) ((mode) == AV_SYNC_MODE_PCR_MASTER || (mode) == AV_SYNC_MODE_IPTV)
136
Song Zhao065800e2021-05-26 15:56:06 -0700137#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
Song Zhaod62bb392021-04-23 12:25:49 -0700138#define OUTLIER_MAX_CNT 8
Song Zhaoc03ba122020-12-23 21:54:02 -0800139
140static uint64_t time_diff (struct timeval *b, struct timeval *a);
141static bool frame_expire(struct av_sync_session* avsync,
142 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800143 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800144 struct vframe * frame,
145 struct vframe * next_frame,
146 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700147static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800148 int cur_period,
149 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800150static void * poll_thread(void * arg);
151static void trigger_audio_start_cb(struct av_sync_session *avsync,
152 avs_ascb_reason reason);
Song Zhaoc03ba122020-12-23 21:54:02 -0800153
Song Zhaoea5a0412021-01-18 16:40:08 -0800154int av_sync_open_session(int *session_id)
155{
156 int fd = msync_create_session();
157 int id, rc;
158
159 if (fd < 0) {
160 log_error("fail");
161 return -1;
162 }
163 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
164 if (rc) {
165 log_error("new session errno:%d", errno);
166 return rc;
167 }
168 *session_id = id;
169 return fd;
170}
171
172void av_sync_close_session(int session)
173{
174 msync_destory_session(session);
175}
176
177static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800178 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800179 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800180 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800181 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800182{
183 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800184 char dev_name[20];
Song Zhaoc03ba122020-12-23 21:54:02 -0800185
186 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
187 if (!avsync) {
188 log_error("OOM");
189 return NULL;
190 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800191
192 if (type == AV_SYNC_TYPE_VIDEO) {
193 avsync->pattern_detector = create_pattern_detector();
194 if (!avsync->pattern_detector) {
195 log_error("pd create fail");
196 goto err;
197 }
198
199 if (!start_thres)
200 avsync->start_thres = DEFAULT_START_THRESHOLD;
201 else {
202 if (start_thres > 5) {
203 log_error("start_thres too big: %d", start_thres);
204 goto err2;
205 }
206 avsync->start_thres = start_thres;
207 }
208 avsync->phase_set = false;
209 avsync->first_frame_toggled = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800210 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800211
212 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800213 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800214 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800215 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800216 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800217 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800218 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800219 avsync->speed = 1.0f;
220 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhao409739b2021-05-12 22:21:40 -0700221 avsync->vsync_interval = -1;
222 avsync->last_disc_pts = -1;
Song Zhaof46932e2021-05-21 01:51:45 -0700223 if (msync_session_get_disc_thres(session_id,
224 &avsync->disc_thres_min, &avsync->disc_thres_max)) {
225 log_error("fail to get disc thres", dev_name, errno);
226 avsync->disc_thres_min = AV_DISC_THRES_MIN;
227 avsync->disc_thres_max = AV_DISC_THRES_MAX;
228 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800229
230 pthread_mutex_init(&avsync->lock, NULL);
Song Zhaof46932e2021-05-21 01:51:45 -0700231 log_info("[%d] mode %d type %d start_thres %d disc_thres %u/%u",
232 session_id, mode, type, start_thres,
233 avsync->disc_thres_min, avsync->disc_thres_max);
Song Zhaoea5a0412021-01-18 16:40:08 -0800234
235 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
236 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
237 if (avsync->fd < 0) {
238 log_error("open %s errno %d", dev_name, errno);
239 goto err2;
240 }
241
wei.dubcc2ed22021-05-19 07:16:10 -0400242 if (avsync->type == AV_SYNC_TYPE_PCR) {
243 if (pcr_monitor_init(&avsync->pcr_monitor)) {
244 log_error("pcr monitor init");
245 goto err2;
246 }
247 }
248
Song Zhaoea5a0412021-01-18 16:40:08 -0800249 if (!attach) {
250 msync_session_set_mode(avsync->fd, mode);
251 avsync->mode = mode;
252 } else {
253 avsync->attached = true;
254 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
255 log_error("get mode");
wei.dubcc2ed22021-05-19 07:16:10 -0400256 goto err3;
Song Zhaoea5a0412021-01-18 16:40:08 -0800257 }
258 avsync->backup_mode = avsync->mode;
259 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy)) {
260 log_error("get policy");
wei.dubcc2ed22021-05-19 07:16:10 -0400261 goto err3;
Song Zhaoea5a0412021-01-18 16:40:08 -0800262 }
yongchun.li107a6162021-05-05 02:38:57 -0700263 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
264 NULL, NULL, NULL, &avsync->in_audio_switch)) {
265 log_error("get state");
wei.dubcc2ed22021-05-19 07:16:10 -0400266 goto err3;
yongchun.li107a6162021-05-05 02:38:57 -0700267 }
268 if (avsync->in_audio_switch) {
269 log_info("audio_switch_state reseted the audio");
270 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
271 }
272
Song Zhaoea5a0412021-01-18 16:40:08 -0800273 log_info("[%d]retrieve sync mode %d policy %d",
274 session_id, avsync->mode, avsync->start_policy);
275 }
276
Song Zhaoc03ba122020-12-23 21:54:02 -0800277 return avsync;
wei.dubcc2ed22021-05-19 07:16:10 -0400278err3:
279 if (avsync->pcr_monitor)
280 pcr_monitor_destroy(avsync->pcr_monitor);
Song Zhaoea5a0412021-01-18 16:40:08 -0800281err2:
282 destroy_pattern_detector(avsync->pattern_detector);
283err:
284 free(avsync);
285 return NULL;
286}
287
288void* av_sync_create(int session_id,
289 enum sync_mode mode,
290 enum sync_type type,
291 int start_thres)
292{
293 return create_internal(session_id, mode,
294 type, start_thres, false);
295}
296
297void* av_sync_attach(int session_id, enum sync_type type)
298{
299 return create_internal(session_id, AV_SYNC_MODE_MAX,
300 type, 0, true);
301}
302
303int av_sync_video_config(void *sync, struct video_config* config)
304{
305 struct av_sync_session *avsync = (struct av_sync_session *)sync;
306
307 if (!avsync || !config)
308 return -1;
309
310 if (config->delay != 1 && config->delay != 2) {
311 log_error("invalid delay: %d\n", config->delay);
312 return -1;
313 }
314
315 avsync->delay = config->delay;
316
317 log_info("[%d] delay: %d",
318 avsync->session_id, config->delay);
319 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800320}
321
322static int internal_stop(struct av_sync_session *avsync)
323{
324 int ret = 0;
325 struct vframe *frame;
326
327 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800328 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
329 frame->free(frame);
330 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800331 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800332 pthread_mutex_unlock(&avsync->lock);
333 return ret;
334}
335
336/* destroy and detach from kernel session */
337void av_sync_destroy(void *sync)
338{
339 struct av_sync_session *avsync = (struct av_sync_session *)sync;
340
341 if (!avsync)
342 return;
343
Song Zhaoea5a0412021-01-18 16:40:08 -0800344 log_info("[%d]begin", avsync->session_id);
345 if (avsync->state != AV_SYNC_STAT_INIT) {
346 if (avsync->type == AV_SYNC_TYPE_VIDEO)
347 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800348
Song Zhaoea5a0412021-01-18 16:40:08 -0800349 avsync->quit_poll = true;
350 if (avsync->poll_thread) {
351 pthread_join(avsync->poll_thread, NULL);
352 avsync->poll_thread = 0;
353 }
354 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoaf368d52021-02-17 17:53:45 -0800355 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800356
Song Zhaoea5a0412021-01-18 16:40:08 -0800357 if (avsync->session_started) {
358 if (avsync->type == AV_SYNC_TYPE_VIDEO)
359 msync_session_set_video_stop(avsync->fd);
360 else
361 msync_session_set_audio_stop(avsync->fd);
362 }
wei.dubcc2ed22021-05-19 07:16:10 -0400363
364 if(avsync->pcr_monitor)
365 pcr_monitor_destroy(avsync->pcr_monitor);
366
Song Zhaoea5a0412021-01-18 16:40:08 -0800367 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800368 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800369 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
370 destroy_q(avsync->frame_q);
371 destroy_pattern_detector(avsync->pattern_detector);
372 }
373 log_info("[%d]done", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800374 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800375}
376
377int avs_sync_set_start_policy(void *sync, enum sync_start_policy policy)
378{
379 struct av_sync_session *avsync = (struct av_sync_session *)sync;
380
381 if (!avsync || !avsync->fd)
382 return -1;
383
384 log_info("[%d]policy %u --> %u", avsync->start_policy, policy);
385 avsync->start_policy = policy;
386 /* v_peek will be handled by libamlavsync */
387 if (policy != AV_SYNC_START_NONE &&
388 policy != AV_SYNC_START_V_PEEK)
389 return msync_session_set_start_policy(avsync->fd, policy);
390
391 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800392}
393
394int av_sync_pause(void *sync, bool pause)
395{
396 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700397 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800398 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800399
400 if (!avsync)
401 return -1;
402
Song Zhaoea5a0412021-01-18 16:40:08 -0800403 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
404 return -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800405
yongchun.li107a6162021-05-05 02:38:57 -0700406 rc = msync_session_get_stat(avsync->fd, &avsync->active_mode,
407 &v_active, &a_active, &v_timeout,
408 &avsync->in_audio_switch);
409
Song Zhaoea5a0412021-01-18 16:40:08 -0800410 /* ignore */
yongchun.li107a6162021-05-05 02:38:57 -0700411 if (avsync->mode == AV_SYNC_MODE_AMASTER
412 && avsync->type == AV_SYNC_TYPE_VIDEO
413 && a_active && !avsync->in_audio_switch)
Song Zhaoc03ba122020-12-23 21:54:02 -0800414 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800415
yongchun.li107a6162021-05-05 02:38:57 -0700416 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
417 log_info("[%d] ignore the pause from audio", avsync->session_id);
418 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
419 return 0;
420 }
421
Song Zhaoea5a0412021-01-18 16:40:08 -0800422 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800423 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800424 log_info("[%d]paused:%d type:%d rc %d",
425 avsync->session_id, pause, avsync->type, rc);
Song Zhaoc03ba122020-12-23 21:54:02 -0800426
Song Zhaoea5a0412021-01-18 16:40:08 -0800427 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800428}
429
430int av_sync_push_frame(void *sync , struct vframe *frame)
431{
432 int ret;
433 struct vframe *prev;
434 struct av_sync_session *avsync = (struct av_sync_session *)sync;
435
436 if (!avsync)
437 return -1;
438
Song Zhaoea5a0412021-01-18 16:40:08 -0800439 if (!avsync->frame_q) {
440 /* policy should be final now */
441 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy)) {
442 log_error("[%d]get policy", avsync->session_id);
443 return -1;
444 }
445
446 avsync->frame_q = create_q(MAX_FRAME_NUM);
447 if (!avsync->frame_q) {
448 log_error("[%d]create queue fail", avsync->session_id);
449 return -1;
450 }
451
452 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
453 avsync->mode == AV_SYNC_MODE_IPTV) {
454 int ret;
455
456 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
457 if (ret) {
458 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
459 destroy_q(avsync->frame_q);
460 return -1;
461 }
462 }
463 }
464
Song Zhaoc03ba122020-12-23 21:54:02 -0800465 if (!peek_item(avsync->frame_q, (void **)&prev, 0)) {
Song Zhaod62bb392021-04-23 12:25:49 -0700466 if (prev->pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800467 dqueue_item(avsync->frame_q, (void **)&prev);
468 prev->free(prev);
Song Zhaoea5a0412021-01-18 16:40:08 -0800469 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800470 }
471 }
472
Song Zhao065800e2021-05-26 15:56:06 -0700473 if (frame->duration == -1)
474 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800475 frame->hold_period = 0;
476 ret = queue_item(avsync->frame_q, frame);
477 if (avsync->state == AV_SYNC_STAT_INIT &&
478 queue_size(avsync->frame_q) >= avsync->start_thres) {
479 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaoea5a0412021-01-18 16:40:08 -0800480 log_info("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800481 }
482
483 if (ret)
484 log_error("%s queue fail:%d", ret);
Song Zhaoea5a0412021-01-18 16:40:08 -0800485 log_debug("[%d]push %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800486 return ret;
487
488}
489
490struct vframe *av_sync_pop_frame(void *sync)
491{
Song Zhaoea5a0412021-01-18 16:40:08 -0800492 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800493 struct av_sync_session *avsync = (struct av_sync_session *)sync;
494 int toggle_cnt = 0;
495 uint32_t systime;
Song Zhao468fd652021-01-15 22:13:04 -0800496 bool pause_pts_reached = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800497 uint32_t interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800498
499 pthread_mutex_lock(&avsync->lock);
500 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhaod62bb392021-04-23 12:25:49 -0700501 log_info("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800502 goto exit;
503 }
504
Song Zhaoea5a0412021-01-18 16:40:08 -0800505 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700506 uint32_t pts;
507
Song Zhaoc03ba122020-12-23 21:54:02 -0800508 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800509 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800510 goto exit;
511 }
Song Zhao35a82df2021-04-15 10:58:49 -0700512 msync_session_get_wall(avsync->fd, &systime, &interval);
513 pts = frame->pts - avsync->delay * interval;
514 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800515 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700516 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800517 }
518
Song Zhaoea5a0412021-01-18 16:40:08 -0800519 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700520 !avsync->first_frame_toggled &&
521 !msync_clock_started(avsync->fd)) {
522 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800523 log_trace("[%d]clock not started", avsync->session_id);
524 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800525 }
526
Song Zhaoea5a0412021-01-18 16:40:08 -0800527 enter_last_frame = avsync->last_frame;
528 msync_session_get_wall(avsync->fd, &systime, &interval);
529
530 /* handle refresh rate change */
531 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
532 avsync->vsync_interval != interval) {
533 log_info("[%d]vsync interval update %d --> %u",
534 avsync->session_id, avsync->vsync_interval, interval);
535 avsync->vsync_interval = interval;
536 avsync->phase_set = false;
537 reset_pattern(avsync->pattern_detector);
538 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800539 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
540 struct vframe *next_frame = NULL;
541
542 peek_item(avsync->frame_q, (void **)&next_frame, 1);
543 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700544 log_debug("[%d]cur_f %u next_f %u size %d",
545 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800546 if (frame_expire(avsync, systime, interval,
547 frame, next_frame, toggle_cnt)) {
548 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800549 toggle_cnt++;
550
Song Zhao35a82df2021-04-15 10:58:49 -0700551 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800552 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao35a82df2021-04-15 10:58:49 -0700553 avsync->last_holding_peroid))
554 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
555
Song Zhaoc03ba122020-12-23 21:54:02 -0800556 if (avsync->last_frame)
557 avsync->last_holding_peroid = avsync->last_frame->hold_period;
558
559 dqueue_item(avsync->frame_q, (void **)&frame);
560 if (avsync->last_frame) {
561 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800562 if (toggle_cnt > 1) {
Song Zhao35a82df2021-04-15 10:58:49 -0700563 log_debug("[%d]free %u cur %u system/d %u/%u", avsync->session_id,
564 avsync->last_frame->pts, frame->pts, systime, systime - avsync->last_poptime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800565 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800566 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800567 } else {
568 avsync->first_frame_toggled = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800569 log_info("[%d]first frame %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800570 }
571 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800572 avsync->last_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800573 } else
574 break;
575 }
576
577 /* pause pts */
578 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800579 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800580 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800581 else
Song Zhao468fd652021-01-15 22:13:04 -0800582 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
583 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
584 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
585 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
586 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800587
Song Zhao468fd652021-01-15 22:13:04 -0800588 if (pause_pts_reached) {
589 if (avsync->pause_pts_cb)
590 avsync->pause_pts_cb(avsync->pause_pts,
Song Zhaoc03ba122020-12-23 21:54:02 -0800591 avsync->pause_cb_priv);
592
Song Zhao468fd652021-01-15 22:13:04 -0800593 /* stay in paused until av_sync_pause(false) */
594 avsync->paused = true;
595 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoea5a0412021-01-18 16:40:08 -0800596 log_info ("[%d]reach pause pts: %u",
597 avsync->session_id, avsync->last_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800598 }
599
600exit:
601 pthread_mutex_unlock(&avsync->lock);
602 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800603 if (enter_last_frame != avsync->last_frame)
604 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhao35a82df2021-04-15 10:58:49 -0700605 log_trace("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhao065800e2021-05-26 15:56:06 -0700606 /* don't update vpts for out_lier */
607 if (avsync->last_frame->duration != -1)
608 msync_session_update_vpts(avsync->fd, systime,
609 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800610 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800611 if (enter_last_frame != avsync->last_frame)
612 log_debug("[%d]pop (nil)", avsync->session_id);
613
Song Zhao35a82df2021-04-15 10:58:49 -0700614 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800615 if (avsync->last_frame)
616 avsync->last_frame->hold_period++;
617 return avsync->last_frame;
618}
619
Song Zhaoc03ba122020-12-23 21:54:02 -0800620static inline uint32_t abs_diff(uint32_t a, uint32_t b)
621{
Song Zhaoea5a0412021-01-18 16:40:08 -0800622 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800623}
624
625static uint64_t time_diff (struct timeval *b, struct timeval *a)
626{
627 return (b->tv_sec - a->tv_sec)*1000000 + (b->tv_usec - a->tv_usec);
628}
629
Song Zhaoc03ba122020-12-23 21:54:02 -0800630static bool frame_expire(struct av_sync_session* avsync,
631 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800632 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800633 struct vframe * frame,
634 struct vframe * next_frame,
635 int toggle_cnt)
636{
637 uint32_t fpts = frame->pts;
638 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800639 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800640
Song Zhaod62bb392021-04-23 12:25:49 -0700641 if (avsync->mode == AV_SYNC_MODE_FREE_RUN)
642 return true;
643
Song Zhaoc03ba122020-12-23 21:54:02 -0800644 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
645 return false;
646
647 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
648 return true;
649
650 if (!fpts) {
651 if (avsync->last_frame) {
652 /* try to accumulate duration as PTS */
653 fpts = avsync->vpts + avsync->last_frame->duration;
654 } else {
655 fpts = avsync->vpts;
656 }
657 }
658 systime += pts_correction;
659
660 /* phase adjustment */
661 if (avsync->phase_set)
662 systime += avsync->phase;
663
Song Zhao35a82df2021-04-15 10:58:49 -0700664 log_trace("[%d]systime:%u phase:%u correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800665 avsync->session_id, systime,
Song Zhao35a82df2021-04-15 10:58:49 -0700666 avsync->phase_set?avsync->phase:0, pts_correction, fpts);
Song Zhaof46932e2021-05-21 01:51:45 -0700667 if (abs_diff(systime, fpts) > avsync->disc_thres_min &&
Song Zhaoc03ba122020-12-23 21:54:02 -0800668 avsync->first_frame_toggled) {
669 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800670 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800671 return false;
672
Song Zhao5d2b4772021-01-18 16:40:08 -0800673 if (avsync->last_systime != systime || avsync->last_pts != fpts) {
674 struct timeval now;
675
676 gettimeofday(&now, NULL);
677 avsync->last_systime = systime;
678 avsync->last_pts = fpts;
679 if (time_diff(&now, &avsync->sync_lost_print_time) >=
680 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700681 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800682 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800683 avsync->sync_lost_cnt = 0;
Song Zhaobc6161d2021-03-08 09:59:33 -0800684 gettimeofday(&avsync->sync_lost_print_time, NULL);
Song Zhao5d2b4772021-01-18 16:40:08 -0800685 } else
686 avsync->sync_lost_cnt++;
687 }
Song Zhaod62bb392021-04-23 12:25:49 -0700688
689 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
690 LIVE_MODE(avsync->mode) &&
Song Zhao065800e2021-05-26 15:56:06 -0700691 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700692 /* outlier by stream error */
693 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700694 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700695 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
696 log_info("render outlier %u", fpts);
697 return true;
698 }
699 }
700
701 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800702 avsync->state = AV_SYNC_STAT_SYNC_LOST;
703 avsync->phase_set = false;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800704 reset_pattern(avsync->pattern_detector);
Song Zhaoc03ba122020-12-23 21:54:02 -0800705 if ((int)(systime - fpts) > 0) {
Song Zhao409739b2021-05-12 22:21:40 -0700706 if (LIVE_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800707 log_info ("[%d]video disc %u --> %u",
708 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700709 msync_session_set_video_dis(avsync->fd, fpts);
710 avsync->last_disc_pts = fpts;
Song Zhaoea5a0412021-01-18 16:40:08 -0800711 }
Song Zhaod62bb392021-04-23 12:25:49 -0700712 /* catch up PCR */
Song Zhaoc03ba122020-12-23 21:54:02 -0800713 return true;
Song Zhao409739b2021-05-12 22:21:40 -0700714 } else if (LIVE_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaof46932e2021-05-21 01:51:45 -0700715 /* vpts wrapping or vpts gapping */
Song Zhaod62bb392021-04-23 12:25:49 -0700716 log_info ("[%d]video disc %u --> %u",
717 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700718 msync_session_set_video_dis(avsync->fd, fpts);
719 avsync->last_disc_pts = fpts;
Song Zhaof46932e2021-05-21 01:51:45 -0700720 /* clean up frames for wrapping case */
721 if ((int)(fpts - systime) > avsync->disc_thres_max)
722 return true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800723 }
724 }
725
Song Zhao52f55192021-05-06 10:52:21 -0700726 /* In some cases, keeping pattern will enlarge the gap */
727 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
728 avsync->first_frame_toggled) {
729 reset_pattern(avsync->pattern_detector);
Song Zhaof46932e2021-05-21 01:51:45 -0700730 log_warn("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700731 systime, fpts);
732 }
733
Song Zhaoc03ba122020-12-23 21:54:02 -0800734 expire = (int)(systime - fpts) >= 0;
735
736 /* scatter the frame in different vsync whenever possible */
737 if (expire && next_frame && next_frame->pts && toggle_cnt) {
738 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhaoea5a0412021-01-18 16:40:08 -0800739 if (systime + interval < next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800740 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800741 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
742 avsync->session_id, systime, interval, next_frame->pts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800743 }
744 } else if (!expire && next_frame && next_frame->pts && !toggle_cnt
745 && avsync->first_frame_toggled) {
746 /* next vsync will have at least 2 frame expired */
Song Zhao35a82df2021-04-15 10:58:49 -0700747 if (systime + interval >= next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800748 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800749 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
750 avsync->session_id, systime, interval, next_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800751 }
752 }
753
Song Zhaoa58c3e92021-03-09 18:52:55 -0800754 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
755 correct_pattern(avsync->pattern_detector, frame, next_frame,
756 (avsync->last_frame?avsync->last_frame->hold_period:0),
757 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800758 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -0800759
760 if (expire) {
761 avsync->vpts = fpts;
762 /* phase adjustment */
763 if (!avsync->phase_set) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800764 uint32_t phase_thres = interval / 4;
Song Zhaoc03ba122020-12-23 21:54:02 -0800765 if ( systime > fpts && (systime - fpts) < phase_thres) {
766 /* too aligned to current VSYNC, separate them to 1/4 VSYNC */
767 avsync->phase += phase_thres - (systime - fpts);
768 avsync->phase_set = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800769 log_info("[%d]adjust phase to %d", avsync->session_id, avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800770 }
771 if (!avsync->phase_set && systime > fpts &&
Song Zhaoea5a0412021-01-18 16:40:08 -0800772 systime < (fpts + interval) &&
773 (systime - fpts) > interval - phase_thres) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800774 /* too aligned to previous VSYNC, separate them to 1/4 VSYNC */
Song Zhaoea5a0412021-01-18 16:40:08 -0800775 avsync->phase += phase_thres + fpts + interval - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800776 avsync->phase_set = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800777 log_info("[%d]adjust phase to %d", avsync->session_id, avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800778 }
779 }
780
781 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -0800782 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800783 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -0800784 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800785 }
786 return expire;
787}
788
Song Zhao35a82df2021-04-15 10:58:49 -0700789static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -0800790{
Song Zhao35a82df2021-04-15 10:58:49 -0700791 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800792 log_trace("[%d]cur_period: %d last_period: %d",
793 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -0700794 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
795 ret = true;
796 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
797 ret = true;
798 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
799 ret = true;
800 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
801 ret = true;
802
803 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800804}
805
806int av_sync_set_speed(void *sync, float speed)
807{
808 struct av_sync_session *avsync = (struct av_sync_session *)sync;
809
810 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800811 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800812 return -1;
813 }
814
Song Zhaoea5a0412021-01-18 16:40:08 -0800815 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
816 avsync->mode == AV_SYNC_MODE_IPTV) {
817 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800818 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800819 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800820
Song Zhaoea5a0412021-01-18 16:40:08 -0800821 avsync->speed = speed;
822
823 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
824 if (speed == 1.0) {
825 avsync->mode = avsync->backup_mode;
826 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
827 } else {
828 avsync->backup_mode = avsync->mode;
829 avsync->mode = AV_SYNC_MODE_FREE_RUN;
830 log_info("[%d]audio to freerun mode", avsync->session_id);
831 }
832 }
833#if 0
Song Zhaoc03ba122020-12-23 21:54:02 -0800834 if (avsync->mode != AV_SYNC_MODE_VMASTER) {
835 log_info("ignore set speed in mode %d", avsync->mode);
836 return 0;
837 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800838#endif
Song Zhaoc03ba122020-12-23 21:54:02 -0800839
Song Zhaoea5a0412021-01-18 16:40:08 -0800840 log_info("session[%d] set rate to %f", avsync->session_id, speed);
841 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800842}
843
844int av_sync_change_mode(void *sync, enum sync_mode mode)
845{
846 struct av_sync_session *avsync = (struct av_sync_session *)sync;
847
848 if (!avsync)
849 return -1;
850
Song Zhaoea5a0412021-01-18 16:40:08 -0800851 if (msync_session_set_mode(avsync->fd, mode)) {
852 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800853 return -1;
854 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800855 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -0800856 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800857 return 0;
858}
859
Song Zhao01031bb2021-05-13 21:23:20 -0700860int av_sync_get_mode(void *sync, enum sync_mode *mode)
861{
862 struct av_sync_session *avsync = (struct av_sync_session *)sync;
863
864 if (!avsync || !mode)
865 return -1;
866
867 *mode = avsync->mode;
868 return 0;
869}
870
Song Zhaoc03ba122020-12-23 21:54:02 -0800871int av_sync_set_pause_pts(void *sync, pts90K pts)
872{
873 struct av_sync_session *avsync = (struct av_sync_session *)sync;
874
875 if (!avsync)
876 return -1;
877
878 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -0800879 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800880 return 0;
881}
882
883int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
884{
885 struct av_sync_session *avsync = (struct av_sync_session *)sync;
886
887 if (!avsync)
888 return -1;
889
890 avsync->pause_pts_cb = cb;
891 avsync->pause_cb_priv = priv;
892 return 0;
893}
Song Zhaoea5a0412021-01-18 16:40:08 -0800894
895static void trigger_audio_start_cb(struct av_sync_session *avsync,
896 avs_ascb_reason reason)
897{
898 if (avsync) {
899 pthread_mutex_lock(&avsync->lock);
900 if (avsync->audio_start) {
901 avsync->audio_start(avsync->audio_start_priv, reason);
902 avsync->session_started = true;
903 avsync->audio_start = NULL;
904 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
905 }
906 pthread_mutex_unlock(&avsync->lock);
907 }
908}
909
910avs_start_ret av_sync_audio_start(
911 void *sync,
912 pts90K pts,
913 pts90K delay,
914 audio_start_cb cb,
915 void *priv)
916{
917 struct av_sync_session *avsync = (struct av_sync_session *)sync;
918 uint32_t start_mode;
919 avs_start_ret ret = AV_SYNC_ASTART_ERR;
920 bool create_poll_t = false;
921
922 if (!avsync)
923 return ret;
924
925 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
926 log_error("[%d]fail to set audio start", avsync->session_id);
927
yongchun.li107a6162021-05-05 02:38:57 -0700928 if (avsync->in_audio_switch
929 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET) {
930 log_info("%d audio_switch_state to start start mode %d",
931 avsync->session_id, start_mode);
932 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
933 }
934
Song Zhaoea5a0412021-01-18 16:40:08 -0800935 if (start_mode == AVS_START_SYNC) {
936 ret = AV_SYNC_ASTART_SYNC;
937 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -0700938 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -0700939 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800940 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -0700941 avsync->state = AV_SYNC_STAT_RUNNING;
942 } else if (start_mode == AVS_START_AGAIN) {
943 ret = AV_SYNC_ASTART_AGAIN;
944 }
945
946 if (ret == AV_SYNC_ASTART_AGAIN)
947 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800948
yongchun.li107a6162021-05-05 02:38:57 -0700949 if (avsync->mode == AV_SYNC_MODE_AMASTER || avsync->in_audio_switch) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800950 create_poll_t = true;
951 if (start_mode == AVS_START_ASYNC) {
952 if (!cb) {
953 log_error("[%d]invalid cb", avsync->session_id);
954 return AV_SYNC_ASTART_ERR;
955 }
956 avsync->audio_start = cb;
957 avsync->audio_start_priv = priv;
958 }
Song Zhaod62bb392021-04-23 12:25:49 -0700959 } else if (LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -0800960 create_poll_t = true;
961
Song Zhaod62bb392021-04-23 12:25:49 -0700962 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800963 int ret;
964
965 log_info("[%d]start poll thread", avsync->session_id);
966 avsync->quit_poll = false;
967 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
968 if (ret) {
969 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
970 return AV_SYNC_ASTART_ERR;
971 }
972 }
Song Zhaod62bb392021-04-23 12:25:49 -0700973 if (LIVE_MODE(avsync->mode)) {
974 uint32_t systime;
975 msync_session_get_wall(avsync->fd, &systime, NULL);
976 log_info("[%d]return %u w %u pts %u d %u",
977 avsync->session_id, ret, systime, pts, delay);
978 }
979exit:
Song Zhaoea5a0412021-01-18 16:40:08 -0800980 log_info("[%d]return %u", avsync->session_id, ret);
981 return ret;
982}
983
984int av_sync_audio_render(
985 void *sync,
986 pts90K pts,
987 struct audio_policy *policy)
988{
989 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -0700990 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800991 uint32_t systime;
992 struct av_sync_session *avsync = (struct av_sync_session *)sync;
993 avs_audio_action action = AA_SYNC_AA_MAX;
994
995 if (!avsync || !policy)
996 return -1;
997
yongchun.li107a6162021-05-05 02:38:57 -0700998 msync_session_get_wall(avsync->fd, &systime, NULL);
999
1000 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
1001 pts, systime, avsync->mode, (int)(pts-systime)/90);
1002
1003 if (avsync->in_audio_switch
1004 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
1005 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
1006 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1007 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1008 action = AV_SYNC_AA_RENDER;
1009 } else if ((int)(systime - pts) > 0) {
1010 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1011 (int)(systime - pts)/90, systime, pts);
1012 action = AV_SYNC_AA_DROP;
1013 } else {
1014 action = AV_SYNC_AA_INSERT;
1015 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1016 (int)(pts - systime)/90, systime, pts);
1017 }
1018 goto done;
1019 }
1020
Song Zhaoea5a0412021-01-18 16:40:08 -08001021 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1022 avsync->mode == AV_SYNC_MODE_AMASTER) {
1023 action = AV_SYNC_AA_RENDER;
1024 goto done;
1025 }
1026
Song Zhaod62bb392021-04-23 12:25:49 -07001027 /* stopping procedure, unblock audio rendering */
1028 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER &&
1029 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1030 action = AV_SYNC_AA_DROP;
1031 goto done;
1032 }
1033
Song Zhaod62bb392021-04-23 12:25:49 -07001034
Song Zhao7daf3a12021-05-10 22:22:25 -07001035 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1036 avsync->mode == AV_SYNC_MODE_AMASTER) {
1037 action = AV_SYNC_AA_RENDER;
1038 goto done;
1039 }
1040
Song Zhaod62bb392021-04-23 12:25:49 -07001041 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1042 LIVE_MODE(avsync->mode) &&
1043 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1044 /* outlier by stream error */
1045 avsync->outlier_cnt++;
1046 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1047 /* treat as disc, just drop current frame */
1048 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1049 avsync->outlier_cnt = 0;
1050 action = AV_SYNC_AA_DROP;
1051 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001052 goto done;
1053 }
1054 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1055 pts = systime;
1056 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001057 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001058 goto done;
1059 }
1060
1061 avsync->outlier_cnt = 0;
1062 /* low bound from sync_lost to sync_setup */
1063 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1064 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1065 action = AV_SYNC_AA_RENDER;
1066 goto done;
1067 }
1068
1069 /* high bound of sync_setup */
1070 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1071 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1072 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001073 action = AV_SYNC_AA_RENDER;
1074 goto done;
1075 }
1076
1077 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001078 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001079 action = AV_SYNC_AA_DROP;
1080 goto done;
1081 }
1082
1083 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001084 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001085 action = AV_SYNC_AA_INSERT;
1086 goto done;
1087 }
1088
1089done:
1090 policy->action = action;
1091 policy->delta = (int)(systime - pts);
1092 if (action == AV_SYNC_AA_RENDER) {
1093 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001094 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001095 if (!out_lier)
1096 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001097 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001098 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001099 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1100 msync_session_update_apts(avsync->fd, systime, pts, 0);
1101 log_info("[%d] audio switch done sys %u pts %u",
1102 avsync->session_id, systime, pts);
1103 msync_session_set_audio_switch(avsync->fd, false);
1104 avsync->in_audio_switch = false;
1105 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1106 } else {
1107 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1108 avsync->session_id, action, systime, pts, systime - pts);
1109 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001110 } else {
Song Zhao409739b2021-05-12 22:21:40 -07001111 if (abs_diff(systime, pts) > AV_DISC_THRES_MIN &&
yongchun.li085b5a42021-05-24 04:22:53 -07001112 avsync->last_disc_pts != pts &&
1113 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001114 log_info ("[%d]audio disc %u --> %u",
1115 avsync->session_id, systime, pts);
1116 msync_session_set_audio_dis(avsync->fd, pts);
1117 avsync->last_disc_pts = pts;
1118 }
Song Zhaof46932e2021-05-21 01:51:45 -07001119 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001120 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001121 }
1122
1123 return ret;
1124}
1125
1126int av_sync_get_clock(void *sync, pts90K *pts)
1127{
1128 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1129
1130 if (!avsync || !pts)
1131 return -1;
1132 return msync_session_get_wall(avsync->fd, pts, NULL);
1133}
1134
1135static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001136 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001137{
Song Zhaoe208d692021-04-19 15:38:52 -07001138 log_info("[%d]amode %d mode %d v/a/vt %d/%d/%d", avsync->session_id,
1139 avsync->active_mode, avsync->mode, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001140 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1141 float speed;
1142 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaoe208d692021-04-19 15:38:52 -07001143 a_active && avsync->audio_start) {
yongchun.li107a6162021-05-05 02:38:57 -07001144 if (v_active || v_timeout || avsync->in_audio_switch) {
Song Zhaoe208d692021-04-19 15:38:52 -07001145 log_info("audio start cb");
1146 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
yongchun.li107a6162021-05-05 02:38:57 -07001147 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001148 }
1149
1150 if (!msync_session_get_rate(avsync->fd, &speed)) {
1151 /* speed change is triggered by asink,
1152 * attached audio HAL will handle it
1153 */
1154 if (speed != avsync->speed)
1155 log_info("[%d]new rate %f", avsync->session_id, speed);
1156 if (speed == 1.0) {
1157 avsync->mode = avsync->backup_mode;
1158 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1159 } else {
1160 avsync->backup_mode = avsync->mode;
1161 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1162 log_info("[%d]audio to freerun mode", avsync->session_id);
1163 }
1164 avsync->speed = speed;
1165 }
Song Zhaod62bb392021-04-23 12:25:49 -07001166 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1167 struct session_debug debug;
1168 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1169 if (debug.debug_freerun) {
1170 avsync->backup_mode = avsync->mode;
1171 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1172 log_warn("[%d]audio to freerun mode", avsync->session_id);
1173 } else {
1174 avsync->mode = avsync->backup_mode;
1175 log_warn("[%d]audio back to mode %d",
1176 avsync->session_id, avsync->mode);
1177 }
1178 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001179 }
1180}
1181
1182static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001183 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001184{
1185 log_info("[%d]amode mode %d %d v/a %d/%d", avsync->session_id,
1186 avsync->active_mode, avsync->mode, v_active, a_active);
Song Zhaod62bb392021-04-23 12:25:49 -07001187 if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1188 struct session_debug debug;
1189 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1190 if (debug.debug_freerun) {
1191 avsync->backup_mode = avsync->mode;
1192 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1193 log_warn("[%d]video to freerun mode", avsync->session_id);
1194 } else
1195 avsync->mode = avsync->backup_mode;
1196 log_warn("[%d]video back to mode %d",
1197 avsync->session_id, avsync->mode);
1198 }
1199 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001200}
1201
1202static void * poll_thread(void * arg)
1203{
1204 int ret = 0;
1205 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1206 const int fd = avsync->fd;
1207 struct pollfd pfd = {
1208 /* default blocking capture */
1209 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1210 .fd = avsync->fd,
1211 };
1212
1213 prctl (PR_SET_NAME, "avs_poll");
1214 log_info("[%d]enter", avsync->session_id);
1215 while (!avsync->quit_poll) {
1216 for (;;) {
1217 ret = poll(&pfd, 1, 10);
1218 if (ret > 0)
1219 break;
1220 if (avsync->quit_poll)
1221 goto exit;
1222 if (errno == EINTR)
1223 continue;
1224 }
1225
1226 /* error handling */
1227 if (pfd.revents & POLLERR)
1228 log_error("[%d]POLLERR received", avsync->session_id);
1229
Song Zhaod62bb392021-04-23 12:25:49 -07001230 /* mode change. Non-exclusive wait so all the processes
1231 * shall be woken up
1232 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001233 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001234 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -08001235
1236 msync_session_get_stat(fd, &avsync->active_mode,
yongchun.li107a6162021-05-05 02:38:57 -07001237 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch);
Song Zhaoea5a0412021-01-18 16:40:08 -08001238
1239 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhaoe208d692021-04-19 15:38:52 -07001240 handle_mode_change_a(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001241 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhaoe208d692021-04-19 15:38:52 -07001242 handle_mode_change_v(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001243 }
1244 }
1245exit:
1246 log_info("[%d]quit", avsync->session_id);
1247 return NULL;
1248}
1249
Song Zhaod62bb392021-04-23 12:25:49 -07001250int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001251{
1252 struct av_sync_session *avsync = (struct av_sync_session *)sync;
wei.dubcc2ed22021-05-19 07:16:10 -04001253 struct pcr_info pcr;
1254 enum pcr_monitor_status status;
1255 int ppm;
Song Zhaoea5a0412021-01-18 16:40:08 -08001256 if (!avsync)
1257 return -1;
1258
1259 if (avsync->type != AV_SYNC_TYPE_PCR)
1260 return -2;
1261
wei.dubcc2ed22021-05-19 07:16:10 -04001262 pcr.monoclk = mono_clock / 1000;
1263 pcr.pts = (long long) pts * 1000 / 90;
1264 pcr_monitor_process(avsync->pcr_monitor, &pcr);
1265
1266 status = pcr_monitor_get_status(avsync->pcr_monitor);
1267
1268 if (status >= DEVIATION_READY) {
1269 pcr_monitor_get_deviation(avsync->pcr_monitor, &ppm);
1270 if (avsync->ppm != ppm) {
1271 avsync->ppm = ppm;
1272 log_info("[%d]ppm:%d", avsync->session_id, ppm);
1273 if (msync_session_set_clock_dev(avsync->fd, ppm))
1274 log_error("set clock dev fail");
1275 }
1276 }
1277
Song Zhaod62bb392021-04-23 12:25:49 -07001278 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001279}
1280
Song Zhaod62bb392021-04-23 12:25:49 -07001281int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001282{
1283 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1284
1285 if (!avsync)
1286 return -1;
1287
Song Zhaod62bb392021-04-23 12:25:49 -07001288 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001289}
1290
1291int av_sync_set_session_name(void *sync, const char *name)
1292{
1293 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1294
1295 if (!avsync)
1296 return -1;
1297
1298 return msync_session_set_name(avsync->fd, name);
1299}
yongchun.li107a6162021-05-05 02:38:57 -07001300
1301int av_sync_set_audio_switch(void *sync, bool start)
1302{
1303 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1304 bool v_active, a_active, v_timeout;
1305
1306 if (!avsync)
1307 return -1;
1308 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
1309 &v_active, &a_active,
Song Zhaobe513572021-05-13 13:10:21 -07001310 &v_timeout, &avsync->in_audio_switch)) {
yongchun.li107a6162021-05-05 02:38:57 -07001311 log_error("[%d] can not get session state",
1312 avsync->session_id);
1313 return -1;
1314 }
1315 if (!v_active || !a_active) {
1316 log_error("[%d] no apply if not AV both active v %d a %d",
1317 avsync->session_id, v_active, a_active);
1318 return -1;
1319 }
1320 if (msync_session_set_audio_switch(avsync->fd, start)) {
1321 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1322 return -1;
1323 }
1324 avsync->in_audio_switch = start;
1325 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1326 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1327 return 0;
1328}
1329
1330int av_sync_get_audio_switch(void *sync, bool *start)
1331{
1332 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1333
1334 if (!avsync)
1335 return -1;
1336 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
1337 NULL, NULL, NULL, &avsync->in_audio_switch)) {
1338 log_error("[%d] can not audio seamless switch state",
1339 avsync->session_id);
1340 return -1;
1341 }
1342 if (start) *start = avsync->in_audio_switch;
1343 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001344}
Song Zhao8039f562021-05-18 18:11:25 -07001345
1346enum clock_recovery_stat av_sync_get_clock_devication(void *sync, int32_t *ppm)
1347{
1348 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1349
wei.dubcc2ed22021-05-19 07:16:10 -04001350 if (!avsync || !ppm)
1351 return CLK_RECOVERY_ERR;
1352 if (avsync->mode != AV_SYNC_MODE_PCR_MASTER)
Song Zhao8039f562021-05-18 18:11:25 -07001353 return CLK_RECOVERY_NOT_RUNNING;
1354
wei.dubcc2ed22021-05-19 07:16:10 -04001355 if (msync_session_get_clock_dev(avsync->fd, ppm))
1356 return CLK_RECOVERY_ERR;
1357
1358 if (*ppm == 0)
1359 return CLK_RECOVERY_ONGOING;
1360 else
1361 return CLK_RECOVERY_READY;
Song Zhao8039f562021-05-18 18:11:25 -07001362}