blob: 668074d3030016826eaa3b3b24b84db9d33ca5d4 [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;
yongchun.li107a6162021-05-05 02:38:57 -0700113 // indicate set audio switch
114 bool in_audio_switch;
115 enum audio_switch_state_ audio_switch_state;
Song Zhaoc03ba122020-12-23 21:54:02 -0800116};
117
118#define MAX_FRAME_NUM 32
119#define DEFAULT_START_THRESHOLD 2
120#define TIME_UNIT90K (90000)
Song Zhaod62bb392021-04-23 12:25:49 -0700121#define AV_DISC_THRES_MIN (TIME_UNIT90K * 3)
Song Zhao7daf3a12021-05-10 22:22:25 -0700122#define A_ADJ_THREDHOLD_HB (900 * 6) //60ms
123#define A_ADJ_THREDHOLD_LB (900 * 2) //20ms
Song Zhao52f55192021-05-06 10:52:21 -0700124#define AV_PATTERN_RESET_THRES (TIME_UNIT90K / 10)
Song Zhao5d2b4772021-01-18 16:40:08 -0800125#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhaod62bb392021-04-23 12:25:49 -0700126#define LIVE_MODE(mode) ((mode) == AV_SYNC_MODE_PCR_MASTER || (mode) == AV_SYNC_MODE_IPTV)
127
128#define STREAM_DISC_THRES (TIME_UNIT90K * 10)
129#define OUTLIER_MAX_CNT 8
Song Zhaoc03ba122020-12-23 21:54:02 -0800130
131static uint64_t time_diff (struct timeval *b, struct timeval *a);
132static bool frame_expire(struct av_sync_session* avsync,
133 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800134 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800135 struct vframe * frame,
136 struct vframe * next_frame,
137 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700138static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800139 int cur_period,
140 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800141static void * poll_thread(void * arg);
142static void trigger_audio_start_cb(struct av_sync_session *avsync,
143 avs_ascb_reason reason);
Song Zhaoc03ba122020-12-23 21:54:02 -0800144
Song Zhaoea5a0412021-01-18 16:40:08 -0800145int av_sync_open_session(int *session_id)
146{
147 int fd = msync_create_session();
148 int id, rc;
149
150 if (fd < 0) {
151 log_error("fail");
152 return -1;
153 }
154 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
155 if (rc) {
156 log_error("new session errno:%d", errno);
157 return rc;
158 }
159 *session_id = id;
160 return fd;
161}
162
163void av_sync_close_session(int session)
164{
165 msync_destory_session(session);
166}
167
168static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800169 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800170 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800171 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800172 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800173{
174 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800175 char dev_name[20];
Song Zhaoc03ba122020-12-23 21:54:02 -0800176
177 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
178 if (!avsync) {
179 log_error("OOM");
180 return NULL;
181 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800182
183 if (type == AV_SYNC_TYPE_VIDEO) {
184 avsync->pattern_detector = create_pattern_detector();
185 if (!avsync->pattern_detector) {
186 log_error("pd create fail");
187 goto err;
188 }
189
190 if (!start_thres)
191 avsync->start_thres = DEFAULT_START_THRESHOLD;
192 else {
193 if (start_thres > 5) {
194 log_error("start_thres too big: %d", start_thres);
195 goto err2;
196 }
197 avsync->start_thres = start_thres;
198 }
199 avsync->phase_set = false;
200 avsync->first_frame_toggled = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800201 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800202
203 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800204 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800205 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800206 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800207 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800208 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800209 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800210 avsync->speed = 1.0f;
211 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoea5a0412021-01-18 16:40:08 -0800212 avsync->vsync_interval = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoc03ba122020-12-23 21:54:02 -0800213
214 pthread_mutex_init(&avsync->lock, NULL);
Song Zhaoea5a0412021-01-18 16:40:08 -0800215 log_info("[%d] mode %d type %d start_thres %d",
216 session_id, mode, type, start_thres);
217
218 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
219 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
220 if (avsync->fd < 0) {
221 log_error("open %s errno %d", dev_name, errno);
222 goto err2;
223 }
224
225 if (!attach) {
226 msync_session_set_mode(avsync->fd, mode);
227 avsync->mode = mode;
228 } else {
229 avsync->attached = true;
230 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
231 log_error("get mode");
232 goto err2;
233 }
234 avsync->backup_mode = avsync->mode;
235 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy)) {
236 log_error("get policy");
237 goto err2;
238 }
yongchun.li107a6162021-05-05 02:38:57 -0700239 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
240 NULL, NULL, NULL, &avsync->in_audio_switch)) {
241 log_error("get state");
242 goto err2;
243 }
244 if (avsync->in_audio_switch) {
245 log_info("audio_switch_state reseted the audio");
246 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
247 }
248
Song Zhaoea5a0412021-01-18 16:40:08 -0800249 log_info("[%d]retrieve sync mode %d policy %d",
250 session_id, avsync->mode, avsync->start_policy);
251 }
252
Song Zhaoc03ba122020-12-23 21:54:02 -0800253 return avsync;
Song Zhaoea5a0412021-01-18 16:40:08 -0800254err2:
255 destroy_pattern_detector(avsync->pattern_detector);
256err:
257 free(avsync);
258 return NULL;
259}
260
261void* av_sync_create(int session_id,
262 enum sync_mode mode,
263 enum sync_type type,
264 int start_thres)
265{
266 return create_internal(session_id, mode,
267 type, start_thres, false);
268}
269
270void* av_sync_attach(int session_id, enum sync_type type)
271{
272 return create_internal(session_id, AV_SYNC_MODE_MAX,
273 type, 0, true);
274}
275
276int av_sync_video_config(void *sync, struct video_config* config)
277{
278 struct av_sync_session *avsync = (struct av_sync_session *)sync;
279
280 if (!avsync || !config)
281 return -1;
282
283 if (config->delay != 1 && config->delay != 2) {
284 log_error("invalid delay: %d\n", config->delay);
285 return -1;
286 }
287
288 avsync->delay = config->delay;
289
290 log_info("[%d] delay: %d",
291 avsync->session_id, config->delay);
292 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800293}
294
295static int internal_stop(struct av_sync_session *avsync)
296{
297 int ret = 0;
298 struct vframe *frame;
299
300 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800301 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
302 frame->free(frame);
303 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800304 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800305 pthread_mutex_unlock(&avsync->lock);
306 return ret;
307}
308
309/* destroy and detach from kernel session */
310void av_sync_destroy(void *sync)
311{
312 struct av_sync_session *avsync = (struct av_sync_session *)sync;
313
314 if (!avsync)
315 return;
316
Song Zhaoea5a0412021-01-18 16:40:08 -0800317 log_info("[%d]begin", avsync->session_id);
318 if (avsync->state != AV_SYNC_STAT_INIT) {
319 if (avsync->type == AV_SYNC_TYPE_VIDEO)
320 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800321
Song Zhaoea5a0412021-01-18 16:40:08 -0800322 avsync->quit_poll = true;
323 if (avsync->poll_thread) {
324 pthread_join(avsync->poll_thread, NULL);
325 avsync->poll_thread = 0;
326 }
327 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoaf368d52021-02-17 17:53:45 -0800328 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800329
Song Zhaoea5a0412021-01-18 16:40:08 -0800330 if (avsync->session_started) {
331 if (avsync->type == AV_SYNC_TYPE_VIDEO)
332 msync_session_set_video_stop(avsync->fd);
333 else
334 msync_session_set_audio_stop(avsync->fd);
335 }
336 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800337 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800338 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
339 destroy_q(avsync->frame_q);
340 destroy_pattern_detector(avsync->pattern_detector);
341 }
342 log_info("[%d]done", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800343 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800344}
345
346int avs_sync_set_start_policy(void *sync, enum sync_start_policy policy)
347{
348 struct av_sync_session *avsync = (struct av_sync_session *)sync;
349
350 if (!avsync || !avsync->fd)
351 return -1;
352
353 log_info("[%d]policy %u --> %u", avsync->start_policy, policy);
354 avsync->start_policy = policy;
355 /* v_peek will be handled by libamlavsync */
356 if (policy != AV_SYNC_START_NONE &&
357 policy != AV_SYNC_START_V_PEEK)
358 return msync_session_set_start_policy(avsync->fd, policy);
359
360 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800361}
362
363int av_sync_pause(void *sync, bool pause)
364{
365 struct av_sync_session *avsync = (struct av_sync_session *)sync;
yongchun.li107a6162021-05-05 02:38:57 -0700366 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -0800367 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800368
369 if (!avsync)
370 return -1;
371
Song Zhaoea5a0412021-01-18 16:40:08 -0800372 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
373 return -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800374
yongchun.li107a6162021-05-05 02:38:57 -0700375 rc = msync_session_get_stat(avsync->fd, &avsync->active_mode,
376 &v_active, &a_active, &v_timeout,
377 &avsync->in_audio_switch);
378
Song Zhaoea5a0412021-01-18 16:40:08 -0800379 /* ignore */
yongchun.li107a6162021-05-05 02:38:57 -0700380 if (avsync->mode == AV_SYNC_MODE_AMASTER
381 && avsync->type == AV_SYNC_TYPE_VIDEO
382 && a_active && !avsync->in_audio_switch)
Song Zhaoc03ba122020-12-23 21:54:02 -0800383 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800384
yongchun.li107a6162021-05-05 02:38:57 -0700385 if (avsync->in_audio_switch && avsync->type == AV_SYNC_TYPE_AUDIO) {
386 log_info("[%d] ignore the pause from audio", avsync->session_id);
387 avsync->audio_switch_state = AUDIO_SWITCH_STAT_RESET;
388 return 0;
389 }
390
Song Zhaoea5a0412021-01-18 16:40:08 -0800391 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800392 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800393 log_info("[%d]paused:%d type:%d rc %d",
394 avsync->session_id, pause, avsync->type, rc);
Song Zhaoc03ba122020-12-23 21:54:02 -0800395
Song Zhaoea5a0412021-01-18 16:40:08 -0800396 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800397}
398
399int av_sync_push_frame(void *sync , struct vframe *frame)
400{
401 int ret;
402 struct vframe *prev;
403 struct av_sync_session *avsync = (struct av_sync_session *)sync;
404
405 if (!avsync)
406 return -1;
407
Song Zhaoea5a0412021-01-18 16:40:08 -0800408 if (!avsync->frame_q) {
409 /* policy should be final now */
410 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy)) {
411 log_error("[%d]get policy", avsync->session_id);
412 return -1;
413 }
414
415 avsync->frame_q = create_q(MAX_FRAME_NUM);
416 if (!avsync->frame_q) {
417 log_error("[%d]create queue fail", avsync->session_id);
418 return -1;
419 }
420
421 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
422 avsync->mode == AV_SYNC_MODE_IPTV) {
423 int ret;
424
425 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
426 if (ret) {
427 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
428 destroy_q(avsync->frame_q);
429 return -1;
430 }
431 }
432 }
433
Song Zhaoc03ba122020-12-23 21:54:02 -0800434 if (!peek_item(avsync->frame_q, (void **)&prev, 0)) {
Song Zhaod62bb392021-04-23 12:25:49 -0700435 if (prev->pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800436 dqueue_item(avsync->frame_q, (void **)&prev);
437 prev->free(prev);
Song Zhaoea5a0412021-01-18 16:40:08 -0800438 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800439 }
440 }
441
442 frame->hold_period = 0;
443 ret = queue_item(avsync->frame_q, frame);
444 if (avsync->state == AV_SYNC_STAT_INIT &&
445 queue_size(avsync->frame_q) >= avsync->start_thres) {
446 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaoea5a0412021-01-18 16:40:08 -0800447 log_info("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800448 }
449
450 if (ret)
451 log_error("%s queue fail:%d", ret);
Song Zhaoea5a0412021-01-18 16:40:08 -0800452 log_debug("[%d]push %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800453 return ret;
454
455}
456
457struct vframe *av_sync_pop_frame(void *sync)
458{
Song Zhaoea5a0412021-01-18 16:40:08 -0800459 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800460 struct av_sync_session *avsync = (struct av_sync_session *)sync;
461 int toggle_cnt = 0;
462 uint32_t systime;
Song Zhao468fd652021-01-15 22:13:04 -0800463 bool pause_pts_reached = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800464 uint32_t interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800465
466 pthread_mutex_lock(&avsync->lock);
467 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhaod62bb392021-04-23 12:25:49 -0700468 log_info("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800469 goto exit;
470 }
471
Song Zhaoea5a0412021-01-18 16:40:08 -0800472 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700473 uint32_t pts;
474
Song Zhaoc03ba122020-12-23 21:54:02 -0800475 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800476 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800477 goto exit;
478 }
Song Zhao35a82df2021-04-15 10:58:49 -0700479 msync_session_get_wall(avsync->fd, &systime, &interval);
480 pts = frame->pts - avsync->delay * interval;
481 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800482 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700483 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800484 }
485
Song Zhaoea5a0412021-01-18 16:40:08 -0800486 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaod4109b62021-04-30 08:47:17 -0700487 !avsync->first_frame_toggled &&
488 !msync_clock_started(avsync->fd)) {
489 pthread_mutex_unlock(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800490 log_trace("[%d]clock not started", avsync->session_id);
491 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800492 }
493
Song Zhaoea5a0412021-01-18 16:40:08 -0800494 enter_last_frame = avsync->last_frame;
495 msync_session_get_wall(avsync->fd, &systime, &interval);
496
497 /* handle refresh rate change */
498 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
499 avsync->vsync_interval != interval) {
500 log_info("[%d]vsync interval update %d --> %u",
501 avsync->session_id, avsync->vsync_interval, interval);
502 avsync->vsync_interval = interval;
503 avsync->phase_set = false;
504 reset_pattern(avsync->pattern_detector);
505 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800506 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
507 struct vframe *next_frame = NULL;
508
509 peek_item(avsync->frame_q, (void **)&next_frame, 1);
510 if (next_frame)
Song Zhaoea5a0412021-01-18 16:40:08 -0800511 log_debug("[%d]cur_f %u next_f %u",
512 avsync->session_id, frame->pts, next_frame->pts);
513 if (frame_expire(avsync, systime, interval,
514 frame, next_frame, toggle_cnt)) {
515 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800516 toggle_cnt++;
517
Song Zhao35a82df2021-04-15 10:58:49 -0700518 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800519 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao35a82df2021-04-15 10:58:49 -0700520 avsync->last_holding_peroid))
521 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
522
Song Zhaoc03ba122020-12-23 21:54:02 -0800523 if (avsync->last_frame)
524 avsync->last_holding_peroid = avsync->last_frame->hold_period;
525
526 dqueue_item(avsync->frame_q, (void **)&frame);
527 if (avsync->last_frame) {
528 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800529 if (toggle_cnt > 1) {
Song Zhao35a82df2021-04-15 10:58:49 -0700530 log_debug("[%d]free %u cur %u system/d %u/%u", avsync->session_id,
531 avsync->last_frame->pts, frame->pts, systime, systime - avsync->last_poptime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800532 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800533 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800534 } else {
535 avsync->first_frame_toggled = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800536 log_info("[%d]first frame %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800537 }
538 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800539 avsync->last_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800540 } else
541 break;
542 }
543
544 /* pause pts */
545 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800546 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800547 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800548 else
Song Zhao468fd652021-01-15 22:13:04 -0800549 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
550 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
551 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
552 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
553 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800554
Song Zhao468fd652021-01-15 22:13:04 -0800555 if (pause_pts_reached) {
556 if (avsync->pause_pts_cb)
557 avsync->pause_pts_cb(avsync->pause_pts,
Song Zhaoc03ba122020-12-23 21:54:02 -0800558 avsync->pause_cb_priv);
559
Song Zhao468fd652021-01-15 22:13:04 -0800560 /* stay in paused until av_sync_pause(false) */
561 avsync->paused = true;
562 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoea5a0412021-01-18 16:40:08 -0800563 log_info ("[%d]reach pause pts: %u",
564 avsync->session_id, avsync->last_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800565 }
566
567exit:
568 pthread_mutex_unlock(&avsync->lock);
569 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800570 if (enter_last_frame != avsync->last_frame)
571 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhao35a82df2021-04-15 10:58:49 -0700572 log_trace("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800573 msync_session_update_vpts(avsync->fd, systime,
574 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800575 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800576 if (enter_last_frame != avsync->last_frame)
577 log_debug("[%d]pop (nil)", avsync->session_id);
578
Song Zhao35a82df2021-04-15 10:58:49 -0700579 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800580 if (avsync->last_frame)
581 avsync->last_frame->hold_period++;
582 return avsync->last_frame;
583}
584
Song Zhaoc03ba122020-12-23 21:54:02 -0800585static inline uint32_t abs_diff(uint32_t a, uint32_t b)
586{
Song Zhaoea5a0412021-01-18 16:40:08 -0800587 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800588}
589
590static uint64_t time_diff (struct timeval *b, struct timeval *a)
591{
592 return (b->tv_sec - a->tv_sec)*1000000 + (b->tv_usec - a->tv_usec);
593}
594
Song Zhaoc03ba122020-12-23 21:54:02 -0800595static bool frame_expire(struct av_sync_session* avsync,
596 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800597 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800598 struct vframe * frame,
599 struct vframe * next_frame,
600 int toggle_cnt)
601{
602 uint32_t fpts = frame->pts;
603 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800604 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800605
Song Zhaod62bb392021-04-23 12:25:49 -0700606 if (avsync->mode == AV_SYNC_MODE_FREE_RUN)
607 return true;
608
Song Zhaoc03ba122020-12-23 21:54:02 -0800609 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
610 return false;
611
612 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
613 return true;
614
615 if (!fpts) {
616 if (avsync->last_frame) {
617 /* try to accumulate duration as PTS */
618 fpts = avsync->vpts + avsync->last_frame->duration;
619 } else {
620 fpts = avsync->vpts;
621 }
622 }
623 systime += pts_correction;
624
625 /* phase adjustment */
626 if (avsync->phase_set)
627 systime += avsync->phase;
628
Song Zhao35a82df2021-04-15 10:58:49 -0700629 log_trace("[%d]systime:%u phase:%u correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800630 avsync->session_id, systime,
Song Zhao35a82df2021-04-15 10:58:49 -0700631 avsync->phase_set?avsync->phase:0, pts_correction, fpts);
Song Zhaod62bb392021-04-23 12:25:49 -0700632 if (abs_diff(systime, fpts) > AV_DISC_THRES_MIN &&
Song Zhaoc03ba122020-12-23 21:54:02 -0800633 avsync->first_frame_toggled) {
634 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800635 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800636 return false;
637
Song Zhao5d2b4772021-01-18 16:40:08 -0800638 if (avsync->last_systime != systime || avsync->last_pts != fpts) {
639 struct timeval now;
640
641 gettimeofday(&now, NULL);
642 avsync->last_systime = systime;
643 avsync->last_pts = fpts;
644 if (time_diff(&now, &avsync->sync_lost_print_time) >=
645 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800646 log_warn("[%d]sync lost systime:%x fpts:%x lost:%u",
647 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800648 avsync->sync_lost_cnt = 0;
Song Zhaobc6161d2021-03-08 09:59:33 -0800649 gettimeofday(&avsync->sync_lost_print_time, NULL);
Song Zhao5d2b4772021-01-18 16:40:08 -0800650 } else
651 avsync->sync_lost_cnt++;
652 }
Song Zhaod62bb392021-04-23 12:25:49 -0700653
654 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
655 LIVE_MODE(avsync->mode) &&
656 abs_diff(systime, fpts) > STREAM_DISC_THRES) {
657 /* outlier by stream error */
658 avsync->outlier_cnt++;
659 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
660 log_info("render outlier %u", fpts);
661 return true;
662 }
663 }
664
665 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800666 avsync->state = AV_SYNC_STAT_SYNC_LOST;
667 avsync->phase_set = false;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800668 reset_pattern(avsync->pattern_detector);
Song Zhaoc03ba122020-12-23 21:54:02 -0800669 if ((int)(systime - fpts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -0700670 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800671 log_info ("[%d]video disc %u --> %u",
672 avsync->session_id, systime, fpts);
673 msync_session_set_video_dis(avsync->fd, frame->pts);
674 }
Song Zhaod62bb392021-04-23 12:25:49 -0700675 /* catch up PCR */
Song Zhaoc03ba122020-12-23 21:54:02 -0800676 return true;
Song Zhaod62bb392021-04-23 12:25:49 -0700677 } else if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800678 /* vpts wrapping */
Song Zhaod62bb392021-04-23 12:25:49 -0700679 log_info ("[%d]video disc %u --> %u",
680 avsync->session_id, systime, fpts);
681 msync_session_set_video_dis(avsync->fd, frame->pts);
682 return false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800683 }
684 }
685
Song Zhao52f55192021-05-06 10:52:21 -0700686 /* In some cases, keeping pattern will enlarge the gap */
687 if (abs_diff(systime, fpts) > AV_PATTERN_RESET_THRES &&
688 avsync->first_frame_toggled) {
689 reset_pattern(avsync->pattern_detector);
690 log_warn("sync pattern reset sys:%x fpts:%x",
691 systime, fpts);
692 }
693
Song Zhaoc03ba122020-12-23 21:54:02 -0800694 expire = (int)(systime - fpts) >= 0;
695
696 /* scatter the frame in different vsync whenever possible */
697 if (expire && next_frame && next_frame->pts && toggle_cnt) {
698 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhaoea5a0412021-01-18 16:40:08 -0800699 if (systime + interval < next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800700 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800701 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
702 avsync->session_id, systime, interval, next_frame->pts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800703 }
704 } else if (!expire && next_frame && next_frame->pts && !toggle_cnt
705 && avsync->first_frame_toggled) {
706 /* next vsync will have at least 2 frame expired */
Song Zhao35a82df2021-04-15 10:58:49 -0700707 if (systime + interval >= next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800708 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800709 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
710 avsync->session_id, systime, interval, next_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800711 }
712 }
713
Song Zhaoa58c3e92021-03-09 18:52:55 -0800714 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
715 correct_pattern(avsync->pattern_detector, frame, next_frame,
716 (avsync->last_frame?avsync->last_frame->hold_period:0),
717 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800718 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -0800719
720 if (expire) {
721 avsync->vpts = fpts;
722 /* phase adjustment */
723 if (!avsync->phase_set) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800724 uint32_t phase_thres = interval / 4;
Song Zhaoc03ba122020-12-23 21:54:02 -0800725 if ( systime > fpts && (systime - fpts) < phase_thres) {
726 /* too aligned to current VSYNC, separate them to 1/4 VSYNC */
727 avsync->phase += phase_thres - (systime - fpts);
728 avsync->phase_set = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800729 log_info("[%d]adjust phase to %d", avsync->session_id, avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800730 }
731 if (!avsync->phase_set && systime > fpts &&
Song Zhaoea5a0412021-01-18 16:40:08 -0800732 systime < (fpts + interval) &&
733 (systime - fpts) > interval - phase_thres) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800734 /* too aligned to previous VSYNC, separate them to 1/4 VSYNC */
Song Zhaoea5a0412021-01-18 16:40:08 -0800735 avsync->phase += phase_thres + fpts + interval - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800736 avsync->phase_set = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800737 log_info("[%d]adjust phase to %d", avsync->session_id, avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800738 }
739 }
740
741 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -0800742 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800743 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -0800744 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800745 }
746 return expire;
747}
748
Song Zhao35a82df2021-04-15 10:58:49 -0700749static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -0800750{
Song Zhao35a82df2021-04-15 10:58:49 -0700751 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800752 log_trace("[%d]cur_period: %d last_period: %d",
753 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -0700754 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
755 ret = true;
756 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
757 ret = true;
758 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
759 ret = true;
760 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
761 ret = true;
762
763 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800764}
765
766int av_sync_set_speed(void *sync, float speed)
767{
768 struct av_sync_session *avsync = (struct av_sync_session *)sync;
769
770 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800771 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800772 return -1;
773 }
774
Song Zhaoea5a0412021-01-18 16:40:08 -0800775 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
776 avsync->mode == AV_SYNC_MODE_IPTV) {
777 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800778 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800779 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800780
Song Zhaoea5a0412021-01-18 16:40:08 -0800781 avsync->speed = speed;
782
783 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
784 if (speed == 1.0) {
785 avsync->mode = avsync->backup_mode;
786 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
787 } else {
788 avsync->backup_mode = avsync->mode;
789 avsync->mode = AV_SYNC_MODE_FREE_RUN;
790 log_info("[%d]audio to freerun mode", avsync->session_id);
791 }
792 }
793#if 0
Song Zhaoc03ba122020-12-23 21:54:02 -0800794 if (avsync->mode != AV_SYNC_MODE_VMASTER) {
795 log_info("ignore set speed in mode %d", avsync->mode);
796 return 0;
797 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800798#endif
Song Zhaoc03ba122020-12-23 21:54:02 -0800799
Song Zhaoea5a0412021-01-18 16:40:08 -0800800 log_info("session[%d] set rate to %f", avsync->session_id, speed);
801 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800802}
803
804int av_sync_change_mode(void *sync, enum sync_mode mode)
805{
806 struct av_sync_session *avsync = (struct av_sync_session *)sync;
807
808 if (!avsync)
809 return -1;
810
Song Zhaoea5a0412021-01-18 16:40:08 -0800811 if (msync_session_set_mode(avsync->fd, mode)) {
812 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800813 return -1;
814 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800815 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -0800816 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800817 return 0;
818}
819
Song Zhao01031bb2021-05-13 21:23:20 -0700820int av_sync_get_mode(void *sync, enum sync_mode *mode)
821{
822 struct av_sync_session *avsync = (struct av_sync_session *)sync;
823
824 if (!avsync || !mode)
825 return -1;
826
827 *mode = avsync->mode;
828 return 0;
829}
830
Song Zhaoc03ba122020-12-23 21:54:02 -0800831int av_sync_set_pause_pts(void *sync, pts90K pts)
832{
833 struct av_sync_session *avsync = (struct av_sync_session *)sync;
834
835 if (!avsync)
836 return -1;
837
838 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -0800839 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800840 return 0;
841}
842
843int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
844{
845 struct av_sync_session *avsync = (struct av_sync_session *)sync;
846
847 if (!avsync)
848 return -1;
849
850 avsync->pause_pts_cb = cb;
851 avsync->pause_cb_priv = priv;
852 return 0;
853}
Song Zhaoea5a0412021-01-18 16:40:08 -0800854
855static void trigger_audio_start_cb(struct av_sync_session *avsync,
856 avs_ascb_reason reason)
857{
858 if (avsync) {
859 pthread_mutex_lock(&avsync->lock);
860 if (avsync->audio_start) {
861 avsync->audio_start(avsync->audio_start_priv, reason);
862 avsync->session_started = true;
863 avsync->audio_start = NULL;
864 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
865 }
866 pthread_mutex_unlock(&avsync->lock);
867 }
868}
869
870avs_start_ret av_sync_audio_start(
871 void *sync,
872 pts90K pts,
873 pts90K delay,
874 audio_start_cb cb,
875 void *priv)
876{
877 struct av_sync_session *avsync = (struct av_sync_session *)sync;
878 uint32_t start_mode;
879 avs_start_ret ret = AV_SYNC_ASTART_ERR;
880 bool create_poll_t = false;
881
882 if (!avsync)
883 return ret;
884
885 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
886 log_error("[%d]fail to set audio start", avsync->session_id);
887
yongchun.li107a6162021-05-05 02:38:57 -0700888 if (avsync->in_audio_switch
889 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_RESET) {
890 log_info("%d audio_switch_state to start start mode %d",
891 avsync->session_id, start_mode);
892 avsync->audio_switch_state = AUDIO_SWITCH_STAT_START;
893 }
894
Song Zhaoea5a0412021-01-18 16:40:08 -0800895 if (start_mode == AVS_START_SYNC) {
896 ret = AV_SYNC_ASTART_SYNC;
897 avsync->session_started = true;
898 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaod62bb392021-04-23 12:25:49 -0700899 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800900 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -0700901 avsync->state = AV_SYNC_STAT_RUNNING;
902 } else if (start_mode == AVS_START_AGAIN) {
903 ret = AV_SYNC_ASTART_AGAIN;
904 }
905
906 if (ret == AV_SYNC_ASTART_AGAIN)
907 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800908
yongchun.li107a6162021-05-05 02:38:57 -0700909 if (avsync->mode == AV_SYNC_MODE_AMASTER || avsync->in_audio_switch) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800910 create_poll_t = true;
911 if (start_mode == AVS_START_ASYNC) {
912 if (!cb) {
913 log_error("[%d]invalid cb", avsync->session_id);
914 return AV_SYNC_ASTART_ERR;
915 }
916 avsync->audio_start = cb;
917 avsync->audio_start_priv = priv;
918 }
Song Zhaod62bb392021-04-23 12:25:49 -0700919 } else if (LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -0800920 create_poll_t = true;
921
Song Zhaod62bb392021-04-23 12:25:49 -0700922 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800923 int ret;
924
925 log_info("[%d]start poll thread", avsync->session_id);
926 avsync->quit_poll = false;
927 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
928 if (ret) {
929 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
930 return AV_SYNC_ASTART_ERR;
931 }
932 }
Song Zhaod62bb392021-04-23 12:25:49 -0700933 if (LIVE_MODE(avsync->mode)) {
934 uint32_t systime;
935 msync_session_get_wall(avsync->fd, &systime, NULL);
936 log_info("[%d]return %u w %u pts %u d %u",
937 avsync->session_id, ret, systime, pts, delay);
938 }
939exit:
Song Zhaoea5a0412021-01-18 16:40:08 -0800940 log_info("[%d]return %u", avsync->session_id, ret);
941 return ret;
942}
943
944int av_sync_audio_render(
945 void *sync,
946 pts90K pts,
947 struct audio_policy *policy)
948{
949 int ret = 0;
950 uint32_t systime;
951 struct av_sync_session *avsync = (struct av_sync_session *)sync;
952 avs_audio_action action = AA_SYNC_AA_MAX;
953
954 if (!avsync || !policy)
955 return -1;
956
yongchun.li107a6162021-05-05 02:38:57 -0700957 msync_session_get_wall(avsync->fd, &systime, NULL);
958
959 log_trace("audio render pts %u, systime %u, mode %u diff ms %d",
960 pts, systime, avsync->mode, (int)(pts-systime)/90);
961
962 if (avsync->in_audio_switch
963 && avsync->audio_switch_state == AUDIO_SWITCH_STAT_START) {
964 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB) {
965 log_info("Audio pts in system range sys %u pts %u\n", systime, pts);
966 avsync->audio_switch_state = AUDIO_SWITCH_STAT_FINISH;
967 action = AV_SYNC_AA_RENDER;
968 } else if ((int)(systime - pts) > 0) {
969 log_info("[%d] audio change drop %d ms sys %u pts %u", avsync->session_id,
970 (int)(systime - pts)/90, systime, pts);
971 action = AV_SYNC_AA_DROP;
972 } else {
973 action = AV_SYNC_AA_INSERT;
974 log_info("[%d] audio change insert %d ms sys %u pts %u", avsync->session_id,
975 (int)(pts - systime)/90, systime, pts);
976 }
977 goto done;
978 }
979
Song Zhaoea5a0412021-01-18 16:40:08 -0800980 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
981 avsync->mode == AV_SYNC_MODE_AMASTER) {
982 action = AV_SYNC_AA_RENDER;
983 goto done;
984 }
985
Song Zhaod62bb392021-04-23 12:25:49 -0700986 /* stopping procedure, unblock audio rendering */
987 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER &&
988 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
989 action = AV_SYNC_AA_DROP;
990 goto done;
991 }
992
Song Zhaod62bb392021-04-23 12:25:49 -0700993
Song Zhao7daf3a12021-05-10 22:22:25 -0700994 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
995 avsync->mode == AV_SYNC_MODE_AMASTER) {
996 action = AV_SYNC_AA_RENDER;
997 goto done;
998 }
999
Song Zhaod62bb392021-04-23 12:25:49 -07001000 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
1001 LIVE_MODE(avsync->mode) &&
1002 abs_diff(systime, pts) > STREAM_DISC_THRES) {
1003 /* outlier by stream error */
1004 avsync->outlier_cnt++;
1005 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
1006 /* treat as disc, just drop current frame */
1007 avsync->state = AV_SYNC_STAT_SYNC_LOST;
1008 avsync->outlier_cnt = 0;
1009 action = AV_SYNC_AA_DROP;
1010 systime = pts;
1011 msync_session_set_audio_dis(avsync->fd, pts);
1012 goto done;
1013 }
1014 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
1015 pts = systime;
1016 action = AV_SYNC_AA_RENDER;
1017 goto done;
1018 }
1019
1020 avsync->outlier_cnt = 0;
1021 /* low bound from sync_lost to sync_setup */
1022 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
1023 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
1024 action = AV_SYNC_AA_RENDER;
1025 goto done;
1026 }
1027
1028 /* high bound of sync_setup */
1029 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
1030 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
1031 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -08001032 action = AV_SYNC_AA_RENDER;
1033 goto done;
1034 }
1035
1036 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -07001037 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -08001038 action = AV_SYNC_AA_DROP;
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_INSERT;
1045 goto done;
1046 }
1047
1048done:
1049 policy->action = action;
1050 policy->delta = (int)(systime - pts);
1051 if (action == AV_SYNC_AA_RENDER) {
1052 avsync->apts = pts;
yongchun.li107a6162021-05-05 02:38:57 -07001053 if (!avsync->in_audio_switch) {
1054 msync_session_update_apts(avsync->fd, systime, pts, 0);
1055 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001056 avsync->session_id, action, systime, pts, systime - pts);
yongchun.li107a6162021-05-05 02:38:57 -07001057 } else if(avsync->audio_switch_state == AUDIO_SWITCH_STAT_FINISH) {
1058 msync_session_update_apts(avsync->fd, systime, pts, 0);
1059 log_info("[%d] audio switch done sys %u pts %u",
1060 avsync->session_id, systime, pts);
1061 msync_session_set_audio_switch(avsync->fd, false);
1062 avsync->in_audio_switch = false;
1063 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1064 } else {
1065 log_trace("[%d] in audio switch ret %d sys %u - pts %u = %d",
1066 avsync->session_id, action, systime, pts, systime - pts);
1067 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001068 } else {
Song Zhao7daf3a12021-05-10 22:22:25 -07001069 log_debug("[%d]return %d sys %u - pts %u = %d",
Song Zhaod62bb392021-04-23 12:25:49 -07001070 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -08001071 }
1072
1073 return ret;
1074}
1075
1076int av_sync_get_clock(void *sync, pts90K *pts)
1077{
1078 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1079
1080 if (!avsync || !pts)
1081 return -1;
1082 return msync_session_get_wall(avsync->fd, pts, NULL);
1083}
1084
1085static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001086 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001087{
Song Zhaoe208d692021-04-19 15:38:52 -07001088 log_info("[%d]amode %d mode %d v/a/vt %d/%d/%d", avsync->session_id,
1089 avsync->active_mode, avsync->mode, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001090 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
1091 float speed;
1092 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaoe208d692021-04-19 15:38:52 -07001093 a_active && avsync->audio_start) {
yongchun.li107a6162021-05-05 02:38:57 -07001094 if (v_active || v_timeout || avsync->in_audio_switch) {
Song Zhaoe208d692021-04-19 15:38:52 -07001095 log_info("audio start cb");
1096 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
yongchun.li107a6162021-05-05 02:38:57 -07001097 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001098 }
1099
1100 if (!msync_session_get_rate(avsync->fd, &speed)) {
1101 /* speed change is triggered by asink,
1102 * attached audio HAL will handle it
1103 */
1104 if (speed != avsync->speed)
1105 log_info("[%d]new rate %f", avsync->session_id, speed);
1106 if (speed == 1.0) {
1107 avsync->mode = avsync->backup_mode;
1108 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1109 } else {
1110 avsync->backup_mode = avsync->mode;
1111 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1112 log_info("[%d]audio to freerun mode", avsync->session_id);
1113 }
1114 avsync->speed = speed;
1115 }
Song Zhaod62bb392021-04-23 12:25:49 -07001116 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1117 struct session_debug debug;
1118 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1119 if (debug.debug_freerun) {
1120 avsync->backup_mode = avsync->mode;
1121 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1122 log_warn("[%d]audio to freerun mode", avsync->session_id);
1123 } else {
1124 avsync->mode = avsync->backup_mode;
1125 log_warn("[%d]audio back to mode %d",
1126 avsync->session_id, avsync->mode);
1127 }
1128 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001129 }
1130}
1131
1132static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001133 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001134{
1135 log_info("[%d]amode mode %d %d v/a %d/%d", avsync->session_id,
1136 avsync->active_mode, avsync->mode, v_active, a_active);
Song Zhaod62bb392021-04-23 12:25:49 -07001137 if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1138 struct session_debug debug;
1139 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1140 if (debug.debug_freerun) {
1141 avsync->backup_mode = avsync->mode;
1142 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1143 log_warn("[%d]video to freerun mode", avsync->session_id);
1144 } else
1145 avsync->mode = avsync->backup_mode;
1146 log_warn("[%d]video back to mode %d",
1147 avsync->session_id, avsync->mode);
1148 }
1149 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001150}
1151
1152static void * poll_thread(void * arg)
1153{
1154 int ret = 0;
1155 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1156 const int fd = avsync->fd;
1157 struct pollfd pfd = {
1158 /* default blocking capture */
1159 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1160 .fd = avsync->fd,
1161 };
1162
1163 prctl (PR_SET_NAME, "avs_poll");
1164 log_info("[%d]enter", avsync->session_id);
1165 while (!avsync->quit_poll) {
1166 for (;;) {
1167 ret = poll(&pfd, 1, 10);
1168 if (ret > 0)
1169 break;
1170 if (avsync->quit_poll)
1171 goto exit;
1172 if (errno == EINTR)
1173 continue;
1174 }
1175
1176 /* error handling */
1177 if (pfd.revents & POLLERR)
1178 log_error("[%d]POLLERR received", avsync->session_id);
1179
Song Zhaod62bb392021-04-23 12:25:49 -07001180 /* mode change. Non-exclusive wait so all the processes
1181 * shall be woken up
1182 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001183 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001184 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -08001185
1186 msync_session_get_stat(fd, &avsync->active_mode,
yongchun.li107a6162021-05-05 02:38:57 -07001187 &v_active, &a_active, &v_timeout, &avsync->in_audio_switch);
Song Zhaoea5a0412021-01-18 16:40:08 -08001188
1189 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhaoe208d692021-04-19 15:38:52 -07001190 handle_mode_change_a(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001191 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhaoe208d692021-04-19 15:38:52 -07001192 handle_mode_change_v(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001193 }
1194 }
1195exit:
1196 log_info("[%d]quit", avsync->session_id);
1197 return NULL;
1198}
1199
Song Zhaod62bb392021-04-23 12:25:49 -07001200int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001201{
1202 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1203
1204 if (!avsync)
1205 return -1;
1206
1207 if (avsync->type != AV_SYNC_TYPE_PCR)
1208 return -2;
1209
Song Zhaod62bb392021-04-23 12:25:49 -07001210 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001211}
1212
Song Zhaod62bb392021-04-23 12:25:49 -07001213int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001214{
1215 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1216
1217 if (!avsync)
1218 return -1;
1219
1220 if (avsync->type != AV_SYNC_TYPE_PCR)
1221 return -2;
1222
Song Zhaod62bb392021-04-23 12:25:49 -07001223 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001224}
1225
1226int av_sync_set_session_name(void *sync, const char *name)
1227{
1228 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1229
1230 if (!avsync)
1231 return -1;
1232
1233 return msync_session_set_name(avsync->fd, name);
1234}
yongchun.li107a6162021-05-05 02:38:57 -07001235
1236int av_sync_set_audio_switch(void *sync, bool start)
1237{
1238 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1239 bool v_active, a_active, v_timeout;
1240
1241 if (!avsync)
1242 return -1;
1243 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
1244 &v_active, &a_active,
Song Zhaobe513572021-05-13 13:10:21 -07001245 &v_timeout, &avsync->in_audio_switch)) {
yongchun.li107a6162021-05-05 02:38:57 -07001246 log_error("[%d] can not get session state",
1247 avsync->session_id);
1248 return -1;
1249 }
1250 if (!v_active || !a_active) {
1251 log_error("[%d] no apply if not AV both active v %d a %d",
1252 avsync->session_id, v_active, a_active);
1253 return -1;
1254 }
1255 if (msync_session_set_audio_switch(avsync->fd, start)) {
1256 log_error("[%d]fail to set audio switch %d", avsync->session_id, start);
1257 return -1;
1258 }
1259 avsync->in_audio_switch = start;
1260 avsync->audio_switch_state = AUDIO_SWITCH_STAT_INIT;
1261 log_info("[%d]update audio switch to %d", avsync->session_id, start);
1262 return 0;
1263}
1264
1265int av_sync_get_audio_switch(void *sync, bool *start)
1266{
1267 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1268
1269 if (!avsync)
1270 return -1;
1271 if (msync_session_get_stat(avsync->fd, &avsync->active_mode,
1272 NULL, NULL, NULL, &avsync->in_audio_switch)) {
1273 log_error("[%d] can not audio seamless switch state",
1274 avsync->session_id);
1275 return -1;
1276 }
1277 if (start) *start = avsync->in_audio_switch;
1278 return 0;
Song Zhao7daf3a12021-05-10 22:22:25 -07001279}