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

BehindLiveWindowException when playing HLS #1074

Closed
kientux opened this issue Dec 18, 2015 · 37 comments
Closed

BehindLiveWindowException when playing HLS #1074

kientux opened this issue Dec 18, 2015 · 37 comments
Labels

Comments

@kientux
Copy link

kientux commented Dec 18, 2015

With latest ExoPlayer library, when playing HLS, sometimes the video hang with BehindLiveWindowException:

E/ExoPlayerImplInternal: Internal track renderer error.
  com.google.android.exoplayer.ExoPlaybackException: com.google.android.exoplayer.BehindLiveWindowException
  at com.google.android.exoplayer.SampleSourceTrackRenderer.maybeThrowError(SampleSourceTrackRenderer.java:154)
  at com.google.android.exoplayer.SampleSourceTrackRenderer.maybeThrowError(SampleSourceTrackRenderer.java:141)
  at com.google.android.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:438)
  at com.google.android.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:213)
  at android.os.Handler.dispatchMessage(Handler.java:98)
  at android.os.Looper.loop(Looper.java:168)
  at android.os.HandlerThread.run(HandlerThread.java:61)
  at com.google.android.exoplayer.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)
  Caused by: com.google.android.exoplayer.BehindLiveWindowException
  at com.google.android.exoplayer.hls.HlsChunkSource.getChunkOperation(HlsChunkSource.java:290)
  at com.google.android.exoplayer.hls.HlsSampleSource.maybeStartLoading(HlsSampleSource.java:541)
  at com.google.android.exoplayer.hls.HlsSampleSource.continueBuffering(HlsSampleSource.java:253)
  at com.google.android.exoplayer.SampleSourceTrackRenderer.continueBufferingSource(SampleSourceTrackRenderer.java:173)
  at com.google.android.exoplayer.MediaCodecTrackRenderer.doSomeWork(MediaCodecTrackRenderer.java:462)
  at com.google.android.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:431)
  at com.google.android.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:213) 
  at android.os.Handler.dispatchMessage(Handler.java:98) 
  at android.os.Looper.loop(Looper.java:168) 
  at android.os.HandlerThread.run(HandlerThread.java:61) 
  at com.google.android.exoplayer.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40) 

But if I just wait for about 3 - 5 seconds (or call preparePlayer() again) then the video starts playing again with no problem. Sometimes there's also SocketTimeoutException of okhttp before this exception, I tried to increase timeout in DefaultHttpDataSource and SocketTimeoutException is gone but this exception persists.

So how to get rid of this? Maybe it's because of slow network connection, is there any way to increase timeout other than in DefaultHttpDataSource?

@ojw28
Copy link
Contributor

ojw28 commented Jan 3, 2016

BehindLiveWindowException can occur when playing a rolling live stream in which segments become unavailable after a certain period of time. For example a rolling live stream might allow you to request segments that correspond to the most recent 2 minutes of the broadcast, but not earlier. In this case we'd say that the window is 2 minutes in length.

BehindLiveWindowException is thrown if the player attempts to request a segment that's no longer available. This is typically caused by:

  • The window being unreasonably small. In this case the fix is to increase the window on the server side.
  • Repeated client buffering causing the client to be playing further and further behind the broadcast until it eventually ends up trying to request segments that are no longer available. In this case the fix might be on the server side if the buffering is due to a server issue. If it's not a server side issue, it's most likely just that the client doesn't have sufficient bandwidth. In this case preparing the player again will allow playback to resume. It should be possible to do this immediately (the 3 - 5 second you mention wait shouldn't be necessary). In previous releases something equivalent happened internally, but we opted to propagate the error and require that applications do this instead. This was for consistency reasons, and also because some applications may wish to do something different. See Make behaviour when dropping off back of live streams consistent across DASH/SS/HLS #765 and the change referenced there for details.

@ojw28 ojw28 closed this as completed Jan 3, 2016
@ojw28 ojw28 added the question label Jan 3, 2016
@ojw28
Copy link
Contributor

ojw28 commented Jan 3, 2016

Note that most often the exception is caused by a combination of the two bullet points above. Repeated client buffering will only cause the exception if the accumulated duration of time spent buffering exceeds the window size minus the duration that the client wants to buffer locally (typically ~30 seconds). So the larger the window size, the less likely this is to occur. I would say that you'd want the window to be at least ~2 minutes.

