blob: 248bf48030275cc0be66203e1483d0fe250e667d [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 Zhao35a82df2021-04-15 10:58:49 -0700109
110 /* error detection */
111 uint32_t last_poptime;
Song Zhaod62bb392021-04-23 12:25:49 -0700112 uint32_t outlier_cnt;
Song Zhao409739b2021-05-12 22:21:40 -0700113 pts90K last_disc_pts;
114
yongchun.li107a6162021-05-05 02:38:57 -0700115 // indicate set audio switch
116 bool in_audio_switch;
117 enum audio_switch_state_ audio_switch_state;
Song Zhaoc03ba122020-12-23 21:54:02 -0800118};
119
120#define MAX_FRAME_NUM 32
121#define DEFAULT_START_THRESHOLD 2
122#define TIME_UNIT90K (90000)
Song Zhaod62bb392021-04-23 12:25:49 -0700123#define AV_DISC_THRES_MIN (TIME_UNIT90K * 3)
Song Zhao7daf3a12021-05-10 22:22:25 -0700124#define A_ADJ_THREDHOLD_HB (900 * 6) //60ms
125#define A_ADJ_THREDHOLD_LB (900 * 2) //20ms
Song Zhao52f55192021-05-06 10:52:21 -0700126#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800127#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhaod62bb392021-04-23 12:25:49 -0700128#define LIVE_MODE(mode) ((mode) == AV_SYNC_MODE_PCR_MASTER || (mode) == AV_SYNC_MODE_IPTV)
129
130#define STREAM_DISC_THRES (TIME_UNIT90K * 10)
131#define OUTLIER_MAX_CNT 8
Song Zhaoc03ba122020-12-23 21:54:02 -0800132
133static uint64_t time_diff (struct timeval *b, struct timeval *a);
134static bool frame_expire(struct av_sync_session* avsync,
135 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800136 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800137 struct vframe * frame,
138 struct vframe * next_frame,
139 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700140static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800141 int cur_period,
142 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800143static void * poll_thread(void * arg);
144static void trigger_audio_start_cb(struct av_sync_session *avsync,
145 avs_ascb_reason reason);
Song Zhaoc03ba122020-12-23 21:54:02 -0800146
Song Zhaoea5a0412021-01-18 16:40:08 -0800147int av_sync_open_session(int *session_id)
148{
149 int fd = msync_create_session();
150 int id, rc;
151
152 if (fd < 0) {
153 log_error("fail");
154 return -1;
155 }
156 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
157 if (rc) {
158 log_error("new session errno:%d", errno);
159 return rc;
160 }
161 *session_id = id;
162 return fd;
163}
164
165void av_sync_close_session(int session)
166{
167 msync_destory_session(session);
168}
169
170static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800171 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800172 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800173 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800174 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800175{
176 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800177 char dev_name[20];
Song Zhaoc03ba122020-12-23 21:54:02 -0800178
179 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
180 if (!avsync) {
181 log_error("OOM");
182 return NULL;
183 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800184
185 if (type == AV_SYNC_TYPE_VIDEO) {
186 avsync->pattern_detector = create_pattern_detector();
187 if (!avsync->pattern_detector) {
188 log_error("pd create fail");
189 goto err;
190 }
191
192 if (!start_thres)
193 avsync->start_thres = DEFAULT_START_THRESHOLD;
194 else {
195 if (start_thres > 5) {
196 log_error("start_thres too big: %d", start_thres);
197 goto err2;
198 }
199 avsync->start_thres = start_thres;
200 }
201 avsync->phase_set = false;
202 avsync->first_frame_toggled = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800203 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800204
205 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800206 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800207 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800208 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800209 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800210 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800211 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800212 avsync->speed = 1.0f;
213 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhao409739b2021-05-12 22:21:40 -0700214 avsync->vsync_interval = -1;
215 avsync->last_disc_pts = -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800216
217 pthread_mutex_init(&avsync->lock, NULL);
Song Zhaoea5a0412021-01-18 16:40:08 -0800218 log_info("[%d] mode %d type %d start_thres %d",
219 session_id, mode, type, start_thres);
220
221 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
222 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
223 if (avsync->fd < 0) {
224 log_error("open %s errno %d", dev_name, errno);
225 goto err2;
226 }
227
228 if (!attach) {
229 msync_session_set_mode(avsync->fd, mode);
230 avsync->mode = mode;
231 } else {
232 avsync->attached = true;
233 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
234 log_error("get mode");
235 goto err2;
236 }
237 avsync->backup_mode = avsync->mode;
238 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy)) {
239 log_error("get policy");
240 goto err2;
241 }
yongchun.li107a6162021-05-05 02:38:57 -0700242 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
243 NULL, NULL, NULL, &avsync->in_audio_switch)) {
244 log_error("get state");
245 goto err2;
246 }
247 if (avsync->in_audio_switch) {
248 log_info("audio_switch_state reseted the audio");
249 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
250 }
251
Song Zhaoea5a0412021-01-18 16:40:08 -0800252 log_info("[%d]retrieve sync mode %d policy %d",
253 session_id, avsync->mode, avsync->start_policy);
254 }
255
Song Zhaoc03ba122020-12-23 21:54:02 -0800256 return avsync;
Song Zhaoea5a0412021-01-18 16:40:08 -0800257err2:
258 destroy_pattern_detector(avsync->pattern_detector);
259err:
260 free(avsync);
261 return NULL;
262}
263
264void* av_sync_create(int session_id,
265 enum sync_mode mode,
266 enum sync_type type,
267 int start_thres)
268{
269 return create_internal(session_id, mode,
270 type, start_thres, false);
271}
272
273void* av_sync_attach(int session_id, enum sync_type type)
274{
275 return create_internal(session_id, AV_SYNC_MODE_MAX,
276 type, 0, true);
277}
278
279int av_sync_video_config(void *sync, struct video_config* config)
280{
281 struct av_sync_session *avsync = (struct av_sync_session *)sync;
282
283 if (!avsync || !config)
284 return -1;
285
286 if (config->delay != 1 && config->delay != 2) {
287 log_error("invalid delay: %d\n", config->delay);
288 return -1;
289 }
290
291 avsync->delay = config->delay;
292
293 log_info("[%d] delay: %d",
294 avsync->session_id, config->delay);
295 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800296}
297
298static int internal_stop(struct av_sync_session *avsync)
299{
300 int ret = 0;
301 struct vframe *frame;
302
303 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800304 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
305 frame->free(frame);
306 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800307 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800308 pthread_mutex_unlock(&avsync->lock);
309 return ret;
310}
311
312/* destroy and detach from kernel session */
313void av_sync_destroy(void *sync)
314{
315 struct av_sync_session *avsync = (struct av_sync_session *)sync;
316
317 if (!avsync)
318 return;
319
Song Zhaoea5a0412021-01-18 16:40:08 -0800320 log_info("[%d]begin", avsync->session_id);
321 if (avsync->state != AV_SYNC_STAT_INIT) {
322 if (avsync->type == AV_SYNC_TYPE_VIDEO)
323 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800324
Song Zhaoea5a0412021-01-18 16:40:08 -0800325 avsync->quit_poll = true;
326 if (avsync->poll_thread) {
327 pthread_join(avsync->poll_thread, NULL);
328 avsync->poll_thread = 0;
329 }
330 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoaf368d52021-02-17 17:53:45 -0800331 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800332
Song Zhaoea5a0412021-01-18 16:40:08 -0800333 if (avsync->session_started) {
334 if (avsync->type == AV_SYNC_TYPE_VIDEO)
335 msync_session_set_video_stop(avsync->fd);
336 else
337 msync_session_set_audio_stop(avsync->fd);
338 }
339 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800340 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800341 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
342 destroy_q(avsync->frame_q);
343 destroy_pattern_detector(avsync->pattern_detector);
344 }
345 log_info("[%d]done", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800346 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800347}
348
349int avs_sync_set_start_policy(void *sync, enum sync_start_policy policy)
350{
351 struct av_sync_session *avsync = (struct av_sync_session *)sync;
352
353 if (!avsync || !avsync->fd)
354 return -1;
355
356 log_info("[%d]policy %u --> %u", avsync->start_policy, policy);
357 avsync->start_policy = policy;
358 /* v_peek will be handled by libamlavsync */
359 if (policy != AV_SYNC_START_NONE &&
360 policy != AV_SYNC_START_V_PEEK)
361 return msync_session_set_start_policy(avsync->fd, policy);
362
363 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800364}
365
366int av_sync_pause(void *sync, bool pause)
367{
368 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700369 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800370 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800371
372 if (!avsync)
373 return -1;
374
Song Zhaoea5a0412021-01-18 16:40:08 -0800375 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
376 return -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800377
yongchun.li107a6162021-05-05 02:38:57 -0700378 rc = msync_session_get_stat(avsync->fd, &avsync->active_mode,
379 &v_active, &a_active, &v_timeout,
380 &avsync->in_audio_switch);
381
Song Zhaoea5a0412021-01-18 16:40:08 -0800382 /* ignore */
yongchun.li107a6162021-05-05 02:38:57 -0700383 if (avsync->mode == AV_SYNC_MODE_AMASTER
384 && avsync->type == AV_SYNC_TYPE_VIDEO
385 && a_active && !avsync->in_audio_switch)
Song Zhaoc03ba122020-12-23 21:54:02 -0800386 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800387
yongchun.li107a6162021-05-05 02:38:57 -0700388 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
389 log_info("[%d] ignore the pause from audio", avsync->session_id);
390 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
391 return 0;
392 }
393
Song Zhaoea5a0412021-01-18 16:40:08 -0800394 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800395 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800396 log_info("[%d]paused:%d type:%d rc %d",
397 avsync->session_id, pause, avsync->type, rc);
Song Zhaoc03ba122020-12-23 21:54:02 -0800398
Song Zhaoea5a0412021-01-18 16:40:08 -0800399 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800400}
401
402int av_sync_push_frame(void *sync , struct vframe *frame)
403{
404 int ret;
405 struct vframe *prev;
406 struct av_sync_session *avsync = (struct av_sync_session *)sync;
407
408 if (!avsync)
409 return -1;
410
Song Zhaoea5a0412021-01-18 16:40:08 -0800411 if (!avsync->frame_q) {
412 /* policy should be final now */
413 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy)) {
414 log_error("[%d]get policy", avsync->session_id);
415 return -1;
416 }
417
418 avsync->frame_q = create_q(MAX_FRAME_NUM);
419 if (!avsync->frame_q) {
420 log_error("[%d]create queue fail", avsync->session_id);
421 return -1;
422 }
423
424 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
425 avsync->mode == AV_SYNC_MODE_IPTV) {
426 int ret;
427
428 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
429 if (ret) {
430 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
431 destroy_q(avsync->frame_q);
432 return -1;
433 }
434 }
435 }
436
Song Zhaoc03ba122020-12-23 21:54:02 -0800437 if (!peek_item(avsync->frame_q, (void **)&prev, 0)) {
Song Zhaod62bb392021-04-23 12:25:49 -0700438 if (prev->pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800439 dqueue_item(avsync->frame_q, (void **)&prev);
440 prev->free(prev);
Song Zhaoea5a0412021-01-18 16:40:08 -0800441 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800442 }
443 }
444
445 frame->hold_period = 0;
446 ret = queue_item(avsync->frame_q, frame);
447 if (avsync->state == AV_SYNC_STAT_INIT &&
448 queue_size(avsync->frame_q) >= avsync->start_thres) {
449 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaoea5a0412021-01-18 16:40:08 -0800450 log_info("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800451 }
452
453 if (ret)
454 log_error("%s queue fail:%d", ret);
Song Zhaoea5a0412021-01-18 16:40:08 -0800455 log_debug("[%d]push %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800456 return ret;
457
458}
459
460struct vframe *av_sync_pop_frame(void *sync)
461{
Song Zhaoea5a0412021-01-18 16:40:08 -0800462 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800463 struct av_sync_session *avsync = (struct av_sync_session *)sync;
464 int toggle_cnt = 0;
465 uint32_t systime;
Song Zhao468fd652021-01-15 22:13:04 -0800466 bool pause_pts_reached = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800467 uint32_t interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800468
469 pthread_mutex_lock(&avsync->lock);
470 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhaod62bb392021-04-23 12:25:49 -0700471 log_info("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800472 goto exit;
473 }
474
Song Zhaoea5a0412021-01-18 16:40:08 -0800475 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700476 uint32_t pts;
477
Song Zhaoc03ba122020-12-23 21:54:02 -0800478 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800479 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800480 goto exit;
481 }
Song Zhao35a82df2021-04-15 10:58:49 -0700482 msync_session_get_wall(avsync->fd, &systime, &interval);
483 pts = frame->pts - avsync->delay * interval;
484 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800485 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700486 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800487 }
488
Song Zhaoea5a0412021-01-18 16:40:08 -0800489 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700490 !avsync->first_frame_toggled &&
491 !msync_clock_started(avsync->fd)) {
492 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800493 log_trace("[%d]clock not started", avsync->session_id);
494 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800495 }
496
Song Zhaoea5a0412021-01-18 16:40:08 -0800497 enter_last_frame = avsync->last_frame;
498 msync_session_get_wall(avsync->fd, &systime, &interval);
499
500 /* handle refresh rate change */
501 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
502 avsync->vsync_interval != interval) {
503 log_info("[%d]vsync interval update %d --> %u",
504 avsync->session_id, avsync->vsync_interval, interval);
505 avsync->vsync_interval = interval;
506 avsync->phase_set = false;
507 reset_pattern(avsync->pattern_detector);
508 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800509 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
510 struct vframe *next_frame = NULL;
511
512 peek_item(avsync->frame_q, (void **)&next_frame, 1);
513 if (next_frame)
Song Zhaoea5a0412021-01-18 16:40:08 -0800514 log_debug("[%d]cur_f %u next_f %u",
515 avsync->session_id, frame->pts, next_frame->pts);
516 if (frame_expire(avsync, systime, interval,
517 frame, next_frame, toggle_cnt)) {
518 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800519 toggle_cnt++;
520
Song Zhao35a82df2021-04-15 10:58:49 -0700521 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800522 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao35a82df2021-04-15 10:58:49 -0700523 avsync->last_holding_peroid))
524 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
525
Song Zhaoc03ba122020-12-23 21:54:02 -0800526 if (avsync->last_frame)
527 avsync->last_holding_peroid = avsync->last_frame->hold_period;
528
529 dqueue_item(avsync->frame_q, (void **)&frame);
530 if (avsync->last_frame) {
531 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800532 if (toggle_cnt > 1) {
Song Zhao35a82df2021-04-15 10:58:49 -0700533 log_debug("[%d]free %u cur %u system/d %u/%u", avsync->session_id,
534 avsync->last_frame->pts, frame->pts, systime, systime - avsync->last_poptime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800535 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800536 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800537 } else {
538 avsync->first_frame_toggled = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800539 log_info("[%d]first frame %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800540 }
541 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800542 avsync->last_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800543 } else
544 break;
545 }
546
547 /* pause pts */
548 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800549 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800550 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800551 else
Song Zhao468fd652021-01-15 22:13:04 -0800552 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
553 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
554 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
555 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
556 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800557
Song Zhao468fd652021-01-15 22:13:04 -0800558 if (pause_pts_reached) {
559 if (avsync->pause_pts_cb)
560 avsync->pause_pts_cb(avsync->pause_pts,
Song Zhaoc03ba122020-12-23 21:54:02 -0800561 avsync->pause_cb_priv);
562
Song Zhao468fd652021-01-15 22:13:04 -0800563 /* stay in paused until av_sync_pause(false) */
564 avsync->paused = true;
565 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoea5a0412021-01-18 16:40:08 -0800566 log_info ("[%d]reach pause pts: %u",
567 avsync->session_id, avsync->last_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800568 }
569
570exit:
571 pthread_mutex_unlock(&avsync->lock);
572 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800573 if (enter_last_frame != avsync->last_frame)
574 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhao35a82df2021-04-15 10:58:49 -0700575 log_trace("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800576 msync_session_update_vpts(avsync->fd, systime,
577 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800578 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800579 if (enter_last_frame != avsync->last_frame)
580 log_debug("[%d]pop (nil)", avsync->session_id);
581
Song Zhao35a82df2021-04-15 10:58:49 -0700582 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800583 if (avsync->last_frame)
584 avsync->last_frame->hold_period++;
585 return avsync->last_frame;
586}
587
Song Zhaoc03ba122020-12-23 21:54:02 -0800588static inline uint32_t abs_diff(uint32_t a, uint32_t b)
589{
Song Zhaoea5a0412021-01-18 16:40:08 -0800590 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800591}
592
593static uint64_t time_diff (struct timeval *b, struct timeval *a)
594{
595 return (b->tv_sec - a->tv_sec)*1000000 + (b->tv_usec - a->tv_usec);
596}
597
Song Zhaoc03ba122020-12-23 21:54:02 -0800598static bool frame_expire(struct av_sync_session* avsync,
599 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800600 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800601 struct vframe * frame,
602 struct vframe * next_frame,
603 int toggle_cnt)
604{
605 uint32_t fpts = frame->pts;
606 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800607 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800608
Song Zhaod62bb392021-04-23 12:25:49 -0700609 if (avsync->mode == AV_SYNC_MODE_FREE_RUN)
610 return true;
611
Song Zhaoc03ba122020-12-23 21:54:02 -0800612 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
613 return false;
614
615 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
616 return true;
617
618 if (!fpts) {
619 if (avsync->last_frame) {
620 /* try to accumulate duration as PTS */
621 fpts = avsync->vpts + avsync->last_frame->duration;
622 } else {
623 fpts = avsync->vpts;
624 }
625 }
626 systime += pts_correction;
627
628 /* phase adjustment */
629 if (avsync->phase_set)
630 systime += avsync->phase;
631
Song Zhao35a82df2021-04-15 10:58:49 -0700632 log_trace("[%d]systime:%u phase:%u correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800633 avsync->session_id, systime,
Song Zhao35a82df2021-04-15 10:58:49 -0700634 avsync->phase_set?avsync->phase:0, pts_correction, fpts);
Song Zhaod62bb392021-04-23 12:25:49 -0700635 if (abs_diff(systime, fpts) > AV_DISC_THRES_MIN &&
Song Zhaoc03ba122020-12-23 21:54:02 -0800636 avsync->first_frame_toggled) {
637 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800638 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800639 return false;
640
Song Zhao5d2b4772021-01-18 16:40:08 -0800641 if (avsync->last_systime != systime || avsync->last_pts != fpts) {
642 struct timeval now;
643
644 gettimeofday(&now, NULL);
645 avsync->last_systime = systime;
646 avsync->last_pts = fpts;
647 if (time_diff(&now, &avsync->sync_lost_print_time) >=
648 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800649 log_warn("[%d]sync lost systime:%x fpts:%x lost:%u",
650 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800651 avsync->sync_lost_cnt = 0;
Song Zhaobc6161d2021-03-08 09:59:33 -0800652 gettimeofday(&avsync->sync_lost_print_time, NULL);
Song Zhao5d2b4772021-01-18 16:40:08 -0800653 } else
654 avsync->sync_lost_cnt++;
655 }
Song Zhaod62bb392021-04-23 12:25:49 -0700656
657 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
658 LIVE_MODE(avsync->mode) &&
659 abs_diff(systime, fpts) > STREAM_DISC_THRES) {
660 /* outlier by stream error */
661 avsync->outlier_cnt++;
662 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
663 log_info("render outlier %u", fpts);
664 return true;
665 }
666 }
667
668 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800669 avsync->state = AV_SYNC_STAT_SYNC_LOST;
670 avsync->phase_set = false;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800671 reset_pattern(avsync->pattern_detector);
Song Zhaoc03ba122020-12-23 21:54:02 -0800672 if ((int)(systime - fpts) > 0) {
Song Zhao409739b2021-05-12 22:21:40 -0700673 if (LIVE_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800674 log_info ("[%d]video disc %u --> %u",
675 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700676 msync_session_set_video_dis(avsync->fd, fpts);
677 avsync->last_disc_pts = fpts;
Song Zhaoea5a0412021-01-18 16:40:08 -0800678 }
Song Zhaod62bb392021-04-23 12:25:49 -0700679 /* catch up PCR */
Song Zhaoc03ba122020-12-23 21:54:02 -0800680 return true;
Song Zhao409739b2021-05-12 22:21:40 -0700681 } else if (LIVE_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800682 /* vpts wrapping */
Song Zhaod62bb392021-04-23 12:25:49 -0700683 log_info ("[%d]video disc %u --> %u",
684 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700685 msync_session_set_video_dis(avsync->fd, fpts);
686 avsync->last_disc_pts = fpts;
687 /* clean up frames */
688 return true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800689 }
690 }
691
Song Zhao52f55192021-05-06 10:52:21 -0700692 /* In some cases, keeping pattern will enlarge the gap */
693 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
694 avsync->first_frame_toggled) {
695 reset_pattern(avsync->pattern_detector);
696 log_warn("sync pattern reset sys:%x fpts:%x",
697 systime, fpts);
698 }
699
Song Zhaoc03ba122020-12-23 21:54:02 -0800700 expire = (int)(systime - fpts) >= 0;
701
702 /* scatter the frame in different vsync whenever possible */
703 if (expire && next_frame && next_frame->pts && toggle_cnt) {
704 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhaoea5a0412021-01-18 16:40:08 -0800705 if (systime + interval < next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800706 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800707 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
708 avsync->session_id, systime, interval, next_frame->pts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800709 }
710 } else if (!expire && next_frame && next_frame->pts && !toggle_cnt
711 && avsync->first_frame_toggled) {
712 /* next vsync will have at least 2 frame expired */
Song Zhao35a82df2021-04-15 10:58:49 -0700713 if (systime + interval >= next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800714 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800715 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
716 avsync->session_id, systime, interval, next_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800717 }
718 }
719
Song Zhaoa58c3e92021-03-09 18:52:55 -0800720 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
721 correct_pattern(avsync->pattern_detector, frame, next_frame,
722 (avsync->last_frame?avsync->last_frame->hold_period:0),
723 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800724 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -0800725
726 if (expire) {
727 avsync->vpts = fpts;
728 /* phase adjustment */
729 if (!avsync->phase_set) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800730 uint32_t phase_thres = interval / 4;
Song Zhaoc03ba122020-12-23 21:54:02 -0800731 if ( systime > fpts && (systime - fpts) < phase_thres) {
732 /* too aligned to current VSYNC, separate them to 1/4 VSYNC */
733 avsync->phase += phase_thres - (systime - fpts);
734 avsync->phase_set = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800735 log_info("[%d]adjust phase to %d", avsync->session_id, avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800736 }
737 if (!avsync->phase_set && systime > fpts &&
Song Zhaoea5a0412021-01-18 16:40:08 -0800738 systime < (fpts + interval) &&
739 (systime - fpts) > interval - phase_thres) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800740 /* too aligned to previous VSYNC, separate them to 1/4 VSYNC */
Song Zhaoea5a0412021-01-18 16:40:08 -0800741 avsync->phase += phase_thres + fpts + interval - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800742 avsync->phase_set = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800743 log_info("[%d]adjust phase to %d", avsync->session_id, avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800744 }
745 }
746
747 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -0800748 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800749 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -0800750 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800751 }
752 return expire;
753}
754
Song Zhao35a82df2021-04-15 10:58:49 -0700755static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -0800756{
Song Zhao35a82df2021-04-15 10:58:49 -0700757 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800758 log_trace("[%d]cur_period: %d last_period: %d",
759 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -0700760 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
761 ret = true;
762 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
763 ret = true;
764 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
765 ret = true;
766 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
767 ret = true;
768
769 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800770}
771
772int av_sync_set_speed(void *sync, float speed)
773{
774 struct av_sync_session *avsync = (struct av_sync_session *)sync;
775
776 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800777 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800778 return -1;
779 }
780
Song Zhaoea5a0412021-01-18 16:40:08 -0800781 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
782 avsync->mode == AV_SYNC_MODE_IPTV) {
783 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800784 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800785 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800786
Song Zhaoea5a0412021-01-18 16:40:08 -0800787 avsync->speed = speed;
788
789 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
790 if (speed == 1.0) {
791 avsync->mode = avsync->backup_mode;
792 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
793 } else {
794 avsync->backup_mode = avsync->mode;
795 avsync->mode = AV_SYNC_MODE_FREE_RUN;
796 log_info("[%d]audio to freerun mode", avsync->session_id);
797 }
798 }
799#if 0
Song Zhaoc03ba122020-12-23 21:54:02 -0800800 if (avsync->mode != AV_SYNC_MODE_VMASTER) {
801 log_info("ignore set speed in mode %d", avsync->mode);
802 return 0;
803 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800804#endif
Song Zhaoc03ba122020-12-23 21:54:02 -0800805
Song Zhaoea5a0412021-01-18 16:40:08 -0800806 log_info("session[%d] set rate to %f", avsync->session_id, speed);
807 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800808}
809
810int av_sync_change_mode(void *sync, enum sync_mode mode)
811{
812 struct av_sync_session *avsync = (struct av_sync_session *)sync;
813
814 if (!avsync)
815 return -1;
816
Song Zhaoea5a0412021-01-18 16:40:08 -0800817 if (msync_session_set_mode(avsync->fd, mode)) {
818 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800819 return -1;
820 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800821 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -0800822 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800823 return 0;
824}
825
Song Zhao01031bb2021-05-13 21:23:20 -0700826int av_sync_get_mode(void *sync, enum sync_mode *mode)
827{
828 struct av_sync_session *avsync = (struct av_sync_session *)sync;
829
830 if (!avsync || !mode)
831 return -1;
832
833 *mode = avsync->mode;
834 return 0;
835}
836
Song Zhaoc03ba122020-12-23 21:54:02 -0800837int av_sync_set_pause_pts(void *sync, pts90K pts)
838{
839 struct av_sync_session *avsync = (struct av_sync_session *)sync;
840
841 if (!avsync)
842 return -1;
843
844 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -0800845 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800846 return 0;
847}
848
849int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
850{
851 struct av_sync_session *avsync = (struct av_sync_session *)sync;
852
853 if (!avsync)
854 return -1;
855
856 avsync->pause_pts_cb = cb;
857 avsync->pause_cb_priv = priv;
858 return 0;
859}
Song Zhaoea5a0412021-01-18 16:40:08 -0800860
861static void trigger_audio_start_cb(struct av_sync_session *avsync,
862 avs_ascb_reason reason)
863{
864 if (avsync) {
865 pthread_mutex_lock(&avsync->lock);
866 if (avsync->audio_start) {
867 avsync->audio_start(avsync->audio_start_priv, reason);
868 avsync->session_started = true;
869 avsync->audio_start = NULL;
870 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
871 }
872 pthread_mutex_unlock(&avsync->lock);
873 }
874}
875
876avs_start_ret av_sync_audio_start(
877 void *sync,
878 pts90K pts,
879 pts90K delay,
880 audio_start_cb cb,
881 void *priv)
882{
883 struct av_sync_session *avsync = (struct av_sync_session *)sync;
884 uint32_t start_mode;
885 avs_start_ret ret = AV_SYNC_ASTART_ERR;
886 bool create_poll_t = false;
887
888 if (!avsync)
889 return ret;
890
891 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
892 log_error("[%d]fail to set audio start", avsync->session_id);
893
yongchun.li107a6162021-05-05 02:38:57 -0700894 if (avsync->in_audio_switch
895 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET) {
896 log_info("%d audio_switch_state to start start mode %d",
897 avsync->session_id, start_mode);
898 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
899 }
900
Song Zhaoea5a0412021-01-18 16:40:08 -0800901 if (start_mode == AVS_START_SYNC) {
902 ret = AV_SYNC_ASTART_SYNC;
903 avsync->session_started = true;
904 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaod62bb392021-04-23 12:25:49 -0700905 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800906 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -0700907 avsync->state = AV_SYNC_STAT_RUNNING;
908 } else if (start_mode == AVS_START_AGAIN) {
909 ret = AV_SYNC_ASTART_AGAIN;
910 }
911
912 if (ret == AV_SYNC_ASTART_AGAIN)
913 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800914
yongchun.li107a6162021-05-05 02:38:57 -0700915 if (avsync->mode == AV_SYNC_MODE_AMASTER || avsync->in_audio_switch) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800916 create_poll_t = true;
917 if (start_mode == AVS_START_ASYNC) {
918 if (!cb) {
919 log_error("[%d]invalid cb", avsync->session_id);
920 return AV_SYNC_ASTART_ERR;
921 }
922 avsync->audio_start = cb;
923 avsync->audio_start_priv = priv;
924 }
Song Zhaod62bb392021-04-23 12:25:49 -0700925 } else if (LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -0800926 create_poll_t = true;
927
Song Zhaod62bb392021-04-23 12:25:49 -0700928 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800929 int ret;
930
931 log_info("[%d]start poll thread", avsync->session_id);
932 avsync->quit_poll = false;
933 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
934 if (ret) {
935 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
936 return AV_SYNC_ASTART_ERR;
937 }
938 }
Song Zhaod62bb392021-04-23 12:25:49 -0700939 if (LIVE_MODE(avsync->mode)) {
940 uint32_t systime;
941 msync_session_get_wall(avsync->fd, &systime, NULL);
942 log_info("[%d]return %u w %u pts %u d %u",
943 avsync->session_id, ret, systime, pts, delay);
944 }
945exit:
Song Zhaoea5a0412021-01-18 16:40:08 -0800946 log_info("[%d]return %u", avsync->session_id, ret);
947 return ret;
948}
949
950int av_sync_audio_render(
951 void *sync,
952 pts90K pts,
953 struct audio_policy *policy)
954{
955 int ret = 0;
956 uint32_t systime;
957 struct av_sync_session *avsync = (struct av_sync_session *)sync;
958 avs_audio_action action = AA_SYNC_AA_MAX;
959
960 if (!avsync || !policy)
961 return -1;
962
yongchun.li107a6162021-05-05 02:38:57 -0700963 msync_session_get_wall(avsync->fd, &systime, NULL);
964
965 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
966 pts, systime, avsync->mode, (int)(pts-systime)/90);
967
968 if (avsync->in_audio_switch
969 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
970 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
971 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
972 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
973 action = AV_SYNC_AA_RENDER;
974 } else if ((int)(systime - pts) > 0) {
975 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
976 (int)(systime - pts)/90, systime, pts);
977 action = AV_SYNC_AA_DROP;
978 } else {
979 action = AV_SYNC_AA_INSERT;
980 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
981 (int)(pts - systime)/90, systime, pts);
982 }
yongchun.li085b5a42021-05-24 04:22:53 -0700983 action = AV_SYNC_AA_RENDER;
yongchun.li107a6162021-05-05 02:38:57 -0700984 goto done;
985 }
986
Song Zhaoea5a0412021-01-18 16:40:08 -0800987 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
988 avsync->mode == AV_SYNC_MODE_AMASTER) {
989 action = AV_SYNC_AA_RENDER;
990 goto done;
991 }
992
Song Zhaod62bb392021-04-23 12:25:49 -0700993 /* stopping procedure, unblock audio rendering */
994 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER &&
995 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
996 action = AV_SYNC_AA_DROP;
997 goto done;
998 }
999
Song Zhaod62bb392021-04-23 12:25:49 -07001000
Song Zhao7daf3a12021-05-10 22:22:25 -07001001 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1002 avsync->mode == AV_SYNC_MODE_AMASTER) {
1003 action = AV_SYNC_AA_RENDER;
1004 goto done;
1005 }
1006
Song Zhaod62bb392021-04-23 12:25:49 -07001007 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1008 LIVE_MODE(avsync->mode) &&
1009 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1010 /* outlier by stream error */
1011 avsync->outlier_cnt++;
1012 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1013 /* treat as disc, just drop current frame */
1014 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1015 avsync->outlier_cnt = 0;
1016 action = AV_SYNC_AA_DROP;
1017 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001018 goto done;
1019 }
1020 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1021 pts = systime;
1022 action = AV_SYNC_AA_RENDER;
1023 goto done;
1024 }
1025
1026 avsync->outlier_cnt = 0;
1027 /* low bound from sync_lost to sync_setup */
1028 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1029 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1030 action = AV_SYNC_AA_RENDER;
1031 goto done;
1032 }
1033
1034 /* high bound of sync_setup */
1035 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1036 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1037 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001038 action = AV_SYNC_AA_RENDER;
1039 goto done;
1040 }
1041
1042 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001043 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001044 action = AV_SYNC_AA_DROP;
1045 goto done;
1046 }
1047
1048 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001049 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001050 action = AV_SYNC_AA_INSERT;
1051 goto done;
1052 }
1053
1054done:
1055 policy->action = action;
1056 policy->delta = (int)(systime - pts);
1057 if (action == AV_SYNC_AA_RENDER) {
1058 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001059 if (!avsync->in_audio_switch) {
1060 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhao409739b2021-05-12 22:21:40 -07001061 log_info("[%d]return %d sys %u - pts %u = %d",
1062 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001063 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1064 msync_session_update_apts(avsync->fd, systime, pts, 0);
1065 log_info("[%d] audio switch done sys %u pts %u",
1066 avsync->session_id, systime, pts);
1067 msync_session_set_audio_switch(avsync->fd, false);
1068 avsync->in_audio_switch = false;
1069 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1070 } else {
1071 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1072 avsync->session_id, action, systime, pts, systime - pts);
1073 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001074 } else {
Song Zhao409739b2021-05-12 22:21:40 -07001075 if (abs_diff(systime, pts) > AV_DISC_THRES_MIN &&
yongchun.li085b5a42021-05-24 04:22:53 -07001076 avsync->last_disc_pts != pts &&
1077 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001078 log_info ("[%d]audio disc %u --> %u",
1079 avsync->session_id, systime, pts);
1080 msync_session_set_audio_dis(avsync->fd, pts);
1081 avsync->last_disc_pts = pts;
1082 }
1083 log_info("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001084 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001085 }
1086
1087 return ret;
1088}
1089
1090int av_sync_get_clock(void *sync, pts90K *pts)
1091{
1092 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1093
1094 if (!avsync || !pts)
1095 return -1;
1096 return msync_session_get_wall(avsync->fd, pts, NULL);
1097}
1098
1099static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001100 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001101{
Song Zhaoe208d692021-04-19 15:38:52 -07001102 log_info("[%d]amode %d mode %d v/a/vt %d/%d/%d", avsync->session_id,
1103 avsync->active_mode, avsync->mode, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001104 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1105 float speed;
1106 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaoe208d692021-04-19 15:38:52 -07001107 a_active && avsync->audio_start) {
yongchun.li107a6162021-05-05 02:38:57 -07001108 if (v_active || v_timeout || avsync->in_audio_switch) {
Song Zhaoe208d692021-04-19 15:38:52 -07001109 log_info("audio start cb");
1110 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
yongchun.li107a6162021-05-05 02:38:57 -07001111 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001112 }
1113
1114 if (!msync_session_get_rate(avsync->fd, &speed)) {
1115 /* speed change is triggered by asink,
1116 * attached audio HAL will handle it
1117 */
1118 if (speed != avsync->speed)
1119 log_info("[%d]new rate %f", avsync->session_id, speed);
1120 if (speed == 1.0) {
1121 avsync->mode = avsync->backup_mode;
1122 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1123 } else {
1124 avsync->backup_mode = avsync->mode;
1125 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1126 log_info("[%d]audio to freerun mode", avsync->session_id);
1127 }
1128 avsync->speed = speed;
1129 }
Song Zhaod62bb392021-04-23 12:25:49 -07001130 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1131 struct session_debug debug;
1132 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1133 if (debug.debug_freerun) {
1134 avsync->backup_mode = avsync->mode;
1135 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1136 log_warn("[%d]audio to freerun mode", avsync->session_id);
1137 } else {
1138 avsync->mode = avsync->backup_mode;
1139 log_warn("[%d]audio back to mode %d",
1140 avsync->session_id, avsync->mode);
1141 }
1142 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001143 }
1144}
1145
1146static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001147 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001148{
1149 log_info("[%d]amode mode %d %d v/a %d/%d", avsync->session_id,
1150 avsync->active_mode, avsync->mode, v_active, a_active);
Song Zhaod62bb392021-04-23 12:25:49 -07001151 if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1152 struct session_debug debug;
1153 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1154 if (debug.debug_freerun) {
1155 avsync->backup_mode = avsync->mode;
1156 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1157 log_warn("[%d]video to freerun mode", avsync->session_id);
1158 } else
1159 avsync->mode = avsync->backup_mode;
1160 log_warn("[%d]video back to mode %d",
1161 avsync->session_id, avsync->mode);
1162 }
1163 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001164}
1165
1166static void * poll_thread(void * arg)
1167{
1168 int ret = 0;
1169 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1170 const int fd = avsync->fd;
1171 struct pollfd pfd = {
1172 /* default blocking capture */
1173 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1174 .fd = avsync->fd,
1175 };
1176
1177 prctl (PR_SET_NAME, "avs_poll");
1178 log_info("[%d]enter", avsync->session_id);
1179 while (!avsync->quit_poll) {
1180 for (;;) {
1181 ret = poll(&pfd, 1, 10);
1182 if (ret > 0)
1183 break;
1184 if (avsync->quit_poll)
1185 goto exit;
1186 if (errno == EINTR)
1187 continue;
1188 }
1189
1190 /* error handling */
1191 if (pfd.revents & POLLERR)
1192 log_error("[%d]POLLERR received", avsync->session_id);
1193
Song Zhaod62bb392021-04-23 12:25:49 -07001194 /* mode change. Non-exclusive wait so all the processes
1195 * shall be woken up
1196 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001197 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001198 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -08001199
1200 msync_session_get_stat(fd, &avsync->active_mode,
yongchun.li107a6162021-05-05 02:38:57 -07001201 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch);
Song Zhaoea5a0412021-01-18 16:40:08 -08001202
1203 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhaoe208d692021-04-19 15:38:52 -07001204 handle_mode_change_a(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001205 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhaoe208d692021-04-19 15:38:52 -07001206 handle_mode_change_v(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001207 }
1208 }
1209exit:
1210 log_info("[%d]quit", avsync->session_id);
1211 return NULL;
1212}
1213
Song Zhaod62bb392021-04-23 12:25:49 -07001214int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001215{
1216 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1217
1218 if (!avsync)
1219 return -1;
1220
1221 if (avsync->type != AV_SYNC_TYPE_PCR)
1222 return -2;
1223
Song Zhaod62bb392021-04-23 12:25:49 -07001224 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001225}
1226
Song Zhaod62bb392021-04-23 12:25:49 -07001227int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001228{
1229 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1230
1231 if (!avsync)
1232 return -1;
1233
Song Zhaod62bb392021-04-23 12:25:49 -07001234 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001235}
1236
1237int av_sync_set_session_name(void *sync, const char *name)
1238{
1239 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1240
1241 if (!avsync)
1242 return -1;
1243
1244 return msync_session_set_name(avsync->fd, name);
1245}
yongchun.li107a6162021-05-05 02:38:57 -07001246
1247int av_sync_set_audio_switch(void *sync, bool start)
1248{
1249 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1250 bool v_active, a_active, v_timeout;
1251
1252 if (!avsync)
1253 return -1;
1254 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
1255 &v_active, &a_active,
Song Zhaobe513572021-05-13 13:10:21 -07001256 &v_timeout, &avsync->in_audio_switch)) {
yongchun.li107a6162021-05-05 02:38:57 -07001257 log_error("[%d] can not get session state",
1258 avsync->session_id);
1259 return -1;
1260 }
1261 if (!v_active || !a_active) {
1262 log_error("[%d] no apply if not AV both active v %d a %d",
1263 avsync->session_id, v_active, a_active);
1264 return -1;
1265 }
1266 if (msync_session_set_audio_switch(avsync->fd, start)) {
1267 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1268 return -1;
1269 }
1270 avsync->in_audio_switch = start;
1271 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1272 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1273 return 0;
1274}
1275
1276int av_sync_get_audio_switch(void *sync, bool *start)
1277{
1278 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1279
1280 if (!avsync)
1281 return -1;
1282 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
1283 NULL, NULL, NULL, &avsync->in_audio_switch)) {
1284 log_error("[%d] can not audio seamless switch state",
1285 avsync->session_id);
1286 return -1;
1287 }
1288 if (start) *start = avsync->in_audio_switch;
1289 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001290}
Song Zhao8039f562021-05-18 18:11:25 -07001291
1292enum clock_recovery_stat av_sync_get_clock_devication(void *sync, int32_t *ppm)
1293{
1294 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1295
1296 if (!avsync || avsync->mode != AV_SYNC_MODE_PCR_MASTER)
1297 return CLK_RECOVERY_NOT_RUNNING;
1298
1299 //TODO
1300 return CLK_RECOVERY_ONGOING;
1301}