blob: 2019c71e8fefb11a802c5a2d6344ab82272107c2 [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 */
9
10#include <pthread.h>
11#include <stdbool.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <sys/time.h>
15
16#include "aml_avsync.h"
17#include "queue.h"
18#include "pattern.h"
19#include "tsync.h"
20#include "aml_avsync_log.h"
21
22enum sync_state {
23 AV_SYNC_STAT_INIT = 0,
24 AV_SYNC_STAT_RUNNING = 1,
25 AV_SYNC_STAT_SYNC_SETUP = 2,
26 AV_SYNC_STAT_SYNC_LOST = 3,
27};
28
29struct av_sync_session {
30 /* session id attached */
31 int session_id;
32 /* playback time, will stop increasing during pause */
33 pts90K stream_time;
34 pts90K vpts;
35
36 /* phase adjustment of stream time for rate control */
37 pts90K phase;
38 bool phase_set;
39
40 /* pts of last rendered frame */
41 pts90K last_pts;
42 struct vframe *last_frame;
43
44 bool first_frame_toggled;
45 /* Whether in pause state */
46 bool paused;
47 enum sync_mode mode;
48 enum sync_state state;
49 void *pattern_detector;
50 void *frame_q;
51 /* start threshold */
52 int start_thres;
53
54 /* display property */
55 int delay;
56 pts90K vsync_interval;
57
58 /* state lock */
59 pthread_mutex_t lock;
60 /* pattern */
61 int last_holding_peroid;
62 bool tsync_started;
63
64 float speed;
65
66 /*pip sync, remove after multi instance is supported*/
67 struct timeval base_sys_time;
68 struct timeval pause_start;
69 uint64_t pause_duration;
70 pts90K first_pts;
71
72 /* pause pts */
73 pts90K pause_pts;
74 pause_pts_done pause_pts_cb;
75 void *pause_cb_priv;
Song Zhao5d2b4772021-01-18 16:40:08 -080076
77 /* log control */
78 uint32_t last_systime;
79 uint32_t sync_lost_cnt;
80 struct timeval sync_lost_print_time;
Song Zhaoc03ba122020-12-23 21:54:02 -080081};
82
83#define MAX_FRAME_NUM 32
84#define DEFAULT_START_THRESHOLD 2
85#define TIME_UNIT90K (90000)
86#define AV_DISCONTINUE_THREDHOLD_MIN (TIME_UNIT90K * 3)
Song Zhao5d2b4772021-01-18 16:40:08 -080087#define SYNC_LOST_PRINT_THRESHOLD 10000000 //10 seconds In micro seconds
Song Zhaoc03ba122020-12-23 21:54:02 -080088
89static uint64_t time_diff (struct timeval *b, struct timeval *a);
90static bool frame_expire(struct av_sync_session* avsync,
91 uint32_t systime,
92 struct vframe * frame,
93 struct vframe * next_frame,
94 int toggle_cnt);
95static bool frame_expire_pip(struct av_sync_session* avsync,
96 struct vframe * frame);
97static void pattern_detect(struct av_sync_session* avsync,
98 int cur_period,
99 int last_period);
100
101void* av_sync_create(int session_id,
102 enum sync_mode mode,
103 int start_thres,
104 int delay, pts90K vsync_interval)
105{
106 struct av_sync_session *avsync = NULL;
107
108 if (start_thres > 5) {
109 log_error("start_thres too big: %d", start_thres);
110 return NULL;
111 }
112 if (delay != 1 && delay != 2) {
113 log_error("invalid delay: %d\n", delay);
114 return NULL;
115 }
116 if (vsync_interval < 750 || vsync_interval > 3750) {
117 log_error("invalid vsync interval: %d", vsync_interval);
118 return NULL;
119 }
120 if (session_id != 0 && session_id != 1) {
121 log_error("invalid session: %d", session_id);
122 return NULL;
123 }
124
125 avsync = (struct av_sync_session *)calloc(1, sizeof(*avsync));
126 if (!avsync) {
127 log_error("OOM");
128 return NULL;
129 }
130 avsync->pattern_detector = create_pattern_detector();
131 if (!avsync->pattern_detector) {
132 log_error("pd create fail");
133 free(avsync);
134 return NULL;
135 }
136 avsync->state = AV_SYNC_STAT_INIT;
137 avsync->first_frame_toggled = false;
138 avsync->paused = false;
139 avsync->phase_set = false;
140 avsync->session_id = session_id;
141 avsync->mode = mode;
142 avsync->last_frame = NULL;
143 avsync->tsync_started = false;
144 avsync->speed = 1.0f;
145 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
146
147 if (!start_thres)
148 avsync->start_thres = DEFAULT_START_THRESHOLD;
149 else
150 avsync->start_thres = start_thres;
151 avsync->delay = delay;
152 avsync->vsync_interval = vsync_interval;
153
154 avsync->frame_q = create_q(MAX_FRAME_NUM);
155 if (!avsync->frame_q) {
156 log_error("create queue fail");
157 destroy_pattern_detector(avsync->pattern_detector);
158 free(avsync);
159 return NULL;
160 }
161 //TODO: connect kernel session
162
163 if (avsync->session_id != 1) {
164 /* just in case sysnode is wrongly set */
165 tsync_send_video_pause(avsync->session_id, false);
166 } else
167 avsync->first_pts = -1;
168
169 pthread_mutex_init(&avsync->lock, NULL);
170 log_info("mode: %d start_thres: %d delay: %d interval: %d session: %d done\n",
171 mode, start_thres, delay, vsync_interval, session_id);
172 return avsync;
173}
174
175static int internal_stop(struct av_sync_session *avsync)
176{
177 int ret = 0;
178 struct vframe *frame;
179
180 pthread_mutex_lock(&avsync->lock);
181 if (avsync->state == AV_SYNC_STAT_INIT)
182 goto exit;
183
184 while (!dqueue_item(avsync->frame_q, (void **)&frame)) {
185 frame->free(frame);
186 }
187
188 avsync->state = AV_SYNC_STAT_INIT;
189exit:
190 pthread_mutex_unlock(&avsync->lock);
191 return ret;
192}
193
194/* destroy and detach from kernel session */
195void av_sync_destroy(void *sync)
196{
197 struct av_sync_session *avsync = (struct av_sync_session *)sync;
198
199 if (!avsync)
200 return;
201
202 log_info("begin");
203 if (avsync->state != AV_SYNC_STAT_INIT)
204 internal_stop(avsync);
205
206 /* all frames are freed */
207 if (avsync->session_id != 1)
208 tsync_set_pts_inc_mode(avsync->session_id, false);
209
210 pthread_mutex_destroy(&avsync->lock);
211 destroy_q(avsync->frame_q);
212 destroy_pattern_detector(avsync->pattern_detector);
213 free(avsync);
214 log_info("done");
215}
216
217int av_sync_pause(void *sync, bool pause)
218{
219 struct av_sync_session *avsync = (struct av_sync_session *)sync;
220
221 if (!avsync)
222 return -1;
223
224 if (avsync->session_id == 1) {
225 if (!avsync->paused && pause) {
226 gettimeofday(&avsync->pause_start, NULL);
227 avsync->paused = true;
228 }
229 if (avsync->paused && !pause) {
230 struct timeval now;
231
232 gettimeofday(&now, NULL);
233 avsync->pause_duration += time_diff(&now, &avsync->pause_start);
234 avsync->paused = false;
235 }
236 return 0;
237 }
238
239 if (avsync->mode == AV_SYNC_MODE_VMASTER) {
240 tsync_send_video_pause(avsync->session_id, pause);
241 }
242 avsync->paused = pause;
243 log_info("paused:%d\n", pause);
244
245 return 0;
246}
247
248int av_sync_push_frame(void *sync , struct vframe *frame)
249{
250 int ret;
251 struct vframe *prev;
252 struct av_sync_session *avsync = (struct av_sync_session *)sync;
253
254 if (!avsync)
255 return -1;
256
257 if (!peek_item(avsync->frame_q, (void **)&prev, 0)) {
258 if (prev->pts == frame->pts) {
259 dqueue_item(avsync->frame_q, (void **)&prev);
260 prev->free(prev);
261 log_info ("drop frame with same pts %u", frame->pts);
262 }
263 }
264
265 frame->hold_period = 0;
266 ret = queue_item(avsync->frame_q, frame);
267 if (avsync->state == AV_SYNC_STAT_INIT &&
268 queue_size(avsync->frame_q) >= avsync->start_thres) {
269 avsync->state = AV_SYNC_STAT_RUNNING;
270 log_info("state: init --> running");
271 }
272
273 if (ret)
274 log_error("%s queue fail:%d", ret);
275 return ret;
276
277}
278
279struct vframe *av_sync_pop_frame(void *sync)
280{
281 struct vframe *frame = NULL;
282 struct av_sync_session *avsync = (struct av_sync_session *)sync;
283 int toggle_cnt = 0;
284 uint32_t systime;
Song Zhao468fd652021-01-15 22:13:04 -0800285 bool pause_pts_reached = false;
Song Zhaoc03ba122020-12-23 21:54:02 -0800286
287 pthread_mutex_lock(&avsync->lock);
288 if (avsync->state == AV_SYNC_STAT_INIT) {
289 log_trace("in state INIT");
290 goto exit;
291 }
292
293 if (avsync->session_id == 1) {
294 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
295 log_info("empty q");
296 goto exit;
297 }
298
299 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
300 if (frame_expire_pip(avsync, frame)) {
301 toggle_cnt++;
302
303 dqueue_item(avsync->frame_q, (void **)&frame);
304 if (avsync->last_frame) {
305 /* free frame that are not for display */
306 if (toggle_cnt > 1)
307 avsync->last_frame->free(avsync->last_frame);
308 } else {
309 avsync->first_frame_toggled = true;
310 log_info("first frame %u", frame->pts);
311 }
312 avsync->last_frame = frame;
313 } else
314 break;
315 }
316 goto exit;
317 }
318
319 if (!avsync->tsync_started) {
320 if (peek_item(avsync->frame_q, (void **)&frame, 0) || !frame) {
321 log_info("empty q");
322 goto exit;
323 }
324
325 if (tsync_enable(avsync->session_id, true))
326 log_error("enable tsync fail");
327 if (avsync->mode == AV_SYNC_MODE_VMASTER) {
328 if (tsync_set_mode(avsync->session_id, AV_SYNC_MODE_VMASTER))
329 log_error("set vmaster mode fail");
330 if (tsync_set_pcr(avsync->session_id, frame->pts))
331 log_error("set pcr fail");
332 log_info("update pcr to: %u", frame->pts);
333 if (tsync_set_pts_inc_mode(avsync->session_id, true))
334 log_error("set inc mode fail");
335 } else if (avsync->mode == AV_SYNC_MODE_AMASTER) {
336 if (tsync_set_pts_inc_mode(avsync->session_id, false))
337 log_error("set inc mode fail");
338 if (tsync_set_mode(avsync->session_id, AV_SYNC_MODE_AMASTER))
339 log_error("set amaster mode fail");
340 } else {
341 //PCR master mode should be set alreay, but it won't hurt to set again.
342 if (tsync_set_mode(avsync->session_id, AV_SYNC_MODE_PCR_MASTER))
343 log_error("set pcrmaster mode fail");
344 }
345
346 tsync_set_video_peek_mode(avsync->session_id);
347 tsync_disable_video_stop_event(avsync->session_id, true);
348 /* video start ASAP */
349 tsync_set_video_sync_thres(avsync->session_id, false);
350 /* video start event */
351 if (tsync_send_video_start(avsync->session_id, frame->pts))
352 log_error("send video start fail");
353 else
354 log_info("video start %u", frame->pts);
355 avsync->tsync_started = true;
356 }
357
358 systime = tsync_get_pcr(avsync->session_id);
359 while (!peek_item(avsync->frame_q, (void **)&frame, 0)) {
360 struct vframe *next_frame = NULL;
361
362 peek_item(avsync->frame_q, (void **)&next_frame, 1);
363 if (next_frame)
364 log_debug("cur_f %u next_f %u", frame->pts, next_frame->pts);
365 if (frame_expire(avsync, systime, frame, next_frame, toggle_cnt)) {
366 log_debug("cur_f %u expire", frame->pts);
367 toggle_cnt++;
368
369 pattern_detect(avsync,
370 (avsync->last_frame?avsync->last_frame->hold_period:0),
371 avsync->last_holding_peroid);
372 if (avsync->last_frame)
373 avsync->last_holding_peroid = avsync->last_frame->hold_period;
374
375 dqueue_item(avsync->frame_q, (void **)&frame);
376 if (avsync->last_frame) {
377 /* free frame that are not for display */
378 if (toggle_cnt > 1)
379 avsync->last_frame->free(avsync->last_frame);
380 } else {
381 avsync->first_frame_toggled = true;
382 log_info("first frame %u", frame->pts);
383 }
384 avsync->last_frame = frame;
Song Zhao5d2b4772021-01-18 16:40:08 -0800385 avsync->last_pts = frame->pts;
Song Zhaoc03ba122020-12-23 21:54:02 -0800386 } else
387 break;
388 }
389
390 /* pause pts */
391 if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS && avsync->last_frame) {
Song Zhaoc03ba122020-12-23 21:54:02 -0800392 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
Song Zhao468fd652021-01-15 22:13:04 -0800393 pause_pts_reached = true;
Song Zhaoc03ba122020-12-23 21:54:02 -0800394 else
Song Zhao468fd652021-01-15 22:13:04 -0800395 pause_pts_reached = (int)(avsync->last_frame->pts - avsync->pause_pts) >= 0;
396 } else if (avsync->pause_pts != AV_SYNC_INVALID_PAUSE_PTS) {
397 if (!peek_item(avsync->frame_q, (void **)&frame, 0))
398 pause_pts_reached = (int)(frame->pts - avsync->pause_pts) >= 0;
399 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800400
Song Zhao468fd652021-01-15 22:13:04 -0800401 if (pause_pts_reached) {
402 if (avsync->pause_pts_cb)
403 avsync->pause_pts_cb(avsync->pause_pts,
Song Zhaoc03ba122020-12-23 21:54:02 -0800404 avsync->pause_cb_priv);
405
Song Zhao468fd652021-01-15 22:13:04 -0800406 /* stay in paused until av_sync_pause(false) */
407 avsync->paused = true;
408 avsync->pause_pts = AV_SYNC_INVALID_PAUSE_PTS;
409 log_info ("reach pause pts: %u", avsync->last_frame->pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800410 }
411
412exit:
413 pthread_mutex_unlock(&avsync->lock);
414 if (avsync->last_frame) {
415 log_debug("pop %u", avsync->last_frame->pts);
416 tsync_set_vpts(avsync->session_id,avsync->last_frame->pts);
417 } else
418 log_debug("pop (nil)");
419 if (avsync->last_frame)
420 avsync->last_frame->hold_period++;
421 return avsync->last_frame;
422}
423
424void av_sync_update_vsync_interval(void *sync, pts90K vsync_interval)
425{
426 struct av_sync_session *avsync = (struct av_sync_session *)sync;
427
428 pthread_mutex_lock(&avsync->lock);
429 avsync->vsync_interval = vsync_interval;
430 if (avsync->state >= AV_SYNC_STAT_RUNNING) {
431 reset_pattern(avsync->pattern_detector);
432 avsync->phase_set = false;
433 }
434 pthread_mutex_unlock(&avsync->lock);
435}
436
437static inline uint32_t abs_diff(uint32_t a, uint32_t b)
438{
439 return a > b ? a - b : b - a;
440}
441
442static uint64_t time_diff (struct timeval *b, struct timeval *a)
443{
444 return (b->tv_sec - a->tv_sec)*1000000 + (b->tv_usec - a->tv_usec);
445}
446
447static bool frame_expire_pip(struct av_sync_session* avsync,
448 struct vframe * frame)
449{
450 struct timeval systime;
451 uint64_t passed;
452 pts90K passed_90k;
453
454 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
455 return false;
456
457 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
458 return true;
459
460 gettimeofday(&systime, NULL);
461 if (avsync->first_pts == -1) {
462 avsync->first_pts = frame->pts;
463 avsync->base_sys_time = systime;
464 log_debug("first_pts %u, sys %d/%d", frame->pts,
465 systime.tv_sec, systime.tv_usec);
466 return true;
467 }
468
469 passed = time_diff(&systime, &avsync->base_sys_time);
470 passed -= avsync->pause_duration;
471 passed *= avsync->speed;
472 passed_90k = (pts90K)(passed * 9 / 100);
473
474 if (passed_90k > (frame->pts - avsync->first_pts)) {
475 log_trace("cur_f %u sys: %u/%d stream: %u",
476 frame->pts, systime.tv_sec, systime.tv_usec, passed_90k);
477 return true;
478 }
479
480 return false;
481}
482
483static bool frame_expire(struct av_sync_session* avsync,
484 uint32_t systime,
485 struct vframe * frame,
486 struct vframe * next_frame,
487 int toggle_cnt)
488{
489 uint32_t fpts = frame->pts;
490 bool expire = false;
491 uint32_t pts_correction = avsync->delay * avsync->vsync_interval;
492
493 if (avsync->paused && avsync->pause_pts == AV_SYNC_INVALID_PAUSE_PTS)
494 return false;
495
496 if (avsync->pause_pts == AV_SYNC_STEP_PAUSE_PTS)
497 return true;
498
499 if (!fpts) {
500 if (avsync->last_frame) {
501 /* try to accumulate duration as PTS */
502 fpts = avsync->vpts + avsync->last_frame->duration;
503 } else {
504 fpts = avsync->vpts;
505 }
506 }
507 systime += pts_correction;
508
509 /* phase adjustment */
510 if (avsync->phase_set)
511 systime += avsync->phase;
512
513 log_trace("systime:%u phase:%u correct:%u", systime,
514 avsync->phase_set?avsync->phase:0, pts_correction);
515 if (abs_diff(systime, fpts) > AV_DISCONTINUE_THREDHOLD_MIN &&
516 avsync->first_frame_toggled) {
517 /* ignore discontinity under pause */
518 if (avsync->paused && avsync->mode != AV_SYNC_MODE_PCR_MASTER)
519 return false;
520
Song Zhao5d2b4772021-01-18 16:40:08 -0800521 if (avsync->last_systime != systime || avsync->last_pts != fpts) {
522 struct timeval now;
523
524 gettimeofday(&now, NULL);
525 avsync->last_systime = systime;
526 avsync->last_pts = fpts;
527 if (time_diff(&now, &avsync->sync_lost_print_time) >=
528 SYNC_LOST_PRINT_THRESHOLD) {
529 log_warn("sync lost systime:%x fpts:%x lost:%u",
530 systime, fpts, avsync->sync_lost_cnt);
531 avsync->sync_lost_cnt = 0;
532 } else
533 avsync->sync_lost_cnt++;
534 }
Song Zhaoc03ba122020-12-23 21:54:02 -0800535 avsync->state = AV_SYNC_STAT_SYNC_LOST;
536 avsync->phase_set = false;
537 if ((int)(systime - fpts) > 0) {
538 if (frame->pts && avsync->mode == AV_SYNC_MODE_VMASTER)
539 tsync_send_video_disc(avsync->session_id, frame->pts);
540 /*catch up PCR */
541 return true;
542 } else if (avsync->mode == AV_SYNC_MODE_PCR_MASTER) {
543 if (frame->pts)
544 tsync_send_video_disc(avsync->session_id, frame->pts);
545 else {
546 tsync_send_video_disc(avsync->session_id, fpts);
547 return true;
548 }
549 }
550 }
551
552 expire = (int)(systime - fpts) >= 0;
553
554 /* scatter the frame in different vsync whenever possible */
555 if (expire && next_frame && next_frame->pts && toggle_cnt) {
556 /* multi frame expired in current vsync but no frame in next vsync */
557 if (systime + avsync->vsync_interval < next_frame->pts) {
558 expire = false;
559 frame->hold_period++;
560 log_debug("unset expire systime:%d inter:%d next_pts:%d toggle_cnt:%d",
561 systime, avsync->vsync_interval, next_frame->pts, toggle_cnt);
562 }
563 } else if (!expire && next_frame && next_frame->pts && !toggle_cnt
564 && avsync->first_frame_toggled) {
565 /* next vsync will have at least 2 frame expired */
566 if (systime + avsync->vsync_interval > next_frame->pts) {
567 expire = true;
568 log_debug("set expire systime:%d inter:%d next_pts:%d",
569 systime, avsync->vsync_interval, next_frame->pts);
570 }
571 }
572
573 correct_pattern(avsync->pattern_detector, frame, next_frame,
574 (avsync->last_frame?avsync->last_frame->hold_period:0),
575 avsync->last_holding_peroid, systime,
576 avsync->vsync_interval, &expire);
577
578 if (expire) {
579 avsync->vpts = fpts;
580 /* phase adjustment */
581 if (!avsync->phase_set) {
582 uint32_t phase_thres = avsync->vsync_interval / 4;
583 //systime = tsync_get_pcr(avsync->session_id);
584 if ( systime > fpts && (systime - fpts) < phase_thres) {
585 /* too aligned to current VSYNC, separate them to 1/4 VSYNC */
586 avsync->phase += phase_thres - (systime - fpts);
587 avsync->phase_set = true;
588 log_info("adjust phase to %d", avsync->phase);
589 }
590 if (!avsync->phase_set && systime > fpts &&
591 systime < (fpts + avsync->vsync_interval) &&
592 (systime - fpts) > avsync->vsync_interval - phase_thres) {
593 /* too aligned to previous VSYNC, separate them to 1/4 VSYNC */
594 avsync->phase += phase_thres + fpts + avsync->vsync_interval - systime;
595 avsync->phase_set = true;
596 log_info("adjust phase to %d", avsync->phase);
597 }
598 }
599
600 if (avsync->state != AV_SYNC_STAT_SYNC_SETUP)
601 log_info("sync setup");
602 avsync->state = AV_SYNC_STAT_SYNC_SETUP;
Song Zhao5d2b4772021-01-18 16:40:08 -0800603 avsync->sync_lost_cnt = 0;
Song Zhaoc03ba122020-12-23 21:54:02 -0800604 }
605 return expire;
606}
607
608static void pattern_detect(struct av_sync_session* avsync, int cur_period, int last_period)
609{
610 log_trace("cur_period: %d last_period: %d", cur_period, last_period);
611 detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P32, cur_period, last_period);
612 detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P22, cur_period, last_period);
613 detect_pattern(avsync->pattern_detector, AV_SYNC_FRAME_P41, cur_period, last_period);
614}
615
616int av_sync_set_speed(void *sync, float speed)
617{
618 struct av_sync_session *avsync = (struct av_sync_session *)sync;
619
620 if (speed < 0.001f || speed > 100) {
621 log_error("wrong speed %f [0.0001, 100]", speed);
622 return -1;
623 }
624
625 avsync->speed = speed;
626 if (avsync->session_id == 1)
627 return 0;
628
629 if (avsync->mode != AV_SYNC_MODE_VMASTER) {
630 log_info("ignore set speed in mode %d", avsync->mode);
631 return 0;
632 }
633
634 return tsync_set_speed(avsync->session_id, speed);
635}
636
637int av_sync_change_mode(void *sync, enum sync_mode mode)
638{
639 struct av_sync_session *avsync = (struct av_sync_session *)sync;
640
641 if (!avsync)
642 return -1;
643
644 if (avsync->session_id == 1)
645 return 0;
646
647 if (avsync->mode != AV_SYNC_MODE_VMASTER || mode != AV_SYNC_MODE_AMASTER) {
648 log_error("only support V to A mode switch");
649 return -1;
650 }
651
652 if (tsync_set_pts_inc_mode(avsync->session_id, false))
653 log_error("set inc mode fail");
654 if (tsync_set_mode(avsync->session_id, AV_SYNC_MODE_AMASTER))
655 log_error("set amaster mode fail");
656 avsync->mode = mode;
657 log_info("update sync mode to %d", mode);
658 return 0;
659}
660
661int av_sync_set_pause_pts(void *sync, pts90K pts)
662{
663 struct av_sync_session *avsync = (struct av_sync_session *)sync;
664
665 if (!avsync)
666 return -1;
667
668 avsync->pause_pts = pts;
Song Zhao468fd652021-01-15 22:13:04 -0800669 log_info("set pause pts: %u", pts);
Song Zhaoc03ba122020-12-23 21:54:02 -0800670 return 0;
671}
672
673int av_sync_set_pause_pts_cb(void *sync, pause_pts_done cb, void *priv)
674{
675 struct av_sync_session *avsync = (struct av_sync_session *)sync;
676
677 if (!avsync)
678 return -1;
679
680 avsync->pause_pts_cb = cb;
681 avsync->pause_cb_priv = priv;
682 return 0;
683}