@crossle
Copy link

crossle commented Feb 1, 2016

@ojw28 How to workaround?

@kientux
Copy link
Author

kientux commented Feb 1, 2016

@crossle Here's my workaround: (HlsChunkSource)

    if (live) {
      if (previousTsChunk == null) {
        chunkMediaSequence = getLiveStartChunkMediaSequence(nextVariantIndex);
      } else {
        chunkMediaSequence = switchingVariantSpliced
            ? previousTsChunk.chunkIndex : previousTsChunk.chunkIndex + 1;
        if (chunkMediaSequence < mediaPlaylist.mediaSequence) {
            if (allowSkipAhead) {
                chunkMediaSequence = getLiveStartChunkMediaSequence(nextVariantIndex);
                liveDiscontinuity = true;
            } else {
                fatalError = new BehindLiveWindowException();
                return;
            }
        }
      }
    } else {
        ....
    }

@myscreen
Copy link

myscreen commented Feb 3, 2016

Where should I use this code? ;(

@ojw28
Copy link
Contributor

ojw28 commented Feb 3, 2016

You should really just fix the source content as per my initial response.

@ravinderpoonia07
Copy link

Am facing the same issue at my end. @ojw28 as per you we have to increase the buffer time from default 10 sec to more then 30 sec and it will solve the problem. But in my case i am using Akamai as my CDN and they don't provide any other option to increase it more then 10 sec, though they provide option to decrease this below 10 (which is not useful). Is there any other alternative option to resolve this.

@ojw28
Copy link
Contributor

ojw28 commented Feb 18, 2016

That doesn't sound right. Are you sure the variable you're looking at isn't the chunk size, for which a 10 second limit would make sense.

@ravinderpoonia07
Copy link

I guess we are not sync. I'm consuming AKAMAI HLS Playback URL (.m3u8) as stream URL. I havent found that we may request custom config against stream URL.

Also would like to understand the term "window" as I'm referring it as HLS segment(.ts) duration size(default is 10 secs) which can't be changed to 30 secs.

@kientux
Copy link
Author

kientux commented Feb 19, 2016

I end up fix this problem with:

  • When BehindLiveWindowException is thrown, just call preparePlayer()
  • When player is buffering for too long (3 seconds in my case), call preparePlayer() too

@ojw28
Copy link
Contributor

ojw28 commented Feb 19, 2016

Window refers to (N-1)*(SegmentDuration), where SegmentDuration is 10s in your case, and N is the number of segments that are listed in each HLS playlist at any given point in time.

I suspect you'll find that your HLS media playlists only contain 3 or 4 segments at any given point in time. Increasing that would help you to avoid this issue.

@ravinderpoonia07
Copy link

@ojw28 Hmm .. consider the fact that I cannot ask/demand customization from server (Akamai) in my case. I just have HLS URL to play though any suggestion to handle it in client side (Player) would be help.

@ojw28
Copy link
Contributor

ojw28 commented Feb 19, 2016

I'd be surprised if Akamai don't allow configuration of the window length. How many segments are listed in your manifests, at any given point in time?

@ravinderpoonia07
Copy link

@ojw28 I have checked and find that it provides me 3 ts segment at a particular time.

@ojw28
Copy link
Contributor

ojw28 commented Feb 22, 2016

Right, and that's your problem. It should be possible for you to increase that somehow.

@ravinderpoonia07
Copy link

@ojw28 Firstly let me know you that i am working with Live stream (not VOD). I am using Akamai playback url given by end client. So it not possible to update anything from Akamai. Is there any kind of solution for client side to resolve this ?

@ojw28
Copy link
Contributor

ojw28 commented Feb 22, 2016

You should request that the provider resolves the issue. Fundamentally you're trying to play a live stream with a live window of insufficient size. It's a content issue. It can only be properly resolved by the content provider.

The best thing that you can do on the client is as @kientux suggested further up this thread, which is to automatically restart the playback each time it fails in this way. This will not be seamless, but it will allow playback to continue once it buffers again.

@ravinderpoonia07
Copy link

@ojw28 Ok....but the purposed client side solution is not suitable for me. I have tried the same stream with BrightCove player (Paid Solution) and it works fine but the strange thing is that they are also using ExoPlayer internally.

@ojw28
Copy link
Contributor

ojw28 commented Feb 22, 2016

So get the provider to fix their content. It's simply not a client side problem if content is not provided correctly.

@ChernyshovYuriy
Copy link

Dear colleagues,
How to calculate window size for the Widevine mpegdash content? I have access to the manifest mpd file but I am not well familiar with the structure in order to detect it?

@ChernyshovYuriy
Copy link

I found another bug still opened and I think that in case of mpegdash we facing BehindLiveWindowException because of it.
Here is link:
#765

@j-t-h
Copy link

j-t-h commented Mar 23, 2016

Where is the correct place to catch the BehindLiveWindowException? I realize that the provider should fix the content, but until I can get the addressed, what is the best place to catch this exception and restart the player?

Here is stack trace:

com.google.android.exoplayer.ExoPlaybackException: com.google.android.exoplayer.BehindLiveWindowException
       at com.google.android.exoplayer.SampleSourceTrackRenderer.maybeThrowError(SampleSourceTrackRenderer.java:263)
       at com.google.android.exoplayer.SampleSourceTrackRenderer.maybeThrowError(SampleSourceTrackRenderer.java:145)
       at com.google.android.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:438)
       at com.google.android.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:213)
       at android.os.Handler.dispatchMessage(Handler.java:98)
       at android.os.Looper.loop(Looper.java:135)
       at android.os.HandlerThread.run(HandlerThread.java:61)
       at com.google.android.exoplayer.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)
