blob: a8b32510a80bdc8bc630080e183c959c5dcc42b6 [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>
Song Zhaoc03ba122020-12-23 21:54:02 -080030
31enum 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;
Song Zhaoc03ba122020-12-23 21:54:02 -0800120};
121
122#define MAX_FRAME_NUM 32
123#define DEFAULT_START_THRESHOLD 2
124#define TIME_UNIT90K (90000)
Song Zhaof46932e2021-05-21 01:51:45 -0700125#define AV_DISC_THRES_MIN (TIME_UNIT90K / 3)
126#define AV_DISC_THRES_MAX (TIME_UNIT90K * 10)
Song Zhao7daf3a12021-05-10 22:22:25 -0700127#define A_ADJ_THREDHOLD_HB (900 * 6) //60ms
128#define A_ADJ_THREDHOLD_LB (900 * 2) //20ms
Song Zhao52f55192021-05-06 10:52:21 -0700129#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800130#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhaod62bb392021-04-23 12:25:49 -0700131#define LIVE_MODE(mode) ((mode) == AV_SYNC_MODE_PCR_MASTER || (mode) == AV_SYNC_MODE_IPTV)
132
Song Zhao065800e2021-05-26 15:56:06 -0700133#define STREAM_DISC_THRES (TIME_UNIT90K / 10)
Song Zhaod62bb392021-04-23 12:25:49 -0700134#define OUTLIER_MAX_CNT 8
Song Zhaoc03ba122020-12-23 21:54:02 -0800135
136static uint64_t time_diff (struct timeval *b, struct timeval *a);
137static bool frame_expire(struct av_sync_session* avsync,
138 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800139 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800140 struct vframe * frame,
141 struct vframe * next_frame,
142 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700143static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800144 int cur_period,
145 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800146static void * poll_thread(void * arg);
147static void trigger_audio_start_cb(struct av_sync_session *avsync,
148 avs_ascb_reason reason);
Song Zhaoc03ba122020-12-23 21:54:02 -0800149
Song Zhaoea5a0412021-01-18 16:40:08 -0800150int av_sync_open_session(int *session_id)
151{
152 int fd = msync_create_session();
153 int id, rc;
154
155 if (fd < 0) {
156 log_error("fail");
157 return -1;
158 }
159 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
160 if (rc) {
161 log_error("new session errno:%d", errno);
162 return rc;
163 }
164 *session_id = id;
165 return fd;
166}
167
168void av_sync_close_session(int session)
169{
170 msync_destory_session(session);
171}
172
173static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800174 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800175 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800176 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800177 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800178{
179 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800180 char dev_name[20];
Song Zhaoc03ba122020-12-23 21:54:02 -0800181
182 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
183 if (!avsync) {
184 log_error("OOM");
185 return NULL;
186 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800187
188 if (type == AV_SYNC_TYPE_VIDEO) {
189 avsync->pattern_detector = create_pattern_detector();
190 if (!avsync->pattern_detector) {
191 log_error("pd create fail");
192 goto err;
193 }
194
195 if (!start_thres)
196 avsync->start_thres = DEFAULT_START_THRESHOLD;
197 else {
198 if (start_thres > 5) {
199 log_error("start_thres too big: %d", start_thres);
200 goto err2;
201 }
202 avsync->start_thres = start_thres;
203 }
204 avsync->phase_set = false;
205 avsync->first_frame_toggled = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800206 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800207
208 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800209 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800210 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800211 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800212 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800213 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800214 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800215 avsync->speed = 1.0f;
216 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhao409739b2021-05-12 22:21:40 -0700217 avsync->vsync_interval = -1;
218 avsync->last_disc_pts = -1;
Song Zhaof46932e2021-05-21 01:51:45 -0700219 if (msync_session_get_disc_thres(session_id,
220 &avsync->disc_thres_min, &avsync->disc_thres_max)) {
221 log_error("fail to get disc thres", dev_name, errno);
222 avsync->disc_thres_min = AV_DISC_THRES_MIN;
223 avsync->disc_thres_max = AV_DISC_THRES_MAX;
224 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800225
226 pthread_mutex_init(&avsync->lock, NULL);
Song Zhaof46932e2021-05-21 01:51:45 -0700227 log_info("[%d] mode %d type %d start_thres %d disc_thres %u/%u",
228 session_id, mode, type, start_thres,
229 avsync->disc_thres_min, avsync->disc_thres_max);
Song Zhaoea5a0412021-01-18 16:40:08 -0800230
231 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
232 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
233 if (avsync->fd < 0) {
234 log_error("open %s errno %d", dev_name, errno);
235 goto err2;
236 }
237
238 if (!attach) {
239 msync_session_set_mode(avsync->fd, mode);
240 avsync->mode = mode;
241 } else {
242 avsync->attached = true;
243 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
244 log_error("get mode");
245 goto err2;
246 }
247 avsync->backup_mode = avsync->mode;
248 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy)) {
249 log_error("get policy");
250 goto err2;
251 }
yongchun.li107a6162021-05-05 02:38:57 -0700252 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
253 NULL, NULL, NULL, &avsync->in_audio_switch)) {
254 log_error("get state");
255 goto err2;
256 }
257 if (avsync->in_audio_switch) {
258 log_info("audio_switch_state reseted the audio");
259 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
260 }
261
Song Zhaoea5a0412021-01-18 16:40:08 -0800262 log_info("[%d]retrieve sync mode %d policy %d",
263 session_id, avsync->mode, avsync->start_policy);
264 }
265
Song Zhaoc03ba122020-12-23 21:54:02 -0800266 return avsync;
Song Zhaoea5a0412021-01-18 16:40:08 -0800267err2:
268 destroy_pattern_detector(avsync->pattern_detector);
269err:
270 free(avsync);
271 return NULL;
272}
273
274void* av_sync_create(int session_id,
275 enum sync_mode mode,
276 enum sync_type type,
277 int start_thres)
278{
279 return create_internal(session_id, mode,
280 type, start_thres, false);
281}
282
283void* av_sync_attach(int session_id, enum sync_type type)
284{
285 return create_internal(session_id, AV_SYNC_MODE_MAX,
286 type, 0, true);
287}
288
289int av_sync_video_config(void *sync, struct video_config* config)
290{
291 struct av_sync_session *avsync = (struct av_sync_session *)sync;
292
293 if (!avsync || !config)
294 return -1;
295
296 if (config->delay != 1 && config->delay != 2) {
297 log_error("invalid delay: %d\n", config->delay);
298 return -1;
299 }
300
301 avsync->delay = config->delay;
302
303 log_info("[%d] delay: %d",
304 avsync->session_id, config->delay);
305 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800306}
307
308static int internal_stop(struct av_sync_session *avsync)
309{
310 int ret = 0;
311 struct vframe *frame;
312
313 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800314 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
315 frame->free(frame);
316 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800317 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800318 pthread_mutex_unlock(&avsync->lock);
319 return ret;
320}
321
322/* destroy and detach from kernel session */
323void av_sync_destroy(void *sync)
324{
325 struct av_sync_session *avsync = (struct av_sync_session *)sync;
326
327 if (!avsync)
328 return;
329
Song Zhaoea5a0412021-01-18 16:40:08 -0800330 log_info("[%d]begin", avsync->session_id);
331 if (avsync->state != AV_SYNC_STAT_INIT) {
332 if (avsync->type == AV_SYNC_TYPE_VIDEO)
333 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800334
Song Zhaoea5a0412021-01-18 16:40:08 -0800335 avsync->quit_poll = true;
336 if (avsync->poll_thread) {
337 pthread_join(avsync->poll_thread, NULL);
338 avsync->poll_thread = 0;
339 }
340 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoaf368d52021-02-17 17:53:45 -0800341 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800342
Song Zhaoea5a0412021-01-18 16:40:08 -0800343 if (avsync->session_started) {
344 if (avsync->type == AV_SYNC_TYPE_VIDEO)
345 msync_session_set_video_stop(avsync->fd);
346 else
347 msync_session_set_audio_stop(avsync->fd);
348 }
349 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800350 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800351 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
352 destroy_q(avsync->frame_q);
353 destroy_pattern_detector(avsync->pattern_detector);
354 }
355 log_info("[%d]done", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800356 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800357}
358
359int avs_sync_set_start_policy(void *sync, enum sync_start_policy policy)
360{
361 struct av_sync_session *avsync = (struct av_sync_session *)sync;
362
363 if (!avsync || !avsync->fd)
364 return -1;
365
366 log_info("[%d]policy %u --> %u", avsync->start_policy, policy);
367 avsync->start_policy = policy;
368 /* v_peek will be handled by libamlavsync */
369 if (policy != AV_SYNC_START_NONE &&
370 policy != AV_SYNC_START_V_PEEK)
371 return msync_session_set_start_policy(avsync->fd, policy);
372
373 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800374}
375
376int av_sync_pause(void *sync, bool pause)
377{
378 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700379 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800380 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800381
382 if (!avsync)
383 return -1;
384
Song Zhaoea5a0412021-01-18 16:40:08 -0800385 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
386 return -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800387
yongchun.li107a6162021-05-05 02:38:57 -0700388 rc = msync_session_get_stat(avsync->fd, &avsync->active_mode,
389 &v_active, &a_active, &v_timeout,
390 &avsync->in_audio_switch);
391
Song Zhaoea5a0412021-01-18 16:40:08 -0800392 /* ignore */
yongchun.li107a6162021-05-05 02:38:57 -0700393 if (avsync->mode == AV_SYNC_MODE_AMASTER
394 && avsync->type == AV_SYNC_TYPE_VIDEO
395 && a_active && !avsync->in_audio_switch)
Song Zhaoc03ba122020-12-23 21:54:02 -0800396 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800397
yongchun.li107a6162021-05-05 02:38:57 -0700398 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
399 log_info("[%d] ignore the pause from audio", avsync->session_id);
400 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
401 return 0;
402 }
403
Song Zhaoea5a0412021-01-18 16:40:08 -0800404 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800405 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800406 log_info("[%d]paused:%d type:%d rc %d",
407 avsync->session_id, pause, avsync->type, rc);
Song Zhaoc03ba122020-12-23 21:54:02 -0800408
Song Zhaoea5a0412021-01-18 16:40:08 -0800409 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800410}
411
412int av_sync_push_frame(void *sync , struct vframe *frame)
413{
414 int ret;
415 struct vframe *prev;
416 struct av_sync_session *avsync = (struct av_sync_session *)sync;
417
418 if (!avsync)
419 return -1;
420
Song Zhaoea5a0412021-01-18 16:40:08 -0800421 if (!avsync->frame_q) {
422 /* policy should be final now */
423 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy)) {
424 log_error("[%d]get policy", avsync->session_id);
425 return -1;
426 }
427
428 avsync->frame_q = create_q(MAX_FRAME_NUM);
429 if (!avsync->frame_q) {
430 log_error("[%d]create queue fail", avsync->session_id);
431 return -1;
432 }
433
434 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
435 avsync->mode == AV_SYNC_MODE_IPTV) {
436 int ret;
437
438 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
439 if (ret) {
440 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
441 destroy_q(avsync->frame_q);
442 return -1;
443 }
444 }
445 }
446
Song Zhaoc03ba122020-12-23 21:54:02 -0800447 if (!peek_item(avsync->frame_q, (void **)&prev, 0)) {
Song Zhaod62bb392021-04-23 12:25:49 -0700448 if (prev->pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800449 dqueue_item(avsync->frame_q, (void **)&prev);
450 prev->free(prev);
Song Zhaoea5a0412021-01-18 16:40:08 -0800451 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800452 }
453 }
454
Song Zhao065800e2021-05-26 15:56:06 -0700455 if (frame->duration == -1)
456 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800457 frame->hold_period = 0;
458 ret = queue_item(avsync->frame_q, frame);
459 if (avsync->state == AV_SYNC_STAT_INIT &&
460 queue_size(avsync->frame_q) >= avsync->start_thres) {
461 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaoea5a0412021-01-18 16:40:08 -0800462 log_info("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800463 }
464
465 if (ret)
466 log_error("%s queue fail:%d", ret);
Song Zhaoea5a0412021-01-18 16:40:08 -0800467 log_debug("[%d]push %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800468 return ret;
469
470}
471
472struct vframe *av_sync_pop_frame(void *sync)
473{
Song Zhaoea5a0412021-01-18 16:40:08 -0800474 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800475 struct av_sync_session *avsync = (struct av_sync_session *)sync;
476 int toggle_cnt = 0;
477 uint32_t systime;
Song Zhao468fd652021-01-15 22:13:04 -0800478 bool pause_pts_reached = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800479 uint32_t interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800480
481 pthread_mutex_lock(&avsync->lock);
482 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhaod62bb392021-04-23 12:25:49 -0700483 log_info("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800484 goto exit;
485 }
486
Song Zhaoea5a0412021-01-18 16:40:08 -0800487 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700488 uint32_t pts;
489
Song Zhaoc03ba122020-12-23 21:54:02 -0800490 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800491 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800492 goto exit;
493 }
Song Zhao35a82df2021-04-15 10:58:49 -0700494 msync_session_get_wall(avsync->fd, &systime, &interval);
495 pts = frame->pts - avsync->delay * interval;
496 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800497 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700498 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800499 }
500
Song Zhaoea5a0412021-01-18 16:40:08 -0800501 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700502 !avsync->first_frame_toggled &&
503 !msync_clock_started(avsync->fd)) {
504 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800505 log_trace("[%d]clock not started", avsync->session_id);
506 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800507 }
508
Song Zhaoea5a0412021-01-18 16:40:08 -0800509 enter_last_frame = avsync->last_frame;
510 msync_session_get_wall(avsync->fd, &systime, &interval);
511
512 /* handle refresh rate change */
513 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
514 avsync->vsync_interval != interval) {
515 log_info("[%d]vsync interval update %d --> %u",
516 avsync->session_id, avsync->vsync_interval, interval);
517 avsync->vsync_interval = interval;
518 avsync->phase_set = false;
519 reset_pattern(avsync->pattern_detector);
520 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800521 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
522 struct vframe *next_frame = NULL;
523
524 peek_item(avsync->frame_q, (void **)&next_frame, 1);
525 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700526 log_debug("[%d]cur_f %u next_f %u size %d",
527 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800528 if (frame_expire(avsync, systime, interval,
529 frame, next_frame, toggle_cnt)) {
530 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800531 toggle_cnt++;
532
Song Zhao35a82df2021-04-15 10:58:49 -0700533 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800534 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao35a82df2021-04-15 10:58:49 -0700535 avsync->last_holding_peroid))
536 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
537
Song Zhaoc03ba122020-12-23 21:54:02 -0800538 if (avsync->last_frame)
539 avsync->last_holding_peroid = avsync->last_frame->hold_period;
540
541 dqueue_item(avsync->frame_q, (void **)&frame);
542 if (avsync->last_frame) {
543 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800544 if (toggle_cnt > 1) {
Song Zhao35a82df2021-04-15 10:58:49 -0700545 log_debug("[%d]free %u cur %u system/d %u/%u", avsync->session_id,
546 avsync->last_frame->pts, frame->pts, systime, systime - avsync->last_poptime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800547 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800548 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800549 } else {
550 avsync->first_frame_toggled = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800551 log_info("[%d]first frame %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800552 }
553 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800554 avsync->last_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800555 } else
556 break;
557 }
558
559 /* pause pts */
560 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800561 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800562 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800563 else
Song Zhao468fd652021-01-15 22:13:04 -0800564 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
565 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
566 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
567 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
568 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800569
Song Zhao468fd652021-01-15 22:13:04 -0800570 if (pause_pts_reached) {
571 if (avsync->pause_pts_cb)
572 avsync->pause_pts_cb(avsync->pause_pts,
Song Zhaoc03ba122020-12-23 21:54:02 -0800573 avsync->pause_cb_priv);
574
Song Zhao468fd652021-01-15 22:13:04 -0800575 /* stay in paused until av_sync_pause(false) */
576 avsync->paused = true;
577 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoea5a0412021-01-18 16:40:08 -0800578 log_info ("[%d]reach pause pts: %u",
579 avsync->session_id, avsync->last_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800580 }
581
582exit:
583 pthread_mutex_unlock(&avsync->lock);
584 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800585 if (enter_last_frame != avsync->last_frame)
586 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhao35a82df2021-04-15 10:58:49 -0700587 log_trace("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhao065800e2021-05-26 15:56:06 -0700588 /* don't update vpts for out_lier */
589 if (avsync->last_frame->duration != -1)
590 msync_session_update_vpts(avsync->fd, systime,
591 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800592 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800593 if (enter_last_frame != avsync->last_frame)
594 log_debug("[%d]pop (nil)", avsync->session_id);
595
Song Zhao35a82df2021-04-15 10:58:49 -0700596 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800597 if (avsync->last_frame)
598 avsync->last_frame->hold_period++;
599 return avsync->last_frame;
600}
601
Song Zhaoc03ba122020-12-23 21:54:02 -0800602static inline uint32_t abs_diff(uint32_t a, uint32_t b)
603{
Song Zhaoea5a0412021-01-18 16:40:08 -0800604 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800605}
606
607static uint64_t time_diff (struct timeval *b, struct timeval *a)
608{
609 return (b->tv_sec - a->tv_sec)*1000000 + (b->tv_usec - a->tv_usec);
610}
611
Song Zhaoc03ba122020-12-23 21:54:02 -0800612static bool frame_expire(struct av_sync_session* avsync,
613 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800614 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800615 struct vframe * frame,
616 struct vframe * next_frame,
617 int toggle_cnt)
618{
619 uint32_t fpts = frame->pts;
620 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800621 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800622
Song Zhaod62bb392021-04-23 12:25:49 -0700623 if (avsync->mode == AV_SYNC_MODE_FREE_RUN)
624 return true;
625
Song Zhaoc03ba122020-12-23 21:54:02 -0800626 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
627 return false;
628
629 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
630 return true;
631
632 if (!fpts) {
633 if (avsync->last_frame) {
634 /* try to accumulate duration as PTS */
635 fpts = avsync->vpts + avsync->last_frame->duration;
636 } else {
637 fpts = avsync->vpts;
638 }
639 }
640 systime += pts_correction;
641
642 /* phase adjustment */
643 if (avsync->phase_set)
644 systime += avsync->phase;
645
Song Zhao35a82df2021-04-15 10:58:49 -0700646 log_trace("[%d]systime:%u phase:%u correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800647 avsync->session_id, systime,
Song Zhao35a82df2021-04-15 10:58:49 -0700648 avsync->phase_set?avsync->phase:0, pts_correction, fpts);
Song Zhaof46932e2021-05-21 01:51:45 -0700649 if (abs_diff(systime, fpts) > avsync->disc_thres_min &&
Song Zhaoc03ba122020-12-23 21:54:02 -0800650 avsync->first_frame_toggled) {
651 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800652 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800653 return false;
654
Song Zhao5d2b4772021-01-18 16:40:08 -0800655 if (avsync->last_systime != systime || avsync->last_pts != fpts) {
656 struct timeval now;
657
658 gettimeofday(&now, NULL);
659 avsync->last_systime = systime;
660 avsync->last_pts = fpts;
661 if (time_diff(&now, &avsync->sync_lost_print_time) >=
662 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700663 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800664 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800665 avsync->sync_lost_cnt = 0;
Song Zhaobc6161d2021-03-08 09:59:33 -0800666 gettimeofday(&avsync->sync_lost_print_time, NULL);
Song Zhao5d2b4772021-01-18 16:40:08 -0800667 } else
668 avsync->sync_lost_cnt++;
669 }
Song Zhaod62bb392021-04-23 12:25:49 -0700670
671 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
672 LIVE_MODE(avsync->mode) &&
Song Zhao065800e2021-05-26 15:56:06 -0700673 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700674 /* outlier by stream error */
675 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700676 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700677 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
678 log_info("render outlier %u", fpts);
679 return true;
680 }
681 }
682
683 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800684 avsync->state = AV_SYNC_STAT_SYNC_LOST;
685 avsync->phase_set = false;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800686 reset_pattern(avsync->pattern_detector);
Song Zhaoc03ba122020-12-23 21:54:02 -0800687 if ((int)(systime - fpts) > 0) {
Song Zhao409739b2021-05-12 22:21:40 -0700688 if (LIVE_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800689 log_info ("[%d]video disc %u --> %u",
690 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700691 msync_session_set_video_dis(avsync->fd, fpts);
692 avsync->last_disc_pts = fpts;
Song Zhaoea5a0412021-01-18 16:40:08 -0800693 }
Song Zhaod62bb392021-04-23 12:25:49 -0700694 /* catch up PCR */
Song Zhaoc03ba122020-12-23 21:54:02 -0800695 return true;
Song Zhao409739b2021-05-12 22:21:40 -0700696 } else if (LIVE_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaof46932e2021-05-21 01:51:45 -0700697 /* vpts wrapping or vpts gapping */
Song Zhaod62bb392021-04-23 12:25:49 -0700698 log_info ("[%d]video disc %u --> %u",
699 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700700 msync_session_set_video_dis(avsync->fd, fpts);
701 avsync->last_disc_pts = fpts;
Song Zhaof46932e2021-05-21 01:51:45 -0700702 /* clean up frames for wrapping case */
703 if ((int)(fpts - systime) > avsync->disc_thres_max)
704 return true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800705 }
706 }
707
Song Zhao52f55192021-05-06 10:52:21 -0700708 /* In some cases, keeping pattern will enlarge the gap */
709 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
710 avsync->first_frame_toggled) {
711 reset_pattern(avsync->pattern_detector);
Song Zhaof46932e2021-05-21 01:51:45 -0700712 log_warn("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700713 systime, fpts);
714 }
715
Song Zhaoc03ba122020-12-23 21:54:02 -0800716 expire = (int)(systime - fpts) >= 0;
717
718 /* scatter the frame in different vsync whenever possible */
719 if (expire && next_frame && next_frame->pts && toggle_cnt) {
720 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhaoea5a0412021-01-18 16:40:08 -0800721 if (systime + interval < next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800722 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800723 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
724 avsync->session_id, systime, interval, next_frame->pts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800725 }
726 } else if (!expire && next_frame && next_frame->pts && !toggle_cnt
727 && avsync->first_frame_toggled) {
728 /* next vsync will have at least 2 frame expired */
Song Zhao35a82df2021-04-15 10:58:49 -0700729 if (systime + interval >= next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800730 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800731 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
732 avsync->session_id, systime, interval, next_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800733 }
734 }
735
Song Zhaoa58c3e92021-03-09 18:52:55 -0800736 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
737 correct_pattern(avsync->pattern_detector, frame, next_frame,
738 (avsync->last_frame?avsync->last_frame->hold_period:0),
739 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800740 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -0800741
742 if (expire) {
743 avsync->vpts = fpts;
744 /* phase adjustment */
745 if (!avsync->phase_set) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800746 uint32_t phase_thres = interval / 4;
Song Zhaoc03ba122020-12-23 21:54:02 -0800747 if ( systime > fpts && (systime - fpts) < phase_thres) {
748 /* too aligned to current VSYNC, separate them to 1/4 VSYNC */
749 avsync->phase += phase_thres - (systime - fpts);
750 avsync->phase_set = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800751 log_info("[%d]adjust phase to %d", avsync->session_id, avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800752 }
753 if (!avsync->phase_set && systime > fpts &&
Song Zhaoea5a0412021-01-18 16:40:08 -0800754 systime < (fpts + interval) &&
755 (systime - fpts) > interval - phase_thres) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800756 /* too aligned to previous VSYNC, separate them to 1/4 VSYNC */
Song Zhaoea5a0412021-01-18 16:40:08 -0800757 avsync->phase += phase_thres + fpts + interval - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800758 avsync->phase_set = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800759 log_info("[%d]adjust phase to %d", avsync->session_id, avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800760 }
761 }
762
763 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -0800764 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800765 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -0800766 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800767 }
768 return expire;
769}
770
Song Zhao35a82df2021-04-15 10:58:49 -0700771static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -0800772{
Song Zhao35a82df2021-04-15 10:58:49 -0700773 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800774 log_trace("[%d]cur_period: %d last_period: %d",
775 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -0700776 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
777 ret = true;
778 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
779 ret = true;
780 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
781 ret = true;
782 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
783 ret = true;
784
785 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800786}
787
788int av_sync_set_speed(void *sync, float speed)
789{
790 struct av_sync_session *avsync = (struct av_sync_session *)sync;
791
792 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800793 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800794 return -1;
795 }
796
Song Zhaoea5a0412021-01-18 16:40:08 -0800797 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
798 avsync->mode == AV_SYNC_MODE_IPTV) {
799 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800800 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800801 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800802
Song Zhaoea5a0412021-01-18 16:40:08 -0800803 avsync->speed = speed;
804
805 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
806 if (speed == 1.0) {
807 avsync->mode = avsync->backup_mode;
808 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
809 } else {
810 avsync->backup_mode = avsync->mode;
811 avsync->mode = AV_SYNC_MODE_FREE_RUN;
812 log_info("[%d]audio to freerun mode", avsync->session_id);
813 }
814 }
815#if 0
Song Zhaoc03ba122020-12-23 21:54:02 -0800816 if (avsync->mode != AV_SYNC_MODE_VMASTER) {
817 log_info("ignore set speed in mode %d", avsync->mode);
818 return 0;
819 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800820#endif
Song Zhaoc03ba122020-12-23 21:54:02 -0800821
Song Zhaoea5a0412021-01-18 16:40:08 -0800822 log_info("session[%d] set rate to %f", avsync->session_id, speed);
823 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800824}
825
826int av_sync_change_mode(void *sync, enum sync_mode mode)
827{
828 struct av_sync_session *avsync = (struct av_sync_session *)sync;
829
830 if (!avsync)
831 return -1;
832
Song Zhaoea5a0412021-01-18 16:40:08 -0800833 if (msync_session_set_mode(avsync->fd, mode)) {
834 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800835 return -1;
836 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800837 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -0800838 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800839 return 0;
840}
841
Song Zhao01031bb2021-05-13 21:23:20 -0700842int av_sync_get_mode(void *sync, enum sync_mode *mode)
843{
844 struct av_sync_session *avsync = (struct av_sync_session *)sync;
845
846 if (!avsync || !mode)
847 return -1;
848
849 *mode = avsync->mode;
850 return 0;
851}
852
Song Zhaoc03ba122020-12-23 21:54:02 -0800853int av_sync_set_pause_pts(void *sync, pts90K pts)
854{
855 struct av_sync_session *avsync = (struct av_sync_session *)sync;
856
857 if (!avsync)
858 return -1;
859
860 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -0800861 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800862 return 0;
863}
864
865int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
866{
867 struct av_sync_session *avsync = (struct av_sync_session *)sync;
868
869 if (!avsync)
870 return -1;
871
872 avsync->pause_pts_cb = cb;
873 avsync->pause_cb_priv = priv;
874 return 0;
875}
Song Zhaoea5a0412021-01-18 16:40:08 -0800876
877static void trigger_audio_start_cb(struct av_sync_session *avsync,
878 avs_ascb_reason reason)
879{
880 if (avsync) {
881 pthread_mutex_lock(&avsync->lock);
882 if (avsync->audio_start) {
883 avsync->audio_start(avsync->audio_start_priv, reason);
884 avsync->session_started = true;
885 avsync->audio_start = NULL;
886 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
887 }
888 pthread_mutex_unlock(&avsync->lock);
889 }
890}
891
892avs_start_ret av_sync_audio_start(
893 void *sync,
894 pts90K pts,
895 pts90K delay,
896 audio_start_cb cb,
897 void *priv)
898{
899 struct av_sync_session *avsync = (struct av_sync_session *)sync;
900 uint32_t start_mode;
901 avs_start_ret ret = AV_SYNC_ASTART_ERR;
902 bool create_poll_t = false;
903
904 if (!avsync)
905 return ret;
906
907 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
908 log_error("[%d]fail to set audio start", avsync->session_id);
909
yongchun.li107a6162021-05-05 02:38:57 -0700910 if (avsync->in_audio_switch
911 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET) {
912 log_info("%d audio_switch_state to start start mode %d",
913 avsync->session_id, start_mode);
914 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
915 }
916
Song Zhaoea5a0412021-01-18 16:40:08 -0800917 if (start_mode == AVS_START_SYNC) {
918 ret = AV_SYNC_ASTART_SYNC;
919 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -0700920 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -0700921 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800922 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -0700923 avsync->state = AV_SYNC_STAT_RUNNING;
924 } else if (start_mode == AVS_START_AGAIN) {
925 ret = AV_SYNC_ASTART_AGAIN;
926 }
927
928 if (ret == AV_SYNC_ASTART_AGAIN)
929 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800930
yongchun.li107a6162021-05-05 02:38:57 -0700931 if (avsync->mode == AV_SYNC_MODE_AMASTER || avsync->in_audio_switch) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800932 create_poll_t = true;
933 if (start_mode == AVS_START_ASYNC) {
934 if (!cb) {
935 log_error("[%d]invalid cb", avsync->session_id);
936 return AV_SYNC_ASTART_ERR;
937 }
938 avsync->audio_start = cb;
939 avsync->audio_start_priv = priv;
940 }
Song Zhaod62bb392021-04-23 12:25:49 -0700941 } else if (LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -0800942 create_poll_t = true;
943
Song Zhaod62bb392021-04-23 12:25:49 -0700944 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800945 int ret;
946
947 log_info("[%d]start poll thread", avsync->session_id);
948 avsync->quit_poll = false;
949 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
950 if (ret) {
951 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
952 return AV_SYNC_ASTART_ERR;
953 }
954 }
Song Zhaod62bb392021-04-23 12:25:49 -0700955 if (LIVE_MODE(avsync->mode)) {
956 uint32_t systime;
957 msync_session_get_wall(avsync->fd, &systime, NULL);
958 log_info("[%d]return %u w %u pts %u d %u",
959 avsync->session_id, ret, systime, pts, delay);
960 }
961exit:
Song Zhaoea5a0412021-01-18 16:40:08 -0800962 log_info("[%d]return %u", avsync->session_id, ret);
963 return ret;
964}
965
966int av_sync_audio_render(
967 void *sync,
968 pts90K pts,
969 struct audio_policy *policy)
970{
971 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -0700972 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800973 uint32_t systime;
974 struct av_sync_session *avsync = (struct av_sync_session *)sync;
975 avs_audio_action action = AA_SYNC_AA_MAX;
976
977 if (!avsync || !policy)
978 return -1;
979
yongchun.li107a6162021-05-05 02:38:57 -0700980 msync_session_get_wall(avsync->fd, &systime, NULL);
981
982 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
983 pts, systime, avsync->mode, (int)(pts-systime)/90);
984
985 if (avsync->in_audio_switch
986 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
987 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
988 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
989 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
990 action = AV_SYNC_AA_RENDER;
991 } else if ((int)(systime - pts) > 0) {
992 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
993 (int)(systime - pts)/90, systime, pts);
994 action = AV_SYNC_AA_DROP;
995 } else {
996 action = AV_SYNC_AA_INSERT;
997 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
998 (int)(pts - systime)/90, systime, pts);
999 }
1000 goto done;
1001 }
1002
Song Zhaoea5a0412021-01-18 16:40:08 -08001003 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1004 avsync->mode == AV_SYNC_MODE_AMASTER) {
1005 action = AV_SYNC_AA_RENDER;
1006 goto done;
1007 }
1008
Song Zhaod62bb392021-04-23 12:25:49 -07001009 /* stopping procedure, unblock audio rendering */
1010 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER &&
1011 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1012 action = AV_SYNC_AA_DROP;
1013 goto done;
1014 }
1015
Song Zhaod62bb392021-04-23 12:25:49 -07001016
Song Zhao7daf3a12021-05-10 22:22:25 -07001017 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1018 avsync->mode == AV_SYNC_MODE_AMASTER) {
1019 action = AV_SYNC_AA_RENDER;
1020 goto done;
1021 }
1022
Song Zhaod62bb392021-04-23 12:25:49 -07001023 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1024 LIVE_MODE(avsync->mode) &&
1025 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1026 /* outlier by stream error */
1027 avsync->outlier_cnt++;
1028 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1029 /* treat as disc, just drop current frame */
1030 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1031 avsync->outlier_cnt = 0;
1032 action = AV_SYNC_AA_DROP;
1033 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001034 goto done;
1035 }
1036 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1037 pts = systime;
1038 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001039 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001040 goto done;
1041 }
1042
1043 avsync->outlier_cnt = 0;
1044 /* low bound from sync_lost to sync_setup */
1045 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1046 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1047 action = AV_SYNC_AA_RENDER;
1048 goto done;
1049 }
1050
1051 /* high bound of sync_setup */
1052 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1053 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1054 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001055 action = AV_SYNC_AA_RENDER;
1056 goto done;
1057 }
1058
1059 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001060 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001061 action = AV_SYNC_AA_DROP;
1062 goto done;
1063 }
1064
1065 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001066 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001067 action = AV_SYNC_AA_INSERT;
1068 goto done;
1069 }
1070
1071done:
1072 policy->action = action;
1073 policy->delta = (int)(systime - pts);
1074 if (action == AV_SYNC_AA_RENDER) {
1075 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001076 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001077 if (!out_lier)
1078 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001079 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001080 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001081 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1082 msync_session_update_apts(avsync->fd, systime, pts, 0);
1083 log_info("[%d] audio switch done sys %u pts %u",
1084 avsync->session_id, systime, pts);
1085 msync_session_set_audio_switch(avsync->fd, false);
1086 avsync->in_audio_switch = false;
1087 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1088 } else {
1089 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1090 avsync->session_id, action, systime, pts, systime - pts);
1091 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001092 } else {
Song Zhao409739b2021-05-12 22:21:40 -07001093 if (abs_diff(systime, pts) > AV_DISC_THRES_MIN &&
yongchun.li085b5a42021-05-24 04:22:53 -07001094 avsync->last_disc_pts != pts &&
1095 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001096 log_info ("[%d]audio disc %u --> %u",
1097 avsync->session_id, systime, pts);
1098 msync_session_set_audio_dis(avsync->fd, pts);
1099 avsync->last_disc_pts = pts;
1100 }
Song Zhaof46932e2021-05-21 01:51:45 -07001101 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001102 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001103 }
1104
1105 return ret;
1106}
1107
1108int av_sync_get_clock(void *sync, pts90K *pts)
1109{
1110 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1111
1112 if (!avsync || !pts)
1113 return -1;
1114 return msync_session_get_wall(avsync->fd, pts, NULL);
1115}
1116
1117static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001118 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001119{
Song Zhaoe208d692021-04-19 15:38:52 -07001120 log_info("[%d]amode %d mode %d v/a/vt %d/%d/%d", avsync->session_id,
1121 avsync->active_mode, avsync->mode, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001122 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1123 float speed;
1124 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaoe208d692021-04-19 15:38:52 -07001125 a_active && avsync->audio_start) {
yongchun.li107a6162021-05-05 02:38:57 -07001126 if (v_active || v_timeout || avsync->in_audio_switch) {
Song Zhaoe208d692021-04-19 15:38:52 -07001127 log_info("audio start cb");
1128 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
yongchun.li107a6162021-05-05 02:38:57 -07001129 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001130 }
1131
1132 if (!msync_session_get_rate(avsync->fd, &speed)) {
1133 /* speed change is triggered by asink,
1134 * attached audio HAL will handle it
1135 */
1136 if (speed != avsync->speed)
1137 log_info("[%d]new rate %f", avsync->session_id, speed);
1138 if (speed == 1.0) {
1139 avsync->mode = avsync->backup_mode;
1140 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1141 } else {
1142 avsync->backup_mode = avsync->mode;
1143 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1144 log_info("[%d]audio to freerun mode", avsync->session_id);
1145 }
1146 avsync->speed = speed;
1147 }
Song Zhaod62bb392021-04-23 12:25:49 -07001148 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1149 struct session_debug debug;
1150 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1151 if (debug.debug_freerun) {
1152 avsync->backup_mode = avsync->mode;
1153 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1154 log_warn("[%d]audio to freerun mode", avsync->session_id);
1155 } else {
1156 avsync->mode = avsync->backup_mode;
1157 log_warn("[%d]audio back to mode %d",
1158 avsync->session_id, avsync->mode);
1159 }
1160 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001161 }
1162}
1163
1164static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001165 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001166{
1167 log_info("[%d]amode mode %d %d v/a %d/%d", avsync->session_id,
1168 avsync->active_mode, avsync->mode, v_active, a_active);
Song Zhaod62bb392021-04-23 12:25:49 -07001169 if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1170 struct session_debug debug;
1171 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1172 if (debug.debug_freerun) {
1173 avsync->backup_mode = avsync->mode;
1174 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1175 log_warn("[%d]video to freerun mode", avsync->session_id);
1176 } else
1177 avsync->mode = avsync->backup_mode;
1178 log_warn("[%d]video back to mode %d",
1179 avsync->session_id, avsync->mode);
1180 }
1181 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001182}
1183
1184static void * poll_thread(void * arg)
1185{
1186 int ret = 0;
1187 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1188 const int fd = avsync->fd;
1189 struct pollfd pfd = {
1190 /* default blocking capture */
1191 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1192 .fd = avsync->fd,
1193 };
1194
1195 prctl (PR_SET_NAME, "avs_poll");
1196 log_info("[%d]enter", avsync->session_id);
1197 while (!avsync->quit_poll) {
1198 for (;;) {
1199 ret = poll(&pfd, 1, 10);
1200 if (ret > 0)
1201 break;
1202 if (avsync->quit_poll)
1203 goto exit;
1204 if (errno == EINTR)
1205 continue;
1206 }
1207
1208 /* error handling */
1209 if (pfd.revents & POLLERR)
1210 log_error("[%d]POLLERR received", avsync->session_id);
1211
Song Zhaod62bb392021-04-23 12:25:49 -07001212 /* mode change. Non-exclusive wait so all the processes
1213 * shall be woken up
1214 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001215 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001216 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -08001217
1218 msync_session_get_stat(fd, &avsync->active_mode,
yongchun.li107a6162021-05-05 02:38:57 -07001219 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch);
Song Zhaoea5a0412021-01-18 16:40:08 -08001220
1221 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhaoe208d692021-04-19 15:38:52 -07001222 handle_mode_change_a(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001223 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhaoe208d692021-04-19 15:38:52 -07001224 handle_mode_change_v(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001225 }
1226 }
1227exit:
1228 log_info("[%d]quit", avsync->session_id);
1229 return NULL;
1230}
1231
Song Zhaod62bb392021-04-23 12:25:49 -07001232int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001233{
1234 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1235
1236 if (!avsync)
1237 return -1;
1238
1239 if (avsync->type != AV_SYNC_TYPE_PCR)
1240 return -2;
1241
Song Zhaod62bb392021-04-23 12:25:49 -07001242 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001243}
1244
Song Zhaod62bb392021-04-23 12:25:49 -07001245int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001246{
1247 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1248
1249 if (!avsync)
1250 return -1;
1251
Song Zhaod62bb392021-04-23 12:25:49 -07001252 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001253}
1254
1255int av_sync_set_session_name(void *sync, const char *name)
1256{
1257 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1258
1259 if (!avsync)
1260 return -1;
1261
1262 return msync_session_set_name(avsync->fd, name);
1263}
yongchun.li107a6162021-05-05 02:38:57 -07001264
1265int av_sync_set_audio_switch(void *sync, bool start)
1266{
1267 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1268 bool v_active, a_active, v_timeout;
1269
1270 if (!avsync)
1271 return -1;
1272 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
1273 &v_active, &a_active,
Song Zhaobe513572021-05-13 13:10:21 -07001274 &v_timeout, &avsync->in_audio_switch)) {
yongchun.li107a6162021-05-05 02:38:57 -07001275 log_error("[%d] can not get session state",
1276 avsync->session_id);
1277 return -1;
1278 }
1279 if (!v_active || !a_active) {
1280 log_error("[%d] no apply if not AV both active v %d a %d",
1281 avsync->session_id, v_active, a_active);
1282 return -1;
1283 }
1284 if (msync_session_set_audio_switch(avsync->fd, start)) {
1285 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1286 return -1;
1287 }
1288 avsync->in_audio_switch = start;
1289 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1290 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1291 return 0;
1292}
1293
1294int av_sync_get_audio_switch(void *sync, bool *start)
1295{
1296 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1297
1298 if (!avsync)
1299 return -1;
1300 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
1301 NULL, NULL, NULL, &avsync->in_audio_switch)) {
1302 log_error("[%d] can not audio seamless switch state",
1303 avsync->session_id);
1304 return -1;
1305 }
1306 if (start) *start = avsync->in_audio_switch;
1307 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001308}
Song Zhao8039f562021-05-18 18:11:25 -07001309
1310enum clock_recovery_stat av_sync_get_clock_devication(void *sync, int32_t *ppm)
1311{
1312 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1313
1314 if (!avsync || avsync->mode != AV_SYNC_MODE_PCR_MASTER)
1315 return CLK_RECOVERY_NOT_RUNNING;
1316
1317 //TODO
1318 return CLK_RECOVERY_ONGOING;
1319}