-
Notifications
You must be signed in to change notification settings - Fork 574
#2426 Support updating HLS Interstitials according to the HLS spec #2427
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
#2426 Support updating HLS Interstitials according to the HLS spec #2427
Conversation
Thanks for the pull request. I don't think we need changes in the parser or the The user of the playlist can then compare and update the interstitial by comparing playlistA with playlistB. |
The change we would need for What does your stream update in the interstitial in the playlist? |
We need the code change because if you revert the changes in
Which is also what you get if you try and play this https://raw.githubusercontent.com/TomVarga/HLS-test-stream/refs/heads/main/ride/audio.m3u8 stream in the demo app. Which means that the player is not handling the playlist according to the HLS spec as updating a daterange tag is allowed, meaning it's OK to not have |
As you can see in the mentioned example stream, and the test I have added: END-DATE get added to the interstitial |
I have updated the PR description with the same as the issue to hopefully avoid some confusion. |
The model is that each time when a playlist is fetched an We don't merge playlist A into playlist B or parts of it, so that multiple states of the playlist are represented. If you see a failure with parsing please file a bug. This isn't related to updateability. |
Sure, I can file the parsing issue as a bug, do please see #2428 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Considering that I have misread the part 'If a Playlist contains two EXT-X-DATERANGE tags with' and haven't realized this in your unit test . I should have looked at this more closely beside the discussion around the START-DATE
problems. Sorry for this.
So bseides the discussion about the spec ambiguity, this change makes totally sense in general as we want to support this according to spec at some point.
In the comment on L1321 I suggest to make an HlsMediaPlaylist.Interstitial.Builder
because I think this would simplify the code and provide a good way to handle the update and validate merging the two or more tags.
Let me know what you think. It's fine to leave it to us to implement that Builder approach or convince me for another approach and why. :)
new ArrayList<>(interstitialMap.values())); | ||
} | ||
|
||
private static Interstitial getUpdatedInterstitial( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about creating an HlsMediaPlaylist.Interstitial.Builder()
that has setters for each field. When a setter is called multiple times, it asserts that it's the unset value or the same value else it throws.
Then we put the Interstitial.Builder
instances in the LinkedHashMap
by ID as you already do. At the very end, when we construct the HlsMediaPlaylist
instance pass in the list of builder, and the constructor of Intersitital
iterates over all builders, calls build()
to get a ImmutableList
of Interstitial
instances.
I think that would make the code a bit simpler. WDYT?
// for consolidating the tags. The subsequent EXT-X-DATERANGE tags can | ||
// appear in a subsequent playlist update, in the case of live or event | ||
// streams. | ||
Uri newAssetUri = (assetUri != null) ? assetUri : oldInterstitial.assetUri; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the old value has precedence as mentioned in the Builder approach above or we should actually throw if not equal.
any AttributeName that appears in both tags MUST have the same AttributeValue.
...es/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsPlaylistParser.java
Show resolved
Hide resolved
restrictions, | ||
clientDefinedAttributes.build())); | ||
|
||
if (interstitialMap.containsKey(id)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you do the Builder
that I suggest below in the other comment, this if
is at the very beginning on L1044 or so. Then you can set each value on the builder after parsing each field. The setter of the builder can then act accordingly: a) when the field wasn't set before: set the value b) if it was already set assert that the new value is either the same or unset, else throw. These validation can then be in the setter of each field. This can include things like checking that there is only an ASSET-URI or an ASSET-LIST.
A simple example of an Media3 Builder: |
I'll update the PR with the builder approach. |
I've pushed the requested changes, do please let me know if you think something is missing or needs improvement. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Thank you very much!
There are two or three things that we need to look at.
The rest are nits or uber-nits, as I gave you the hard way like I'd do internally. We can share these things also when leave some of them to me and I can do these nits when preparing for internal review. :)
...ies/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsMediaPlaylist.java
Outdated
Show resolved
Hide resolved
...ies/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsMediaPlaylist.java
Outdated
Show resolved
Hide resolved
...ies/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsMediaPlaylist.java
Outdated
Show resolved
Hide resolved
...ies/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsMediaPlaylist.java
Outdated
Show resolved
Hide resolved
public Builder setClientDefinedAttributes( | ||
List<HlsMediaPlaylist.ClientDefinedAttribute> clientDefinedAttributes) { | ||
if (clientDefinedAttributes.isEmpty()) return this; | ||
if (!this.clientDefinedAttributes.isEmpty()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure how to interpret the spec. These attributes are not interpreted by a player by spec, so changing them would not have any implications for playback. We could choose to be a bit less strict here.
From the text of the spec, we could as an alternative to your proposal allow any new attributes, but make sure we don't override existing ones with a different value. Easiest would probably to have a Map
here in the builder keyed by the attribute.name
and then check for equality if an attribute with the same name is provided an additional time. Then when build()
is called this is converted to a list.
Being a bit less strict would mean to just make sure to not create duplicate name
s and either ignore the new attribute or allow it to be overridden. So being less strict gives us the burden to decide exactly that which we may want to avoid.
So I think I'd vote for checking equality. :)
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we definitely need to allow new attributes to the list.
I agree probably easiest is to have a Map as you've described.
I also agree I'd rather check value equality too.
I'll add this in a follow up commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added some validation, do let me know if it looks OK to you.
...es/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsPlaylistParser.java
Outdated
Show resolved
Hide resolved
...yer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/HlsMediaPlaylistParserTest.java
Outdated
Show resolved
Hide resolved
...yer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/HlsMediaPlaylistParserTest.java
Outdated
Show resolved
Hide resolved
...yer_hls/src/test/java/androidx/media3/exoplayer/hls/playlist/HlsMediaPlaylistParserTest.java
Outdated
Show resolved
Hide resolved
...ies/exoplayer_hls/src/main/java/androidx/media3/exoplayer/hls/playlist/HlsMediaPlaylist.java
Outdated
Show resolved
Hide resolved
I think I addressed most of your comments, I'll work on a commit for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice! Thank you very much!
I'm going to take this to send it for internal review.
Can you please let me quickly know that's fine? Looks to me you applied the changes for the client defined attributes.
Yes, that's fine. Thank you. |
… spec - if an interstitial already appeared, then attempt to update it
- use a builder - don't throw parse exception for missing START-DATE instead ignore the interstitial
… spec - some code style cleanup - fix negated expression in checkArguments and add test for it
… spec - add validation for clientDefinedAttribute
3efb6a9
to
d580062
Compare
I'm going to send this for internal review now. You may see some more commits being added as I make changes in response to review feedback. Please refrain from pushing any more substantive changes as it will complicate the internal review - thanks! |
9050266
to
16b9880
Compare
Use case description
According to the latest version of the HLS spec at https://datatracker.ietf.org/doc/html/draft-pantos-hls-rfc8216bis#section-4.4.5.1
In a live stream scenario our system does updates to an interstitial according to the spec.
Here is simplified example stream:
https://raw.githubusercontent.com/TomVarga/HLS-test-stream/refs/heads/main/ride/audio.m3u8
Proposed solution
I am creating a PR to show my proposed solution, which is going to allow updating the interstitial, but still require the START-DATE for the first appearance of the interstitial.
This is a naive solution:
Can use https://raw.githubusercontent.com/TomVarga/HLS-test-stream/refs/heads/main/ride/audio.m3u8 in the demo app to validate these changes