libdvr: Cannot playback short audio recording [1/1]
PD#SWPL-100857
PD#OTT-36232
Problem:
Fail to playback a short audio recording.
Solution:
Avoid unexpectly triggerring REACHED_END event.
Verify:
Locally tested OK in RDK AH212 environment.
Signed-off-by: Wentao.MA <wentao.ma@amlogic.com>
Change-Id: Ic5d87e784557163e6d4ee9f9538c50dbb5ab0d59
diff --git a/include/dvr_playback.h b/include/dvr_playback.h
index 6424ff0..0ed2ae3 100644
--- a/include/dvr_playback.h
+++ b/include/dvr_playback.h
@@ -351,9 +351,11 @@
uint32_t first_start_time;
//The segment id where a playback is initially started
uint64_t first_start_id;
- //Determine whether it is needed to check the cache value from AmTsPlayer_getDelayTime
- //It is only allowed to check cache one time in a single playback
- DVR_Bool_t check_cache_flag;
+
+ // Tells whether the delay from AmTsPlayer_getDelayTime is valid.
+ // Notice it can be invalid in a short period at starting phase of a playback.
+ DVR_Bool_t delay_is_effective;
+
DVR_Bool_t need_seek_start;
//init fake pid
int fake_pid;
diff --git a/src/dvr_playback.c b/src/dvr_playback.c
index 60cff30..a92e5e4 100644
--- a/src/dvr_playback.c
+++ b/src/dvr_playback.c
@@ -63,6 +63,7 @@
static int _dvr_playback_sent_transition_ok(DVR_PlaybackHandle_t handle, DVR_Bool_t is_lock);
static uint32_t dvr_playback_calculate_last_valid_segment(
DVR_PlaybackHandle_t handle, uint64_t *segmentid, uint32_t *pos);
+static int get_effective_tsplayer_delay_time(DVR_Playback_t* playback,int64_t* time);
@@ -1356,22 +1357,23 @@
_dvr_playback_sent_event((DVR_PlaybackHandle_t)player, DVR_PLAYBACK_EVENT_NODATA, ¬ify, DVR_FALSE);
}
}
- //send reached event
- if ((ret != DVR_SUCCESS &&
- (player->vendor != DVR_PLAYBACK_VENDOR_AMAZON) &&
- (delay <= MIN_TSPLAYER_DELAY_TIME ||
- player->cmd.cur_cmd == DVR_PLAYBACK_CMD_FF) &&
- _dvr_pauselive_decode_success((DVR_PlaybackHandle_t)player)) ||
- (reach_end_timeout >= MAX_REACHEND_TIMEOUT )) {
- //send end event to hal
+
+ DVR_Bool_t cond1 = (ret != DVR_SUCCESS);
+ DVR_Bool_t cond2 = (player->vendor != DVR_PLAYBACK_VENDOR_AMAZON);
+ DVR_Bool_t cond3 = (delay <= MIN_TSPLAYER_DELAY_TIME);
+ DVR_Bool_t cond4 = (player->cmd.cur_cmd == DVR_PLAYBACK_CMD_FF);
+ DVR_Bool_t cond5 = (player->delay_is_effective == DVR_TRUE);
+ DVR_Bool_t cond6 = (reach_end_timeout >= MAX_REACHEND_TIMEOUT);
+ if ((cond1 && cond2 && (cond3 || cond4) && cond5) || cond6) {
+ DVR_PB_INFO("REACHED_END conditions: cond1:%d, cond2:%d, (cond3:%d, cond4:%d),"
+ " cond5:%d, cond6:%d. delay:%d, reach_end_timeout:%d",
+ (int)cond1,(int)cond2,(int)cond3,(int)cond4,(int)cond5,(int)cond6,
+ delay,reach_end_timeout);
DVR_Play_Notify_t notify;
memset(¬ify, 0 , sizeof(DVR_Play_Notify_t));
notify.event = DVR_PLAYBACK_EVENT_REACHED_END;
- //get play statue not here
dvr_playback_pause((DVR_PlaybackHandle_t)player, DVR_FALSE);
_dvr_playback_sent_event((DVR_PlaybackHandle_t)player, DVR_PLAYBACK_EVENT_REACHED_END, ¬ify, DVR_TRUE);
- //continue,timeshift mode, when read end,need wait cur recording segment
- DVR_PB_INFO("playback is send end delay:[%d]reach_end_timeout[%d]ms", delay, reach_end_timeout);
dvr_mutex_lock(&player->lock);
_dvr_playback_timeoutwait((DVR_PlaybackHandle_t)player, timeout);
dvr_mutex_unlock(&player->lock);
@@ -1435,7 +1437,8 @@
continue;
}
//if need write whole block size, we need check read buf len is eq block size.
- if (b_writed_whole_block == DVR_TRUE) {
+ if (b_writed_whole_block == DVR_TRUE
+ && (player->has_video || player->dec_func || player->cryptor)) {
//buf_len is block size value.
if (real_read < buf_len) {
//continue to read data from file
@@ -1761,7 +1764,7 @@
//need seek to start pos
player->first_start_time = 0;
player->first_start_id = UINT64_MAX;
- player->check_cache_flag = DVR_TRUE;
+ player->delay_is_effective = DVR_FALSE;
player->need_seek_start = DVR_TRUE;
//fake_pid init
player->fake_pid = getFakePid();
@@ -3267,38 +3270,13 @@
} else {
cur = segment_tell_position_time(player->r_handle, pos);
}
- AmTsPlayer_getDelayTime(player->handle, &cache);
-
pthread_mutex_unlock(&player->segment_lock);
- // The idea here is to work around a weakness of AmTsPlayer_getDelayTime at
- // starting phase of a playback in a short period of 20ms or less. During the
- // said period, getDelayTime does NOT work as expect to return real cache
- // length because demux isn't actually running to provide valid pts to
- // TsPlayer. "cache==0" implies the situation that playback is NOT actually
- // started. Under such conditions a '0' cache size may NOT reflect actual data
- // length remaining in TsPlayer cache, therefore corresponding libdvr 'cur' is
- // useless if data in TsPlayer cache is not considered, so it needs to be
- // reset to a previous valid state. To make the reset operation stricter, extra
- // AmTsPlayer_getPts invocations on both video/audio are introduced to test if
- // TsPlayer can get valid pts which indicates the actual running status of
- // demux. (JIRA issue: SWPL-68740)
- if (player->first_start_id != UINT64_MAX && cache == 0
- && player->check_cache_flag == DVR_TRUE ) {
- uint64_t pts_a=0;
- uint64_t pts_v=0;
- AmTsPlayer_getPts(player->handle, TS_STREAM_AUDIO, &pts_a);
- AmTsPlayer_getPts(player->handle, TS_STREAM_VIDEO, &pts_v);
- if ((int64_t)pts_a <= 0 && (int64_t)pts_v <= 0) {
- // Identified the wired situation and just return previous valid state
- cur = player->first_start_time;
- *id = player->first_start_id;
- return cur;
- }
- }
- if (cache != 0) {
- // Do NOT permit to enter 'if' code block above any more
- player->check_cache_flag=DVR_FALSE;
+ int ret = get_effective_tsplayer_delay_time(player, &cache);
+ if (player->first_start_id != UINT64_MAX && ret == DVR_FAILURE) {
+ cur = player->first_start_time;
+ *id = player->first_start_id;
+ return cur;
}
if (player->state == DVR_PLAYBACK_STATE_STOP) {
@@ -4173,3 +4151,41 @@
return DVR_SUCCESS;
}
+
+// This function ensures a valid TsPlayer delay time is provided or else it
+// returns DVR_FAILURE. It is designed to workaround a weakness of
+// AmTsPlayer_getDelayTime at starting phase of a playback in a short period
+// of 20ms or less. During the said period, getDelayTime does NOT work as
+// expect to return real delay length because demux isn't actually running
+// to provide valid pts to TsPlayer.
+static int get_effective_tsplayer_delay_time(DVR_Playback_t* playback,int64_t* time)
+{
+ int64_t delay=0;
+ uint64_t pts_a=0;
+ uint64_t pts_v=0;
+
+ DVR_RETURN_IF_FALSE(playback != NULL);
+
+ AmTsPlayer_getDelayTime(playback->handle, &delay);
+ DVR_RETURN_IF_FALSE(*time >= 0);
+
+ if (playback->delay_is_effective) {
+ *time = delay;
+ return DVR_SUCCESS;
+ } else if (delay > 0) {
+ *time = delay;
+ playback->delay_is_effective=DVR_TRUE;
+ return DVR_SUCCESS;
+ }
+
+ AmTsPlayer_getPts(playback->handle, TS_STREAM_AUDIO, &pts_a);
+ AmTsPlayer_getPts(playback->handle, TS_STREAM_VIDEO, &pts_v);
+ if ((int64_t)pts_a > 0 || (int64_t)pts_v > 0) {
+ *time = delay;
+ playback->delay_is_effective=DVR_TRUE;
+ return DVR_SUCCESS;
+ }
+
+ return DVR_FAILURE;
+}
+