blob: 9c56c4e33b4e0e7410211806f385510aafcfcd98 [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
yongchun.li5f52fb02021-06-04 18:13:05 -0700392 /* ignore only when video try to pause when audio is acive, on which
393 the control of the STC will be relays.
394 When resume,it can do always as it is possible that video just
395 paused earlier without audio yet,then audio added later before resume.
396 We shall not igore that otherwise it could cause video freeze. */
397 if (avsync->mode == AV_SYNC_MODE_AMASTER &&
398 avsync->type == AV_SYNC_TYPE_VIDEO &&
399 a_active &&
400 !avsync->in_audio_switch) {
401 if (!pause) {
402 log_info("[%d] clear video pause when audio active",
403 avsync->session_id);
404 avsync->paused = pause;
405 } else {
406 log_info("[%d] ignore the pause from video when audio active",
407 avsync->session_id);
408 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800409 return 0;
yongchun.li5f52fb02021-06-04 18:13:05 -0700410 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800411
yongchun.li107a6162021-05-05 02:38:57 -0700412 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
413 log_info("[%d] ignore the pause from audio", avsync->session_id);
414 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
415 return 0;
416 }
417
Song Zhaoea5a0412021-01-18 16:40:08 -0800418 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800419 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800420 log_info("[%d]paused:%d type:%d rc %d",
421 avsync->session_id, pause, avsync->type, rc);
Song Zhaoc03ba122020-12-23 21:54:02 -0800422
Song Zhaoea5a0412021-01-18 16:40:08 -0800423 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800424}
425
426int av_sync_push_frame(void *sync , struct vframe *frame)
427{
428 int ret;
429 struct vframe *prev;
430 struct av_sync_session *avsync = (struct av_sync_session *)sync;
431
432 if (!avsync)
433 return -1;
434
Song Zhaoea5a0412021-01-18 16:40:08 -0800435 if (!avsync->frame_q) {
436 /* policy should be final now */
437 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy)) {
438 log_error("[%d]get policy", avsync->session_id);
439 return -1;
440 }
441
442 avsync->frame_q = create_q(MAX_FRAME_NUM);
443 if (!avsync->frame_q) {
444 log_error("[%d]create queue fail", avsync->session_id);
445 return -1;
446 }
447
448 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
449 avsync->mode == AV_SYNC_MODE_IPTV) {
450 int ret;
451
452 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
453 if (ret) {
454 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
455 destroy_q(avsync->frame_q);
456 return -1;
457 }
458 }
459 }
460
Song Zhaoc03ba122020-12-23 21:54:02 -0800461 if (!peek_item(avsync->frame_q, (void **)&prev, 0)) {
Song Zhaod62bb392021-04-23 12:25:49 -0700462 if (prev->pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800463 dqueue_item(avsync->frame_q, (void **)&prev);
464 prev->free(prev);
Song Zhaoea5a0412021-01-18 16:40:08 -0800465 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800466 }
467 }
468
Song Zhao065800e2021-05-26 15:56:06 -0700469 if (frame->duration == -1)
470 frame->duration = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800471 frame->hold_period = 0;
472 ret = queue_item(avsync->frame_q, frame);
473 if (avsync->state == AV_SYNC_STAT_INIT &&
474 queue_size(avsync->frame_q) >= avsync->start_thres) {
475 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaoea5a0412021-01-18 16:40:08 -0800476 log_info("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800477 }
478
479 if (ret)
480 log_error("%s queue fail:%d", ret);
Song Zhaoea5a0412021-01-18 16:40:08 -0800481 log_debug("[%d]push %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800482 return ret;
483
484}
485
486struct vframe *av_sync_pop_frame(void *sync)
487{
Song Zhaoea5a0412021-01-18 16:40:08 -0800488 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800489 struct av_sync_session *avsync = (struct av_sync_session *)sync;
490 int toggle_cnt = 0;
491 uint32_t systime;
Song Zhao468fd652021-01-15 22:13:04 -0800492 bool pause_pts_reached = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800493 uint32_t interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800494
495 pthread_mutex_lock(&avsync->lock);
496 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhaod62bb392021-04-23 12:25:49 -0700497 log_info("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800498 goto exit;
499 }
500
Song Zhaoea5a0412021-01-18 16:40:08 -0800501 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700502 uint32_t pts;
503
Song Zhaoc03ba122020-12-23 21:54:02 -0800504 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800505 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800506 goto exit;
507 }
Song Zhao35a82df2021-04-15 10:58:49 -0700508 msync_session_get_wall(avsync->fd, &systime, &interval);
509 pts = frame->pts - avsync->delay * interval;
510 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800511 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700512 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800513 }
514
Song Zhaoea5a0412021-01-18 16:40:08 -0800515 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700516 !avsync->first_frame_toggled &&
517 !msync_clock_started(avsync->fd)) {
518 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800519 log_trace("[%d]clock not started", avsync->session_id);
520 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800521 }
522
Song Zhaoea5a0412021-01-18 16:40:08 -0800523 enter_last_frame = avsync->last_frame;
524 msync_session_get_wall(avsync->fd, &systime, &interval);
525
526 /* handle refresh rate change */
527 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
528 avsync->vsync_interval != interval) {
529 log_info("[%d]vsync interval update %d --> %u",
530 avsync->session_id, avsync->vsync_interval, interval);
531 avsync->vsync_interval = interval;
532 avsync->phase_set = false;
533 reset_pattern(avsync->pattern_detector);
534 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800535 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
536 struct vframe *next_frame = NULL;
537
538 peek_item(avsync->frame_q, (void **)&next_frame, 1);
539 if (next_frame)
Song Zhaof46932e2021-05-21 01:51:45 -0700540 log_debug("[%d]cur_f %u next_f %u size %d",
541 avsync->session_id, frame->pts, next_frame->pts, queue_size(avsync->frame_q));
Song Zhaoea5a0412021-01-18 16:40:08 -0800542 if (frame_expire(avsync, systime, interval,
543 frame, next_frame, toggle_cnt)) {
544 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800545 toggle_cnt++;
546
Song Zhao35a82df2021-04-15 10:58:49 -0700547 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800548 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao35a82df2021-04-15 10:58:49 -0700549 avsync->last_holding_peroid))
550 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
551
Song Zhaoc03ba122020-12-23 21:54:02 -0800552 if (avsync->last_frame)
553 avsync->last_holding_peroid = avsync->last_frame->hold_period;
554
555 dqueue_item(avsync->frame_q, (void **)&frame);
556 if (avsync->last_frame) {
557 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800558 if (toggle_cnt > 1) {
Song Zhao35a82df2021-04-15 10:58:49 -0700559 log_debug("[%d]free %u cur %u system/d %u/%u", avsync->session_id,
560 avsync->last_frame->pts, frame->pts, systime, systime - avsync->last_poptime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800561 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800562 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800563 } else {
564 avsync->first_frame_toggled = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800565 log_info("[%d]first frame %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800566 }
567 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800568 avsync->last_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800569 } else
570 break;
571 }
572
573 /* pause pts */
574 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800575 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800576 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800577 else
Song Zhao468fd652021-01-15 22:13:04 -0800578 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
579 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
580 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
581 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
582 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800583
Song Zhao468fd652021-01-15 22:13:04 -0800584 if (pause_pts_reached) {
585 if (avsync->pause_pts_cb)
586 avsync->pause_pts_cb(avsync->pause_pts,
Song Zhaoc03ba122020-12-23 21:54:02 -0800587 avsync->pause_cb_priv);
588
Song Zhao468fd652021-01-15 22:13:04 -0800589 /* stay in paused until av_sync_pause(false) */
590 avsync->paused = true;
591 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoea5a0412021-01-18 16:40:08 -0800592 log_info ("[%d]reach pause pts: %u",
593 avsync->session_id, avsync->last_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800594 }
595
596exit:
597 pthread_mutex_unlock(&avsync->lock);
598 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800599 if (enter_last_frame != avsync->last_frame)
600 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhao35a82df2021-04-15 10:58:49 -0700601 log_trace("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhao065800e2021-05-26 15:56:06 -0700602 /* don't update vpts for out_lier */
603 if (avsync->last_frame->duration != -1)
604 msync_session_update_vpts(avsync->fd, systime,
605 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800606 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800607 if (enter_last_frame != avsync->last_frame)
608 log_debug("[%d]pop (nil)", avsync->session_id);
609
Song Zhao35a82df2021-04-15 10:58:49 -0700610 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800611 if (avsync->last_frame)
612 avsync->last_frame->hold_period++;
613 return avsync->last_frame;
614}
615
Song Zhaoc03ba122020-12-23 21:54:02 -0800616static inline uint32_t abs_diff(uint32_t a, uint32_t b)
617{
Song Zhaoea5a0412021-01-18 16:40:08 -0800618 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800619}
620
621static uint64_t time_diff (struct timeval *b, struct timeval *a)
622{
623 return (b->tv_sec - a->tv_sec)*1000000 + (b->tv_usec - a->tv_usec);
624}
625
Song Zhaoc03ba122020-12-23 21:54:02 -0800626static bool frame_expire(struct av_sync_session* avsync,
627 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800628 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800629 struct vframe * frame,
630 struct vframe * next_frame,
631 int toggle_cnt)
632{
633 uint32_t fpts = frame->pts;
634 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800635 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800636
Song Zhaod62bb392021-04-23 12:25:49 -0700637 if (avsync->mode == AV_SYNC_MODE_FREE_RUN)
638 return true;
639
Song Zhaoc03ba122020-12-23 21:54:02 -0800640 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
641 return false;
642
643 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
644 return true;
645
646 if (!fpts) {
647 if (avsync->last_frame) {
648 /* try to accumulate duration as PTS */
649 fpts = avsync->vpts + avsync->last_frame->duration;
650 } else {
651 fpts = avsync->vpts;
652 }
653 }
654 systime += pts_correction;
655
656 /* phase adjustment */
657 if (avsync->phase_set)
658 systime += avsync->phase;
659
Song Zhao35a82df2021-04-15 10:58:49 -0700660 log_trace("[%d]systime:%u phase:%u correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800661 avsync->session_id, systime,
Song Zhao35a82df2021-04-15 10:58:49 -0700662 avsync->phase_set?avsync->phase:0, pts_correction, fpts);
Song Zhaof46932e2021-05-21 01:51:45 -0700663 if (abs_diff(systime, fpts) > avsync->disc_thres_min &&
Song Zhaoc03ba122020-12-23 21:54:02 -0800664 avsync->first_frame_toggled) {
665 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800666 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800667 return false;
668
Song Zhao5d2b4772021-01-18 16:40:08 -0800669 if (avsync->last_systime != systime || avsync->last_pts != fpts) {
670 struct timeval now;
671
672 gettimeofday(&now, NULL);
673 avsync->last_systime = systime;
674 avsync->last_pts = fpts;
675 if (time_diff(&now, &avsync->sync_lost_print_time) >=
676 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaof46932e2021-05-21 01:51:45 -0700677 log_warn("[%d]sync lost systime:%u fpts:%u lost:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800678 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800679 avsync->sync_lost_cnt = 0;
Song Zhaobc6161d2021-03-08 09:59:33 -0800680 gettimeofday(&avsync->sync_lost_print_time, NULL);
Song Zhao5d2b4772021-01-18 16:40:08 -0800681 } else
682 avsync->sync_lost_cnt++;
683 }
Song Zhaod62bb392021-04-23 12:25:49 -0700684
685 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
686 LIVE_MODE(avsync->mode) &&
Song Zhao065800e2021-05-26 15:56:06 -0700687 abs_diff(avsync->last_pts, fpts) > STREAM_DISC_THRES) {
Song Zhaod62bb392021-04-23 12:25:49 -0700688 /* outlier by stream error */
689 avsync->outlier_cnt++;
Song Zhao065800e2021-05-26 15:56:06 -0700690 frame->duration = -1;
Song Zhaod62bb392021-04-23 12:25:49 -0700691 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
692 log_info("render outlier %u", fpts);
693 return true;
694 }
695 }
696
697 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800698 avsync->state = AV_SYNC_STAT_SYNC_LOST;
699 avsync->phase_set = false;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800700 reset_pattern(avsync->pattern_detector);
Song Zhaoc03ba122020-12-23 21:54:02 -0800701 if ((int)(systime - fpts) > 0) {
Song Zhao409739b2021-05-12 22:21:40 -0700702 if (LIVE_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800703 log_info ("[%d]video disc %u --> %u",
704 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700705 msync_session_set_video_dis(avsync->fd, fpts);
706 avsync->last_disc_pts = fpts;
Song Zhaoea5a0412021-01-18 16:40:08 -0800707 }
Song Zhaod62bb392021-04-23 12:25:49 -0700708 /* catch up PCR */
Song Zhaoc03ba122020-12-23 21:54:02 -0800709 return true;
Song Zhao409739b2021-05-12 22:21:40 -0700710 } else if (LIVE_MODE(avsync->mode) && avsync->last_disc_pts != fpts) {
Song Zhaof46932e2021-05-21 01:51:45 -0700711 /* vpts wrapping or vpts gapping */
Song Zhaod62bb392021-04-23 12:25:49 -0700712 log_info ("[%d]video disc %u --> %u",
713 avsync->session_id, systime, fpts);
Song Zhao409739b2021-05-12 22:21:40 -0700714 msync_session_set_video_dis(avsync->fd, fpts);
715 avsync->last_disc_pts = fpts;
Song Zhaof46932e2021-05-21 01:51:45 -0700716 /* clean up frames for wrapping case */
717 if ((int)(fpts - systime) > avsync->disc_thres_max)
718 return true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800719 }
720 }
721
Song Zhao52f55192021-05-06 10:52:21 -0700722 /* In some cases, keeping pattern will enlarge the gap */
723 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
724 avsync->first_frame_toggled) {
725 reset_pattern(avsync->pattern_detector);
Song Zhaof46932e2021-05-21 01:51:45 -0700726 log_warn("sync pattern reset sys:%u fpts:%u",
Song Zhao52f55192021-05-06 10:52:21 -0700727 systime, fpts);
728 }
729
Song Zhaoc03ba122020-12-23 21:54:02 -0800730 expire = (int)(systime - fpts) >= 0;
731
732 /* scatter the frame in different vsync whenever possible */
733 if (expire && next_frame && next_frame->pts && toggle_cnt) {
734 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhaoea5a0412021-01-18 16:40:08 -0800735 if (systime + interval < next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800736 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800737 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
738 avsync->session_id, systime, interval, next_frame->pts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800739 }
740 } else if (!expire && next_frame && next_frame->pts && !toggle_cnt
741 && avsync->first_frame_toggled) {
742 /* next vsync will have at least 2 frame expired */
Song Zhao35a82df2021-04-15 10:58:49 -0700743 if (systime + interval >= next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800744 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800745 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
746 avsync->session_id, systime, interval, next_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800747 }
748 }
749
Song Zhaoa58c3e92021-03-09 18:52:55 -0800750 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
751 correct_pattern(avsync->pattern_detector, frame, next_frame,
752 (avsync->last_frame?avsync->last_frame->hold_period:0),
753 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800754 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -0800755
756 if (expire) {
757 avsync->vpts = fpts;
758 /* phase adjustment */
759 if (!avsync->phase_set) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800760 uint32_t phase_thres = interval / 4;
Song Zhaoc03ba122020-12-23 21:54:02 -0800761 if ( systime > fpts && (systime - fpts) < phase_thres) {
762 /* too aligned to current VSYNC, separate them to 1/4 VSYNC */
763 avsync->phase += phase_thres - (systime - fpts);
764 avsync->phase_set = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800765 log_info("[%d]adjust phase to %d", avsync->session_id, avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800766 }
767 if (!avsync->phase_set && systime > fpts &&
Song Zhaoea5a0412021-01-18 16:40:08 -0800768 systime < (fpts + interval) &&
769 (systime - fpts) > interval - phase_thres) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800770 /* too aligned to previous VSYNC, separate them to 1/4 VSYNC */
Song Zhaoea5a0412021-01-18 16:40:08 -0800771 avsync->phase += phase_thres + fpts + interval - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800772 avsync->phase_set = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800773 log_info("[%d]adjust phase to %d", avsync->session_id, avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800774 }
775 }
776
777 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -0800778 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800779 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -0800780 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800781 }
782 return expire;
783}
784
Song Zhao35a82df2021-04-15 10:58:49 -0700785static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -0800786{
Song Zhao35a82df2021-04-15 10:58:49 -0700787 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800788 log_trace("[%d]cur_period: %d last_period: %d",
789 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -0700790 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
791 ret = true;
792 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
793 ret = true;
794 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
795 ret = true;
796 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
797 ret = true;
798
799 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800800}
801
802int av_sync_set_speed(void *sync, float speed)
803{
804 struct av_sync_session *avsync = (struct av_sync_session *)sync;
805
806 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800807 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800808 return -1;
809 }
810
Song Zhaoea5a0412021-01-18 16:40:08 -0800811 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
812 avsync->mode == AV_SYNC_MODE_IPTV) {
813 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800814 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800815 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800816
Song Zhaoea5a0412021-01-18 16:40:08 -0800817 avsync->speed = speed;
818
819 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
820 if (speed == 1.0) {
821 avsync->mode = avsync->backup_mode;
822 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
823 } else {
824 avsync->backup_mode = avsync->mode;
825 avsync->mode = AV_SYNC_MODE_FREE_RUN;
826 log_info("[%d]audio to freerun mode", avsync->session_id);
827 }
828 }
829#if 0
Song Zhaoc03ba122020-12-23 21:54:02 -0800830 if (avsync->mode != AV_SYNC_MODE_VMASTER) {
831 log_info("ignore set speed in mode %d", avsync->mode);
832 return 0;
833 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800834#endif
Song Zhaoc03ba122020-12-23 21:54:02 -0800835
Song Zhaoea5a0412021-01-18 16:40:08 -0800836 log_info("session[%d] set rate to %f", avsync->session_id, speed);
837 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800838}
839
840int av_sync_change_mode(void *sync, enum sync_mode mode)
841{
842 struct av_sync_session *avsync = (struct av_sync_session *)sync;
843
844 if (!avsync)
845 return -1;
846
Song Zhaoea5a0412021-01-18 16:40:08 -0800847 if (msync_session_set_mode(avsync->fd, mode)) {
848 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800849 return -1;
850 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800851 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -0800852 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800853 return 0;
854}
855
Song Zhao01031bb2021-05-13 21:23:20 -0700856int av_sync_get_mode(void *sync, enum sync_mode *mode)
857{
858 struct av_sync_session *avsync = (struct av_sync_session *)sync;
859
860 if (!avsync || !mode)
861 return -1;
862
863 *mode = avsync->mode;
864 return 0;
865}
866
Song Zhaoc03ba122020-12-23 21:54:02 -0800867int av_sync_set_pause_pts(void *sync, pts90K pts)
868{
869 struct av_sync_session *avsync = (struct av_sync_session *)sync;
870
871 if (!avsync)
872 return -1;
873
874 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -0800875 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800876 return 0;
877}
878
879int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
880{
881 struct av_sync_session *avsync = (struct av_sync_session *)sync;
882
883 if (!avsync)
884 return -1;
885
886 avsync->pause_pts_cb = cb;
887 avsync->pause_cb_priv = priv;
888 return 0;
889}
Song Zhaoea5a0412021-01-18 16:40:08 -0800890
891static void trigger_audio_start_cb(struct av_sync_session *avsync,
892 avs_ascb_reason reason)
893{
894 if (avsync) {
895 pthread_mutex_lock(&avsync->lock);
896 if (avsync->audio_start) {
897 avsync->audio_start(avsync->audio_start_priv, reason);
898 avsync->session_started = true;
899 avsync->audio_start = NULL;
900 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
901 }
902 pthread_mutex_unlock(&avsync->lock);
903 }
904}
905
906avs_start_ret av_sync_audio_start(
907 void *sync,
908 pts90K pts,
909 pts90K delay,
910 audio_start_cb cb,
911 void *priv)
912{
913 struct av_sync_session *avsync = (struct av_sync_session *)sync;
914 uint32_t start_mode;
915 avs_start_ret ret = AV_SYNC_ASTART_ERR;
916 bool create_poll_t = false;
917
918 if (!avsync)
919 return ret;
920
921 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
922 log_error("[%d]fail to set audio start", avsync->session_id);
923
yongchun.li107a6162021-05-05 02:38:57 -0700924 if (avsync->in_audio_switch
925 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET) {
926 log_info("%d audio_switch_state to start start mode %d",
927 avsync->session_id, start_mode);
928 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
929 }
930
Song Zhaoea5a0412021-01-18 16:40:08 -0800931 if (start_mode == AVS_START_SYNC) {
932 ret = AV_SYNC_ASTART_SYNC;
933 avsync->session_started = true;
Song Zhao065800e2021-05-26 15:56:06 -0700934 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaod62bb392021-04-23 12:25:49 -0700935 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800936 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -0700937 avsync->state = AV_SYNC_STAT_RUNNING;
938 } else if (start_mode == AVS_START_AGAIN) {
939 ret = AV_SYNC_ASTART_AGAIN;
940 }
941
942 if (ret == AV_SYNC_ASTART_AGAIN)
943 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800944
yongchun.li107a6162021-05-05 02:38:57 -0700945 if (avsync->mode == AV_SYNC_MODE_AMASTER || avsync->in_audio_switch) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800946 create_poll_t = true;
947 if (start_mode == AVS_START_ASYNC) {
948 if (!cb) {
949 log_error("[%d]invalid cb", avsync->session_id);
950 return AV_SYNC_ASTART_ERR;
951 }
952 avsync->audio_start = cb;
953 avsync->audio_start_priv = priv;
954 }
Song Zhaod62bb392021-04-23 12:25:49 -0700955 } else if (LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -0800956 create_poll_t = true;
957
Song Zhaod62bb392021-04-23 12:25:49 -0700958 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800959 int ret;
960
961 log_info("[%d]start poll thread", avsync->session_id);
962 avsync->quit_poll = false;
963 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
964 if (ret) {
965 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
966 return AV_SYNC_ASTART_ERR;
967 }
968 }
Song Zhaod62bb392021-04-23 12:25:49 -0700969 if (LIVE_MODE(avsync->mode)) {
970 uint32_t systime;
971 msync_session_get_wall(avsync->fd, &systime, NULL);
972 log_info("[%d]return %u w %u pts %u d %u",
973 avsync->session_id, ret, systime, pts, delay);
974 }
975exit:
Song Zhaoea5a0412021-01-18 16:40:08 -0800976 log_info("[%d]return %u", avsync->session_id, ret);
977 return ret;
978}
979
980int av_sync_audio_render(
981 void *sync,
982 pts90K pts,
983 struct audio_policy *policy)
984{
985 int ret = 0;
Song Zhao065800e2021-05-26 15:56:06 -0700986 bool out_lier = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800987 uint32_t systime;
988 struct av_sync_session *avsync = (struct av_sync_session *)sync;
989 avs_audio_action action = AA_SYNC_AA_MAX;
990
991 if (!avsync || !policy)
992 return -1;
993
yongchun.li107a6162021-05-05 02:38:57 -0700994 msync_session_get_wall(avsync->fd, &systime, NULL);
995
996 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
997 pts, systime, avsync->mode, (int)(pts-systime)/90);
998
999 if (avsync->in_audio_switch
1000 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
1001 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
1002 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
1003 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
1004 action = AV_SYNC_AA_RENDER;
1005 } else if ((int)(systime - pts) > 0) {
1006 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
1007 (int)(systime - pts)/90, systime, pts);
1008 action = AV_SYNC_AA_DROP;
1009 } else {
1010 action = AV_SYNC_AA_INSERT;
1011 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
1012 (int)(pts - systime)/90, systime, pts);
1013 }
1014 goto done;
1015 }
1016
Song Zhaoea5a0412021-01-18 16:40:08 -08001017 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 /* stopping procedure, unblock audio rendering */
1024 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER &&
1025 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
1026 action = AV_SYNC_AA_DROP;
1027 goto done;
1028 }
1029
Song Zhaod62bb392021-04-23 12:25:49 -07001030
Song Zhao7daf3a12021-05-10 22:22:25 -07001031 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
1032 avsync->mode == AV_SYNC_MODE_AMASTER) {
1033 action = AV_SYNC_AA_RENDER;
1034 goto done;
1035 }
1036
Song Zhaod62bb392021-04-23 12:25:49 -07001037 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1038 LIVE_MODE(avsync->mode) &&
1039 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1040 /* outlier by stream error */
1041 avsync->outlier_cnt++;
1042 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1043 /* treat as disc, just drop current frame */
1044 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1045 avsync->outlier_cnt = 0;
1046 action = AV_SYNC_AA_DROP;
1047 systime = pts;
Song Zhaod62bb392021-04-23 12:25:49 -07001048 goto done;
1049 }
1050 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1051 pts = systime;
1052 action = AV_SYNC_AA_RENDER;
Song Zhao065800e2021-05-26 15:56:06 -07001053 out_lier = true;
Song Zhaod62bb392021-04-23 12:25:49 -07001054 goto done;
1055 }
1056
1057 avsync->outlier_cnt = 0;
1058 /* low bound from sync_lost to sync_setup */
1059 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1060 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1061 action = AV_SYNC_AA_RENDER;
1062 goto done;
1063 }
1064
1065 /* high bound of sync_setup */
1066 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1067 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1068 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001069 action = AV_SYNC_AA_RENDER;
1070 goto done;
1071 }
1072
1073 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001074 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001075 action = AV_SYNC_AA_DROP;
1076 goto done;
1077 }
1078
1079 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001080 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001081 action = AV_SYNC_AA_INSERT;
1082 goto done;
1083 }
1084
1085done:
1086 policy->action = action;
1087 policy->delta = (int)(systime - pts);
1088 if (action == AV_SYNC_AA_RENDER) {
1089 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001090 if (!avsync->in_audio_switch) {
Song Zhao065800e2021-05-26 15:56:06 -07001091 if (!out_lier)
1092 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaof46932e2021-05-21 01:51:45 -07001093 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhao409739b2021-05-12 22:21:40 -07001094 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001095 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1096 msync_session_update_apts(avsync->fd, systime, pts, 0);
1097 log_info("[%d] audio switch done sys %u pts %u",
1098 avsync->session_id, systime, pts);
1099 msync_session_set_audio_switch(avsync->fd, false);
1100 avsync->in_audio_switch = false;
1101 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1102 } else {
1103 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1104 avsync->session_id, action, systime, pts, systime - pts);
1105 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001106 } else {
Song Zhao409739b2021-05-12 22:21:40 -07001107 if (abs_diff(systime, pts) > AV_DISC_THRES_MIN &&
yongchun.li085b5a42021-05-24 04:22:53 -07001108 avsync->last_disc_pts != pts &&
1109 !avsync->in_audio_switch) {
Song Zhao409739b2021-05-12 22:21:40 -07001110 log_info ("[%d]audio disc %u --> %u",
1111 avsync->session_id, systime, pts);
1112 msync_session_set_audio_dis(avsync->fd, pts);
1113 avsync->last_disc_pts = pts;
1114 }
Song Zhaof46932e2021-05-21 01:51:45 -07001115 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001116 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001117 }
1118
1119 return ret;
1120}
1121
1122int av_sync_get_clock(void *sync, pts90K *pts)
1123{
1124 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1125
1126 if (!avsync || !pts)
1127 return -1;
1128 return msync_session_get_wall(avsync->fd, pts, NULL);
1129}
1130
1131static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001132 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001133{
Song Zhaoe208d692021-04-19 15:38:52 -07001134 log_info("[%d]amode %d mode %d v/a/vt %d/%d/%d", avsync->session_id,
1135 avsync->active_mode, avsync->mode, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001136 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1137 float speed;
1138 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaoe208d692021-04-19 15:38:52 -07001139 a_active && avsync->audio_start) {
yongchun.li107a6162021-05-05 02:38:57 -07001140 if (v_active || v_timeout || avsync->in_audio_switch) {
Song Zhaoe208d692021-04-19 15:38:52 -07001141 log_info("audio start cb");
1142 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
yongchun.li107a6162021-05-05 02:38:57 -07001143 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001144 }
1145
1146 if (!msync_session_get_rate(avsync->fd, &speed)) {
1147 /* speed change is triggered by asink,
1148 * attached audio HAL will handle it
1149 */
1150 if (speed != avsync->speed)
1151 log_info("[%d]new rate %f", avsync->session_id, speed);
1152 if (speed == 1.0) {
1153 avsync->mode = avsync->backup_mode;
1154 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1155 } else {
1156 avsync->backup_mode = avsync->mode;
1157 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1158 log_info("[%d]audio to freerun mode", avsync->session_id);
1159 }
1160 avsync->speed = speed;
1161 }
Song Zhaod62bb392021-04-23 12:25:49 -07001162 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1163 struct session_debug debug;
1164 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1165 if (debug.debug_freerun) {
1166 avsync->backup_mode = avsync->mode;
1167 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1168 log_warn("[%d]audio to freerun mode", avsync->session_id);
1169 } else {
1170 avsync->mode = avsync->backup_mode;
1171 log_warn("[%d]audio back to mode %d",
1172 avsync->session_id, avsync->mode);
1173 }
1174 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001175 }
1176}
1177
1178static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001179 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001180{
1181 log_info("[%d]amode mode %d %d v/a %d/%d", avsync->session_id,
1182 avsync->active_mode, avsync->mode, v_active, a_active);
Song Zhaod62bb392021-04-23 12:25:49 -07001183 if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1184 struct session_debug debug;
1185 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1186 if (debug.debug_freerun) {
1187 avsync->backup_mode = avsync->mode;
1188 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1189 log_warn("[%d]video to freerun mode", avsync->session_id);
1190 } else
1191 avsync->mode = avsync->backup_mode;
1192 log_warn("[%d]video back to mode %d",
1193 avsync->session_id, avsync->mode);
1194 }
1195 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001196}
1197
1198static void * poll_thread(void * arg)
1199{
1200 int ret = 0;
1201 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1202 const int fd = avsync->fd;
1203 struct pollfd pfd = {
1204 /* default blocking capture */
1205 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1206 .fd = avsync->fd,
1207 };
1208
1209 prctl (PR_SET_NAME, "avs_poll");
1210 log_info("[%d]enter", avsync->session_id);
1211 while (!avsync->quit_poll) {
1212 for (;;) {
1213 ret = poll(&pfd, 1, 10);
1214 if (ret > 0)
1215 break;
1216 if (avsync->quit_poll)
1217 goto exit;
1218 if (errno == EINTR)
1219 continue;
1220 }
1221
1222 /* error handling */
1223 if (pfd.revents & POLLERR)
1224 log_error("[%d]POLLERR received", avsync->session_id);
1225
Song Zhaod62bb392021-04-23 12:25:49 -07001226 /* mode change. Non-exclusive wait so all the processes
1227 * shall be woken up
1228 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001229 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001230 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -08001231
1232 msync_session_get_stat(fd, &avsync->active_mode,
yongchun.li107a6162021-05-05 02:38:57 -07001233 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch);
Song Zhaoea5a0412021-01-18 16:40:08 -08001234
1235 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhaoe208d692021-04-19 15:38:52 -07001236 handle_mode_change_a(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001237 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhaoe208d692021-04-19 15:38:52 -07001238 handle_mode_change_v(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001239 }
1240 }
1241exit:
1242 log_info("[%d]quit", avsync->session_id);
1243 return NULL;
1244}
1245
Song Zhaod62bb392021-04-23 12:25:49 -07001246int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001247{
1248 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1249
1250 if (!avsync)
1251 return -1;
1252
1253 if (avsync->type != AV_SYNC_TYPE_PCR)
1254 return -2;
1255
Song Zhaod62bb392021-04-23 12:25:49 -07001256 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001257}
1258
Song Zhaod62bb392021-04-23 12:25:49 -07001259int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001260{
1261 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1262
1263 if (!avsync)
1264 return -1;
1265
Song Zhaod62bb392021-04-23 12:25:49 -07001266 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001267}
1268
1269int av_sync_set_session_name(void *sync, const char *name)
1270{
1271 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1272
1273 if (!avsync)
1274 return -1;
1275
1276 return msync_session_set_name(avsync->fd, name);
1277}
yongchun.li107a6162021-05-05 02:38:57 -07001278
1279int av_sync_set_audio_switch(void *sync, bool start)
1280{
1281 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1282 bool v_active, a_active, v_timeout;
1283
1284 if (!avsync)
1285 return -1;
1286 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
1287 &v_active, &a_active,
Song Zhaobe513572021-05-13 13:10:21 -07001288 &v_timeout, &avsync->in_audio_switch)) {
yongchun.li107a6162021-05-05 02:38:57 -07001289 log_error("[%d] can not get session state",
1290 avsync->session_id);
1291 return -1;
1292 }
1293 if (!v_active || !a_active) {
1294 log_error("[%d] no apply if not AV both active v %d a %d",
1295 avsync->session_id, v_active, a_active);
1296 return -1;
1297 }
1298 if (msync_session_set_audio_switch(avsync->fd, start)) {
1299 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1300 return -1;
1301 }
1302 avsync->in_audio_switch = start;
1303 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1304 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1305 return 0;
1306}
1307
1308int av_sync_get_audio_switch(void *sync, bool *start)
1309{
1310 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1311
1312 if (!avsync)
1313 return -1;
1314 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
1315 NULL, NULL, NULL, &avsync->in_audio_switch)) {
1316 log_error("[%d] can not audio seamless switch state",
1317 avsync->session_id);
1318 return -1;
1319 }
1320 if (start) *start = avsync->in_audio_switch;
1321 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001322}
Song Zhao8039f562021-05-18 18:11:25 -07001323
1324enum clock_recovery_stat av_sync_get_clock_devication(void *sync, int32_t *ppm)
1325{
1326 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1327
1328 if (!avsync || avsync->mode != AV_SYNC_MODE_PCR_MASTER)
1329 return CLK_RECOVERY_NOT_RUNNING;
1330
1331 //TODO
1332 return CLK_RECOVERY_ONGOING;
1333}