blob: e30dc51eba37d293733df1b0e21bf7a220328243 [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
Song Zhaoea5a0412021-01-18 16:40:08 -080038#define SESSION_DEV "avsync_s"
39
Song Zhaoc03ba122020-12-23 21:54:02 -080040struct av_sync_session {
41 /* session id attached */
42 int session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -080043 int fd;
44 bool attached;
45 enum sync_mode mode;
46 /* for audio trickplay */
47 enum sync_mode backup_mode;
48 enum sync_type type;
49 uint32_t start_policy;
Song Zhaoc03ba122020-12-23 21:54:02 -080050
Song Zhaoea5a0412021-01-18 16:40:08 -080051 /* playback time, will stop increasing during pause */
52 pts90K vpts;
53 pts90K apts;
54
55 /* phase adjustment of stream time for rate control (Video ONLY) */
Song Zhaoc03ba122020-12-23 21:54:02 -080056 pts90K phase;
57 bool phase_set;
58
59 /* pts of last rendered frame */
Song Zhaoea5a0412021-01-18 16:40:08 -080060 pts90K last_wall;
Song Zhaoc03ba122020-12-23 21:54:02 -080061 pts90K last_pts;
62 struct vframe *last_frame;
63
64 bool first_frame_toggled;
65 /* Whether in pause state */
66 bool paused;
Song Zhaoea5a0412021-01-18 16:40:08 -080067 enum sync_state state;
Song Zhaoc03ba122020-12-23 21:54:02 -080068 void *pattern_detector;
69 void *frame_q;
Song Zhaoc03ba122020-12-23 21:54:02 -080070
Song Zhaoea5a0412021-01-18 16:40:08 -080071 /* start control */
72 int start_thres;
73 audio_start_cb audio_start;
74 void *audio_start_priv;
75
76 /* render property */
Song Zhaoc03ba122020-12-23 21:54:02 -080077 int delay;
78 pts90K vsync_interval;
79
80 /* state lock */
81 pthread_mutex_t lock;
82 /* pattern */
83 int last_holding_peroid;
Song Zhaoea5a0412021-01-18 16:40:08 -080084 bool session_started;
Song Zhaoc03ba122020-12-23 21:54:02 -080085
86 float speed;
87
Song Zhaoc03ba122020-12-23 21:54:02 -080088 /* pause pts */
89 pts90K pause_pts;
90 pause_pts_done pause_pts_cb;
91 void *pause_cb_priv;
Song Zhao5d2b4772021-01-18 16:40:08 -080092
93 /* log control */
94 uint32_t last_systime;
95 uint32_t sync_lost_cnt;
96 struct timeval sync_lost_print_time;
Song Zhaoea5a0412021-01-18 16:40:08 -080097
98 pthread_t poll_thread;
99 /* pcr master, IPTV only */
100 bool quit_poll;
101 enum sync_mode active_mode;
Song Zhao35a82df2021-04-15 10:58:49 -0700102
103 /* error detection */
104 uint32_t last_poptime;
Song Zhaod62bb392021-04-23 12:25:49 -0700105 uint32_t outlier_cnt;
Song Zhaoc03ba122020-12-23 21:54:02 -0800106};
107
108#define MAX_FRAME_NUM 32
109#define DEFAULT_START_THRESHOLD 2
110#define TIME_UNIT90K (90000)
Song Zhaod62bb392021-04-23 12:25:49 -0700111#define AV_DISC_THRES_MIN (TIME_UNIT90K * 3)
112#define A_ADJ_THREDHOLD_HB (TIME_UNIT90K/10)
113#define A_ADJ_THREDHOLD_LB (TIME_UNIT90K/40)
Song Zhao5d2b4772021-01-18 16:40:08 -0800114#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhaod62bb392021-04-23 12:25:49 -0700115#define LIVE_MODE(mode) ((mode) == AV_SYNC_MODE_PCR_MASTER || (mode) == AV_SYNC_MODE_IPTV)
116
117#define STREAM_DISC_THRES (TIME_UNIT90K * 10)
118#define OUTLIER_MAX_CNT 8
Song Zhaoc03ba122020-12-23 21:54:02 -0800119
120static uint64_t time_diff (struct timeval *b, struct timeval *a);
121static bool frame_expire(struct av_sync_session* avsync,
122 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800123 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800124 struct vframe * frame,
125 struct vframe * next_frame,
126 int toggle_cnt);
Song Zhao35a82df2021-04-15 10:58:49 -0700127static bool pattern_detect(struct av_sync_session* avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800128 int cur_period,
129 int last_period);
Song Zhaoea5a0412021-01-18 16:40:08 -0800130static void * poll_thread(void * arg);
131static void trigger_audio_start_cb(struct av_sync_session *avsync,
132 avs_ascb_reason reason);
Song Zhaoc03ba122020-12-23 21:54:02 -0800133
Song Zhaoea5a0412021-01-18 16:40:08 -0800134int av_sync_open_session(int *session_id)
135{
136 int fd = msync_create_session();
137 int id, rc;
138
139 if (fd < 0) {
140 log_error("fail");
141 return -1;
142 }
143 rc = ioctl(fd, AMSYNC_IOC_ALLOC_SESSION, &id);
144 if (rc) {
145 log_error("new session errno:%d", errno);
146 return rc;
147 }
148 *session_id = id;
149 return fd;
150}
151
152void av_sync_close_session(int session)
153{
154 msync_destory_session(session);
155}
156
157static void* create_internal(int session_id,
Song Zhaoc03ba122020-12-23 21:54:02 -0800158 enum sync_mode mode,
Song Zhaoea5a0412021-01-18 16:40:08 -0800159 enum sync_type type,
Song Zhaoc03ba122020-12-23 21:54:02 -0800160 int start_thres,
Song Zhaoea5a0412021-01-18 16:40:08 -0800161 bool attach)
Song Zhaoc03ba122020-12-23 21:54:02 -0800162{
163 struct av_sync_session *avsync = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800164 char dev_name[20];
Song Zhaoc03ba122020-12-23 21:54:02 -0800165
166 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
167 if (!avsync) {
168 log_error("OOM");
169 return NULL;
170 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800171
172 if (type == AV_SYNC_TYPE_VIDEO) {
173 avsync->pattern_detector = create_pattern_detector();
174 if (!avsync->pattern_detector) {
175 log_error("pd create fail");
176 goto err;
177 }
178
179 if (!start_thres)
180 avsync->start_thres = DEFAULT_START_THRESHOLD;
181 else {
182 if (start_thres > 5) {
183 log_error("start_thres too big: %d", start_thres);
184 goto err2;
185 }
186 avsync->start_thres = start_thres;
187 }
188 avsync->phase_set = false;
189 avsync->first_frame_toggled = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800190 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800191
192 avsync->type = type;
Song Zhaoc03ba122020-12-23 21:54:02 -0800193 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800194 avsync->paused = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800195 avsync->session_id = session_id;
Song Zhaoea5a0412021-01-18 16:40:08 -0800196 avsync->backup_mode = mode;
Song Zhaoc03ba122020-12-23 21:54:02 -0800197 avsync->last_frame = NULL;
Song Zhaoea5a0412021-01-18 16:40:08 -0800198 avsync->session_started = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800199 avsync->speed = 1.0f;
200 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoea5a0412021-01-18 16:40:08 -0800201 avsync->vsync_interval = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoc03ba122020-12-23 21:54:02 -0800202
203 pthread_mutex_init(&avsync->lock, NULL);
Song Zhaoea5a0412021-01-18 16:40:08 -0800204 log_info("[%d] mode %d type %d start_thres %d",
205 session_id, mode, type, start_thres);
206
207 snprintf(dev_name, sizeof(dev_name), "/dev/%s%d", SESSION_DEV, session_id);
208 avsync->fd = open(dev_name, O_RDONLY | O_CLOEXEC);
209 if (avsync->fd < 0) {
210 log_error("open %s errno %d", dev_name, errno);
211 goto err2;
212 }
213
214 if (!attach) {
215 msync_session_set_mode(avsync->fd, mode);
216 avsync->mode = mode;
217 } else {
218 avsync->attached = true;
219 if (msync_session_get_mode(avsync->fd, &avsync->mode)) {
220 log_error("get mode");
221 goto err2;
222 }
223 avsync->backup_mode = avsync->mode;
224 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy)) {
225 log_error("get policy");
226 goto err2;
227 }
228 log_info("[%d]retrieve sync mode %d policy %d",
229 session_id, avsync->mode, avsync->start_policy);
230 }
231
Song Zhaoc03ba122020-12-23 21:54:02 -0800232 return avsync;
Song Zhaoea5a0412021-01-18 16:40:08 -0800233err2:
234 destroy_pattern_detector(avsync->pattern_detector);
235err:
236 free(avsync);
237 return NULL;
238}
239
240void* av_sync_create(int session_id,
241 enum sync_mode mode,
242 enum sync_type type,
243 int start_thres)
244{
245 return create_internal(session_id, mode,
246 type, start_thres, false);
247}
248
249void* av_sync_attach(int session_id, enum sync_type type)
250{
251 return create_internal(session_id, AV_SYNC_MODE_MAX,
252 type, 0, true);
253}
254
255int av_sync_video_config(void *sync, struct video_config* config)
256{
257 struct av_sync_session *avsync = (struct av_sync_session *)sync;
258
259 if (!avsync || !config)
260 return -1;
261
262 if (config->delay != 1 && config->delay != 2) {
263 log_error("invalid delay: %d\n", config->delay);
264 return -1;
265 }
266
267 avsync->delay = config->delay;
268
269 log_info("[%d] delay: %d",
270 avsync->session_id, config->delay);
271 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800272}
273
274static int internal_stop(struct av_sync_session *avsync)
275{
276 int ret = 0;
277 struct vframe *frame;
278
279 pthread_mutex_lock(&avsync->lock);
Song Zhaoc03ba122020-12-23 21:54:02 -0800280 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
281 frame->free(frame);
282 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800283 avsync->state = AV_SYNC_STAT_INIT;
Song Zhaoc03ba122020-12-23 21:54:02 -0800284 pthread_mutex_unlock(&avsync->lock);
285 return ret;
286}
287
288/* destroy and detach from kernel session */
289void av_sync_destroy(void *sync)
290{
291 struct av_sync_session *avsync = (struct av_sync_session *)sync;
292
293 if (!avsync)
294 return;
295
Song Zhaoea5a0412021-01-18 16:40:08 -0800296 log_info("[%d]begin", avsync->session_id);
297 if (avsync->state != AV_SYNC_STAT_INIT) {
298 if (avsync->type == AV_SYNC_TYPE_VIDEO)
299 internal_stop(avsync);
Song Zhaoc03ba122020-12-23 21:54:02 -0800300
Song Zhaoea5a0412021-01-18 16:40:08 -0800301 avsync->quit_poll = true;
302 if (avsync->poll_thread) {
303 pthread_join(avsync->poll_thread, NULL);
304 avsync->poll_thread = 0;
305 }
306 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_STOP);
Song Zhaoaf368d52021-02-17 17:53:45 -0800307 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800308
Song Zhaoea5a0412021-01-18 16:40:08 -0800309 if (avsync->session_started) {
310 if (avsync->type == AV_SYNC_TYPE_VIDEO)
311 msync_session_set_video_stop(avsync->fd);
312 else
313 msync_session_set_audio_stop(avsync->fd);
314 }
315 close(avsync->fd);
Song Zhaoc03ba122020-12-23 21:54:02 -0800316 pthread_mutex_destroy(&avsync->lock);
Song Zhaoea5a0412021-01-18 16:40:08 -0800317 if (avsync->type == AV_SYNC_TYPE_VIDEO) {
318 destroy_q(avsync->frame_q);
319 destroy_pattern_detector(avsync->pattern_detector);
320 }
321 log_info("[%d]done", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800322 free(avsync);
Song Zhaoea5a0412021-01-18 16:40:08 -0800323}
324
325int avs_sync_set_start_policy(void *sync, enum sync_start_policy policy)
326{
327 struct av_sync_session *avsync = (struct av_sync_session *)sync;
328
329 if (!avsync || !avsync->fd)
330 return -1;
331
332 log_info("[%d]policy %u --> %u", avsync->start_policy, policy);
333 avsync->start_policy = policy;
334 /* v_peek will be handled by libamlavsync */
335 if (policy != AV_SYNC_START_NONE &&
336 policy != AV_SYNC_START_V_PEEK)
337 return msync_session_set_start_policy(avsync->fd, policy);
338
339 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800340}
341
342int av_sync_pause(void *sync, bool pause)
343{
344 struct av_sync_session *avsync = (struct av_sync_session *)sync;
Song Zhaoea5a0412021-01-18 16:40:08 -0800345 int rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800346
347 if (!avsync)
348 return -1;
349
Song Zhaoea5a0412021-01-18 16:40:08 -0800350 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER)
351 return -1;
Song Zhaoc03ba122020-12-23 21:54:02 -0800352
Song Zhaoea5a0412021-01-18 16:40:08 -0800353 /* ignore */
354 if (avsync->mode == AV_SYNC_MODE_AMASTER && avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhaoc03ba122020-12-23 21:54:02 -0800355 return 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800356
Song Zhaoea5a0412021-01-18 16:40:08 -0800357 rc = msync_session_set_pause(avsync->fd, pause);
Song Zhaoc03ba122020-12-23 21:54:02 -0800358 avsync->paused = pause;
Song Zhaoea5a0412021-01-18 16:40:08 -0800359 log_info("[%d]paused:%d type:%d rc %d",
360 avsync->session_id, pause, avsync->type, rc);
Song Zhaoc03ba122020-12-23 21:54:02 -0800361
Song Zhaoea5a0412021-01-18 16:40:08 -0800362 return rc;
Song Zhaoc03ba122020-12-23 21:54:02 -0800363}
364
365int av_sync_push_frame(void *sync , struct vframe *frame)
366{
367 int ret;
368 struct vframe *prev;
369 struct av_sync_session *avsync = (struct av_sync_session *)sync;
370
371 if (!avsync)
372 return -1;
373
Song Zhaoea5a0412021-01-18 16:40:08 -0800374 if (!avsync->frame_q) {
375 /* policy should be final now */
376 if (msync_session_get_start_policy(avsync->fd, &avsync->start_policy)) {
377 log_error("[%d]get policy", avsync->session_id);
378 return -1;
379 }
380
381 avsync->frame_q = create_q(MAX_FRAME_NUM);
382 if (!avsync->frame_q) {
383 log_error("[%d]create queue fail", avsync->session_id);
384 return -1;
385 }
386
387 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
388 avsync->mode == AV_SYNC_MODE_IPTV) {
389 int ret;
390
391 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
392 if (ret) {
393 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
394 destroy_q(avsync->frame_q);
395 return -1;
396 }
397 }
398 }
399
Song Zhaoc03ba122020-12-23 21:54:02 -0800400 if (!peek_item(avsync->frame_q, (void **)&prev, 0)) {
Song Zhaod62bb392021-04-23 12:25:49 -0700401 if (prev->pts == frame->pts && avsync->mode == AV_SYNC_MODE_AMASTER) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800402 dqueue_item(avsync->frame_q, (void **)&prev);
403 prev->free(prev);
Song Zhaoea5a0412021-01-18 16:40:08 -0800404 log_info ("[%d]drop frame with same pts %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800405 }
406 }
407
408 frame->hold_period = 0;
409 ret = queue_item(avsync->frame_q, frame);
410 if (avsync->state == AV_SYNC_STAT_INIT &&
411 queue_size(avsync->frame_q) >= avsync->start_thres) {
412 avsync->state = AV_SYNC_STAT_RUNNING;
Song Zhaoea5a0412021-01-18 16:40:08 -0800413 log_info("[%d]state: init --> running", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800414 }
415
416 if (ret)
417 log_error("%s queue fail:%d", ret);
Song Zhaoea5a0412021-01-18 16:40:08 -0800418 log_debug("[%d]push %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800419 return ret;
420
421}
422
423struct vframe *av_sync_pop_frame(void *sync)
424{
Song Zhaoea5a0412021-01-18 16:40:08 -0800425 struct vframe *frame = NULL, *enter_last_frame = NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800426 struct av_sync_session *avsync = (struct av_sync_session *)sync;
427 int toggle_cnt = 0;
428 uint32_t systime;
Song Zhao468fd652021-01-15 22:13:04 -0800429 bool pause_pts_reached = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800430 uint32_t interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800431
432 pthread_mutex_lock(&avsync->lock);
433 if (avsync->state == AV_SYNC_STAT_INIT) {
Song Zhaod62bb392021-04-23 12:25:49 -0700434 log_info("[%d]in state INIT", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800435 goto exit;
436 }
437
Song Zhaoea5a0412021-01-18 16:40:08 -0800438 if (!avsync->session_started) {
Song Zhao35a82df2021-04-15 10:58:49 -0700439 uint32_t pts;
440
Song Zhaoc03ba122020-12-23 21:54:02 -0800441 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800442 log_info("[%d]empty q", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800443 goto exit;
444 }
Song Zhao35a82df2021-04-15 10:58:49 -0700445 msync_session_get_wall(avsync->fd, &systime, &interval);
446 pts = frame->pts - avsync->delay * interval;
447 msync_session_set_video_start(avsync->fd, pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800448 avsync->session_started = true;
Song Zhao35a82df2021-04-15 10:58:49 -0700449 log_info("[%d]video start %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800450 }
451
Song Zhaoea5a0412021-01-18 16:40:08 -0800452 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
453 !avsync->first_frame_toggled && !msync_clock_started(avsync->fd)) {
454 log_trace("[%d]clock not started", avsync->session_id);
455 return NULL;
Song Zhaoc03ba122020-12-23 21:54:02 -0800456 }
457
Song Zhaoea5a0412021-01-18 16:40:08 -0800458 enter_last_frame = avsync->last_frame;
459 msync_session_get_wall(avsync->fd, &systime, &interval);
460
461 /* handle refresh rate change */
462 if (avsync->vsync_interval == AV_SYNC_INVALID_PAUSE_PTS ||
463 avsync->vsync_interval != interval) {
464 log_info("[%d]vsync interval update %d --> %u",
465 avsync->session_id, avsync->vsync_interval, interval);
466 avsync->vsync_interval = interval;
467 avsync->phase_set = false;
468 reset_pattern(avsync->pattern_detector);
469 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800470 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
471 struct vframe *next_frame = NULL;
472
473 peek_item(avsync->frame_q, (void **)&next_frame, 1);
474 if (next_frame)
Song Zhaoea5a0412021-01-18 16:40:08 -0800475 log_debug("[%d]cur_f %u next_f %u",
476 avsync->session_id, frame->pts, next_frame->pts);
477 if (frame_expire(avsync, systime, interval,
478 frame, next_frame, toggle_cnt)) {
479 log_debug("[%d]cur_f %u expire", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800480 toggle_cnt++;
481
Song Zhao35a82df2021-04-15 10:58:49 -0700482 if (pattern_detect(avsync,
Song Zhaoc03ba122020-12-23 21:54:02 -0800483 (avsync->last_frame?avsync->last_frame->hold_period:0),
Song Zhao35a82df2021-04-15 10:58:49 -0700484 avsync->last_holding_peroid))
485 log_info("[%d] %u break the pattern", avsync->session_id, avsync->last_frame->pts);
486
Song Zhaoc03ba122020-12-23 21:54:02 -0800487 if (avsync->last_frame)
488 avsync->last_holding_peroid = avsync->last_frame->hold_period;
489
490 dqueue_item(avsync->frame_q, (void **)&frame);
491 if (avsync->last_frame) {
492 /* free frame that are not for display */
Song Zhaoea5a0412021-01-18 16:40:08 -0800493 if (toggle_cnt > 1) {
Song Zhao35a82df2021-04-15 10:58:49 -0700494 log_debug("[%d]free %u cur %u system/d %u/%u", avsync->session_id,
495 avsync->last_frame->pts, frame->pts, systime, systime - avsync->last_poptime);
Song Zhaoc03ba122020-12-23 21:54:02 -0800496 avsync->last_frame->free(avsync->last_frame);
Song Zhaoea5a0412021-01-18 16:40:08 -0800497 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800498 } else {
499 avsync->first_frame_toggled = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800500 log_info("[%d]first frame %u", avsync->session_id, frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800501 }
502 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800503 avsync->last_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800504 } else
505 break;
506 }
507
508 /* pause pts */
509 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800510 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800511 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800512 else
Song Zhao468fd652021-01-15 22:13:04 -0800513 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
514 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
515 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
516 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
517 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800518
Song Zhao468fd652021-01-15 22:13:04 -0800519 if (pause_pts_reached) {
520 if (avsync->pause_pts_cb)
521 avsync->pause_pts_cb(avsync->pause_pts,
Song Zhaoc03ba122020-12-23 21:54:02 -0800522 avsync->pause_cb_priv);
523
Song Zhao468fd652021-01-15 22:13:04 -0800524 /* stay in paused until av_sync_pause(false) */
525 avsync->paused = true;
526 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
Song Zhaoea5a0412021-01-18 16:40:08 -0800527 log_info ("[%d]reach pause pts: %u",
528 avsync->session_id, avsync->last_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800529 }
530
531exit:
532 pthread_mutex_unlock(&avsync->lock);
533 if (avsync->last_frame) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800534 if (enter_last_frame != avsync->last_frame)
535 log_debug("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhao35a82df2021-04-15 10:58:49 -0700536 log_trace("[%d]pop %u", avsync->session_id, avsync->last_frame->pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800537 msync_session_update_vpts(avsync->fd, systime,
538 avsync->last_frame->pts, interval * avsync->delay);
Song Zhaoc03ba122020-12-23 21:54:02 -0800539 } else
Song Zhaoea5a0412021-01-18 16:40:08 -0800540 if (enter_last_frame != avsync->last_frame)
541 log_debug("[%d]pop (nil)", avsync->session_id);
542
Song Zhao35a82df2021-04-15 10:58:49 -0700543 avsync->last_poptime = systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800544 if (avsync->last_frame)
545 avsync->last_frame->hold_period++;
546 return avsync->last_frame;
547}
548
Song Zhaoc03ba122020-12-23 21:54:02 -0800549static inline uint32_t abs_diff(uint32_t a, uint32_t b)
550{
Song Zhaoea5a0412021-01-18 16:40:08 -0800551 return (int)(a - b) > 0 ? a - b : b - a;
Song Zhaoc03ba122020-12-23 21:54:02 -0800552}
553
554static uint64_t time_diff (struct timeval *b, struct timeval *a)
555{
556 return (b->tv_sec - a->tv_sec)*1000000 + (b->tv_usec - a->tv_usec);
557}
558
Song Zhaoc03ba122020-12-23 21:54:02 -0800559static bool frame_expire(struct av_sync_session* avsync,
560 uint32_t systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800561 uint32_t interval,
Song Zhaoc03ba122020-12-23 21:54:02 -0800562 struct vframe * frame,
563 struct vframe * next_frame,
564 int toggle_cnt)
565{
566 uint32_t fpts = frame->pts;
567 bool expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800568 uint32_t pts_correction = avsync->delay * interval;
Song Zhaoc03ba122020-12-23 21:54:02 -0800569
Song Zhaod62bb392021-04-23 12:25:49 -0700570 if (avsync->mode == AV_SYNC_MODE_FREE_RUN)
571 return true;
572
Song Zhaoc03ba122020-12-23 21:54:02 -0800573 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
574 return false;
575
576 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
577 return true;
578
579 if (!fpts) {
580 if (avsync->last_frame) {
581 /* try to accumulate duration as PTS */
582 fpts = avsync->vpts + avsync->last_frame->duration;
583 } else {
584 fpts = avsync->vpts;
585 }
586 }
587 systime += pts_correction;
588
589 /* phase adjustment */
590 if (avsync->phase_set)
591 systime += avsync->phase;
592
Song Zhao35a82df2021-04-15 10:58:49 -0700593 log_trace("[%d]systime:%u phase:%u correct:%u fpts:%u",
Song Zhaoea5a0412021-01-18 16:40:08 -0800594 avsync->session_id, systime,
Song Zhao35a82df2021-04-15 10:58:49 -0700595 avsync->phase_set?avsync->phase:0, pts_correction, fpts);
Song Zhaod62bb392021-04-23 12:25:49 -0700596 if (abs_diff(systime, fpts) > AV_DISC_THRES_MIN &&
Song Zhaoc03ba122020-12-23 21:54:02 -0800597 avsync->first_frame_toggled) {
598 /* ignore discontinity under pause */
Song Zhaoea5a0412021-01-18 16:40:08 -0800599 if (avsync->paused)
Song Zhaoc03ba122020-12-23 21:54:02 -0800600 return false;
601
Song Zhao5d2b4772021-01-18 16:40:08 -0800602 if (avsync->last_systime != systime || avsync->last_pts != fpts) {
603 struct timeval now;
604
605 gettimeofday(&now, NULL);
606 avsync->last_systime = systime;
607 avsync->last_pts = fpts;
608 if (time_diff(&now, &avsync->sync_lost_print_time) >=
609 SYNC_LOST_PRINT_THRESHOLD) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800610 log_warn("[%d]sync lost systime:%x fpts:%x lost:%u",
611 avsync->session_id, systime, fpts, avsync->sync_lost_cnt);
Song Zhao5d2b4772021-01-18 16:40:08 -0800612 avsync->sync_lost_cnt = 0;
Song Zhaobc6161d2021-03-08 09:59:33 -0800613 gettimeofday(&avsync->sync_lost_print_time, NULL);
Song Zhao5d2b4772021-01-18 16:40:08 -0800614 } else
615 avsync->sync_lost_cnt++;
616 }
Song Zhaod62bb392021-04-23 12:25:49 -0700617
618 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
619 LIVE_MODE(avsync->mode) &&
620 abs_diff(systime, fpts) > STREAM_DISC_THRES) {
621 /* outlier by stream error */
622 avsync->outlier_cnt++;
623 if (avsync->outlier_cnt < OUTLIER_MAX_CNT) {
624 log_info("render outlier %u", fpts);
625 return true;
626 }
627 }
628
629 avsync->outlier_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800630 avsync->state = AV_SYNC_STAT_SYNC_LOST;
631 avsync->phase_set = false;
Song Zhaoa58c3e92021-03-09 18:52:55 -0800632 reset_pattern(avsync->pattern_detector);
Song Zhaoc03ba122020-12-23 21:54:02 -0800633 if ((int)(systime - fpts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -0700634 if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800635 log_info ("[%d]video disc %u --> %u",
636 avsync->session_id, systime, fpts);
637 msync_session_set_video_dis(avsync->fd, frame->pts);
638 }
Song Zhaod62bb392021-04-23 12:25:49 -0700639 /* catch up PCR */
Song Zhaoc03ba122020-12-23 21:54:02 -0800640 return true;
Song Zhaod62bb392021-04-23 12:25:49 -0700641 } else if (LIVE_MODE(avsync->mode)) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800642 /* vpts wrapping */
Song Zhaod62bb392021-04-23 12:25:49 -0700643 log_info ("[%d]video disc %u --> %u",
644 avsync->session_id, systime, fpts);
645 msync_session_set_video_dis(avsync->fd, frame->pts);
646 return false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800647 }
648 }
649
650 expire = (int)(systime - fpts) >= 0;
651
652 /* scatter the frame in different vsync whenever possible */
653 if (expire && next_frame && next_frame->pts && toggle_cnt) {
654 /* multi frame expired in current vsync but no frame in next vsync */
Song Zhaoea5a0412021-01-18 16:40:08 -0800655 if (systime + interval < next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800656 expire = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800657 log_debug("[%d]unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
658 avsync->session_id, systime, interval, next_frame->pts, toggle_cnt);
Song Zhaoc03ba122020-12-23 21:54:02 -0800659 }
660 } else if (!expire && next_frame && next_frame->pts && !toggle_cnt
661 && avsync->first_frame_toggled) {
662 /* next vsync will have at least 2 frame expired */
Song Zhao35a82df2021-04-15 10:58:49 -0700663 if (systime + interval >= next_frame->pts) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800664 expire = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800665 log_debug("[%d]set expire systime:%d inter:%d next_pts:%d",
666 avsync->session_id, systime, interval, next_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800667 }
668 }
669
Song Zhaoa58c3e92021-03-09 18:52:55 -0800670 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP)
671 correct_pattern(avsync->pattern_detector, frame, next_frame,
672 (avsync->last_frame?avsync->last_frame->hold_period:0),
673 avsync->last_holding_peroid, systime,
Song Zhaoea5a0412021-01-18 16:40:08 -0800674 interval, &expire);
Song Zhaoc03ba122020-12-23 21:54:02 -0800675
676 if (expire) {
677 avsync->vpts = fpts;
678 /* phase adjustment */
679 if (!avsync->phase_set) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800680 uint32_t phase_thres = interval / 4;
Song Zhaoc03ba122020-12-23 21:54:02 -0800681 if ( systime > fpts && (systime - fpts) < phase_thres) {
682 /* too aligned to current VSYNC, separate them to 1/4 VSYNC */
683 avsync->phase += phase_thres - (systime - fpts);
684 avsync->phase_set = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800685 log_info("[%d]adjust phase to %d", avsync->session_id, avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800686 }
687 if (!avsync->phase_set && systime > fpts &&
Song Zhaoea5a0412021-01-18 16:40:08 -0800688 systime < (fpts + interval) &&
689 (systime - fpts) > interval - phase_thres) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800690 /* too aligned to previous VSYNC, separate them to 1/4 VSYNC */
Song Zhaoea5a0412021-01-18 16:40:08 -0800691 avsync->phase += phase_thres + fpts + interval - systime;
Song Zhaoc03ba122020-12-23 21:54:02 -0800692 avsync->phase_set = true;
Song Zhaoea5a0412021-01-18 16:40:08 -0800693 log_info("[%d]adjust phase to %d", avsync->session_id, avsync->phase);
Song Zhaoc03ba122020-12-23 21:54:02 -0800694 }
695 }
696
697 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
Song Zhaoea5a0412021-01-18 16:40:08 -0800698 log_info("[%d]sync setup", avsync->session_id);
Song Zhaoc03ba122020-12-23 21:54:02 -0800699 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -0800700 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800701 }
702 return expire;
703}
704
Song Zhao35a82df2021-04-15 10:58:49 -0700705static bool pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
Song Zhaoc03ba122020-12-23 21:54:02 -0800706{
Song Zhao35a82df2021-04-15 10:58:49 -0700707 bool ret = false;
Song Zhaoea5a0412021-01-18 16:40:08 -0800708 log_trace("[%d]cur_period: %d last_period: %d",
709 avsync->session_id, cur_period, last_period);
Song Zhao35a82df2021-04-15 10:58:49 -0700710 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period))
711 ret = true;
712 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period))
713 ret = true;
714 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period))
715 ret = true;
716 if (detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P11, cur_period, last_period))
717 ret = true;
718
719 return ret;
Song Zhaoc03ba122020-12-23 21:54:02 -0800720}
721
722int av_sync_set_speed(void *sync, float speed)
723{
724 struct av_sync_session *avsync = (struct av_sync_session *)sync;
725
726 if (speed < 0.001f || speed > 100) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800727 log_error("[%d]wrong speed %f [0.0001, 100]", avsync->session_id, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800728 return -1;
729 }
730
Song Zhaoea5a0412021-01-18 16:40:08 -0800731 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER ||
732 avsync->mode == AV_SYNC_MODE_IPTV) {
733 log_info("[%d]ignore set speed in mode %d", avsync->session_id, avsync->mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800734 return 0;
Song Zhaoea5a0412021-01-18 16:40:08 -0800735 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800736
Song Zhaoea5a0412021-01-18 16:40:08 -0800737 avsync->speed = speed;
738
739 if (avsync->type == AV_SYNC_TYPE_AUDIO) {
740 if (speed == 1.0) {
741 avsync->mode = avsync->backup_mode;
742 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
743 } else {
744 avsync->backup_mode = avsync->mode;
745 avsync->mode = AV_SYNC_MODE_FREE_RUN;
746 log_info("[%d]audio to freerun mode", avsync->session_id);
747 }
748 }
749#if 0
Song Zhaoc03ba122020-12-23 21:54:02 -0800750 if (avsync->mode != AV_SYNC_MODE_VMASTER) {
751 log_info("ignore set speed in mode %d", avsync->mode);
752 return 0;
753 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800754#endif
Song Zhaoc03ba122020-12-23 21:54:02 -0800755
Song Zhaoea5a0412021-01-18 16:40:08 -0800756 log_info("session[%d] set rate to %f", avsync->session_id, speed);
757 return msync_session_set_rate(avsync->fd, speed);
Song Zhaoc03ba122020-12-23 21:54:02 -0800758}
759
760int av_sync_change_mode(void *sync, enum sync_mode mode)
761{
762 struct av_sync_session *avsync = (struct av_sync_session *)sync;
763
764 if (!avsync)
765 return -1;
766
Song Zhaoea5a0412021-01-18 16:40:08 -0800767 if (msync_session_set_mode(avsync->fd, mode)) {
768 log_error("[%d]fail to set mode %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800769 return -1;
770 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800771 avsync->mode = mode;
Song Zhaoea5a0412021-01-18 16:40:08 -0800772 log_info("[%d]update sync mode to %d", avsync->session_id, mode);
Song Zhaoc03ba122020-12-23 21:54:02 -0800773 return 0;
774}
775
776int av_sync_set_pause_pts(void *sync, pts90K pts)
777{
778 struct av_sync_session *avsync = (struct av_sync_session *)sync;
779
780 if (!avsync)
781 return -1;
782
783 avsync->pause_pts = pts;
Song Zhaoea5a0412021-01-18 16:40:08 -0800784 log_info("[%d]set pause pts: %u", avsync->session_id, pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800785 return 0;
786}
787
788int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
789{
790 struct av_sync_session *avsync = (struct av_sync_session *)sync;
791
792 if (!avsync)
793 return -1;
794
795 avsync->pause_pts_cb = cb;
796 avsync->pause_cb_priv = priv;
797 return 0;
798}
Song Zhaoea5a0412021-01-18 16:40:08 -0800799
800static void trigger_audio_start_cb(struct av_sync_session *avsync,
801 avs_ascb_reason reason)
802{
803 if (avsync) {
804 pthread_mutex_lock(&avsync->lock);
805 if (avsync->audio_start) {
806 avsync->audio_start(avsync->audio_start_priv, reason);
807 avsync->session_started = true;
808 avsync->audio_start = NULL;
809 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
810 }
811 pthread_mutex_unlock(&avsync->lock);
812 }
813}
814
815avs_start_ret av_sync_audio_start(
816 void *sync,
817 pts90K pts,
818 pts90K delay,
819 audio_start_cb cb,
820 void *priv)
821{
822 struct av_sync_session *avsync = (struct av_sync_session *)sync;
823 uint32_t start_mode;
824 avs_start_ret ret = AV_SYNC_ASTART_ERR;
825 bool create_poll_t = false;
826
827 if (!avsync)
828 return ret;
829
830 if (msync_session_set_audio_start(avsync->fd, pts, delay, &start_mode))
831 log_error("[%d]fail to set audio start", avsync->session_id);
832
Song Zhaoea5a0412021-01-18 16:40:08 -0800833 if (start_mode == AVS_START_SYNC) {
834 ret = AV_SYNC_ASTART_SYNC;
835 avsync->session_started = true;
836 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaod62bb392021-04-23 12:25:49 -0700837 } else if (start_mode == AVS_START_ASYNC) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800838 ret = AV_SYNC_ASTART_ASYNC;
Song Zhaod62bb392021-04-23 12:25:49 -0700839 avsync->state = AV_SYNC_STAT_RUNNING;
840 } else if (start_mode == AVS_START_AGAIN) {
841 ret = AV_SYNC_ASTART_AGAIN;
842 }
843
844 if (ret == AV_SYNC_ASTART_AGAIN)
845 goto exit;
Song Zhaoea5a0412021-01-18 16:40:08 -0800846
847 if (avsync->mode == AV_SYNC_MODE_AMASTER) {
848 create_poll_t = true;
849 if (start_mode == AVS_START_ASYNC) {
850 if (!cb) {
851 log_error("[%d]invalid cb", avsync->session_id);
852 return AV_SYNC_ASTART_ERR;
853 }
854 avsync->audio_start = cb;
855 avsync->audio_start_priv = priv;
856 }
Song Zhaod62bb392021-04-23 12:25:49 -0700857 } else if (LIVE_MODE(avsync->mode))
Song Zhaoea5a0412021-01-18 16:40:08 -0800858 create_poll_t = true;
859
Song Zhaod62bb392021-04-23 12:25:49 -0700860 if (create_poll_t && !avsync->poll_thread) {
Song Zhaoea5a0412021-01-18 16:40:08 -0800861 int ret;
862
863 log_info("[%d]start poll thread", avsync->session_id);
864 avsync->quit_poll = false;
865 ret = pthread_create(&avsync->poll_thread, NULL, poll_thread, avsync);
866 if (ret) {
867 log_error("[%d]create poll thread errno %d", avsync->session_id, errno);
868 return AV_SYNC_ASTART_ERR;
869 }
870 }
Song Zhaod62bb392021-04-23 12:25:49 -0700871 if (LIVE_MODE(avsync->mode)) {
872 uint32_t systime;
873 msync_session_get_wall(avsync->fd, &systime, NULL);
874 log_info("[%d]return %u w %u pts %u d %u",
875 avsync->session_id, ret, systime, pts, delay);
876 }
877exit:
Song Zhaoea5a0412021-01-18 16:40:08 -0800878 log_info("[%d]return %u", avsync->session_id, ret);
879 return ret;
880}
881
882int av_sync_audio_render(
883 void *sync,
884 pts90K pts,
885 struct audio_policy *policy)
886{
887 int ret = 0;
888 uint32_t systime;
889 struct av_sync_session *avsync = (struct av_sync_session *)sync;
890 avs_audio_action action = AA_SYNC_AA_MAX;
891
892 if (!avsync || !policy)
893 return -1;
894
895 if (avsync->mode == AV_SYNC_MODE_FREE_RUN ||
896 avsync->mode == AV_SYNC_MODE_AMASTER) {
897 action = AV_SYNC_AA_RENDER;
898 goto done;
899 }
900
Song Zhaod62bb392021-04-23 12:25:49 -0700901 /* stopping procedure, unblock audio rendering */
902 if (avsync->mode == AV_SYNC_MODE_PCR_MASTER &&
903 avsync->active_mode == AV_SYNC_MODE_FREE_RUN) {
904 action = AV_SYNC_AA_DROP;
905 goto done;
906 }
907
Song Zhaoea5a0412021-01-18 16:40:08 -0800908 msync_session_get_wall(avsync->fd, &systime, NULL);
Song Zhaod62bb392021-04-23 12:25:49 -0700909
910 if (avsync->state == AV_SYNC_STAT_SYNC_SETUP &&
911 LIVE_MODE(avsync->mode) &&
912 abs_diff(systime, pts) > STREAM_DISC_THRES) {
913 /* outlier by stream error */
914 avsync->outlier_cnt++;
915 if (avsync->outlier_cnt > OUTLIER_MAX_CNT) {
916 /* treat as disc, just drop current frame */
917 avsync->state = AV_SYNC_STAT_SYNC_LOST;
918 avsync->outlier_cnt = 0;
919 action = AV_SYNC_AA_DROP;
920 systime = pts;
921 msync_session_set_audio_dis(avsync->fd, pts);
922 goto done;
923 }
924 log_info("[%d]ignore outlier %u", avsync->session_id, pts);
925 pts = systime;
926 action = AV_SYNC_AA_RENDER;
927 goto done;
928 }
929
930 avsync->outlier_cnt = 0;
931 /* low bound from sync_lost to sync_setup */
932 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_LB) {
933 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
934 action = AV_SYNC_AA_RENDER;
935 goto done;
936 }
937
938 /* high bound of sync_setup */
939 if (abs_diff(systime, pts) < A_ADJ_THREDHOLD_HB &&
940 avsync->state != AV_SYNC_STAT_SYNC_LOST) {
941 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhaoea5a0412021-01-18 16:40:08 -0800942 action = AV_SYNC_AA_RENDER;
943 goto done;
944 }
945
946 if ((int)(systime - pts) > 0) {
Song Zhaod62bb392021-04-23 12:25:49 -0700947 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -0800948 action = AV_SYNC_AA_DROP;
949 goto done;
950 }
951
952 if ((int)(systime - pts) < 0) {
Song Zhaod62bb392021-04-23 12:25:49 -0700953 avsync->state = AV_SYNC_STAT_SYNC_LOST;
Song Zhaoea5a0412021-01-18 16:40:08 -0800954 action = AV_SYNC_AA_INSERT;
955 goto done;
956 }
957
958done:
959 policy->action = action;
960 policy->delta = (int)(systime - pts);
961 if (action == AV_SYNC_AA_RENDER) {
962 avsync->apts = pts;
963 msync_session_update_apts(avsync->fd, systime, pts, 0);
Song Zhaod62bb392021-04-23 12:25:49 -0700964 log_debug("[%d]return %d sys %u - pts %u = %d",
965 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800966 } else {
Song Zhaod62bb392021-04-23 12:25:49 -0700967 log_info("[%d]return %d sys %u - pts %u = %d",
968 avsync->session_id, action, systime, pts, systime - pts);
Song Zhaoea5a0412021-01-18 16:40:08 -0800969 }
970
971 return ret;
972}
973
974int av_sync_get_clock(void *sync, pts90K *pts)
975{
976 struct av_sync_session *avsync = (struct av_sync_session *)sync;
977
978 if (!avsync || !pts)
979 return -1;
980 return msync_session_get_wall(avsync->fd, pts, NULL);
981}
982
983static void handle_mode_change_a(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -0700984 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -0800985{
Song Zhaoe208d692021-04-19 15:38:52 -0700986 log_info("[%d]amode %d mode %d v/a/vt %d/%d/%d", avsync->session_id,
987 avsync->active_mode, avsync->mode, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -0800988 if (avsync->active_mode == AV_SYNC_MODE_AMASTER) {
989 float speed;
990 if (avsync->start_policy == AV_SYNC_START_ALIGN &&
Song Zhaoe208d692021-04-19 15:38:52 -0700991 a_active && avsync->audio_start) {
992 if (v_active || v_timeout) {
993 log_info("audio start cb");
994 trigger_audio_start_cb(avsync, AV_SYNC_ASCB_OK);
995 }
Song Zhaoea5a0412021-01-18 16:40:08 -0800996 }
997
998 if (!msync_session_get_rate(avsync->fd, &speed)) {
999 /* speed change is triggered by asink,
1000 * attached audio HAL will handle it
1001 */
1002 if (speed != avsync->speed)
1003 log_info("[%d]new rate %f", avsync->session_id, speed);
1004 if (speed == 1.0) {
1005 avsync->mode = avsync->backup_mode;
1006 log_info("[%d]audio back to mode %d", avsync->session_id, avsync->mode);
1007 } else {
1008 avsync->backup_mode = avsync->mode;
1009 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1010 log_info("[%d]audio to freerun mode", avsync->session_id);
1011 }
1012 avsync->speed = speed;
1013 }
Song Zhaod62bb392021-04-23 12:25:49 -07001014 } else if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1015 struct session_debug debug;
1016 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1017 if (debug.debug_freerun) {
1018 avsync->backup_mode = avsync->mode;
1019 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1020 log_warn("[%d]audio to freerun mode", avsync->session_id);
1021 } else {
1022 avsync->mode = avsync->backup_mode;
1023 log_warn("[%d]audio back to mode %d",
1024 avsync->session_id, avsync->mode);
1025 }
1026 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001027 }
1028}
1029
1030static void handle_mode_change_v(struct av_sync_session* avsync,
Song Zhaoe208d692021-04-19 15:38:52 -07001031 bool v_active, bool a_active, bool v_timeout)
Song Zhaoea5a0412021-01-18 16:40:08 -08001032{
1033 log_info("[%d]amode mode %d %d v/a %d/%d", avsync->session_id,
1034 avsync->active_mode, avsync->mode, v_active, a_active);
Song Zhaod62bb392021-04-23 12:25:49 -07001035 if (avsync->active_mode == AV_SYNC_MODE_PCR_MASTER) {
1036 struct session_debug debug;
1037 if (!msync_session_get_debug_mode(avsync->fd, &debug)) {
1038 if (debug.debug_freerun) {
1039 avsync->backup_mode = avsync->mode;
1040 avsync->mode = AV_SYNC_MODE_FREE_RUN;
1041 log_warn("[%d]video to freerun mode", avsync->session_id);
1042 } else
1043 avsync->mode = avsync->backup_mode;
1044 log_warn("[%d]video back to mode %d",
1045 avsync->session_id, avsync->mode);
1046 }
1047 }
Song Zhaoea5a0412021-01-18 16:40:08 -08001048}
1049
1050static void * poll_thread(void * arg)
1051{
1052 int ret = 0;
1053 struct av_sync_session *avsync = (struct av_sync_session *)arg;
1054 const int fd = avsync->fd;
1055 struct pollfd pfd = {
1056 /* default blocking capture */
1057 .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM,
1058 .fd = avsync->fd,
1059 };
1060
1061 prctl (PR_SET_NAME, "avs_poll");
1062 log_info("[%d]enter", avsync->session_id);
1063 while (!avsync->quit_poll) {
1064 for (;;) {
1065 ret = poll(&pfd, 1, 10);
1066 if (ret > 0)
1067 break;
1068 if (avsync->quit_poll)
1069 goto exit;
1070 if (errno == EINTR)
1071 continue;
1072 }
1073
1074 /* error handling */
1075 if (pfd.revents & POLLERR)
1076 log_error("[%d]POLLERR received", avsync->session_id);
1077
Song Zhaod62bb392021-04-23 12:25:49 -07001078 /* mode change. Non-exclusive wait so all the processes
1079 * shall be woken up
1080 */
Song Zhaoea5a0412021-01-18 16:40:08 -08001081 if (pfd.revents & POLLPRI) {
Song Zhaoe208d692021-04-19 15:38:52 -07001082 bool v_active, a_active, v_timeout;
Song Zhaoea5a0412021-01-18 16:40:08 -08001083
1084 msync_session_get_stat(fd, &avsync->active_mode,
Song Zhaoe208d692021-04-19 15:38:52 -07001085 &v_active, &a_active, &v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001086
1087 if (avsync->type == AV_SYNC_TYPE_AUDIO)
Song Zhaoe208d692021-04-19 15:38:52 -07001088 handle_mode_change_a(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001089 else if (avsync->type == AV_SYNC_TYPE_VIDEO)
Song Zhaoe208d692021-04-19 15:38:52 -07001090 handle_mode_change_v(avsync, v_active, a_active, v_timeout);
Song Zhaoea5a0412021-01-18 16:40:08 -08001091 }
1092 }
1093exit:
1094 log_info("[%d]quit", avsync->session_id);
1095 return NULL;
1096}
1097
Song Zhaod62bb392021-04-23 12:25:49 -07001098int av_sync_set_pcr_clock(void *sync, pts90K pts, uint64_t mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001099{
1100 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1101
1102 if (!avsync)
1103 return -1;
1104
1105 if (avsync->type != AV_SYNC_TYPE_PCR)
1106 return -2;
1107
Song Zhaod62bb392021-04-23 12:25:49 -07001108 return msync_session_set_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001109}
1110
Song Zhaod62bb392021-04-23 12:25:49 -07001111int av_sync_get_pcr_clock(void *sync, pts90K *pts, uint64_t * mono_clock)
Song Zhaoea5a0412021-01-18 16:40:08 -08001112{
1113 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1114
1115 if (!avsync)
1116 return -1;
1117
1118 if (avsync->type != AV_SYNC_TYPE_PCR)
1119 return -2;
1120
Song Zhaod62bb392021-04-23 12:25:49 -07001121 return msync_session_get_pcr(avsync->fd, pts, mono_clock);
Song Zhaoea5a0412021-01-18 16:40:08 -08001122}
1123
1124int av_sync_set_session_name(void *sync, const char *name)
1125{
1126 struct av_sync_session *avsync = (struct av_sync_session *)sync;
1127
1128 if (!avsync)
1129 return -1;
1130
1131 return msync_session_set_name(avsync->fd, name);
1132}