Caused by com.google.android.exoplayer.BehindLiveWindowException
       at com.google.android.exoplayer.hls.HlsChunkSource.getChunkOperation(HlsChunkSource.java:401)
       at com.google.android.exoplayer.hls.HlsSampleSource.maybeStartLoading(HlsSampleSource.java:697)
       at com.google.android.exoplayer.hls.HlsSampleSource.continueBuffering(HlsSampleSource.java:264)
       at com.google.android.exoplayer.SampleSourceTrackRenderer.doSomeWork(SampleSourceTrackRenderer.java:127)
       at com.google.android.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:431)
       at com.google.android.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:213)
       at android.os.Handler.dispatchMessage(Handler.java:98)
       at android.os.Looper.loop(Looper.java:135)
       at android.os.HandlerThread.run(HandlerThread.java:61)
       at com.google.android.exoplayer.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)

@ChernyshovYuriy
Copy link

The correct place is implementation of the
ExoPlayer.Listener
and it's method
void onPlayerError(ExoPlaybackException error);
In my case, I add it's implementation via
mExoPlayer.addListener(***)
Then, when you will get onPlayerError you can process Exception.

@huykn
Copy link

huykn commented Jun 3, 2016

1513
File:HlsRendererBuilder add line chunkSource.setAdaptiveMode(HlsChunkSource.ADAPTIVE_MODE_NONE);
to method: onSingleManifest
Work for me!

@ChernyshovYuriy
Copy link

@huykn , in this case you loose ability to dynamically select variant base on network conditions and you have to control from your client side which variant select in order to provide best user experience. In other words, if the network quality is low you have to detect it by yourself and switch stream into lower variant, otherwise buffering will be more and more frequent and end user experience of your application will be unpredicted. Keep this in mind.

@ojw28
Copy link
Contributor

ojw28 commented Jun 3, 2016

Specifically for HLS, it seems this issue can be caused by non-aligned segment numbers across the different variants, in addition to the other causes mentioned above. Non-aligned segment numbers are permitted by the HLS spec, and therefore failing to correctly handle this case is an ExoPlayer issue. It's kind of tracked by #699, but it would be good to have a bug explicitly tracking this resulting in BehindLiveWindowException.

@huykn - Are you able to provide test content that reproduces this issue? If so, please file a new issue on this tracker providing all of the information requested in the issue template, and we'll use that to track the problem.

@krok55
Copy link

krok55 commented Aug 1, 2016

Hello,

I'm also getting this exception on one of my HLS playbacks.
After applying the patch from @kientux the problem resolved.

Any chance for a temporary built-in solution until the root cause for this problem will be found?

Thanks

@kientux
Copy link
Author

kientux commented Aug 2, 2016

@krok55 The root cause was found. As you see in the conversation above, this is problem from content provider, not client. So ExoPlayer might never try to handle this exception.

@ojw28
Copy link
Contributor

ojw28 commented Aug 11, 2016

Note - There are fixes in 1.5.10 and 2.x.x releases of ExoPlayer that help a second root cause of BehindLiveWindowException in HLS playbacks.

@inantop
Copy link

inantop commented Aug 17, 2016

Note that Apple's documentation on using HTTP live streaming has 3 segments in it https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StreamingMediaGuide/UsingHTTPLiveStreaming/UsingHTTPLiveStreaming.html

I hardly think this is a content problem

@ojw28
Copy link
Contributor

ojw28 commented Aug 18, 2016

  • Is this still actually an issue in 1.5.10? As per my comment above, we pushed some fixes as part of that release.
  • I wouldn't class a non-productionized sample command as evidence of best practice. Note that they're actually overriding the default value (=5) of their own tool with a smaller value (=3) in that sample command, without giving any justification. I can't see any good reason for doing this, where-as it will definitely make failures/re-buffering/content-jumps more likely across all platforms by restricting the window length to be unnecessarily short.

@JonWatson
Copy link

I'm still seeing this in 1.5.10 across a variety of HLS Live streams.

@ishantsagar
Copy link

I am also facing the same issue with Exoplayer 2.x.x and 1.5.x versions while playing the Live HLS Video. Need resolution of it on client end, guys?

@theBradfo
Copy link

theBradfo commented Oct 5, 2016

I just experienced this with ExoPlayer 1.5.11 with a live hls stream. Stack trace is the same as aforementioned:

                                                                                     com.google.android.exoplayer.ExoPlaybackException: com.google.android.exoplayer.BehindLiveWindowException
                                                                                         at com.google.android.exoplayer.SampleSourceTrackRenderer.maybeThrowError(SampleSourceTrackRenderer.java:262)
                                                                                         at com.google.android.exoplayer.SampleSourceTrackRenderer.maybeThrowError(SampleSourceTrackRenderer.java:144)
                                                                                         at com.google.android.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:439)
                                                                                         at com.google.android.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:211)
                                                                                         at android.os.Handler.dispatchMessage(Handler.java:98)
                                                                                         at android.os.Looper.loop(Looper.java:136)
                                                                                         at android.os.HandlerThread.run(HandlerThread.java:61)
                                                                                         at com.google.android.exoplayer.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)
                                                                                      Caused by: com.google.android.exoplayer.BehindLiveWindowException
                                                                                         at com.google.android.exoplayer.hls.HlsChunkSource.getChunkOperation(HlsChunkSource.java:414)
                                                                                         at com.google.android.exoplayer.hls.HlsSampleSource.maybeStartLoading(HlsSampleSource.java:711)
                                                                                         at com.google.android.exoplayer.hls.HlsSampleSource.continueBuffering(HlsSampleSource.java:262)
                                                                                         at com.google.android.exoplayer.SampleSourceTrackRenderer.doSomeWork(SampleSourceTrackRenderer.java:126)
                                                                                         at com.google.android.exoplayer.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:432)
                                                                                         at com.google.android.exoplayer.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:211) 
                                                                                         at android.os.Handler.dispatchMessage(Handler.java:98) 
                                                                                         at android.os.Looper.loop(Looper.java:136) 
                                                                                         at android.os.HandlerThread.run(HandlerThread.java:61) 
                                                                                         at com.google.android.exoplayer.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40) 

I'm unable to provide a sample stream as they are authenticated, but please let me know if there's any additional information i can provide.

@ishantsagar
Copy link

@theBradfo Just wait for some couple of days, new fixed release is about to come for this issue.

@theBradfo
Copy link

@ishantsagar, @ojw28 can you provide any information on this forthcoming release and potentially some detail on how it would fix this issue?

@ojw28
Copy link
Contributor

ojw28 commented Oct 5, 2016

@ishantsagar - Please don't cross post on multiple issues (i.e. this one and #1782), it adds unnecessary noise to the issue tracker. Please continue this discussion on the open issue, which is #1782.

@google google locked and limited conversation to collaborators Oct 5, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests