Comments (8)
- Does ExoPlayer expect clients to request for byte ranges out of bound implicitly?
I think this question is not framed the same way I think about it. My mental model:
-
The media3
DataSource.open
method is documented as follows:The following edge case behaviors apply:
- If the requested position is within the resource, but the requested length extends beyond the end of the resource, then open will succeed and data from the requested position to the end of the resource will be made available through read.
- If the requested position is equal to the length of the resource, then open will succeed, and read will immediately return RESULT_END_OF_INPUT.
- If the requested position is greater than the length of the resource, then open will throw an IOException for which isCausedByPositionOutOfRange will be true.
-
Therefore all implementations of
DataSource
need to follow these requirements.
In #1032 (comment) you said:
Request/Headers/Range=bytes=108421975-
which doesn't containlength
, and theposition
here 108421975 is one byte extra than it's actual total length. We had multiple records with 416 and they all have this same pattern.
I'm not 100% sure what you mean the 'actual total length' of your content is in this example, whether it's 108421975
or 108421974
. If the content length is 108421975
then the second bullet applies (i.e. we're requesting data that starts just after the end of the content). If it's 108421974
then the third bullet applies.
- It is reasonable to depend on header fields as based on HTTP semantics for 416, it
SHOULD
notMUST
returnContentRange
in header, however some endpoints do not respect the semantics.
Looking at the code it's not obvious to me that we do assume the ContentRange
header is included. We have cases for both where it's empty/absent and where it's incomplete (second matcher group missing) - in both cases we return C.LENGTH_UNSET
from this method:
The conclusion in #1032 seems to be that the manifest of this media is malformed, which is what led to these out-of-bounds requests? If that's the case, there's little ExoPlayer can do - the media has resulted in us requesting data that the server can't satisfy.
I'm not really sure what different behaviour you want ExoPlayer to do here - if the ContentRange
header on the 416 response is missing the length we can't check if the requested position is equal to the length (case 2 in the docs above), and so we have to throw. Note that you call this code a '416 workaround' but it's specifically for the case when the requested position is equal to the content length. If your content length above is 108421974
then even if you change the server behaviour to include the length in the ContentRange
header, we will still throw (because the third bullet above applies).
from media.
Hey @icbaker, thank you so much for looking into it and really appreciate the detailed response.
To answer your questions:
I'm not 100% sure what you mean the 'actual total length' of your content is in this example, whether it's 108421975 or 108421974. If the content length is 108421975 then the second bullet applies (i.e. we're requesting data that starts just after the end of the content). If it's 108421974 then the third bullet applies.
108421975
is the content length in which case the second bullet will apply as per you mentioned which will returnRESULT_END_OF_INPUT
- We know from the endpoints that consumes ExoPlayer requests that it receives such requests
Request/Headers/Range=bytes=108421975-
, what we don't know and would really need help is to get your insights on when this could happen on ExoPlayer front?- If I can rephrase my question in a different way -
How did ExoPlayer thought of handling 416 by specifically adding a check when the requested position is equal to the content length?
- We would like to backtrack from the symptom (checking the requested position) to get to the root cause of unbounded (out-of-bound) requests and it would really help debug our issue.
- We think that maybe going backwards from the solution to handle 416, we can find the problem that causes this 416
- If I can rephrase my question in a different way -
from media.
The conclusion in #1032 seems to be that the manifest of this media is malformed, which is what led to these out-of-bounds requests? If that's the case, there's little ExoPlayer can do - the media has resulted in us requesting data that the server can't satisfy.
- The interesting observation from this bug is that it doesn't happen for all the users, it only happens for few of them that alone impacts the download errors and makes us believe that the user experience is bad
- If there was a manifest problem, then it would have been a much larger issue (but it only happens for few users) and easily reproducible (but we weren't able to reproduce with the same manifest an end-user that sees 416 gets in any of the titles - not even a single one of them)
- However, we haven't ruled this one out and we are still looking into manifest generation code but given the evidence, we think it is less likely the manifest problem
from media.
A major question is what kind of situation cause exoplayer to make unbounded requests (i.e.bytes xxx-
)?
It's clear that it's "when exoplayer does not know the length," but what causes that to happen? Does exoplayer rely on the mpd to determine the length, the sidx atom, or the Content-Range header? If the Content-Range header, is this simply the first one to be returned, or does it continue to update this with each 206 response? (If most were correct, but one were missing or broken, would this confuse it?)
Would an MPD corruption do this? What kind of corruption would cause this but not break playback?
I am certain that in some cases, cloudfront is "hanging-up" on exoplayer without sending any response, leading eventually to a socket timeout. This is a situation we're working on, but would it cause this kind of problem? (My attempts to do this intentionally have not reproduced the problem.)
We believe this occurs most with users who have a bad network connection. It is possible that segment downloads are interrupted. Would this cause exoplayer to lose track of the length? (How does it keep track of this between launches?)
I can reproduce our 416 errors by intentionally replacing the Content-Range length with *
, but I haven't found any "normal" way to get into this situation.
from media.
How did ExoPlayer thought of handling 416 by specifically adding a check when the requested position is equal to the content length?
This is basically what I answered above: Because the DataSource
interface requires that behaviour. This is due to adapting between different interpretations of an 'out of bound' request. The DataSource
interface states that it's OK to request content that starts just after the last byte of the actual content, and the result is no bytes are read. The HTTP protocol thinks this is an out of bounds read (same as reading bytes that start e.g. 10 bytes after the end of the actual content) - i..e an error. Therefore a DataSource
implementation that maps between the DataSource
interface and the HTTP protocol has to distinguish these cases in order to map some HTTP 'out of bounds' errors back to 'read no bytes' - hence the code you've highlighted.
A major question is what kind of situation cause exoplayer to make unbounded requests (i.e.
bytes xxx-
)?
This can also be phrased as "when does ExoPlayer pass a DataSpec
with length == LENGTH_UNSET
to DataSource.open
?". And this pushes the discussion out of DataSource
implementations, up to the layer(s) of the player above.
Does exoplayer rely on the mpd to determine the length, the sidx atom, or the Content-Range header?
I'm afraid I'm not familiar enough with the DASH or caching parts of ExoPlayer to answer this question confidently - possibly @marcbaechinger can help more here.
from media.
A major question is what kind of situation cause exoplayer to make unbounded requests (i.e.
bytes xxx-
)?This can also be phrased as "when does ExoPlayer pass a
DataSpec
withlength == LENGTH_UNSET
toDataSource.open
?". And this pushes the discussion out ofDataSource
implementations, up to the layer(s) of the player above.
I agree. This is an equivalent question. My expectation is that this happens somewhere between exoplayer itself and its cache, not inside of DataSource.
from media.
A major question is what kind of situation cause exoplayer to make unbounded requests (i.e.
bytes xxx-
)?This can also be phrased as "when does ExoPlayer pass a
DataSpec
withlength == LENGTH_UNSET
toDataSource.open
?". And this pushes the discussion out ofDataSource
implementations, up to the layer(s) of the player above.
@icbaker thanks for looking into it. When you say layers up to the player above, do you mean CacheWriter
? Do you think length == LENGTH_UNSET
would be possible for CacheWriter
?
from media.
A major question is what kind of situation cause exoplayer to make unbounded requests (i.e.
bytes xxx-
)?This can also be phrased as "when does ExoPlayer pass a
DataSpec
withlength == LENGTH_UNSET
toDataSource.open
?". And this pushes the discussion out ofDataSource
implementations, up to the layer(s) of the player above.Does exoplayer rely on the mpd to determine the length, the sidx atom, or the Content-Range header?
I'm afraid I'm not familiar enough with the DASH or caching parts of ExoPlayer to answer this question confidently - possibly @marcbaechinger can help more here.
Pushing up for awareness, @marcbaechinger would you be able to help us here
from media.
Related Issues (20)
- LL-HLS Streams with CMCD enabled lead to ExoPlaybackException HOT 2
- Force reset ExoPlayer internals to generate new audioSessionId and clear audio tracks HOT 1
- How to call setMediaSource method by MediaController? HOT 1
- How to call setMediaSource method by MediaController? HOT 2
- Seamless transitions to clipped items with a second decoder HOT 1
- Exoplayer misinterprets RTSP streams audioInputFormat as mp4a.40.1 instead of mp4a.40.2 HOT 1
- ExoPlayer clarification on DASH Byte-Range request against Player Buffer params' adjustments
- Unable to style default `SubtitleView` of the Media3 ExoPlayer HOT 3
- DefaultDrmSession should handle when key is already available (getKeyRequest() -> REQUEST_TYPE_NONE) HOT 4
- Support for playing Kotlin Multiplatform resources HOT 13
- HLS playback crash on Android 6 and below. HOT 2
- AGP 8.3.0 and newer crash: IllegalAccessError: Illegal class access: 'androidx.media3.session.MediaSessionStub' attempting to access 'com.google.common.util.concurrent.ImmediateFuture' HOT 10
- Media3 Exoplayer subtitle font size increase HOT 1
- Stall in ExoPlayer when EventStream falls out of window and is removed from the DASH manifest
- Sound disappears when custom equalizer is enabled
- Playback Error on Image Track (IllegalArgumentException: x + width must be <= bitmap.width()) HOT 1
- Multiple DRM protection levels in DASH stream with low DRM protection level on device HOT 7
- Captions can't be turned on using Google Assistant HOT 3
- Support for setting the start and end times of playback in TextOverlay. HOT 4
- Media Controllers — Slot reservation
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from media.