Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DISCONTINUITY_ENCOUNTERED errors after consecutive audio track switches, for DASH live content, result in an endless loop #1252

Open
TomaszKowalik opened this issue May 26, 2023 · 2 comments

Comments

@TomaszKowalik
Copy link

Hi,

We have encountered an issue related to audiotrack switching for live content. It was discovered on Tizen 2020 Smart TV. We are using the default "seamless" audioTrackSwitchingMode. After a few consecutive audio track changes, I'm seeing DISCONTINUITY_ENCOUNTERED errors with messages like: "A discontinuity has been encountered at position 1685101429.977 and was sought at position 1685101430.0586665". But after that another DISCONTINUITY_ENCOUNTERED errros are showing up, player keeps seeking to positions from errors messages, resulting in an endless loop. After a few DISCONTINUITY_ENCOUNTERED errors, MEDIA_TIME_BEFORE_MANIFEST errors also start showing up.

To address this issue, I have implemented the following fix: After the first MEDIA_TIME_BEFORE_MANIFEST error, I seek back to a position of rxPlayer.getMinimumPosition() + 5, and playback resumes from there correctly. However, the loop of DISCONTINUITY_ENCOUNTERED errors persists until the first occurrence of the MEDIA_TIME_BEFORE_MANIFEST error.

I would like to know the best approach to resolve this issue. Please advise on the recommended solution.

Thank you.

@peaBerberian
Copy link
Collaborator

Hello,

Interesting, I thought we completely fixed those types of Tizen issues. Which RxPlayer version are you using?


For a little bit of history and explanation, Tizen is a peculiar platform which do not seek where we tell it to seek but instead to a close position where it thinks it will be able to restart playback faster.

For example, the RxPlayer may want to seek at a position, say, 10.5 seconds at some point and tell Tizen's browser to do that, but in turn, the position will end up to be at 10.2 seconds instead because Tizen would have thought that this is a better position to restart playback from.

To our understanding, this does not respect the HTML WHATWG standard (and is not observed in any other implementation) and we exchanged with Samsung about this, but they did not want to change this behavior, for different reasons.

However, developing a multi-platform media player is complex as many unexpected scenarios may happen anywhere in the whole stack (from hardware and drivers to the RxPlayer), which we have to detect and work-around.
Thus we have a lot of heuristics and guards to ensure that playback goes well, by ensuring that nothing seems off. Among them, we detect when there is an unexpected "hole" in the buffer which no media segment seems to fill. We call this a "discontinuity", here in the RxPlayer.

The RebufferingController, an RxPlayer "module" (basically an independent subpart of the RxPlayer), monitors where discontinuity appears and "jumps" over it as soon as they are encountered, to directly go to the part after it. That's when it does that that the DISCOUNTINUITY_ENCOUNTERED warning is sent (with in its message, both the position at which we 'were in and the position the RxPlayer has seeked to).

But with Tizen, those seeks to skip discontinuities may be brought back to a position milliseconds before, often "inside" the corresponding discontinuity hole.
Thus the RxPlayer re-detects the discontinuity, we re-seek after it and so on, in a loop.

Because that discontinuity monitoring logic is central to the RxPlayer, we in the end preferred to keep that logic that way and to just add exceptions for Tizen: If the position appears to abnormally go back in time on Tizen, we forbid further seeks for 5 seconds (if 5 seconds have elapsed and we're still locked at the previous position, we re-enable the discontinuity-skipping logic because Tizen may actually really be stuck on the discontinuity).

As far as we know, this logic fixed all Tizen auto-seeking issues we were previously having.


In logs, if you enabled "DEBUG" verbosity, you should see:

Init: the device appeared to have seeked back by itself.

When we detect that Tizen has seeked back. From this point, we will forbid discontinuity-seeking for 5 seconds.

Init: letting the device get out of a stall by itself

When playback is still stuck but the RxPlayer is letting Tizen try to get out of a discontinuity by itself due to the 5 seconds rules explained earlier.

And:

Init: ignored stall for too long, checking discontinuity

If those 5 seconds have passed but Tizen wasn't able to get out of the hole.

Do you see any of these logs when the problematic behavior arises?

@TomaszKowalik
Copy link
Author

Hi,
Thanks for the explanation! I'm using rxPlayer v 3.30.0

In the "DEBUG" logs, I can find all of the logs you mentioned. In between of one discontinuity warning and another I can find logs like:

Init: ignored stall for too long, checking discontinuity 5008.799999995972
Init: Pause playback to build buffer
Init: discontinuity found 1685445536.241 1685445536.4072292
SA: skippable discontinuity found in the stream 1685445536.168 1685445536.408229
API: Sending warning: t: MediaError (DISCONTINUITY_ENCOUNTERED) A discontinuity has been encountered at position 1685445536.241, seeked at position 1685445536.408229
SI: Pushing segment strictly after previous one. audio 1685445545.9905624 1685445545.99
AVSB: Acknowledging complete segment audio P: 1 A: 2 R: audio_112035_fra=112000 S: 1685445545.9905624-1.92
SI: found true buffered end audio 1685445547.91 1685445547.9105625
SI: current audio inventory timeline:
1685445534.17|A|1685445536.24 ~ 1685445536.39|A|1685445547.91
[A] P: 1 || R: audio_112035_fra=112000(112000)
API: current media element state tick event ratechange position 1685445536.408229 seeking true internalSeek null rebuffering false freezing false ended false paused false playbackRate 0 readyState 2
API: current playback timeline:
1685445534.17|==2.07==|1685445536.24 ~0.15~ 1685445536.39|==11.52==|1685445547.91
ratechange
ABR: Choosing representation with bandwidth estimation. 4714400 video=4714400
SI: current video inventory timeline:
1685445501.91|A|1685445503.83 ~ 1685445503.83|B|1685445505.67 ~ 1685445505.67|C|1685445509.51 ~ 1685445509.51|D|1685445513.35 ~ 1685445513.35|B|1685445515.27 ~ 1685445515.27|E|1685445517.19 ~ 1685445517.19|F|1685445555.67
[A] P: 1 || R: video=3590400(3590400)
[B] P: 1 || R: video=1444800(1444800)
[C] P: 1 || R: video=648000(648000)
[D] P: 1 || R: video=1066800(1066800)
[E] P: 1 || R: video=2671200(2671200)
[F] P: 1 || R: video=4714400(4714400)
SI: current audio inventory timeline:
1685445534.17|A|1685445536.24 ~ 1685445536.39|A|1685445547.91
[A] P: 1 || R: audio_112035_fra=112000(112000)
RS: future discontinuity encountered audio 1685445536.241 1685445536.3905625
Init: Resume playback speed 1
API: playerStateChange event PLAYING
                                                               ^1685445536.408229 
seeking
ABR: Choosing representation with bandwidth estimation. 4714400 video=4714400
SI: current video inventory timeline:
1685445501.91|A|1685445503.83 ~ 1685445503.83|B|1685445505.67 ~ 1685445505.67|C|1685445509.51 ~ 1685445509.51|D|1685445513.35 ~ 1685445513.35|B|1685445515.27 ~ 1685445515.27|E|1685445517.19 ~ 1685445517.19|F|1685445555.67
[A] P: 1 || R: video=3590400(3590400)
[B] P: 1 || R: video=1444800(1444800)
[C] P: 1 || R: video=648000(648000)
[D] P: 1 || R: video=1066800(1066800)
[E] P: 1 || R: video=2671200(2671200)
[F] P: 1 || R: video=4714400(4714400)
SI: current audio inventory timeline:
1685445534.17|A|1685445536.24 ~ 1685445536.39|A|1685445547.91
[A] P: 1 || R: audio_112035_fra=112000(112000)
RS: current discontinuity encountered audio 1685445536.3905625
ratechange
ABR: Choosing representation with bandwidth estimation. 4714400 video=4714400
SI: current video inventory timeline:
1685445501.91|A|1685445503.83 ~ 1685445503.83|B|1685445505.67 ~ 1685445505.67|C|1685445509.51 ~ 1685445509.51|D|1685445513.35 ~ 1685445513.35|B|1685445515.27 ~ 1685445515.27|E|1685445517.19 ~ 1685445517.19|F|1685445555.67
[A] P: 1 || R: video=3590400(3590400)
[B] P: 1 || R: video=1444800(1444800)
[C] P: 1 || R: video=648000(648000)
[D] P: 1 || R: video=1066800(1066800)
[E] P: 1 || R: video=2671200(2671200)
[F] P: 1 || R: video=4714400(4714400)
SI: current audio inventory timeline:
1685445534.17|A|1685445536.24 ~ 1685445536.39|A|1685445547.91
[A] P: 1 || R: audio_112035_fra=112000(112000)
RS: current discontinuity encountered audio 1685445536.3905625
SI: Pushing segment strictly after previous one. audio 1685445547.9105625 1685445547.91
timeupdate
ABR: Choosing representation with bandwidth estimation. 4714400 video=4714400
SI: current video inventory timeline:
1685445501.91|A|1685445503.83 ~ 1685445503.83|B|1685445505.67 ~ 1685445505.67|C|1685445509.51 ~ 1685445509.51|D|1685445513.35 ~ 1685445513.35|B|1685445515.27 ~ 1685445515.27|E|1685445517.19 ~ 1685445517.19|F|1685445557.59
[A] P: 1 || R: video=3590400(3590400)
[B] P: 1 || R: video=1444800(1444800)
[C] P: 1 || R: video=648000(648000)
[D] P: 1 || R: video=1066800(1066800)
[E] P: 1 || R: video=2671200(2671200)
[F] P: 1 || R: video=4714400(4714400)
SI: current audio inventory timeline:
1685445534.43|A|1685445536.24 ~ 1685445536.39|A|1685445540.23
[A] P: 1 || R: audio_112035_fra=112000(112000)
RS: future discontinuity encountered audio 1685445536.241 1685445536.3905625
Init: letting the device get out of a stall by itself
SI: Pushing segment strictly after previous one. audio 1685445540.2305624 1685445540.23
AVSB: Acknowledging complete segment audio P: 1 A: 2 R: audio_112035_fra=112000 S: 1685445540.2305624-1.92
SI: found true buffered end audio 1685445542.15 1685445542.1505625
SI: current audio inventory timeline:
1685445534.43|A|1685445536.24 ~ 1685445536.39|A|1685445542.15
seeked
ABR: Choosing representation with bandwidth estimation. 4714400 video=4714400
SI: current video inventory timeline:
1685445501.91|A|1685445503.83 ~ 1685445503.83|B|1685445505.67 ~ 1685445505.67|C|1685445509.51 ~ 1685445509.51|D|1685445513.35 ~ 1685445513.35|B|1685445515.27 ~ 1685445515.27|E|1685445517.19 ~ 1685445517.19|F|1685445555.67
[A] P: 1 || R: video=3590400(3590400)
[B] P: 1 || R: video=1444800(1444800)
[C] P: 1 || R: video=648000(648000)
[D] P: 1 || R: video=1066800(1066800)
[E] P: 1 || R: video=2671200(2671200)
[F] P: 1 || R: video=4714400(4714400)
Stream: no more media segment to request. Cancelling queue. video
SI: current video inventory timeline:
1685445501.91|A|1685445503.83 ~ 1685445503.83|B|1685445505.67 ~ 1685445505.67|C|1685445509.51 ~ 1685445509.51|D|1685445513.35 ~ 1685445513.35|B|1685445515.27 ~ 1685445515.27|E|1685445517.19 ~ 1685445517.19|F|1685445555.67
[A] P: 1 || R: video=3590400(3590400)
[B] P: 1 || R: video=1444800(1444800)
[C] P: 1 || R: video=648000(648000)
[D] P: 1 || R: video=1066800(1066800)
[E] P: 1 || R: video=2671200(2671200)
[F] P: 1 || R: video=4714400(4714400)
Stream: Media segments now need to be requested. Starting queue. audio 10
SF: Beginning request audio P: 1 A: 1 R: audio_112034_deu=112000 S: 1685445536.3905625-1.92
Init: the device appeared to have seeked back by itself.
API: current media element state tick event canplay position 1685445534.548 seeking false internalSeek null rebuffering false freezing false ended false paused false playbackRate 1 readyState 3
API: current playback timeline:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants